Collapse multiple whitespace, trim, and increase max length to 160 chars
for observation titles in file-context deny reason.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix migration version conflict: addSessionPlatformSourceColumn now uses v25
- Sanitize observation titles in file-context deny reason (strip newlines, limit length)
- Guard json_each() with LIKE '[%' check for legacy bare-path rows
- Guard /stream SSE endpoint with 503 before DB initialization
- Scope bun-runner signal exit handling to start subcommand only
- Normalize platformSource at route boundary in DataRoutes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change file-read gate from deny to allow with limit:1, injecting the
observation timeline as additionalContext. Edit now works on gated files
since the file registers as "read" with near-zero token cost.
- Add updatedInput to HookResult type for PreToolUse hooks.
- Add .npmrc with legacy-peer-deps=true for tree-sitter peer dep conflicts.
- Add --legacy-peer-deps to npm fallback paths in smart-install.js so end
users without bun can install the 24 grammar packages.
- Rebuild plugin artifacts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove duplicate TranscriptWatcher/config imports in worker-service.ts
- Use normalizePlatformSource in handleSessionInitByClaudeId for consistency
- Don't skip DB completion when session not in memory (completeByClaudeId)
- Add try-catch around fetch in useContextPreview refresh callback
- Deduplicate store.getAllProjects() call in DataRoutes
- Fix malformed comment separators in migration runner
- Fix missing closing brace and JSDoc opener (merge artifact) in migration runner
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix indentation bugs flagged in PR review (SettingsDefaultsManager,
MigrationRunner), add current date/time to file read gate timeline
so the model can judge observation recency, and add documentation
for the file read gate feature.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs fixed:
1. SessionCompletionHandler called dbManager.getSessionStore() during
WorkerService construction, before DB initialization. Changed to
accept DatabaseManager and defer the call to runtime.
2. migration009 (generated_by_model, relevance_count columns) only ran
via the deprecated MigrationRunner path, never through SessionStore's
migration chain. Added addObservationModelColumns() to SessionStore
constructor. Checks column existence directly since schema_versions
may have been marked applied without the ALTER TABLE succeeding.
Also removed duplicate transcriptWatcher declaration and shutdown block
(merge artifact).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Filenames containing quotes, backslashes, or newlines could produce
malformed smart_outline/smart_unfold examples in the deny message.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Number(x) || 10 converts 0 to 10 since 0 is falsy, making it impossible
to request zero context depth (anchor only). Replace with explicit null
check in timeline(), getContextTimeline(), getTimelineByQuery().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tests/servers/mcp-tool-schemas.test.ts: remove `import '../../src/servers/mcp-server.js'`
which triggered server startup side effects; test only needs to read the TS source as text
- src/services/worker/SearchManager.ts: add Number() coercion for depth_before/depth_after
in timeline(), getContextTimeline(), getTimelineByQuery() — HTTP query strings deliver
these as strings, coercion ensures they are always numbers before being passed to
filterByDepth() and getTimelineAround*()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both tools had properties:{} which prevents MCP clients from exposing
params to the LLM, causing every call to send {} and get a 500 error
("Either query or filters required for search").
- search: declare query, limit, project, type, obs_type, dateStart, dateEnd, offset, orderBy
- timeline: declare anchor, query, depth_before, depth_after, project
- Add 3 schema regression tests (static source validation)
Closes#1384Closes#1413
Co-Authored-By: Claude <noreply@anthropic.com>
- Sort within-day observations chronologically (was specificity-ordered)
- Canonicalize relative paths to POSIX format before DB lookup
- Skip projects param when allProjects is empty (prevents cross-project leaks)
- Remove dead stderrMessage field and hook-command block (unused after permissionDecision switch)
- Type permissionDecision as 'allow' | 'deny' union instead of string
- Remove redundant non-null assertions in getObservationsByFilePath
- Add edit guidance to deny message (use sed via Bash with smart tools)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deny reason is the routing surface — show all cheaper exits:
semantic priming from the timeline, get_observations for details,
and smart_outline/smart_unfold for current code structure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The per-session FileReadGate was never requested and broke the cost
savings loop — subsequent reads in the same session silently bypassed
the timeline, hiding newly created observations.
Now the timeline fires on every read that has observations, using the
hook contract's permissionDecision: "deny" with the timeline as the
reason (exit 0 + JSON) instead of exit code 2 + stderr.
- Delete FileReadGate.ts entirely
- Remove /api/file-context/gate endpoint from DataRoutes
- Switch handler from exit code 2 to permissionDecision: "deny"
- Restore permissionDecision fields to HookResult
- Eliminate one HTTP round-trip per read (no gate check needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Resolve relative filePath against input.cwd before statSync; early-return on ENOENT
- Replace LIKE '%path%' with exact json_each equality to prevent false matches
- Sanitize and parameterize LIMIT to prevent NaN SQL errors
- Fix day-sorting to use earliest epoch in group, not first (specificity-sorted) item
- Use exact path equality in deduplicateObservations instead of substring includes
- Scope FileReadGate by session+cwd to prevent worktree collisions
- Refresh lastAccess TTL on active sessions; throttle prune to every 50 calls
- Type params as (string | number)[] instead of any[]
- Remove unused permissionDecision fields from HookResult
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Skip gate for files under 1,500 bytes — timeline (~370 tokens) costs
more than just reading small files directly
- Deduplicate observations by memory_session_id (one per session)
- Rank by specificity: files_modified > files_read, fewer tagged files > many
- Fetch 40 candidates, dedup/score down to 15 for display
- Reduce default by-file query limit from 30 to 15
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The compiled binary (v10.6.3) creates these columns at runtime via
MigrationRunner, but no corresponding migration exists in the TypeScript
source. Anyone building from source gets observations without these
columns, breaking the feedback pipeline and model tracking.
This migration conditionally adds both columns using PRAGMA table_info
checks, making it safe for databases that already have them.
Refs: #1626
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The per-prompt Chroma vector search injection on UserPromptSubmit adds latency
and context noise. Disable by default while we iterate on a more precise
file-context approach. Users can still opt in via CLAUDE_MEM_SEMANTIC_INJECT=true.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PHP was listed as a supported language in CHANGELOG and .php files were
scanned by search.ts, but parser.ts was missing:
- .php extension in LANG_MAP (causing detectLanguage to return 'unknown')
- 'php' entry in GRAMMAR_PACKAGES (no grammar path to resolve)
- PHP query patterns for symbol extraction
- PHP case in getQueryKey()
This meant smart_search/smart_outline/smart_unfold scanned PHP files
but extracted 0 symbols because the grammar could not be resolved.
Changes:
- Add '.php' -> 'php' to LANG_MAP
- Add 'php' -> 'tree-sitter-php/php' to GRAMMAR_PACKAGES
- Add PHP tree-sitter query patterns (functions, methods, classes, interfaces, traits, use statements)
- Add 'php' case to getQueryKey()
- Add tree-sitter-php ^0.24.2 to devDependencies
On Bun/Windows, `require.main !== module` in CJS mode causes the worker
to exit silently with code 0. The wrapper already sets CLAUDE_MEM_MANAGED=true
when spawning the inner worker, so checking this env var is a safe fallback
that doesn't affect standalone execution.
Ref #1450 (incomplete fix in PR #1518 — ESM path fixed but CJS branch not).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: wire up Cursor integration in installer — was incorrectly marked "coming soon"
CursorHooksInstaller.ts was fully built but never connected to the
installer. Set supported: true in IDE detection and call installCursorHooks
in the setup flow, matching the pattern used by other integrations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: wire up Cursor MCP configuration during install
PR review flagged that the hint says "hooks + MCP integration" but
configureCursorMcp() was never called during install. Now invoked
after hooks install with graceful fallback if MCP setup fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Observer prompt now explicitly requires XML observation blocks or empty
responses — prose explanations like "Skipping" are discarded. ResponseProcessor
logs a warning when non-XML content is received. Recording focus expanded to
include concrete debugging findings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The parser correctly strips observation types from concepts arrays when the
LLM ignores the prompt instruction. This is routine data normalization, not
an error — downgrade to debug to reduce log noise.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The install simplification in 21b10b46 over-applied scope: it replaced the
entire runInstallCommand (interactive IDE multi-select, --ide flag, 13 IDE
setup dispatchers) with just two `claude` CLI commands. The intent was to
simplify the Claude Code path only.
Now: Claude Code uses `claude plugin marketplace add` + `claude plugin install`.
All other IDEs get the full installer flow (file copy, registration, IDE-specific
setup). Interactive multi-select and --ide flag are restored.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The generated_by_model column was added to the observations table in the
Phase 0 governance schema migration but never wired into the INSERT
statements. All 3,878+ observations in production have this field NULL.
This fix threads the model ID from each agent (SDKAgent, GeminiAgent,
OpenRouterAgent) through processAgentResponse() into storeObservation(),
storeObservations(), and storeObservationsAndMarkComplete().
Unblocks Thompson Sampling RFC (#1571) which needs {obs_type}:{model}
as the bandit arm key.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical:
- migrations: change version 8 → 25 to avoid collision with
MigrationRunner.addObservationHierarchicalFields (uses version 8)
- SessionRoutes: remove duplicate imports that prevent compilation
Major:
- SessionRoutes: call applyTierRouting() before every generator spawn
(stale-recovery and crash-recovery paths were missing it)
- applyTierRouting: clear session.modelOverride at top before re-evaluating
to prevent stale tier from persisting across spawns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>