From 397e8bb8c0d32fe720059b64b13f6a5f43a3ac2d Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 09:58:35 -0700 Subject: [PATCH 1/7] Add design spec for worktree create/remove VSCode tasks Co-Authored-By: Claude Sonnet 5 --- ...2026-07-16-worktree-vscode-tasks-design.md | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-16-worktree-vscode-tasks-design.md diff --git a/docs/superpowers/specs/2026-07-16-worktree-vscode-tasks-design.md b/docs/superpowers/specs/2026-07-16-worktree-vscode-tasks-design.md new file mode 100644 index 0000000..3670cdc --- /dev/null +++ b/docs/superpowers/specs/2026-07-16-worktree-vscode-tasks-design.md @@ -0,0 +1,97 @@ +# Worktree Create/Remove VSCode Tasks — Design + +## Goal + +Add the same "worktree: create" / "worktree: remove" VS Code tasks used in `github.com/stlab/cel-rs` to `templates/.vscode/tasks.json`, so consumer projects get one-click git-worktree management with tokensave integration, matching the reference example — but with the tokensave calls made best-effort so a consumer without `tokensave` installed still gets a fully working worktree create/remove. + +## Reference (cel-rs, verbatim source) + +`.vscode/tasks.json`: + +```json +"inputs": [ + { + "id": "worktreeName", + "type": "promptString", + "description": "Worktree name (e.g. my-feature) — branch will be worktree-" + } +], +"tasks": [ + { + "label": "worktree: create", + "type": "shell", + "command": "git worktree add \".claude/worktrees/${input:worktreeName}\" -b \"worktree-${input:worktreeName}\" && tokensave init \".claude/worktrees/${input:worktreeName}\" && tokensave branch add \"worktree-${input:worktreeName}\" --path \".claude/worktrees/${input:worktreeName}\" && code --new-window \".claude/worktrees/${input:worktreeName}\"", + "options": { "cwd": "${workspaceFolder}" }, + "problemMatcher": [], + "presentation": { "reveal": "always", "panel": "dedicated" } + }, + { + "label": "worktree: remove", + "type": "shell", + "command": "git worktree remove \".claude/worktrees/${input:worktreeName}\" && tokensave branch gc", + "options": { "cwd": "${workspaceFolder}" }, + "problemMatcher": [], + "presentation": { "reveal": "always", "panel": "dedicated" } + } +] +``` + +`.gitignore`: `.claude/worktrees/` and `.tokensave` (both unanchored). + +## Scope + +Files touched: + +1. `templates/.vscode/tasks.json` — convert to JSONC (adds `//` section-divider comments); add the `worktreeName` input and the two worktree tasks (adapted per below); add matching section-divider comments to the pre-existing CMake-preset and cleanup tasks now that the file supports comments. +2. `templates/.gitignore` — add `.claude/worktrees/` and `.tokensave`. + +Not in scope: `templates/.vscode/extensions.json` (tokensave isn't a VS Code extension, nothing to recommend); cpp-library's own root `.vscode/` (it has no tasks.json of its own — only the template, which is consumer-facing). + +## Adaptations from the reference + +**1. JSONC conversion.** `templates/.vscode/tasks.json` has been strict JSON since it was created (validated via `python3 -m json.tool` in every prior task). cel-rs's file uses `//` comments. Per your direction, we're matching cel-rs's style, which means the validation method changes: a small regex preprocessor strips full-line `//` comments before parsing, since cel-rs's comments are always on their own line (never trailing after a JSON token): + +```bash +python3 -c ' +import json, re +text = open("templates/.vscode/tasks.json").read() +text = re.sub(r"^[ \t]*//.*$", "", text, flags=re.MULTILINE) +json.loads(text) +print("OK") +' +``` +(Single-quoted outer `-c` argument, deliberately — a double-quoted bash string would let the shell itself interpolate the trailing `$` in the regex before Python ever sees it.) + +**2. Best-effort tokensave (the change from your last question).** The reference chains `tokensave init && tokensave branch add` directly into the command with plain `&&`, so a missing `tokensave` binary would abort the whole task (same class of problem as the CMake Tools sync issue found in the previous feature's final review). Instead, the tokensave calls are wrapped in a group that always reports success, scoped so it can't mask a real `git worktree add`/`git worktree remove` failure: + +Default (bash/zsh — macOS/Linux; also used as the base `command` VS Code falls back to): + +```text +git worktree add ".claude/worktrees/${input:worktreeName}" -b "worktree-${input:worktreeName}" && (command -v tokensave >/dev/null 2>&1 && tokensave init ".claude/worktrees/${input:worktreeName}" && tokensave branch add "worktree-${input:worktreeName}" --path ".claude/worktrees/${input:worktreeName}" || true) && code --new-window ".claude/worktrees/${input:worktreeName}" +``` + +Windows override (per-task `"windows"` block overriding both `"command"` and the shell, same mechanism already used for the 8 CMake preset tasks — needed here because cmd.exe's existence-check syntax differs from bash's, not just because of `&&` support): + +```text +git worktree add ".claude/worktrees/${input:worktreeName}" -b "worktree-${input:worktreeName}" && (where tokensave >nul 2>&1 && (tokensave init ".claude/worktrees/${input:worktreeName}" && tokensave branch add "worktree-${input:worktreeName}" --path ".claude/worktrees/${input:worktreeName}") || ver>nul) && code --new-window ".claude/worktrees/${input:worktreeName}" +``` + +`ver>nul` is a deliberate choice over `exit /b 0` — the latter risks terminating the whole `cmd.exe /c "..."` invocation early (since we're not inside a separate batch-file scope), which would skip `code --new-window` entirely. `ver` is a harmless always-succeeds no-op. + +`worktree: remove` follows the identical pattern with `tokensave branch gc` in place of init/branch-add, and no trailing `code` call to protect. + +Net effect: if `tokensave` is missing OR present-but-erroring, the worktree is still created/removed and the editor still opens — tokensave bookkeeping is strictly secondary to the primary git operation, matching the design principle already established for the CMake Tools sync. + +**3. Windows `&&` compatibility.** Same fix already applied to the 8 CMake preset tasks last session (Windows PowerShell 5.1 doesn't support `&&`) — covered by the same `"windows"` override above, so no separate change needed. + +**4. Placement and organization.** The two new tasks and the `worktreeName` input go at the top of their respective arrays (matching cel-rs's placement and being the natural first stop for someone opening a new consumer project). Section-divider comments are added: + +- `// ============ Worktree Tasks ============` above the two new tasks +- `// ============ CMake Preset Tasks ============` above the existing "Configure & Build: Default Configuration" (the first pre-existing task) +- `// ============ Cleanup Tasks ============` above "Clean Build Directory (Active Config)" (the first pre-existing clean task) + +**5. Gitignore.** Both `.claude/worktrees/` and `.tokensave` added to `templates/.gitignore`, unanchored, matching cel-rs exactly — since the copied tasks generate both. + +## Process for this change + +Per your instruction: this work happens in an isolated worktree (default `.worktrees/` location — no existing worktree-directory convention in this repo to follow, and no explicit override given for the controller's own dev tooling), finishing with a pushed branch + PR rather than a direct push to `main`. From 51c856d81d1507f73b2de2bde151020ccebc229d Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 10:06:40 -0700 Subject: [PATCH 2/7] Add implementation plan for worktree create/remove VSCode tasks Co-Authored-By: Claude Sonnet 5 --- .../2026-07-16-worktree-vscode-tasks-plan.md | 510 ++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md diff --git a/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md new file mode 100644 index 0000000..f474bcc --- /dev/null +++ b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md @@ -0,0 +1,510 @@ +# Worktree Create/Remove VSCode Tasks Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add cel-rs's "worktree: create" / "worktree: remove" VS Code tasks (git-worktree management with tokensave integration) to `templates/.vscode/tasks.json`, with the tokensave calls made best-effort so consumers without `tokensave` installed still get a fully working worktree create/remove. + +**Architecture:** `templates/.vscode/tasks.json` converts from strict JSON to JSONC (adding `//` section-divider comments, matching cel-rs's style); one new `promptString` input and two new tasks are added at the top of their respective arrays. `templates/.gitignore` gains two entries for the directories/files those tasks generate. Neither file needs re-registering in `cmake/cpp-library-setup.cmake` — both are already in `TEMPLATE_FILES` from prior work. + +**Tech Stack:** VS Code `tasks.json` schema (shell tasks, `promptString` inputs, per-platform `"windows"` overrides), `git worktree`, the `tokensave` CLI. + +## Global Constraints + +- Design spec: `docs/superpowers/specs/2026-07-16-worktree-vscode-tasks-design.md` — follow it exactly. +- The new tasks and input go at the **top** of their arrays (matching cel-rs's placement). +- `templates/.vscode/tasks.json` is no longer strict JSON — validate it going forward with the comment-tolerant regex check in Task 1, not `python3 -m json.tool` directly. +- Tokensave calls in both new tasks must be best-effort: skipped cleanly if `tokensave` isn't on PATH, and non-fatal even if present-but-erroring — never able to block `git worktree add`/`git worktree remove` or (for create) `code --new-window`. +- No changes to `cmake/cpp-library-setup.cmake`, `templates/.vscode/extensions.json`, or cpp-library's own root `.vscode/` — out of scope per the spec. + +--- + +### Task 1: Add worktree tasks to `templates/.vscode/tasks.json` + +**Files:** +- Modify: `templates/.vscode/tasks.json` (full-file replacement — every existing task gains no functional change, only the addition of section-divider comments and the two new tasks/input) + +**Interfaces:** +- Produces: `worktree: create` and `worktree: remove` tasks, and a `worktreeName` promptString input, all live at `templates/.vscode/tasks.json`. Task 3 verifies these directly; no other task depends on their internals. + +- [ ] **Step 1: Replace the full contents of `templates/.vscode/tasks.json`** + +Replace the entire file with exactly this content: + +```json +{ + "version": "2.0.0", + "inputs": [ + { "id": "worktreeName", "type": "promptString", "description": "Worktree name (e.g. my-feature) — branch will be worktree-" }, + { "id": "setConfigurePreset-default", "type": "command", "command": "cmake.setConfigurePreset", "args": "default" }, + { "id": "setConfigurePreset-test", "type": "command", "command": "cmake.setConfigurePreset", "args": "test" }, + { "id": "setConfigurePreset-docs", "type": "command", "command": "cmake.setConfigurePreset", "args": "docs" }, + { "id": "setConfigurePreset-clang-tidy", "type": "command", "command": "cmake.setConfigurePreset", "args": "clang-tidy" }, + { "id": "setConfigurePreset-init", "type": "command", "command": "cmake.setConfigurePreset", "args": "init" }, + { "id": "setConfigurePreset-install", "type": "command", "command": "cmake.setConfigurePreset", "args": "install" }, + { "id": "setBuildPreset-default", "type": "command", "command": "cmake.setBuildPreset", "args": "default" }, + { "id": "setBuildPreset-test", "type": "command", "command": "cmake.setBuildPreset", "args": "test" }, + { "id": "setBuildPreset-docs", "type": "command", "command": "cmake.setBuildPreset", "args": "docs" }, + { "id": "setBuildPreset-clang-tidy", "type": "command", "command": "cmake.setBuildPreset", "args": "clang-tidy" }, + { "id": "setBuildPreset-init", "type": "command", "command": "cmake.setBuildPreset", "args": "init" }, + { "id": "setBuildPreset-install", "type": "command", "command": "cmake.setBuildPreset", "args": "install" }, + { "id": "setTestPreset-test", "type": "command", "command": "cmake.setTestPreset", "args": "test" }, + { "id": "setTestPreset-clang-tidy", "type": "command", "command": "cmake.setTestPreset", "args": "clang-tidy" } + ], + "tasks": [ + // ============ Worktree Tasks ============ + { + "label": "worktree: create", + "type": "shell", + "command": "git worktree add \".claude/worktrees/${input:worktreeName}\" -b \"worktree-${input:worktreeName}\" && (command -v tokensave >/dev/null 2>&1 && tokensave init \".claude/worktrees/${input:worktreeName}\" && tokensave branch add \"worktree-${input:worktreeName}\" --path \".claude/worktrees/${input:worktreeName}\" || true) && code --new-window \".claude/worktrees/${input:worktreeName}\"", + "options": { + "cwd": "${workspaceFolder}" + }, + "windows": { + "command": "git worktree add \".claude/worktrees/${input:worktreeName}\" -b \"worktree-${input:worktreeName}\" && (where tokensave >nul 2>&1 && (tokensave init \".claude/worktrees/${input:worktreeName}\" && tokensave branch add \"worktree-${input:worktreeName}\" --path \".claude/worktrees/${input:worktreeName}\") || ver>nul) && code --new-window \".claude/worktrees/${input:worktreeName}\"", + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + }, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + }, + { + "label": "worktree: remove", + "type": "shell", + "command": "git worktree remove \".claude/worktrees/${input:worktreeName}\" && (command -v tokensave >/dev/null 2>&1 && tokensave branch gc || true)", + "options": { + "cwd": "${workspaceFolder}" + }, + "windows": { + "command": "git worktree remove \".claude/worktrees/${input:worktreeName}\" && (where tokensave >nul 2>&1 && tokensave branch gc || ver>nul)", + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + }, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + }, + // ============ CMake Preset Tasks ============ + { + "label": "Configure & Build: Default Configuration", + "type": "shell", + "command": "cmake --preset default && cmake --build --preset default", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-default} ${input:setBuildPreset-default}" + } + }, + "group": { "kind": "build", "isDefault": true }, + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Default configuration for building the library Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Configure & Build: Test Configuration", + "type": "shell", + "command": "cmake --preset test && cmake --build --preset test", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-test} ${input:setBuildPreset-test}" + } + }, + "group": "build", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Configuration for building and running tests Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Configure & Build: Documentation Configuration", + "type": "shell", + "command": "cmake --preset docs && cmake --build --preset docs", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-docs} ${input:setBuildPreset-docs}" + } + }, + "group": "build", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Configuration for building documentation Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Configure & Build: Clang-Tidy Configuration", + "type": "shell", + "command": "cmake --preset clang-tidy && cmake --build --preset clang-tidy", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-clang-tidy} ${input:setBuildPreset-clang-tidy}" + } + }, + "group": "build", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Configuration for running clang-tidy static analysis Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Configure & Build: Initialize Templates", + "type": "shell", + "command": "cmake --preset init && cmake --build --preset init", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-init} ${input:setBuildPreset-init}" + } + }, + "group": "build", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Force regeneration of template files (CMakePresets.json, CI, etc.) Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Configure & Build: Install Configuration", + "type": "shell", + "command": "cmake --preset install && cmake --build --preset install", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-install} ${input:setBuildPreset-install}" + } + }, + "group": "build", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Release build for installation with CPM_USE_LOCAL_PACKAGES enabled for testing installed packages Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Build & Test: Run All Tests", + "type": "shell", + "command": "cmake --preset test && cmake --build --preset test && ctest --preset test", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-test} ${input:setBuildPreset-test} ${input:setTestPreset-test}" + } + }, + "group": { "kind": "test", "isDefault": true }, + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Configuration for building and running tests Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + { + "label": "Build & Test: Run Tests with Clang-Tidy", + "type": "shell", + "command": "cmake --preset clang-tidy && cmake --build --preset clang-tidy && ctest --preset clang-tidy", + "options": { + "env": { + "CMAKE_TOOLS_SYNC": "${input:setConfigurePreset-clang-tidy} ${input:setBuildPreset-clang-tidy} ${input:setTestPreset-clang-tidy}" + } + }, + "group": "test", + "problemMatcher": ["$gcc", "$msCompile"], + "detail": "Configuration for running clang-tidy static analysis Requires the CMake Tools extension (ms-vscode.cmake-tools) — without it, this task fails to start.", + "windows": { + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + } + }, + // ============ Cleanup Tasks ============ + { + "label": "Clean Build Directory (Active Config)", + "type": "shell", + "command": "cmake -E rm -rf \"${command:cmake.buildDirectory}\"", + "detail": "Deletes the build directory for the CMake Tools extension's currently active configure preset. Requires the CMake Tools extension with an active preset selected." + }, + { + "label": "Clean Build Directory (All Presets)", + "type": "shell", + "command": "cmake -E rm -rf \"${workspaceFolder}/build\"", + "detail": "Deletes the entire build/ directory, covering every preset's binary directory." + }, + { + "label": "Clean CPM Cache", + "type": "shell", + "command": "cmake -E rm -rf \"${workspaceFolder}/.cache/cpm\"", + "detail": "Deletes the CPM dependency source cache (CPM_SOURCE_CACHE)." + } + ] +} +``` + +- [ ] **Step 2: Validate the file as JSONC (comment-tolerant)** + +Run: + +```bash +python3 -c ' +import json, re +text = open("templates/.vscode/tasks.json").read() +text = re.sub(r"^[ \t]*//.*$", "", text, flags=re.MULTILINE) +data = json.loads(text) +print("OK, tasks:", len(data["tasks"]), "inputs:", len(data["inputs"])) +' +``` + +Expected: `OK, tasks: 13 inputs: 15` (11 pre-existing tasks + 2 new; 14 pre-existing inputs + 1 new). + +- [ ] **Step 3: Commit** + +```bash +git add templates/.vscode/tasks.json +git commit -m "Add worktree create/remove VSCode tasks with best-effort tokensave sync" +``` + +--- + +### Task 2: Gitignore the worktree directory and tokensave state + +**Files:** +- Modify: `templates/.gitignore` + +**Interfaces:** +- Consumes: nothing from Task 1 (independent file). + +- [ ] **Step 1: Add the two new entries** + +Change `templates/.gitignore` from: + +``` +# Auto-generated from cpp-library (https://github.com/stlab/cpp-library) +# Do not edit this file directly - it will be overwritten when templates are regenerated + +/.cpm-cache +/.cache +/build +.DS_Store +compile_commands.json +``` + +to: + +``` +# Auto-generated from cpp-library (https://github.com/stlab/cpp-library) +# Do not edit this file directly - it will be overwritten when templates are regenerated + +/.cpm-cache +/.cache +/build +.DS_Store +compile_commands.json +.claude/worktrees/ +.tokensave +``` + +- [ ] **Step 2: Commit** + +```bash +git add templates/.gitignore +git commit -m "Gitignore worktree directory and tokensave state in consumer template" +``` + +--- + +### Task 3: End-to-end verification + +**Files:** none (scratch verification only; no repository changes). + +**Interfaces:** +- Consumes: `templates/.vscode/tasks.json` and `templates/.gitignore` from Tasks 1 and 2. + +This environment has both `tokensave` and `code` CLIs on `PATH` (confirm with `command -v tokensave` and `command -v code` — both should print a path). That lets the "tokensave present" branch of each task be tested for real. The "tokensave absent" branch is tested by substituting a guaranteed-nonexistent command name (`tokensave-simulated-missing`) in place of `tokensave` in a copy of the command string — this exercises the exact same conditional logic without needing to hide the real binary via PATH manipulation (which is fragile to test correctly across Git Bash / cmd.exe boundary translation). Actually running `code --new-window` is skipped in automated verification (it would open a real GUI window); `code --version` is used instead as a lightweight liveness check of the same binary the real command would invoke. + +- [ ] **Step 1: Confirm both CLIs are present** + +```bash +command -v tokensave +command -v code +``` + +Expected: both print a file path, exit 0. + +- [ ] **Step 2: Verify the template copies correctly into a scratch consumer project** + +```bash +SCRATCH="$(mktemp -d)" +mkdir -p "$SCRATCH/cmake" "$SCRATCH/include/wtcheck/wtcheck" +curl -fsSL https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake -o "$SCRATCH/cmake/CPM.cmake" +echo "#pragma once" > "$SCRATCH/include/wtcheck/wtcheck.hpp" +cat > "$SCRATCH/CMakeLists.txt" <<'EOF' +cmake_minimum_required(VERSION 3.24) +include(cmake/CPM.cmake) +CPMAddPackage( + NAME cpp-library + SOURCE_DIR "D:/repos/github.com/stlab/cpp-library" +) +include("${cpp-library_SOURCE_DIR}/cpp-library.cmake") +cpp_library_enable_dependency_tracking() +project(wtcheck) +include(CTest) +cpp_library_setup( + DESCRIPTION "Scratch consumer project for worktree-task template verification" + NAMESPACE wtcheck + HEADERS "include/wtcheck/wtcheck.hpp" +) +EOF +cmake -S "$SCRATCH" -B "$SCRATCH/build" 2>&1 | grep "Copied template file" +diff "$SCRATCH/.vscode/tasks.json" templates/.vscode/tasks.json +diff "$SCRATCH/.gitignore" templates/.gitignore +``` + +Expected: the `grep` shows `-- Copied template file: .vscode/tasks.json` and `-- Copied template file: .gitignore` among its output (confirming both were freshly copied, not skipped as already-present), and both `diff` commands produce no output (byte-identical copies). + +- [ ] **Step 3: Set up a scratch git repo for command-behavior testing** + +```bash +CMDTEST="$(mktemp -d)" +cd "$CMDTEST" +git init -q +git commit -q --allow-empty -m "init" +``` + +- [ ] **Step 4: Test "worktree: create" (bash form, tokensave present)** + +Run the exact command string from the task, substituting `myfeature` for `${input:worktreeName}`: + +```bash +cd "$CMDTEST" +git worktree add ".claude/worktrees/myfeature" -b "worktree-myfeature" && (command -v tokensave >/dev/null 2>&1 && tokensave init ".claude/worktrees/myfeature" && tokensave branch add "worktree-myfeature" --path ".claude/worktrees/myfeature" || true) +echo "EXIT: $?" +git worktree list +``` + +Expected: `EXIT: 0`, and `git worktree list` shows both the main worktree and `.claude/worktrees/myfeature` on branch `worktree-myfeature`. + +- [ ] **Step 5: Test "worktree: remove" (bash form, tokensave present)** + +```bash +cd "$CMDTEST" +git worktree remove ".claude/worktrees/myfeature" && (command -v tokensave >/dev/null 2>&1 && tokensave branch gc || true) +echo "EXIT: $?" +git worktree list +``` + +Expected: `EXIT: 0`, and `git worktree list` no longer shows `.claude/worktrees/myfeature`. + +- [ ] **Step 6: Test "worktree: create" / "worktree: remove" (bash form, tokensave simulated absent)** + +Same as Steps 4–5, but with `tokensave` replaced by a nonexistent command name in the copied string: + +```bash +cd "$CMDTEST" +git worktree add ".claude/worktrees/myfeature2" -b "worktree-myfeature2" && (command -v tokensave-simulated-missing >/dev/null 2>&1 && tokensave-simulated-missing init ".claude/worktrees/myfeature2" && tokensave-simulated-missing branch add "worktree-myfeature2" --path ".claude/worktrees/myfeature2" || true) +echo "CREATE EXIT: $?" +git worktree list + +git worktree remove ".claude/worktrees/myfeature2" && (command -v tokensave-simulated-missing >/dev/null 2>&1 && tokensave-simulated-missing branch gc || true) +echo "REMOVE EXIT: $?" +git worktree list +``` + +Expected: both `EXIT: 0` lines, worktree appears after create and is gone after remove — proving the worktree is created/removed successfully even when the tokensave binary doesn't exist. + +- [ ] **Step 7: Test the Windows/cmd.exe form (tokensave present)** + +```bash +cd "$CMDTEST" +cmd.exe /d /c "git worktree add \".claude/worktrees/myfeature3\" -b \"worktree-myfeature3\" && (where tokensave >nul 2>&1 && (tokensave init \".claude/worktrees/myfeature3\" && tokensave branch add \"worktree-myfeature3\" --path \".claude/worktrees/myfeature3\") || ver>nul)" +echo "EXIT: $?" +git worktree list +cmd.exe /d /c "git worktree remove \".claude/worktrees/myfeature3\" && (where tokensave >nul 2>&1 && tokensave branch gc || ver>nul)" +echo "EXIT: $?" +git worktree list +``` + +Expected: both exit 0; worktree present after create, gone after remove. + +- [ ] **Step 8: Test the Windows/cmd.exe form (tokensave simulated absent)** + +```bash +cd "$CMDTEST" +cmd.exe /d /c "git worktree add \".claude/worktrees/myfeature4\" -b \"worktree-myfeature4\" && (where tokensave-simulated-missing >nul 2>&1 && (tokensave-simulated-missing init \".claude/worktrees/myfeature4\" && tokensave-simulated-missing branch add \"worktree-myfeature4\" --path \".claude/worktrees/myfeature4\") || ver>nul)" +echo "EXIT: $?" +git worktree list +cmd.exe /d /c "git worktree remove \".claude/worktrees/myfeature4\" && (where tokensave-simulated-missing >nul 2>&1 && tokensave-simulated-missing branch gc || ver>nul)" +echo "EXIT: $?" +git worktree list +``` + +Expected: both exit 0; worktree present after create, gone after remove — proving the cmd.exe conditional syntax (`where` / `ver>nul`) behaves the same as the bash form when the binary is absent. + +- [ ] **Step 9: Confirm `code` CLI liveness without opening a new window** + +```bash +code --version +``` + +Expected: prints a version string, exit 0. (The actual `&& code --new-window "..."` invocation at the end of the real task is not exercised here — opening a real editor window is outside what automated headless verification should do. Note this explicitly in the report, same as the CMake Tools extension-dependent behaviors noted in the prior feature's verification.) + +- [ ] **Step 10: Clean up scratch directories** + +```bash +rm -rf "$SCRATCH" "$CMDTEST" +``` + +(No commit — this task produces no repository changes.) + +## Self-Review Notes + +- **Spec coverage:** JSONC conversion (Task 1, Step 1-2), best-effort tokensave wrapping for both tasks and both platforms (Task 1, Step 1; verified in Task 3 Steps 4-8), section-divider comments (Task 1, Step 1), gitignore additions (Task 2), placement at top of arrays (Task 1, Step 1) — all covered. +- **Placeholder scan:** none found; every step has literal content. +- **Type/name consistency:** `worktreeName` input id matches across both new tasks' `${input:worktreeName}` references; no drift. From b7c56642a6d544cf1841bac29ed5cfa784ac7f2a Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 10:13:39 -0700 Subject: [PATCH 3/7] Add worktree create/remove VSCode tasks with best-effort tokensave sync --- templates/.vscode/tasks.json | 80 ++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/templates/.vscode/tasks.json b/templates/.vscode/tasks.json index 67add4c..ed49151 100644 --- a/templates/.vscode/tasks.json +++ b/templates/.vscode/tasks.json @@ -1,6 +1,69 @@ { "version": "2.0.0", + "inputs": [ + { "id": "worktreeName", "type": "promptString", "description": "Worktree name (e.g. my-feature) — branch will be worktree-" }, + { "id": "setConfigurePreset-default", "type": "command", "command": "cmake.setConfigurePreset", "args": "default" }, + { "id": "setConfigurePreset-test", "type": "command", "command": "cmake.setConfigurePreset", "args": "test" }, + { "id": "setConfigurePreset-docs", "type": "command", "command": "cmake.setConfigurePreset", "args": "docs" }, + { "id": "setConfigurePreset-clang-tidy", "type": "command", "command": "cmake.setConfigurePreset", "args": "clang-tidy" }, + { "id": "setConfigurePreset-init", "type": "command", "command": "cmake.setConfigurePreset", "args": "init" }, + { "id": "setConfigurePreset-install", "type": "command", "command": "cmake.setConfigurePreset", "args": "install" }, + { "id": "setBuildPreset-default", "type": "command", "command": "cmake.setBuildPreset", "args": "default" }, + { "id": "setBuildPreset-test", "type": "command", "command": "cmake.setBuildPreset", "args": "test" }, + { "id": "setBuildPreset-docs", "type": "command", "command": "cmake.setBuildPreset", "args": "docs" }, + { "id": "setBuildPreset-clang-tidy", "type": "command", "command": "cmake.setBuildPreset", "args": "clang-tidy" }, + { "id": "setBuildPreset-init", "type": "command", "command": "cmake.setBuildPreset", "args": "init" }, + { "id": "setBuildPreset-install", "type": "command", "command": "cmake.setBuildPreset", "args": "install" }, + { "id": "setTestPreset-test", "type": "command", "command": "cmake.setTestPreset", "args": "test" }, + { "id": "setTestPreset-clang-tidy", "type": "command", "command": "cmake.setTestPreset", "args": "clang-tidy" } + ], "tasks": [ + // ============ Worktree Tasks ============ + { + "label": "worktree: create", + "type": "shell", + "command": "git worktree add \".claude/worktrees/${input:worktreeName}\" -b \"worktree-${input:worktreeName}\" && (command -v tokensave >/dev/null 2>&1 && tokensave init \".claude/worktrees/${input:worktreeName}\" && tokensave branch add \"worktree-${input:worktreeName}\" --path \".claude/worktrees/${input:worktreeName}\" || true) && code --new-window \".claude/worktrees/${input:worktreeName}\"", + "options": { + "cwd": "${workspaceFolder}" + }, + "windows": { + "command": "git worktree add \".claude/worktrees/${input:worktreeName}\" -b \"worktree-${input:worktreeName}\" && (where tokensave >nul 2>&1 && (tokensave init \".claude/worktrees/${input:worktreeName}\" && tokensave branch add \"worktree-${input:worktreeName}\" --path \".claude/worktrees/${input:worktreeName}\") || ver>nul) && code --new-window \".claude/worktrees/${input:worktreeName}\"", + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + }, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + }, + { + "label": "worktree: remove", + "type": "shell", + "command": "git worktree remove \".claude/worktrees/${input:worktreeName}\" && (command -v tokensave >/dev/null 2>&1 && tokensave branch gc || true)", + "options": { + "cwd": "${workspaceFolder}" + }, + "windows": { + "command": "git worktree remove \".claude/worktrees/${input:worktreeName}\" && (where tokensave >nul 2>&1 && tokensave branch gc || ver>nul)", + "options": { + "shell": { + "executable": "cmd.exe", + "args": ["/d", "/c"] + } + } + }, + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "dedicated" + } + }, + // ============ CMake Preset Tasks ============ { "label": "Configure & Build: Default Configuration", "type": "shell", @@ -169,6 +232,7 @@ } } }, + // ============ Cleanup Tasks ============ { "label": "Clean Build Directory (Active Config)", "type": "shell", @@ -187,21 +251,5 @@ "command": "cmake -E rm -rf \"${workspaceFolder}/.cache/cpm\"", "detail": "Deletes the CPM dependency source cache (CPM_SOURCE_CACHE)." } - ], - "inputs": [ - { "id": "setConfigurePreset-default", "type": "command", "command": "cmake.setConfigurePreset", "args": "default" }, - { "id": "setConfigurePreset-test", "type": "command", "command": "cmake.setConfigurePreset", "args": "test" }, - { "id": "setConfigurePreset-docs", "type": "command", "command": "cmake.setConfigurePreset", "args": "docs" }, - { "id": "setConfigurePreset-clang-tidy", "type": "command", "command": "cmake.setConfigurePreset", "args": "clang-tidy" }, - { "id": "setConfigurePreset-init", "type": "command", "command": "cmake.setConfigurePreset", "args": "init" }, - { "id": "setConfigurePreset-install", "type": "command", "command": "cmake.setConfigurePreset", "args": "install" }, - { "id": "setBuildPreset-default", "type": "command", "command": "cmake.setBuildPreset", "args": "default" }, - { "id": "setBuildPreset-test", "type": "command", "command": "cmake.setBuildPreset", "args": "test" }, - { "id": "setBuildPreset-docs", "type": "command", "command": "cmake.setBuildPreset", "args": "docs" }, - { "id": "setBuildPreset-clang-tidy", "type": "command", "command": "cmake.setBuildPreset", "args": "clang-tidy" }, - { "id": "setBuildPreset-init", "type": "command", "command": "cmake.setBuildPreset", "args": "init" }, - { "id": "setBuildPreset-install", "type": "command", "command": "cmake.setBuildPreset", "args": "install" }, - { "id": "setTestPreset-test", "type": "command", "command": "cmake.setTestPreset", "args": "test" }, - { "id": "setTestPreset-clang-tidy", "type": "command", "command": "cmake.setTestPreset", "args": "clang-tidy" } ] } From e221ba4306c2486311c6818e3b4937651c25d610 Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 10:17:45 -0700 Subject: [PATCH 4/7] Gitignore worktree directory and tokensave state in consumer template --- templates/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/.gitignore b/templates/.gitignore index d22a445..37c6abd 100644 --- a/templates/.gitignore +++ b/templates/.gitignore @@ -6,3 +6,5 @@ /build .DS_Store compile_commands.json +.claude/worktrees/ +.tokensave From 6b3de62e4faaeb21602d335a090e6c707bb72ecd Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 10:33:42 -0700 Subject: [PATCH 5/7] Clarify Task 3 verification scope: create-task tests are a documented prefix, not the full command --- .../plans/2026-07-16-worktree-vscode-tasks-plan.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md index f474bcc..e1e6d6c 100644 --- a/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md +++ b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md @@ -418,9 +418,11 @@ git init -q git commit -q --allow-empty -m "init" ``` +**Note on Steps 4, 6, 7, 8 below:** each of these steps tests only the `git worktree ... && (tokensave ... || true)` (or `|| ver>nul`) portion of the task's command string — a *prefix* that stops right before the trailing `&& code --new-window "..."` segment, not the task's full command. This is intentional, not an oversight: in both the bash and Windows forms, the parenthesized tokensave subshell always resolves to exit 0 via its trailing `|| true` / `|| ver>nul` fallback, regardless of whether tokensave succeeds, is absent, or errors. That means the `&&` immediately before `code --new-window` is guaranteed to be reached in every case these steps exercise — so testing up through that point, combined with the separate `code --version` liveness check in Step 9, together cover the task's real behavior without needing to launch a GUI window during automated verification. + - [ ] **Step 4: Test "worktree: create" (bash form, tokensave present)** -Run the exact command string from the task, substituting `myfeature` for `${input:worktreeName}`: +Run the git+tokensave portion of the task's command string (omitting the trailing `&& code --new-window ...` — see the note above and Step 9 for why), substituting `myfeature` for `${input:worktreeName}`: ```bash cd "$CMDTEST" @@ -444,7 +446,7 @@ Expected: `EXIT: 0`, and `git worktree list` no longer shows `.claude/worktrees/ - [ ] **Step 6: Test "worktree: create" / "worktree: remove" (bash form, tokensave simulated absent)** -Same as Steps 4–5, but with `tokensave` replaced by a nonexistent command name in the copied string: +Same as Steps 4–5 — again using only the git+tokensave prefix, omitting the trailing `&& code --new-window ...` (see the note before Step 4) — but with `tokensave` replaced by a nonexistent command name in the copied string: ```bash cd "$CMDTEST" @@ -461,6 +463,8 @@ Expected: both `EXIT: 0` lines, worktree appears after create and is gone after - [ ] **Step 7: Test the Windows/cmd.exe form (tokensave present)** +As with Steps 4 and 6, this exercises only the git+tokensave prefix of the `windows.command` string, omitting the trailing `&& code --new-window ...` (see the note before Step 4). + ```bash cd "$CMDTEST" cmd.exe /d /c "git worktree add \".claude/worktrees/myfeature3\" -b \"worktree-myfeature3\" && (where tokensave >nul 2>&1 && (tokensave init \".claude/worktrees/myfeature3\" && tokensave branch add \"worktree-myfeature3\" --path \".claude/worktrees/myfeature3\") || ver>nul)" @@ -475,6 +479,8 @@ Expected: both exit 0; worktree present after create, gone after remove. - [ ] **Step 8: Test the Windows/cmd.exe form (tokensave simulated absent)** +Same prefix-only scope as Step 7 (see the note before Step 4) — the trailing `&& code --new-window ...` is not exercised here either. + ```bash cd "$CMDTEST" cmd.exe /d /c "git worktree add \".claude/worktrees/myfeature4\" -b \"worktree-myfeature4\" && (where tokensave-simulated-missing >nul 2>&1 && (tokensave-simulated-missing init \".claude/worktrees/myfeature4\" && tokensave-simulated-missing branch add \"worktree-myfeature4\" --path \".claude/worktrees/myfeature4\") || ver>nul)" From 7be049ad8fbdae5fcb110973a807a6872a99c17d Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 10:40:47 -0700 Subject: [PATCH 6/7] Add detail fields to worktree create/remove tasks Co-Authored-By: Claude Sonnet 5 --- templates/.vscode/tasks.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/.vscode/tasks.json b/templates/.vscode/tasks.json index ed49151..e1161ad 100644 --- a/templates/.vscode/tasks.json +++ b/templates/.vscode/tasks.json @@ -39,7 +39,8 @@ "presentation": { "reveal": "always", "panel": "dedicated" - } + }, + "detail": "Prompts for a name, creates a git worktree at .claude/worktrees/ on branch worktree-, best-effort syncs it with tokensave if installed, and opens it in a new window." }, { "label": "worktree: remove", @@ -61,7 +62,8 @@ "presentation": { "reveal": "always", "panel": "dedicated" - } + }, + "detail": "Prompts for a name, removes the git worktree at .claude/worktrees/, and best-effort garbage-collects tokensave's branch tracking if installed." }, // ============ CMake Preset Tasks ============ { From 0c92a113ff76e4496f0ec92e60e71648b70e7c30 Mon Sep 17 00:00:00 2001 From: Sean Parent Date: Thu, 16 Jul 2026 12:13:45 -0700 Subject: [PATCH 7/7] Fix plan doc: mark tasks.json snippet as jsonc, add missing detail fields The Step 1 "exactly this content" snippet had gone stale relative to the shipped templates/.vscode/tasks.json after the final-review detail-field addition (7be049a). Also relabels the code fence jsonc since it contains // comments, not strict JSON. Co-Authored-By: Claude Sonnet 5 --- .../plans/2026-07-16-worktree-vscode-tasks-plan.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md index e1e6d6c..8c469ac 100644 --- a/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md +++ b/docs/superpowers/plans/2026-07-16-worktree-vscode-tasks-plan.md @@ -30,7 +30,7 @@ Replace the entire file with exactly this content: -```json +```jsonc { "version": "2.0.0", "inputs": [ @@ -72,7 +72,8 @@ Replace the entire file with exactly this content: "presentation": { "reveal": "always", "panel": "dedicated" - } + }, + "detail": "Prompts for a name, creates a git worktree at .claude/worktrees/ on branch worktree-, best-effort syncs it with tokensave if installed, and opens it in a new window." }, { "label": "worktree: remove", @@ -94,7 +95,8 @@ Replace the entire file with exactly this content: "presentation": { "reveal": "always", "panel": "dedicated" - } + }, + "detail": "Prompts for a name, removes the git worktree at .claude/worktrees/, and best-effort garbage-collects tokensave's branch tracking if installed." }, // ============ CMake Preset Tasks ============ {