Port: port/pr-29-feature/25-git-worktree-support#7
Merged
Conversation
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Documents the Shared Knowledge / Namespaced Session architecture for first-class git worktree support in OpenWolf (Approach 2 scope). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11-task TDD plan covering detection utility, hook updates, CLI guards, and smoke test for first-class git worktree support in OpenWolf. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… worktree README section
vi.mock("node:child_process") cannot patch live bindings on CJS built-ins
when imported via ESM. Switching to vi.spyOn on the git-wrapper ESM module.
Also adds git worktree section to README per CONTRIBUTING guidelines.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The init refactor inadvertently dropped critical Claude Code integration: HOOK_SETTINGS used a non-standard format, settings were written to .wolf/settings.json instead of .claude/settings.json, and the CLAUDE.md snippet and .claude/rules/openwolf.md creation were removed. - Restore HOOK_SETTINGS to Claude Code format (matcher/hooks/command) - Write hooks to .claude/settings.json with merge via replaceOpenWolfHooks() - Add writeClaudeRules() for .claude/rules/openwolf.md and CLAUDE.md snippet - Remove writeReadme() (should not modify user README.md) - Gate writeIdentity() behind !isUpgrade to respect CREATE_IF_MISSING - Use atomic writeJSON() for .claude/settings.json writes - Fix || to ?? for CLAUDE_PROJECT_DIR in shared.ts - Remove TOCTOU existsSync before idempotent mkdirSync in ensureSessionDir() - Fix Next steps output to suggest correct files for git add Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix critical regressions and edge cases found during pre-merge review: - Use --git-dir vs --git-common-dir comparison for worktree detection, fixing false positives on git submodules and subdirectories - Add shared.js and package.json (type:module) to writeHooks() so hooks actually work at runtime - Fix openwolf status in worktree mode by resolving wolfDir before the existence check - Fix writeHooks() source path resolution to find compiled hooks relative to __dirname instead of templatesDir - Add error discrimination in detectWorktreeContext() catch blocks to warn on unexpected git failures instead of silently falling back - Fix writeSettings() to backup and warn on corrupted settings.json instead of silently overwriting - Wrap scanProject in try/catch to prevent mid-init crashes - Revert Rust doc comment regex from // back to /// (only match doc comments) - Remove unused imports (execSync, isWindows, readText, writeText) - Add tests for submodule false-positive guard and error warning behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix critical bugs: ensureSessionDir crash on mkdirSync failure, .wolf/ skip checks broken in worktree mode (check both projectRoot and mainRepoRoot), memory.md split-brain between hooks and Claude (write to shared wolfDir), and writeJSON silently swallowing fallback failures. Add error logging to all 6 hook catch handlers, fix stale docs paths in hooks.md, remove premature v1.1.0 version claim, scan sessionDir for orphaned .tmp files, guard writeGitIgnore against EACCES, align init.ts worktree detection with findProjectRoot(), and document bare-repo worktree limitation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rehensive error logging
## Critical fixes
- **Worktree hook resolution**: Hook commands now use `git rev-parse --git-common-dir` at shell invocation time to resolve to the main checkout where `.wolf/hooks/` lives, instead of relying on `$CLAUDE_PROJECT_DIR` which points to the worktree directory in worktree mode.
- **Restore cerebrum seeding on fresh init**: Re-added `seedCerebrum()`, `detectProjectName()`, and `detectProjectDescription()` helpers so new projects get project name/description in `cerebrum.md`.
- **Anatomy scan upgrade-safe**: Wrapped `scanProject()` in `if (!isUpgrade)` guard so upgrades preserve user-curated entries. Added error reason to catch output.
- **Token-ledger created_at initialization**: Stamps `created_at` on first init when the field is empty.
- **Fixed docs: memory.md is shared, not session-scoped**: Corrected README.md and docs/troubleshooting.md to list `token-ledger.json` and `_session.json` as session-scoped, with `memory.md` explicitly noted as shared across worktrees.
## Important improvements
- **10 empty catch blocks in hooks now log to stderr** (post-write.ts, session-start.ts, stop.ts, shared.ts): All hooks still exit 0 but report errors for debugging. ENOENT filtered where appropriate.
- **Fixed registerProject call**: Removed erroneous `await`, restored openwolf self-guard, restored multi-manifest project name detection.
- **writeIdentity() differentiates ENOENT**: Now warns on malformed package.json instead of silently ignoring.
- **Restored fuller CLAUDE.md snippet**: New projects get the full header with description; existing CLAUDE.md files use smarter detection.
- **Added findTemplatesDir fallback candidates**: 4 candidates instead of 2 for better resilience.
- **Added daemon status hint**: Init summary now mentions daemon can be started manually.
- **18 new tests for settings merge**: Comprehensive coverage for `replaceOpenWolfHooks()` and `isOpenWolfHook()` with upgrade, preservation, idempotency, and edge case scenarios. All 27 tests pass.
## Files changed
- src/cli/init.ts: Restored lost functions, fixed worktree hook commands, exported test helpers
- src/cli/init.test.ts: New test file with 18 tests for settings merge logic
- src/hooks/{post-write,session-start,shared,stop}.ts: Added stderr logging to error cases
- README.md, docs/troubleshooting.md: Corrected memory.md scope documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ree errors, tests) - Fix SQL regex in shared.ts:569 to match unquoted table names - Move memory.md from sessionFiles to sharedFiles in status.ts - Extract detectWorktreeContext to src/hooks/worktree-helper.ts (zero deps) - Remove empty catch in worktree.ts; unexpected errors now propagate - Preserve targeted fallback for non-git/ENOENT cases in utils/worktree.ts - Remove stderr silencers (2>/dev/null) from init.ts WOLF_ROOT - Add worktree guard tests for initCommand() - Update worktree tests to mock node:child_process directly (ESM compat) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…te drift Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s import Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Single source of truth for the hook script basename list — eliminates the duplication across init/update/status that allowed worktree-helper.js to be missed in any one call site. Replaces the source-text regex test with a direct contains-check on the imported constant, covering all three call sites and removing the process.cwd() fragility flagged in PR review. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the awkward triple-tuple stdio assertion with a single-string 'pipe' + object-level `as const`. Cache not-a-repo, missing-git, and timeout fallbacks in detectWorktreeContext so a broken-git project does not re-pay the 2s timeout on every hook call within the same process. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eserve cause Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…etadata
Replace all bare catch {} blocks in init.ts with ENOENT-aware handlers.
ENOENT (file not found) is silently ignored; all other errors (EACCES,
corrupted JSON, EPERM, etc.) emit a console.warn so the user gets a
signal during openwolf init.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tings.json is corrupt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ck sites Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…solution Templates were never copied into the build output, so findTemplatesDir always failed at runtime. Add a build:templates step and a correct candidate path (../../templates from dist/src/cli → dist/templates). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getWolfDir() was returning <worktree>/.wolf which does not exist — .wolf/ only lives in the main checkout. This caused ensureWolfDir() to exit(0) silently, making every hook a no-op in worktree mode. Session isolation is already handled by getSessionDir(), so getWolfDir() should always return mainRepoRoot/.wolf. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… modules
Consolidate isOpenWolfHook, replaceOpenWolfHooks, and findTemplatesDir which
were duplicated across init.ts and update.ts — each now lives in one canonical
module. Fixes path.basename("") bug in post-write.ts that produced empty
filenames in bug-log summaries, adds worktree guard to update command, and
removes redundant process.exit mock from session-start tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unnecessary path.basename() on function name in post-write.ts - Standardize ?? operator in shared.ts for consistency with CLAUDE_PROJECT_DIR checks - Add package-lock.json to .gitignore (pnpm-lock.yaml is authoritative) - Add test for worktree session ledger path isolation in stop.ts All changes verified: pnpm build passes, smoke test passes, all tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- post-write.ts: use ?? instead of || for CLAUDE_PROJECT_DIR to match
shared.ts fix and correctly treat empty-string env var as unset
- stop.test.ts: replace inline require('node:fs') with named ESM
imports (mkdirSync, existsSync, readFileSync) for consistency
Build passes, all 54 tests pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
briansumma
added a commit
that referenced
this pull request
Jun 23, 2026
All 8 review points verified against the code and incorporated: - #1 nested lock: updateJSON now extracts _writeJSONUnsafe instead of calling writeJSON inside its own lock (avoids EEXIST retry + spurious unlocked warning). - #2 hooks boundary: NDJSON helper needs a self-contained copy in src/hooks/ (can't import src/buglog under tsconfig.hooks.json) plus the canonical CLI copy. - #3 stop.ts: added to the B4 table; nudge string match buglog.json -> buglog. - #4 _session.json RMW: post-write.ts and stop.ts session writes added to A2, with a documented semantic caveat for shared-checkout session conflation. - #5 logBug: noted as a 4th RMW site (CLI, unlocked); added B6 (lift withFileLock to a shared module if B3b locking is chosen). - #6 atomicity wording: single-write-syscall framing, not "POSIX atomic". - #7 testing: added concurrent append + read (torn final line) test. - #8 TOCTOU: documented the staleness-storm bound. Co-Authored-By: Claude Opus 4.8 (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.
Ported from upstream cytostack/openwolf. Needs review before merge.