Skip to content

Bundle two-root cleanup: PAI docs sweep + pack sources + commands architecture (#108, #113, #114)#135

Merged
virtualian merged 3 commits intomainfrom
fix/108-113-114-two-root-cleanup
Apr 15, 2026
Merged

Bundle two-root cleanup: PAI docs sweep + pack sources + commands architecture (#108, #113, #114)#135
virtualian merged 3 commits intomainfrom
fix/108-113-114-two-root-cleanup

Conversation

@virtualian
Copy link
Copy Markdown
Owner

Summary

Bundled fix for three peer issues from the post-#101 two-root split:

Three separate commits, one per issue, for a clean revert story.

User decisions received before execution

Question Answer
#113 commands architecture Option B — canonical ~/.pai/commands/ + symlinks into ~/.claude/commands/ (peer of #110 skills fix)
/cs fate Slash command — restore via ~/.pai/commands/cs.md symlinked from ~/.claude/commands/cs.md
Stale ~/.claude/PAI/ mirror deletion Leave alone — out of scope, maintainer decides in a separate PR

What's in each commit

3f4e937 — Sweep stale ~/.claude/ refs in release-template PAI/ tree (#108)

  • FeatureRegistry.ts:10: usage comment ~/.claude/Tools/~/.pai/PAI/Tools/
  • THENOTIFICATIONSYSTEM.md: notifications.ts path → ~/.pai/hooks/
  • THEHOOKSYSTEM.md: 16 hook-path refs swept via targeted replace_all
  • README.md: prose + ASCII tree rewritten to document the post-Implement CLAUDE_CONFIG_DIR + PAI_DIR two-root separation #101 split (CONFIG at ~/.claude/, CODE at ~/.pai/)

Note: RebuildPAI.ts:16, CLAUDE.md algorithm anchor, and Algorithm/v3.7.0.md were already fixed in the repo on an earlier commit — the runtime files at ~/.pai/PAI/ are stale because they came from a pre-fix install, and will self-correct on the next install run.

c60aedf — Sweep stale CODE-root refs in pack sources + release skills (#114)

  • Packs/Utilities/PAIUpgrade/SKILL.md + Workflows/Upgrade.md: hooks path
  • Packs/Telos/Workflows/Update.md: 3 update-telos.ts commands-path refs canonicalized to ~/.pai/commands/ (harness still reads via symlink)
  • Packs/Research/MigrationNotes.md: 5 command refs canonicalized
  • Mirrored fixes in Releases/v4.0.3+/.claude/skills/** copies

Scope reality check: The real repo-side surface was 16 refs across 5 files, not the 446/138 #114 described. #114's count was against the runtime tree ~/.pai/skills/**; most of those runtime refs come from pack sources that were already fixed in earlier commits, so they'll self-correct on reinstall.

50cb0b7 — Add canonical ~/.pai/commands/ home and installer migration (#113)

  • New: Releases/v4.0.3+/.claude/PAI-Install/engine/command-migration.tsmigratePerPackCommands(), direct peer of skill-migration.ts scaled for flat .md files. Same state machine (move / link-only / drift modes), same rollback, same drift-backup pattern, same getPaiCommandsDir() env-var resolution. Bundled 6.81 KB, compiles clean.
  • actions.ts: import + invocation right after migratePerPackSymlinks in runRepository. Runs on both fresh installs and upgrades.
  • New: Releases/v4.0.3+/.claude/commands/.gitkeep — placeholder so the canonical dir ships with the release template.
  • Packs/ContextSearch/INSTALL.md: architecture transition note at the top documenting the new model. Wizard bash scripts stay functional as-is — the next main-installer run detects drift from any direct copies and converts them into symlinks via the new migrator.

cs.md is already present in Packs/ContextSearch/src/commands/ — the new migrator guarantees it reaches ~/.pai/commands/cs.md with a symlink at ~/.claude/commands/cs.md on the next install, restoring /cs as a first-class slash command.

Explicitly NOT in this PR (follow-up work)

  • Full bash-script rewrite of Packs/ContextSearch/INSTALL.md to delegate command placement to the main installer. Transition note added instead; wizards remain functional and self-correct on next main-installer run.
  • Deletion of stale ~/.claude/PAI/ mirror tree — per user direction, out of scope (maintainer call for a separate PR).
  • Runtime-only stale refs in ~/.pai/skills/** (433 refs) and ~/.pai/PAI/** (178 refs) — those self-correct on the next install run because the repo sources are already correct.
  • Removal of any cs-as-skill workaround — I searched the repo and only the context-search skill exists by that name in the skill listing; no removable cs skill declaration was found.

Verification

  • RebuildPAI.ts: bun build → 3.97 KB, 0 errors
  • actions.ts: bun build → 59.49 KB, 7 modules, 0 errors
  • command-migration.ts: bun build → 6.81 KB, 1 module, 0 errors
  • Post-sweep CODE-root grep: 10 refs remain in Releases tree, all legitimate KEEP (harness scan-path documentation in TypeScript comments: GetCounts.ts, actions.ts, skill-migration.ts, the new command-migration.ts)
  • Post-sweep Packs grep: 6 refs remain in Packs/ContextSearch/INSTALL.md, all in bash-wizard scripts that are functional under Option B (harness scan path ~/.claude/commands/ resolves via symlink to canonical ~/.pai/commands/)
  • KEEP list honored: spot-checked ~/.claude/settings.json refs preserved in THENOTIFICATIONSYSTEM.md:109, 207 and PAIUpgrade/SKILL.md:351

Test plan

  • Run the PAI installer on a fresh ~/.pai/ tree — verify ~/.pai/commands/ is created and populated from pack sources
  • Run the installer on an existing tree with real files in ~/.claude/commands/ — verify they're moved to ~/.pai/commands/ and replaced with symlinks
  • Verify /cs slash command is invocable after install
  • Verify /context-search still works after install
  • Regression-check: confirm skill-migration still runs correctly alongside command-migration
  • grep -rE '~/\.claude/(PAI\|MEMORY\|hooks\|agents\|commands\|Tools\|skills)/' Releases/ Packs/ --include='*.md' --include='*.ts' returns only KEEP-list matches

Closes #108
Closes #113
Closes #114

🤖 Generated with Claude Code

virtualian and others added 3 commits April 15, 2026 19:02
Fix remaining stale CODE-root references in Releases/v4.0.3+/.claude/PAI/
docs and tool comments. Per-occurrence judgment preserves legitimate
~/.claude/settings.json KEEP refs.

- FeatureRegistry.ts:10: usage comment ~/.claude/Tools/ → ~/.pai/PAI/Tools/
- THENOTIFICATIONSYSTEM.md: notifications.ts path hooks/ → ~/.pai/hooks/
- THEHOOKSYSTEM.md: 16 hook-path refs ~/.claude/hooks/ → ~/.pai/hooks/
- README.md: prose + ASCII tree rewritten for post-#101 two-root split
  (CONFIG at ~/.claude/, CODE at ~/.pai/)

Fixes #108

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix remaining stale ~/.claude/{hooks,commands}/ refs in Packs/ sources and
their Releases/ mirrors. Per-occurrence judgment; KEEP list (settings.json,
projects/, keybindings.json) preserved throughout.

Real repo-side surface was 16 refs across 5 files, not the 446/138 that
issue #114 described — those counted the runtime tree (~/.pai/skills/**),
which mostly self-corrects on next install since most refs there come from
already-fixed pack sources.

- Packs/Utilities/PAIUpgrade/SKILL.md + Workflows/Upgrade.md: hooks path
- Packs/Telos/Workflows/Update.md: update-telos.ts commands path
  canonicalized to ~/.pai/commands/ (harness still reads via symlink)
- Packs/Research/MigrationNotes.md: 5 command refs canonicalized
- Mirrored fixes in Releases/v4.0.3+/.claude/skills/** copies

Out of scope: Packs/ContextSearch/INSTALL.md bash-script rewrite (handled
in #113 commit with transition note).

Fixes #114

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Slash commands were forgotten by the two-root split (#101): no canonical
home under ~/.pai/, installer never touched commands/, pack wizards were
the only placement mechanism. This commit lands the Option B architecture:
~/.pai/commands/ becomes the single source of truth, symlinked into
~/.claude/commands/ so the harness scan path still works.

- New: engine/command-migration.ts — migratePerPackCommands(), peer of
  skill-migration.ts scaled for flat .md files. Same state machine,
  same rollback semantics, same drift-backup pattern. 6.81 KB bundled.
- engine/actions.ts: import + invocation after migratePerPackSymlinks
  in runRepository. Runs on both fresh installs and upgrades.
- New: Releases/v4.0.3+/.claude/commands/.gitkeep — placeholder so the
  canonical dir ships with the release template.
- Packs/ContextSearch/INSTALL.md: architecture transition note at top
  documenting the new model. Wizard bash scripts are left functional
  (they still copy to ~/.claude/commands/); the next main-installer run
  detects drift and converts real files into symlinks via the new
  migrator. Full wizard rewrite is follow-up work.

Restores /cs as a slash command: cs.md exists in Packs/ContextSearch/src/
commands/, and the new migrator guarantees it reaches ~/.pai/commands/cs.md
with a symlink at ~/.claude/commands/cs.md on the next install.

Peer of #110 (skills migration). Architecture confirmed with user:
Option B + /cs as slash command + leave stale ~/.claude/PAI/ mirror alone.

Fixes #113

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@virtualian virtualian merged commit 54ebf5e into main Apr 15, 2026
@virtualian virtualian deleted the fix/108-113-114-two-root-cleanup branch April 15, 2026 19:26
virtualian added a commit that referenced this pull request Apr 15, 2026
Patterned off command-migration.ts (PR #135). Ships engine/memory-migration.ts
with a single entry point migrateMemoryDirectory(claudeConfigDir, paiDir, emit,
options?), wired into runRepository immediately after user-context migration
and before the skill/command migrators.

Semantics:
- Idempotent via marker file at <dest>/STATE/migration.json. Second run
  sees the marker and noops regardless of source state.
- Refuses with a diagnostic (both paths + file counts + latest mtime) if
  both source and dest contain meaningful content without a marker.
  Merging is a data-integrity decision outside installer scope.
- renameSync first, cpSync+rmSync fallback on EXDEV. Preserves mode and
  timestamps. Marker written inside the new location after the move.
- Meaningful-content filter ignores .DS_Store and dotfile cruft so empty
  stub directories don't trip ambiguity detection.
- Dry-run mode (options.dryRun=true) reports the intended action without
  touching the filesystem and without writing telemetry.
- Telemetry logged to <paiDir>/MEMORY/LEARNING/SYSTEM/memory-migration-*.json
  so the outcome surfaces in the learning digest, not stdout where users
  miss it.

Tests (engine/memory-migration.test.ts, 8 cases):
- fresh install: noop-nothing-to-migrate
- source has only .DS_Store: noop
- upgrade: renames source into dest, writes marker, preserves nested files
- second run: noop-already-migrated regardless of source state
- ambiguity: refused-ambiguous, neither side mutated, telemetry written
- dry-run would-migrate: filesystem untouched
- dry-run would-refuse-ambiguous: no telemetry written
- post-migration telemetry entry exists in LEARNING/SYSTEM/

All 8 pass. Regression-checked skill-migration.test.ts (17/17 pass).
install.sh and PAI-Install/install.sh pass bash -n.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
virtualian added a commit that referenced this pull request Apr 15, 2026
#121, #107) (#136)

* Promote tryExec into shared engine/exec.ts (#121)

Extract the triplicated safe-subprocess helper into a leaf utility module
with zero imports from the installer tree, so any consumer (current or
future) can depend on it without circular-import risk. Replace the three
hand-rolled copies:

- actions.ts: delete local tryExec, import from ./exec
- detect.ts: delete local tryExec, import from ./exec, pass explicit
  5000ms timeout at every call site to preserve the historical detect
  probe bound (tryExec default is 30000ms, matching actions.ts)
- repo-url.ts: rewrite readOriginRemote around tryExec, preserving the
  .git existsSync short-circuit

Zero behavioral change — purely structural consolidation. Flagged by the
/simplify review in PR #120 (#115 fix) as pre-existing debt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Automate MEMORY migration for v4.0.2 → v4.0.3+ upgraders (#107)

Patterned off command-migration.ts (PR #135). Ships engine/memory-migration.ts
with a single entry point migrateMemoryDirectory(claudeConfigDir, paiDir, emit,
options?), wired into runRepository immediately after user-context migration
and before the skill/command migrators.

Semantics:
- Idempotent via marker file at <dest>/STATE/migration.json. Second run
  sees the marker and noops regardless of source state.
- Refuses with a diagnostic (both paths + file counts + latest mtime) if
  both source and dest contain meaningful content without a marker.
  Merging is a data-integrity decision outside installer scope.
- renameSync first, cpSync+rmSync fallback on EXDEV. Preserves mode and
  timestamps. Marker written inside the new location after the move.
- Meaningful-content filter ignores .DS_Store and dotfile cruft so empty
  stub directories don't trip ambiguity detection.
- Dry-run mode (options.dryRun=true) reports the intended action without
  touching the filesystem and without writing telemetry.
- Telemetry logged to <paiDir>/MEMORY/LEARNING/SYSTEM/memory-migration-*.json
  so the outcome surfaces in the learning digest, not stdout where users
  miss it.

Tests (engine/memory-migration.test.ts, 8 cases):
- fresh install: noop-nothing-to-migrate
- source has only .DS_Store: noop
- upgrade: renames source into dest, writes marker, preserves nested files
- second run: noop-already-migrated regardless of source state
- ambiguity: refused-ambiguous, neither side mutated, telemetry written
- dry-run would-migrate: filesystem untouched
- dry-run would-refuse-ambiguous: no telemetry written
- post-migration telemetry entry exists in LEARNING/SYSTEM/

All 8 pass. Regression-checked skill-migration.test.ts (17/17 pass).
install.sh and PAI-Install/install.sh pass bash -n.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment