@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,11 @@
1
+ export declare const DATA_DIR: string;
2
+ export declare const DB_PATH: string;
3
+ export declare const CONFIG_PATH: string;
4
+ export type AppConfig = {
5
+ version: number;
6
+ storage: {
7
+ dbPath: string;
8
+ };
9
+ };
10
+ export declare function resolveConfig(): AppConfig;
11
+ export declare function isInitialized(): boolean;
package/dist/config.js ADDED
@@ -0,0 +1,17 @@
1
+ import os from "os";
2
+ import path from "path";
3
+ import fs from "fs";
4
+ export const DATA_DIR = path.join(os.homedir(), ".whyline");
5
+ export const DB_PATH = path.join(DATA_DIR, "memory.db");
6
+ export const CONFIG_PATH = path.join(DATA_DIR, "config.json");
7
+ export function resolveConfig() {
8
+ if (fs.existsSync(CONFIG_PATH)) {
9
+ const raw = fs.readFileSync(CONFIG_PATH, "utf-8");
10
+ return JSON.parse(raw);
11
+ }
12
+ return { version: 1, storage: { dbPath: DB_PATH } };
13
+ }
14
+ export function isInitialized() {
15
+ return fs.existsSync(DB_PATH);
16
+ }
17
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC5D,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AAS9D,MAAM,UAAU,aAAa;IAC3B,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;IACtC,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import Database from "better-sqlite3";
2
+ export declare function openDb(dbPath: string): Database.Database;
@@ -0,0 +1,8 @@
1
+ import Database from "better-sqlite3";
2
+ export function openDb(dbPath) {
3
+ const db = new Database(dbPath);
4
+ db.pragma("journal_mode = WAL");
5
+ db.pragma("foreign_keys = ON");
6
+ return db;
7
+ }
8
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type Database from "better-sqlite3";
2
+ export declare function runMigrations(db: Database.Database): void;
@@ -0,0 +1,19 @@
1
+ import { MIGRATIONS } from "./schema.js";
2
+ export function runMigrations(db) {
3
+ db.exec(`
4
+ CREATE TABLE IF NOT EXISTS migrations (
5
+ version INTEGER PRIMARY KEY,
6
+ applied_at TEXT NOT NULL
7
+ );
8
+ `);
9
+ const applied = db
10
+ .prepare("SELECT version FROM migrations ORDER BY version")
11
+ .all()
12
+ .map((r) => r.version);
13
+ const pending = MIGRATIONS.filter((m) => !applied.includes(m.version));
14
+ for (const migration of pending) {
15
+ db.exec(migration.sql);
16
+ db.prepare("INSERT INTO migrations (version, applied_at) VALUES (?, ?)").run(migration.version, new Date().toISOString());
17
+ }
18
+ }
19
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,aAAa,CAAC,EAAqB;IACjD,EAAE,CAAC,IAAI,CAAC;;;;;GAKP,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,EAAE;SACf,OAAO,CAA0B,iDAAiD,CAAC;SACnF,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAEzB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvE,KAAK,MAAM,SAAS,IAAI,OAAO,EAAE,CAAC;QAChC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACvB,EAAE,CAAC,OAAO,CAAC,4DAA4D,CAAC,CAAC,GAAG,CAC1E,SAAS,CAAC,OAAO,EACjB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CACzB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export type Migration = {
2
+ version: number;
3
+ sql: string;
4
+ };
5
+ export declare const MIGRATIONS: Migration[];
@@ -0,0 +1,64 @@
1
+ export const MIGRATIONS = [
2
+ {
3
+ version: 1,
4
+ sql: `
5
+ CREATE TABLE IF NOT EXISTS memories (
6
+ id TEXT PRIMARY KEY,
7
+ created_at TEXT NOT NULL,
8
+ updated_at TEXT NOT NULL,
9
+ repo_id TEXT NOT NULL,
10
+ repo_path TEXT,
11
+ repo_name TEXT,
12
+ branch TEXT,
13
+ commit_sha TEXT,
14
+ task TEXT,
15
+ intent TEXT NOT NULL,
16
+ summary TEXT NOT NULL,
17
+ decision TEXT NOT NULL,
18
+ why TEXT NOT NULL,
19
+ source TEXT NOT NULL,
20
+ raw_transcript_path TEXT,
21
+ embedding_text TEXT NOT NULL
22
+ );
23
+
24
+ CREATE TABLE IF NOT EXISTS memory_files (
25
+ memory_id TEXT NOT NULL,
26
+ file_path TEXT NOT NULL,
27
+ PRIMARY KEY (memory_id, file_path),
28
+ FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
29
+ );
30
+
31
+ CREATE TABLE IF NOT EXISTS memory_tags (
32
+ memory_id TEXT NOT NULL,
33
+ tag TEXT NOT NULL,
34
+ PRIMARY KEY (memory_id, tag),
35
+ FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
36
+ );
37
+
38
+ CREATE TABLE IF NOT EXISTS memory_alternatives (
39
+ memory_id TEXT NOT NULL,
40
+ value TEXT NOT NULL,
41
+ UNIQUE(memory_id, value)
42
+ );
43
+
44
+ CREATE TABLE IF NOT EXISTS memory_risks (
45
+ memory_id TEXT NOT NULL,
46
+ value TEXT NOT NULL,
47
+ UNIQUE(memory_id, value)
48
+ );
49
+
50
+ CREATE TABLE IF NOT EXISTS memory_followups (
51
+ memory_id TEXT NOT NULL,
52
+ value TEXT NOT NULL,
53
+ UNIQUE(memory_id, value)
54
+ );
55
+
56
+ CREATE INDEX IF NOT EXISTS idx_memories_repo_id ON memories(repo_id);
57
+ CREATE INDEX IF NOT EXISTS idx_memories_repo_path ON memories(repo_path);
58
+ CREATE INDEX IF NOT EXISTS idx_memories_commit_sha ON memories(commit_sha);
59
+ CREATE INDEX IF NOT EXISTS idx_memory_files_file_path ON memory_files(file_path);
60
+ CREATE INDEX IF NOT EXISTS idx_memory_tags_tag ON memory_tags(tag);
61
+ `,
62
+ },
63
+ ];
64
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,UAAU,GAAgB;IACrC;QACE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyDJ;KACF;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getChangedFilesForCommit(repoRoot: string, commitSha: string): string[];
2
+ export declare function getFileRenameHistory(repoRoot: string, filePath: string): string[];
@@ -0,0 +1,45 @@
1
+ import { execSync } from "child_process";
2
+ export function getChangedFilesForCommit(repoRoot, commitSha) {
3
+ try {
4
+ // --name-status gives type + paths; we parse renames to include both old and new paths
5
+ const output = execSync(`git diff-tree --no-commit-id -r --name-status ${commitSha}`, {
6
+ cwd: repoRoot,
7
+ encoding: "utf-8",
8
+ });
9
+ const paths = new Set();
10
+ for (const line of output.trim().split("\n").filter(Boolean)) {
11
+ const parts = line.split("\t");
12
+ const status = parts[0];
13
+ if (status.startsWith("R") || status.startsWith("C")) {
14
+ // Rename or copy: parts[1] = old path, parts[2] = new path
15
+ if (parts[1])
16
+ paths.add(parts[1]);
17
+ if (parts[2])
18
+ paths.add(parts[2]);
19
+ }
20
+ else {
21
+ // Added, modified, deleted: parts[1] = path
22
+ if (parts[1])
23
+ paths.add(parts[1]);
24
+ }
25
+ }
26
+ return [...paths];
27
+ }
28
+ catch {
29
+ return [];
30
+ }
31
+ }
32
+ export function getFileRenameHistory(repoRoot, filePath) {
33
+ try {
34
+ const output = execSync(`git log --follow --name-only --format="" -- ${filePath}`, { cwd: repoRoot, encoding: "utf-8" });
35
+ const paths = new Set([filePath]);
36
+ for (const line of output.trim().split("\n").filter(Boolean)) {
37
+ paths.add(line.trim());
38
+ }
39
+ return [...paths];
40
+ }
41
+ catch {
42
+ return [filePath];
43
+ }
44
+ }
45
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/git/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,wBAAwB,CAAC,QAAgB,EAAE,SAAiB;IAC1E,IAAI,CAAC;QACH,uFAAuF;QACvF,MAAM,MAAM,GAAG,QAAQ,CAAC,iDAAiD,SAAS,EAAE,EAAE;YACpF,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrD,2DAA2D;gBAC3D,IAAI,KAAK,CAAC,CAAC,CAAC;oBAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAClC,IAAI,KAAK,CAAC,CAAC,CAAC;oBAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,4CAA4C;gBAC5C,IAAI,KAAK,CAAC,CAAC,CAAC;oBAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,QAAgB;IACrE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CACrB,+CAA+C,QAAQ,EAAE,EACzD,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CACrC,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function getRepoRoot(cwd: string): string | null;
2
+ export declare function getCurrentBranch(repoRoot: string): string | null;
3
+ export declare function resolveCommit(repoRoot: string, ref: string): string;
@@ -0,0 +1,25 @@
1
+ import { execSync } from "child_process";
2
+ export function getRepoRoot(cwd) {
3
+ try {
4
+ return execSync("git rev-parse --show-toplevel", { cwd, encoding: "utf-8" }).trim();
5
+ }
6
+ catch {
7
+ return null;
8
+ }
9
+ }
10
+ export function getCurrentBranch(repoRoot) {
11
+ try {
12
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
13
+ cwd: repoRoot,
14
+ encoding: "utf-8",
15
+ }).trim();
16
+ return branch === "HEAD" ? null : branch;
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export function resolveCommit(repoRoot, ref) {
23
+ return execSync(`git rev-parse ${ref}`, { cwd: repoRoot, encoding: "utf-8" }).trim();
24
+ }
25
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/git/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,+BAA+B,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,iCAAiC,EAAE;YACzD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,GAAW;IACzD,OAAO,QAAQ,CAAC,iBAAiB,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACvF,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function normalizeRemoteUrl(url: string): string;
2
+ export declare function getRepoId(repoRoot: string): string;
3
+ export declare function getRepoName(repoRoot: string): string;
@@ -0,0 +1,49 @@
1
+ import { execSync } from "child_process";
2
+ import crypto from "crypto";
3
+ import path from "path";
4
+ export function normalizeRemoteUrl(url) {
5
+ return url
6
+ .trim()
7
+ .toLowerCase()
8
+ .replace(/\.git$/, "")
9
+ .replace(/^git@([^:]+):(.+)$/, "https://$1/$2");
10
+ }
11
+ export function getRepoId(repoRoot) {
12
+ try {
13
+ const remote = execSync("git config --get remote.origin.url", {
14
+ cwd: repoRoot,
15
+ encoding: "utf-8",
16
+ }).trim();
17
+ if (remote) {
18
+ return crypto
19
+ .createHash("sha256")
20
+ .update(normalizeRemoteUrl(remote))
21
+ .digest("hex")
22
+ .slice(0, 32);
23
+ }
24
+ }
25
+ catch {
26
+ // no remote — fall through
27
+ }
28
+ return crypto
29
+ .createHash("sha256")
30
+ .update(path.resolve(repoRoot))
31
+ .digest("hex")
32
+ .slice(0, 32);
33
+ }
34
+ export function getRepoName(repoRoot) {
35
+ try {
36
+ const remote = execSync("git config --get remote.origin.url", {
37
+ cwd: repoRoot,
38
+ encoding: "utf-8",
39
+ }).trim();
40
+ if (remote) {
41
+ return path.basename(normalizeRemoteUrl(remote));
42
+ }
43
+ }
44
+ catch {
45
+ // no remote
46
+ }
47
+ return path.basename(repoRoot);
48
+ }
49
+ //# sourceMappingURL=repoId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoId.js","sourceRoot":"","sources":["../../src/git/repoId.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,GAAG;SACP,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,OAAO,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,oCAAoC,EAAE;YAC5D,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM;iBACV,UAAU,CAAC,QAAQ,CAAC;iBACpB,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;iBAClC,MAAM,CAAC,KAAK,CAAC;iBACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2BAA2B;IAC7B,CAAC;IACD,OAAO,MAAM;SACV,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SAC9B,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,oCAAoC,EAAE;YAC5D,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function createMcpServer(): Promise<void>;
@@ -0,0 +1,296 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { resolveConfig } from "../config.js";
5
+ import { openDb } from "../db/connection.js";
6
+ import { searchMemory, isStale } from "../memory/searchMemory.js";
7
+ import { saveMemory, generateMemoryId, buildEmbeddingText, getMemoriesByCommit, getMemoriesByFile, listMemories, } from "../memory/saveMemory.js";
8
+ import { getRepoId } from "../git/repoId.js";
9
+ import { getFileRenameHistory } from "../git/diff.js";
10
+ import { redactSecrets } from "../memory/redactSecrets.js";
11
+ import { checkQuality, checkDuplicates } from "../memory/qualityCheck.js";
12
+ import { SearchMemoryInput, SaveMemoryInput, GetCommitMemoryInput, GetFileMemoriesInput, GetRecentMemoriesInput, } from "./tools.js";
13
+ function resolveRepoId(repoPath, repoId) {
14
+ if (repoId)
15
+ return repoId;
16
+ if (repoPath) {
17
+ try {
18
+ return getRepoId(repoPath);
19
+ }
20
+ catch {
21
+ return undefined;
22
+ }
23
+ }
24
+ return undefined;
25
+ }
26
+ export async function createMcpServer() {
27
+ const server = new Server({ name: "whyline", version: "0.1.0" }, { capabilities: { tools: {} } });
28
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
29
+ tools: [
30
+ {
31
+ name: "search_coding_memory",
32
+ description: "Search stored coding memories by keyword. Returns relevant memories with reasoning about why and tradeoffs made.",
33
+ inputSchema: {
34
+ type: "object",
35
+ properties: {
36
+ query: { type: "string", description: "Search query" },
37
+ repoPath: { type: "string", description: "Absolute path to the git repository" },
38
+ repoId: { type: "string", description: "Repository ID (hash)" },
39
+ files: {
40
+ type: "array",
41
+ items: { type: "string" },
42
+ description: "Filter by file paths",
43
+ },
44
+ tags: {
45
+ type: "array",
46
+ items: { type: "string" },
47
+ description: "Filter by tags (memory must have all listed tags)",
48
+ },
49
+ since: { type: "string", description: "ISO date — only memories created after this (e.g. 2025-01-01)" },
50
+ before: { type: "string", description: "ISO date — only memories created before this (e.g. 2025-12-31)" },
51
+ limit: { type: "number", description: "Max results (default 10)" },
52
+ },
53
+ required: ["query"],
54
+ },
55
+ },
56
+ {
57
+ name: "save_coding_memory",
58
+ description: "Save a new coding memory with reasoning, decisions, and context. Returns warnings if fields are too short, contain filler text, or a similar memory already exists — surface these warnings to the user so they can enrich the memory.",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ repoPath: { type: "string" },
63
+ commitSha: { type: "string" },
64
+ files: { type: "array", items: { type: "string" } },
65
+ task: { type: "string" },
66
+ intent: { type: "string" },
67
+ summary: { type: "string" },
68
+ decision: { type: "string" },
69
+ why: { type: "string" },
70
+ alternativesRejected: { type: "array", items: { type: "string" } },
71
+ risks: { type: "array", items: { type: "string" } },
72
+ followUps: { type: "array", items: { type: "string" } },
73
+ tags: { type: "array", items: { type: "string" } },
74
+ source: {
75
+ type: "string",
76
+ enum: ["manual", "claude-code", "cli", "hook"],
77
+ },
78
+ },
79
+ required: ["files", "intent", "summary", "decision", "why"],
80
+ },
81
+ },
82
+ {
83
+ name: "get_commit_memory",
84
+ description: "Get coding memories associated with a specific git commit.",
85
+ inputSchema: {
86
+ type: "object",
87
+ properties: {
88
+ commitSha: { type: "string" },
89
+ repoPath: { type: "string" },
90
+ repoId: { type: "string" },
91
+ },
92
+ required: ["commitSha"],
93
+ },
94
+ },
95
+ {
96
+ name: "get_file_memories",
97
+ description: "Get coding memories that touch a specific file path.",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {
101
+ filePath: { type: "string" },
102
+ repoPath: { type: "string" },
103
+ repoId: { type: "string" },
104
+ limit: { type: "number" },
105
+ },
106
+ required: ["filePath"],
107
+ },
108
+ },
109
+ {
110
+ name: "get_recent_memories",
111
+ description: "Get the most recent coding memories for a repo without requiring a search query. Use this at session start when the task is not yet defined, to surface relevant recent context.",
112
+ inputSchema: {
113
+ type: "object",
114
+ properties: {
115
+ repoPath: { type: "string", description: "Absolute path to the git repository" },
116
+ repoId: { type: "string", description: "Repository ID (hash)" },
117
+ limit: { type: "number", description: "Max results (default 5)" },
118
+ },
119
+ required: [],
120
+ },
121
+ },
122
+ ],
123
+ }));
124
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
125
+ const db = openDb(resolveConfig().storage.dbPath);
126
+ try {
127
+ switch (request.params.name) {
128
+ case "search_coding_memory": {
129
+ const input = SearchMemoryInput.parse(request.params.arguments);
130
+ const resolvedRepoId = resolveRepoId(input.repoPath, input.repoId);
131
+ const results = searchMemory(db, {
132
+ query: input.query,
133
+ repoId: resolvedRepoId,
134
+ repoPath: input.repoPath,
135
+ files: input.files,
136
+ tags: input.tags,
137
+ since: input.since,
138
+ before: input.before,
139
+ limit: input.limit,
140
+ });
141
+ return {
142
+ content: [
143
+ {
144
+ type: "text",
145
+ text: JSON.stringify({
146
+ memories: results.map((r) => ({
147
+ id: r.memory.id,
148
+ commitSha: r.memory.commitSha,
149
+ createdAt: r.memory.createdAt,
150
+ files: r.memory.files,
151
+ intent: r.memory.intent,
152
+ summary: r.memory.summary,
153
+ decision: r.memory.decision,
154
+ why: r.memory.why,
155
+ alternativesRejected: r.memory.alternativesRejected,
156
+ risks: r.memory.risks,
157
+ followUps: r.memory.followUps,
158
+ tags: r.memory.tags,
159
+ relevanceReason: r.relevanceReason,
160
+ isStale: isStale(r.memory),
161
+ })),
162
+ }),
163
+ },
164
+ ],
165
+ };
166
+ }
167
+ case "save_coding_memory": {
168
+ const input = SaveMemoryInput.parse(request.params.arguments);
169
+ const resolvedRepoId = resolveRepoId(input.repoPath, undefined);
170
+ const now = new Date().toISOString();
171
+ const id = generateMemoryId();
172
+ const memory = {
173
+ id,
174
+ createdAt: now,
175
+ updatedAt: now,
176
+ repoId: resolvedRepoId ?? "unknown",
177
+ repoPath: input.repoPath,
178
+ commitSha: input.commitSha,
179
+ files: input.files,
180
+ tags: input.tags.map(redactSecrets),
181
+ task: input.task ? redactSecrets(input.task) : undefined,
182
+ intent: redactSecrets(input.intent),
183
+ summary: redactSecrets(input.summary),
184
+ decision: redactSecrets(input.decision),
185
+ why: redactSecrets(input.why),
186
+ alternativesRejected: input.alternativesRejected.map(redactSecrets),
187
+ risks: input.risks.map(redactSecrets),
188
+ followUps: input.followUps.map(redactSecrets),
189
+ source: input.source,
190
+ embeddingText: "",
191
+ };
192
+ memory.embeddingText = buildEmbeddingText(memory);
193
+ const qualityWarnings = checkQuality(memory);
194
+ const duplicateWarnings = checkDuplicates(db, memory);
195
+ saveMemory(db, memory);
196
+ return {
197
+ content: [{
198
+ type: "text",
199
+ text: JSON.stringify({
200
+ id,
201
+ saved: true,
202
+ warnings: [
203
+ ...qualityWarnings.map((w) => w.message),
204
+ ...duplicateWarnings.map((w) => w.message),
205
+ ],
206
+ }),
207
+ }],
208
+ };
209
+ }
210
+ case "get_commit_memory": {
211
+ const input = GetCommitMemoryInput.parse(request.params.arguments);
212
+ const memories = getMemoriesByCommit(db, input.commitSha);
213
+ return {
214
+ content: [
215
+ {
216
+ type: "text",
217
+ text: JSON.stringify({
218
+ memories: memories.map((m) => ({
219
+ id: m.id,
220
+ intent: m.intent,
221
+ decision: m.decision,
222
+ why: m.why,
223
+ files: m.files,
224
+ risks: m.risks,
225
+ followUps: m.followUps,
226
+ })),
227
+ }),
228
+ },
229
+ ],
230
+ };
231
+ }
232
+ case "get_file_memories": {
233
+ const input = GetFileMemoriesInput.parse(request.params.arguments);
234
+ const resolvedRepoId = resolveRepoId(input.repoPath, input.repoId) ?? null;
235
+ const filePaths = input.repoPath
236
+ ? getFileRenameHistory(input.repoPath, input.filePath)
237
+ : [input.filePath];
238
+ const memories = getMemoriesByFile(db, resolvedRepoId, filePaths, input.limit);
239
+ return {
240
+ content: [
241
+ {
242
+ type: "text",
243
+ text: JSON.stringify({
244
+ memories: memories.map((m) => ({
245
+ id: m.id,
246
+ commitSha: m.commitSha,
247
+ intent: m.intent,
248
+ decision: m.decision,
249
+ why: m.why,
250
+ risks: m.risks,
251
+ followUps: m.followUps,
252
+ })),
253
+ }),
254
+ },
255
+ ],
256
+ };
257
+ }
258
+ case "get_recent_memories": {
259
+ const input = GetRecentMemoriesInput.parse(request.params.arguments);
260
+ const resolvedRepoId = resolveRepoId(input.repoPath, input.repoId);
261
+ const memories = listMemories(db, { repoId: resolvedRepoId, limit: input.limit });
262
+ return {
263
+ content: [
264
+ {
265
+ type: "text",
266
+ text: JSON.stringify({
267
+ memories: memories.map((m) => ({
268
+ id: m.id,
269
+ commitSha: m.commitSha,
270
+ createdAt: m.createdAt,
271
+ files: m.files,
272
+ intent: m.intent,
273
+ decision: m.decision,
274
+ why: m.why,
275
+ risks: m.risks,
276
+ followUps: m.followUps,
277
+ tags: m.tags,
278
+ isStale: isStale(m),
279
+ })),
280
+ }),
281
+ },
282
+ ],
283
+ };
284
+ }
285
+ default:
286
+ throw new Error(`Unknown tool: ${request.params.name}`);
287
+ }
288
+ }
289
+ finally {
290
+ db.close();
291
+ }
292
+ });
293
+ const transport = new StdioServerTransport();
294
+ await server.connect(transport);
295
+ }
296
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}