agentcache 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,243 +1,163 @@
1
1
  # AgentCache
2
2
 
3
- Your AI coding agents forget everything between sessions. AgentCache fixes that it learns what you know, remembers it across sessions, and injects it into every future agent automatically, across every IDE.
4
-
5
- > "Don't mock the database in integration tests — we got burned when mocked tests passed but prod migration failed"
6
-
7
- That lesson, learned once, becomes a permanent rule. Every future session with every IDE gets it. You never say it again.
8
-
9
- ## What it does
10
-
11
- AgentCache observes your coding sessions and compiles reusable knowledge — rules, lessons, architectural decisions, project context — into a local database. Every future session gets that knowledge injected at the start, regardless of IDE or LLM.
12
-
13
- - **Learns** from what your agents discover during sessions
14
- - **Injects** relevant knowledge at the start of every new session
15
- - **Works everywhere** — any IDE, any LLM, simultaneously
16
- - **Stays local** — SQLite on your machine, nothing leaves your disk
17
-
18
- ## Install
3
+ **Your codebase learns.** AgentCache compiles what your AI agents discover into a `SKILL.md` that every future session in any IDE, with any LLM reads automatically.
19
4
 
20
5
  ```bash
21
6
  npm install -g agentcache
22
7
  ```
23
8
 
24
- Done. Start a session in any IDE — AgentCache is already running.
9
+ That's it. No config. No accounts. No sync server.
25
10
 
26
- No init. No setup. No config. The install:
11
+ ---
27
12
 
28
- 1. Creates `~/.agentcache/agentcache.db`
29
- 2. Detects installed IDEs (Claude Code, Cursor, Roo Code, Windsurf, Continue, Codex)
30
- 3. Registers itself as an MCP server in each
31
- 4. Sets up Claude Code hooks for automatic transcript recovery
32
- 5. Spawns `compile-all` in background to process your existing transcript history
13
+ ## The Problem
14
+
15
+ You tell Claude "don't mock the database in integration tests." It forgets. You tell Cursor the same thing. You tell Codex. You repeat yourself across every IDE, every session, every project.
33
16
 
34
- ## Team knowledge without a sync server
17
+ Your agents are amnesiac. Your knowledge evaporates.
35
18
 
36
- Compiled project knowledge is written to `<repo>/.agentcache/skills/project-knowledge/SKILL.md`. Commit it. Every teammate gets your team's accumulated decisions and context on clone, automatically picked up by any Agent Skills-compatible tool.
19
+ ## What AgentCache Does
20
+
21
+ After a few sessions, AgentCache produces a `SKILL.md` in your repo:
37
22
 
38
23
  ```markdown
24
+ # Project Knowledge
25
+
26
+ ## Rules
27
+ - Never mock the database in integration tests — we got burned when mocks passed but prod migration failed
28
+ - Always use snake_case for database columns
29
+ - Run type-check before committing
30
+
39
31
  ## Decisions
40
32
  - Using Drizzle ORM over Prisma for raw SQL escape hatches
41
33
  - PostgreSQL for all persistent state, Redis for ephemeral cache only
42
34
 
43
- ## Current Context
35
+ ## Context
44
36
  - Migrating from REST to GraphQL, both coexist until Q3
37
+ - Auth service rewrite driven by compliance (not tech debt)
45
38
  ```
46
39
 
47
- No sync server. No accounts. Just git.
40
+ This file lives at `<repo>/.agentcache/skills/project-knowledge/SKILL.md`. It's auto-discovered by **38+ tools** that support the Agent Skills spec — no MCP connection required. Commit it. Every teammate gets your team's accumulated knowledge on clone.
41
+
42
+ **The database is local. The output is git.**
48
43
 
49
- ## How it works
44
+ ## How It Works
50
45
 
51
46
  ```
52
- ┌────────────────────────────────────────────────────────────────────────┐
53
- Your Machine
54
- │ │
55
- ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
56
- │ │ Claude │ │ Cursor │ │ Roo │ │ Codex │ ... │
57
- │ Code │ │ │ │ Code │ │ │ │
58
- │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
59
- └─────────────┴─────────────┴─────────────┘
60
- │ │ MCP Protocol (stdio) │
61
- │ ┌────────────┴────────────┐ │
62
- │ AgentCache MCP Server │ │
63
- │ └────────────┬────────────┘ │
64
- │ │ │
65
- │ ┌─────────┴──────────┐ │
66
- │ │ ~/.agentcache/ │ │
67
- │ │ agentcache.db │ │
68
- │ │ (SQLite + WAL) │ │
69
- │ └────────────────────┘ │
70
- └────────────────────────────────────────────────────────────────────────┘
47
+ Session 1 (Claude Code) Session 2 (Cursor) Session 3 (Codex)
48
+ │ │
49
+ └───────────────────────────┴───────────────────────┘
50
+
51
+ AgentCache (MCP Server)
52
+
53
+ ┌───────────────┴───────────────┐
54
+
55
+ ~/.agentcache/ <repo>/.agentcache/
56
+ agentcache.db skills/.../SKILL.md
57
+ (local SQLite) (committed to git)
71
58
  ```
72
59
 
73
- ### The cycle
60
+ 1. **Session starts** → agent calls `inject_context` → gets compiled rules, lessons, decisions
61
+ 2. **During session** → agent calls `compile_submit` as it learns things
62
+ 3. **Session ends** → knowledge compiles into the database
63
+ 4. **Periodically** → database projects into `SKILL.md` for git distribution
74
64
 
75
- 1. **Session starts** agent calls `inject_context` receives compiled rules, lessons, decisions
76
- 2. **During session** — agent calls `compile_submit` incrementally as it learns things
77
- 3. **Session ends** — observations are already saved. If the session terminates unexpectedly, transcript recovery handles it next time.
65
+ Knowledge compounds. One lesson stated once propagates to every future session across every IDE.
78
66
 
79
- ### Knowledge types
67
+ ## Install
80
68
 
81
- | Type | Scope | Example |
82
- |------|-------|---------|
83
- | Rule | Global | "Always use snake_case for database columns" |
84
- | Lesson | Global | "Don't mock the database in integration tests — mocked tests passed but prod migration failed" |
85
- | Decision | Project | "Using Drizzle ORM over Prisma because we need raw SQL escape hatches" |
86
- | Context | Project | "Currently migrating from REST to GraphQL, both coexist" |
69
+ ```bash
70
+ npm install -g agentcache
71
+ ```
87
72
 
88
- Rules and lessons are global — they apply to all your projects. Decisions and context are project-scoped.
73
+ The install automatically:
74
+ 1. Creates `~/.agentcache/agentcache.db`
75
+ 2. Detects your IDEs (Claude Code, Cursor, Roo Code, Windsurf, Continue, Codex)
76
+ 3. Registers as an MCP server in each — with auto-approve
77
+ 4. Sets up Claude Code hooks for transcript recovery
78
+ 5. Compiles your existing transcript history in the background
79
+
80
+ **Zero config. Zero setup. Start a session and it's working.**
89
81
 
90
- ## Security model
82
+ ## Supported IDEs
91
83
 
92
- AgentCache creates a persistent feedback loop: agents write observations → observations compile into knowledge → knowledge injects into future sessions. This is the product's core value **and** its main attack surface. Both are the same thing.
84
+ | IDE | MCP | Auto-Approve | Transcript Recovery |
85
+ |-----|-----|-------------|-------------------|
86
+ | Claude Code | ✓ | ✓ | Full (hooks + JSONL) |
87
+ | Cursor | ✓ | ✓ | Full (agent transcripts) |
88
+ | Roo Code (VS Code) | ✓ | ✓ | Full (task history) |
89
+ | Codex | ✓ | ✓ | Full (session JSONL) |
90
+ | Continue | ✓ | ✓ | Full (session JSON) |
91
+ | Windsurf | ✓ | ✓ | Incremental only |
92
+ | Goose | — | — | Full (SQLite) |
93
93
 
94
- ### What the security model guarantees
94
+ All IDEs share the same knowledge database. A rule learned in Claude Code is injected in Cursor the next time you open it.
95
95
 
96
- - **Quarantine by default** — AUTO observations (agent-submitted) are never injected until confirmed across 2+ independent sessions. A single prompt-injected `compile_submit` call cannot poison your knowledge base — it lands in quarantine and requires independent reinforcement before it's ever served.
97
- - **Enforced rules are human-only** — The enforce mechanism (which blocks agent tool calls) can only be set via CLI (`agentcache add-rule --enforce`). No MCP tool can create policy an agent is subject to.
98
- - **Scope gate** — Agent-submitted observations are always project-scoped. Promotion to global scope requires explicit human action (USER authority). An agent cannot write a global rule.
99
- - **Quarantine ≠ absent** — Quarantined items are captured and visible in `agentcache review`. They just don't inject. The review command is how you clear or promote them.
96
+ ## Security Model
100
97
 
101
- ### What the security model does not guarantee
98
+ AgentCache creates a feedback loop: agents write observations → observations compile → knowledge injects into future sessions. This is the product's value **and** its attack surface.
102
99
 
103
- - `compile-all` processes raw transcripts that may contain injected content. Extraction prompt hardening raises the bar, but a sufficiently crafted transcript can still produce a quarantined (non-injecting) entry. Review your pending queue periodically.
104
- - `locked` mode disables `compile_submit` entirely and requires human-triggered batch compilation. It reduces the attack surface significantly but `compile-all` against a poisoned transcript is still a vector.
100
+ **Quarantine gate**: Agent-submitted observations require confirmation across 2+ independent sessions before injection. A single prompt-injected `compile_submit` cannot poison your knowledge.
105
101
 
106
- ### Security modes
102
+ **Human-only enforcement**: Policy rules (that block tool calls) can only be created via CLI. No MCP tool can create policy.
107
103
 
108
- Configure in `~/.agentcache/config.json`:
104
+ **Scope gate**: Agent-submitted observations are always project-scoped. Global requires explicit human action.
105
+
106
+ ### Security Modes
109
107
 
110
108
  ```json
111
109
  { "security": "auto" }
112
110
  ```
113
111
 
114
- | Mode | Behavior | For |
115
- |------|----------|-----|
116
- | `auto` (default) | Quarantine — AUTO items inject after 2+ session confirmations | Solo devs, indie shops |
117
- | `review` | All new items land in quarantine. Nothing injects until `agentcache review` approves it | BFSI, healthcare, regulated environments |
118
- | `locked` | `compile_submit` disabled. Compile-all only, human-triggered batch review | Maximum control |
112
+ | Mode | Behavior |
113
+ |------|----------|
114
+ | `auto` | Quarantine — new items inject after 2+ session confirmations |
115
+ | `review` | Nothing injects until `agentcache review` approves it |
116
+ | `locked` | `compile_submit` disabled. Human-triggered batch only |
119
117
 
120
- ## CLI commands
118
+ ## CLI
121
119
 
122
120
  ```bash
123
- agentcache status # Knowledge stats for current project
124
- agentcache doctor # Diagnose installation problems
125
- agentcache review # List quarantined items, approve or reject
126
- agentcache promote <id> # Promote a single item past quarantine
127
- agentcache add-rule "never commit secrets" --enforce # Create enforced policy (human only)
128
- agentcache add-rule "use tabs" --global # Global rule across all projects
129
- agentcache compile-all # Batch-compile all unprocessed transcripts
130
- agentcache setup # Re-register with IDEs (only if postinstall failed)
121
+ agentcache doctor # Diagnose installation
122
+ agentcache status # Knowledge stats
123
+ agentcache review # Approve/reject quarantined items
124
+ agentcache promote <id> # Approve a single item
125
+ agentcache add-rule "never force push" --enforce # Create policy (human-only)
126
+ agentcache compile-all # Batch-compile all transcripts
127
+ agentcache setup # Re-register with IDEs
131
128
  ```
132
129
 
133
- ## compile-all — batch compilation
134
-
135
- Processes all pending transcripts without depending on active MCP sessions.
130
+ ## compile-all
136
131
 
137
- **LLM backend (first available wins):**
132
+ Processes all uncompiled transcripts from all IDEs using the first available LLM backend:
138
133
 
139
- 1. CLI tools with stored auth: `claude`, `codex`, `gemini`, `copilot`, `aider`, `goose`
134
+ 1. CLI tools: `claude`, `codex`, `gemini`, `copilot`, `aider`, `goose`
140
135
  2. Ollama at `localhost:11434`
141
136
  3. `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`
142
137
 
143
- **Triggers automatically:**
138
+ Runs automatically on install and when pending transcripts exceed 20.
144
139
 
145
- - After `npm install -g agentcache` (clears initial backlog)
146
- - When pending transcripts exceed 20 (background janitor)
147
- - Lockfile prevents concurrent runs
148
-
149
- ## MCP tools
150
-
151
- | Tool | Purpose |
152
- |------|---------|
153
- | `inject_context` | Load compiled knowledge at session start |
154
- | `compile_submit` | Submit observations incrementally during session |
155
- | `compile_cluster` | Resolve clustering when observations overlap existing knowledge |
156
- | `compile_extract` | Process queued transcripts from previous sessions |
157
- | `enforce` | Check tool calls against enforced policy rules |
158
- | `save_observation` | Save a permanent observation (USER authority, never auto-deprecated) |
159
- | `get_knowledge` | Query the knowledge database |
160
- | `deprecate_knowledge` | Mark knowledge as deprecated |
161
-
162
- ## How knowledge compiles
163
-
164
- ```
165
- Observations (raw)
166
-
167
-
168
- Extract → Normalize → Canonicalize → Cluster → Detect Contradictions → Compile
169
-
170
- ┌───────────────────────────────────────────┘
171
-
172
- PENDING store
173
-
174
- ┌─────────┴──────────┐
175
- │ │
176
- AUTO items USER items
177
- (quarantine gate) (inject immediately)
178
- 2+ sessions before
179
- injection
180
- ```
181
-
182
- **Two compilation paths:**
183
-
184
- - **In-session** — agent processes extraction via MCP tools in your IDE
185
- - **Batch** — `compile-all` runs independently, processes full backlog
186
-
187
- **Two output formats:**
188
-
189
- - **MCP injection** — structured context via `inject_context`
190
- - **SKILL.md** — Agent Skills spec files auto-discovered by 38+ tools without MCP
191
-
192
- ## Design principles
193
-
194
- **Zero config** — `npm install -g agentcache` is the only step. No dotfiles, no init, no config to maintain.
195
-
196
- **Universal** — MCP is the only interface. Any IDE, any LLM. No IDE-specific code paths.
197
-
198
- **Developer-scoped** — One database per developer, not per project. Global knowledge (rules, lessons) benefits all your projects. Project knowledge stays scoped.
199
-
200
- **Resilient to abrupt exits** — Incremental submission + transcript recovery + pipe-independent compilation means knowledge survives crashes, ctrl-c, and MCP disconnects.
201
-
202
- **Anti-bloat** — Confidence promotion, 30-day decay on unused items, budget caps (20 rules / 10 lessons / 10 decisions / 5 context per session), priority ranking.
203
-
204
- ## Supported IDEs
205
-
206
- | IDE | MCP | Auto-Approve | Transcript Recovery | Hooks |
207
- |-----|-----|-------------|-------------------|-------|
208
- | Claude Code | Yes | Yes | Full (JSONL) | Stop, SessionStart, PreToolUse |
209
- | Cursor | Yes | Yes | Incremental only | — |
210
- | Roo Code | Yes | Yes | Full (JSON via compile-all) | — |
211
- | Windsurf | Yes | Yes | Incremental only | — |
212
- | Continue | Yes | Yes | Full (JSON) | — |
213
- | Codex | Yes | Yes | Full (JSONL via compile-all) | — |
214
- | Goose | — | — | Full (SQLite via compile-all) | — |
215
- | Aider | Coming soon | | | |
216
- | GitHub Copilot | Coming soon | | | |
217
- | Zed AI | Coming soon | | | |
218
-
219
- ## Data storage
140
+ ## Data
220
141
 
221
142
  ```
222
143
  ~/.agentcache/
223
- ├── agentcache.db # Knowledge, observations, sessions, pending queue
224
- ├── config.json # Security mode and settings
225
- ├── compile-all.lock # Prevents concurrent compilation
226
- └── skills/developer-knowledge/SKILL.md # Global skill (auto-generated)
227
- ```
144
+ ├── agentcache.db # Knowledge database (SQLite + WAL)
145
+ ├── config.json # Security mode
146
+ └── compile-all.lock # Prevents concurrent compilation
228
147
 
229
- No data leaves your machine. No network calls. No telemetry. No accounts.
230
-
231
- ### Project identity
148
+ <repo>/.agentcache/
149
+ └── skills/project-knowledge/SKILL.md # Git-committed team knowledge
150
+ ```
232
151
 
233
- Projects are identified by a hash of their full filesystem path. `/work/api` and `/personal/api` are different projects. Knowledge never leaks between same-named projects in different locations.
152
+ No network calls. No telemetry. No accounts. Everything stays on your machine (except what you choose to commit).
234
153
 
235
- ## Roadmap
154
+ ## Principles
236
155
 
237
- - **Native plugins** — Marketplace listings and deeper UI integrations for all supported IDEs
238
- - **Team knowledge sharing** — Share compiled knowledge across your team
239
- - **Cloud sync** — Same developer, different machines, same knowledge
240
- - **Analytics dashboard** — Compilation stats, knowledge growth, most-referenced rules
156
+ - **Zero config** — `npm install -g` is the only step
157
+ - **Universal** — MCP protocol, any IDE, any LLM
158
+ - **Git-native output** — SKILL.md is the distribution mechanism
159
+ - **Secure by default** — quarantine gate, scope restrictions, human-only policy
160
+ - **Anti-bloat** — 30-day decay, budget caps, confidence promotion
241
161
 
242
162
  ## Contributing
243
163
 
@@ -246,7 +166,7 @@ git clone https://github.com/raghav-a21ai/agentcache
246
166
  cd agentcache
247
167
  npm install
248
168
  npm run build
249
- npm test
169
+ npm test # 205 tests
250
170
  ```
251
171
 
252
172
  ## License
@@ -0,0 +1,71 @@
1
+ // src/utils/ide-detector.ts
2
+ import { existsSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+ function getRooConfigPath() {
6
+ const home = homedir();
7
+ if (process.platform === "darwin") {
8
+ return join(home, "Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
9
+ }
10
+ if (process.platform === "win32") {
11
+ return join(process.env.APPDATA || join(home, "AppData/Roaming"), "Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
12
+ }
13
+ return join(home, ".config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
14
+ }
15
+ function getWindsurfConfigPath() {
16
+ const home = homedir();
17
+ return join(home, ".codeium", "windsurf", "mcp_config.json");
18
+ }
19
+ function getContinueConfigPath() {
20
+ const home = homedir();
21
+ return join(home, ".continue", "mcpServers", "agentcache.json");
22
+ }
23
+ function getCodexConfigPath() {
24
+ const home = homedir();
25
+ return join(home, ".codex", "config.toml");
26
+ }
27
+ function detectInstalledIdes() {
28
+ const home = homedir();
29
+ return [
30
+ {
31
+ name: "Claude Code",
32
+ detected: existsSync(join(home, ".claude")),
33
+ mcpConfigPath: join(home, ".claude.json"),
34
+ mcpConfigFormat: "claude-settings"
35
+ },
36
+ {
37
+ name: "Cursor",
38
+ detected: existsSync(join(home, ".cursor")),
39
+ mcpConfigPath: join(home, ".cursor", "mcp.json"),
40
+ mcpConfigFormat: "mcp-json"
41
+ },
42
+ {
43
+ name: "Roo Code",
44
+ detected: existsSync(getRooConfigPath()),
45
+ mcpConfigPath: getRooConfigPath(),
46
+ mcpConfigFormat: "mcp-json"
47
+ },
48
+ {
49
+ name: "Windsurf",
50
+ detected: existsSync(join(home, ".codeium", "windsurf")) || existsSync(join(home, ".windsurf")),
51
+ mcpConfigPath: getWindsurfConfigPath(),
52
+ mcpConfigFormat: "mcp-json"
53
+ },
54
+ {
55
+ name: "Continue",
56
+ detected: existsSync(join(home, ".continue")),
57
+ mcpConfigPath: getContinueConfigPath(),
58
+ mcpConfigFormat: "continue-dir"
59
+ },
60
+ {
61
+ name: "Codex",
62
+ detected: existsSync(join(home, ".codex")),
63
+ mcpConfigPath: getCodexConfigPath(),
64
+ mcpConfigFormat: "codex-toml"
65
+ }
66
+ ];
67
+ }
68
+
69
+ export {
70
+ detectInstalledIdes
71
+ };
@@ -1,75 +1,7 @@
1
- // src/utils/ide-detector.ts
2
- import { existsSync } from "fs";
3
- import { join } from "path";
4
- import { homedir } from "os";
5
- function getRooConfigPath() {
6
- const home = homedir();
7
- if (process.platform === "darwin") {
8
- return join(home, "Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
9
- }
10
- if (process.platform === "win32") {
11
- return join(process.env.APPDATA || join(home, "AppData/Roaming"), "Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
12
- }
13
- return join(home, ".config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json");
14
- }
15
- function getWindsurfConfigPath() {
16
- const home = homedir();
17
- return join(home, ".codeium", "windsurf", "mcp_config.json");
18
- }
19
- function getContinueConfigPath() {
20
- const home = homedir();
21
- return join(home, ".continue", "mcpServers", "agentcache.json");
22
- }
23
- function getCodexConfigPath() {
24
- const home = homedir();
25
- return join(home, ".codex", "config.toml");
26
- }
27
- function detectInstalledIdes() {
28
- const home = homedir();
29
- return [
30
- {
31
- name: "Claude Code",
32
- detected: existsSync(join(home, ".claude")),
33
- mcpConfigPath: join(home, ".claude.json"),
34
- mcpConfigFormat: "claude-settings"
35
- },
36
- {
37
- name: "Cursor",
38
- detected: existsSync(join(home, ".cursor")),
39
- mcpConfigPath: join(home, ".cursor", "mcp.json"),
40
- mcpConfigFormat: "mcp-json"
41
- },
42
- {
43
- name: "Roo Code",
44
- detected: existsSync(getRooConfigPath()),
45
- mcpConfigPath: getRooConfigPath(),
46
- mcpConfigFormat: "mcp-json"
47
- },
48
- {
49
- name: "Windsurf",
50
- detected: existsSync(join(home, ".codeium", "windsurf")) || existsSync(join(home, ".windsurf")),
51
- mcpConfigPath: getWindsurfConfigPath(),
52
- mcpConfigFormat: "mcp-json"
53
- },
54
- {
55
- name: "Continue",
56
- detected: existsSync(join(home, ".continue")),
57
- mcpConfigPath: getContinueConfigPath(),
58
- mcpConfigFormat: "continue-dir"
59
- },
60
- {
61
- name: "Codex",
62
- detected: existsSync(join(home, ".codex")),
63
- mcpConfigPath: getCodexConfigPath(),
64
- mcpConfigFormat: "codex-toml"
65
- }
66
- ];
67
- }
68
-
69
1
  // src/utils/ide-registrar.ts
70
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync, appendFileSync } from "fs";
71
- import { join as join2, dirname } from "path";
72
- import { homedir as homedir2 } from "os";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from "fs";
3
+ import { join, dirname } from "path";
4
+ import { homedir } from "os";
73
5
  import { execSync } from "child_process";
74
6
  function findNodeBinary() {
75
7
  try {
@@ -83,7 +15,7 @@ function findAgentcacheScript() {
83
15
  const binPath = execSync("which agentcache", { encoding: "utf-8" }).trim();
84
16
  return binPath;
85
17
  } catch {
86
- return join2(dirname(dirname(__dirname)), "dist", "cli.js");
18
+ return join(dirname(dirname(__dirname)), "dist", "cli.js");
87
19
  }
88
20
  }
89
21
  function isVscodeExtensionIde(ide) {
@@ -116,9 +48,9 @@ function registerMcpServer(ide) {
116
48
  return false;
117
49
  }
118
50
  function registerClaudeCode() {
119
- const claudeJsonPath = join2(homedir2(), ".claude.json");
51
+ const claudeJsonPath = join(homedir(), ".claude.json");
120
52
  let config = {};
121
- if (existsSync2(claudeJsonPath)) {
53
+ if (existsSync(claudeJsonPath)) {
122
54
  try {
123
55
  config = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
124
56
  } catch {
@@ -137,10 +69,10 @@ function registerClaudeCode() {
137
69
  writeFileSync(claudeJsonPath, JSON.stringify(config, null, 2));
138
70
  serverRegistered = true;
139
71
  }
140
- const settingsPath = join2(homedir2(), ".claude", "settings.json");
141
- if (existsSync2(join2(homedir2(), ".claude"))) {
72
+ const settingsPath = join(homedir(), ".claude", "settings.json");
73
+ if (existsSync(join(homedir(), ".claude"))) {
142
74
  let settings = {};
143
- if (existsSync2(settingsPath)) {
75
+ if (existsSync(settingsPath)) {
144
76
  try {
145
77
  settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
146
78
  } catch {
@@ -164,7 +96,7 @@ function registerClaudeCode() {
164
96
  }
165
97
  function registerMcpJson(ide) {
166
98
  let config = {};
167
- if (existsSync2(ide.mcpConfigPath)) {
99
+ if (existsSync(ide.mcpConfigPath)) {
168
100
  try {
169
101
  config = JSON.parse(readFileSync(ide.mcpConfigPath, "utf-8"));
170
102
  } catch {
@@ -212,7 +144,7 @@ function registerContinue(ide) {
212
144
  }
213
145
  function registerCodex(ide) {
214
146
  const configPath = ide.mcpConfigPath;
215
- if (existsSync2(configPath)) {
147
+ if (existsSync(configPath)) {
216
148
  const content = readFileSync(configPath, "utf-8");
217
149
  if (content.includes("[mcp_servers.agentcache]")) return false;
218
150
  }
@@ -223,7 +155,7 @@ args = ["serve"]
223
155
  default_tools_approval_mode = "auto"
224
156
  `;
225
157
  mkdirSync(dirname(configPath), { recursive: true });
226
- if (existsSync2(configPath)) {
158
+ if (existsSync(configPath)) {
227
159
  appendFileSync(configPath, tomlBlock);
228
160
  } else {
229
161
  writeFileSync(configPath, tomlBlock.trimStart());
@@ -231,10 +163,10 @@ default_tools_approval_mode = "auto"
231
163
  return true;
232
164
  }
233
165
  function registerClaudeHooks() {
234
- const settingsPath = join2(homedir2(), ".claude", "settings.json");
235
- if (!existsSync2(join2(homedir2(), ".claude"))) return false;
166
+ const settingsPath = join(homedir(), ".claude", "settings.json");
167
+ if (!existsSync(join(homedir(), ".claude"))) return false;
236
168
  let settings = {};
237
- if (existsSync2(settingsPath)) {
169
+ if (existsSync(settingsPath)) {
238
170
  try {
239
171
  settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
240
172
  } catch {
@@ -265,7 +197,6 @@ function registerClaudeHooks() {
265
197
  }
266
198
 
267
199
  export {
268
- detectInstalledIdes,
269
200
  registerMcpServer,
270
201
  registerClaudeHooks
271
202
  };
@@ -139,19 +139,62 @@ function parse3(path) {
139
139
  return events;
140
140
  }
141
141
 
142
- // src/utils/transcript-parsers/roo-code-json.ts
143
- var roo_code_json_exports = {};
144
- __export(roo_code_json_exports, {
142
+ // src/utils/transcript-parsers/cursor-jsonl.ts
143
+ var cursor_jsonl_exports = {};
144
+ __export(cursor_jsonl_exports, {
145
145
  canParse: () => canParse4,
146
146
  parse: () => parse4
147
147
  });
148
148
  import { readFileSync as readFileSync4 } from "fs";
149
149
  function canParse4(path) {
150
- return path.includes("roo-cline/tasks/") && path.endsWith("api_conversation_history.json");
150
+ if (!path.endsWith(".jsonl")) return false;
151
+ return path.includes(".cursor/projects/") && path.includes("/agent-transcripts/");
151
152
  }
152
153
  function parse4(path) {
153
154
  const content = readFileSync4(path, "utf-8");
154
155
  const events = [];
156
+ for (const line of content.split("\n")) {
157
+ if (!line.trim()) continue;
158
+ try {
159
+ const obj = JSON.parse(line);
160
+ if (obj.role === "user" && obj.message?.content) {
161
+ const blocks = Array.isArray(obj.message.content) ? obj.message.content : [{ type: "text", text: obj.message.content }];
162
+ const text = blocks.filter((c) => c.type === "text").map((c) => c.text).join("\n");
163
+ if (text) events.push({ type: "message", role: "user", content: text });
164
+ } else if (obj.role === "assistant" && obj.message?.content) {
165
+ const blocks = Array.isArray(obj.message.content) ? obj.message.content : [{ type: "text", text: obj.message.content }];
166
+ for (const block of blocks) {
167
+ if (block.type === "text" && block.text) {
168
+ events.push({ type: "message", role: "assistant", content: block.text });
169
+ } else if (block.type === "tool_use") {
170
+ events.push({
171
+ type: "tool_use",
172
+ tool_name: block.name,
173
+ tool_input: block.input
174
+ });
175
+ }
176
+ }
177
+ }
178
+ } catch {
179
+ continue;
180
+ }
181
+ }
182
+ return events;
183
+ }
184
+
185
+ // src/utils/transcript-parsers/roo-code-json.ts
186
+ var roo_code_json_exports = {};
187
+ __export(roo_code_json_exports, {
188
+ canParse: () => canParse5,
189
+ parse: () => parse5
190
+ });
191
+ import { readFileSync as readFileSync5 } from "fs";
192
+ function canParse5(path) {
193
+ return path.includes("roo-cline/tasks/") && path.endsWith("api_conversation_history.json");
194
+ }
195
+ function parse5(path) {
196
+ const content = readFileSync5(path, "utf-8");
197
+ const events = [];
155
198
  try {
156
199
  const messages = JSON.parse(content);
157
200
  if (!Array.isArray(messages)) return [];
@@ -182,7 +225,7 @@ function parse4(path) {
182
225
  }
183
226
 
184
227
  // src/utils/transcript-parsers/index.ts
185
- var parsers = [codex_jsonl_exports, roo_code_json_exports, claude_jsonl_exports, continue_json_exports];
228
+ var parsers = [codex_jsonl_exports, cursor_jsonl_exports, roo_code_json_exports, claude_jsonl_exports, continue_json_exports];
186
229
  function parseTranscriptAuto(path) {
187
230
  for (const parser of parsers) {
188
231
  if (parser.canParse(path)) return parser.parse(path);
@@ -194,6 +237,31 @@ function parseTranscriptAuto(path) {
194
237
  function parseTranscript(path) {
195
238
  return parseTranscriptAuto(path);
196
239
  }
240
+ function findLatestTranscript() {
241
+ const baseDir = getClaudeTranscriptsDir();
242
+ if (!existsSync(baseDir)) return null;
243
+ let latest = null;
244
+ try {
245
+ const dirs = readdirSync(baseDir).map((d) => join(baseDir, d)).filter((d) => statSync(d).isDirectory());
246
+ for (const dir of dirs) {
247
+ try {
248
+ const files = readdirSync(dir).filter((f) => f.endsWith(".jsonl"));
249
+ for (const file of files) {
250
+ const fullPath = join(dir, file);
251
+ const mtime = statSync(fullPath).mtimeMs;
252
+ if (!latest || mtime > latest.mtime) {
253
+ latest = { path: fullPath, mtime };
254
+ }
255
+ }
256
+ } catch {
257
+ continue;
258
+ }
259
+ }
260
+ } catch {
261
+ return null;
262
+ }
263
+ return latest?.path ?? null;
264
+ }
197
265
  function findAllClaudeTranscripts() {
198
266
  const baseDir = getClaudeTranscriptsDir();
199
267
  if (!existsSync(baseDir)) return [];
@@ -247,6 +315,37 @@ function findAllCodexTranscripts() {
247
315
  walkDir(baseDir);
248
316
  return transcripts;
249
317
  }
318
+ function findAllCursorTranscripts() {
319
+ const baseDir = join(homedir(), ".cursor", "projects");
320
+ if (!existsSync(baseDir)) return [];
321
+ const transcripts = [];
322
+ try {
323
+ for (const projectDir of readdirSync(baseDir)) {
324
+ const agentDir = join(baseDir, projectDir, "agent-transcripts");
325
+ if (!existsSync(agentDir)) continue;
326
+ try {
327
+ for (const sessionDir of readdirSync(agentDir)) {
328
+ const sessionPath = join(agentDir, sessionDir);
329
+ if (!statSync(sessionPath).isDirectory()) continue;
330
+ try {
331
+ for (const file of readdirSync(sessionPath)) {
332
+ if (file.endsWith(".jsonl")) {
333
+ const full = join(sessionPath, file);
334
+ if (statSync(full).size > 100) {
335
+ transcripts.push(full);
336
+ }
337
+ }
338
+ }
339
+ } catch {
340
+ }
341
+ }
342
+ } catch {
343
+ }
344
+ }
345
+ } catch {
346
+ }
347
+ return transcripts;
348
+ }
250
349
  function findAllRooCodeTranscripts() {
251
350
  const possibleDirs = [
252
351
  join(homedir(), "Library", "Application Support", "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "tasks"),
@@ -267,15 +366,23 @@ function findAllRooCodeTranscripts() {
267
366
  }
268
367
  return transcripts;
269
368
  }
369
+ function findAllGooseSessionIds() {
370
+ const dbPath = join(homedir(), ".local", "share", "goose", "sessions", "sessions.db");
371
+ if (!existsSync(dbPath)) return [];
372
+ return [dbPath];
373
+ }
270
374
  function getGooseDbPath() {
271
375
  return join(homedir(), ".local", "share", "goose", "sessions", "sessions.db");
272
376
  }
273
377
 
274
378
  export {
275
379
  parseTranscript,
380
+ findLatestTranscript,
276
381
  findAllClaudeTranscripts,
277
382
  findAllContinueTranscripts,
278
383
  findAllCodexTranscripts,
384
+ findAllCursorTranscripts,
279
385
  findAllRooCodeTranscripts,
386
+ findAllGooseSessionIds,
280
387
  getGooseDbPath
281
388
  };
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import { Command } from "commander";
5
5
  var program = new Command();
6
6
  program.name("agentcache").description("Engineering Knowledge Compiler \u2014 universal, zero-config").version("0.3.1");
7
7
  program.command("setup").description("Detect IDEs and register AgentCache (runs automatically on install)").action(async () => {
8
- const { runSetup } = await import("./setup-45BVUDXN.js");
8
+ const { runSetup } = await import("./setup-CVG35TUZ.js");
9
9
  await runSetup();
10
10
  });
11
11
  program.command("serve").description("Start AgentCache MCP server (spawned by IDEs automatically)").action(async () => {
@@ -14,7 +14,7 @@ program.command("serve").description("Start AgentCache MCP server (spawned by ID
14
14
  });
15
15
  program.command("compile-session").description("Stop hook: queue transcript for compilation").action(async () => {
16
16
  try {
17
- const { handleStop } = await import("./stop-TPCRE7RE.js");
17
+ const { handleStop } = await import("./stop-WGGRX6TQ.js");
18
18
  let payload;
19
19
  try {
20
20
  let data = "";
@@ -34,7 +34,7 @@ program.command("compile-session").description("Stop hook: queue transcript for
34
34
  });
35
35
  program.command("discover").description("SessionStart hook: discover uncompiled transcripts").action(async () => {
36
36
  try {
37
- const { handleSessionStart } = await import("./session-start-EIHYCS3J.js");
37
+ const { handleSessionStart } = await import("./session-start-DGMGEAJU.js");
38
38
  await handleSessionStart();
39
39
  } catch (err) {
40
40
  process.stderr.write(`agentcache discover: ${err.message}
@@ -47,7 +47,7 @@ program.command("enforce").description("PreToolUse hook: policy enforcement").ac
47
47
  data += chunk;
48
48
  }
49
49
  try {
50
- const { handlePreToolUse } = await import("./pre-tool-use-7F7NTHCS.js");
50
+ const { handlePreToolUse } = await import("./pre-tool-use-A4AJHZOJ.js");
51
51
  const input = JSON.parse(data);
52
52
  const result = handlePreToolUse(input);
53
53
  process.stdout.write(JSON.stringify(result));
@@ -202,40 +202,99 @@ program.command("doctor").description("Diagnose AgentCache installation and repo
202
202
  warning("Not initialized yet \u2014 run: agentcache setup");
203
203
  }
204
204
  console.log("\nIDE registrations:");
205
- const claudeJson = join(homedir(), ".claude.json");
206
- if (existsSync(claudeJson)) {
207
- try {
208
- const config = JSON.parse(readFileSync(claudeJson, "utf-8"));
209
- if (config.mcpServers?.agentcache) {
210
- pass("Claude Code: registered");
205
+ const { detectInstalledIdes } = await import("./ide-detector-5TRCR4F5.js");
206
+ const ides = detectInstalledIdes();
207
+ for (const ide of ides) {
208
+ if (!ide.detected) continue;
209
+ if (ide.mcpConfigFormat === "claude-settings") {
210
+ const claudeJson = join(homedir(), ".claude.json");
211
+ if (existsSync(claudeJson)) {
212
+ try {
213
+ const config = JSON.parse(readFileSync(claudeJson, "utf-8"));
214
+ if (config.mcpServers?.agentcache) {
215
+ pass("Claude Code: registered");
216
+ } else {
217
+ warning("Claude Code: detected but not registered");
218
+ }
219
+ } catch {
220
+ warning("Claude Code: config unreadable");
221
+ }
211
222
  } else {
212
- warning("Claude Code: ~/.claude.json exists but no agentcache server");
223
+ warning("Claude Code: detected but not registered");
213
224
  }
214
- } catch {
215
- warning("Claude Code: ~/.claude.json unreadable");
216
- }
217
- } else {
218
- warning("Claude Code: not registered");
219
- }
220
- const settingsPath = join(homedir(), ".claude", "settings.json");
221
- if (existsSync(settingsPath)) {
222
- try {
223
- const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
224
- const perms = settings.permissions?.allow || [];
225
- if (perms.some((p) => p.includes("agentcache"))) {
226
- pass("Claude Code permissions: auto-approved");
225
+ const settingsPath = join(homedir(), ".claude", "settings.json");
226
+ if (existsSync(settingsPath)) {
227
+ try {
228
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
229
+ const perms = settings.permissions?.allow || [];
230
+ if (perms.some((p) => p.includes("agentcache"))) {
231
+ pass("Claude Code permissions: auto-approved");
232
+ } else {
233
+ warning("Claude Code permissions: not in allow list");
234
+ }
235
+ if (settings.hooks?.Stop?.some((h) => JSON.stringify(h).includes("agentcache"))) {
236
+ pass("Claude Code hooks: registered");
237
+ } else {
238
+ warning("Claude Code hooks: not registered");
239
+ }
240
+ } catch {
241
+ warning("Claude Code settings: unreadable");
242
+ }
243
+ }
244
+ } else if (ide.mcpConfigFormat === "codex-toml") {
245
+ if (existsSync(ide.mcpConfigPath)) {
246
+ try {
247
+ const content = readFileSync(ide.mcpConfigPath, "utf-8");
248
+ if (content.includes("[mcp_servers.agentcache]")) {
249
+ pass(`${ide.name}: registered`);
250
+ } else {
251
+ warning(`${ide.name}: detected but not registered`);
252
+ }
253
+ } catch {
254
+ warning(`${ide.name}: config unreadable`);
255
+ }
227
256
  } else {
228
- warning("Claude Code permissions: not in allow list");
257
+ warning(`${ide.name}: detected but not registered`);
229
258
  }
230
- if (settings.hooks?.Stop?.some((h) => JSON.stringify(h).includes("agentcache"))) {
231
- pass("Claude Code hooks: registered");
259
+ } else {
260
+ if (existsSync(ide.mcpConfigPath)) {
261
+ try {
262
+ const config = JSON.parse(readFileSync(ide.mcpConfigPath, "utf-8"));
263
+ if (config.mcpServers?.agentcache) {
264
+ pass(`${ide.name}: registered`);
265
+ } else {
266
+ warning(`${ide.name}: detected but not registered`);
267
+ }
268
+ } catch {
269
+ warning(`${ide.name}: config unreadable`);
270
+ }
232
271
  } else {
233
- warning("Claude Code hooks: not registered");
272
+ warning(`${ide.name}: detected but not registered`);
234
273
  }
235
- } catch {
236
- warning("Claude Code settings: unreadable");
237
274
  }
238
275
  }
276
+ const notDetected = ides.filter((i) => !i.detected).map((i) => i.name);
277
+ if (notDetected.length > 0) {
278
+ console.log(` \xB7 Not detected: ${notDetected.join(", ")}`);
279
+ }
280
+ console.log("\nTranscript sources:");
281
+ const { findAllClaudeTranscripts, findAllCursorTranscripts, findAllContinueTranscripts, findAllCodexTranscripts, findAllRooCodeTranscripts } = await import("./transcript-JWSGSDSF.js");
282
+ const sources = [
283
+ { name: "Claude Code", fn: findAllClaudeTranscripts },
284
+ { name: "Cursor", fn: findAllCursorTranscripts },
285
+ { name: "Continue", fn: findAllContinueTranscripts },
286
+ { name: "Codex", fn: findAllCodexTranscripts },
287
+ { name: "Roo Code", fn: findAllRooCodeTranscripts }
288
+ ];
289
+ let totalTranscripts = 0;
290
+ for (const src of sources) {
291
+ const count = src.fn().length;
292
+ totalTranscripts += count;
293
+ if (count > 0) pass(`${src.name}: ${count} transcripts`);
294
+ }
295
+ if (totalTranscripts === 0) {
296
+ warning("No transcripts found from any IDE");
297
+ }
239
298
  console.log("\nLLM backends (for compile-all):");
240
299
  const backends = ["claude", "codex", "gemini", "copilot", "aider", "goose"];
241
300
  const found = [];
@@ -267,7 +326,7 @@ ${ok} passed, ${warn} warnings, ${fail} errors`);
267
326
  if (fail > 0) process.exit(1);
268
327
  });
269
328
  program.command("compile-all").description("Batch-compile all unprocessed transcripts using an available LLM CLI").action(async () => {
270
- const { runCompileAll } = await import("./compile-all-7ESDEBFG.js");
329
+ const { runCompileAll } = await import("./compile-all-PTWTZVP5.js");
271
330
  await runCompileAll();
272
331
  });
273
332
  program.command("status").description("Show AgentCache knowledge stats").action(async () => {
@@ -3,28 +3,29 @@ import {
3
3
  processExtraction,
4
4
  startCompile
5
5
  } from "./chunk-CUBZRYS5.js";
6
+ import "./chunk-GGAATZKM.js";
7
+ import {
8
+ acquireLock,
9
+ releaseLock
10
+ } from "./chunk-JUDLOBOC.js";
11
+ import {
12
+ SqliteKnowledgeRepository
13
+ } from "./chunk-PSASDZQE.js";
6
14
  import {
7
15
  findAllClaudeTranscripts,
8
16
  findAllCodexTranscripts,
9
17
  findAllContinueTranscripts,
18
+ findAllCursorTranscripts,
10
19
  findAllRooCodeTranscripts,
11
20
  getGooseDbPath,
12
21
  parseTranscript
13
- } from "./chunk-IGCH7SZT.js";
14
- import {
15
- acquireLock,
16
- releaseLock
17
- } from "./chunk-JUDLOBOC.js";
18
- import "./chunk-GGAATZKM.js";
22
+ } from "./chunk-WTXSZBQE.js";
19
23
  import {
20
24
  getDbPath,
21
25
  getGitRoot,
22
26
  getProjectId,
23
27
  isInitialized
24
28
  } from "./chunk-T4COG3XD.js";
25
- import {
26
- SqliteKnowledgeRepository
27
- } from "./chunk-PSASDZQE.js";
28
29
  import {
29
30
  __esm,
30
31
  __export,
@@ -294,6 +295,7 @@ function discoverAllTranscripts(repo) {
294
295
  const results = [];
295
296
  const allPaths = [
296
297
  ...findAllClaudeTranscripts(),
298
+ ...findAllCursorTranscripts(),
297
299
  ...findAllContinueTranscripts(),
298
300
  ...findAllCodexTranscripts(),
299
301
  ...findAllRooCodeTranscripts()
@@ -311,6 +313,14 @@ function inferProjectRoot(transcriptPath) {
311
313
  const slug = transcriptPath.split(".claude/projects/")[1]?.split("/")[0] || "";
312
314
  if (slug.startsWith("-")) return slug.replace(/-/g, "/");
313
315
  }
316
+ if (transcriptPath.includes(".cursor/projects/")) {
317
+ const slug = transcriptPath.split(".cursor/projects/")[1]?.split("/")[0] || "";
318
+ if (slug) {
319
+ const asPath = "/" + slug.replace(/-/g, "/");
320
+ const root = getGitRoot(asPath);
321
+ if (root) return root;
322
+ }
323
+ }
314
324
  try {
315
325
  const events = parseTranscript(transcriptPath);
316
326
  for (const event of events) {
@@ -0,0 +1,7 @@
1
+ import {
2
+ detectInstalledIdes
3
+ } from "./chunk-5UO7NJPQ.js";
4
+ import "./chunk-KFQGP6VL.js";
5
+ export {
6
+ detectInstalledIdes
7
+ };
package/dist/mcp.js CHANGED
@@ -7,14 +7,17 @@ import {
7
7
  startCompile
8
8
  } from "./chunk-CUBZRYS5.js";
9
9
  import {
10
- parseTranscript
11
- } from "./chunk-IGCH7SZT.js";
10
+ computeCanonicalHash
11
+ } from "./chunk-GGAATZKM.js";
12
12
  import {
13
13
  spawnCompileAll
14
14
  } from "./chunk-JUDLOBOC.js";
15
15
  import {
16
- computeCanonicalHash
17
- } from "./chunk-GGAATZKM.js";
16
+ SqliteKnowledgeRepository
17
+ } from "./chunk-PSASDZQE.js";
18
+ import {
19
+ parseTranscript
20
+ } from "./chunk-WTXSZBQE.js";
18
21
  import {
19
22
  findProjectRoot,
20
23
  getDataDir,
@@ -22,9 +25,6 @@ import {
22
25
  getProjectId,
23
26
  isInitialized
24
27
  } from "./chunk-T4COG3XD.js";
25
- import {
26
- SqliteKnowledgeRepository
27
- } from "./chunk-PSASDZQE.js";
28
28
  import "./chunk-KFQGP6VL.js";
29
29
 
30
30
  // src/mcp.ts
@@ -2,18 +2,20 @@ import {
2
2
  spawnCompileAll
3
3
  } from "./chunk-JUDLOBOC.js";
4
4
  import {
5
- detectInstalledIdes,
6
5
  registerClaudeHooks,
7
6
  registerMcpServer
8
- } from "./chunk-JVLMZU5I.js";
7
+ } from "./chunk-SLRKWMSE.js";
8
+ import {
9
+ SqliteKnowledgeRepository
10
+ } from "./chunk-PSASDZQE.js";
11
+ import {
12
+ detectInstalledIdes
13
+ } from "./chunk-5UO7NJPQ.js";
9
14
  import {
10
15
  getDataDir,
11
16
  getDbPath,
12
17
  migrateFromLegacy
13
18
  } from "./chunk-T4COG3XD.js";
14
- import {
15
- SqliteKnowledgeRepository
16
- } from "./chunk-PSASDZQE.js";
17
19
  import "./chunk-KFQGP6VL.js";
18
20
 
19
21
  // src/postinstall.ts
@@ -1,17 +1,18 @@
1
+ import {
2
+ SqliteKnowledgeRepository
3
+ } from "./chunk-PSASDZQE.js";
1
4
  import {
2
5
  findAllClaudeTranscripts,
3
6
  findAllCodexTranscripts,
4
7
  findAllContinueTranscripts,
8
+ findAllCursorTranscripts,
5
9
  findAllRooCodeTranscripts
6
- } from "./chunk-IGCH7SZT.js";
10
+ } from "./chunk-WTXSZBQE.js";
7
11
  import {
8
12
  getDbPath,
9
13
  getProjectId,
10
14
  isInitialized
11
15
  } from "./chunk-T4COG3XD.js";
12
- import {
13
- SqliteKnowledgeRepository
14
- } from "./chunk-PSASDZQE.js";
15
16
  import "./chunk-KFQGP6VL.js";
16
17
 
17
18
  // src/hooks/session-start.ts
@@ -19,6 +20,14 @@ import { statSync } from "fs";
19
20
  import { basename, dirname } from "path";
20
21
  import { randomUUID } from "crypto";
21
22
  function inferProjectRootFromTranscriptPath(path) {
23
+ if (path.includes(".claude/projects/")) {
24
+ const slug2 = path.split(".claude/projects/")[1]?.split("/")[0] || "";
25
+ if (slug2.startsWith("-")) return slug2.replace(/-/g, "/");
26
+ }
27
+ if (path.includes(".cursor/projects/")) {
28
+ const slug2 = path.split(".cursor/projects/")[1]?.split("/")[0] || "";
29
+ if (slug2) return "/" + slug2.replace(/-/g, "/");
30
+ }
22
31
  const dir = dirname(path);
23
32
  const slug = basename(dir);
24
33
  if (slug.startsWith("-")) {
@@ -32,6 +41,7 @@ async function handleSessionStart() {
32
41
  const compiledPaths = new Set(repo.getAllCompiledTranscriptPaths());
33
42
  const allTranscripts = [
34
43
  ...findAllClaudeTranscripts(),
44
+ ...findAllCursorTranscripts(),
35
45
  ...findAllContinueTranscripts(),
36
46
  ...findAllCodexTranscripts(),
37
47
  ...findAllRooCodeTranscripts()
@@ -1,16 +1,18 @@
1
1
  import {
2
- detectInstalledIdes,
3
2
  registerClaudeHooks,
4
3
  registerMcpServer
5
- } from "./chunk-JVLMZU5I.js";
4
+ } from "./chunk-SLRKWMSE.js";
5
+ import {
6
+ SqliteKnowledgeRepository
7
+ } from "./chunk-PSASDZQE.js";
8
+ import {
9
+ detectInstalledIdes
10
+ } from "./chunk-5UO7NJPQ.js";
6
11
  import {
7
12
  getDataDir,
8
13
  getDbPath,
9
14
  migrateFromLegacy
10
15
  } from "./chunk-T4COG3XD.js";
11
- import {
12
- SqliteKnowledgeRepository
13
- } from "./chunk-PSASDZQE.js";
14
16
  import "./chunk-KFQGP6VL.js";
15
17
 
16
18
  // src/setup.ts
@@ -0,0 +1,24 @@
1
+ import {
2
+ findAllClaudeTranscripts,
3
+ findAllCodexTranscripts,
4
+ findAllContinueTranscripts,
5
+ findAllCursorTranscripts,
6
+ findAllGooseSessionIds,
7
+ findAllRooCodeTranscripts,
8
+ findLatestTranscript,
9
+ getGooseDbPath,
10
+ parseTranscript
11
+ } from "./chunk-WTXSZBQE.js";
12
+ import "./chunk-T4COG3XD.js";
13
+ import "./chunk-KFQGP6VL.js";
14
+ export {
15
+ findAllClaudeTranscripts,
16
+ findAllCodexTranscripts,
17
+ findAllContinueTranscripts,
18
+ findAllCursorTranscripts,
19
+ findAllGooseSessionIds,
20
+ findAllRooCodeTranscripts,
21
+ findLatestTranscript,
22
+ getGooseDbPath,
23
+ parseTranscript
24
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentcache",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Knowledge cache for AI agents — learns how you work, remembers across sessions, works everywhere",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  evaluatePolicy
3
3
  } from "./chunk-T7BJPANN.js";
4
+ import {
5
+ SqliteKnowledgeRepository
6
+ } from "./chunk-PSASDZQE.js";
4
7
  import {
5
8
  findProjectRoot,
6
9
  getDbPath,
7
10
  getProjectId,
8
11
  isInitialized
9
12
  } from "./chunk-T4COG3XD.js";
10
- import {
11
- SqliteKnowledgeRepository
12
- } from "./chunk-PSASDZQE.js";
13
13
  import "./chunk-KFQGP6VL.js";
14
14
 
15
15
  // src/hooks/pre-tool-use.ts
@@ -1,12 +1,12 @@
1
+ import {
2
+ SqliteKnowledgeRepository
3
+ } from "./chunk-PSASDZQE.js";
1
4
  import {
2
5
  findProjectRoot,
3
6
  getDbPath,
4
7
  getProjectId,
5
8
  isInitialized
6
9
  } from "./chunk-T4COG3XD.js";
7
- import {
8
- SqliteKnowledgeRepository
9
- } from "./chunk-PSASDZQE.js";
10
10
  import "./chunk-KFQGP6VL.js";
11
11
 
12
12
  // src/hooks/stop.ts