diff --git a/.gitignore b/.gitignore index a704f33..6dc05d7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,19 @@ node_modules/ # Build and package artifacts dist/ build/ +out/ coverage/ +.nyc_output/ *.tgz +*.tsbuildinfo + +# Planning and design artifacts +docs/superpowers/ + +# Bun caches and legacy lockfiles +.bun/ +.bun-install/ +bun.lockb # Logs *.log @@ -19,9 +30,20 @@ pnpm-debug.log* .env.* !.env.example +# Caches and temporary files +.cache/ +.temp/ +tmp/ +temp/ +.eslintcache +*.tmp +*.temp + # Editor directories .idea/ .vscode/ +*.swp +*.swo # OS files .DS_Store diff --git a/docs/superpowers/plans/2026-03-25-skills-vault-cli-package-reorg.md b/docs/superpowers/plans/2026-03-25-skills-vault-cli-package-reorg.md deleted file mode 100644 index 1150735..0000000 --- a/docs/superpowers/plans/2026-03-25-skills-vault-cli-package-reorg.md +++ /dev/null @@ -1,389 +0,0 @@ -# Skills Vault CLI Package Reorganization 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:** Reorganize the repository into a publishable pure CLI package named `@xixu-me/skills-vault` with the public binary `skvlt`, while preserving the existing `backup` and `restore` behavior. - -**Architecture:** Introduce a single CLI dispatcher in `src/cli.ts`, move command orchestration into `src/commands/`, isolate non-public helpers under `src/internal/`, and relocate tests into `test/` with behavior-oriented names. The migration should preserve behavior through TDD: write the failing tests first, then move logic, then remove the legacy `scripts/` production layout. - -**Tech Stack:** Bun 1.3.x, TypeScript, Bun test runner, Node-compatible filesystem/process APIs - ---- - -## File Map - -### Create - -- `src/cli.ts` -- `src/commands/backup.ts` -- `src/commands/restore.ts` -- `src/internal/args/parse-backup-args.ts` -- `src/internal/args/parse-restore-args.ts` -- `src/internal/install/resolve-install-concurrency.ts` -- `src/internal/install/run-with-concurrency.ts` -- `src/internal/manifest/build-manifest.ts` -- `src/internal/manifest/parse-manifest.ts` -- `src/internal/paths/defaults.ts` -- `src/internal/process/run-bunx.ts` -- `test/cli.test.ts` -- `test/backup.test.ts` -- `test/restore.test.ts` -- `test/install-concurrency.test.ts` -- `README.md` - -### Modify - -- `package.json` - -### Delete After Migration - -- `scripts/backup.ts` -- `scripts/restore.ts` -- `scripts/restore-lib.ts` -- `scripts/restore-lib.test.ts` - -## Task 1: Establish the CLI Shell and Package Metadata - -**Files:** - -- Create: `src/cli.ts` -- Create: `test/cli.test.ts` -- Modify: `package.json` - -- [ ] **Step 1: Write the failing CLI dispatch test** - -```ts -import { expect, test } from "bun:test"; -import { runCli } from "../src/cli"; - -test("dispatches the restore command", async () => { - const result = await runCli(["restore", "--help"]); - expect(result.exitCode).toBe(0); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `bun test test/cli.test.ts` -Expected: FAIL because `../src/cli` does not exist yet. - -- [ ] **Step 3: Write minimal CLI implementation** - -```ts -type CliResult = { exitCode: number }; - -export async function runCli(argv: string[]): Promise { - const [command] = argv; - if (command === "backup") { - return { exitCode: 0 }; - } - if (command === "restore") { - return { exitCode: 0 }; - } - console.error("Usage: skvlt "); - return { exitCode: 1 }; -} - -if (import.meta.main) { - const result = await runCli(Bun.argv.slice(2)); - process.exit(result.exitCode); -} -``` - -- [ ] **Step 4: Update package metadata for the new CLI** - -```json -{ - "name": "@xixu-me/skills-vault", - "bin": { - "skvlt": "./src/cli.ts" - }, - "scripts": { - "backup": "bun run ./src/cli.ts backup", - "backup:dry-run": "bun run ./src/cli.ts backup --dry-run", - "restore": "bun run ./src/cli.ts restore", - "restore:dry-run": "bun run ./src/cli.ts restore --dry-run" - } -} -``` - -- [ ] **Step 5: Run test to verify it passes** - -Run: `bun test test/cli.test.ts` -Expected: PASS - -- [ ] **Step 6: Smoke test the top-level CLI** - -Run: `bun run ./src/cli.ts` -Expected: exit code `1` and top-level usage text for `skvlt` - -- [ ] **Step 7: Commit** - -```bash -git add package.json src/cli.ts test/cli.test.ts -git commit -m "refactor(cli): add top-level skvlt entrypoint" -``` - -## Task 2: Move Backup Into Command and Internal Modules - -**Files:** - -- Create: `src/commands/backup.ts` -- Create: `src/internal/args/parse-backup-args.ts` -- Create: `src/internal/manifest/build-manifest.ts` -- Create: `src/internal/paths/defaults.ts` -- Create: `src/internal/process/run-bunx.ts` -- Create: `test/backup.test.ts` -- Modify: `src/cli.ts` -- Delete later: `scripts/backup.ts` - -- [ ] **Step 1: Write the failing backup dry-run test** - -```ts -import { expect, test } from "bun:test"; -import { runBackup } from "../src/commands/backup"; - -test("prints manifest YAML during backup dry-run", async () => { - const result = await runBackup(["--dry-run"]); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain("sources:"); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `bun test test/backup.test.ts` -Expected: FAIL because `../src/commands/backup` does not exist yet. - -- [ ] **Step 3: Extract shared process and path helpers** - -```ts -// src/internal/process/run-bunx.ts -export async function runBunx(args: string[]) { - const proc = Bun.spawn({ - cmd: ["bunx", ...args], - stdout: "pipe", - stderr: "pipe", - }); - const [stdout, stderr, exitCode] = await Promise.all([ - new Response(proc.stdout).text(), - new Response(proc.stderr).text(), - proc.exited, - ]); - return { stdout, stderr, exitCode }; -} -``` - -- [ ] **Step 4: Move backup orchestration into `src/commands/backup.ts`** - -```ts -export async function runBackup(argv: string[]) { - const options = parseBackupArgs(argv); - const installedSkillNames = await getInstalledSkillNames( - options.projectScope, - ); - const manifest = buildManifest(installedSkillNames, options.lockFilePath); - return options.dryRun - ? { exitCode: 0, stdout: manifest, stderr: "" } - : await writeBackupManifest(options.outputPath, manifest); -} -``` - -- [ ] **Step 5: Wire the CLI dispatcher to the backup command** - -Run: `bun test test/cli.test.ts test/backup.test.ts` -Expected: PASS - -- [ ] **Step 6: Smoke test backup dry-run through the new CLI** - -Run: `bun run ./src/cli.ts backup --dry-run` -Expected: prints YAML with `sources:` and exits `0` - -- [ ] **Step 7: Commit** - -```bash -git add src/cli.ts src/commands/backup.ts src/internal/args/parse-backup-args.ts src/internal/manifest/build-manifest.ts src/internal/paths/defaults.ts src/internal/process/run-bunx.ts test/backup.test.ts -git commit -m "refactor(backup): move backup flow into command modules" -``` - -## Task 3: Move Restore Concurrency Helpers Into Internal Install Modules - -**Files:** - -- Create: `src/internal/install/resolve-install-concurrency.ts` -- Create: `src/internal/install/run-with-concurrency.ts` -- Create: `test/install-concurrency.test.ts` -- Delete later: `scripts/restore-lib.ts` -- Delete later: `scripts/restore-lib.test.ts` - -- [ ] **Step 1: Copy the existing concurrency coverage into the new test location and add one naming assertion** - -```ts -import { expect, test } from "bun:test"; -import { resolveInstallConcurrency } from "../src/internal/install/resolve-install-concurrency"; -import { runWithConcurrency } from "../src/internal/install/run-with-concurrency"; - -test("resolveInstallConcurrency caps auto concurrency at task count", () => { - expect( - resolveInstallConcurrency({ taskCount: 2, availableParallelism: 16 }), - ).toBe(2); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `bun test test/install-concurrency.test.ts` -Expected: FAIL because the new install modules do not exist yet. - -- [ ] **Step 3: Move the concurrency implementations into focused internal files** - -```ts -// src/internal/install/resolve-install-concurrency.ts -export function resolveInstallConcurrency(options: ResolveOptions): number { - // keep half-of-available-parallelism default with safe caps -} - -// src/internal/install/run-with-concurrency.ts -export async function runWithConcurrency( - items: T[], - concurrency: number, - worker: Worker, - options: Options, -) { - // preserve bounded scheduling and continue-on-error semantics -} -``` - -- [ ] **Step 4: Run the concurrency tests to verify they pass** - -Run: `bun test test/install-concurrency.test.ts` -Expected: PASS - -- [ ] **Step 5: Commit** - -```bash -git add src/internal/install/resolve-install-concurrency.ts src/internal/install/run-with-concurrency.ts test/install-concurrency.test.ts -git commit -m "refactor(restore): isolate install concurrency helpers" -``` - -## Task 4: Move Restore Into Command and Manifest Modules - -**Files:** - -- Create: `src/commands/restore.ts` -- Create: `src/internal/args/parse-restore-args.ts` -- Create: `src/internal/manifest/parse-manifest.ts` -- Create: `test/restore.test.ts` -- Modify: `src/cli.ts` -- Modify: `src/internal/process/run-bunx.ts` -- Delete later: `scripts/restore.ts` - -- [ ] **Step 1: Write the failing restore dry-run test** - -```ts -import { expect, test } from "bun:test"; -import { runRestore } from "../src/commands/restore"; - -test("prints per-source install commands during restore dry-run", async () => { - const result = await runRestore(["--dry-run"]); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain("[dry-run] bunx skills add"); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -Run: `bun test test/restore.test.ts` -Expected: FAIL because `../src/commands/restore` does not exist yet. - -- [ ] **Step 3: Move manifest parsing and restore orchestration into the new structure** - -```ts -export async function runRestore(argv: string[]) { - const options = parseRestoreArgs(argv); - const manifest = parseManifest(options.manifestPath); - const plan = createRestorePlan(manifest, options); - return options.dryRun - ? previewRestorePlan(plan) - : await executeRestorePlan(plan, options); -} -``` - -- [ ] **Step 4: Reconnect CLI dispatch to the restore command** - -Run: `bun test test/cli.test.ts test/restore.test.ts test/install-concurrency.test.ts` -Expected: PASS - -- [ ] **Step 5: Smoke test restore dry-run through the CLI** - -Run: `bun run ./src/cli.ts restore --dry-run --concurrency 4 --only-source anthropics/skills` -Expected: prints dry-run commands and a concurrency summary using the new module layout - -- [ ] **Step 6: Commit** - -```bash -git add src/cli.ts src/commands/restore.ts src/internal/args/parse-restore-args.ts src/internal/manifest/parse-manifest.ts src/internal/process/run-bunx.ts test/restore.test.ts -git commit -m "refactor(restore): move restore flow into command modules" -``` - -## Task 5: Remove Legacy Script Layout and Finish Packaging - -**Files:** - -- Create: `README.md` -- Modify: `package.json` -- Delete: `scripts/backup.ts` -- Delete: `scripts/restore.ts` -- Delete: `scripts/restore-lib.ts` -- Delete: `scripts/restore-lib.test.ts` - -- [ ] **Step 1: Write the failing packaging/readme expectation test or checklist** - -```md -- package name is @xixu-me/skills-vault -- CLI docs use skvlt -- no production code remains under scripts/ -``` - -- [ ] **Step 2: Delete the legacy production script files after the new tests are green** - -Run: `rg --files scripts` -Expected: only temporary migration leftovers remain before deletion, then no production code files remain there - -- [ ] **Step 3: Write the README around the single supported CLI** - -````md -# Skills Vault - -## Install - -```bash -bun install -``` - -## Usage - -```bash -skvlt backup -skvlt restore --dry-run -``` -```` - -- [ ] **Step 4: Run full verification** - -Run: `bun test` -Expected: all tests pass - -Run: `bun run ./src/cli.ts backup --dry-run` -Expected: YAML manifest output - -Run: `bun run ./src/cli.ts restore --dry-run --only-source anthropics/skills` -Expected: dry-run install command output - -- [ ] **Step 5: Commit** - -```bash -git add package.json README.md src test -git rm scripts/backup.ts scripts/restore.ts scripts/restore-lib.ts scripts/restore-lib.test.ts -git commit -m "refactor(package): publish as skvlt CLI package" -``` diff --git a/docs/superpowers/specs/2026-03-25-cli-package-structure-design.md b/docs/superpowers/specs/2026-03-25-cli-package-structure-design.md deleted file mode 100644 index f8f8cd5..0000000 --- a/docs/superpowers/specs/2026-03-25-cli-package-structure-design.md +++ /dev/null @@ -1,287 +0,0 @@ -# Skills Vault CLI Package Structure Design - -**Date:** 2026-03-25 -**Status:** Proposed -**Scope:** Reorganize the repository into a publishable CLI package with a clear public entrypoint and cleaner internal file naming. - -## Goal - -Turn the repository from a small script-oriented workspace into a pure CLI package with: - -- one stable public command -- clear separation between command entrypoints and internal implementation -- file names that describe behavior instead of temporary script intent -- test files that map cleanly to CLI behavior and internal concurrency logic - -## Brand and Naming Contract - -- Product brand: `Skills Vault` -- Package scope: `@xixu-me` -- CLI binary: `skvlt` -- Repository name: `skills-vault` -- Fixed package name: `@xixu-me/skills-vault` - -## Current State - -The repository is currently organized around a `scripts/` folder: - -- `scripts/backup.ts` -- `scripts/restore.ts` -- `scripts/restore-lib.ts` - -This works for local execution, but it blurs a few boundaries: - -- public CLI entrypoints and internal implementation live in the same folder -- `restore-lib.ts` reads like a temporary helper rather than a long-term package module -- tests are currently colocated with script-era naming instead of package-era behavior naming -- the future published interface is not obvious from the repository layout - -## Design Principles - -1. Treat the package as a pure CLI product, not a general-purpose library. -2. Expose exactly one stable public command: `skvlt`. -3. Keep command orchestration separate from lower-level helpers. -4. Use descriptive file names such as `parse-manifest.ts` instead of generic names such as `utils.ts`. -5. Mark non-public code as internal so future maintainers do not mistake it for supported API surface. -6. Keep test layout behavior-oriented and stable across future refactors. - -## Target Structure - -```text -skills-vault/ - src/ - cli.ts - commands/ - backup.ts - restore.ts - internal/ - args/ - parse-backup-args.ts - parse-restore-args.ts - install/ - resolve-install-concurrency.ts - run-with-concurrency.ts - manifest/ - build-manifest.ts - parse-manifest.ts - paths/ - defaults.ts - process/ - run-bunx.ts - test/ - backup.test.ts - restore.test.ts - install-concurrency.test.ts - manifests/ - skills.yaml - package.json - README.md - LICENSE -``` - -## Responsibilities - -### `src/cli.ts` - -Top-level executable entrypoint. - -Responsibilities: - -- read the first subcommand -- dispatch to `backup` or `restore` -- print top-level help for invalid or missing commands -- normalize top-level error handling and exit codes - -It should not contain manifest parsing, installation logic, or path computation. - -### `src/commands/backup.ts` - -Backup command orchestration. - -Responsibilities: - -- parse backup-specific arguments -- read installed skills and lock metadata -- build manifest content -- write output or print dry-run content -- emit backup-focused user messages - -### `src/commands/restore.ts` - -Restore command orchestration. - -Responsibilities: - -- parse restore-specific arguments -- parse manifest content -- compute pending install work -- perform dry-run previews -- invoke bounded concurrent installation -- report per-source install progress and failures - -### `src/internal/args/*` - -Argument parsing only. - -Responsibilities: - -- transform raw argv into strongly shaped options -- validate numeric values such as concurrency -- keep parsing rules close to each command without mixing them into business logic - -### `src/internal/install/*` - -Restore-only install execution helpers. - -Responsibilities: - -- derive safe default concurrency from device parallelism -- cap configured concurrency to meaningful task counts -- run source installs with bounded concurrency -- preserve failure behavior for `continue-on-error` vs fail-fast execution - -### `src/internal/manifest/*` - -Manifest transformation logic. - -Responsibilities: - -- parse YAML-like manifest structure into typed in-memory state -- build manifest output from installed skills and lock file data - -### `src/internal/process/run-bunx.ts` - -Single process-launch wrapper. - -Responsibilities: - -- run `bunx` -- capture stdout, stderr, and exit code consistently -- avoid duplicating spawn logic in each command - -### `src/internal/paths/defaults.ts` - -Default path derivation. - -Responsibilities: - -- compute default manifest path -- compute default global lock file path -- keep default filesystem behavior centralized - -## Naming Rules - -The reorganization should adopt these naming conventions: - -- public entrypoints use short command-oriented names -- internal files use behavior names, not umbrella names -- avoid `lib.ts`, `utils.ts`, `helpers.ts`, or `common.ts` -- prefer one responsibility per file -- keep the `internal/` namespace explicit so the package does not accidentally imply a supported programmatic API - -Examples: - -- good: `parse-restore-args.ts` -- good: `run-with-concurrency.ts` -- poor: `restore-lib.ts` -- poor: `shared-utils.ts` - -## Public Interface - -The public interface becomes: - -```bash -skvlt backup -skvlt restore -skvlt restore --dry-run -``` - -This is the only documented public contract. - -Development-time convenience scripts may remain in `package.json`, but they should call the new CLI entrypoint rather than pointing at legacy script files. The repository should no longer treat `scripts/*.ts` paths as public or stable. - -## Migration Plan - -1. Create `src/`, `src/commands/`, `src/internal/`, and `test/`. -2. Move backup orchestration from `scripts/backup.ts` into `src/commands/backup.ts`. -3. Move restore orchestration from `scripts/restore.ts` into `src/commands/restore.ts`. -4. Split `scripts/restore-lib.ts` into `src/internal/install/resolve-install-concurrency.ts` and `src/internal/install/run-with-concurrency.ts`. -5. Extract shared `bunx` process logic into `src/internal/process/run-bunx.ts`. -6. Extract default paths into `src/internal/paths/defaults.ts`. -7. Extract command-specific argv parsing into `src/internal/args/`. -8. Move tests into `test/` and rename them to match behavior-level ownership. -9. Remove `scripts/` as a production code directory. -10. Update `package.json` so the package name is `@xixu-me/skills-vault` and the published CLI entrypoint is `skvlt`. -11. Add a `README.md` that documents `skvlt` as the single supported entrypoint. - -## Error Handling - -The structure change should preserve current operational semantics: - -- invalid CLI input exits with code `1` -- dry-run never mutates install state -- restore fail-fast behavior remains the default -- `--continue-on-error` continues remaining source installs and reports final failures -- concurrency remains bounded and does not exceed useful work count - -## Testing Strategy - -The new layout should support three main testing layers: - -### `test/backup.test.ts` - -- backup command option parsing -- manifest generation behavior -- dry-run output behavior - -### `test/restore.test.ts` - -- restore command option parsing -- source filtering -- already-installed skip behavior -- dry-run behavior -- failure reporting behavior - -### `test/install-concurrency.test.ts` - -- automatic concurrency derivation -- configured concurrency clamping -- maximum active worker limit -- fail-fast scheduling behavior -- continue-on-error aggregation behavior - -## Non-Goals - -This reorganization does not attempt to: - -- expose a reusable library API -- add new end-user CLI commands beyond `backup` and `restore` -- redesign the manifest format -- change installation providers or command semantics beyond current behavior - -## Risks and Mitigations - -### Risk: behavior drift during file moves - -Mitigation: - -- preserve existing tests where possible -- add focused tests around concurrency and command parsing before major movement - -### Risk: accidental exposure of internal modules as public API - -Mitigation: - -- keep implementation under `src/internal/` -- document only the `skvlt` CLI command in `README.md` - -### Risk: release confusion if old script paths remain documented - -Mitigation: - -- remove `scripts/` as a supported runtime path -- update all docs and package scripts to point at the single CLI entrypoint - -## Recommendation - -Proceed with the reorganization as a pure CLI package for `Skills Vault`, using the `@xixu-me` scope, the `skvlt` binary, explicit internal namespaces, behavior-based file names, and tests separated from runtime code.