knit-mcp 0.12.0 → 0.16.1

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 (29) hide show
  1. package/README.md +356 -54
  2. package/dist/{cache-46OKHDRR.js → cache-7S5DFFQ6.js} +8 -7
  3. package/dist/{chunk-WADRF26Z.js → chunk-2FAS6CV4.js} +1 -1
  4. package/dist/{chunk-M3YZOJNW.js → chunk-BBQSWT4H.js} +18 -2
  5. package/dist/{chunk-MOOVNMIN.js → chunk-FX3SVNHX.js} +1 -1
  6. package/dist/{chunk-KKLAJLPO.js → chunk-JE4BZQUD.js} +24 -21
  7. package/dist/{chunk-QQNHF4XY.js → chunk-OZCVBNHF.js} +28 -3
  8. package/dist/chunk-Q3GNWHEW.js +192 -0
  9. package/dist/{chunk-GATMQQK5.js → chunk-QM4U75VE.js} +59 -10
  10. package/dist/chunk-RCPPLCKR.js +149 -0
  11. package/dist/chunk-V54QPQ6K.js +13 -0
  12. package/dist/{chunk-ST4X7LZT.js → chunk-YRLAWCYW.js} +10 -6
  13. package/dist/{chunk-TE6NP6BZ.js → chunk-ZESAIRIL.js} +57 -29
  14. package/dist/cli.js +32 -18
  15. package/dist/doctor-2ESSKFZE.js +14 -0
  16. package/dist/{install-agents-AH7EBB4J.js → install-agents-2JYKFLU6.js} +10 -9
  17. package/dist/{instructions-CF6K57Z2.js → instructions-4SLOUME2.js} +7 -3
  18. package/dist/{refresh-S62AZ3QA.js → refresh-4X4HMDMT.js} +4 -4
  19. package/dist/setup-2YN36GWS.js +385 -0
  20. package/dist/{status-2SEITNIE.js → status-RPHO7QQO.js} +2 -2
  21. package/dist/{tools-ZQHRWMVK.js → tools-7VJRV64S.js} +541 -232
  22. package/dist/ui-GN4JT4XR.js +736 -0
  23. package/package.json +14 -6
  24. package/webapp/dist/assets/index-BvEqg_UZ.js +40 -0
  25. package/webapp/dist/assets/index-vxJVGpVM.css +1 -0
  26. package/webapp/dist/index.html +14 -0
  27. package/webapp/index.html +13 -0
  28. package/dist/doctor-NI22FPXV.js +0 -12
  29. package/dist/setup-62ZH7GEI.js +0 -134
package/README.md CHANGED
@@ -3,50 +3,80 @@
3
3
  <a href="https://github.com/PDgit12/knit/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/PDgit12/knit/ci.yml?style=for-the-badge&label=CI&color=10b981" alt="CI" /></a>
4
4
  <img src="https://img.shields.io/badge/license-MIT-3b82f6?style=for-the-badge" alt="license" />
5
5
  <img src="https://img.shields.io/badge/node-%E2%89%A518-339933?style=for-the-badge&logo=node.js&logoColor=white" alt="node" />
6
- <img src="https://img.shields.io/badge/tests-665%20passing-22c55e?style=for-the-badge" alt="tests" />
7
- <img src="https://img.shields.io/badge/MCP%20tools-53-7c3aed?style=for-the-badge" alt="tools" />
6
+ <img src="https://img.shields.io/badge/MCP%20tools-55-7c3aed?style=for-the-badge" alt="tools" />
7
+ <img src="https://img.shields.io/badge/agents-6-10b981?style=for-the-badge" alt="agents supported" />
8
+ <img src="https://img.shields.io/badge/local--first-100%25-3b82f6?style=for-the-badge" alt="local-first" />
8
9
  </p>
9
10
 
10
11
  <h1 align="center">🧶 knit</h1>
11
12
 
12
13
  <p align="center">
13
- <strong>An intelligent command layer for Claude Code.</strong><br/>
14
- Project-scoped memory · on-demand workflow · parallel team worktrees · honest token accounting.<br/>
15
- <em>All in one MCP server.</em>
14
+ <strong>Universal MCP brain for agentic coding platforms.</strong><br/>
15
+ Project-scoped memory · on-demand workflow · parallel team worktrees · live analytics dashboard.<br/>
16
+ <em>Works with Claude Code, Cursor, Codex CLI, Cline, Continue, and GitHub Copilot (via VS Code Agent mode) — anything that speaks MCP.</em>
16
17
  </p>
17
18
 
18
19
  <p align="center">
19
20
  <a href="#-quick-start">Quick start</a> ·
20
21
  <a href="#-what-knit-is">What it is</a> ·
21
- <a href="#-whats-new-in-v0110">v0.11</a> ·
22
- <a href="#-52-mcp-tools">Tools</a> ·
23
- <a href="#-how-its-different">Comparison</a> ·
24
- <a href="#-honest-comparison-vs-memory-libraries">vs mem0/Letta</a>
22
+ <a href="#-how-search-works">How search works</a> ·
23
+ <a href="#-55-mcp-tools">Tools</a> ·
24
+ <a href="#-the-dashboard">Dashboard</a> ·
25
+ <a href="#-how-its-different">vs mem0/Letta</a>
25
26
  </p>
26
27
 
27
28
  ---
28
29
 
29
30
  ## 🧠 What knit is
30
31
 
31
- Knit makes Claude Code do the right thing automatically — because you can't predict how a user will phrase a request. It does three jobs at once:
32
+ Knit gives **any MCP-speaking coding agent** the right defaults automatically — because you can't predict how a user will phrase a request, and every agent (Claude Code, Cursor, Codex CLI, Cline, Continue, GitHub Copilot) ends up burning tokens re-discovering the same project facts. Knit does four jobs at once:
32
33
 
33
34
  | | |
34
35
  |---|---|
35
- | 🧠 **Memory** | Every project keeps a brain at `~/.knit/projects/<hash>/`. Sessions compound: learnings, false positives, session summaries, and a static-analysis import graph are all queryable next session. |
36
- | 🪶 **Tokens** | `CLAUDE.md` is ~2 KB (project facts only). Protocol depth is fetched on demand via `knit_get_workflow(phase)`. Knit is **net-negative** on context cost. |
36
+ | 🧠 **Memory** | Every project keeps a brain at `~/.knit/projects/<hash>/`. Sessions compound: learnings, false positives, session summaries, and a static-analysis import graph are all queryable next session. Cross-project pool at `~/.knit/global/`. |
37
+ | 🪶 **Tokens** | `CLAUDE.md` is ~2 KB (project facts only). Protocol depth is fetched on demand via `knit_get_workflow(phase)`. Per-cache-hit savings ≈ 15K tokens (calibrated from instrumented RESEARCH phases — override via env). Reuse-ratio + ROI surfaced in the dashboard. |
37
38
  | 🛠️ **Workflow** | A 4-tier classification (Inquiry / Trivial / Standard / Complex) with phase-triggered plan mode, quality-gated `LEARN`, and team-scoped git worktrees so parallel agents don't step on each other. |
39
+ | 📊 **Dashboard** | New in v0.13. `knit ui` opens a local-first analytics dashboard at `http://127.0.0.1:7421` — bento layout, brain savings, per-project ROI, **force-directed brain graph**, real-time sync via SSE. See [Dashboard](#-the-dashboard). |
38
40
 
39
- It's a **single product**, not three. Every design choice has to win on memory + tokens + workflow together.
41
+ **Local-first** invariant: zero cloud calls in memory/retrieval/classification. Dashboard binds to `127.0.0.1` only, with Host/Origin validation + CSP headers. Your brain stays on your machine.
42
+
43
+ It's a **single product**, not four. Every design choice has to win on memory + tokens + workflow + analytics together.
40
44
 
41
45
  ---
42
46
 
43
47
  ## 🚀 Quick start
44
48
 
45
49
  ```bash
46
- npx knit-mcp@latest setup
50
+ npm install -g knit-mcp
51
+ knit setup # adds Knit MCP to your agent's config (Claude Code / Cursor / Codex / etc.)
52
+ knit ui # opens the brain dashboard at http://127.0.0.1:7421 (optional but recommended)
47
53
  ```
48
54
 
49
- Adds the Knit MCP server to your Claude Code config (`~/.claude.json`). **No per-project setup.** Open Claude Code in any project — the first MCP tool call auto-initializes the brain, hooks, and per-project CLAUDE.md block.
55
+ **No per-project setup.** Open your MCP-speaking agent in any project — the first MCP tool call auto-initializes the brain, hooks, and per-project CLAUDE.md block.
56
+
57
+ ### Adoption per agent
58
+
59
+ v0.14: a single `knit setup` detects **every** installed MCP-speaking agent on
60
+ your machine and writes Knit's config into each one's native format. No
61
+ per-agent manual setup, no copy-pasted JSON.
62
+
63
+ | Agent | Auto-detected by `knit setup` | Config format written | Hook support |
64
+ |---|---|---|---|
65
+ | Claude Code | ✅ `~/.claude.json` | JSON · `mcpServers` | ✅ PreToolUse / PostToolUse / Stop |
66
+ | Cursor | ✅ `.cursor/mcp.json` | JSON · `mcpServers` | ⚠️ approval flow only |
67
+ | Codex CLI | ✅ `~/.codex/config.toml` | **TOML** · `[mcp_servers.knit-brain]` | ⚠️ approval flow only |
68
+ | Cline | ✅ `~/.cline/mcp.json` + `AGENTS.md` | JSON · `mcpServers` | ⚠️ approval flow only |
69
+ | Continue | ✅ `.continue/mcpServers/knit-brain.yaml` | **YAML** per-server | ⚠️ approval flow only |
70
+ | GitHub Copilot (VS Code Agent mode) | ✅ `.vscode/mcp.json` | JSON · `servers` (unique key) | ⚠️ approval flow only |
71
+ | Any other MCP client | ✅ stdio works universally | per the client's docs | varies |
72
+
73
+ > **"Hook support" caveat:** only Claude Code has lifecycle hooks (PreToolUse /
74
+ > PostToolUse / Stop). For the other 5 agents Knit enforces the protocol via
75
+ > the MCP `instructions` field (handshake primer) + **server-side soft-gates**
76
+ > in tool responses — same effect as hooks, transport-layer instead of host-layer.
77
+ > Opt into block-strictness enforcement with `knit_set_protocol_strictness({level: 'block'})`.
78
+
79
+ > **Supported shells:** macOS, Linux, WSL, Git Bash, PowerShell. Windows `cmd.exe` is not supported as the hook-runner shell — use PowerShell (default in modern Windows Terminal) or Git Bash.
50
80
 
51
81
  > **Supported shells:** macOS, Linux, WSL, Git Bash, PowerShell. Windows `cmd.exe` is not supported as the hook-runner shell — use PowerShell (default in modern Windows Terminal) or Git Bash.
52
82
 
@@ -58,47 +88,269 @@ Knit ships **Protocol Guard in `warn` mode by default** — hooks print reminder
58
88
  knit_set_protocol_strictness({ level: "off" })
59
89
  ```
60
90
 
61
- ### Uninstall in 30 seconds
91
+ ### Uninstall
92
+
93
+ One command kills all data:
62
94
 
63
95
  ```bash
64
96
  rm -rf ~/.knit # all per-project + global memory
65
97
  ```
66
98
 
67
- Then:
68
- 1. Remove `"knit-brain"` from `mcpServers` in `~/.claude.json`
69
- 2. Delete the `<!-- knit:start --> ... <!-- knit:end -->` block from each project's `CLAUDE.md`
70
- 3. Remove `_knitOwned` entries from each project's `.claude/settings.local.json`
99
+ Then remove Knit's registration from each agent you've used `knit setup` with:
100
+
101
+ | Agent | File to edit | What to remove |
102
+ |---|---|---|
103
+ | Claude Code (global) | `~/.claude.json` | the `"knit-brain"` entry under `mcpServers` |
104
+ | Claude Code (global) | `~/.claude/CLAUDE.md` | the `## Knit Brain (MCP)` block (appended by `knit setup`) |
105
+ | Cursor | `~/.cursor/mcp.json` or `.cursor/mcp.json` | the `"knit-brain"` entry under `mcpServers` |
106
+ | Codex CLI | `~/.codex/config.toml` | the `[mcp_servers.knit-brain]` section |
107
+ | Cline | `~/.cline/mcp.json` | the `"knit-brain"` entry under `mcpServers` |
108
+ | Continue | `.continue/mcpServers/knit-brain.yaml` | delete the file |
109
+ | VS Code Copilot | `.vscode/mcp.json` (or user `mcp.json`) | the `"knit-brain"` entry under `servers` |
110
+
111
+ Per-project residue to clean:
112
+
113
+ - `<project>/CLAUDE.md` — delete the `<!-- knit:start --> ... <!-- knit:end -->` block
114
+ - `<project>/.claude/settings.local.json` — remove hook entries tagged `_knitOwned: true`
115
+ - `<project>/.claude/KNIT.md` — sidecar written when CLAUDE.md had no markers; delete if present
116
+ - `<project>/.claude/agents/knit-*.md` — installed VoltAgent subagents; delete the `knit-` prefixed ones
117
+ - `<project>/AGENTS.md` — if you use Codex CLI or Cline, the marker-wrapped Knit block was written here; delete the block or the file
71
118
 
72
119
  Knit writes nowhere else on your machine.
73
120
 
74
121
  ---
75
122
 
76
- ## What's new in v0.9.0
123
+ ## 🔍 How search works
124
+
125
+ Knit's retrieval is **BM25 + Reciprocal Rank Fusion** over your learnings,
126
+ session summaries, and the cross-project pool, with two cheap-but-honest
127
+ lexical-bridging layers stacked on top: **2-gram fallback** for typos and
128
+ rare compounds, and **curated coding-domain synonym expansion** for the
129
+ most common semantic-gap pairs. No vector embeddings, no remote inference,
130
+ no API calls.
131
+
132
+ **Why this design choice (not an oversight):**
133
+
134
+ - **Deterministic.** Same query → same ranking, every time. No model
135
+ drift, no upgrade-day surprises.
136
+ - **Fast.** Sub-millisecond on corpora ≤ 1K entries (your typical
137
+ project memory). No cold start, no model load.
138
+ - **Local-first.** Zero network calls. Your memory never leaves the
139
+ machine.
140
+ - **Auditable.** You can explain every hit by looking at term overlap
141
+ + the synonym dictionary (50 pairs, hand-curated). No "the model
142
+ said so."
143
+ - **Honest at the boundary.** The bench has documented misses where
144
+ even synonym expansion can't bridge the gap — we ship those visible,
145
+ not hidden.
146
+
147
+ **What it does well.** Exact term match, identifier search
148
+ (`knit_classify_task`), rare-term emphasis (e.g. `PIPE_BUF`), multi-word
149
+ ranking, tag filtering, cross-project diversification (max 2 per
150
+ project), branch diversification on sessions (max 2 per branch). **Typo
151
+ recovery via 2-gram fallback** (`knit_clasify` → `knit_classify_task`).
152
+ **Synonym recovery via curated dictionary** (`hook` ↔ `webhook`,
153
+ `schema` ↔ `migration`, `auth` ↔ `authentication`, `cache` ↔ `memo`,
154
+ `deploy` ↔ `ship` ↔ `release`, etc. — see
155
+ [`src/engine/retrieval/synonyms.ts`](src/engine/retrieval/synonyms.ts)
156
+ for the full ~50-pair dictionary). Synonym matches scored at 0.4× of a
157
+ direct BM25 hit so genuine matches always rank higher.
158
+
159
+ **What it still cannot do.** Multi-word paraphrase ("how do schema
160
+ changes ship" with no shared terms). Deep abstraction-level bridging
161
+ ("data consistency" → "atomic temp+rename"). Question intent
162
+ ("what's the right pattern for X"). Negation. Cross-entry synthesis
163
+ ("based on the auth lessons, what should I do for OAuth"). These need
164
+ either embeddings (model dependency + bundle weight, breaks local-first
165
+ unless run locally via ONNX) or an LLM call layer (Knit-as-retrieval
166
+ becomes Knit-as-agent, different identity). v0.20+ candidate: hybrid
167
+ retrieval (BM25 + local embeddings via RRF) — opt-in, bench-gated.
168
+
169
+ **The practical implication.** Search with words close to how you
170
+ recorded the learning, OR words that have a synonym pair in the
171
+ dictionary. If you write a learning about *webhook signatures*, you
172
+ can now search either *webhook signatures* OR *hook signatures* —
173
+ the dictionary bridges those. For genuinely different vocabulary that
174
+ isn't in the synonym table, use `knit_search_global_learnings` to widen
175
+ the corpus, or call `knit_search_sessions` to pull from past narrative
176
+ summaries that may use more terms.
177
+
178
+ **Bench numbers (v0.16):** synthetic 88.0% top-1 / **100% recall@5**,
179
+ learnings (real-prose) 86.7% top-1 / 96.7% recall@5. Both default ON;
180
+ opt-out via `enableNgramFallback: false` + `enableSynonyms: false` for
181
+ a strict lexical-only baseline.
77
182
 
78
- v0.9 closes the **enforcement story** — every honest limit from the v0.8 architecture got a structural fix.
183
+ ---
79
184
 
80
- ### Anti-hallucination
185
+ ## ✨ What's new in v0.16.0
186
+
187
+ v0.16 is the **semantic-lite release**. Two retrieval improvements that
188
+ close the most common BM25 lexical gaps without an embedding model or
189
+ external API call. Both default ON, both bench-pinned non-regressive.
190
+
191
+ - **Curated synonym expansion.** Hand-curated dictionary of ~50
192
+ coding-domain synonym pairs (`webhook` ↔ `hook`, `schema` ↔
193
+ `migration`, `auth` ↔ `authentication`, `cache` ↔ `memo`, `deploy` ↔
194
+ `ship` ↔ `release`, etc.) in `src/engine/retrieval/synonyms.ts`. When
195
+ a query token has known synonyms, BM25 scores documents containing
196
+ those synonyms with a 0.4× discount weight (higher than the 2-gram
197
+ fallback's 0.25 because synonyms are conceptually closer than
198
+ near-spelling matches). Fires both as a fallback (term unmatched,
199
+ synonym matched) and a boost (term matched directly, synonym widens
200
+ reach).
201
+ - **2-gram fallback default ON.** `enableNgramFallback` flipped from
202
+ default `false` → default `true`. v0.15 introduced this as opt-in to
203
+ avoid bench regression risk; v0.16 flips the default after both
204
+ benches verified strictly stable.
205
+ - **FIFO-safe `handleIndexRequirements`.** Latent v0.12.1 hardening
206
+ bug: `openSync(O_RDONLY)` on a named pipe blocked indefinitely
207
+ before `fstat` could reject it. Now passes `O_NONBLOCK`; regular
208
+ files unaffected.
209
+
210
+ Bench impact (v0.15 → v0.16): synthetic 86%/96% → **88%/100%**;
211
+ learnings 83.3%/96.7% → **86.7%/96.7%**. The synthetic recall@5 hit
212
+ 100% because synonym expansion closed the "hook events authenticated"
213
+ miss that BM25 alone couldn't bridge.
214
+
215
+ ## ✨ What's new in v0.15.0
216
+
217
+ v0.15 is the **deep-clean release**. A second six-dimension internal audit
218
+ graded the post-v0.14.1 codebase and surfaced the deferred items — defense-
219
+ in-depth, retrieval honesty, UX parity, the trailing TODO debt. A single
220
+ audit-cleanup branch closed them all, then six parallel agents re-graded
221
+ the post-fix code to confirm nothing new slipped in.
222
+
223
+ - **Security defense-in-depth.** Every `git` invocation in `worktrees.ts`
224
+ migrated to `execFileSync` with array args (no shell). Agent fetcher
225
+ cache writes are SHA256-verified via sidecars; tampered caches force
226
+ a fresh fetch with stderr alert; pre-v0.15 caches backfilled on first
227
+ read. `qs` CVE (GHSA-q8mj-m7cp-5q26) pinned via npm `overrides` —
228
+ `npm audit` now reports 0 vulnerabilities.
229
+ - **Brain mechanics.** New `pruneLearningsByAge` parallels the sessions
230
+ pattern (atomic rewrite, conservatively preserves unparseable dates +
231
+ `#false-positive` entries). `readLearnings` schema-validates on read.
232
+ Opt-in BM25 2-gram fallback (`enableNgramFallback`, default off)
233
+ rescues typo-only queries without disturbing benchmarks.
234
+ - **Retrieval honesty.** New `bench:learnings` regression bench against
235
+ 30 real-learning-shape narrative entries — gates at top-1 ≥ 75% /
236
+ recall@5 ≥ 90% (currently 83.3% / 96.7%). Compounding-metrics response
237
+ now surfaces token-saved methodology with env-var overrides.
238
+ - **UX & instructions.** Webapp DoctorView shows per-agent rows (parity
239
+ with CLI `knit doctor`). Workflow `EXECUTE` + `REVIEW` phases now embed
240
+ `knit_suggest_command` hooks so the agent defers to user slash-commands
241
+ for test/lint/ship/qa/review. `buildUpdateNotice` surfaces npm-update
242
+ banner in the MCP instructions field — Cursor/Codex/Cline/Continue/
243
+ Copilot users now see updates at handshake.
244
+
245
+ ## ✨ What's new in v0.14.0
246
+
247
+ v0.14 is the **universality release**. Three coordinated shifts: every
248
+ MCP-speaking agent works out of the box, Knit composes with the slash
249
+ commands you already wrote, and enforcement works across all agents
250
+ (not just Claude Code).
251
+
252
+ ### 🌍 Six agents, one install
253
+
254
+ `knit setup` now detects every installed MCP-speaking agent and writes Knit's
255
+ config into each one's native format — JSON for Claude Code / Cursor / Cline /
256
+ VS Code (note: `servers` not `mcpServers` for VS Code), TOML for Codex CLI,
257
+ YAML for Continue. If Codex CLI or Cline is detected, a marker-wrapped
258
+ `AGENTS.md` is also written at project root (the cross-agent rules convention).
259
+ `knit doctor` now reports per-agent registration status, so you can see
260
+ which of your agents are wired up at a glance.
261
+
262
+ ### 🔧 Cross-platform protocol enforcement
263
+
264
+ Only Claude Code has hook lifecycles (PreToolUse / PostToolUse / Stop). For
265
+ the other 5 agents, v0.14 adds **server-side soft-gates** in MCP tool
266
+ responses. When strictness is set to `block`, protocol-critical handlers
267
+ return `{ status: 'protocol_required', next_action: '...' }` instead of
268
+ proceeding — the agent reads the response, follows the breadcrumb, retries.
269
+ This is the universality answer: same enforcement, transport layer instead
270
+ of host layer. Default strictness stays `warn` so existing flows are unchanged.
271
+
272
+ ### ⚡ Agent-native slash-command auto-detection
273
+
274
+ Two new Tier-1 MCP tools:
275
+
276
+ - `knit_scan_agent_commands` — scans `.claude/commands/`, `.cursor/rules/`,
277
+ `.clinerules/`, `~/.codex/prompts/`, `~/.continue/prompts/`, `.github/prompts/`
278
+ and surfaces every user-defined slash command + its description.
279
+ - `knit_suggest_command({phase})` — given a protocol phase (test/lint/review/
280
+ ship), returns matching commands so the agent can invoke `/test` (or
281
+ whatever you wrote) via the host's native slash mechanism, instead of
282
+ describing the work in prose.
283
+
284
+ Cached at `~/.knit/projects/<hash>/agent-commands.json` with a 1-hour TTL
285
+ (~10ms re-scan when stale). Read-only filesystem ops; Knit never executes
286
+ commands — the host agent invokes via its own mechanism.
287
+
288
+ Dashboard exposes the scan results at **`#/commands`** with searchable
289
+ per-agent listing.
290
+
291
+ ### 🛡️ Audit + hardening before publish
292
+
293
+ v0.14 included a deep-dive internal audit of every dashboard
294
+ endpoint, MCP handler, fs.watch race condition, and supply-chain dep. Five
295
+ inline fixes landed in commit `e4e1793`:
296
+ - `fs.watch` error handler now resets `watcher = null` so SSE recovers
297
+ cleanly after a watcher death (pre-fix, real-time sync silently stopped
298
+ until `knit ui` restart).
299
+ - JSON + SSE responses gained `X-Content-Type-Options: nosniff`,
300
+ `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer` (pre-fix only on
301
+ HTML).
302
+ - `handleDefineTeam` + `handlePostTeamFindings` now call `redactSecrets` on
303
+ user-supplied team metadata + finding descriptions (pre-fix: raw write to
304
+ disk). 9 of 9 write handlers now redact uniformly.
305
+
306
+ CBSE-style attack class verified PASS on every dashboard endpoint:
307
+ Host-validation + Origin-validation + read-only contract + same-origin CSP
308
+ + hex-only project-id regex. No malicious-page-can-read-your-brain vector.
309
+
310
+ ## ✨ What's new in v0.13.0
311
+
312
+ v0.13 ships the **dashboard** — the visual surface on top of the brain. Plus security hardening and the universal positioning (works with every MCP-speaking agent).
313
+
314
+ ### 📊 Brain dashboard (`knit ui`)
315
+
316
+ A single command opens a local-first analytics surface at `http://127.0.0.1:7421` — bento layout inspired by modern fintech dashboards, color-blocked cards, generous spacing, real-time sync.
317
+
318
+ | View | What it shows |
319
+ |---|---|
320
+ | **Brain** (`#/`) | Hero card with net tokens saved across all projects, recent activity feed (live), memory hit-rate arc, top projects by ROI |
321
+ | **Graph** (`#/graph`) | Project picker → **force-directed brain graph**: every learning is a node, edges by Jaccard similarity over shared tags + domains. Click any node for the full lesson. Threshold slider. |
322
+ | **Cross-project** (`#/global`) | Cross-project learnings pool, filterable by source project |
323
+ | **Per-project** (`#/p/:id`) | Searchable learnings list, retrieval signals, ROI deep dive (`#/p/:id/metrics`), graph (`#/p/:id/graph`) |
324
+ | **Health** (`#/doctor`) | Install diagnostics: ~/.knit writable, MCP registered, version current |
81
325
 
82
- - 📎 **Citation rule in the MCP `instructions` field.** Every session's system prompt now tells the agent: *"when you state a fact about this codebase, cite the Knit tool result that verified it — e.g. (per `knit_query_imports`). If you can't cite, say 'unverified' explicitly."* Makes hallucinations visible at the **claim level**.
83
- - 🔍 **`knit_verify_claim` tool.** Single-call fact-check against the knowledge graph. Parses *"A imports B"*, *"X exports Y"*, *"A is tested by B"*, *"X exists"* and returns `verified | contradicted | unparseable` with evidence.
326
+ **Real-time sync via SSE.** The server watches `~/.knit/` via `fs.watch`; any agent recording a learning anywhere updates the open dashboard within ~250ms. No polling.
84
327
 
85
- ### Smarter retrieval
328
+ ### 🔐 Security hardening (real, not theater)
86
329
 
87
- - **Auto-search inside `knit_classify_task`.** For `standard` / `complex` tier, classify now runs BM25 over (description + affected domains) automatically and embeds top-3 hits as `pre_emptive_learnings`. Closes the *"agent skipped `knit_search_learnings` before re-investigating"* gap with **zero extra calls**.
88
- - 📚 **`suggested_reads` from `knit_build_context`.** Curated list of files worth opening *before* editing — three signals: graph-importers (blast radius), graph-imports (likely needed), memory-mentions (files referenced by past learnings). Each entry carries `{ path, reason, via }`.
89
- - 🪜 **`knit_get_learning` — hierarchical retrieval.** Search returns headlines (summary + tags); the agent expands a specific learning by id only when needed. **Pay-per-detail.**
90
- - 🧮 **`knit_consolidate_learnings`.** Tag-Jaccard clustering of similar learnings → one pattern entry per cluster. Dry-run by default; `commit=true` persists with originals tagged `#consolidated` (preserved but deprioritized).
330
+ The dashboard is a localhost HTTP server, which has real attack surface. v0.13 closes it:
91
331
 
92
- ### Hook-level enforcement (`HOOKS_VERSION` 6 7)
332
+ - **Host-header validation** — rejects requests whose `Host` isn't `127.0.0.1`/`localhost`. Blocks **DNS rebinding** (a malicious site you visit could resolve `evil.com` to 127.0.0.1 and trick your browser into reading the dashboard).
333
+ - **Origin-header validation** — cross-origin requests get `403`. Same defense pattern as PostgreSQL, Redis, Docker daemon, the React dev server.
334
+ - **Content-Security-Policy** on every HTML response — same-origin scripts only, no `'unsafe-eval'`, no external sources.
335
+ - **X-Frame-Options: DENY**, X-Content-Type-Options: nosniff, Referrer-Policy: no-referrer.
336
+ - **No mutation endpoints** in v0.13 (read-only dashboard). Setup wizard / refresh button stay deferred until proper CSRF protection lands.
93
337
 
94
- | Hook | What it does |
95
- |---|---|
96
- | **PreToolUse search-gate** | For `standard`/`complex` tasks, blocks Edit/Write (in `block` mode) or warns (default `warn`) when `knit_search_learnings` hasn't fired in the current turn. |
97
- | **PreToolUse content inspection** | Reads proposed Edit/Write content, parses local imports, warns on relative paths that don't resolve on disk — **catches hallucinated imports before they land**. |
98
- | **PostToolUse import validation** | After the file lands, re-parses imports and warns about unresolved relative paths — catches anything that slipped past the pre-check. |
99
- | **Stop-hook budget watch** | Cheap CLAUDE.md size check at session end; warns if it crosses the 12.5 KB over-budget threshold. Drift becomes visible even when the agent doesn't call `knit_brain_status`. |
338
+ ### 🌍 Universal positioning
339
+
340
+ Knit is an MCP server. Anything that speaks MCP works:
100
341
 
101
- > **Upgrade note.** After `npx knit-mcp@latest setup`, **restart Claude Code**. The `instructions` field and tier-gated `tools/list` only flow into the system prompt at handshake. The `HOOKS_VERSION` bump auto-regenerates installed hooks on the next brain load — no manual `knit refresh` needed.
342
+ - **Claude Code** handshake via stdio, `instructions` field carries protocol primer
343
+ - **Cursor** — register knit MCP server in settings
344
+ - **Codex CLI** — `~/.codex/config.toml` mcpServers section
345
+ - **Cline / Continue** — both speak MCP, same setup
346
+
347
+ The dashboard works regardless of which agent you use — it reads the brain from disk.
348
+
349
+ ### 🪙 Token-economy lever
350
+
351
+ `knit ui` notifies you when a new `knit-mcp` is available on npm — polls the registry every 5 minutes server-side, banner pops in the dashboard with the one-line `npm install -g knit-mcp@latest` command. No stale installs.
352
+
353
+ > **Upgrade note.** After `npm install -g knit-mcp@latest`, **restart your agent**. The `instructions` field flows into the system prompt at handshake. The `HOOKS_VERSION` bump auto-regenerates installed hooks on the next brain load — no manual `knit refresh` needed.
102
354
 
103
355
  ---
104
356
 
@@ -115,7 +367,47 @@ Each surface gets a `healthy | warn | over-budget` verdict from `knit_brain_stat
115
367
 
116
368
  ---
117
369
 
118
- ## 🛠️ 43 MCP Tools
370
+ ## 📊 The dashboard
371
+
372
+ Run `knit ui` to open the local analytics surface. **Single command**, no other CLI needed for normal operation:
373
+
374
+ ```bash
375
+ knit ui
376
+ # Knit Dashboard — http://127.0.0.1:7421
377
+ # Reading from: /Users/<you>/.knit
378
+ # Press Ctrl-C to stop.
379
+ # (automatically opens your default browser)
380
+ ```
381
+
382
+ | Feature | What you see |
383
+ |---|---|
384
+ | **Bento home** | Big "Net tokens saved" hero card (dark), live recent activity (green "live" dot when SSE connected), memory hit-rate gauge, top projects by ROI as color-blocked cards |
385
+ | **Brain graph** | Force-directed visualization of one project's learnings. Nodes sized by access count, colored by domain. Edges by Jaccard similarity over tags + domains. Click any node → side panel with the full lesson. Threshold slider live-recomputes the graph. |
386
+ | **Per-project deep dive** | Hero card with verdict tone (cold/warming/compounding/strong), retrieval signals, classifications-by-tier breakdown, top domains heatmap, searchable learnings list |
387
+ | **Health** | Install diagnostics — Node version, Knit version, ~/.knit permissions, MCP registration in `~/.claude.json` |
388
+
389
+ **API endpoints** (all read-only, all 127.0.0.1 only):
390
+
391
+ - `GET /api/version` — runtime version + update check + security metadata
392
+ - `GET /api/brain/summary` — global counts
393
+ - `GET /api/brain/aggregate` — cross-project ROI totals
394
+ - `GET /api/projects` — project list
395
+ - `GET /api/projects/:id/learnings` — full learning entries
396
+ - `GET /api/projects/:id/metrics` — compounding ROI for one project
397
+ - `GET /api/projects/:id/graph` — force-directed node + edge data (Jaccard threshold tunable)
398
+ - `GET /api/global/learnings` — cross-project pool
399
+ - `GET /api/doctor` — install diagnostics
400
+ - `GET /api/events` — Server-Sent Events stream for real-time sync
401
+
402
+ ---
403
+
404
+ ## 🛠️ 55 MCP Tools
405
+
406
+ > **49 active by default** at first handshake. The remaining 6 are tier-gated:
407
+ > teams (9 tools, auto-on when ≥3 domains detected), subagents (1 tool, auto-on
408
+ > when `.claude/agents/` exists), and admin (3 tools, opt-in via
409
+ > `knit_enable_feature("admin")`). Call `knit_list_features` to see what's
410
+ > available and how to enable.
119
411
 
120
412
  <details open>
121
413
  <summary><strong>🕸️ Knowledge graph</strong> <em>(Tier 1, ~5ms)</em></summary>
@@ -361,9 +653,13 @@ Pair with `knit_compounding_metrics` for the value side of the ledger (sessions,
361
653
  ## 💻 CLI
362
654
 
363
655
  ```bash
364
- knit setup # one time: add MCP to Claude settings
365
- knit status # dashboard: sessions, learnings, hit rate, knowledge health
366
- knit refresh # force rebuild knowledge brain
656
+ knit setup # one time: detects all 6 MCP-speaking agents and registers Knit in each
657
+ knit doctor # install health check: version, MCP registration per agent, knowledgebase
658
+ knit ui # launch the local Knit dashboard (http://127.0.0.1:7421)
659
+ knit status # text snapshot: sessions, learnings, hit rate, knowledge health
660
+ knit refresh # force rebuild knowledge brain
661
+ knit install-agents # install VoltAgent subagents into <project>/.claude/agents/
662
+ knit export <fmt> # export learnings (current targets: obsidian)
367
663
  ```
368
664
 
369
665
  Example `knit status`:
@@ -379,11 +675,11 @@ Knowledge Base
379
675
  Accessed: 12 (67% hit rate)
380
676
  False positives: 3
381
677
 
382
- Token budget (v0.9)
678
+ Token budget (v0.16)
383
679
  CLAUDE.md: 2.0 KB → healthy
384
- Tool registry: 8.4 KB → healthy (31 active / 43 total)
385
- Instructions: 2.2 KB → healthy
386
- Per-session total: 12.6 KB → healthy
680
+ Tool registry: ~13 KB → warn (49 active / 55 total)
681
+ Instructions: ~4 KB → healthy
682
+ Per-session total: ~20 KB → healthy
387
683
 
388
684
  Compounding
389
685
  Sessions logged: 14
@@ -399,7 +695,7 @@ Compounding
399
695
  |--|---|---|---|---|
400
696
  | **Bet** | Slash-command flows | Agent rules | 100+ agents in swarms | **One disciplined agent, compounding memory** |
401
697
  | **Setup** | Install skills per-project | Manual `.claude/` setup | `npx ruflo init` (heavy) | **`npx knit-mcp setup` (light)** |
402
- | **Memory** | jsonl files in-tree | Memory directory | Vector DB + 4-tier consolidation | **Local, searchable, vectorless BM25 + graph fusion** |
698
+ | **Memory** | jsonl files in-tree | Memory directory | Vector DB + 4-tier consolidation | **Local, searchable, vectorless BM25 + graph fusion + 2-gram fallback + 50-pair synonym dictionary** |
403
699
  | **Token cost** | Skills loaded into context | Rules loaded into context | 314 tools advertised | **~2 KB CLAUDE.md, tier-gated registry, budget guardrail** |
404
700
  | **Parallel work** | None | None | Multi-agent swarms + federation | **Team-scoped git worktrees** |
405
701
  | **Cloud dependency** | None | None | Cognitum.One (cloud backbone) | **None — fully local** |
@@ -434,7 +730,7 @@ The mem0 / Letta / agentmemory comparison deserves a separate section because th
434
730
 
435
731
  Run it yourself: `npm run bench`. Source: [`benchmarks/retrieval-synthetic.ts`](./benchmarks/retrieval-synthetic.ts).
436
732
 
437
- **These numbers are NOT apples-to-apples with agentmemory's.** Their benchmark is 1,500 questions from real long conversations; Knit's is 50 hand-authored questions on a 7KB synthetic corpus. The numbers are close because the architecture is similar (BM25 + RRF), not because we've proven parity at scale. **Real comparison requires running LongMemEval-S on Knit** — on the roadmap for v0.13.
733
+ **These numbers are NOT apples-to-apples with agentmemory's.** Their benchmark is 1,500 questions from real long conversations; Knit's is 50 hand-authored questions on a 7KB synthetic corpus. The numbers are close because the architecture is similar (BM25 + RRF), not because we've proven parity at scale. **Real comparison requires running LongMemEval-S on Knit** — on the roadmap (a v0.20+ candidate alongside hybrid BM25 + local embeddings retrieval).
438
734
 
439
735
  **Knit isn't trying to be a better mem0.** It's a different product:
440
736
  - **MCP-native + zero-glue install** — mem0/Letta require SDK integration; Knit drops into any MCP host (Claude Code, Cursor, Codex) with one command.
@@ -452,7 +748,12 @@ LongMemEval-S R@5/R@10 + LOCOMO LLM-as-Judge runs are on the roadmap (v0.13+). U
452
748
 
453
749
  | Version | Headline |
454
750
  |---|---|
455
- | **v0.12.0** | **Picture Perfect: Structural Enforcement.** Diagnostic enforcing. Budget verdict surfaces in the MCP `instructions` field at handshake (before any tool description is read). `knit_load_session` carries `budget_health` + `learnings_health` nudges. `engram doctor` exits non-zero on over-budget; `engram setup` runs doctor as final step. New PostToolUse hook warns immediately on over-budget CLAUDE.md edits (HOOKS_VERSION 11→12; auto-rolls to existing users). This repo dogfoods: hand-curated 16KB CLAUDE.md migrated to lean 3.8KB + `.claude/MARKETING.md` sidecar. New `npm run bench:tokens` measures real MCP-on vs MCP-off cost: 93% smaller per-recall call, 50% smaller per-classify, payback at 3 recall calls. 53 tools, 705 tests. |
751
+ | **v0.16.0** | **Semantic-lite retrieval.** Curated coding-domain synonym dictionary (~50 pairs) closes the most common BM25 lexical gaps (`hook` `webhook`, `schema` `migration`, etc.) without an embedding model. 2-gram fallback for typos default ON after bench verification. Synthetic bench 88% top-1 / **100% recall@5** (was 96%); learnings 86.7% top-1 / 96.7% recall@5. Plus a FIFO-safe `O_NONBLOCK` fix to `handleIndexRequirements`. 55 tools, 818 tests. |
752
+ | **v0.15.0** | **Deep-clean audit release.** Six-dimension second audit + atomic-write helper applied to 9+ sites including `~/.claude.json` (a torn write there used to brick Claude Code). SHA256 sidecars on agent-fetcher cache writes detect tampering and re-fetch. `qs` CVE pinned via `npm overrides` → 0 vulns. Opt-in BM25 2-gram fallback for typos. `pruneLearningsByAge` + schema-validated `readLearnings`. Webapp DoctorView shows per-agent rows. Update notice surfaces in MCP `instructions` field for all 6 agents. 55 tools, 805+ tests. |
753
+ | **v0.14.1** | **Ship-readiness audit + atomicity hardening.** First six-dimension audit + 14 P1 fixes: `writeFileAtomic` helper across 9+ persistence paths; `handleSetupProject` redaction gap closed; `record_learning` substring dedup matches the description claim; soft-gate documented in instructions field; pre-publish leak gate. 55 tools. |
754
+ | **v0.14.0** | **Universality release.** Single `knit setup` detects + writes to every installed MCP-speaking agent (Claude Code, Cursor, Codex CLI, Cline, Continue, GitHub Copilot via VS Code Agent mode). Server-side soft-gates as the cross-platform protocol enforcement layer for agents without hook lifecycles. Slash-command auto-detection via `knit_scan_agent_commands` + `knit_suggest_command`. 55 tools. |
755
+ | **v0.13.0** | **Brain dashboard release.** `knit ui` opens a local-first analytics dashboard (Monetir-inspired bento, force-directed brain graph, real-time SSE sync, Host/Origin validation + CSP). Security hardening across every endpoint. Universal positioning copy across CLI + README. |
756
+ | **v0.12.0** | **Picture Perfect: Structural Enforcement.** Diagnostic → enforcing. Budget verdict surfaces in the MCP `instructions` field at handshake (before any tool description is read). `knit_load_session` carries `budget_health` + `learnings_health` nudges. `knit doctor` exits non-zero on over-budget; `knit setup` runs doctor as final step. New PostToolUse hook warns immediately on over-budget CLAUDE.md edits (HOOKS_VERSION 11→12; auto-rolls to existing users). This repo dogfoods: hand-curated 16KB CLAUDE.md migrated to lean 3.8KB plus an internal long-form sidecar. New `npm run bench:tokens` measures real MCP-on vs MCP-off cost: 93% smaller per-recall call, 50% smaller per-classify, payback at 3 recall calls. 53 tools, 705 tests. |
456
757
  | **v0.11.4** | Dogfood audit · ran a full audit of Knit's own codebase using its own `knit_spawn_team_worktree` primitive (4 parallel teams: Core Logic, Infrastructure, UI, Quality Assurance). Fixes: HIGH `engram refresh` no longer clobbers user-curated CLAUDE.md (now uses `spliceKnitBlock` like `cache.ts`); `saveSource`/`loadSource` validate `sourceId`; `appendGlobalLearning` propagates write failures; `redactSecrets` applied to `label`/`tags`/`domains` across all persistence boundaries; 100KB response ceiling on `knit_generate_test_cases`; full v0.11 tool surface now documented in `workflow-protocol.ts` generator (was frozen at the v0.4 surface). Plus: 16 key tools reclassified with `[PROTOCOL]`/`[REVIEW]`/`[MEMORY]`/`[GRAPH]` prefixes so the LLM picks the right tool reliably. 53 tools, 687 tests. |
457
758
  | **v0.11.3** | Propagation patch · `update_available` flag now surfaces in `knit_load_session` response (≈100% session reach vs. brain_status' low reach) + startup stderr nag on stale versions. Helps FUTURE upgrades land faster; doesn't retroactively reach v0.10.x users. 53 tools, 665 tests. |
458
759
  | **v0.11.2** | Pre-publish polish · chunk cap (2000) + `errorResponse` envelope across handlers + CLAUDE.md generator surfaces v0.11 tools · new `engram doctor` install health-check CLI · upgrade-path smoke test caught + fixed a data-loss bug in cache.ts (Case B was wiping user permissions on upgrade) · 11 real exploit-payload integration tests prove C1/C2/H1 fixes hold · `npm run bench` ships a synthetic retrieval harness (50 Q&A) measuring 86% top-1 / 96% R@5. 53 tools, 664 tests. |
@@ -488,17 +789,18 @@ git clone https://github.com/PDgit12/knit.git
488
789
  cd knit
489
790
  npm install
490
791
  npm run dev # run CLI locally
491
- npm run test # 492 tests
792
+ npm run test # 818 tests, ~8 s
492
793
  npm run typecheck # TypeScript strict mode
493
- npm run build # compile CLI + MCP server
794
+ npm run bench # retrieval bench: synthetic + learnings-shape
795
+ npm run build # compile CLI + MCP server + webapp
494
796
  ```
495
797
 
496
798
  ### Architecture
497
799
 
498
800
  ```
499
801
  knit (npm package)
500
- ├── dist/cli.js # CLI: setup, status, refresh
501
- └── dist/mcp/server.js # MCP server: 43 tools (tier-gated), auto-init
802
+ ├── dist/cli.js # CLI: setup, doctor, ui, status, refresh, install-agents, export
803
+ └── dist/mcp/server.js # MCP server: 55 tools (tier-gated), auto-init
502
804
 
503
805
  per-project, in ~/.knit/projects/<hash>/
504
806
  ├── knowledge.json # import graph + exports + test map
@@ -513,7 +815,7 @@ per-project, in <project>/
513
815
  └── .claude/settings.local.json # per-machine hooks, knit-managed
514
816
  ```
515
817
 
516
- **Zero external dependencies for the knowledge brain.** 492 tests. Strict-mode TypeScript.
818
+ **Zero external dependencies for the knowledge brain.** 818 tests, 0 `npm audit` vulnerabilities. Strict-mode TypeScript.
517
819
 
518
820
  ---
519
821
 
@@ -2,14 +2,15 @@ import {
2
2
  detectProjectRoot,
3
3
  getBrain,
4
4
  refreshBrain
5
- } from "./chunk-KKLAJLPO.js";
6
- import "./chunk-GATMQQK5.js";
7
- import "./chunk-WADRF26Z.js";
8
- import "./chunk-WKQHCLLO.js";
9
- import "./chunk-MOOVNMIN.js";
10
- import "./chunk-ST4X7LZT.js";
11
- import "./chunk-M3YZOJNW.js";
5
+ } from "./chunk-JE4BZQUD.js";
6
+ import "./chunk-QM4U75VE.js";
7
+ import "./chunk-V54QPQ6K.js";
8
+ import "./chunk-2FAS6CV4.js";
12
9
  import "./chunk-POXT5OYN.js";
10
+ import "./chunk-WKQHCLLO.js";
11
+ import "./chunk-FX3SVNHX.js";
12
+ import "./chunk-YRLAWCYW.js";
13
+ import "./chunk-BBQSWT4H.js";
13
14
  import "./chunk-VB2TIR6L.js";
14
15
  import "./chunk-7UFS67HP.js";
15
16
  import "./chunk-27TA2ZQZ.js";
@@ -313,7 +313,7 @@ function generateHooks(config, rootPath) {
313
313
  if (size <= TARGET) return;
314
314
  const kb = Math.round(size/1024*10)/10;
315
315
  const verdict = size > SLACK ? "over-budget" : "warn";
316
- process.stderr.write("[knit] BUDGET " + verdict + ": " + f + " is now " + kb + "KB (target 6.5KB). Move long-form content to .claude/MARKETING.md or run \\\`engram refresh\\\`.\\n");
316
+ process.stderr.write("[knit] BUDGET " + verdict + ": " + f + " is now " + kb + "KB (target 6.5KB). Trim CLAUDE.md or run \\\`knit refresh\\\` to regenerate.\\n");
317
317
  } catch (e) { try { process.stderr.write('[knit] claude-md size watch hook failed: ' + (e && e.message ? e.message : e) + '\\n'); } catch {} }
318
318
  });
319
319
  `),
@@ -1,14 +1,30 @@
1
1
  // src/engine/learnings.ts
2
- import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync } from "fs";
2
+ import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, rmdirSync, renameSync } from "fs";
3
3
  import { dirname } from "path";
4
4
  function readLearnings(filePath) {
5
5
  if (!existsSync(filePath)) return [];
6
6
  const content = readFileSync(filePath, "utf-8");
7
7
  const entries = [];
8
8
  const sections = content.split(/^## /m).slice(1);
9
+ let parseFailures = 0;
10
+ let emptyShells = 0;
9
11
  for (const section of sections) {
10
12
  const entry = parseEntry(section);
11
- if (entry) entries.push(entry);
13
+ if (!entry) {
14
+ parseFailures++;
15
+ continue;
16
+ }
17
+ if (!entry.summary.trim() || !entry.lesson.trim()) {
18
+ emptyShells++;
19
+ continue;
20
+ }
21
+ entries.push(entry);
22
+ }
23
+ if (parseFailures > 0 || emptyShells > 0) {
24
+ process.stderr.write(
25
+ `[knit] readLearnings(${filePath}): skipped ${parseFailures} unparseable, ${emptyShells} empty-shell entries
26
+ `
27
+ );
12
28
  }
13
29
  return entries;
14
30
  }
@@ -325,7 +325,7 @@ function buildSummary(allFiles, sourceFiles, importGraph, testMap, rootPath) {
325
325
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
326
326
  if (pkg.main) entryPoints.push(pkg.main);
327
327
  if (pkg.bin) {
328
- const bins = typeof pkg.bin === "string" ? [pkg.bin] : Object.values(pkg.bin);
328
+ const bins = typeof pkg.bin === "string" ? [pkg.bin] : Object.values(pkg.bin).filter((v) => typeof v === "string");
329
329
  entryPoints.push(...bins);
330
330
  }
331
331
  }