@balpal4495/quorum 3.0.3 → 3.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 (243) hide show
  1. package/bin/commands/compass.js +4 -4
  2. package/bin/shared/llm.js +2 -2
  3. package/dist/advisor/ask.d.ts +13 -0
  4. package/dist/advisor/ask.d.ts.map +1 -0
  5. package/dist/advisor/ask.js +67 -0
  6. package/dist/advisor/ask.js.map +1 -0
  7. package/dist/advisor/index.d.ts +3 -0
  8. package/dist/advisor/index.d.ts.map +1 -0
  9. package/dist/advisor/index.js +2 -0
  10. package/dist/advisor/index.js.map +1 -0
  11. package/dist/advisor/prompt.d.ts +5 -0
  12. package/dist/advisor/prompt.d.ts.map +1 -0
  13. package/{modules/advisor/prompt.ts → dist/advisor/prompt.js} +22 -26
  14. package/dist/advisor/prompt.js.map +1 -0
  15. package/dist/advisor/types.d.ts +23 -0
  16. package/dist/advisor/types.d.ts.map +1 -0
  17. package/dist/advisor/types.js +2 -0
  18. package/dist/advisor/types.js.map +1 -0
  19. package/dist/compass/behavior.d.ts +4 -0
  20. package/dist/compass/behavior.d.ts.map +1 -0
  21. package/dist/compass/behavior.js +138 -0
  22. package/dist/compass/behavior.js.map +1 -0
  23. package/dist/compass/create.d.ts +3 -0
  24. package/dist/compass/create.d.ts.map +1 -0
  25. package/dist/compass/create.js +289 -0
  26. package/dist/compass/create.js.map +1 -0
  27. package/dist/compass/evidence/collect.d.ts +11 -0
  28. package/dist/compass/evidence/collect.d.ts.map +1 -0
  29. package/dist/compass/evidence/collect.js +86 -0
  30. package/dist/compass/evidence/collect.js.map +1 -0
  31. package/dist/compass/index.d.ts +8 -0
  32. package/dist/compass/index.d.ts.map +1 -0
  33. package/dist/compass/index.js +8 -0
  34. package/dist/compass/index.js.map +1 -0
  35. package/dist/compass/prompts/index.d.ts +28 -0
  36. package/dist/compass/prompts/index.d.ts.map +1 -0
  37. package/{modules/compass/prompts/index.ts → dist/compass/prompts/index.js} +13 -38
  38. package/dist/compass/prompts/index.js.map +1 -0
  39. package/dist/compass/prompts/system.d.ts +2 -0
  40. package/dist/compass/prompts/system.d.ts.map +1 -0
  41. package/{modules/compass/prompts/system.ts → dist/compass/prompts/system.js} +2 -1
  42. package/dist/compass/prompts/system.js.map +1 -0
  43. package/dist/compass/propose.d.ts +15 -0
  44. package/dist/compass/propose.d.ts.map +1 -0
  45. package/dist/compass/propose.js +128 -0
  46. package/dist/compass/propose.js.map +1 -0
  47. package/dist/compass/schemas.d.ts +1271 -0
  48. package/dist/compass/schemas.d.ts.map +1 -0
  49. package/dist/compass/schemas.js +113 -0
  50. package/dist/compass/schemas.js.map +1 -0
  51. package/dist/compass/score.d.ts +25 -0
  52. package/dist/compass/score.d.ts.map +1 -0
  53. package/dist/compass/score.js +89 -0
  54. package/dist/compass/score.js.map +1 -0
  55. package/dist/compass/sources/index.d.ts +9 -0
  56. package/dist/compass/sources/index.d.ts.map +1 -0
  57. package/dist/compass/sources/index.js +408 -0
  58. package/dist/compass/sources/index.js.map +1 -0
  59. package/dist/compass/types.d.ts +334 -0
  60. package/dist/compass/types.d.ts.map +1 -0
  61. package/dist/compass/types.js +2 -0
  62. package/dist/compass/types.js.map +1 -0
  63. package/dist/council/advisors.d.ts +15 -0
  64. package/dist/council/advisors.d.ts.map +1 -0
  65. package/dist/council/advisors.js +46 -0
  66. package/dist/council/advisors.js.map +1 -0
  67. package/dist/council/chairman.d.ts +13 -0
  68. package/dist/council/chairman.d.ts.map +1 -0
  69. package/dist/council/chairman.js +145 -0
  70. package/dist/council/chairman.js.map +1 -0
  71. package/dist/council/deliberate.d.ts +22 -0
  72. package/dist/council/deliberate.d.ts.map +1 -0
  73. package/dist/council/deliberate.js +99 -0
  74. package/dist/council/deliberate.js.map +1 -0
  75. package/dist/council/frame.d.ts +8 -0
  76. package/dist/council/frame.d.ts.map +1 -0
  77. package/dist/council/frame.js +40 -0
  78. package/dist/council/frame.js.map +1 -0
  79. package/dist/council/index.d.ts +6 -0
  80. package/dist/council/index.d.ts.map +1 -0
  81. package/dist/council/index.js +4 -0
  82. package/dist/council/index.js.map +1 -0
  83. package/dist/council/personas.d.ts +18 -0
  84. package/dist/council/personas.d.ts.map +1 -0
  85. package/dist/council/personas.js +44 -0
  86. package/dist/council/personas.js.map +1 -0
  87. package/dist/council/reviewers.d.ts +13 -0
  88. package/dist/council/reviewers.d.ts.map +1 -0
  89. package/dist/council/reviewers.js +59 -0
  90. package/dist/council/reviewers.js.map +1 -0
  91. package/dist/council/risk.d.ts +16 -0
  92. package/dist/council/risk.d.ts.map +1 -0
  93. package/dist/council/risk.js +74 -0
  94. package/dist/council/risk.js.map +1 -0
  95. package/dist/council/types.d.ts +95 -0
  96. package/dist/council/types.d.ts.map +1 -0
  97. package/dist/council/types.js +2 -0
  98. package/dist/council/types.js.map +1 -0
  99. package/dist/jury/evaluate.d.ts +13 -0
  100. package/dist/jury/evaluate.d.ts.map +1 -0
  101. package/{modules/jury/evaluate.ts → dist/jury/evaluate.js} +60 -84
  102. package/dist/jury/evaluate.js.map +1 -0
  103. package/dist/jury/index.d.ts +6 -0
  104. package/dist/jury/index.d.ts.map +1 -0
  105. package/dist/jury/index.js +4 -0
  106. package/dist/jury/index.js.map +1 -0
  107. package/dist/jury/preflight.d.ts +26 -0
  108. package/dist/jury/preflight.d.ts.map +1 -0
  109. package/dist/jury/preflight.js +71 -0
  110. package/dist/jury/preflight.js.map +1 -0
  111. package/dist/jury/schema.d.ts +57 -0
  112. package/dist/jury/schema.d.ts.map +1 -0
  113. package/dist/jury/schema.js +21 -0
  114. package/dist/jury/schema.js.map +1 -0
  115. package/dist/jury/types.d.ts +47 -0
  116. package/dist/jury/types.d.ts.map +1 -0
  117. package/dist/jury/types.js +2 -0
  118. package/dist/jury/types.js.map +1 -0
  119. package/dist/oracle/adapters/lance-db.d.ts +15 -0
  120. package/dist/oracle/adapters/lance-db.d.ts.map +1 -0
  121. package/dist/oracle/adapters/lance-db.js +68 -0
  122. package/dist/oracle/adapters/lance-db.js.map +1 -0
  123. package/dist/oracle/adapters/xenova-embedder.d.ts +21 -0
  124. package/dist/oracle/adapters/xenova-embedder.d.ts.map +1 -0
  125. package/dist/oracle/adapters/xenova-embedder.js +36 -0
  126. package/dist/oracle/adapters/xenova-embedder.js.map +1 -0
  127. package/dist/oracle/bm25.d.ts +20 -0
  128. package/dist/oracle/bm25.d.ts.map +1 -0
  129. package/dist/oracle/bm25.js +82 -0
  130. package/dist/oracle/bm25.js.map +1 -0
  131. package/dist/oracle/index.d.ts +21 -0
  132. package/dist/oracle/index.d.ts.map +1 -0
  133. package/dist/oracle/index.js +25 -0
  134. package/dist/oracle/index.js.map +1 -0
  135. package/dist/oracle/log.d.ts +6 -0
  136. package/dist/oracle/log.d.ts.map +1 -0
  137. package/dist/oracle/log.js +12 -0
  138. package/dist/oracle/log.js.map +1 -0
  139. package/dist/oracle/propose.d.ts +25 -0
  140. package/dist/oracle/propose.d.ts.map +1 -0
  141. package/dist/oracle/propose.js +133 -0
  142. package/dist/oracle/propose.js.map +1 -0
  143. package/dist/oracle/query.d.ts +17 -0
  144. package/dist/oracle/query.d.ts.map +1 -0
  145. package/dist/oracle/query.js +106 -0
  146. package/dist/oracle/query.js.map +1 -0
  147. package/dist/oracle/summary.d.ts +11 -0
  148. package/dist/oracle/summary.d.ts.map +1 -0
  149. package/dist/oracle/summary.js +102 -0
  150. package/dist/oracle/summary.js.map +1 -0
  151. package/dist/oracle/types.d.ts +31 -0
  152. package/dist/oracle/types.d.ts.map +1 -0
  153. package/dist/oracle/types.js +2 -0
  154. package/dist/oracle/types.js.map +1 -0
  155. package/dist/sentinel/assert.d.ts +28 -0
  156. package/dist/sentinel/assert.d.ts.map +1 -0
  157. package/dist/sentinel/assert.js +63 -0
  158. package/dist/sentinel/assert.js.map +1 -0
  159. package/dist/sentinel/coverage.d.ts +14 -0
  160. package/dist/sentinel/coverage.d.ts.map +1 -0
  161. package/dist/sentinel/coverage.js +96 -0
  162. package/dist/sentinel/coverage.js.map +1 -0
  163. package/dist/sentinel/drift.d.ts +12 -0
  164. package/dist/sentinel/drift.d.ts.map +1 -0
  165. package/dist/sentinel/drift.js +149 -0
  166. package/dist/sentinel/drift.js.map +1 -0
  167. package/dist/sentinel/index.d.ts +7 -0
  168. package/dist/sentinel/index.d.ts.map +1 -0
  169. package/dist/sentinel/index.js +5 -0
  170. package/dist/sentinel/index.js.map +1 -0
  171. package/dist/sentinel/review.d.ts +15 -0
  172. package/dist/sentinel/review.d.ts.map +1 -0
  173. package/dist/sentinel/review.js +177 -0
  174. package/dist/sentinel/review.js.map +1 -0
  175. package/dist/setup.d.ts +103 -0
  176. package/dist/setup.d.ts.map +1 -0
  177. package/dist/setup.js +87 -0
  178. package/dist/setup.js.map +1 -0
  179. package/dist/shared/types.d.ts +173 -0
  180. package/dist/shared/types.d.ts.map +1 -0
  181. package/dist/shared/types.js +16 -0
  182. package/dist/shared/types.js.map +1 -0
  183. package/package.json +13 -8
  184. package/.github/copilot-instructions.md +0 -117
  185. package/CLAUDE.md +0 -146
  186. package/GEMINI.md +0 -73
  187. package/SETUP.md +0 -264
  188. package/evals/__tests__/eval.test.ts +0 -31
  189. package/evals/cases/auth_hs256_rejected.json +0 -46
  190. package/evals/cases/auth_rs256_valid.json +0 -30
  191. package/evals/cases/cache_missing_lock.json +0 -31
  192. package/evals/cases/db_naive_not_null.json +0 -32
  193. package/evals/cases/logging_pii_leak.json +0 -32
  194. package/evals/cases/migration_with_rollback.json +0 -43
  195. package/evals/cases/no_evidence_novel_design.json +0 -16
  196. package/evals/cases/payment_no_idempotency.json +0 -33
  197. package/evals/cases/redis_session_rejected.json +0 -32
  198. package/evals/cases/safe_refactor.json +0 -17
  199. package/evals/runner.ts +0 -226
  200. package/modules/AGENTS.md +0 -78
  201. package/modules/CLAUDE.md +0 -93
  202. package/modules/README.md +0 -504
  203. package/modules/advisor/ask.ts +0 -87
  204. package/modules/advisor/index.ts +0 -2
  205. package/modules/advisor/types.ts +0 -26
  206. package/modules/compass/behavior.ts +0 -161
  207. package/modules/compass/create.ts +0 -365
  208. package/modules/compass/evidence/collect.ts +0 -109
  209. package/modules/compass/index.ts +0 -7
  210. package/modules/compass/propose.ts +0 -152
  211. package/modules/compass/schemas.ts +0 -121
  212. package/modules/compass/score.ts +0 -77
  213. package/modules/compass/sources/index.ts +0 -413
  214. package/modules/compass/types.ts +0 -431
  215. package/modules/council/advisors.ts +0 -71
  216. package/modules/council/chairman.ts +0 -183
  217. package/modules/council/deliberate.ts +0 -141
  218. package/modules/council/frame.ts +0 -54
  219. package/modules/council/index.ts +0 -9
  220. package/modules/council/personas.ts +0 -57
  221. package/modules/council/reviewers.ts +0 -82
  222. package/modules/council/risk.ts +0 -89
  223. package/modules/council/types.ts +0 -107
  224. package/modules/jury/index.ts +0 -5
  225. package/modules/jury/preflight.ts +0 -101
  226. package/modules/jury/schema.ts +0 -24
  227. package/modules/jury/types.ts +0 -50
  228. package/modules/oracle/adapters/lance-db.ts +0 -81
  229. package/modules/oracle/adapters/xenova-embedder.ts +0 -43
  230. package/modules/oracle/bm25.ts +0 -92
  231. package/modules/oracle/index.ts +0 -36
  232. package/modules/oracle/log.ts +0 -15
  233. package/modules/oracle/propose.ts +0 -164
  234. package/modules/oracle/query.ts +0 -146
  235. package/modules/oracle/summary.ts +0 -116
  236. package/modules/oracle/types.ts +0 -32
  237. package/modules/sentinel/assert.ts +0 -95
  238. package/modules/sentinel/coverage.ts +0 -106
  239. package/modules/sentinel/drift.ts +0 -163
  240. package/modules/sentinel/index.ts +0 -6
  241. package/modules/sentinel/review.ts +0 -208
  242. package/modules/setup.ts +0 -202
  243. package/modules/shared/types.ts +0 -193
@@ -1,413 +0,0 @@
1
- import type { ProductSource, ProductSourceFinding, ProductSourceScanInput } from "../types"
2
-
3
- export function docsSource(): ProductSource {
4
- return {
5
- id: "docs",
6
- kind: "docs",
7
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
8
- const { promises: fs } = await import("fs")
9
- const path = await import("path")
10
-
11
- const targets = [
12
- "README.md",
13
- "SETUP.md",
14
- "CLAUDE.md",
15
- "AGENTS.md",
16
- "GEMINI.md",
17
- "modules/README.md",
18
- "quorum/CLAUDE.md",
19
- "quorum/SETUP.md",
20
- "docs",
21
- ]
22
-
23
- const findings: ProductSourceFinding[] = []
24
- let idx = 0
25
-
26
- async function scanMarkdown(filePath: string): Promise<void> {
27
- let content: string
28
- try {
29
- content = await fs.readFile(filePath, "utf8")
30
- } catch {
31
- return
32
- }
33
- const rel = path.relative(input.rootDir, filePath).replace(/\\/g, "/")
34
- const lines = content.split("\n")
35
-
36
- // Extract headings as structural claims
37
- for (let i = 0; i < lines.length; i++) {
38
- const line = lines[i]
39
- const headingMatch = line.match(/^#{1,3}\s+(.+)/)
40
- if (headingMatch) {
41
- const heading = headingMatch[1].trim()
42
- // Grab up to 3 lines of context below
43
- const context = lines
44
- .slice(i + 1, i + 4)
45
- .join(" ")
46
- .replace(/```[^`]*```/g, "")
47
- .trim()
48
- .slice(0, 200)
49
- findings.push({
50
- id: `docs-${idx++}`,
51
- kind: "docs",
52
- source: rel,
53
- path: rel,
54
- line: i + 1,
55
- title: heading,
56
- summary: context || heading,
57
- confidence: 0.8,
58
- tags: inferTags(heading + " " + context),
59
- })
60
- }
61
-
62
- // Extract CLI code blocks (``` lines starting with quorum)
63
- if (line.trim().startsWith("quorum ") || line.trim().startsWith("npx quorum")) {
64
- const cmd = line.trim()
65
- findings.push({
66
- id: `docs-cmd-${idx++}`,
67
- kind: "docs",
68
- source: rel,
69
- path: rel,
70
- line: i + 1,
71
- title: `CLI usage: ${cmd.slice(0, 60)}`,
72
- summary: `Documented command: ${cmd}`,
73
- confidence: 0.85,
74
- tags: ["cli", "command", ...inferTags(cmd)],
75
- })
76
- }
77
- }
78
- }
79
-
80
- async function scanDir(dir: string): Promise<void> {
81
- let entries
82
- try {
83
- entries = await fs.readdir(dir, { withFileTypes: true })
84
- } catch {
85
- return
86
- }
87
- for (const entry of entries) {
88
- const full = path.join(dir, entry.name)
89
- if (entry.isDirectory() && !["node_modules", ".git", "dist"].includes(entry.name)) {
90
- await scanDir(full)
91
- } else if (entry.isFile() && entry.name.endsWith(".md")) {
92
- await scanMarkdown(full)
93
- }
94
- }
95
- }
96
-
97
- for (const target of targets) {
98
- const full = path.join(input.rootDir, target)
99
- let stat
100
- try { stat = await fs.stat(full) } catch { continue }
101
- if (stat.isDirectory()) {
102
- await scanDir(full)
103
- } else {
104
- await scanMarkdown(full)
105
- }
106
- }
107
-
108
- return area(input.area, findings)
109
- },
110
- }
111
- }
112
-
113
- export function packageSource(): ProductSource {
114
- return {
115
- id: "package",
116
- kind: "package",
117
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
118
- const { promises: fs } = await import("fs")
119
- const path = await import("path")
120
- const pkgPath = path.join(input.rootDir, "package.json")
121
- let pkg: Record<string, unknown>
122
- try {
123
- pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"))
124
- } catch {
125
- return []
126
- }
127
-
128
- const findings: ProductSourceFinding[] = []
129
- let idx = 0
130
-
131
- if (pkg.name) findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: "Package name", summary: `Published as: ${pkg.name}`, confidence: 1, tags: ["package", "identity"] })
132
- if (pkg.description) findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: "Package description", summary: String(pkg.description), confidence: 1, tags: ["package", "description"] })
133
- if (pkg.bin) {
134
- for (const [name, entry] of Object.entries(pkg.bin as Record<string, string>)) {
135
- findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: `CLI binary: ${name}`, summary: `CLI binary '${name}' at ${entry}`, confidence: 1, tags: ["cli", "binary"] })
136
- }
137
- }
138
- if (pkg.scripts) {
139
- for (const [name, cmd] of Object.entries(pkg.scripts as Record<string, string>)) {
140
- findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: `Script: ${name}`, summary: `npm run ${name}: ${cmd}`, confidence: 0.9, tags: ["script", name] })
141
- }
142
- }
143
- if (pkg.exports) {
144
- findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: "Package exports", summary: `Exports: ${JSON.stringify(pkg.exports)}`, confidence: 0.95, tags: ["exports", "api"] })
145
- }
146
- if (pkg.engines) {
147
- findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: "Engine requirements", summary: `Node: ${(pkg.engines as Record<string, string>).node ?? "unspecified"}`, confidence: 1, tags: ["runtime", "engines"] })
148
- }
149
- const deps = { ...(pkg.dependencies as Record<string, string> ?? {}), ...(pkg.optionalDependencies as Record<string, string> ?? {}) }
150
- if (Object.keys(deps).length > 0) {
151
- findings.push({ id: `pkg-${idx++}`, kind: "package", source: "package.json", title: "Runtime dependencies", summary: Object.keys(deps).join(", "), confidence: 0.9, tags: ["dependencies"] })
152
- }
153
-
154
- return findings
155
- },
156
- }
157
- }
158
-
159
- export function cliSource(): ProductSource {
160
- return {
161
- id: "cli",
162
- kind: "cli",
163
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
164
- const { promises: fs } = await import("fs")
165
- const path = await import("path")
166
-
167
- const findings: ProductSourceFinding[] = []
168
- let idx = 0
169
-
170
- const binDir = path.join(input.rootDir, "bin", "commands")
171
- let commandFiles: string[] = []
172
- try {
173
- commandFiles = (await fs.readdir(binDir)).filter(f => f.endsWith(".js"))
174
- } catch {
175
- return []
176
- }
177
-
178
- for (const file of commandFiles) {
179
- const cmdName = file.replace(".js", "")
180
- const filePath = path.join(binDir, file)
181
- let content: string
182
- try { content = await fs.readFile(filePath, "utf8") } catch { continue }
183
-
184
- const relPath = `bin/commands/${file}`
185
-
186
- // Detect subcommands from switch/if patterns
187
- const subcmdMatches = [...content.matchAll(/case ["']([a-z-]+)["']/g)]
188
- const subcommands = subcmdMatches.map(m => m[1])
189
-
190
- // Detect flags
191
- const flagMatches = [...content.matchAll(/["'](--[a-z-]+)["']/g)]
192
- const flags = [...new Set(flagMatches.map(m => m[1]))]
193
-
194
- // Detect LLM usage
195
- const usesLLM = /llm|LLM|provider|model/.test(content)
196
-
197
- // Detect Chronicle reads/writes
198
- const readsChronicle = /readCommitted|findChronicleDir|committed/.test(content)
199
- const writesChronicle = /writeFile.*proposals|proposals.*writeFile|oracle\.propose/.test(content)
200
-
201
- findings.push({
202
- id: `cli-${idx++}`,
203
- kind: "cli",
204
- source: relPath,
205
- path: relPath,
206
- title: `Command: quorum ${cmdName}`,
207
- summary: [
208
- `quorum ${cmdName}`,
209
- subcommands.length > 0 ? `Subcommands: ${subcommands.join(", ")}` : "",
210
- flags.length > 0 ? `Flags: ${flags.slice(0, 8).join(", ")}` : "",
211
- usesLLM ? "Uses LLM" : "No LLM required",
212
- readsChronicle ? "Reads Chronicle" : "",
213
- writesChronicle ? "Writes Chronicle proposals" : "",
214
- ].filter(Boolean).join(" | "),
215
- confidence: 0.9,
216
- tags: [
217
- "cli", "command", cmdName,
218
- ...subcommands.map(s => `subcommand:${s}`),
219
- usesLLM ? "llm" : "deterministic",
220
- readsChronicle ? "chronicle" : "",
221
- ].filter(Boolean),
222
- })
223
- }
224
-
225
- return area(input.area, findings)
226
- },
227
- }
228
- }
229
-
230
- export function repoSource(): ProductSource {
231
- return {
232
- id: "repo",
233
- kind: "code",
234
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
235
- const { promises: fs } = await import("fs")
236
- const path = await import("path")
237
-
238
- const findings: ProductSourceFinding[] = []
239
- let idx = 0
240
-
241
- // Scan modules/
242
- const modulesDir = path.join(input.rootDir, "modules")
243
- try {
244
- const entries = await fs.readdir(modulesDir, { withFileTypes: true })
245
- for (const entry of entries) {
246
- if (entry.isDirectory() && !entry.name.startsWith("_") && !["shared"].includes(entry.name)) {
247
- findings.push({
248
- id: `repo-module-${idx++}`,
249
- kind: "code",
250
- source: `modules/${entry.name}/`,
251
- path: `modules/${entry.name}/`,
252
- title: `Module: ${entry.name}`,
253
- summary: `TypeScript module: modules/${entry.name}/`,
254
- confidence: 0.85,
255
- tags: ["module", entry.name, "code"],
256
- })
257
- }
258
- }
259
- } catch { /* no modules dir */ }
260
-
261
- // Scan workflows
262
- const workflowsDir = path.join(input.rootDir, ".github", "workflows")
263
- try {
264
- const entries = await fs.readdir(workflowsDir)
265
- for (const file of entries.filter(f => f.endsWith(".yml"))) {
266
- const content = await fs.readFile(path.join(workflowsDir, file), "utf8")
267
- const nameMatch = content.match(/^name:\s*(.+)$/m)
268
- findings.push({
269
- id: `repo-workflow-${idx++}`,
270
- kind: "config",
271
- source: `.github/workflows/${file}`,
272
- path: `.github/workflows/${file}`,
273
- title: `Workflow: ${nameMatch?.[1]?.trim() ?? file}`,
274
- summary: `CI/CD workflow: ${nameMatch?.[1]?.trim() ?? file}`,
275
- confidence: 0.8,
276
- tags: ["workflow", "ci", "github-actions"],
277
- })
278
- }
279
- } catch { /* no workflows */ }
280
-
281
- return area(input.area, findings)
282
- },
283
- }
284
- }
285
-
286
- export function testsSource(): ProductSource {
287
- return {
288
- id: "tests",
289
- kind: "tests",
290
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
291
- const { promises: fs } = await import("fs")
292
- const path = await import("path")
293
-
294
- const findings: ProductSourceFinding[] = []
295
- let idx = 0
296
-
297
- async function walkTests(dir: string): Promise<void> {
298
- let entries
299
- try { entries = await fs.readdir(dir, { withFileTypes: true }) } catch { return }
300
- for (const entry of entries) {
301
- const full = path.join(dir, entry.name)
302
- if (entry.isDirectory() && !["node_modules", "dist"].includes(entry.name)) {
303
- await walkTests(full)
304
- } else if (entry.isFile() && (entry.name.endsWith(".test.ts") || entry.name.endsWith(".test.js"))) {
305
- let content: string
306
- try { content = await fs.readFile(full, "utf8") } catch { continue }
307
- const rel = path.relative(input.rootDir, full).replace(/\\/g, "/")
308
- // Extract describe/it/test names
309
- const describeMatches = [...content.matchAll(/(?:describe|it|test)\s*\(\s*["'`]([^"'`]+)/g)]
310
- const behaviors = describeMatches.map(m => m[1]).slice(0, 5)
311
- if (behaviors.length > 0) {
312
- findings.push({
313
- id: `test-${idx++}`,
314
- kind: "tests",
315
- source: rel,
316
- path: rel,
317
- title: `Test: ${path.basename(entry.name, ".test.ts")}`,
318
- summary: `Regression-protected: ${behaviors.join("; ")}`,
319
- confidence: 0.85,
320
- tags: ["test", "guaranteed-behavior", ...inferTags(behaviors.join(" "))],
321
- })
322
- }
323
- }
324
- }
325
- }
326
-
327
- await walkTests(path.join(input.rootDir, "modules"))
328
- await walkTests(path.join(input.rootDir, "evals"))
329
-
330
- return area(input.area, findings)
331
- },
332
- }
333
- }
334
-
335
- export function configSource(): ProductSource {
336
- return {
337
- id: "config",
338
- kind: "config",
339
- async scan(input: ProductSourceScanInput): Promise<ProductSourceFinding[]> {
340
- const { promises: fs } = await import("fs")
341
- const path = await import("path")
342
-
343
- const findings: ProductSourceFinding[] = []
344
- let idx = 0
345
-
346
- const configFiles = ["tsconfig.json", ".npmignore", ".gitignore"]
347
- for (const file of configFiles) {
348
- let content: string
349
- try { content = await fs.readFile(path.join(input.rootDir, file), "utf8") } catch { continue }
350
- findings.push({
351
- id: `cfg-${idx++}`,
352
- kind: "config",
353
- source: file,
354
- path: file,
355
- title: `Config: ${file}`,
356
- summary: `${file} — ${content.slice(0, 100).replace(/\n/g, " ").trim()}`,
357
- confidence: 0.75,
358
- tags: ["config", file.replace(/[^a-z]/gi, "-")],
359
- })
360
- }
361
- return findings
362
- },
363
- }
364
- }
365
-
366
- // ── Helpers ────────────────────────────────────────────────────────────────────
367
-
368
- function inferTags(text: string): string[] {
369
- const tags: string[] = []
370
- const lower = text.toLowerCase()
371
- const patterns: [RegExp, string][] = [
372
- [/onboard|init|install|setup|get.?started/, "onboarding"],
373
- [/auth|jwt|session|login|token/, "auth"],
374
- [/database|migration|sql|postgres|mysql/, "database"],
375
- [/payment|stripe|billing|checkout/, "payments"],
376
- [/pii|privacy|gdpr|personal.?data/, "pii"],
377
- [/commit|proposal|review|approve|memory/, "chronicle"],
378
- [/advisor|brief|query/, "advisor"],
379
- [/sentinel|coverage|drift/, "sentinel"],
380
- [/jury|evaluate|score/, "jury"],
381
- [/council|deliberate|validate/, "council"],
382
- [/compass|pathway|bet|direction/, "compass"],
383
- [/cli|command|terminal/, "cli"],
384
- [/test|eval|spec/, "testing"],
385
- [/llm|gpt|claude|openai|anthropic|gemini/, "llm"],
386
- ]
387
- for (const [rx, tag] of patterns) {
388
- if (rx.test(lower)) tags.push(tag)
389
- }
390
- return tags
391
- }
392
-
393
- function area(filterArea: string | undefined, findings: ProductSourceFinding[]): ProductSourceFinding[] {
394
- if (!filterArea) return findings
395
- const lower = filterArea.toLowerCase()
396
- return findings.filter(f =>
397
- f.tags.some(t => t.toLowerCase().includes(lower)) ||
398
- f.summary.toLowerCase().includes(lower) ||
399
- f.title.toLowerCase().includes(lower),
400
- )
401
- }
402
-
403
- // Re-export all sources as a convenience default set
404
- export function defaultSources(): ProductSource[] {
405
- return [
406
- docsSource(),
407
- packageSource(),
408
- cliSource(),
409
- repoSource(),
410
- testsSource(),
411
- configSource(),
412
- ]
413
- }