Commit Graph

64 Commits

Author SHA1 Message Date
gaebal-gajae
97ea6ff30f fix(workflows): remove retired ultrawork lifecycle surfaces 2026-08-24 06:29:11 +00:00
Bellman
0eb316a555 fix: close terminal independent review 2026-08-22 22:18:56 +00:00
Bellman
8a8512c082 fix: close binding review edge cases 2026-08-22 21:48:13 +00:00
Bellman
ec3cd5977b fix: close final binding review defects 2026-08-22 19:56:53 +00:00
Bellman
0f67476702 fix: close current-head runtime review blockers 2026-08-22 13:31:23 +00:00
Bellman
bf70cd20db fix: close terminal restore and provenance blockers 2026-08-22 12:40:56 +00:00
Bellman
bec6de960a fix: close five release verification regressions 2026-08-22 10:39:23 +00:00
gaebal-gajae
a18a681e16 fix: close release promotion security review blockers 2026-08-22 06:30:45 +00:00
Bellman
15f98c8f1d fix(hooks): restore PreCompact checkpoint after compaction (closes #3730) (#3731)
The PreCompact hook wrote checkpoint files but had no restore path:
after auto-compaction, OMC-owned state (mode progress, TODOs, plan
anchors) was lost from context. The checkpoint was write-only.

This adds the smallest lifecycle fix:

Writer (src/hooks/pre-compact/index.ts):
- Extend CompactCheckpoint with plan_refs: durable pointers to the
  active PRD (ralph PRD mode) and boulder plan, plus bounded counts.
  No conversation data, no universal plan contract.
- collectPlanRefs() resolves existing PRD/boulder artifacts and records
  references only; plan file contents are never copied.
- formatCompactSummary() includes plan refs in the pre-compact message.
- createCompactCheckpoint() now threads session_id for PRD resolution.

Restore (src/hooks/pre-compact/restore.ts — new):
- findLatestCheckpointForRestore(): newest-wins, bounded by age
  (24h) and size (256KB), fail-open on malformed/missing/oversized/
  stale, with project-scoped isolation via getOmcRoot.
- markCheckpointRestored(): session-scoped replay guard prevents
  duplicate injection; a different (older) checkpoint is still a
  legitimate restore target.
- formatCheckpointRestoreContext(): bounded advisory context (<=1200
  chars) mirroring the writer's durable anchors.

SessionStart hook (scripts/session-start.mjs + template):
- Restores the newest checkpoint only when source === 'compact'
  (post-compaction resume), never on startup/resume/clear.
- Import is gated on CLAUDE_PLUGIN_ROOT; restore fails open.

Docs: ARCHITECTURE.md, HOOKS.md updated; the 'unreachable note' in
formatCompactSummary() now accurately references the restore path.

Tests: 27 new focused tests (17 module-level + 10 SessionStart
hook-level) covering writer→restore lifecycle, plan anchors, project/
session isolation, stale/malformed/oversized handling, no-checkpoint,
and no-duplicate-replay.

Signed off.
2026-08-14 04:34:49 +09:00
Bellman
21954d859a fix(purge): track live plugin cache occupancy 2026-08-12 11:04:47 +00:00
Bellman
696c3d1ec6 fix(session-start): keep plugin drift guidance on marketplace channel (#3500)
Keep managed-plugin SessionStart drift and update guidance on the marketplace channel.

— gaebal-gajae
2026-07-16 08:35:07 +00:00
Bellman
d55ca23b78 fix(session-start): align update notices with plugin channel (#3499) 2026-07-16 08:21:05 +00:00
Bellman
761ed11286 fix(hooks): make session end shutdown durable and bounded (#3478)
Persist SessionEnd cleanup intent before hook return, move deferred effects into fenced recoverable workers, and retain the generated shipping closure used by scripts/run.cjs.

Fixes #3477
2026-07-13 21:05:47 +00:00
Bellman
46c788de3d fix: ignore stale plugin root for update notices (#3214)
* fix: ignore stale plugin root for update notices

* fix session-start plugin root version precedence

---------

Co-authored-by: Codex Review <codex-review@example.com>
2026-06-06 23:51:14 +09:00
Bellman
abd21cf00b Make SessionStart update notices user-visible (#3157)
Move update availability text out of SessionStart additionalContext and into the hook systemMessage output so the model does not carry persistent update prompt context. Preserve passive autoUpgradePrompt=false wording and cover both installed script paths.\n\nConstraint: issue #3155 requires user-visible update notices without permanent model additionalContext.\nRejected: stderr-only notices | successful SessionStart stderr is not a sufficiently contract-safe user-visible channel.\nConfidence: high\nScope-risk: narrow\nDirective: Keep update notices out of hookSpecificOutput.additionalContext; use user-visible hook output for future startup notices.\nTested: npm test -- --run src/installer/__tests__/session-start-template.test.ts src/__tests__/session-start-script-context.test.ts; npx tsc --noEmit; npm run lint -- src/installer/__tests__/session-start-template.test.ts src/__tests__/session-start-script-context.test.ts; git diff --check; node --check scripts/session-start.mjs; node --check templates/hooks/session-start.mjs\nNot-tested: Manual Claude Code UI rendering of SessionStart systemMessage

Co-authored-by: Codex Review <codex-review@example.com>
2026-05-28 03:15:48 +09:00
Joao Pster
dc3f3b82c0 fix(multi-repo): accept repo subdirs as cwd; stop workspace search at $HOME
Addresses Codex review on #3130.

P1 (validateCwd): cwd is commonly a subdirectory of the repo/workspace root.
The previous direct-only check rejected subdirs and made session-start skip
all restoration. Now walk up from cwd to find a .git or .omc-workspace,
stopping at $HOME so a stray marker/repo in $HOME cannot validate an unrelated
dir. Applied to both scripts/session-start.mjs and templates/hooks/session-start.mjs.

P2 (findWorkspaceRoot): the home-boundary check now runs before the marker
check, so a stray ~/.omc-workspace no longer collapses unrelated repos under
home into one shared state root.

Added a regression test: session-start accepts a nested subdir of a .git repo.

Confidence: high
Scope-risk: narrow
2026-05-26 12:53:28 -03:00
Joao Pster
44c55993df Merge origin/dev into feat/multi-repo-workspace
Resolve conflicts after dev advanced past the merge base:
- package.json / plugin.json / marketplace.json / docs/CLAUDE.md: keep dev's 4.14.4 version (feature PR carries no version bump)
- scripts/keyword-detector.mjs: combine dev's added 'ultragoal' clear target with branch's omcRoot arg
- src/hud/render.ts: combine branch's local-build "L" suffix with dev's updateNotification gate
- src/__tests__/doctor-conflicts.test.ts: keep both new imports (checkWorkspaceMarker + checkWindowsUnsafePluginHooks)
- dist/ and bridge/: regenerated via npm run build (generated artifacts)

Confidence: high
Scope-risk: moderate
2026-05-26 11:42:52 -03:00
Bellman
707b3357e0 Fix update-check cache path consistency (#3112)
* Keep update-check cache under Claude config

Route HUD and hook update-cache access through the same CLAUDE_CONFIG_DIR-aware helper so Windows and custom config roots do not split writer and reader state.

Constraint: Scope limited to update-check path consistency for issue #3109.

Rejected: Moving the cache to ~/.omc | That would preserve the HUD-only path and diverge from existing CLAUDE_CONFIG_DIR-aware updater/config storage.

Confidence: high

Scope-risk: narrow

Directive: Keep future update-check readers and writers on getUpdateCheckCachePath().

Tested: npm test -- --run src/__tests__/update-check-path.test.ts src/__tests__/config-dir.test.ts; npx eslint src/utils/config-dir.ts src/hud/index.ts src/__tests__/update-check-path.test.ts; npm run build

Not-tested: Full test suite

* Keep session-start template helper in sync

Expose the update-check cache helper from the template-local config-dir module so direct template execution has the same helper that session-start imports.

Constraint: Scope limited to the update-check path/template regression from PR #3112 CI.

Rejected: Changing session-start error handling | The failure was missing helper propagation, not restore-context behavior.

Confidence: high

Scope-risk: narrow

Directive: Keep templates/hooks/lib/config-dir.mjs aligned with update-check helpers used by templates/hooks/session-start.mjs.

Tested: npm test -- --run src/installer/__tests__/session-start-template.test.ts src/__tests__/update-check-path.test.ts src/__tests__/config-dir.test.ts; npm run build; git diff --check

Not-tested: Full test suite

---------

Co-authored-by: Codex Review <codex-review@example.com>
2026-05-26 00:00:48 +08:00
Joao Pster
1484fa07eb feat(multi-repo): full multi-repo workspace support
Adapt OMC state, hooks, HUD, and session tracking to operate correctly
across multiple git repos that share one logical workspace, instead of
assuming "single repo == single state root".

Core:
- `.omc-workspace` marker anchors `.omc/` at a non-git parent dir.
  Resolution order: `OMC_STATE_DIR` > `.omc-workspace` > git root > cwd
  (src/lib/worktree-paths.ts).
- Session-scoped state via `resolveSessionStatePaths(name, sessionId, dir)`
  returning branded `ReadPath`/`WritePath`, so a read path can never be
  silently used as a write path. An ESLint `no-restricted-syntax` rule bans
  casting these brands outside worktree-paths.ts.
- `resolveSessionId()` centralizes session-id resolution (hook payload wins
  for hooks, env wins for CLI) in src/lib/session-id.ts.
- Opt-in legacy state migration via `OMC_MIGRATE_LEGACY_STATE=1`; nothing is
  copied by default.

Concurrency and isolation:
- session-start hook uses PID-aware liveness: a dead owner session no longer
  suppresses state restore.
- subagent-tracker migrated to session-scoped paths plus `withFileLockSync`,
  keeping the hot-path lock scope minimal (read, update, write). Perf bench
  records Windows p99 around 3.0 to 3.7 ms, under the Linux budget.
- New concurrent ralph-session and project-memory integration tests.

HUD:
- Multi-repo workspace chip showing subrepo and active-session counts
  (src/hud/elements/multi-repo.ts).
- "L" suffix on the OMC version when running from a local fork; local installs
  are detected even when the fork is copied (not symlinked) into the plugin
  cache.

Other:
- ultragoal artifacts made workspace-aware.
- CI guard (scripts/ci/check-multirepo-paths.mjs wired into ci.yml) plus audit
  and smoke scripts that keep new code on the canonical path helpers.

Constraint: dist/ and bridge/ are tracked in this repo, so artifacts were
rebuilt against dev and committed.
Directive: session-scoped state must go through resolveSessionStatePaths();
do not cast ReadPath/WritePath.
Confidence: high
Scope-risk: broad
2026-05-25 12:56:22 -03:00
Bellman
bc5f3bc41d Fix hook background notification output isolation (#2966)
Co-authored-by: Codex Review <codex-review@example.com>
2026-05-08 12:14:44 +09:00
Ethan Stark
9dbcf7a377 fix(hooks): align SessionStart model routing override with pre-tool enforcer (#2868)
Reviewed by OMX session omx-pr-2868-review. All CI checks passed.
2026-04-30 13:15:03 +09:00
Codex Review
3e2a81642a Reconcile hard-terminated sessions from explicit start markers
SessionEnd remains the normal cleanup path. SessionStart now writes a narrow session-scoped marker and only reconciles prior marked sessions when the marker owns its session directory, no SessionEnd summary exists, and PPID/boot evidence shows the owner is gone. The backstop clears OMC mode/mission state only and deliberately avoids team runtime shutdown or tmux PID killing.

Constraint: Issue #2816 requires SessionEnd to stay primary and SessionStart cleanup to fail closed on ambiguous ownership

Rejected: Global stale sweep by age | could erase active concurrent sessions without explicit ownership

Rejected: Process-name dedupe or tmux PID cleanup | explicitly disallowed and unsafe for SessionStart

Confidence: high

Scope-risk: moderate

Directive: Do not broaden SessionStart reconciliation without explicit owner evidence and active-session safety tests

Tested: npm test -- --run src/hooks/__tests__/bridge-routing.test.ts src/hooks/session-end/__tests__/mode-state-cleanup.test.ts

Tested: npx tsc --noEmit

Tested: npm run build

Tested: npm run lint (passes with pre-existing warnings)
2026-04-27 10:39:45 +09:00
Bellman
1142556639 Fix stale Ralph stop hook after cancel (#2833)
Fixes #2832.
2026-04-26 12:39:39 +09:00
Codex Review
9326a3b9b1 Preserve provider routing guidance across SessionStart hooks
Standalone and template SessionStart hooks already prioritized the model-routing override marker, but only the TypeScript bridge emitted the actual provider-safety guidance. This preserves the Bedrock/Vertex/proxy force-inherit reminder across shipped hook surfaces and adds budget-pressure parity tests for both standalone paths.

Constraint: SessionStart scripts/templates must remain standalone and cannot import the TypeScript config loader.

Rejected: Rely on bridge-only coverage | standalone/template hooks are shipped surfaces and can miss provider-safety guidance.

Confidence: high

Scope-risk: narrow

Directive: Keep provider detection and SessionStart priority rules aligned across bridge, scripts, and templates until hook generation is centralized.

Tested: 178 targeted Vitest tests; npm run build; npx tsc --noEmit --pretty false; targeted ESLint; node --check on changed SessionStart scripts; git diff --check; code-review APPROVE; architect WATCH with prior BLOCK resolved

Not-tested: Full GitHub CI on follow-up branch pending PR creation
2026-04-23 04:45:33 +00:00
Codex Review
c5671d2dc5 Reduce prompt token melting at hook ingress
Large prompt payloads were entering through several independent hook paths: keyword-triggered full skill injection, learned-skill body injection, root AGENTS startup loading, and multi-file context loading. This change converts skill paths to compact path-backed guidance, caps learned-skill descriptors, compacts OMC startup guidance, and enforces aggregate budgets at SessionStart and context-file loading boundaries.

Constraint: Hook templates and standalone scripts must remain runnable without importing the TypeScript runtime.

Rejected: Inline full SKILL.md bodies on keyword detection | this caused the hottest UserPromptSubmit token blowups.

Rejected: Per-file AGENTS truncation only | multi-file AGENTS/CLAUDE accumulation could still exceed budget.

Confidence: high

Scope-risk: moderate

Directive: Keep budget constants aligned across source, scripts, and templates until hook template generation is centralized.

Tested: 584 targeted Vitest tests; npx tsc --noEmit --pretty false; targeted ESLint on changed TS/test files; node --check on changed mjs hooks/scripts; npm run build; git diff --check; code-review APPROVE; architect CLEAR

Not-tested: Full repo lint is still blocked by 10 pre-existing warnings outside touched paths
2026-04-23 04:01:42 +00:00
Zhichang Yu
e19dceac28 fix(session-start): ensure stale-root parent dir exists before temp symlink
If stalePath's parent directory was removed (deleted config tree),
symlinkSync throws ENOENT and the repair is silently skipped.
Create the parent directory recursively before creating the temp symlink.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-14 13:13:49 +08:00
Zhichang Yu
5b957ef289 fix(session-start): unlink dangling stale path before fallback symlink
If renameSync fails after tmpLink creation (e.g., replacing an existing
junction on Windows), the fallback path recreates the symlink at stalePath.
Without unlinking first, symlinkSync throws EEXIST on a pre-existing
dangling link and the error is swallowed — leaving the stale root broken.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-14 12:54:43 +08:00
Zhichang Yu
65ee9f4384 fix(session-start): use absolute symlink target on POSIX
POSIX symlink target was relative (just version name), resolving from
symlink parent — wrong when stalePath isn't under cacheBase.
Always use absolute path so the symlink works regardless of parent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-14 12:47:03 +08:00
Zhichang Yu
b145f90606 fix(session-start): strip trailing separators before creating stale-root symlink
Trailing / or \ in CLAUDE_PLUGIN_ROOT causes tmpLink to be placed
inside the non-existent version directory, making symlinkSync fail with
ENOENT. Strip trailing separators before deriving paths.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-14 12:39:31 +08:00
Zhichang Yu
3869074837 fix(session-start): symlink stale CLAUDE_PLUGIN_ROOT to latest version
Upgrade removes old version directories but running sessions still have
the old CLAUDE_PLUGIN_ROOT in their environment, causing "Plugin directory
does not exist" errors on every hook invocation.

Guard detects when CLAUDE_PLUGIN_ROOT points to a deleted version
directory and creates a symlink from the stale path to the latest version,
so subsequent run.cjs invocations resolve correctly.

Constraint: Must not block or delay session-start
Constraint: Atomic symlink to avoid race conditions on concurrent upgrades
Rejected: Error suppression only | sessions keep failing until restart
Rejected: Skip grace period | could delete in-use cache dirs
Confidence: high
Scope-risk: narrow
Directive: Grace period (24h) prevents removing dirs still referenced by long-running sessions
Not-tested: Concurrent upgrade race condition (requires multi-process test harness)
2026-04-14 12:39:31 +08:00
Codex Review
a84bae555a fix(state-root): centralize OMC_STATE_DIR resolution across hook entrypoints (#2532)
scripts/persistent-mode.cjs and .mjs hardcoded join(directory, '.omc', 'state'),
bypassing OMC_STATE_DIR entirely. session-start.mjs had the same bug across all
state-restore paths (ultrawork, ralph, notepad, todos).

Add scripts/lib/state-root.{mjs,cjs} — thin async wrappers that delegate to
getOmcRoot() from dist/lib/worktree-paths.js (the canonical resolver) when
CLAUDE_PLUGIN_ROOT is set, with an inline OMC_STATE_DIR + simplified-hash
fallback when dist is unavailable (dev/first-run only).

Wire the helper into all three hook entrypoints so every state read/write
goes through a single resolver.

Add src/__tests__/state-root-resolution.test.ts — 7 subprocess regression tests
covering:
  - Default .omc path when OMC_STATE_DIR is unset
  - session-start restores ralph/ultrawork from centralized dir
  - session-start does NOT restore when state is only in default .omc
  - Stop hook blocks when active ralph state is in default dir (baseline)
  - Stop hook blocks when active ralph state is in centralized dir
  - Stop hook does NOT block when state is only in default dir + OMC_STATE_DIR set

Note: stop-hook fixtures require fresh started_at/last_checked_at timestamps
because persistent-mode.cjs treats state older than 2h as stale and ignores it.

Constraint: scripts/persistent-mode.cjs is CJS; dist/lib/worktree-paths.js is ESM
— resolved via dynamic import() inside the async helper.
Rejected: inline OMC_STATE_DIR check in each script | duplicates project-identifier
logic and drifts over time.
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 06:07:18 +00:00
Pedro Rodrigues
b8948f6d3c fix: respect CLAUDE_CONFIG_DIR across remaining code paths
Several code paths hardcoded ~/.claude instead of resolving the active config directory. Introduce
getClaudeConfigDir() as a shared helper (with ESM/CJS/shell mirrors in scripts/lib/) and update
all call sites:

- transcript validation: allow paths under the active config directory
- transcript fallback resolution: build projects/ lookups from the active config directory instead
  of inline env-var fallback
- rules discovery: use getClaudeConfigDir() instead of hardcoded path
- rules injector: remove dead homeDir parameter from findRuleFiles and USER_RULE_DIR export;
  breaking change to the public surface (no npm dependents)
- uninstall: preserve existing CLAUDE_CONFIG_DIR env var
- CLI: use getClaudeConfigDir() for runtime paths and config directory descriptions
  (default: ~/.claude/)
- orchestrator: allow absolute paths under the active config directory while preserving
  project-root and relative-path checks
- skills tools: reference the active config directory in runtime output and help text
- shared memory: read .omc-config.json from the active config directory
- session history search: resolve transcript roots from the active config directory
- auto-slash-command executor: replace hardcoded ~/.claude in error message output
- factcheck guard: add ${CLAUDE_CONFIG_DIR} token to forbidden_path_prefixes defaults and token
  expander, replacing the hardcoded ${HOME}/.claude prefix
- config-dir helper: implement full getClaudeConfigDir() in config-dir.ts with tilde expansion
  and trailing-slash normalization, replacing the trivial getConfigDir() wrapper and the re-export
  from paths.ts
- runtime Node scripts: use shared config-dir helpers (ESM and CJS) instead of repeating
  ~/.claude fallbacks
- standalone hook templates: add templates/hooks/lib/config-dir.mjs shared helper (mirrors
  scripts/lib/config-dir.mjs) so template scripts resolve the config directory consistently
- HUD wrapper: import the shared lib/config-dir helper instead of embedding duplicate
  config-directory resolution logic
- persistent-mode scripts: resolve native tasks/todos from [$CLAUDE_CONFIG_DIR|~/.claude]
- shell scripts: use a shared config-dir.sh helper with ~ expansion and trailing-slash
  normalization
- installer: copy config-dir helpers alongside standalone hooks and the HUD find-node.sh helper
- plugin setup: move nodeBin to module scope so both settings.json and hooks.json patching blocks
  can access it (pre-existing const scoping bug where hooks.json patch always failed silently)
- skill snippets: replace $HOME/.claude with ${CLAUDE_CONFIG_DIR:-$HOME/.claude} in executable
  shell snippets across 8 skill files
- skill prose instructions: replace hardcoded ~/.claude in LLM-actionable directives (Read/Write
  tool targets, bash code blocks, path references in step instructions) across 9 skill files so
  an LLM executing the skill resolves the active config directory
- HUD usage API: document and test that Keychain service names hash the exact CLAUDE_CONFIG_DIR
  string, preserving distinct service-name mapping for ~-prefixed vs expanded inputs
- test files: align mock paths from paths.js to config-dir.js; fix vi.mock hoisting in
  doctor-conflicts.test.ts; resolve macOS /var symlink mismatch in bridge-integration,
  team-status, and edge-cases tests; update string-pattern assertions in hud-windows.test.ts
  and mingw-escape.test.ts
- test script: source lib/config-dir.sh in scripts/test-pr25.sh for post-install path
  verification

Adds focused regression coverage in:

- src/__tests__/auto-update.test.ts
- src/__tests__/cli-config-stop-callback.test.ts
- src/__tests__/config-dir.test.ts
- src/__tests__/delegation-enforcement-levels.test.ts
- src/__tests__/doctor-conflicts.test.ts
- src/__tests__/hud-api-key-source.test.ts
- src/__tests__/hud-marketplace-resolution.test.ts
- src/__tests__/hud-windows.test.ts
- src/__tests__/hud/cli-diagnostic.test.ts
- src/__tests__/hud/usage-api-lock.test.ts
- src/__tests__/hud/usage-api-stale.test.ts
- src/__tests__/hud/usage-api.test.ts
- src/__tests__/installer.test.ts
- src/__tests__/purge-stale-cache.test.ts
- src/__tests__/session-history-search.test.ts
- src/__tests__/setup-claude-md-script.test.ts
- src/__tests__/shared-memory.test.ts
- src/hooks/factcheck/__tests__/factcheck.test.ts
- src/installer/__tests__/standalone-hook-reconcile.test.ts
- src/notifications/__tests__/config-merge.test.ts
- src/notifications/__tests__/profiles.test.ts
- src/openclaw/__tests__/config.test.ts
- src/skills/__tests__/mingw-escape.test.ts
- src/team/__tests__/bridge-integration.test.ts
- src/team/__tests__/edge-cases.test.ts
- src/team/__tests__/inbox-outbox.test.ts
- src/team/__tests__/message-router.test.ts
- src/team/__tests__/outbox-reader.test.ts
- src/team/__tests__/team-registration.test.ts
- src/team/__tests__/team-status.test.ts
2026-04-04 19:40:17 +01:00
riftzen-bit
23ecc11ee7 fix(hooks): clear timeout in finally block for session-start scripts
Move clearTimeout from try body to finally block in both session-start
scripts to prevent timer leaks on fetch errors.

Constraint: Fetch abort controller requires timeout to be cleared
Confidence: high
Scope-risk: narrow
2026-03-28 14:40:55 -07:00
ToToKr
d6333b0464 fix(session-start): warn when silentAutoUpdate is set but inoperative in plugin mode (#1875)
When running as a Claude Code plugin (CLAUDE_PLUGIN_ROOT is set), the
silentAutoUpdate config option has no effect because session-start.mjs
never calls initSilentAutoUpdate() and performUpdate() blocks on
isRunningAsPlugin(). Add a session-start warning when both conditions
are detected, directing users to use the correct update method.

Fixes #1773

Co-authored-by: sspark-kisane <woo47380@gmail.com>
2026-03-25 15:34:10 +09:00
Yeachan-Heo
a6a0ff61eb Restore project memory on real session starts
The installed SessionStart hook runs in its own Node process, so the
existing project-memory registration path never reached the startup
additionalContext consumed by Claude Code. Load and, when needed,
refresh persisted project memory directly from the plugin runtime
inside the session-start script, then append the formatted summary
without relying on process-local collector state. Keep the legacy
helper aligned with plugin-root-aware imports.

Constraint: The installed SessionStart runtime is `scripts/session-start.mjs`, not the in-process bridge path
Constraint: Session-start hooks must remain failure-tolerant and continue on missing dist/runtime artifacts
Rejected: Refactor all session-start assembly into shared bridge/script runtime | broader change than needed for the bug
Rejected: Preserve collector-only registration across processes | process isolation makes that design ineffective here
Confidence: high
Scope-risk: narrow
Directive: Do not rely on in-memory contextCollector state for subprocess hook injection paths without a persisted or returned handoff
Tested: node --check scripts/session-start.mjs scripts/project-memory-session.mjs
Tested: Manual A/B subprocess reproduction against pre-fix session-start script vs patched script with persisted project-memory.json
Tested: Added focused regression test in src/__tests__/session-start-script-context.test.ts
Not-tested: Full Vitest run in this worktree (local shared node_modules does not expose a runnable repo-local vitest binary)
Related: issue #1779
2026-03-20 03:50:54 +00:00
Bellman
37360484fb fix(hooks): use correct npm package name in session-start update check (#1556) 2026-03-11 13:22:37 +09:00
Yeachan-Heo
ed0b695849 Fix stale context handoff for issue 1386 2026-03-06 10:37:13 +00:00
Bellman
517d599723 Fix HUD build guidance and detection for plugin cache (#1328) (#1332) 2026-03-04 23:16:18 +09:00
Bellman
de4efbbd75 fix(notifications): fix 3 reply listener bugs preventing Telegram reply injection (#1099)
* fix(notifications): fix 3 reply listener bugs preventing Telegram reply injection

Bug 1: session-start.mjs now calls startReplyListener() after notify block
so the reply listener daemon is started automatically on session start.

Bug 2: injectReply() replaces confidence-based analyzePaneContent() check
with simple empty-pane check, fixing false negatives on non-English panes.

Bug 3: sendToPane() splits tmux send-keys into two commands - text with
-l flag (literal) then Enter separately - fixing submit in Claude Code TUI.

Fixes #1097

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(notifications): remove unused analyzePaneContent import and dead code

Clean up dead code from the confidence check removal: remove unused
analyzePaneContent import and update doc comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: gaebal-gajae <gaebal-gajae@layofflabs.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 17:00:32 +09:00
Bellman
2fb310d3d6 fix(hooks): robust path resolution and graceful fallback for stale CLAUDE_PLUGIN_ROOT (#1011)
When a plugin update replaces an old version directory, sessions still
referencing the old CLAUDE_PLUGIN_ROOT fail with MODULE_NOT_FOUND,
stopping execution. This was intermittent and depended on timing of
cache cleanup vs hook invocation.

Changes:
- run.cjs: validate target exists before spawning; fall back to latest
  available plugin cache version with the same script; exit 0 gracefully
  when no valid target is found (prevents hook errors from blocking execution)
- session-start.mjs: use atomic temp-symlink + rename for symlink updates
  to eliminate the race window between rmSync and symlinkSync
- Add regression tests for run.cjs graceful fallback scenarios

Fixes #1007

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 07:55:13 +09:00
ZhuoHao Ou
2d83a53f70 fix(hooks): use junction type for Windows symlink compatibility
On Windows, directory symlinks require Developer Mode or admin
privileges. Junction type works without either, making the cache
symlink approach reliable across all platforms.
2026-02-24 15:48:38 +08:00
ZhuoHao Ou
3085e3f707 fix(hooks): address code review feedback for PR #980
- Handle EEXIST race in symlinkSync when concurrent sessions create
  the same symlink simultaneously
- Add comment linking staleStats default to STALE_THRESHOLD_MS constant
- Add test for updating existing symlink pointing to non-latest target
2026-02-24 15:09:44 +08:00
ZhuoHao Ou
affd960f71 fix(hooks): symlink old plugin cache versions instead of deleting them
Stop hooks fail with "Cannot find module" when a plugin is updated
mid-session because session-start.mjs aggressively deletes old cache
directories while running sessions still reference them via the
resolved CLAUDE_PLUGIN_ROOT environment variable.

Changes:
- session-start.mjs: Replace rmSync with symlinkSync for old versions
  (beyond latest 2), so stale CLAUDE_PLUGIN_ROOT paths follow the
  symlink to the current version's scripts
- paths.ts: Increase purgeStalePluginCacheVersions grace period from
  1 hour to 24 hours to avoid premature deletion during long sessions
- Add integration tests for the symlink cleanup behavior
- Update existing purge-stale-cache test staleStats default to match
  the new 24-hour threshold

Closes #970
2026-02-24 14:49:44 +08:00
Yeachan-Heo
040fafdd7d refactor: remove remaining sisyphus references repository-wide 2026-02-22 06:52:44 +00:00
Yeachan-Heo
f8079dd9f6 fix: session-start hook crash and notification env var mismatch
- Remove duplicate `const configDir` declaration in session-start.mjs
  that caused a SyntaxError killing the hook on every startup
- Add Telegram env var fallbacks (OMC_TELEGRAM_NOTIFIER_BOT_TOKEN,
  OMC_TELEGRAM_NOTIFIER_UID) to notification config
- Wire up notify('session-start') in bridge.ts processSessionStart

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 15:46:28 +00:00
Yeachan-Heo
1a35bb0758 Merge remote-tracking branch 'origin/feat/issue-560-notifications-dev' into dev
# Conflicts:
#	dist/cli/commands/doctor-conflicts.js.map
#	dist/cli/index.js.map
#	dist/features/auto-update.d.ts.map
#	dist/features/auto-update.js.map
#	dist/hooks/session-end/__tests__/callbacks.test.js.map
#	dist/hooks/session-end/callbacks.js.map
#	dist/notifications/config.js
#	dist/notifications/config.js.map
#	src/features/auto-update.ts
2026-02-11 15:31:15 +00:00
Yeachan-Heo
d766030c01 feat: support CLAUDE_CONFIG_DIR env var across all OMC components
All hardcoded ~/.claude paths now respect the CLAUDE_CONFIG_DIR
environment variable when set, enabling custom config directory
locations. Added src/utils/config-dir.ts as the canonical source
and updated getClaudeConfigDir() in paths.ts to delegate to it.

Closes #559

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 15:01:58 +00:00
Yeachan-Heo
72c816f2c4 feat: add lifecycle notifications for Discord and Telegram
Implement a full notification pipeline for session-start, session-stop, session-end, and ask-user-question events with tmux/context metadata and env-based auto-configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:19:27 +00:00
Yeachan-Heo
fb6828562c fix(hooks): improve Windows compatibility for hook scripts (#524)
Use pathToFileURL for dynamic imports instead of raw file paths, which
fixes "hook error" on Windows where backslash paths break ESM imports.
Add suppressOutput: true to empty hook responses to mitigate the known
Claude Code "hook error" display bug (#10936).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 00:36:22 +00:00
Yeachan-Heo
aae0ea2df3 fix: eliminate session state leakage across parallel Claude Code sessions
When multiple Claude Code sessions run in the same directory, mode state
(ultrawork, ralph, autopilot, etc.) leaked between sessions because state
files fell back to legacy shared paths. This change enforces session-scoped
state isolation: when a session_id is known, legacy state is invisible.

Key changes:
- persistent-mode.cjs: add isSessionMatch() helper, remove legacy fallback
  in readStateFileWithSession() when sessionId present, apply to all 8 modes
- session-start.mjs: restore only from session-scoped paths when session_id
  exists, legacy paths only when session_id absent
- ralph/loop.ts: readRalphState() and isUltraQAActive() no legacy fallback
- ultraqa/index.ts: readUltraQAState() no legacy fallback
- autopilot/state.ts: readAutopilotState() session-scoped only, thread
  sessionId through cancel.ts, validation.ts, enforcement.ts; fix missing
  sessionId propagation in transitionRalphToUltraQA -> updateExecution
- state-tools.ts: warnings added for missing session_id, schema descriptions
  updated
- Tests updated to match session-first behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 03:55:07 +00:00