@malindar/whyline 0.1.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 (164) hide show
  1. package/.claude/settings.local.json +33 -0
  2. package/.github/workflows/ci.yml +35 -0
  3. package/.github/workflows/publish.yml +37 -0
  4. package/.prettierrc.json +7 -0
  5. package/CLAUDE.md +74 -0
  6. package/LICENSE +21 -0
  7. package/README.md +359 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +125 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/delete.d.ts +3 -0
  12. package/dist/commands/delete.js +42 -0
  13. package/dist/commands/delete.js.map +1 -0
  14. package/dist/commands/doctor.d.ts +1 -0
  15. package/dist/commands/doctor.js +111 -0
  16. package/dist/commands/doctor.js.map +1 -0
  17. package/dist/commands/edit.d.ts +1 -0
  18. package/dist/commands/edit.js +78 -0
  19. package/dist/commands/edit.js.map +1 -0
  20. package/dist/commands/export.d.ts +8 -0
  21. package/dist/commands/export.js +90 -0
  22. package/dist/commands/export.js.map +1 -0
  23. package/dist/commands/import.d.ts +1 -0
  24. package/dist/commands/import.js +110 -0
  25. package/dist/commands/import.js.map +1 -0
  26. package/dist/commands/init.d.ts +5 -0
  27. package/dist/commands/init.js +23 -0
  28. package/dist/commands/init.js.map +1 -0
  29. package/dist/commands/install-claude.d.ts +3 -0
  30. package/dist/commands/install-claude.js +180 -0
  31. package/dist/commands/install-claude.js.map +1 -0
  32. package/dist/commands/list.d.ts +4 -0
  33. package/dist/commands/list.js +35 -0
  34. package/dist/commands/list.js.map +1 -0
  35. package/dist/commands/mcp.d.ts +1 -0
  36. package/dist/commands/mcp.js +10 -0
  37. package/dist/commands/mcp.js.map +1 -0
  38. package/dist/commands/save.d.ts +4 -0
  39. package/dist/commands/save.js +74 -0
  40. package/dist/commands/save.js.map +1 -0
  41. package/dist/commands/search.d.ts +7 -0
  42. package/dist/commands/search.js +46 -0
  43. package/dist/commands/search.js.map +1 -0
  44. package/dist/commands/show.d.ts +3 -0
  45. package/dist/commands/show.js +30 -0
  46. package/dist/commands/show.js.map +1 -0
  47. package/dist/commands/stats.d.ts +1 -0
  48. package/dist/commands/stats.js +27 -0
  49. package/dist/commands/stats.js.map +1 -0
  50. package/dist/commands/summarize.d.ts +3 -0
  51. package/dist/commands/summarize.js +140 -0
  52. package/dist/commands/summarize.js.map +1 -0
  53. package/dist/config.d.ts +11 -0
  54. package/dist/config.js +17 -0
  55. package/dist/config.js.map +1 -0
  56. package/dist/db/connection.d.ts +2 -0
  57. package/dist/db/connection.js +8 -0
  58. package/dist/db/connection.js.map +1 -0
  59. package/dist/db/migrations.d.ts +2 -0
  60. package/dist/db/migrations.js +19 -0
  61. package/dist/db/migrations.js.map +1 -0
  62. package/dist/db/schema.d.ts +5 -0
  63. package/dist/db/schema.js +64 -0
  64. package/dist/db/schema.js.map +1 -0
  65. package/dist/git/diff.d.ts +2 -0
  66. package/dist/git/diff.js +45 -0
  67. package/dist/git/diff.js.map +1 -0
  68. package/dist/git/git.d.ts +3 -0
  69. package/dist/git/git.js +25 -0
  70. package/dist/git/git.js.map +1 -0
  71. package/dist/git/repoId.d.ts +3 -0
  72. package/dist/git/repoId.js +49 -0
  73. package/dist/git/repoId.js.map +1 -0
  74. package/dist/mcp/server.d.ts +1 -0
  75. package/dist/mcp/server.js +296 -0
  76. package/dist/mcp/server.js.map +1 -0
  77. package/dist/mcp/tools.d.ts +119 -0
  78. package/dist/mcp/tools.js +43 -0
  79. package/dist/mcp/tools.js.map +1 -0
  80. package/dist/memory/parseSummary.d.ts +14 -0
  81. package/dist/memory/parseSummary.js +53 -0
  82. package/dist/memory/parseSummary.js.map +1 -0
  83. package/dist/memory/qualityCheck.d.ts +13 -0
  84. package/dist/memory/qualityCheck.js +78 -0
  85. package/dist/memory/qualityCheck.js.map +1 -0
  86. package/dist/memory/redactSecrets.d.ts +7 -0
  87. package/dist/memory/redactSecrets.js +29 -0
  88. package/dist/memory/redactSecrets.js.map +1 -0
  89. package/dist/memory/repoContext.d.ts +2 -0
  90. package/dist/memory/repoContext.js +23 -0
  91. package/dist/memory/repoContext.js.map +1 -0
  92. package/dist/memory/saveMemory.d.ts +40 -0
  93. package/dist/memory/saveMemory.js +223 -0
  94. package/dist/memory/saveMemory.js.map +1 -0
  95. package/dist/memory/searchMemory.d.ts +17 -0
  96. package/dist/memory/searchMemory.js +122 -0
  97. package/dist/memory/searchMemory.js.map +1 -0
  98. package/dist/memory/types.d.ts +48 -0
  99. package/dist/memory/types.js +2 -0
  100. package/dist/memory/types.js.map +1 -0
  101. package/dist/output/format.d.ts +3 -0
  102. package/dist/output/format.js +43 -0
  103. package/dist/output/format.js.map +1 -0
  104. package/docs/architecture.md +387 -0
  105. package/docs/ec6ab3bf-60cf-4629-ad9e-3048e8e3c43a.png +0 -0
  106. package/docs/logo.png +0 -0
  107. package/eslint.config.js +16 -0
  108. package/how-to-run/01-install.md +69 -0
  109. package/how-to-run/02-wire-up-your-repo.md +80 -0
  110. package/how-to-run/03-test-it-manually.md +91 -0
  111. package/how-to-run/04-test-with-claude-code.md +70 -0
  112. package/how-to-run/CLAUDE.md.template +72 -0
  113. package/how-to-run/README.md +49 -0
  114. package/package.json +60 -0
  115. package/src/cli.ts +142 -0
  116. package/src/commands/delete.ts +47 -0
  117. package/src/commands/doctor.ts +128 -0
  118. package/src/commands/edit.ts +80 -0
  119. package/src/commands/export.ts +95 -0
  120. package/src/commands/import.ts +119 -0
  121. package/src/commands/init.ts +31 -0
  122. package/src/commands/install-claude.ts +203 -0
  123. package/src/commands/list.ts +41 -0
  124. package/src/commands/mcp.ts +12 -0
  125. package/src/commands/save.ts +85 -0
  126. package/src/commands/search.ts +56 -0
  127. package/src/commands/show.ts +37 -0
  128. package/src/commands/stats.ts +31 -0
  129. package/src/commands/summarize.ts +183 -0
  130. package/src/config.ts +26 -0
  131. package/src/db/connection.ts +8 -0
  132. package/src/db/migrations.ts +26 -0
  133. package/src/db/schema.ts +68 -0
  134. package/src/git/diff.ts +43 -0
  135. package/src/git/git.ts +25 -0
  136. package/src/git/repoId.ts +49 -0
  137. package/src/hooks/post-commit.sample.sh +9 -0
  138. package/src/mcp/server.ts +326 -0
  139. package/src/mcp/tools.ts +53 -0
  140. package/src/memory/parseSummary.ts +72 -0
  141. package/src/memory/qualityCheck.ts +102 -0
  142. package/src/memory/redactSecrets.ts +32 -0
  143. package/src/memory/repoContext.ts +25 -0
  144. package/src/memory/saveMemory.ts +369 -0
  145. package/src/memory/searchMemory.ts +153 -0
  146. package/src/memory/types.ts +57 -0
  147. package/src/output/format.ts +44 -0
  148. package/src/skill/SKILL.md +95 -0
  149. package/tests/cliV02.test.ts +213 -0
  150. package/tests/doctor.test.ts +253 -0
  151. package/tests/exportImport.test.ts +248 -0
  152. package/tests/fileRename.test.ts +156 -0
  153. package/tests/gitHelpers.test.ts +94 -0
  154. package/tests/init.test.ts +93 -0
  155. package/tests/installClaude.test.ts +157 -0
  156. package/tests/parseSummary.test.ts +111 -0
  157. package/tests/qualityCheck.test.ts +182 -0
  158. package/tests/redactSecrets.test.ts +75 -0
  159. package/tests/saveMemory.test.ts +196 -0
  160. package/tests/searchFilters.test.ts +139 -0
  161. package/tests/searchMemory.test.ts +273 -0
  162. package/tests/stale.test.ts +47 -0
  163. package/tsconfig.json +18 -0
  164. package/vitest.config.ts +8 -0
@@ -0,0 +1,387 @@
1
+ # Whyline — Architecture
2
+
3
+ ## What it does
4
+
5
+ Whyline captures the reasoning behind code changes and makes it available to future AI coding sessions.
6
+
7
+ Git stores diffs. Whyline stores the *why* — the intent, the decision, the alternatives that were rejected, the risks that were acknowledged. It does this by sitting at two points in the development loop:
8
+
9
+ - **Session start** — searches past memories and surfaces relevant context to Claude before any code is touched
10
+ - **After commit** — synthesizes the conversation into a structured record and saves it to a local SQLite database
11
+
12
+ No cloud. No background daemon. No extra UI. Just a CLI and an MCP server.
13
+
14
+ ---
15
+
16
+ ## The development loop
17
+
18
+ ```mermaid
19
+ sequenceDiagram
20
+ participant Dev as Developer
21
+ participant CC as Claude Code
22
+ participant MCP as Whyline MCP Server
23
+ participant DB as SQLite (~/.whyline/memory.db)
24
+ participant Git as Git
25
+
26
+ Dev->>CC: "Add retention policy for audit logs"
27
+ CC->>MCP: search_coding_memory(query, repoPath, files)
28
+ MCP->>DB: query memories by keyword + repo
29
+ DB-->>MCP: ranked results with relevanceReason + isStale flag
30
+ MCP-->>CC: past decisions surfaced
31
+ CC-->>Dev: "Last time we touched this, we chose X because Y. Still the case?"
32
+
33
+ Dev->>CC: work on task...
34
+ CC->>Git: git commit
35
+
36
+ Git-->>CC: commit SHA
37
+ CC-->>Dev: "Here's what I'm saving — let me know if you want to add anything"
38
+ Dev->>CC: (optional corrections)
39
+ CC->>MCP: save_coding_memory(intent, decision, why, files, commitSha, ...)
40
+ MCP->>DB: INSERT memory + junction tables
41
+ DB-->>MCP: saved
42
+ MCP-->>CC: { id, saved: true, warnings[] }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## System components
48
+
49
+ ```mermaid
50
+ graph TB
51
+ subgraph CLI["CLI (whyline)"]
52
+ init[init]
53
+ save[save]
54
+ search[search]
55
+ show[show]
56
+ list[list]
57
+ delete[delete]
58
+ stats[stats]
59
+ edit[edit]
60
+ export[export]
61
+ import[import]
62
+ summarize[summarize]
63
+ doctor[doctor]
64
+ install[install-claude]
65
+ mcp_cmd[mcp]
66
+ end
67
+
68
+ subgraph MCP["MCP Server (stdio)"]
69
+ search_tool[search_coding_memory]
70
+ save_tool[save_coding_memory]
71
+ commit_tool[get_commit_memory]
72
+ file_tool[get_file_memories]
73
+ recent_tool[get_recent_memories]
74
+ end
75
+
76
+ subgraph Memory["Memory Layer"]
77
+ parseSummary[parseSummary\nmarkdown → structured]
78
+ redact[redactSecrets\nscans all text fields]
79
+ saveMemory[saveMemory\ndb.transaction]
80
+ searchMemory[searchMemory\nkeyword scoring + isStale]
81
+ qualityCheck[qualityCheck\nwarnings on save]
82
+ summarizeCmd[Claude API\nfield improvement]
83
+ end
84
+
85
+ subgraph Git["Git Helpers"]
86
+ repoId[repoId\nremote URL → hash]
87
+ repoContext[repoContext\ncwd → RepoContext]
88
+ diff[diff\ngit diff-tree]
89
+ end
90
+
91
+ subgraph DB["SQLite (~/.whyline/)"]
92
+ memories[(memories)]
93
+ files[(memory_files)]
94
+ tags[(memory_tags)]
95
+ alts[(memory_alternatives)]
96
+ risks_t[(memory_risks)]
97
+ followups[(memory_followups)]
98
+ end
99
+
100
+ save --> parseSummary
101
+ save --> redact
102
+ save --> repoContext
103
+ save --> saveMemory
104
+
105
+ search --> searchMemory
106
+ show --> saveMemory
107
+ summarize --> summarizeCmd
108
+ summarize --> saveMemory
109
+
110
+ save_tool --> redact
111
+ save_tool --> saveMemory
112
+ save_tool --> qualityCheck
113
+ search_tool --> searchMemory
114
+ commit_tool --> saveMemory
115
+ file_tool --> saveMemory
116
+ recent_tool --> saveMemory
117
+
118
+ saveMemory --> memories
119
+ saveMemory --> files
120
+ saveMemory --> tags
121
+ saveMemory --> alts
122
+ saveMemory --> risks_t
123
+ saveMemory --> followups
124
+
125
+ repoContext --> repoId
126
+ repoContext --> diff
127
+
128
+ mcp_cmd --> MCP
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Data model
134
+
135
+ A single **memory** record captures one coding session. All list fields are stored in separate junction tables and joined at read time.
136
+
137
+ ```mermaid
138
+ erDiagram
139
+ memories {
140
+ TEXT id PK
141
+ TEXT repo_id
142
+ TEXT repo_path
143
+ TEXT repo_name
144
+ TEXT branch
145
+ TEXT commit_sha
146
+ TEXT task
147
+ TEXT intent
148
+ TEXT summary
149
+ TEXT decision
150
+ TEXT why
151
+ TEXT source
152
+ TEXT embedding_text
153
+ TEXT created_at
154
+ TEXT updated_at
155
+ }
156
+
157
+ memory_files {
158
+ TEXT memory_id FK
159
+ TEXT file_path
160
+ }
161
+
162
+ memory_tags {
163
+ TEXT memory_id FK
164
+ TEXT tag
165
+ }
166
+
167
+ memory_alternatives {
168
+ TEXT memory_id FK
169
+ TEXT value
170
+ }
171
+
172
+ memory_risks {
173
+ TEXT memory_id FK
174
+ TEXT value
175
+ }
176
+
177
+ memory_followups {
178
+ TEXT memory_id FK
179
+ TEXT value
180
+ }
181
+
182
+ memories ||--o{ memory_files : "files touched"
183
+ memories ||--o{ memory_tags : "tags"
184
+ memories ||--o{ memory_alternatives : "alternatives rejected"
185
+ memories ||--o{ memory_risks : "known risks"
186
+ memories ||--o{ memory_followups : "follow-up tasks"
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Save pipeline
192
+
193
+ When a memory is saved (via CLI or MCP), every text field passes through the same pipeline before touching the database.
194
+
195
+ ```mermaid
196
+ flowchart LR
197
+ A[Raw input\nmarkdown or MCP fields] --> B[parseSummary\nextract structured fields]
198
+ B --> C[redactSecrets\nreplace tokens / keys / PEM blocks]
199
+ C --> D[buildEmbeddingText\nconcatenate all fields]
200
+ D --> E[qualityCheck\nwarn if fields too short or filler]
201
+ E --> F[saveMemory\ndb.transaction INSERT]
202
+ F --> G[(SQLite)]
203
+ ```
204
+
205
+ **Secret patterns redacted:**
206
+ - GitHub tokens (`ghp_`, `gho_`, `ghs_`)
207
+ - npm tokens (`npm_`)
208
+ - AWS access keys (`AKIA...`)
209
+ - Bearer tokens
210
+ - `.env`-style assignments (`API_KEY=value`)
211
+ - PEM private key blocks
212
+
213
+ ---
214
+
215
+ ## Search pipeline
216
+
217
+ Search is deterministic keyword scoring — no embeddings, no external service. Results include an `isStale` flag for memories older than 90 days.
218
+
219
+ ```mermaid
220
+ flowchart TD
221
+ A[query + repoPath + files] --> B[resolve repo_id from repoPath]
222
+ B --> C{repo_id results?}
223
+ C -- yes --> D[fetch memories by repo_id]
224
+ C -- no --> E[fallback: fetch by repo_path LIKE]
225
+ D --> F[apply date + tag filters]
226
+ E --> F
227
+ F --> G[scoreMemory for each result]
228
+ G --> H{query provided?}
229
+ H -- yes --> I{contentScore > 0?}
230
+ I -- yes --> J[keep result]
231
+ I -- no --> K[discard — same-repo bonus alone not enough]
232
+ H -- no --> J
233
+ J --> L[sort by total score desc]
234
+ L --> M[limit results]
235
+ M --> N[explainRelevance → relevanceReason]
236
+ N --> O[isStale: age > 90 days]
237
+ ```
238
+
239
+ **Score weights:**
240
+
241
+ | Component | Points |
242
+ |-----------|--------|
243
+ | Same repo | +10 |
244
+ | File overlap | +8 |
245
+ | Tag match | +5 |
246
+ | Decision match | +4 |
247
+ | Why match | +3 |
248
+ | Summary match | +2 |
249
+ | File path match | +2 |
250
+ | Recency (≤30 days) | +1 |
251
+
252
+ The `relevanceReason` field describes which components fired, e.g. `"Matched: same repo (+10), tag match (+5)"`. The `isStale` flag is set for memories older than 90 days — Claude surfaces a verification prompt when it's true.
253
+
254
+ ---
255
+
256
+ ## Summarize pipeline
257
+
258
+ `whyline summarize <id>` improves a saved memory's text quality using the Claude API.
259
+
260
+ ```mermaid
261
+ flowchart LR
262
+ A[memory ID] --> B[load from SQLite]
263
+ B --> C[build prompt\nwith all 8 text fields]
264
+ C --> D[call claude-haiku\nvia HTTPS]
265
+ D --> E[parse JSON response]
266
+ E --> F[show before/after diff\nof changed fields only]
267
+ F --> G{user confirms\nor --force?}
268
+ G -- yes --> H[updateMemory\nrebuild embeddingText]
269
+ G -- no --> I[cancelled]
270
+ H --> J[(SQLite)]
271
+ ```
272
+
273
+ Requires `ANTHROPIC_API_KEY` in the environment. Uses `claude-haiku-4-5-20251001` — no new npm dependency (uses Node's built-in `https` module).
274
+
275
+ ---
276
+
277
+ ## Repo identity
278
+
279
+ Whyline needs a stable identifier for each repo so memories can be scoped and searched correctly even if the repo is cloned to a different local path.
280
+
281
+ ```mermaid
282
+ flowchart TD
283
+ A[getRepoId] --> B{remote URL available?}
284
+ B -- yes --> C[normalise URL\nstrip .git, git@ → https://]
285
+ C --> D[sha256 → truncate to 32 chars]
286
+ B -- no --> E[hash of absolute repo path]
287
+ D --> F[repo_id stored in DB]
288
+ E --> F
289
+ F --> G[also store repo_path for fallback search]
290
+ ```
291
+
292
+ This means memories survive repo renames and remain queryable by path if the remote changes.
293
+
294
+ ---
295
+
296
+ ## MCP integration
297
+
298
+ The MCP server runs as a stdio process, launched by Claude Code when a session starts in a repo that has `.mcp.json`.
299
+
300
+ ```mermaid
301
+ sequenceDiagram
302
+ participant CC as Claude Code
303
+ participant Server as Whyline MCP (stdio)
304
+ participant DB as SQLite
305
+
306
+ CC->>Server: spawn process (node dist/cli.js mcp)
307
+ CC->>Server: ListTools request
308
+ Server-->>CC: 5 tool descriptors
309
+
310
+ CC->>Server: CallTool: search_coding_memory
311
+ Server->>DB: openDb → searchMemory → db.close
312
+ Server-->>CC: JSON results with relevanceReason + isStale
313
+
314
+ CC->>Server: CallTool: save_coding_memory
315
+ Server->>DB: openDb → redactSecrets → qualityCheck → saveMemory → db.close
316
+ Server-->>CC: { id, saved: true, warnings[] }
317
+ ```
318
+
319
+ The DB connection is opened and closed per request — no persistent connection. All stdout is reserved for JSON-RPC; logs go to stderr only.
320
+
321
+ ---
322
+
323
+ ## Directory structure
324
+
325
+ ```
326
+ src/
327
+ cli.ts entry point, commander, shebang
328
+ config.ts DATA_DIR, DB_PATH, resolveConfig(), isInitialized()
329
+ commands/
330
+ init.ts create ~/.whyline/, run migrations
331
+ save.ts parse markdown → redact → save
332
+ search.ts resolve repo, score, print results
333
+ show.ts fetch by id or commit SHA
334
+ list.ts list memories, --repo, --limit
335
+ delete.ts delete by ID with confirmation
336
+ stats.ts total memories, repos, top files
337
+ edit.ts open memory in $EDITOR
338
+ export.ts dump as JSON (schemaVersion envelope) or markdown
339
+ import.ts ingest JSON export, deduplicate, redact
340
+ summarize.ts improve memory fields via Claude API
341
+ doctor.ts 7-check setup diagnostic, exits 1 on failure
342
+ install-claude.ts create/update .mcp.json, CLAUDE.md, settings.local.json
343
+ mcp.ts start MCP stdio server
344
+ db/
345
+ connection.ts openDb() — WAL + foreign_keys
346
+ schema.ts MIGRATIONS[] — versioned SQL
347
+ migrations.ts runMigrations() — idempotent
348
+ git/
349
+ git.ts getRepoRoot, getCurrentBranch, resolveCommit
350
+ repoId.ts getRepoId(), getRepoName(), normalizeRemoteUrl()
351
+ diff.ts getChangedFilesForCommit(), getFileRenameHistory()
352
+ repoContext.ts getRepoContext() → RepoContext
353
+ memory/
354
+ types.ts CodingMemory, ScoreBreakdown, SearchResult, RepoContext
355
+ parseSummary.ts markdown → structured fields (9 headings)
356
+ redactSecrets.ts SECRET_PATTERNS[], redactSecrets()
357
+ saveMemory.ts saveMemory(), updateMemory(), getMemoryById(), listMemories(), …
358
+ searchMemory.ts scoreMemory(), explainRelevance(), searchMemory(), isStale()
359
+ qualityCheck.ts checkQuality(), checkDuplicates() → warnings[]
360
+ repoContext.ts assembles RepoContext from cwd + ref
361
+ mcp/
362
+ server.ts createMcpServer() — 5 tools, stdio transport
363
+ tools.ts Zod schemas for all tool inputs
364
+ output/
365
+ format.ts formatMemory() with [STALE] note, formatSearchResult()
366
+ skill/
367
+ SKILL.md Claude Code skill instructions (keep in sync with CLAUDE.md.template)
368
+ hooks/
369
+ post-commit.sample.sh reminder hook template
370
+
371
+ how-to-run/
372
+ CLAUDE.md.template injected into user repos by install-claude (keep in sync with SKILL.md)
373
+ 01-install.md
374
+ 02-wire-up-your-repo.md
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Keeping instruction files in sync
380
+
381
+ Three files describe how Claude should behave. They must always be consistent — see `CLAUDE.md` for the full sync rule.
382
+
383
+ | File | Purpose |
384
+ |------|---------|
385
+ | `src/skill/SKILL.md` | Used when Whyline is loaded as a Claude Code skill |
386
+ | `how-to-run/CLAUDE.md.template` | Injected into user repos by `whyline install-claude` |
387
+ | Deployed `CLAUDE.md` files | Already-wired repos — patch manually after changes |
package/docs/logo.png ADDED
Binary file
@@ -0,0 +1,16 @@
1
+ import eslint from "@eslint/js";
2
+ import tseslint from "typescript-eslint";
3
+
4
+ export default tseslint.config(
5
+ eslint.configs.recommended,
6
+ ...tseslint.configs.recommended,
7
+ {
8
+ rules: {
9
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
10
+ "@typescript-eslint/no-explicit-any": "warn",
11
+ },
12
+ },
13
+ {
14
+ ignores: ["dist/**", "node_modules/**"],
15
+ }
16
+ );
@@ -0,0 +1,69 @@
1
+ # Step 1 — Install Whyline
2
+
3
+ ## Prerequisites
4
+
5
+ - Node.js 18 or later (Node 22 recommended)
6
+ - npm
7
+ - git
8
+
9
+ Check your versions:
10
+
11
+ ```bash
12
+ node --version # should be v18+
13
+ npm --version
14
+ git --version
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Clone and build
20
+
21
+ ```bash
22
+ git clone <whyline-repo-url>
23
+ cd whyline
24
+ npm install
25
+ npm run build
26
+ ```
27
+
28
+ ## Rebuild native bindings (required on Node 20+)
29
+
30
+ `better-sqlite3` uses native C++ bindings. You must compile them for your Node version:
31
+
32
+ ```bash
33
+ npm rebuild better-sqlite3
34
+ ```
35
+
36
+ If `npm rebuild` fails or produces no `.node` file (common on Node 22), run manually:
37
+
38
+ ```bash
39
+ npx node-gyp rebuild
40
+ mkdir -p node_modules/better-sqlite3/build/Release
41
+ cp build/Release/better_sqlite3.node node_modules/better-sqlite3/build/Release/
42
+ ```
43
+
44
+ ## Make the CLI available globally
45
+
46
+ ```bash
47
+ npm link
48
+ ```
49
+
50
+ Verify:
51
+
52
+ ```bash
53
+ which whyline # should print a path
54
+ whyline --version # should print 0.1.0
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Initialize storage
60
+
61
+ ```bash
62
+ whyline init
63
+ ```
64
+
65
+ This creates `~/.whyline/` with:
66
+ - `memory.db` — SQLite database
67
+ - `config.json` — storage config
68
+
69
+ You only need to do this once per machine. Running it again is safe (idempotent).
@@ -0,0 +1,80 @@
1
+ # Step 2 — Wire Up Your Repo
2
+
3
+ Run this once in each repo you want Whyline to work in:
4
+
5
+ ```bash
6
+ cd your-project
7
+ whyline install-claude
8
+ ```
9
+
10
+ That's it. The command creates or updates three files:
11
+
12
+ | File | What it does |
13
+ |------|-------------|
14
+ | `.mcp.json` | Registers the `whyline` MCP server with Claude Code |
15
+ | `CLAUDE.md` | Adds the memory instructions so Claude searches and saves automatically |
16
+ | `.claude/settings.local.json` | Auto-approves the five MCP tool calls so Claude doesn't prompt on every use |
17
+
18
+ Running it again is safe — it merges, never overwrites unrelated content.
19
+
20
+ ---
21
+
22
+ ## What the files look like
23
+
24
+ ### `.mcp.json`
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "whyline": {
30
+ "command": "whyline",
31
+ "args": ["mcp"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ > **If `whyline` is not on your PATH** (e.g. you didn't run `npm link`), edit this to use the absolute path:
38
+ > ```json
39
+ > {
40
+ > "mcpServers": {
41
+ > "whyline": {
42
+ > "command": "node",
43
+ > "args": ["/absolute/path/to/whyline/dist/cli.js", "mcp"]
44
+ > }
45
+ > }
46
+ > }
47
+ > ```
48
+
49
+ ### `.claude/settings.local.json`
50
+
51
+ ```json
52
+ {
53
+ "permissions": {
54
+ "allow": [
55
+ "mcp__whyline__save_coding_memory",
56
+ "mcp__whyline__search_coding_memory",
57
+ "mcp__whyline__get_recent_memories",
58
+ "mcp__whyline__get_file_memories",
59
+ "mcp__whyline__get_commit_memory"
60
+ ]
61
+ },
62
+ "enabledMcpjsonServers": ["whyline"]
63
+ }
64
+ ```
65
+
66
+ > `settings.local.json` is machine-specific. Add it to your `.gitignore` if you don't want it committed.
67
+
68
+ ### `CLAUDE.md`
69
+
70
+ The Whyline section is appended to any existing `CLAUDE.md`, or a new file is created if none exists. See `CLAUDE.md.template` in this folder for the full content.
71
+
72
+ ---
73
+
74
+ ## Verify the setup
75
+
76
+ ```bash
77
+ whyline doctor
78
+ ```
79
+
80
+ All seven checks should pass before you start a session.
@@ -0,0 +1,91 @@
1
+ # Step 3 — Test It Manually (CLI)
2
+
3
+ Before testing with Claude Code, verify the CLI works end-to-end.
4
+
5
+ ---
6
+
7
+ ## Save a test memory
8
+
9
+ Create a test summary file:
10
+
11
+ ```bash
12
+ cat > /tmp/test-memory.md << 'EOF'
13
+ Intent:
14
+ Test that Whyline is working correctly.
15
+
16
+ Summary:
17
+ Ran a manual test save to verify the CLI and database are working.
18
+
19
+ Decision:
20
+ Use a hardcoded test file rather than a real commit summary.
21
+
22
+ Why:
23
+ Fastest way to verify the install without needing a real coding session.
24
+
25
+ Alternatives rejected:
26
+ - Skipping the manual test entirely.
27
+
28
+ Risks:
29
+ - None for this test.
30
+
31
+ Follow-ups:
32
+ - Delete this test memory after verifying.
33
+
34
+ Tags:
35
+ - test
36
+ - install-check
37
+ EOF
38
+ ```
39
+
40
+ Save it (run from inside any git repo, or use `--commit` with any valid SHA):
41
+
42
+ ```bash
43
+ cd /path/to/any-git-repo
44
+ whyline save --commit HEAD --summary-file /tmp/test-memory.md
45
+ ```
46
+
47
+ Expected output:
48
+ ```
49
+ Saved memory mem_xxxxx
50
+ Repo: your-repo-name
51
+ Commit: abc12345
52
+ Files: 0
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Search for it
58
+
59
+ ```bash
60
+ whyline search "install check"
61
+ ```
62
+
63
+ Expected: one result with `[Matched: ...]` relevance reason.
64
+
65
+ ---
66
+
67
+ ## Show it
68
+
69
+ ```bash
70
+ whyline show mem_xxxxx # use the ID printed above
71
+ ```
72
+
73
+ Expected: full verbose output with all fields.
74
+
75
+ ---
76
+
77
+ ## Show by commit
78
+
79
+ ```bash
80
+ whyline show --commit HEAD
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Clean up
86
+
87
+ ```bash
88
+ # The test memory lives in ~/.whyline/memory.db
89
+ # There's no delete command in v0.1 — you can ignore it or wipe the DB:
90
+ rm ~/.whyline/memory.db && whyline init
91
+ ```