agent-bober 0.6.2 → 0.8.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 (190) hide show
  1. package/README.md +220 -30
  2. package/dist/cli/commands/eval.d.ts +2 -0
  3. package/dist/cli/commands/eval.d.ts.map +1 -1
  4. package/dist/cli/commands/eval.js +10 -0
  5. package/dist/cli/commands/eval.js.map +1 -1
  6. package/dist/cli/commands/init.d.ts.map +1 -1
  7. package/dist/cli/commands/init.js +357 -62
  8. package/dist/cli/commands/init.js.map +1 -1
  9. package/dist/cli/commands/plan.d.ts +2 -0
  10. package/dist/cli/commands/plan.d.ts.map +1 -1
  11. package/dist/cli/commands/plan.js +10 -0
  12. package/dist/cli/commands/plan.js.map +1 -1
  13. package/dist/cli/commands/run.d.ts +2 -0
  14. package/dist/cli/commands/run.d.ts.map +1 -1
  15. package/dist/cli/commands/run.js +10 -0
  16. package/dist/cli/commands/run.js.map +1 -1
  17. package/dist/cli/commands/sprint.d.ts +2 -0
  18. package/dist/cli/commands/sprint.d.ts.map +1 -1
  19. package/dist/cli/commands/sprint.js +10 -0
  20. package/dist/cli/commands/sprint.js.map +1 -1
  21. package/dist/cli/index.js +22 -2
  22. package/dist/cli/index.js.map +1 -1
  23. package/dist/config/schema.d.ts +160 -43
  24. package/dist/config/schema.d.ts.map +1 -1
  25. package/dist/config/schema.js +11 -7
  26. package/dist/config/schema.js.map +1 -1
  27. package/dist/contracts/sprint-contract.d.ts +8 -8
  28. package/dist/discovery/config-generator.d.ts +28 -0
  29. package/dist/discovery/config-generator.d.ts.map +1 -0
  30. package/dist/discovery/config-generator.js +225 -0
  31. package/dist/discovery/config-generator.js.map +1 -0
  32. package/dist/discovery/index.d.ts +20 -0
  33. package/dist/discovery/index.d.ts.map +1 -0
  34. package/dist/discovery/index.js +19 -0
  35. package/dist/discovery/index.js.map +1 -0
  36. package/dist/discovery/scanner.d.ts +17 -0
  37. package/dist/discovery/scanner.d.ts.map +1 -0
  38. package/dist/discovery/scanner.js +120 -0
  39. package/dist/discovery/scanner.js.map +1 -0
  40. package/dist/discovery/scanners/ci-checks.d.ts +10 -0
  41. package/dist/discovery/scanners/ci-checks.d.ts.map +1 -0
  42. package/dist/discovery/scanners/ci-checks.js +169 -0
  43. package/dist/discovery/scanners/ci-checks.js.map +1 -0
  44. package/dist/discovery/scanners/code-conventions.d.ts +12 -0
  45. package/dist/discovery/scanners/code-conventions.d.ts.map +1 -0
  46. package/dist/discovery/scanners/code-conventions.js +216 -0
  47. package/dist/discovery/scanners/code-conventions.js.map +1 -0
  48. package/dist/discovery/scanners/documentation.d.ts +17 -0
  49. package/dist/discovery/scanners/documentation.d.ts.map +1 -0
  50. package/dist/discovery/scanners/documentation.js +92 -0
  51. package/dist/discovery/scanners/documentation.js.map +1 -0
  52. package/dist/discovery/scanners/git-conventions.d.ts +11 -0
  53. package/dist/discovery/scanners/git-conventions.d.ts.map +1 -0
  54. package/dist/discovery/scanners/git-conventions.js +128 -0
  55. package/dist/discovery/scanners/git-conventions.js.map +1 -0
  56. package/dist/discovery/scanners/package-scripts.d.ts +9 -0
  57. package/dist/discovery/scanners/package-scripts.d.ts.map +1 -0
  58. package/dist/discovery/scanners/package-scripts.js +112 -0
  59. package/dist/discovery/scanners/package-scripts.js.map +1 -0
  60. package/dist/discovery/scanners/test-conventions.d.ts +9 -0
  61. package/dist/discovery/scanners/test-conventions.d.ts.map +1 -0
  62. package/dist/discovery/scanners/test-conventions.js +231 -0
  63. package/dist/discovery/scanners/test-conventions.js.map +1 -0
  64. package/dist/discovery/synthesizer.d.ts +30 -0
  65. package/dist/discovery/synthesizer.d.ts.map +1 -0
  66. package/dist/discovery/synthesizer.js +348 -0
  67. package/dist/discovery/synthesizer.js.map +1 -0
  68. package/dist/discovery/types.d.ts +160 -0
  69. package/dist/discovery/types.d.ts.map +1 -0
  70. package/dist/discovery/types.js +9 -0
  71. package/dist/discovery/types.js.map +1 -0
  72. package/dist/index.d.ts +12 -0
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +12 -0
  75. package/dist/index.js.map +1 -1
  76. package/dist/mcp/index.d.ts +4 -0
  77. package/dist/mcp/index.d.ts.map +1 -0
  78. package/dist/mcp/index.js +4 -0
  79. package/dist/mcp/index.js.map +1 -0
  80. package/dist/mcp/run-manager.d.ts +47 -0
  81. package/dist/mcp/run-manager.d.ts.map +1 -0
  82. package/dist/mcp/run-manager.js +79 -0
  83. package/dist/mcp/run-manager.js.map +1 -0
  84. package/dist/mcp/server.d.ts +15 -0
  85. package/dist/mcp/server.d.ts.map +1 -0
  86. package/dist/mcp/server.js +107 -0
  87. package/dist/mcp/server.js.map +1 -0
  88. package/dist/mcp/tools/config.d.ts +2 -0
  89. package/dist/mcp/tools/config.d.ts.map +1 -0
  90. package/dist/mcp/tools/config.js +153 -0
  91. package/dist/mcp/tools/config.js.map +1 -0
  92. package/dist/mcp/tools/contracts.d.ts +2 -0
  93. package/dist/mcp/tools/contracts.d.ts.map +1 -0
  94. package/dist/mcp/tools/contracts.js +61 -0
  95. package/dist/mcp/tools/contracts.js.map +1 -0
  96. package/dist/mcp/tools/eval.d.ts +2 -0
  97. package/dist/mcp/tools/eval.d.ts.map +1 -0
  98. package/dist/mcp/tools/eval.js +157 -0
  99. package/dist/mcp/tools/eval.js.map +1 -0
  100. package/dist/mcp/tools/index.d.ts +20 -0
  101. package/dist/mcp/tools/index.d.ts.map +1 -0
  102. package/dist/mcp/tools/index.js +47 -0
  103. package/dist/mcp/tools/index.js.map +1 -0
  104. package/dist/mcp/tools/init.d.ts +2 -0
  105. package/dist/mcp/tools/init.d.ts.map +1 -0
  106. package/dist/mcp/tools/init.js +222 -0
  107. package/dist/mcp/tools/init.js.map +1 -0
  108. package/dist/mcp/tools/plan.d.ts +2 -0
  109. package/dist/mcp/tools/plan.d.ts.map +1 -0
  110. package/dist/mcp/tools/plan.js +97 -0
  111. package/dist/mcp/tools/plan.js.map +1 -0
  112. package/dist/mcp/tools/principles.d.ts +2 -0
  113. package/dist/mcp/tools/principles.d.ts.map +1 -0
  114. package/dist/mcp/tools/principles.js +66 -0
  115. package/dist/mcp/tools/principles.js.map +1 -0
  116. package/dist/mcp/tools/registry.d.ts +45 -0
  117. package/dist/mcp/tools/registry.d.ts.map +1 -0
  118. package/dist/mcp/tools/registry.js +23 -0
  119. package/dist/mcp/tools/registry.js.map +1 -0
  120. package/dist/mcp/tools/run.d.ts +2 -0
  121. package/dist/mcp/tools/run.d.ts.map +1 -0
  122. package/dist/mcp/tools/run.js +66 -0
  123. package/dist/mcp/tools/run.js.map +1 -0
  124. package/dist/mcp/tools/spec.d.ts +2 -0
  125. package/dist/mcp/tools/spec.d.ts.map +1 -0
  126. package/dist/mcp/tools/spec.js +32 -0
  127. package/dist/mcp/tools/spec.js.map +1 -0
  128. package/dist/mcp/tools/sprint.d.ts +2 -0
  129. package/dist/mcp/tools/sprint.d.ts.map +1 -0
  130. package/dist/mcp/tools/sprint.js +243 -0
  131. package/dist/mcp/tools/sprint.js.map +1 -0
  132. package/dist/mcp/tools/status.d.ts +2 -0
  133. package/dist/mcp/tools/status.d.ts.map +1 -0
  134. package/dist/mcp/tools/status.js +76 -0
  135. package/dist/mcp/tools/status.js.map +1 -0
  136. package/dist/orchestrator/agentic-loop.d.ts +7 -6
  137. package/dist/orchestrator/agentic-loop.d.ts.map +1 -1
  138. package/dist/orchestrator/agentic-loop.js +33 -40
  139. package/dist/orchestrator/agentic-loop.js.map +1 -1
  140. package/dist/orchestrator/context-handoff.d.ts +20 -20
  141. package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
  142. package/dist/orchestrator/evaluator-agent.js +2 -2
  143. package/dist/orchestrator/evaluator-agent.js.map +1 -1
  144. package/dist/orchestrator/generator-agent.d.ts.map +1 -1
  145. package/dist/orchestrator/generator-agent.js +2 -2
  146. package/dist/orchestrator/generator-agent.js.map +1 -1
  147. package/dist/orchestrator/model-resolver.d.ts +35 -4
  148. package/dist/orchestrator/model-resolver.d.ts.map +1 -1
  149. package/dist/orchestrator/model-resolver.js +68 -15
  150. package/dist/orchestrator/model-resolver.js.map +1 -1
  151. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  152. package/dist/orchestrator/planner-agent.js +2 -2
  153. package/dist/orchestrator/planner-agent.js.map +1 -1
  154. package/dist/orchestrator/tools/index.d.ts +3 -4
  155. package/dist/orchestrator/tools/index.d.ts.map +1 -1
  156. package/dist/orchestrator/tools/index.js.map +1 -1
  157. package/dist/orchestrator/tools/schemas.d.ts +11 -12
  158. package/dist/orchestrator/tools/schemas.d.ts.map +1 -1
  159. package/dist/orchestrator/tools/schemas.js +3 -2
  160. package/dist/orchestrator/tools/schemas.js.map +1 -1
  161. package/dist/providers/anthropic.d.ts +15 -0
  162. package/dist/providers/anthropic.d.ts.map +1 -0
  163. package/dist/providers/anthropic.js +133 -0
  164. package/dist/providers/anthropic.js.map +1 -0
  165. package/dist/providers/factory.d.ts +37 -0
  166. package/dist/providers/factory.d.ts.map +1 -0
  167. package/dist/providers/factory.js +119 -0
  168. package/dist/providers/factory.js.map +1 -0
  169. package/dist/providers/google.d.ts +39 -0
  170. package/dist/providers/google.d.ts.map +1 -0
  171. package/dist/providers/google.js +195 -0
  172. package/dist/providers/google.js.map +1 -0
  173. package/dist/providers/index.d.ts +7 -0
  174. package/dist/providers/index.d.ts.map +1 -0
  175. package/dist/providers/index.js +6 -0
  176. package/dist/providers/index.js.map +1 -0
  177. package/dist/providers/openai-compat.d.ts +39 -0
  178. package/dist/providers/openai-compat.d.ts.map +1 -0
  179. package/dist/providers/openai-compat.js +42 -0
  180. package/dist/providers/openai-compat.js.map +1 -0
  181. package/dist/providers/openai.d.ts +41 -0
  182. package/dist/providers/openai.d.ts.map +1 -0
  183. package/dist/providers/openai.js +205 -0
  184. package/dist/providers/openai.js.map +1 -0
  185. package/dist/providers/types.d.ts +144 -0
  186. package/dist/providers/types.d.ts.map +1 -0
  187. package/dist/providers/types.js +8 -0
  188. package/dist/providers/types.js.map +1 -0
  189. package/package.json +22 -4
  190. package/skills/bober.principles/SKILL.md +36 -3
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Scanner: Test Conventions
3
+ *
4
+ * Detects test framework, file naming patterns, directory structure,
5
+ * mocking library, and coverage configuration.
6
+ */
7
+ import { readFile } from "node:fs/promises";
8
+ import { join, dirname, relative } from "node:path";
9
+ import { glob } from "glob";
10
+ import { fileExists } from "../../utils/fs.js";
11
+ // ── Constants ─────────────────────────────────────────────────────
12
+ const IGNORE_DIRS = [
13
+ "node_modules",
14
+ "dist",
15
+ ".git",
16
+ ".bober",
17
+ "build",
18
+ "coverage",
19
+ ".next",
20
+ "__pycache__",
21
+ ".turbo",
22
+ ".cache",
23
+ "out",
24
+ ".vercel",
25
+ ];
26
+ async function readPackageJson(projectRoot) {
27
+ const pkgPath = join(projectRoot, "package.json");
28
+ if (!(await fileExists(pkgPath)))
29
+ return null;
30
+ try {
31
+ const raw = await readFile(pkgPath, "utf-8");
32
+ return JSON.parse(raw);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ function detectFramework(pkg) {
39
+ if (!pkg)
40
+ return "unknown";
41
+ const allDeps = {
42
+ ...(pkg.dependencies ?? {}),
43
+ ...(pkg.devDependencies ?? {}),
44
+ };
45
+ if ("vitest" in allDeps)
46
+ return "vitest";
47
+ if ("jest" in allDeps)
48
+ return "jest";
49
+ if ("mocha" in allDeps)
50
+ return "mocha";
51
+ if ("jasmine" in allDeps)
52
+ return "jasmine";
53
+ if ("pytest" in allDeps)
54
+ return "pytest";
55
+ // Check scripts for clues
56
+ const scripts = pkg.scripts ?? {};
57
+ const testScript = Object.values(scripts).join(" ").toLowerCase();
58
+ if (testScript.includes("vitest"))
59
+ return "vitest";
60
+ if (testScript.includes("jest"))
61
+ return "jest";
62
+ if (testScript.includes("mocha"))
63
+ return "mocha";
64
+ if (testScript.includes("pytest"))
65
+ return "pytest";
66
+ return "unknown";
67
+ }
68
+ function detectMockingLibrary(pkg, framework) {
69
+ if (!pkg)
70
+ return "unknown";
71
+ const allDeps = {
72
+ ...(pkg.dependencies ?? {}),
73
+ ...(pkg.devDependencies ?? {}),
74
+ };
75
+ // vitest and jest have built-in mocking
76
+ if (framework === "vitest")
77
+ return "vitest";
78
+ if (framework === "jest")
79
+ return "jest";
80
+ if ("sinon" in allDeps)
81
+ return "sinon";
82
+ if ("testdouble" in allDeps)
83
+ return "testdouble";
84
+ return "none";
85
+ }
86
+ function detectFilePattern(testFiles) {
87
+ let testTs = 0;
88
+ let specTs = 0;
89
+ let testJs = 0;
90
+ let specJs = 0;
91
+ for (const f of testFiles) {
92
+ if (f.endsWith(".test.ts") || f.endsWith(".test.tsx"))
93
+ testTs++;
94
+ else if (f.endsWith(".spec.ts") || f.endsWith(".spec.tsx"))
95
+ specTs++;
96
+ else if (f.endsWith(".test.js") || f.endsWith(".test.jsx"))
97
+ testJs++;
98
+ else if (f.endsWith(".spec.js") || f.endsWith(".spec.jsx"))
99
+ specJs++;
100
+ }
101
+ const total = testTs + specTs + testJs + specJs;
102
+ if (total === 0)
103
+ return "unknown";
104
+ const counts = [
105
+ ["*.test.ts", testTs],
106
+ ["*.spec.ts", specTs],
107
+ ["*.test.js", testJs],
108
+ ["*.spec.js", specJs],
109
+ ];
110
+ const [dominant] = counts.sort((a, b) => b[1] - a[1]);
111
+ if (!dominant)
112
+ return "unknown";
113
+ // If dominant pattern accounts for >= 80% of test files, use it
114
+ if (dominant[1] / total >= 0.8)
115
+ return dominant[0];
116
+ return "mixed";
117
+ }
118
+ // ── Directory structure detection ─────────────────────────────────
119
+ function detectColocated(testFiles, projectRoot) {
120
+ if (testFiles.length === 0)
121
+ return false;
122
+ let colocatedCount = 0;
123
+ let separateCount = 0;
124
+ for (const filePath of testFiles) {
125
+ const rel = relative(projectRoot, filePath);
126
+ const dir = dirname(rel);
127
+ if (dir.includes("__tests__") ||
128
+ dir.startsWith("test/") ||
129
+ dir.startsWith("tests/") ||
130
+ dir === "test" ||
131
+ dir === "tests") {
132
+ separateCount++;
133
+ }
134
+ else {
135
+ colocatedCount++;
136
+ }
137
+ }
138
+ return colocatedCount >= separateCount;
139
+ }
140
+ function extractTestDirs(testFiles, projectRoot) {
141
+ const dirs = new Set();
142
+ for (const filePath of testFiles) {
143
+ const rel = relative(projectRoot, filePath);
144
+ const dir = dirname(rel);
145
+ if (dir.includes("__tests__") ||
146
+ dir.startsWith("test") ||
147
+ dir.startsWith("tests")) {
148
+ // Get the top-level test directory name
149
+ const parts = dir.split("/");
150
+ const testDirPart = parts.find((p) => p === "__tests__" || p === "test" || p === "tests");
151
+ if (testDirPart)
152
+ dirs.add(testDirPart);
153
+ }
154
+ }
155
+ return Array.from(dirs);
156
+ }
157
+ // ── Coverage config detection ─────────────────────────────────────
158
+ async function detectCoverageConfig(projectRoot) {
159
+ // Check vitest.config.ts / vitest.config.js
160
+ const vitestConfigs = ["vitest.config.ts", "vitest.config.js", "vitest.config.mjs"];
161
+ for (const cfg of vitestConfigs) {
162
+ const cfgPath = join(projectRoot, cfg);
163
+ if (await fileExists(cfgPath)) {
164
+ try {
165
+ const content = await readFile(cfgPath, "utf-8");
166
+ if (content.includes("coverage"))
167
+ return true;
168
+ }
169
+ catch {
170
+ // Skip
171
+ }
172
+ }
173
+ }
174
+ // Check jest.config.ts / jest.config.js
175
+ const jestConfigs = [
176
+ "jest.config.ts",
177
+ "jest.config.js",
178
+ "jest.config.mjs",
179
+ "jest.config.json",
180
+ ];
181
+ for (const cfg of jestConfigs) {
182
+ if (await fileExists(join(projectRoot, cfg)))
183
+ return true;
184
+ }
185
+ // Check package.json for coverage config
186
+ const pkgPath = join(projectRoot, "package.json");
187
+ if (await fileExists(pkgPath)) {
188
+ try {
189
+ const raw = await readFile(pkgPath, "utf-8");
190
+ const pkg = JSON.parse(raw);
191
+ if ("jest" in pkg) {
192
+ const jestConfig = pkg["jest"];
193
+ if ("collectCoverage" in jestConfig || "coverageDirectory" in jestConfig) {
194
+ return true;
195
+ }
196
+ }
197
+ }
198
+ catch {
199
+ // Skip
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+ // ── Main scanner ──────────────────────────────────────────────────
205
+ export async function scanTestConventions(projectRoot) {
206
+ const ignore = IGNORE_DIRS.map((d) => `**/${d}/**`);
207
+ let testFiles;
208
+ try {
209
+ testFiles = await glob("**/*.{test,spec}.{ts,tsx,js,jsx}", { cwd: projectRoot, ignore, absolute: true });
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ const pkg = await readPackageJson(projectRoot);
215
+ const framework = detectFramework(pkg);
216
+ const mockingLibrary = detectMockingLibrary(pkg, framework);
217
+ const filePattern = detectFilePattern(testFiles);
218
+ const colocated = detectColocated(testFiles, projectRoot);
219
+ const testDirs = extractTestDirs(testFiles, projectRoot);
220
+ const hasCoverageConfig = await detectCoverageConfig(projectRoot);
221
+ return {
222
+ framework,
223
+ filePattern,
224
+ colocated,
225
+ testDirs,
226
+ mockingLibrary,
227
+ hasCoverageConfig,
228
+ testFileCount: testFiles.length,
229
+ };
230
+ }
231
+ //# sourceMappingURL=test-conventions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-conventions.js","sourceRoot":"","sources":["../../../src/discovery/scanners/test-conventions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * LLM-powered principles synthesizer.
3
+ *
4
+ * synthesizePrinciples() takes a DiscoveryReport produced by scanProject()
5
+ * and makes a single LLM call to produce a comprehensive principles.md
6
+ * document tailored to the scanned project.
7
+ *
8
+ * The returned markdown is ready to write to .bober/principles.md.
9
+ */
10
+ import type { BoberConfig } from "../config/schema.js";
11
+ import type { DiscoveryReport } from "./types.js";
12
+ /**
13
+ * Validate the synthesized markdown contains required structure.
14
+ * Returns true if valid; false otherwise. Never throws.
15
+ */
16
+ export declare function validatePrinciplesMarkdown(markdown: string): boolean;
17
+ /**
18
+ * Make a single LLM call to synthesize a DiscoveryReport into a
19
+ * comprehensive principles.md markdown document.
20
+ *
21
+ * If the LLM response fails validation (missing headings), the raw
22
+ * response is returned anyway — never throws on validation failure.
23
+ *
24
+ * @param report DiscoveryReport produced by scanProject().
25
+ * @param projectRoot Absolute path to the project root (used in prompt).
26
+ * @param config Full BoberConfig — uses planner provider/model/endpoint.
27
+ * @returns Markdown string starting with "# Project Principles".
28
+ */
29
+ export declare function synthesizePrinciples(report: DiscoveryReport, projectRoot: string, config: BoberConfig): Promise<string>;
30
+ //# sourceMappingURL=synthesizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesizer.d.ts","sourceRoot":"","sources":["../../src/discovery/synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AA+TlD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAYpE;AAID;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CAmCjB"}
@@ -0,0 +1,348 @@
1
+ /**
2
+ * LLM-powered principles synthesizer.
3
+ *
4
+ * synthesizePrinciples() takes a DiscoveryReport produced by scanProject()
5
+ * and makes a single LLM call to produce a comprehensive principles.md
6
+ * document tailored to the scanned project.
7
+ *
8
+ * The returned markdown is ready to write to .bober/principles.md.
9
+ */
10
+ import { createClient } from "../providers/factory.js";
11
+ import { resolveModel } from "../orchestrator/model-resolver.js";
12
+ // ── Required headings ─────────────────────────────────────────────
13
+ const REQUIRED_HEADINGS = [
14
+ "## Code Style",
15
+ "## TypeScript Conventions",
16
+ "## Testing Standards",
17
+ "## Git Workflow",
18
+ "## Error Handling",
19
+ "## File Organization",
20
+ "## Dependencies and Imports",
21
+ ];
22
+ // ── Prompt builders ───────────────────────────────────────────────
23
+ function buildSystemPrompt() {
24
+ return `You are analyzing a codebase to produce project principles for an AI development harness.
25
+
26
+ Your output will be read by AI code generators (like Claude Code) as binding rules they must follow.
27
+ Every rule you write must be:
28
+ - Specific and actionable — a code generator can follow it without ambiguity
29
+ - Grounded in the actual codebase evidence provided — do not invent conventions
30
+ - Concrete, never vague — NEVER write phrases like "follow best practices", "maintain code quality", "write clean code", or any similar platitude
31
+
32
+ You are writing binding rules, not recommendations. Write in imperative mood ("Use X", "Never do Y").`;
33
+ }
34
+ function formatPackageScripts(report) {
35
+ const ps = report.packageScripts;
36
+ if (!ps)
37
+ return " (no package.json detected)";
38
+ const lines = [];
39
+ lines.push(` Package manager: ${ps.packageManager ?? "unknown"}`);
40
+ lines.push(` All scripts: ${Object.keys(ps.allScripts).join(", ")}`);
41
+ const cats = Object.entries(ps.categorized);
42
+ if (cats.length > 0) {
43
+ lines.push(" Detected command mappings:");
44
+ for (const [category, mapping] of cats) {
45
+ if (mapping) {
46
+ lines.push(` ${category}: ${mapping.runCommand} (script: "${mapping.scriptName}", raw: "${mapping.command}")`);
47
+ }
48
+ }
49
+ }
50
+ return lines.join("\n");
51
+ }
52
+ function formatCIChecks(report) {
53
+ const ci = report.ciChecks;
54
+ if (!ci || ci.workflows.length === 0)
55
+ return " (no CI workflows detected)";
56
+ const lines = [];
57
+ for (const workflow of ci.workflows) {
58
+ lines.push(` Workflow: ${workflow.file}`);
59
+ for (const step of workflow.steps) {
60
+ const name = step.name ? `"${step.name}"` : "(unnamed)";
61
+ lines.push(` - [${step.category}] ${name}: ${step.runCommand}`);
62
+ }
63
+ }
64
+ if (ci.allRunCommands.length > 0) {
65
+ lines.push(` All CI run commands: ${ci.allRunCommands.join(", ")}`);
66
+ }
67
+ return lines.join("\n");
68
+ }
69
+ function formatGitConventions(report) {
70
+ const git = report.gitConventions;
71
+ if (!git)
72
+ return " (no git history detected)";
73
+ const lines = [];
74
+ lines.push(` Uses conventional commits: ${git.usesConventionalCommits}`);
75
+ lines.push(` Most common commit prefix: ${git.mostCommonPrefix ?? "(none detected)"}`);
76
+ lines.push(` Has linear history (no merge commits): ${git.hasLinearHistory}`);
77
+ lines.push(` Merge commit ratio: ${(git.mergeCommitRatio * 100).toFixed(0)}%`);
78
+ if (git.branchPatterns.length > 0) {
79
+ lines.push(` Branch naming patterns: ${git.branchPatterns.join(", ")}`);
80
+ }
81
+ if (git.recentMessages.length > 0) {
82
+ const sample = git.recentMessages.slice(0, 10);
83
+ lines.push(" Recent commit messages (sample):");
84
+ for (const msg of sample) {
85
+ lines.push(` - ${msg}`);
86
+ }
87
+ }
88
+ return lines.join("\n");
89
+ }
90
+ function formatCodeConventions(report) {
91
+ const cc = report.codeConventions;
92
+ if (!cc)
93
+ return " (no source files scanned)";
94
+ const lines = [];
95
+ lines.push(` Files sampled: ${cc.filesSampled}`);
96
+ // File naming
97
+ lines.push(` File naming: dominant style is "${cc.fileNaming.dominant}"`);
98
+ const namingCounts = Object.entries(cc.fileNaming.counts)
99
+ .filter(([, count]) => count > 0)
100
+ .map(([style, count]) => `${style}=${count}`)
101
+ .join(", ");
102
+ if (namingCounts) {
103
+ lines.push(` Counts by style: ${namingCounts}`);
104
+ }
105
+ // Imports
106
+ lines.push(` Import style: ${cc.importStyle.relativeCount} relative, ${cc.importStyle.absoluteCount} absolute/alias`);
107
+ lines.push(` Uses .js extensions in imports: ${cc.importStyle.usesJsExtensions}`);
108
+ if (cc.importStyle.examples.length > 0) {
109
+ lines.push(" Import examples:");
110
+ for (const ex of cc.importStyle.examples) {
111
+ lines.push(` ${ex.trim()}`);
112
+ }
113
+ }
114
+ // Exports
115
+ lines.push(` Export style: dominant is "${cc.exportStyle.dominant}" (named=${cc.exportStyle.namedExportCount}, default=${cc.exportStyle.defaultExportCount})`);
116
+ // TypeScript
117
+ if (cc.typescriptPatterns) {
118
+ const ts = cc.typescriptPatterns;
119
+ lines.push(` TypeScript usage:`);
120
+ lines.push(` interface declarations: ${ts.interfaceCount}`);
121
+ lines.push(` type alias declarations: ${ts.typeAliasCount}`);
122
+ lines.push(` enum declarations: ${ts.enumCount}`);
123
+ lines.push(` "any" usages: ${ts.anyCount}`);
124
+ lines.push(` @ts-ignore/@ts-expect-error usages: ${ts.tsIgnoreCount}`);
125
+ }
126
+ return lines.join("\n");
127
+ }
128
+ function formatTestConventions(report) {
129
+ const tc = report.testConventions;
130
+ if (!tc)
131
+ return " (no test files detected)";
132
+ const lines = [];
133
+ lines.push(` Framework: ${tc.framework}`);
134
+ lines.push(` Mocking library: ${tc.mockingLibrary}`);
135
+ lines.push(` File naming pattern: ${tc.filePattern}`);
136
+ lines.push(` Tests colocated with source: ${tc.colocated}`);
137
+ lines.push(` Test file count: ${tc.testFileCount}`);
138
+ lines.push(` Has coverage config: ${tc.hasCoverageConfig}`);
139
+ if (tc.testDirs.length > 0) {
140
+ lines.push(` Test directories: ${tc.testDirs.join(", ")}`);
141
+ }
142
+ return lines.join("\n");
143
+ }
144
+ function formatDocumentation(report) {
145
+ const docs = report.documentation;
146
+ if (!docs || docs.files.length === 0)
147
+ return " (no documentation files found)";
148
+ const lines = [];
149
+ for (const file of docs.files) {
150
+ const truncated = file.truncated ? " (truncated)" : "";
151
+ lines.push(` File: ${file.path}${truncated}`);
152
+ // Include a short excerpt (first 300 chars) to give the LLM flavour
153
+ const excerpt = file.content.slice(0, 300).replace(/\n/g, "\n ");
154
+ lines.push(` ${excerpt}`);
155
+ if (file.truncated) {
156
+ lines.push(" [... content truncated ...]");
157
+ }
158
+ }
159
+ return lines.join("\n");
160
+ }
161
+ function formatDetectedStack(report) {
162
+ const ds = report.detectedStack;
163
+ if (!ds)
164
+ return " (stack detection failed)";
165
+ const active = [];
166
+ if (ds.hasTypescript)
167
+ active.push("TypeScript");
168
+ if (ds.hasReact)
169
+ active.push("React");
170
+ if (ds.hasNext)
171
+ active.push("Next.js");
172
+ if (ds.hasVite)
173
+ active.push("Vite");
174
+ if (ds.hasVitest)
175
+ active.push("Vitest");
176
+ if (ds.hasJest)
177
+ active.push("Jest");
178
+ if (ds.hasPlaywright)
179
+ active.push("Playwright");
180
+ if (ds.hasEslint)
181
+ active.push("ESLint");
182
+ if (ds.hasPython)
183
+ active.push("Python");
184
+ if (ds.hasRust)
185
+ active.push("Rust");
186
+ if (ds.hasNestjs)
187
+ active.push("NestJS");
188
+ if (ds.hasFastify)
189
+ active.push("Fastify");
190
+ if (ds.hasExpress)
191
+ active.push("Express");
192
+ const lines = [];
193
+ lines.push(` Primary language: ${ds.primaryLanguage}`);
194
+ lines.push(` Detected technologies: ${active.length > 0 ? active.join(", ") : "(none)"}`);
195
+ return lines.join("\n");
196
+ }
197
+ function buildUserMessage(report, projectRoot) {
198
+ const date = new Date().toISOString().slice(0, 10);
199
+ const sections = [];
200
+ sections.push(`# Codebase Analysis Report
201
+ Project root: ${projectRoot}
202
+ Scanned at: ${report.scannedAt}
203
+ Package manager: ${report.packageManager ?? "unknown"}`);
204
+ sections.push(`## Package Scripts and Detected Commands
205
+ ${formatPackageScripts(report)}`);
206
+ sections.push(`## CI/CD Workflows
207
+ ${formatCIChecks(report)}`);
208
+ sections.push(`## Git Conventions
209
+ ${formatGitConventions(report)}`);
210
+ sections.push(`## Code Conventions
211
+ ${formatCodeConventions(report)}`);
212
+ sections.push(`## Test Conventions
213
+ ${formatTestConventions(report)}`);
214
+ sections.push(`## Documentation Excerpts
215
+ ${formatDocumentation(report)}`);
216
+ sections.push(`## Detected Stack
217
+ ${formatDetectedStack(report)}`);
218
+ sections.push(`---
219
+
220
+ # Instructions
221
+
222
+ Using the codebase analysis above, produce a comprehensive \`principles.md\` document.
223
+
224
+ **Content requirements — you MUST follow all of these:**
225
+
226
+ 1. Include file path examples for each convention discovered.
227
+ Example: "Components use PascalCase naming — see src/components/UserProfile.tsx"
228
+ Example: "Imports use relative paths with .js extensions — see src/utils/fs.ts"
229
+
230
+ 2. Note any inconsistencies with the majority pattern.
231
+ Example: "Most files use camelCase but src/utils/parse-config.ts uses kebab-case"
232
+ Example: "Named exports dominate but some utility files use default exports"
233
+
234
+ 3. NEVER use vague phrases like "follow best practices", "maintain code quality",
235
+ "write clean code", "be consistent", "use idiomatic code", or similar platitudes.
236
+ Every rule must be specific and actionable.
237
+
238
+ 4. Produce specific actionable rules that a code generator can follow without ambiguity.
239
+ BAD: "Handle errors properly"
240
+ GOOD: "All async functions must catch errors and either rethrow with context or return null — never swallow errors silently"
241
+
242
+ 5. Base every rule on the actual evidence in the report above. Do not invent conventions
243
+ that are not supported by the scanned data.
244
+
245
+ **Output format — produce EXACTLY this structure:**
246
+
247
+ \`\`\`markdown
248
+ # Project Principles
249
+ > Auto-discovered by agent-bober on ${date}
250
+
251
+ ## Code Style
252
+ [rules]
253
+
254
+ ## TypeScript Conventions
255
+ [rules]
256
+
257
+ ## Testing Standards
258
+ [rules]
259
+
260
+ ## Git Workflow
261
+ [rules]
262
+
263
+ ## Error Handling
264
+ [rules]
265
+
266
+ ## File Organization
267
+ [rules]
268
+
269
+ ## Dependencies and Imports
270
+ [rules]
271
+ \`\`\`
272
+
273
+ Output ONLY the markdown document — no preamble, no explanation, no text outside the code fence.`);
274
+ return sections.join("\n\n");
275
+ }
276
+ // ── Response parsing ──────────────────────────────────────────────
277
+ /**
278
+ * Strip markdown code fences from a response if present.
279
+ *
280
+ * Handles:
281
+ * - ```markdown ... ```
282
+ * - ```md ... ```
283
+ * - ``` ... ```
284
+ * - No fences (returned as-is)
285
+ */
286
+ function stripCodeFences(text) {
287
+ const trimmed = text.trim();
288
+ // Match opening fence with optional language tag, capture content, closing fence
289
+ const fenceMatch = /^```(?:markdown|md)?\s*\n([\s\S]*?)\n?```\s*$/.exec(trimmed);
290
+ if (fenceMatch) {
291
+ return fenceMatch[1].trim();
292
+ }
293
+ return trimmed;
294
+ }
295
+ /**
296
+ * Validate the synthesized markdown contains required structure.
297
+ * Returns true if valid; false otherwise. Never throws.
298
+ */
299
+ export function validatePrinciplesMarkdown(markdown) {
300
+ if (!markdown.includes("# Project Principles")) {
301
+ return false;
302
+ }
303
+ for (const heading of REQUIRED_HEADINGS) {
304
+ if (!markdown.includes(heading)) {
305
+ return false;
306
+ }
307
+ }
308
+ return true;
309
+ }
310
+ // ── Public API ────────────────────────────────────────────────────
311
+ /**
312
+ * Make a single LLM call to synthesize a DiscoveryReport into a
313
+ * comprehensive principles.md markdown document.
314
+ *
315
+ * If the LLM response fails validation (missing headings), the raw
316
+ * response is returned anyway — never throws on validation failure.
317
+ *
318
+ * @param report DiscoveryReport produced by scanProject().
319
+ * @param projectRoot Absolute path to the project root (used in prompt).
320
+ * @param config Full BoberConfig — uses planner provider/model/endpoint.
321
+ * @returns Markdown string starting with "# Project Principles".
322
+ */
323
+ export async function synthesizePrinciples(report, projectRoot, config) {
324
+ const client = createClient(config.planner.provider ?? null, config.planner.endpoint ?? null, config.planner.providerConfig, config.planner.model);
325
+ const model = resolveModel(config.planner.model);
326
+ const systemPrompt = buildSystemPrompt();
327
+ const userMessage = buildUserMessage(report, projectRoot);
328
+ const response = await client.chat({
329
+ model,
330
+ system: systemPrompt,
331
+ messages: [
332
+ { role: "user", content: userMessage },
333
+ ],
334
+ // No tools — single chat call
335
+ tools: [],
336
+ maxTokens: 16384,
337
+ });
338
+ const raw = response.text;
339
+ const stripped = stripCodeFences(raw);
340
+ // Validation — if it fails, return stripped anyway (never throw)
341
+ // This ensures callers always get something useful even if the model
342
+ // deviated from the requested format.
343
+ if (!validatePrinciplesMarkdown(stripped)) {
344
+ return stripped || raw;
345
+ }
346
+ return stripped;
347
+ }
348
+ //# sourceMappingURL=synthesizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesizer.js","sourceRoot":"","sources":["../../src/discovery/synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAGjE,qEAAqE;AAErE,MAAM,iBAAiB,GAAG;IACxB,eAAe;IACf,2BAA2B;IAC3B,sBAAsB;IACtB,iBAAiB;IACjB,mBAAmB;IACnB,sBAAsB;IACtB,6BAA6B;CACrB,CAAC;AAEX,qEAAqE;AAErE,SAAS,iBAAiB;IACxB,OAAO;;;;;;;;sGAQ6F,CAAC;AACvG,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAuB;IACnD,MAAM,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC;IACjC,IAAI,CAAC,EAAE;QAAE,OAAO,8BAA8B,CAAC;IAE/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,cAAc,IAAI,SAAS,EAAE,CAAC,CAAC;IACnE,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEtE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC3C,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,KAAK,OAAO,CAAC,UAAU,cAAc,OAAO,CAAC,UAAU,YAAY,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;YACpH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,MAAuB;IAC7C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC3B,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,8BAA8B,CAAC;IAE5E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,QAAQ,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,KAAK,IAAI,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,IAAI,EAAE,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAuB;IACnD,MAAM,GAAG,GAAG,MAAM,CAAC,cAAc,CAAC;IAClC,IAAI,CAAC,GAAG;QAAE,OAAO,6BAA6B,CAAC;IAE/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,gCAAgC,GAAG,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAC1E,KAAK,CAAC,IAAI,CAAC,gCAAgC,GAAG,CAAC,gBAAgB,IAAI,iBAAiB,EAAE,CAAC,CAAC;IACxF,KAAK,CAAC,IAAI,CAAC,4CAA4C,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,GAAG,CAAC,gBAAgB,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAEhF,IAAI,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,6BAA6B,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,GAAG,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACjD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAuB;IACpD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC;IAClC,IAAI,CAAC,EAAE;QAAE,OAAO,6BAA6B,CAAC;IAE9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;IAElD,cAAc;IACd,KAAK,CAAC,IAAI,CAAC,qCAAqC,EAAE,CAAC,UAAU,CAAC,QAAQ,GAAG,CAAC,CAAC;IAC3E,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;SACtD,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC;SAChC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;SAC5C,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,IAAI,YAAY,EAAE,CAAC;QACjB,KAAK,CAAC,IAAI,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,UAAU;IACV,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,WAAW,CAAC,aAAa,cAAc,EAAE,CAAC,WAAW,CAAC,aAAa,iBAAiB,CAAC,CAAC;IACvH,KAAK,CAAC,IAAI,CAAC,qCAAqC,EAAE,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnF,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACjC,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,UAAU;IACV,KAAK,CAAC,IAAI,CAAC,gCAAgC,EAAE,CAAC,WAAW,CAAC,QAAQ,YAAY,EAAE,CAAC,WAAW,CAAC,gBAAgB,aAAa,EAAE,CAAC,WAAW,CAAC,kBAAkB,GAAG,CAAC,CAAC;IAEhK,aAAa;IACb,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,+BAA+B,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,gCAAgC,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;QAChE,KAAK,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;QACrD,KAAK,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,2CAA2C,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,MAAuB;IACpD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC;IAClC,IAAI,CAAC,EAAE;QAAE,OAAO,4BAA4B,CAAC;IAE7C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,kCAAkC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IAC7D,KAAK,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAE7D,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAuB;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC;IAClC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,kCAAkC,CAAC;IAEhF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC;QAC/C,oEAAoE;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,mBAAmB,CAAC,MAAuB;IAClD,MAAM,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC;IAChC,IAAI,CAAC,EAAE;QAAE,OAAO,4BAA4B,CAAC;IAE7C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAC,aAAa;QAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,EAAE,CAAC,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvC,IAAI,EAAE,CAAC,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,aAAa;QAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,EAAE,CAAC,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE3F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,gBAAgB,CACvB,MAAuB,EACvB,WAAmB;IAEnB,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,QAAQ,CAAC,IAAI,CAAC;gBACA,WAAW;cACb,MAAM,CAAC,SAAS;mBACX,MAAM,CAAC,cAAc,IAAI,SAAS,EAAE,CAAC,CAAC;IAEvD,QAAQ,CAAC,IAAI,CAAC;EACd,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEhC,QAAQ,CAAC,IAAI,CAAC;EACd,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE1B,QAAQ,CAAC,IAAI,CAAC;EACd,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEhC,QAAQ,CAAC,IAAI,CAAC;EACd,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEjC,QAAQ,CAAC,IAAI,CAAC;EACd,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEjC,QAAQ,CAAC,IAAI,CAAC;EACd,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/B,QAAQ,CAAC,IAAI,CAAC;EACd,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/B,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA+BsB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;iGAwBuD,CAAC,CAAC;IAEjG,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,qEAAqE;AAErE;;;;;;;;GAQG;AACH,SAAS,eAAe,CAAC,IAAY;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE5B,iFAAiF;IACjF,MAAM,UAAU,GAAG,+CAA+C,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IACzD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qEAAqE;AAErE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAuB,EACvB,WAAmB,EACnB,MAAmB;IAEnB,MAAM,MAAM,GAAG,YAAY,CACzB,MAAM,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,EAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,EAC/B,MAAM,CAAC,OAAO,CAAC,cAAc,EAC7B,MAAM,CAAC,OAAO,CAAC,KAAK,CACrB,CAAC;IAEF,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEjD,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;IACzC,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC;QACjC,KAAK;QACL,MAAM,EAAE,YAAY;QACpB,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;SACvC;QACD,8BAA8B;QAC9B,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC1B,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAEtC,iEAAiE;IACjE,qEAAqE;IACrE,sCAAsC;IACtC,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,QAAQ,IAAI,GAAG,CAAC;IACzB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}