claude-launchpad 0.10.0 → 0.10.1-dev.0

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.
Files changed (31) hide show
  1. package/README.md +117 -120
  2. package/dist/chunk-7YDBTED2.js +154 -0
  3. package/dist/chunk-7YDBTED2.js.map +1 -0
  4. package/dist/chunk-J5NT4JGE.js +77 -0
  5. package/dist/chunk-J5NT4JGE.js.map +1 -0
  6. package/dist/{chunk-TALTTAMW.js → chunk-JXFTVFPC.js} +43 -3
  7. package/dist/chunk-JXFTVFPC.js.map +1 -0
  8. package/dist/{chunk-4AF3NGNF.js → chunk-YEGOHLE7.js} +3 -3
  9. package/dist/{chunk-JTKRLIEV.js → chunk-ZMSHFAZQ.js} +2 -1
  10. package/dist/cli.js +47 -90
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/memory/server.js +39 -75
  13. package/dist/commands/memory/server.js.map +1 -1
  14. package/dist/{context-AGNCZJPC.js → context-SGPGEJV4.js} +4 -4
  15. package/dist/{extract-RPRYPT3Z.js → extract-T32FMLN5.js} +4 -4
  16. package/dist/{install-PSSMUGLO.js → install-OKLYDFBJ.js} +2 -2
  17. package/dist/pull-4VKUDKTB.js +66 -0
  18. package/dist/pull-4VKUDKTB.js.map +1 -0
  19. package/dist/push-WI3ZIPZU.js +89 -0
  20. package/dist/push-WI3ZIPZU.js.map +1 -0
  21. package/dist/{stats-DAUYJ4BE.js → stats-77WLARNA.js} +4 -4
  22. package/dist/{tui-A4TJFNE3.js → tui-YV7AFJFR.js} +3 -3
  23. package/package.json +1 -1
  24. package/dist/chunk-TALTTAMW.js.map +0 -1
  25. /package/dist/{chunk-4AF3NGNF.js.map → chunk-YEGOHLE7.js.map} +0 -0
  26. /package/dist/{chunk-JTKRLIEV.js.map → chunk-ZMSHFAZQ.js.map} +0 -0
  27. /package/dist/{context-AGNCZJPC.js.map → context-SGPGEJV4.js.map} +0 -0
  28. /package/dist/{extract-RPRYPT3Z.js.map → extract-T32FMLN5.js.map} +0 -0
  29. /package/dist/{install-PSSMUGLO.js.map → install-OKLYDFBJ.js.map} +0 -0
  30. /package/dist/{stats-DAUYJ4BE.js.map → stats-77WLARNA.js.map} +0 -0
  31. /package/dist/{tui-A4TJFNE3.js.map → tui-YV7AFJFR.js.map} +0 -0
package/README.md CHANGED
@@ -4,106 +4,109 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/claude-launchpad?style=flat-square)](https://www.npmjs.com/package/claude-launchpad)
5
5
  [![GitHub stars](https://img.shields.io/github/stars/mboss37/claude-launchpad?style=flat-square)](https://github.com/mboss37/claude-launchpad)
6
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/mboss37/claude-launchpad/blob/master/LICENSE)
7
+ ![macOS](https://img.shields.io/badge/macOS-supported-brightgreen?style=flat-square&logo=apple)
8
+ ![Linux](https://img.shields.io/badge/Linux-supported-brightgreen?style=flat-square&logo=linux)
9
+ ![Windows](https://img.shields.io/badge/Windows-untested-yellow?style=flat-square&logo=windows)
7
10
 
8
- **Score your Claude Code setup. Fix what's broken. Prove it works.**
11
+ **Score your Claude Code config. Fix it. Prove it works.**
9
12
 
10
- CLAUDE.md is advisory, so Claude follows your rules about 80% of the time. Hooks are deterministic: 100% compliance. Most developers have zero hooks and too many instructions. This tool scores your setup, fixes the gaps, and proves Claude follows your config.
13
+ Claude Code follows CLAUDE.md about 80% of the time. Hooks run at 100%. Most developers have zero hooks and too many instructions. Claude Launchpad scores your setup, fixes the gaps, and tests that Claude actually follows your rules.
14
+
15
+ This is for developers using Claude Code who want consistent results: solo devs, vibe coders, AI-first teams. If you have ever wondered why Claude ignores half your CLAUDE.md, this is the fix.
16
+
17
+ ## Install and See Your Score
11
18
 
12
19
  ```bash
13
20
  npx claude-launchpad
14
21
  ```
15
22
 
16
- That's it. Run it in any project with Claude Code. You'll see a score out of 100 and a list of exactly what's wrong. Run `--fix` to auto-repair.
23
+ ```
24
+ Instruction Budget ━━━━━━━━━━━━━━━━━━━━ 100%
25
+ CLAUDE.md Quality ━━━━━━━━━━━━━━━━━━━━ 100%
26
+ Settings ━━━━━━━━━━━━━━━━━━━━ 100%
27
+ Hooks ━━━━━━━━━━━━━━━━━━━━ 100%
28
+ Rules ━━━━━━━━━━━━━━━━━━━━ 100%
29
+ Permissions ━━━━━━━━━━━━━━━━━━━━ 100%
30
+ MCP Servers ━━━━━━━━━━━━━━━━━━━━ 100%
17
31
 
18
- Claude Launchpad has 4 CLI commands (`init`, `doctor`, `eval`, `memory`) plus 1 in-session skill (`/lp-enhance`). Memory is optional.
32
+ Overall ━━━━━━━━━━━━━━━━━━━━ 100%
19
33
 
20
- ## Two Paths, One Tool
34
+ No issues found. Your configuration looks solid.
35
+ ```
36
+
37
+ A typical unconfigured project scores ~31%. After `--fix`, it jumps to ~91%.
21
38
 
22
- ### Starting a new project?
39
+ ## Quick Start
40
+
41
+ **New project:**
23
42
 
24
43
  ```bash
25
- claude-launchpad init
44
+ npx claude-launchpad init
26
45
  ```
27
46
 
28
- Detects your stack and generates `CLAUDE.md` with your commands and conventions. Creates `TASKS.md` for tracking, `BACKLOG.md` for parking features, sets up hooks that auto-format and block dangerous operations, and adds `.claudeignore` for noise files.
29
-
30
- Then use `/lp-enhance` inside Claude Code to have Claude read your actual codebase and fill in the architecture and guardrails — not boilerplate, real project-specific content.
47
+ Detects your stack, generates config, hooks, and permissions. Start at ~93%.
31
48
 
32
- ### Already have a project?
49
+ **Existing project:**
33
50
 
34
51
  ```bash
35
- claude-launchpad
52
+ npx claude-launchpad doctor --fix
36
53
  ```
37
54
 
38
- Scores your config out of 100 and tells you what's wrong. Run `doctor --fix` for automatic repairs, `/lp-enhance` for AI-powered rewrites, and `eval` to prove behavior.
55
+ Scores your config, auto-repairs everything it can.
39
56
 
40
- ## Command Model
57
+ ## The Three-File System
41
58
 
42
- | Command | What it does | Runs |
59
+ | File | Purpose | Example |
43
60
  |---|---|---|
44
- | `claude-launchpad init` | Detect stack, generate config, hooks, permissions | Locally |
45
- | `claude-launchpad` | Default entrypoint (routes to doctor when config exists) | Locally |
46
- | `claude-launchpad doctor --fix` | Auto-fix issues: hooks, rules, sections, .claudeignore | Locally |
47
- | `claude-launchpad doctor --watch` | Live score that updates when you save config files | Locally |
48
- | `/lp-enhance` (skill) | Claude reads your code and completes CLAUDE.md | Inside Claude Code |
49
- | `claude-launchpad eval` | Run Claude against test scenarios, prove config works | Via Claude CLI |
50
- | `claude-launchpad memory` | Optional memory setup (or stats) + installs `/lp-migrate-memory` skill | Locally |
51
- | `claude-launchpad memory --dashboard` | TUI dashboard for memory visualization | Locally |
61
+ | `CLAUDE.md` | What Claude needs to know | Stack, commands, conventions, guardrails |
62
+ | `TASKS.md` | What we're doing now | Current sprint, session log, progress |
63
+ | `BACKLOG.md` | What we're doing later | Parked features with P0/P1/P2 priority tiers |
52
64
 
53
- ## Quick Start
65
+ Without BACKLOG.md, deferred features get lost in conversation history or bloat TASKS.md. Init generates all three. Doctor checks for them. `--fix` creates any that are missing.
54
66
 
55
- ```bash
56
- cd your-project
57
- npx claude-launchpad # see your score
58
- npx claude-launchpad doctor --fix # fix everything
59
- ```
67
+ ## Commands
68
+
69
+ | Command | What it does | Runs |
70
+ |---|---|---|
71
+ | `claude-launchpad` | Score your config (routes to doctor) | Locally, free |
72
+ | `claude-launchpad init` | Detect stack, generate config + hooks + permissions | Locally, free |
73
+ | `claude-launchpad doctor --fix` | Auto-fix issues found by doctor | Locally, free |
74
+ | `claude-launchpad eval` | Run Claude against test scenarios, score results | Via Claude CLI |
75
+ | `claude-launchpad memory` | Optional persistent memory system | Locally |
76
+ | `/lp-enhance` (skill) | Claude reads your code and completes CLAUDE.md | Inside Claude Code |
60
77
 
61
- A typical unconfigured project scores ~42%. After `--fix`, it jumps to ~86%. Run `init` on a fresh project and you start at ~93%.
78
+ ## Doctor
62
79
 
63
- ## The Doctor
80
+ Runs 7 analyzers against your `.claude/` directory and CLAUDE.md. No API calls, no network, no cost.
64
81
 
65
- The core of the tool. Runs 7 core analyzers against your `.claude/` directory and `CLAUDE.md` (plus an optional Memory analyzer when agentic memory is detected):
82
+ **Analyzers:**
66
83
 
67
84
  | Analyzer | What it catches |
68
85
  |---|---|
69
- | **Instruction Budget** | Too many instructions in CLAUDE.md Claude starts ignoring rules past ~200 |
70
- | **CLAUDE.md Quality** | Missing essential sections, vague instructions ("write good code"), hardcoded secrets |
86
+ | **Instruction Budget** | Too many instructions. Claude starts ignoring rules past ~200. |
87
+ | **CLAUDE.md Quality** | Missing sections, vague instructions, hardcoded secrets |
71
88
  | **Settings** | No hooks configured, dangerous tool access without safety nets |
72
- | **Hooks** | Missing auto-format on save, no .env file protection, no security gates, no PostCompact hook |
89
+ | **Hooks** | Missing auto-format, no .env protection, no PostCompact hook |
73
90
  | **Rules** | Dead rule files, stale references, empty configs |
74
- | **Permissions** | Credential file exposure (~/.ssh, ~/.aws, ~/.npmrc), blanket Bash approval, bypass mode unprotected, sandbox disabled, .env gap between hooks and .claudeignore, no force-push protection |
91
+ | **Permissions** | Credential exposure (~/.ssh, ~/.aws), blanket Bash approval, sandbox disabled |
75
92
  | **MCP Servers** | Invalid transport configs, missing commands/URLs |
76
93
 
77
- Output looks like this:
78
-
79
- ```
80
- Instruction Budget ━━━━━━━━━━━━━━━━━━━━ 100%
81
- CLAUDE.md Quality ━━━━━━━━━━━━━━━━━━━━ 100%
82
- Settings ━━━━━━━━━━━━━━━━━━━━ 100%
83
- Hooks ━━━━━━━━━━━━━━━━━━━━ 100%
84
- Rules ━━━━━━━━━━━━━━━━━━━━ 100%
85
- Permissions ━━━━━━━━━━━━━━━━━━━━ 100%
86
- MCP Servers ━━━━━━━━━━────────── 50%
87
-
88
- Overall ━━━━━━━━━━━━━━━━━━━─ 93%
94
+ An optional Memory analyzer runs when agentic memory is detected.
89
95
 
90
- ✓ No issues found. Your configuration looks solid.
91
- ```
92
-
93
- **All doctor flags:**
96
+ **Flags:**
94
97
 
95
98
  | Flag | What it does |
96
99
  |---|---|
97
- | `--fix` | Auto-fixes issues: adds hooks, CLAUDE.md sections, BACKLOG.md, rules, .claudeignore |
98
- | `--fix --dry-run` | Preview what --fix would change without applying |
99
- | `--watch` | Re-runs every second, updates when you save a config file |
100
- | `--json` | Pure JSON output, no colors, no banner — for scripts and CI |
101
- | `--min-score <n>` | Exit code 1 if score is below threshold use in CI to block bad configs |
100
+ | `--fix` | Auto-fix: adds hooks, CLAUDE.md sections, BACKLOG.md, rules, .claudeignore |
101
+ | `--fix --dry-run` | Preview fixes without applying them |
102
+ | `--watch` | Re-runs every second as you edit config files |
103
+ | `--json` | Pure JSON output for scripts and CI |
104
+ | `--min-score <n>` | Exit code 1 if score is below threshold (for CI) |
102
105
  | `-p, --path <dir>` | Run on a different directory |
103
106
 
104
107
  ## Init
105
108
 
106
- Detects your project and generates Claude Code config that fits. No templates, no menus — it reads your manifest files and figures it out.
109
+ Reads your manifest files (package.json, go.mod, pyproject.toml, etc.) and generates config that fits. No templates, no menus.
107
110
 
108
111
  ```
109
112
  → Detecting project...
@@ -119,78 +122,40 @@ Detects your project and generates Claude Code config that fits. No templates, n
119
122
  ✓ Generated .claude/rules/conventions.md
120
123
  ```
121
124
 
122
- **Works with:** TypeScript, JavaScript, Python, Go, Ruby, Rust, Dart, PHP, Java, Kotlin, Swift, Elixir, C# — and detects frameworks (Next.js, FastAPI, Django, Rails, Laravel, Express, SvelteKit, Angular, NestJS, and 15+ more).
123
-
124
125
  **What init writes:**
125
- - Always writes: `CLAUDE.md`, `TASKS.md`, `BACKLOG.md`, `.claude/settings.json`
126
+ - Always: `CLAUDE.md`, `TASKS.md`, `BACKLOG.md`, `.claude/settings.json`
126
127
  - Creates when missing: `.claude/.gitignore`, `.claudeignore`, `.claude/rules/conventions.md`
127
- - Offers `/lp-enhance` install (project/global/skip) only when no project/global/legacy install already exists
128
+ - Offers `/lp-enhance` install (project/global/skip) if not already present
128
129
 
129
- **The three-file system:**
130
-
131
- | File | Purpose |
132
- |---|---|
133
- | `CLAUDE.md` | What Claude needs to know — stack, commands, conventions, guardrails |
134
- | `TASKS.md` | What we're doing now — sprint tracking, session continuity |
135
- | `BACKLOG.md` | What we're doing later — parked features with P0/P1/P2 priority tiers |
136
-
137
- Without BACKLOG.md, deferred features get lost in conversation history or bloat TASKS.md. Init generates it, doctor checks for it, `--fix` creates it if missing.
130
+ **Supported stacks:** TypeScript, JavaScript, Python, Go, Ruby, Rust, Dart, PHP, Java, Kotlin, Swift, Elixir, C#. Detects frameworks: Next.js, FastAPI, Django, Rails, Laravel, Express, SvelteKit, Angular, NestJS, and 15+ more.
138
131
 
139
132
  ## Enhance
140
133
 
141
- Init detects your stack but can't understand your architecture. The `/lp-enhance` skill runs inside your Claude Code session to read your actual code and fill in the details.
134
+ Init detects your stack but cannot read your architecture. The `/lp-enhance` skill runs inside Claude Code to fill in the details.
142
135
 
143
136
  ```
144
137
  /lp-enhance
145
138
  ```
146
139
 
147
- Installed as a skill during `init` (you pick global or project scope). Claude reads your codebase and updates CLAUDE.md with real content - actual architecture, actual conventions, actual guardrails, and memory management instructions. Not boilerplate. It also suggests project-specific hooks (including PostCompact for session continuity) and MCP servers based on what it finds.
140
+ Claude reads your codebase and updates CLAUDE.md with real content: actual architecture, actual conventions, actual guardrails. Not boilerplate. It also suggests project-specific hooks and MCP servers.
148
141
 
149
142
  Stays under the 200-instruction budget. Overflows detailed content to `.claude/rules/` files. If the skill is missing, `doctor --fix` will create it.
150
143
 
151
- ## Memory
152
-
153
- Optional persistent memory system that replaces Claude Code's built-in flat-file memory with intelligent, decay-based retrieval.
154
-
155
- ```bash
156
- claude-launchpad memory
157
- ```
158
-
159
- Requires native deps first: `npm install better-sqlite3 sqlite-vec` (the CLI will prompt you if missing). Interactive setup - asks before changing anything. Installs a SQLite database, hooks for automatic context injection, and 7 MCP tools.
160
-
161
- **What it does:**
162
- - **Smart session injection** - each session starts with the most relevant memories, ranked by 6 signals (context, value, importance, recency, type, noise) and packed into a 2000-token budget across three tiers (full content / summary / title-only)
163
- - **Stop hook** extracts facts from the conversation transcript when you're done
164
- - **Decay model** - memories fade naturally based on type (episodic: 60 days, semantic: 1 year, procedural: 2 years)
165
- - **Self-tuning retrieval** - memories Claude actively searches for rise in rank; memories injected but never used gradually stop appearing
166
- - **Project-scoped** - memories are partitioned per project, no cross-contamination
167
- - **TUI dashboard** (`--dashboard`) for visualization with vim navigation, filtering, and search
168
-
169
- No cloud. No sync. Everything stays in `~/.agentic-memory/memory.db`.
170
-
171
- **Memory flags:**
172
-
173
- | Flag | What it does |
174
- |---|---|
175
- | `--dashboard` | Opens the interactive TUI dashboard |
176
-
177
- Default behavior of `claude-launchpad memory`:
178
- - If memory is not installed, it runs interactive install
179
- - If memory is installed, it shows memory stats
144
+ **When to re-run:** after major refactors, new dependencies, or architecture changes.
180
145
 
181
146
  ## Eval
182
147
 
183
- The part nobody else has built. Runs Claude against real test scenarios and scores the results.
148
+ Runs Claude against real test scenarios and scores the results. Nobody else has built this.
184
149
 
185
150
  ```bash
186
- # Interactive mode pick suite, runs, and model
151
+ # Interactive mode (pick suite, runs, model)
187
152
  claude-launchpad eval
188
153
 
189
154
  # Or pass flags directly
190
155
  claude-launchpad eval --suite security --runs 1 --model haiku
191
156
  ```
192
157
 
193
- Each scenario creates an isolated sandbox with your full Claude Code config (settings.json, rules, hooks, .claudeignore) copied in, runs Claude with a task, and checks if your configuration made Claude follow the rules:
158
+ Each scenario creates an isolated sandbox with your full Claude Code config copied in. It runs Claude with a task and checks if your configuration made Claude follow the rules.
194
159
 
195
160
  ```
196
161
  ✓ security/sql-injection 10/10 PASS
@@ -203,7 +168,7 @@ Each scenario creates an isolated sandbox with your full Claude Code config (set
203
168
  Config Eval Score ━━━━━━━━━━━━━━━━━━━─ 95%
204
169
  ```
205
170
 
206
- Results are saved to `.claude/eval/` as structured markdown you can feed these reports back to Claude to fix the failures.
171
+ Results save to `.claude/eval/` as structured markdown. Feed them back to Claude to fix failures.
207
172
 
208
173
  **Suites:**
209
174
 
@@ -213,19 +178,48 @@ Results are saved to `.claude/eval/` as structured markdown — you can feed the
213
178
  | `conventions` | 5 | Error handling, immutability, file size, naming, no hardcoded values |
214
179
  | `workflow` | 4 | Git conventions, session continuity, memory persistence, deferred tracking |
215
180
 
216
- **All eval flags:**
181
+ **Flags:**
217
182
 
218
183
  | Flag | What it does |
219
184
  |---|---|
220
185
  | `--suite <name>` | Run one suite: `security`, `conventions`, or `workflow` |
221
- | `-p, --path <dir>` | Project root to evaluate (defaults to current directory) |
186
+ | `-p, --path <dir>` | Project root to evaluate (defaults to cwd) |
222
187
  | `--scenarios <path>` | Use a custom scenarios directory |
223
188
  | `--model <model>` | Model to use: `haiku`, `sonnet`, `opus` |
224
189
  | `--runs <n>` | Runs per scenario (default 3, median score used) |
225
- | `--debug` | Keep sandbox directories so you can inspect what Claude wrote |
190
+ | `--debug` | Keep sandbox directories for inspection |
226
191
  | `--json` | JSON output |
227
192
  | `--timeout <ms>` | Timeout per run (default 120000) |
228
193
 
194
+ ## Memory
195
+
196
+ Optional persistent memory that replaces Claude Code's built-in flat-file memory with intelligent, decay-based retrieval.
197
+
198
+ ```bash
199
+ claude-launchpad memory
200
+ ```
201
+
202
+ If memory is not installed, it runs interactive setup. If installed, it shows stats. Requires native deps first: `npm install better-sqlite3 sqlite-vec`.
203
+
204
+ **What it does:**
205
+ - **Smart session injection** starts each session with the most relevant memories, ranked by 6 signals and packed into a 2000-token budget across three tiers
206
+ - **Stop hook** extracts facts from the conversation when you finish
207
+ - **Decay model** fades memories naturally (episodic: 60 days, semantic: 1 year, procedural: 2 years)
208
+ - **Self-tuning retrieval** promotes memories Claude searches for, demotes ones injected but never used
209
+ - **Project-scoped** with no cross-contamination between projects
210
+ - **TUI dashboard** (`--dashboard`) with vim navigation, filtering, and search
211
+ - **Cross-device sync** via private GitHub Gist — push/pull memories between machines
212
+
213
+ Data stays in `~/.agentic-memory/memory.db`. Sync is opt-in and uses your existing `gh` CLI auth.
214
+
215
+ | Flag / Subcommand | What it does |
216
+ |---|---|
217
+ | `--dashboard` | Opens the interactive TUI dashboard |
218
+ | `push` | Push memories to a private GitHub Gist |
219
+ | `pull` | Pull memories from a private GitHub Gist |
220
+ | `push --project <name>` | Push only one project's memories |
221
+ | `pull --project <name>` | Pull only one project's memories |
222
+
229
223
  ## Use in CI
230
224
 
231
225
  Block PRs that degrade your Claude Code config quality:
@@ -252,35 +246,38 @@ Score below threshold = exit code 1 = PR blocked.
252
246
 
253
247
  **Doctor** reads your files and runs static analysis. No API calls. No network. No cost.
254
248
 
255
- **Init** scans manifest files (package.json, go.mod, pyproject.toml, etc.), detects your stack, and generates 8 files: CLAUDE.md (with sprint reviews and backlog management), TASKS.md (with deferred issues section), BACKLOG.md (priority-tiered feature parking), settings.json (with credential deny rules, sandbox enabled, bypass mode disabled, hooks including sprint review and PostCompact), .claude/.gitignore, .claudeignore, /lp-enhance skill, and language-specific rules. Formatter hooks use hardcoded safe commands only.
256
-
257
- **Enhance** is a `/lp-enhance` skill installed during `init`. It runs inside your active Claude Code session - no separate process, no overhead. Claude already has your codebase context, so it produces better results than an external command.
249
+ **Init** scans manifest files (package.json, go.mod, pyproject.toml, etc.) and detects your stack. Generates 8 files:
250
+ - CLAUDE.md (sprint reviews, backlog management)
251
+ - TASKS.md (session log, sprint tracking)
252
+ - BACKLOG.md (priority-tiered feature parking)
253
+ - settings.json (credential deny rules, sandbox, hooks)
254
+ - .claude/.gitignore, .claudeignore, /lp-enhance skill, conventions.md
258
255
 
259
- **Eval** creates a temp directory, copies your full `.claude/` config (settings.json, rules, hooks, permissions) and `.claudeignore` into it, writes seed files from the scenario YAML, initializes a git repo, runs Claude via the Agent SDK (or falls back to CLI), then checks the output with grep/file assertions. Your code is never copied, only your Claude Code configuration. Sandbox is cleaned up after (or preserved with `--debug`).
256
+ Formatter hooks use hardcoded safe commands only.
260
257
 
261
- ## Why This Exists
258
+ **Enhance** is a `/lp-enhance` skill installed during `init`. It runs inside your active Claude Code session, not a separate process. Claude already has your codebase context, so it produces better results than an external command.
262
259
 
263
- Nobody measures their Claude Code config quality. You write CLAUDE.md, hope Claude follows it, and never verify. This tool gives you a number. Fix the issues, re-run, watch it go up.
260
+ **Eval** creates a temp directory, copies your full `.claude/` config (settings.json, rules, hooks, permissions) and `.claudeignore` into it, writes seed files from the scenario YAML, initializes a git repo, runs Claude via the Agent SDK (or falls back to CLI), then checks the output with grep/file assertions. Your code is never copied, only your Claude Code configuration. Sandbox is cleaned up after (or preserved with `--debug`).
264
261
 
265
262
  ## Glossary
266
263
 
267
- New to Claude Code? Here's what the terms mean:
264
+ New to Claude Code? Here's what the terms mean.
268
265
 
269
266
  | Term | What it is |
270
267
  |---|---|
271
268
  | **CLAUDE.md** | A markdown file in your project root that tells Claude how to work on your code. Think of it as instructions for your AI pair programmer. [Official docs](https://docs.anthropic.com/en/docs/claude-code/memory#claudemd) |
272
269
  | **TASKS.md** | Sprint tracker and session log. Claude reads this at session start to pick up where you left off. |
273
270
  | **BACKLOG.md** | Where deferred features live. Priority tiers (P0/P1/P2) keep future ideas organized without cluttering TASKS.md. |
274
- | **Hooks** | Shell commands that run automatically when Claude does something. For example: auto-format a file after Claude edits it, or block Claude from reading your `.env` file. They live in `.claude/settings.json`. |
271
+ | **Hooks** | Shell commands that run automatically when Claude does something. Example: auto-format after edits, block reading `.env`. They live in `.claude/settings.json`. |
275
272
  | **Instruction budget** | CLAUDE.md has a soft limit of ~200 actionable lines. Past that, Claude starts ignoring rules at the bottom. Doctor counts your lines and warns you. |
276
273
  | **Rules** | Extra markdown files in `.claude/rules/` that Claude reads alongside CLAUDE.md. Use them to offload detailed conventions so CLAUDE.md stays under budget. |
277
- | **Compaction** | When a Claude Code conversation gets too long, it compresses older messages to free up space. This can lose context a PostCompact hook re-injects critical files (like TASKS.md) after compaction. |
274
+ | **Compaction** | When a conversation gets too long, Claude compresses older messages. This can lose context. A PostCompact hook re-injects critical files (like TASKS.md) after compaction. |
278
275
  | **MCP Servers** | External tools Claude can connect to (databases, APIs, docs). Configured in `.claude/settings.json`. Most projects don't need them. |
279
- | **.claudeignore** | Like `.gitignore` but for Claude. Tells Claude which files to skip (node_modules, dist, lockfiles) so it doesn't waste time reading noise. |
276
+ | **.claudeignore** | Like `.gitignore` but for Claude. Tells Claude which files to skip so it doesn't waste time reading noise. |
280
277
 
281
278
  ## Privacy
282
279
 
283
- No telemetry. No analytics. No data sent anywhere. Doctor, init, and fix are fully offline. Memory stores data locally at `~/.agentic-memory/` - no cloud sync. Enhance and eval run through your local Claude CLI - no data passes through this tool. [Full privacy policy](https://mboss37.github.io/claude-launchpad/privacy.html).
280
+ No telemetry. No analytics. No data sent anywhere. Doctor, init, and fix are fully offline. Memory stores data locally at `~/.agentic-memory/`. The optional sync feature (`memory push/pull`) uses a private GitHub Gist under your own account — data goes to GitHub, not to us. Enhance and eval run through your local Claude CLI, no data passes through this tool. [Full privacy policy](https://mboss37.github.io/claude-launchpad/privacy.html).
284
281
 
285
282
  ## License
286
283
 
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_CONFIG,
4
+ resolveDataDir
5
+ } from "./chunk-ZMSHFAZQ.js";
6
+
7
+ // src/commands/memory/utils/gist-transport.ts
8
+ import { execSync } from "child_process";
9
+ import { readFileSync, writeFileSync, unlinkSync, mkdirSync } from "fs";
10
+ import { join, dirname } from "path";
11
+ import { tmpdir } from "os";
12
+ var EXEC_OPTS = { encoding: "utf-8", timeout: 3e4 };
13
+ var GIST_FILENAME = "agentic-memory-sync.json";
14
+ var SYNC_CONFIG_FILE = "sync-config.json";
15
+ function syncConfigPath() {
16
+ return join(resolveDataDir(DEFAULT_CONFIG.dataDir), SYNC_CONFIG_FILE);
17
+ }
18
+ function assertGhAvailable() {
19
+ try {
20
+ execSync("gh --version", { ...EXEC_OPTS, stdio: "pipe" });
21
+ } catch {
22
+ throw new Error(
23
+ "Memory sync requires the GitHub CLI.\nInstall: https://cli.github.com/\nThen run: gh auth login"
24
+ );
25
+ }
26
+ try {
27
+ execSync("gh auth status", { ...EXEC_OPTS, stdio: "pipe" });
28
+ } catch {
29
+ throw new Error(
30
+ "gh is installed but not authenticated.\nRun: gh auth login"
31
+ );
32
+ }
33
+ }
34
+ function loadSyncConfig() {
35
+ try {
36
+ const raw = readFileSync(syncConfigPath(), "utf-8");
37
+ const parsed = JSON.parse(raw);
38
+ if (typeof parsed.gistId === "string" && parsed.gistId.length > 0) {
39
+ return { gistId: parsed.gistId };
40
+ }
41
+ return null;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+ function saveSyncConfig(config) {
47
+ const filePath = syncConfigPath();
48
+ mkdirSync(dirname(filePath), { recursive: true });
49
+ writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
50
+ }
51
+ function createGist(payload) {
52
+ const tmpFile = join(tmpdir(), GIST_FILENAME);
53
+ try {
54
+ writeFileSync(tmpFile, payload, "utf-8");
55
+ const result = execSync(
56
+ `gh gist create "${tmpFile}" --desc "agentic-memory sync" --public=false`,
57
+ { ...EXEC_OPTS, stdio: ["pipe", "pipe", "pipe"] }
58
+ ).trim();
59
+ const gistId = result.split("/").pop() ?? "";
60
+ if (!gistId) throw new Error(`Failed to parse gist ID from: ${result}`);
61
+ saveSyncConfig({ gistId });
62
+ return gistId;
63
+ } finally {
64
+ try {
65
+ unlinkSync(tmpFile);
66
+ } catch {
67
+ }
68
+ }
69
+ }
70
+ function readGist(gistId) {
71
+ try {
72
+ return execSync(
73
+ `gh gist view "${gistId}" --filename "${GIST_FILENAME}" --raw`,
74
+ { ...EXEC_OPTS, stdio: ["pipe", "pipe", "pipe"] }
75
+ );
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+ function updateGist(gistId, payload) {
81
+ const tmpFile = join(tmpdir(), GIST_FILENAME);
82
+ try {
83
+ writeFileSync(tmpFile, payload, "utf-8");
84
+ execSync(
85
+ `gh gist edit "${gistId}" --filename "${GIST_FILENAME}" "${tmpFile}"`,
86
+ { ...EXEC_OPTS, stdio: ["pipe", "pipe", "pipe"] }
87
+ );
88
+ } finally {
89
+ try {
90
+ unlinkSync(tmpFile);
91
+ } catch {
92
+ }
93
+ }
94
+ }
95
+
96
+ // src/commands/memory/utils/sync-merge.ts
97
+ function memoryToSyncRow(m) {
98
+ return {
99
+ id: m.id,
100
+ type: m.type,
101
+ title: m.title,
102
+ content: m.content,
103
+ context: m.context,
104
+ source: m.source,
105
+ project: m.project,
106
+ tags: [...m.tags],
107
+ importance: m.importance,
108
+ access_count: m.accessCount,
109
+ injection_count: m.injectionCount,
110
+ created_at: m.createdAt,
111
+ updated_at: m.updatedAt,
112
+ last_accessed: m.lastAccessed
113
+ };
114
+ }
115
+ function mergeFromRemote(memoryRepo, relationRepo, payload, project) {
116
+ let inserted = 0;
117
+ let updated = 0;
118
+ let relationsAdded = 0;
119
+ const memories = project ? payload.memories.filter((m) => m.project === project) : payload.memories;
120
+ for (const remote of memories) {
121
+ const local = memoryRepo.getById(remote.id);
122
+ if (!local) {
123
+ memoryRepo.upsertFromSync(remote);
124
+ inserted++;
125
+ } else if (remote.updated_at > local.updatedAt) {
126
+ memoryRepo.upsertFromSync(remote);
127
+ updated++;
128
+ }
129
+ }
130
+ const localIds = new Set(memoryRepo.getAll().map((m) => m.id));
131
+ const relations = payload.relations.filter(
132
+ (r) => localIds.has(r.source_id) && localIds.has(r.target_id)
133
+ );
134
+ for (const rel of relations) {
135
+ const added = relationRepo.create(
136
+ rel.source_id,
137
+ rel.target_id,
138
+ rel.relation_type
139
+ );
140
+ if (added) relationsAdded++;
141
+ }
142
+ return { inserted, updated, relationsAdded };
143
+ }
144
+
145
+ export {
146
+ assertGhAvailable,
147
+ loadSyncConfig,
148
+ createGist,
149
+ readGist,
150
+ updateGist,
151
+ memoryToSyncRow,
152
+ mergeFromRemote
153
+ };
154
+ //# sourceMappingURL=chunk-7YDBTED2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/utils/gist-transport.ts","../src/commands/memory/utils/sync-merge.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport { readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomUUID } from 'node:crypto';\nimport { resolveDataDir, DEFAULT_CONFIG } from '../config.js';\nimport type { SyncConfig } from '../types.js';\n\nconst EXEC_OPTS = { encoding: 'utf-8' as const, timeout: 30_000 };\nconst GIST_FILENAME = 'agentic-memory-sync.json';\nconst SYNC_CONFIG_FILE = 'sync-config.json';\n\nfunction syncConfigPath(): string {\n return join(resolveDataDir(DEFAULT_CONFIG.dataDir), SYNC_CONFIG_FILE);\n}\n\nexport function assertGhAvailable(): void {\n try {\n execSync('gh --version', { ...EXEC_OPTS, stdio: 'pipe' });\n } catch {\n throw new Error(\n 'Memory sync requires the GitHub CLI.\\n' +\n 'Install: https://cli.github.com/\\n' +\n 'Then run: gh auth login'\n );\n }\n try {\n execSync('gh auth status', { ...EXEC_OPTS, stdio: 'pipe' });\n } catch {\n throw new Error(\n 'gh is installed but not authenticated.\\n' +\n 'Run: gh auth login'\n );\n }\n}\n\nexport function loadSyncConfig(): SyncConfig | null {\n try {\n const raw = readFileSync(syncConfigPath(), 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (typeof parsed.gistId === 'string' && parsed.gistId.length > 0) {\n return { gistId: parsed.gistId };\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport function saveSyncConfig(config: SyncConfig): void {\n const filePath = syncConfigPath();\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function createGist(payload: string): string {\n const tmpFile = join(tmpdir(), GIST_FILENAME);\n try {\n writeFileSync(tmpFile, payload, 'utf-8');\n const result = execSync(\n `gh gist create \"${tmpFile}\" --desc \"agentic-memory sync\" --public=false`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n ).trim();\n const gistId = result.split('/').pop() ?? '';\n if (!gistId) throw new Error(`Failed to parse gist ID from: ${result}`);\n saveSyncConfig({ gistId });\n return gistId;\n } finally {\n try { unlinkSync(tmpFile); } catch { /* ignore */ }\n }\n}\n\nexport function readGist(gistId: string): string | null {\n try {\n return execSync(\n `gh gist view \"${gistId}\" --filename \"${GIST_FILENAME}\" --raw`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n );\n } catch {\n return null;\n }\n}\n\nexport function updateGist(gistId: string, payload: string): void {\n const tmpFile = join(tmpdir(), GIST_FILENAME);\n try {\n writeFileSync(tmpFile, payload, 'utf-8');\n execSync(\n `gh gist edit \"${gistId}\" --filename \"${GIST_FILENAME}\" \"${tmpFile}\"`,\n { ...EXEC_OPTS, stdio: ['pipe', 'pipe', 'pipe'] },\n );\n } finally {\n try { unlinkSync(tmpFile); } catch { /* ignore */ }\n }\n}\n","import type { Memory, SyncPayload, SyncMemoryRow, MergeResult, RelationType } from '../types.js';\nimport type { MemoryRepo } from '../storage/memory-repo.js';\nimport type { RelationRepo } from '../storage/relation-repo.js';\n\nfunction memoryToSyncRow(m: Memory): SyncMemoryRow {\n return {\n id: m.id,\n type: m.type,\n title: m.title,\n content: m.content,\n context: m.context,\n source: m.source,\n project: m.project,\n tags: [...m.tags],\n importance: m.importance,\n access_count: m.accessCount,\n injection_count: m.injectionCount,\n created_at: m.createdAt,\n updated_at: m.updatedAt,\n last_accessed: m.lastAccessed,\n };\n}\n\nexport { memoryToSyncRow };\n\nexport function mergeFromRemote(\n memoryRepo: MemoryRepo,\n relationRepo: RelationRepo,\n payload: SyncPayload,\n project?: string,\n): MergeResult {\n let inserted = 0;\n let updated = 0;\n let relationsAdded = 0;\n\n const memories = project\n ? payload.memories.filter((m) => m.project === project)\n : payload.memories;\n\n for (const remote of memories) {\n const local = memoryRepo.getById(remote.id);\n if (!local) {\n memoryRepo.upsertFromSync(remote);\n inserted++;\n } else if (remote.updated_at > local.updatedAt) {\n memoryRepo.upsertFromSync(remote);\n updated++;\n }\n }\n\n const localIds = new Set(memoryRepo.getAll().map((m) => m.id));\n const relations = payload.relations.filter(\n (r) => localIds.has(r.source_id) && localIds.has(r.target_id),\n );\n\n for (const rel of relations) {\n const added = relationRepo.create(\n rel.source_id,\n rel.target_id,\n rel.relation_type as RelationType,\n );\n if (added) relationsAdded++;\n }\n\n return { inserted, updated, relationsAdded };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/memory/types.ts
4
+ import { z } from "zod";
5
+ var MEMORY_TYPES = ["working", "episodic", "semantic", "procedural", "pattern"];
6
+ var MEMORY_SOURCES = ["manual", "session_end", "consolidation", "hook", "import"];
7
+ var RELATION_TYPES = [
8
+ "relates_to",
9
+ "depends_on",
10
+ "contradicts",
11
+ "extends",
12
+ "implements",
13
+ "derived_from"
14
+ ];
15
+ var StoreInputSchema = z.object({
16
+ type: z.enum(MEMORY_TYPES),
17
+ content: z.string().min(1).max(1e4),
18
+ title: z.string().max(200).optional(),
19
+ tags: z.array(z.string()).max(20).default([]),
20
+ importance: z.number().min(0).max(1).default(0.5),
21
+ context: z.string().optional(),
22
+ source: z.enum(MEMORY_SOURCES).default("manual"),
23
+ project: z.string().max(200).optional()
24
+ });
25
+ var SearchInputSchema = z.object({
26
+ query: z.string().min(1).max(500),
27
+ id: z.string().optional(),
28
+ type: z.enum(MEMORY_TYPES).optional(),
29
+ tags: z.array(z.string()).max(10).optional(),
30
+ limit: z.number().int().min(1).max(50).default(10),
31
+ min_importance: z.number().min(0).max(1).default(0),
32
+ project: z.string().max(200).optional()
33
+ });
34
+ var ForgetInputSchema = z.object({
35
+ id: z.string(),
36
+ hard_delete: z.boolean().default(false)
37
+ });
38
+ var RelateInputSchema = z.object({
39
+ source_id: z.string(),
40
+ target_id: z.string(),
41
+ relation_type: z.enum(RELATION_TYPES)
42
+ });
43
+ var SyncPayloadSchema = z.object({
44
+ version: z.number(),
45
+ machine_id: z.string(),
46
+ pushed_at: z.string(),
47
+ memories: z.array(z.object({
48
+ id: z.string(),
49
+ type: z.enum(MEMORY_TYPES),
50
+ title: z.string().nullable(),
51
+ content: z.string(),
52
+ context: z.string().nullable(),
53
+ source: z.enum(MEMORY_SOURCES).nullable(),
54
+ project: z.string().nullable(),
55
+ tags: z.array(z.string()),
56
+ importance: z.number(),
57
+ access_count: z.number(),
58
+ injection_count: z.number(),
59
+ created_at: z.string(),
60
+ updated_at: z.string(),
61
+ last_accessed: z.string().nullable()
62
+ })),
63
+ relations: z.array(z.object({
64
+ source_id: z.string(),
65
+ target_id: z.string(),
66
+ relation_type: z.enum(RELATION_TYPES),
67
+ created_at: z.string()
68
+ }))
69
+ });
70
+
71
+ export {
72
+ MEMORY_TYPES,
73
+ MEMORY_SOURCES,
74
+ RELATION_TYPES,
75
+ SyncPayloadSchema
76
+ };
77
+ //# sourceMappingURL=chunk-J5NT4JGE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory/types.ts"],"sourcesContent":["import { z } from 'zod';\n\n// ── Memory Types ──────────────────────────────────────────────\n\nexport const MEMORY_TYPES = ['working', 'episodic', 'semantic', 'procedural', 'pattern'] as const;\nexport type MemoryType = typeof MEMORY_TYPES[number];\n\nexport const MEMORY_SOURCES = ['manual', 'session_end', 'consolidation', 'hook', 'import'] as const;\nexport type MemorySource = typeof MEMORY_SOURCES[number];\n\nexport const RELATION_TYPES = [\n 'relates_to', 'depends_on', 'contradicts', 'extends', 'implements', 'derived_from',\n] as const;\nexport type RelationType = typeof RELATION_TYPES[number];\n\n// ── Core Entities ─────────────────────────────────────────────\n\nexport interface Memory {\n readonly id: string;\n readonly type: MemoryType;\n readonly title: string | null;\n readonly content: string;\n readonly context: string | null;\n readonly source: MemorySource | null;\n readonly project: string | null;\n readonly tags: readonly string[];\n readonly importance: number;\n readonly createdAt: string;\n readonly updatedAt: string;\n readonly accessCount: number;\n readonly lastAccessed: string | null;\n readonly injectionCount: number;\n}\n\nexport interface Relation {\n readonly sourceId: string;\n readonly targetId: string;\n readonly relationType: RelationType;\n readonly createdAt: string;\n}\n\n// ── Search Types ──────────────────────────────────────────────\n\nexport interface SearchResult {\n readonly memory: Memory;\n readonly score: number;\n readonly explanation: string;\n}\n\nexport interface FtsMatch {\n readonly rowid: number;\n readonly memoryId: string;\n readonly rank: number;\n}\n\nexport interface ScoredCandidate {\n readonly memoryId: string;\n readonly textScore: number;\n readonly importanceScore: number;\n readonly recencyScore: number;\n readonly accessScore: number;\n readonly contextScore: number;\n readonly composite: number;\n}\n\n// ── Decay Parameters ──────────────────────────────────────────\n\nexport interface DecayParams {\n readonly tauByType: Record<MemoryType, number>;\n readonly accessModifiers: readonly { readonly maxCount: number; readonly multiplier: number }[];\n readonly relationModifier: { readonly connectedThreshold: number; readonly connectedMultiplier: number; readonly isolatedMultiplier: number };\n readonly importanceFloor: number;\n readonly pruneThreshold: number;\n readonly pruneMinAgeDays: number;\n}\n\n// ── Input Schemas (for MCP tools) ─────────────────────────────\n\nexport const StoreInputSchema = z.object({\n type: z.enum(MEMORY_TYPES),\n content: z.string().min(1).max(10000),\n title: z.string().max(200).optional(),\n tags: z.array(z.string()).max(20).default([]),\n importance: z.number().min(0).max(1).default(0.5),\n context: z.string().optional(),\n source: z.enum(MEMORY_SOURCES).default('manual'),\n project: z.string().max(200).optional(),\n});\nexport type StoreInput = z.infer<typeof StoreInputSchema>;\n\nexport const SearchInputSchema = z.object({\n query: z.string().min(1).max(500),\n id: z.string().optional(),\n type: z.enum(MEMORY_TYPES).optional(),\n tags: z.array(z.string()).max(10).optional(),\n limit: z.number().int().min(1).max(50).default(10),\n min_importance: z.number().min(0).max(1).default(0),\n project: z.string().max(200).optional(),\n});\nexport type SearchInput = z.infer<typeof SearchInputSchema>;\n\nexport const ForgetInputSchema = z.object({\n id: z.string(),\n hard_delete: z.boolean().default(false),\n});\nexport type ForgetInput = z.infer<typeof ForgetInputSchema>;\n\nexport const RelateInputSchema = z.object({\n source_id: z.string(),\n target_id: z.string(),\n relation_type: z.enum(RELATION_TYPES),\n});\nexport type RelateInput = z.infer<typeof RelateInputSchema>;\n\n// ── Sync Types ───────────────────────────────────────────────\n\nexport interface SyncPayload {\n readonly version: number;\n readonly machine_id: string;\n readonly pushed_at: string;\n readonly memories: readonly SyncMemoryRow[];\n readonly relations: readonly SyncRelationRow[];\n}\n\nexport interface SyncMemoryRow {\n readonly id: string;\n readonly type: MemoryType;\n readonly title: string | null;\n readonly content: string;\n readonly context: string | null;\n readonly source: MemorySource | null;\n readonly project: string | null;\n readonly tags: readonly string[];\n readonly importance: number;\n readonly access_count: number;\n readonly injection_count: number;\n readonly created_at: string;\n readonly updated_at: string;\n readonly last_accessed: string | null;\n}\n\nexport interface SyncRelationRow {\n readonly source_id: string;\n readonly target_id: string;\n readonly relation_type: RelationType;\n readonly created_at: string;\n}\n\nexport const SyncPayloadSchema = z.object({\n version: z.number(),\n machine_id: z.string(),\n pushed_at: z.string(),\n memories: z.array(z.object({\n id: z.string(),\n type: z.enum(MEMORY_TYPES),\n title: z.string().nullable(),\n content: z.string(),\n context: z.string().nullable(),\n source: z.enum(MEMORY_SOURCES).nullable(),\n project: z.string().nullable(),\n tags: z.array(z.string()),\n importance: z.number(),\n access_count: z.number(),\n injection_count: z.number(),\n created_at: z.string(),\n updated_at: z.string(),\n last_accessed: z.string().nullable(),\n })),\n relations: z.array(z.object({\n source_id: z.string(),\n target_id: z.string(),\n relation_type: z.enum(RELATION_TYPES),\n created_at: z.string(),\n })),\n});\n\nexport interface SyncConfig {\n readonly gistId: string;\n}\n\nexport interface MergeResult {\n readonly inserted: number;\n readonly updated: number;\n readonly relationsAdded: number;\n}\n\n// ── Stats ─────────────────────────────────────────────────────\n\nexport interface MemoryStats {\n readonly totalMemories: number;\n readonly byType: Record<MemoryType, number>;\n readonly totalRelations: number;\n readonly dbSizeBytes: number;\n readonly oldestMemory: string | null;\n readonly newestMemory: string | null;\n readonly topInjected: readonly { readonly id: string; readonly title: string | null; readonly injectionCount: number }[];\n}\n"],"mappings":"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","names":[]}