Bundle installer engine cleanup: tryExec extraction + MEMORY migration (#121, #107)#136
Merged
virtualian merged 2 commits intomainfrom Apr 15, 2026
Merged
Conversation
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>
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>
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.
Bundles two installer-engine issues on a single branch with one commit each for bisectability.
#121 — Promote
tryExecinto sharedengine/exec.tsExtract the triplicated safe-subprocess helper into a leaf utility module with zero imports from the installer tree. Replaces three copies:
actions.ts— delete localtryExec, import from./execdetect.ts— delete localtryExec, import from./exec, pass explicit5000mstimeout at every call site to preserve the historical detect-probe bound (tryExecdefault is30000ms, matchingactions.ts)repo-url.ts— rewritereadOriginRemotearoundtryExec, preserving the.gitexistsSyncshort-circuitZero behavioral change — purely structural consolidation. Originally flagged by the /simplify review in PR #120 (#115 fix) as pre-existing debt and deferred out of that scope.
Commit:
cc0fcc5#107 — Automate MEMORY migration for v4.0.2 → v4.0.3+ upgraders
Ships
engine/memory-migration.tspatterned offcommand-migration.ts(PR #135). Automates the~/.claude/MEMORY/→~/.pai/MEMORY/relocation that PR #106 documented but left manual.Semantics:
<dest>/STATE/migration.json. Second run sees the marker and noops regardless of source state.renameSyncfirst,cpSync+rmSyncfallback onEXDEV. Preserves mode and timestamps. Marker written inside the new location after the move..DS_Storeand dotfile cruft so empty stub directories don't trip ambiguity detection.options.dryRun=true) reports the intended action without touching the filesystem and without writing telemetry.<paiDir>/MEMORY/LEARNING/SYSTEM/memory-migration-*.jsonso the outcome surfaces in the learning digest, not stdout where users miss it.Wiring: Called from
runRepositoryimmediately aftermigrateUserContextand beforemigratePerPackSymlinks/migratePerPackCommands. Runs on every install path; the idempotent + noop-on-absent-source semantics make this safe for fresh installs.Tests (
engine/memory-migration.test.ts, 8 cases — all passing):noop-nothing-to-migrate.DS_Store→ noopmethod: "rename"noop-already-migratedregardless of source staterefused-ambiguous, neither side mutated, telemetry writtenLEARNING/SYSTEM/Commit:
dad8df5Verification
engine/exec.tstypechecks viabun build --target=bunengine/actions.ts,engine/detect.ts,engine/repo-url.tstypecheck clean after refactorengine/memory-migration.ts+engine/memory-migration.test.tstypecheckbun test engine/memory-migration.test.ts— 8/8 passbun test engine/skill-migration.test.ts— 17/17 pass (regression check)bash -n Releases/v4.0.3+/.claude/install.shbash -n Releases/v4.0.3+/.claude/PAI-Install/install.shTest plan
~/.claude/MEMORY/if desired: importmigrateMemoryDirectory, call with{ dryRun: true }, verify no writesIssues closed
🤖 Generated with Claude Code