@ariso-ai/ivan 1.0.24 → 1.0.26

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 (189) hide show
  1. package/.github/workflows/ivanagent.yml +1 -1
  2. package/README.md +29 -0
  3. package/dist/database/migration.d.ts +3 -2
  4. package/dist/database/migration.d.ts.map +1 -1
  5. package/dist/database/migration.js +4 -2
  6. package/dist/database/migration.js.map +1 -1
  7. package/dist/database/migrations/015_create_learnings_tables.d.ts +3 -0
  8. package/dist/database/migrations/015_create_learnings_tables.d.ts.map +1 -0
  9. package/dist/database/migrations/015_create_learnings_tables.js +32 -0
  10. package/dist/database/migrations/015_create_learnings_tables.js.map +1 -0
  11. package/dist/database/migrations/016_create_reviews_table.d.ts +3 -0
  12. package/dist/database/migrations/016_create_reviews_table.d.ts.map +1 -0
  13. package/dist/database/migrations/016_create_reviews_table.js +19 -0
  14. package/dist/database/migrations/016_create_reviews_table.js.map +1 -0
  15. package/dist/database/migrations/index.d.ts +1 -0
  16. package/dist/database/migrations/index.d.ts.map +1 -1
  17. package/dist/database/migrations/index.js +2 -0
  18. package/dist/database/migrations/index.js.map +1 -1
  19. package/dist/database/types.d.ts +1 -1
  20. package/dist/database/types.d.ts.map +1 -1
  21. package/dist/database.d.ts +1 -1
  22. package/dist/database.d.ts.map +1 -1
  23. package/dist/index.js +13 -5
  24. package/dist/index.js.map +1 -1
  25. package/dist/learnings/builder.d.ts +25 -0
  26. package/dist/learnings/builder.d.ts.map +1 -0
  27. package/dist/learnings/builder.js +247 -0
  28. package/dist/learnings/builder.js.map +1 -0
  29. package/dist/learnings/database.d.ts +45 -0
  30. package/dist/learnings/database.d.ts.map +1 -0
  31. package/dist/learnings/database.js +63 -0
  32. package/dist/learnings/database.js.map +1 -0
  33. package/dist/learnings/embeddings.d.ts +20 -0
  34. package/dist/learnings/embeddings.d.ts.map +1 -0
  35. package/dist/learnings/embeddings.js +54 -0
  36. package/dist/learnings/embeddings.js.map +1 -0
  37. package/dist/learnings/evidence-writer.d.ts +13 -0
  38. package/dist/learnings/evidence-writer.d.ts.map +1 -0
  39. package/dist/learnings/evidence-writer.js +182 -0
  40. package/dist/learnings/evidence-writer.js.map +1 -0
  41. package/dist/learnings/extractor.d.ts +32 -0
  42. package/dist/learnings/extractor.d.ts.map +1 -0
  43. package/dist/learnings/extractor.js +265 -0
  44. package/dist/learnings/extractor.js.map +1 -0
  45. package/dist/learnings/github-evidence.d.ts +89 -0
  46. package/dist/learnings/github-evidence.d.ts.map +1 -0
  47. package/dist/learnings/github-evidence.js +255 -0
  48. package/dist/learnings/github-evidence.js.map +1 -0
  49. package/dist/learnings/github-ingestion.d.ts +18 -0
  50. package/dist/learnings/github-ingestion.d.ts.map +1 -0
  51. package/dist/learnings/github-ingestion.js +29 -0
  52. package/dist/learnings/github-ingestion.js.map +1 -0
  53. package/dist/learnings/heuristics.d.ts +17 -0
  54. package/dist/learnings/heuristics.d.ts.map +1 -0
  55. package/dist/learnings/heuristics.js +52 -0
  56. package/dist/learnings/heuristics.js.map +1 -0
  57. package/dist/learnings/id.d.ts +11 -0
  58. package/dist/learnings/id.d.ts.map +1 -0
  59. package/dist/learnings/id.js +36 -0
  60. package/dist/learnings/id.js.map +1 -0
  61. package/dist/learnings/index.d.ts +9 -0
  62. package/dist/learnings/index.d.ts.map +1 -0
  63. package/dist/learnings/index.js +55 -0
  64. package/dist/learnings/index.js.map +1 -0
  65. package/dist/learnings/ingest-pr-command.d.ts +8 -0
  66. package/dist/learnings/ingest-pr-command.d.ts.map +1 -0
  67. package/dist/learnings/ingest-pr-command.js +15 -0
  68. package/dist/learnings/ingest-pr-command.js.map +1 -0
  69. package/dist/learnings/ingest-repo-command.d.ts +9 -0
  70. package/dist/learnings/ingest-repo-command.d.ts.map +1 -0
  71. package/dist/learnings/ingest-repo-command.js +62 -0
  72. package/dist/learnings/ingest-repo-command.js.map +1 -0
  73. package/dist/learnings/init-command.d.ts +15 -0
  74. package/dist/learnings/init-command.d.ts.map +1 -0
  75. package/dist/learnings/init-command.js +36 -0
  76. package/dist/learnings/init-command.js.map +1 -0
  77. package/dist/learnings/install-hooks-command.d.ts +17 -0
  78. package/dist/learnings/install-hooks-command.d.ts.map +1 -0
  79. package/dist/learnings/install-hooks-command.js +241 -0
  80. package/dist/learnings/install-hooks-command.js.map +1 -0
  81. package/dist/learnings/learning-writer.d.ts +6 -0
  82. package/dist/learnings/learning-writer.d.ts.map +1 -0
  83. package/dist/learnings/learning-writer.js +42 -0
  84. package/dist/learnings/learning-writer.js.map +1 -0
  85. package/dist/learnings/parser.d.ts +12 -0
  86. package/dist/learnings/parser.d.ts.map +1 -0
  87. package/dist/learnings/parser.js +133 -0
  88. package/dist/learnings/parser.js.map +1 -0
  89. package/dist/learnings/paths.d.ts +6 -0
  90. package/dist/learnings/paths.d.ts.map +1 -0
  91. package/dist/learnings/paths.js +11 -0
  92. package/dist/learnings/paths.js.map +1 -0
  93. package/dist/learnings/query-command.d.ts +9 -0
  94. package/dist/learnings/query-command.d.ts.map +1 -0
  95. package/dist/learnings/query-command.js +37 -0
  96. package/dist/learnings/query-command.js.map +1 -0
  97. package/dist/learnings/query.d.ts +7 -0
  98. package/dist/learnings/query.d.ts.map +1 -0
  99. package/dist/learnings/query.js +65 -0
  100. package/dist/learnings/query.js.map +1 -0
  101. package/dist/learnings/rebuild-command.d.ts +8 -0
  102. package/dist/learnings/rebuild-command.d.ts.map +1 -0
  103. package/dist/learnings/rebuild-command.js +16 -0
  104. package/dist/learnings/rebuild-command.js.map +1 -0
  105. package/dist/learnings/record-types.d.ts +98 -0
  106. package/dist/learnings/record-types.d.ts.map +1 -0
  107. package/dist/learnings/record-types.js +5 -0
  108. package/dist/learnings/record-types.js.map +1 -0
  109. package/dist/learnings/repository.d.ts +18 -0
  110. package/dist/learnings/repository.d.ts.map +1 -0
  111. package/dist/learnings/repository.js +73 -0
  112. package/dist/learnings/repository.js.map +1 -0
  113. package/dist/learnings/types.d.ts +17 -0
  114. package/dist/learnings/types.d.ts.map +1 -0
  115. package/dist/learnings/types.js +4 -0
  116. package/dist/learnings/types.js.map +1 -0
  117. package/dist/learnings/validator.d.ts +14 -0
  118. package/dist/learnings/validator.d.ts.map +1 -0
  119. package/dist/learnings/validator.js +44 -0
  120. package/dist/learnings/validator.js.map +1 -0
  121. package/dist/learnings/weighting.d.ts +33 -0
  122. package/dist/learnings/weighting.d.ts.map +1 -0
  123. package/dist/learnings/weighting.js +106 -0
  124. package/dist/learnings/weighting.js.map +1 -0
  125. package/dist/services/address-executor.d.ts +0 -1
  126. package/dist/services/address-executor.d.ts.map +1 -1
  127. package/dist/services/address-executor.js +1 -4
  128. package/dist/services/address-executor.js.map +1 -1
  129. package/dist/services/address-task-executor.d.ts +0 -1
  130. package/dist/services/address-task-executor.d.ts.map +1 -1
  131. package/dist/services/address-task-executor.js +18 -14
  132. package/dist/services/address-task-executor.js.map +1 -1
  133. package/dist/services/claude-cli-executor.d.ts +1 -1
  134. package/dist/services/claude-cli-executor.d.ts.map +1 -1
  135. package/dist/services/claude-executor.d.ts +1 -1
  136. package/dist/services/claude-executor.d.ts.map +1 -1
  137. package/dist/services/claude-executor.js +2 -2
  138. package/dist/services/claude-executor.js.map +1 -1
  139. package/dist/services/git-interfaces.d.ts +3 -3
  140. package/dist/services/git-interfaces.d.ts.map +1 -1
  141. package/dist/services/git-manager-cli.d.ts +1 -1
  142. package/dist/services/git-manager-cli.d.ts.map +1 -1
  143. package/dist/services/git-manager-cli.js +36 -13
  144. package/dist/services/git-manager-cli.js.map +1 -1
  145. package/dist/services/git-manager-pat.d.ts +2 -2
  146. package/dist/services/git-manager-pat.d.ts.map +1 -1
  147. package/dist/services/git-manager-pat.js +31 -8
  148. package/dist/services/git-manager-pat.js.map +1 -1
  149. package/dist/services/github-api-client.d.ts +39 -3
  150. package/dist/services/github-api-client.d.ts.map +1 -1
  151. package/dist/services/github-api-client.js +76 -8
  152. package/dist/services/github-api-client.js.map +1 -1
  153. package/dist/services/index.d.ts +2 -1
  154. package/dist/services/index.d.ts.map +1 -1
  155. package/dist/services/index.js.map +1 -1
  156. package/dist/services/job-manager.d.ts +1 -1
  157. package/dist/services/job-manager.d.ts.map +1 -1
  158. package/dist/services/job-manager.js.map +1 -1
  159. package/dist/services/openai-service.d.ts +1 -0
  160. package/dist/services/openai-service.d.ts.map +1 -1
  161. package/dist/services/openai-service.js +54 -0
  162. package/dist/services/openai-service.js.map +1 -1
  163. package/dist/services/pr-service-cli.d.ts +1 -1
  164. package/dist/services/pr-service-cli.d.ts.map +1 -1
  165. package/dist/services/pr-service-pat.d.ts +1 -1
  166. package/dist/services/pr-service-pat.d.ts.map +1 -1
  167. package/dist/services/pr-service-pat.js +2 -2
  168. package/dist/services/pr-service-pat.js.map +1 -1
  169. package/dist/services/repository-manager-cli.d.ts +1 -1
  170. package/dist/services/repository-manager-cli.d.ts.map +1 -1
  171. package/dist/services/repository-manager-cli.js.map +1 -1
  172. package/dist/services/repository-manager-pat.d.ts +3 -3
  173. package/dist/services/repository-manager-pat.d.ts.map +1 -1
  174. package/dist/services/repository-manager-pat.js.map +1 -1
  175. package/dist/services/review-executor.d.ts +8 -0
  176. package/dist/services/review-executor.d.ts.map +1 -0
  177. package/dist/services/review-executor.js +159 -0
  178. package/dist/services/review-executor.js.map +1 -0
  179. package/dist/services/service-factory.d.ts +1 -1
  180. package/dist/services/service-factory.d.ts.map +1 -1
  181. package/dist/services/task-executor.d.ts +3 -2
  182. package/dist/services/task-executor.d.ts.map +1 -1
  183. package/dist/services/task-executor.js +54 -13
  184. package/dist/services/task-executor.js.map +1 -1
  185. package/dist/types/non-interactive-config.d.ts +5 -0
  186. package/dist/types/non-interactive-config.d.ts.map +1 -1
  187. package/dist/web-server.d.ts.map +1 -1
  188. package/dist/web-server.js.map +1 -1
  189. package/package.json +7 -5
@@ -0,0 +1,11 @@
1
+ import path from 'path';
2
+ export const CANONICAL_LEARNINGS_ROOT = '.ivan';
3
+ export const LESSONS_JSONL_RELATIVE_PATH = `${CANONICAL_LEARNINGS_ROOT}/lessons.jsonl`;
4
+ export const LEARNINGS_DB_RELATIVE_PATH = `${CANONICAL_LEARNINGS_ROOT}/db.sqlite`;
5
+ export function canonicalLearningsPath(...segments) {
6
+ return path.posix.join(CANONICAL_LEARNINGS_ROOT, ...segments);
7
+ }
8
+ export function resolveCanonicalLearningsPath(repoPath, ...segments) {
9
+ return path.join(path.resolve(repoPath), '.ivan', ...segments);
10
+ }
11
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/learnings/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,wBAAwB,gBAAgB,CAAC;AACvF,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,wBAAwB,YAAY,CAAC;AAElF,MAAM,UAAU,sBAAsB,CAAC,GAAG,QAAkB;IAC1D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,EAAE,GAAG,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,QAAgB,EAChB,GAAG,QAAkB;IAErB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,9 @@
1
+ interface QueryCommandOptions {
2
+ repo: string;
3
+ text: string;
4
+ limit?: string;
5
+ }
6
+ /** Commander action handler: validates options, calls `queryLearnings`, and pretty-prints results. */
7
+ export declare function runQueryCommand(options: QueryCommandOptions): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=query-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-command.d.ts","sourceRoot":"","sources":["../../src/learnings/query-command.ts"],"names":[],"mappings":"AAMA,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sGAAsG;AACtG,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -0,0 +1,37 @@
1
+ // CLI handler for `ivan learnings query`.
2
+ // Searches the local `.ivan/db.sqlite` and prints each result with statement, metadata, and evidence links.
3
+ import chalk from 'chalk';
4
+ import { queryLearnings } from './query.js';
5
+ /** Commander action handler: validates options, calls `queryLearnings`, and pretty-prints results. */
6
+ export async function runQueryCommand(options) {
7
+ const limit = options.limit ? parseInt(options.limit, 10) : 5;
8
+ if (Number.isNaN(limit) || limit <= 0) {
9
+ throw new Error('Query limit must be a positive integer');
10
+ }
11
+ const results = await queryLearnings(options.repo, options.text, { limit });
12
+ if (results.length === 0) {
13
+ console.log(chalk.yellow('No learnings matched that query.'));
14
+ return;
15
+ }
16
+ results.forEach((result, index) => {
17
+ console.log(chalk.cyan(`${index + 1}. ${result.statement}`));
18
+ const metadata = [`id=${result.id}`, `kind=${result.kind}`];
19
+ if (result.confidence !== undefined) {
20
+ metadata.push(`confidence=${result.confidence.toFixed(2)}`);
21
+ }
22
+ console.log(chalk.gray(` ${metadata.join(' | ')}`));
23
+ if (result.rationale) {
24
+ console.log(chalk.gray(` Rationale: ${result.rationale}`));
25
+ }
26
+ if (result.applicability) {
27
+ console.log(chalk.gray(` Applicability: ${result.applicability}`));
28
+ }
29
+ if (result.source_url) {
30
+ console.log(chalk.gray(` Source: ${result.source_url}`));
31
+ }
32
+ if (index < results.length - 1) {
33
+ console.log('');
34
+ }
35
+ });
36
+ }
37
+ //# sourceMappingURL=query-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-command.js","sourceRoot":"","sources":["../../src/learnings/query-command.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,4GAA4G;AAE5G,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ5C,sGAAsG;AACtG,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA4B;IAE5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAE7D,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE,EAAE,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACpC,QAAQ,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAEtD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { LearningsQueryResult, LearningsSearchOptions } from './types.js';
2
+ /**
3
+ * Searches the learnings database for records relevant to `text`.
4
+ * Opens the DB read-only and closes it before returning.
5
+ */
6
+ export declare function queryLearnings(repoPath: string, text: string, options?: LearningsSearchOptions): Promise<LearningsQueryResult[]>;
7
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/learnings/query.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAmB/E;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA4BjC"}
@@ -0,0 +1,65 @@
1
+ // Vector search over the learnings SQLite database.
2
+ import { sql } from 'kysely';
3
+ import { openLearningsDatabase } from './database.js';
4
+ import { embedText } from './embeddings.js';
5
+ const MIN_VECTOR_SIMILARITY = 0.12;
6
+ /**
7
+ * Searches the learnings database for records relevant to `text`.
8
+ * Opens the DB read-only and closes it before returning.
9
+ */
10
+ export async function queryLearnings(repoPath, text, options = {}) {
11
+ const searchText = text.trim();
12
+ if (!searchText) {
13
+ throw new Error('Query text must not be empty');
14
+ }
15
+ const db = openLearningsDatabase(repoPath, { readonly: true });
16
+ try {
17
+ const rawLimit = options.limit ?? 5;
18
+ const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.min(rawLimit, 100) : 5;
19
+ const vectorRows = await runVectorSearch(db, searchText, limit);
20
+ return vectorRows.map(({ distance: _distance, ...row }) => ({
21
+ id: row.id,
22
+ kind: row.kind,
23
+ statement: row.statement,
24
+ status: row.status,
25
+ title: row.title ?? undefined,
26
+ rationale: row.rationale ?? undefined,
27
+ applicability: row.applicability ?? undefined,
28
+ confidence: row.confidence ?? undefined,
29
+ source_url: row.source_url ?? undefined
30
+ }));
31
+ }
32
+ finally {
33
+ await db.destroy();
34
+ }
35
+ }
36
+ async function runVectorSearch(db, text, limit) {
37
+ let queryVector;
38
+ try {
39
+ queryVector = Buffer.from(new Float32Array(await embedText(text)).buffer);
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ const { rows } = await sql `
45
+ SELECT
46
+ l.id,
47
+ l.title,
48
+ l.kind,
49
+ l.statement,
50
+ l.rationale,
51
+ l.applicability,
52
+ l.confidence,
53
+ l.status,
54
+ l.source_url,
55
+ distance
56
+ FROM learning_vectors lv
57
+ INNER JOIN learnings l ON l.id = lv.learning_id
58
+ WHERE lv.vector MATCH ${queryVector}
59
+ AND k = ${limit}
60
+ AND l.status = 'active'
61
+ ORDER BY distance
62
+ `.execute(db);
63
+ return rows.filter((row) => Number.isFinite(row.distance) && 1 - row.distance >= MIN_VECTOR_SIMILARITY);
64
+ }
65
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/learnings/query.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC7B,OAAO,EAAE,qBAAqB,EAA0B,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAkB5C,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,IAAY,EACZ,UAAkC,EAAE;IAEpC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,EAAE,GAAG,qBAAqB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;QACpC,MAAM,KAAK,GACT,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAEhE,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1D,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,SAAS;YACrC,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,SAAS;YAC7C,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;YACvC,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,SAAS;SACxC,CAAC,CAAC,CAAC;IACN,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,EAA6B,EAC7B,IAAY,EACZ,KAAa;IAEb,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAmB;;;;;;;;;;;;;;4BAcnB,WAAW;gBACvB,KAAK;;;GAGlB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAEd,OAAO,IAAI,CAAC,MAAM,CAChB,CAAC,GAAG,EAAE,EAAE,CACN,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,IAAI,qBAAqB,CAC7E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ interface RebuildCommandOptions {
2
+ repo: string;
3
+ ifStale?: boolean;
4
+ }
5
+ /** Commander action handler: calls `rebuildLearningsDatabase` and prints record counts. */
6
+ export declare function runRebuildCommand(options: RebuildCommandOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=rebuild-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild-command.d.ts","sourceRoot":"","sources":["../../src/learnings/rebuild-command.ts"],"names":[],"mappings":"AASA,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,2FAA2F;AAC3F,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -0,0 +1,16 @@
1
+ // CLI handler for `ivan learnings rebuild`.
2
+ // Drops and recreates `.ivan/db.sqlite` from the canonical JSONL files without touching GitHub.
3
+ import chalk from 'chalk';
4
+ import { isLearningsDatabaseStale, rebuildLearningsDatabase } from './builder.js';
5
+ /** Commander action handler: calls `rebuildLearningsDatabase` and prints record counts. */
6
+ export async function runRebuildCommand(options) {
7
+ if (options.ifStale && !(await isLearningsDatabaseStale(options.repo))) {
8
+ console.log(chalk.gray('.ivan/db.sqlite is up to date'));
9
+ return;
10
+ }
11
+ const result = await rebuildLearningsDatabase(options.repo);
12
+ console.log(chalk.green('✅ Learnings database rebuilt'));
13
+ console.log(chalk.gray(`DB: ${result.dbPath}`));
14
+ console.log(chalk.gray(`Learnings: ${result.learningCount}`));
15
+ }
16
+ //# sourceMappingURL=rebuild-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild-command.js","sourceRoot":"","sources":["../../src/learnings/rebuild-command.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,gGAAgG;AAEhG,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,cAAc,CAAC;AAOtB,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAA8B;IAE9B,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,98 @@
1
+ /** Shared fields present on every record in the learnings store. */
2
+ export interface CanonicalRecord {
3
+ id: string;
4
+ type: 'evidence' | 'learning';
5
+ created_at: string;
6
+ updated_at: string;
7
+ }
8
+ /** In-memory signal derived from a GitHub PR payload. Never written to disk. */
9
+ export interface EvidenceSignal extends CanonicalRecord {
10
+ type: 'evidence';
11
+ source_system: string;
12
+ /** Narrows the evidence kind: `pull_request`, `pr_review_thread`, `pr_review`, `pr_issue_comment`, `pr_check`. */
13
+ source_type: string;
14
+ external_url?: string;
15
+ parent_url?: string;
16
+ author_name?: string;
17
+ author_type?: string;
18
+ occurred_at?: string;
19
+ /**
20
+ * Raw weight assigned by evidence type before boosts or penalties.
21
+ * See `weighting.ts` for the scoring functions that produce these values.
22
+ *
23
+ * | source_type / condition | base_weight | Notes |
24
+ * |--------------------------------------|-------------|------------------------------------|
25
+ * | pr_review (CHANGES_REQUESTED) | 6 | Actionable feedback |
26
+ * | pr_review_thread (unresolved) | 5 | Still-open issue |
27
+ * | pr_check (failure / error) | 4 | CI failure signal |
28
+ * | pr_review_thread (resolved) | 3 | Addressed inline thread |
29
+ * | pr_issue_comment | 3 | General PR discussion |
30
+ * | pr_review (APPROVED / COMMENTED) | 2 | Verdict without actionable content |
31
+ * | pr_check (passing) | 1 | Low signal; not extracted |
32
+ */
33
+ base_weight?: number;
34
+ /**
35
+ * Final weight after applying boosts and penalties.
36
+ * Evidence is extracted into a learning when `final_weight >= 3` (see `extractor.ts`).
37
+ * Confidence is derived as `0.35 + min(final_weight, 12) / 20` → [0.35, 0.95].
38
+ *
39
+ * **Boosts** (added to `base_weight`)
40
+ * | Label | Condition |
41
+ * |------------------------|----------------------------------------------------|
42
+ * | `changes_requested` | Review state is CHANGES_REQUESTED |
43
+ * | `approved` | Review state is APPROVED |
44
+ * | `unresolved_thread` | Review thread is not yet resolved |
45
+ * | `inline_code_comment` | Thread is diff-anchored (has a file path) |
46
+ *
47
+ * **Penalties** (subtracted from `base_weight`, floored at 0)
48
+ * | Label | Δ | Condition |
49
+ * |------------------------|----|--------------------------------------------------|
50
+ * | `low_signal_text` | −2 | Body starts with `nit:`, `style:`, or `typo:` |
51
+ * | `outdated_thread` | — | Thread marked outdated (label only, no Δ) |
52
+ * | `review_comment_only` | — | Review state is COMMENTED (label only, no Δ) |
53
+ */
54
+ final_weight?: number;
55
+ /** Labels that increased the signal value (e.g. `changes_requested`, `unresolved_thread`). */
56
+ boosts: string[];
57
+ /** Labels that decreased the signal value (e.g. `low_signal_text`, `outdated_thread`). */
58
+ penalties: string[];
59
+ }
60
+ /** In-memory content for an evidence signal. Never written to disk. */
61
+ export interface EvidenceContext {
62
+ title?: string;
63
+ content: string;
64
+ diff_hunk?: string;
65
+ file_path?: string;
66
+ line_start?: number;
67
+ line_end?: number;
68
+ }
69
+ /** Maps evidence signal id to its in-memory content. */
70
+ export type EvidenceContextCache = Map<string, EvidenceContext>;
71
+ /** An extracted engineering insight derived from one or more evidence records. */
72
+ export interface LearningRecord extends CanonicalRecord {
73
+ type: 'learning';
74
+ /** Relative path within the repo (e.g. `.ivan/lessons.jsonl#L3`). */
75
+ sourcePath: string;
76
+ /** `repo_convention` for project-specific rules; `engineering_lesson` for general patterns. */
77
+ kind: string;
78
+ source_type?: string;
79
+ title?: string;
80
+ /** The actionable statement distilled from the evidence. */
81
+ statement: string;
82
+ rationale?: string;
83
+ applicability?: string;
84
+ /** 0.35–0.95; derived from `final_weight` via `inferConfidence`. */
85
+ confidence?: number;
86
+ status: string;
87
+ /** GitHub URL of the PR that generated this learning. */
88
+ source_url?: string;
89
+ /** Cached 1536-dim embedding vector from `text-embedding-3-small`. */
90
+ embedding?: number[];
91
+ /** SHA-256 hex of the embedding input string; used to detect content changes. */
92
+ embeddingInputHash?: string;
93
+ }
94
+ /** The full in-memory view of all canonical JSONL data for one repo. */
95
+ export interface LearningsDataset {
96
+ learnings: LearningRecord[];
97
+ }
98
+ //# sourceMappingURL=record-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-types.d.ts","sourceRoot":"","sources":["../../src/learnings/record-types.ts"],"names":[],"mappings":"AAIA,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAe,SAAQ,eAAe;IACrD,IAAI,EAAE,UAAU,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,kHAAkH;IAClH,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,0FAA0F;IAC1F,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wDAAwD;AACxD,MAAM,MAAM,oBAAoB,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEhE,kFAAkF;AAClF,MAAM,WAAW,cAAe,SAAQ,eAAe;IACrD,IAAI,EAAE,UAAU,CAAC;IACjB,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B"}
@@ -0,0 +1,5 @@
1
+ // Canonical record types persisted as JSONL files under `.ivan/`.
2
+ // These are the source-of-truth data structures; the SQLite database is a
3
+ // derived, rebuilable index built from these files.
4
+ export {};
5
+ //# sourceMappingURL=record-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-types.js","sourceRoot":"","sources":["../../src/learnings/record-types.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,0EAA0E;AAC1E,oDAAoD"}
@@ -0,0 +1,18 @@
1
+ /** Resolved path context for the repository being tracked. */
2
+ export interface LearningsRepositoryContext {
3
+ repoPath: string;
4
+ remoteUrl?: string;
5
+ }
6
+ /** Resolves and validates the repository path. */
7
+ export declare function resolveLearningsRepositoryContext(repoPath: string): LearningsRepositoryContext;
8
+ /** Creates `.ivan/` if it doesn't exist; returns the list of paths actually created. */
9
+ export declare function ensureLearningsDirectories(context: LearningsRepositoryContext): string[];
10
+ /** Creates empty canonical JSONL files when they do not already exist. */
11
+ export declare function ensureCanonicalJsonlFiles(repoPath: string): string[];
12
+ /**
13
+ * No-op: `.ivan/db.sqlite` is intentionally tracked in git so the database is
14
+ * available to all collaborators without requiring a rebuild.
15
+ * Always returns false (no changes made).
16
+ */
17
+ export declare function ensureGitignoreCoverage(_repoPath: string): boolean;
18
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/learnings/repository.ts"],"names":[],"mappings":"AASA,8DAA8D;AAC9D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,kDAAkD;AAClD,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,MAAM,GACf,0BAA0B,CAS5B;AAED,wFAAwF;AACxF,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,0BAA0B,GAClC,MAAM,EAAE,CAQV;AAED,0EAA0E;AAC1E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAepE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElE"}
@@ -0,0 +1,73 @@
1
+ // Repository identity resolution and learnings directory management.
2
+ // Responsible for identifying which repo is being tracked and creating the local
3
+ // `.ivan/` storage directory.
4
+ import { execFileSync } from 'child_process';
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { resolveCanonicalLearningsPath } from './paths.js';
8
+ /** Resolves and validates the repository path. */
9
+ export function resolveLearningsRepositoryContext(repoPath) {
10
+ const resolvedRepoPath = path.resolve(repoPath);
11
+ assertDirectoryExists(resolvedRepoPath);
12
+ const remoteUrl = readRemoteUrl(resolvedRepoPath);
13
+ return {
14
+ repoPath: resolvedRepoPath,
15
+ ...(remoteUrl !== undefined ? { remoteUrl } : {})
16
+ };
17
+ }
18
+ /** Creates `.ivan/` if it doesn't exist; returns the list of paths actually created. */
19
+ export function ensureLearningsDirectories(context) {
20
+ const directory = resolveCanonicalLearningsPath(context.repoPath);
21
+ if (fs.existsSync(directory)) {
22
+ return [];
23
+ }
24
+ fs.mkdirSync(directory, { recursive: true });
25
+ return [directory];
26
+ }
27
+ /** Creates empty canonical JSONL files when they do not already exist. */
28
+ export function ensureCanonicalJsonlFiles(repoPath) {
29
+ const files = [
30
+ resolveCanonicalLearningsPath(repoPath, 'evidence.jsonl'),
31
+ resolveCanonicalLearningsPath(repoPath, 'lessons.jsonl')
32
+ ];
33
+ const created = [];
34
+ for (const filePath of files) {
35
+ if (!fs.existsSync(filePath)) {
36
+ fs.writeFileSync(filePath, '', 'utf8');
37
+ created.push(filePath);
38
+ }
39
+ }
40
+ return created;
41
+ }
42
+ /**
43
+ * No-op: `.ivan/db.sqlite` is intentionally tracked in git so the database is
44
+ * available to all collaborators without requiring a rebuild.
45
+ * Always returns false (no changes made).
46
+ */
47
+ export function ensureGitignoreCoverage(_repoPath) {
48
+ return false;
49
+ }
50
+ /** Throws a descriptive error if `repoPath` does not exist or is not a directory. */
51
+ function assertDirectoryExists(repoPath) {
52
+ if (!fs.existsSync(repoPath)) {
53
+ throw new Error(`Repository path does not exist: ${repoPath}`);
54
+ }
55
+ if (!fs.statSync(repoPath).isDirectory()) {
56
+ throw new Error(`Repository path is not a directory: ${repoPath}`);
57
+ }
58
+ }
59
+ /** Reads `remote.origin.url` from git config; returns `undefined` silently if the repo has no remote. */
60
+ function readRemoteUrl(repoPath) {
61
+ try {
62
+ const remoteUrl = execFileSync('git', ['config', '--get', 'remote.origin.url'], {
63
+ cwd: repoPath,
64
+ encoding: 'utf8',
65
+ stdio: ['ignore', 'pipe', 'ignore']
66
+ }).trim();
67
+ return remoteUrl || undefined;
68
+ }
69
+ catch {
70
+ return undefined;
71
+ }
72
+ }
73
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/learnings/repository.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,iFAAiF;AACjF,8BAA8B;AAE9B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC;AAQ3D,kDAAkD;AAClD,MAAM,UAAU,iCAAiC,CAC/C,QAAgB;IAEhB,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IAExC,MAAM,SAAS,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,0BAA0B,CACxC,OAAmC;IAEnC,MAAM,SAAS,GAAG,6BAA6B,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAC;AACrB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,MAAM,KAAK,GAAG;QACZ,6BAA6B,CAAC,QAAQ,EAAE,gBAAgB,CAAC;QACzD,6BAA6B,CAAC,QAAQ,EAAE,eAAe,CAAC;KACzD,CAAC;IACF,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,SAAS,qBAAqB,CAAC,QAAgB;IAC7C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,uCAAuC,QAAQ,EAAE,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,yGAAyG;AACzG,SAAS,aAAa,CAAC,QAAgB;IACrC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,YAAY,CAC5B,KAAK,EACL,CAAC,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,EACxC;YACE,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CACF,CAAC,IAAI,EAAE,CAAC;QAET,OAAO,SAAS,IAAI,SAAS,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ /** Controls how many results `queryLearnings` returns. */
2
+ export interface LearningsSearchOptions {
3
+ limit?: number;
4
+ }
5
+ /** A fully hydrated learning returned by `queryLearnings`. */
6
+ export interface LearningsQueryResult {
7
+ id: string;
8
+ title?: string;
9
+ kind: string;
10
+ statement: string;
11
+ rationale?: string;
12
+ applicability?: string;
13
+ confidence?: number;
14
+ status: string;
15
+ source_url?: string;
16
+ }
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/learnings/types.ts"],"names":[],"mappings":"AAGA,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -0,0 +1,4 @@
1
+ // Public-facing query types returned by `queryLearnings`. These are read-only
2
+ // projections of the SQLite data—separate from the canonical JSONL record types.
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/learnings/types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iFAAiF"}
@@ -0,0 +1,14 @@
1
+ import type { LearningsDataset } from './record-types.js';
2
+ /** Thrown by `validateLearningsDataset` when the dataset contains one or more structural problems. */
3
+ export declare class LearningsValidationError extends Error {
4
+ /** Each string describes one broken invariant, formatted as `{sourcePath}: {reason}`. */
5
+ issues: string[];
6
+ constructor(issues: string[]);
7
+ }
8
+ /**
9
+ * Validates all records in `dataset` against the schema rules:
10
+ * correct ID prefixes, no duplicates, and correct file locations.
11
+ * Throws `LearningsValidationError` listing every issue found; returns void on success.
12
+ */
13
+ export declare function validateLearningsDataset(dataset: LearningsDataset): void;
14
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/learnings/validator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAI1D,sGAAsG;AACtG,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,yFAAyF;IACzF,MAAM,EAAE,MAAM,EAAE,CAAC;gBAEL,MAAM,EAAE,MAAM,EAAE;CAK7B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAmCxE"}
@@ -0,0 +1,44 @@
1
+ // Structural validation for the canonical JSONL dataset before it is used to build
2
+ // or query the SQLite database. Throws early with a human-readable list of all
3
+ // issues so users can fix everything in one pass rather than one error at a time.
4
+ import { isStableRecordId } from './id.js';
5
+ import { LESSONS_JSONL_RELATIVE_PATH } from './paths.js';
6
+ /** Thrown by `validateLearningsDataset` when the dataset contains one or more structural problems. */
7
+ export class LearningsValidationError extends Error {
8
+ /** Each string describes one broken invariant, formatted as `{sourcePath}: {reason}`. */
9
+ issues;
10
+ constructor(issues) {
11
+ super(`Invalid learnings records:\n- ${issues.join('\n- ')}`);
12
+ this.name = 'LearningsValidationError';
13
+ this.issues = issues;
14
+ }
15
+ }
16
+ /**
17
+ * Validates all records in `dataset` against the schema rules:
18
+ * correct ID prefixes, no duplicates, and correct file locations.
19
+ * Throws `LearningsValidationError` listing every issue found; returns void on success.
20
+ */
21
+ export function validateLearningsDataset(dataset) {
22
+ const issues = [];
23
+ const learningIds = new Set();
24
+ for (const learning of dataset.learnings) {
25
+ if (!isStableRecordId(learning.id, 'lrn')) {
26
+ issues.push(`${learning.sourcePath}: learning id "${learning.id}" must start with "lrn_"`);
27
+ }
28
+ if (learningIds.has(learning.id)) {
29
+ issues.push(`${learning.sourcePath}: duplicate learning id "${learning.id}"`);
30
+ }
31
+ learningIds.add(learning.id);
32
+ if (!learning.statement.trim()) {
33
+ issues.push(`${learning.sourcePath}: learning statement must not be empty`);
34
+ }
35
+ const learningSourceFile = learning.sourcePath.split('#')[0];
36
+ if (learningSourceFile !== LESSONS_JSONL_RELATIVE_PATH) {
37
+ issues.push(`${learning.sourcePath}: learning must live in ${LESSONS_JSONL_RELATIVE_PATH}`);
38
+ }
39
+ }
40
+ if (issues.length > 0) {
41
+ throw new LearningsValidationError(issues);
42
+ }
43
+ }
44
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/learnings/validator.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,gFAAgF;AAChF,kFAAkF;AAGlF,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAEzD,sGAAsG;AACtG,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD,yFAAyF;IACzF,MAAM,CAAW;IAEjB,YAAY,MAAgB;QAC1B,KAAK,CAAC,iCAAiC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAyB;IAChE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IAEtC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACzC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CACT,GAAG,QAAQ,CAAC,UAAU,kBAAkB,QAAQ,CAAC,EAAE,0BAA0B,CAC9E,CAAC;QACJ,CAAC;QAED,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CACT,GAAG,QAAQ,CAAC,UAAU,4BAA4B,QAAQ,CAAC,EAAE,GAAG,CACjE,CAAC;QACJ,CAAC;QACD,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE7B,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CACT,GAAG,QAAQ,CAAC,UAAU,wCAAwC,CAC/D,CAAC;QACJ,CAAC;QAED,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,IAAI,kBAAkB,KAAK,2BAA2B,EAAE,CAAC;YACvD,MAAM,CAAC,IAAI,CACT,GAAG,QAAQ,CAAC,UAAU,2BAA2B,2BAA2B,EAAE,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { GitHubCheckEvidence, GitHubIssueCommentEvidence, GitHubReviewEvidence, GitHubReviewThreadEvidence } from './github-evidence.js';
2
+ /** The computed signal strength for a single piece of evidence, with audit trail labels. */
3
+ export interface EvidenceWeight {
4
+ baseWeight: number;
5
+ finalWeight: number;
6
+ /** Labels that raised the signal (e.g. `changes_requested`, `unresolved_thread`). */
7
+ boosts: string[];
8
+ /** Labels that reduced the signal (e.g. `low_signal_text`, `outdated_thread`). */
9
+ penalties: string[];
10
+ }
11
+ /** Scores a plain PR issue comment; base weight 3 before text-quality adjustment. */
12
+ export declare function weightIssueComment(comment: GitHubIssueCommentEvidence): EvidenceWeight;
13
+ /**
14
+ * Scores a PR review. `CHANGES_REQUESTED` starts at 6 (actionable feedback);
15
+ * other states start at 2. Low-signal text reduces either by 2.
16
+ */
17
+ export declare function weightReview(review: GitHubReviewEvidence): EvidenceWeight;
18
+ /**
19
+ * Scores a review thread. Unresolved threads start at 5 (still open issue),
20
+ * resolved at 3. Inline code comments get a boost; outdated threads get a penalty.
21
+ */
22
+ export declare function weightReviewThread(thread: GitHubReviewThreadEvidence): EvidenceWeight;
23
+ /**
24
+ * Scores a CI check. Failures/errors are high-signal (weight 4); passing checks
25
+ * are low-signal (weight 1) and bypass the text-quality computation entirely.
26
+ */
27
+ export declare function weightCheck(check: GitHubCheckEvidence): EvidenceWeight;
28
+ /** Wraps `classifyAuthorType` into the `{ author_type, author_name }` shape expected by `EvidenceRecord`. */
29
+ export declare function inferAuthorFields(authorName?: string): {
30
+ author_type?: string;
31
+ author_name?: string;
32
+ };
33
+ //# sourceMappingURL=weighting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weighting.d.ts","sourceRoot":"","sources":["../../src/learnings/weighting.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,oBAAoB,EACpB,0BAA0B,EAC3B,MAAM,sBAAsB,CAAC;AAO9B,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kFAAkF;IAClF,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,0BAA0B,GAClC,cAAc,CAMhB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc,CAiBzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,0BAA0B,GACjC,cAAc,CAsBhB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAkBtE;AAED,6GAA6G;AAC7G,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAMA"}