@planu/cli 0.36.0 → 0.38.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 (257) hide show
  1. package/dist/config/license-plans.json +2 -1
  2. package/dist/engine/reverse-engineer/api-detector.d.ts +3 -0
  3. package/dist/engine/reverse-engineer/api-detector.d.ts.map +1 -0
  4. package/dist/engine/reverse-engineer/api-detector.js +170 -0
  5. package/dist/engine/reverse-engineer/api-detector.js.map +1 -0
  6. package/dist/engine/reverse-engineer/complexity-analyzer.d.ts +3 -0
  7. package/dist/engine/reverse-engineer/complexity-analyzer.d.ts.map +1 -0
  8. package/dist/engine/reverse-engineer/complexity-analyzer.js +230 -0
  9. package/dist/engine/reverse-engineer/complexity-analyzer.js.map +1 -0
  10. package/dist/engine/reverse-engineer/config-analyzer.d.ts +3 -0
  11. package/dist/engine/reverse-engineer/config-analyzer.d.ts.map +1 -0
  12. package/dist/engine/reverse-engineer/config-analyzer.js +247 -0
  13. package/dist/engine/reverse-engineer/config-analyzer.js.map +1 -0
  14. package/dist/engine/reverse-engineer/dependency-graph.d.ts +3 -0
  15. package/dist/engine/reverse-engineer/dependency-graph.d.ts.map +1 -0
  16. package/dist/engine/reverse-engineer/dependency-graph.js +197 -0
  17. package/dist/engine/reverse-engineer/dependency-graph.js.map +1 -0
  18. package/dist/engine/reverse-engineer/index.d.ts +7 -0
  19. package/dist/engine/reverse-engineer/index.d.ts.map +1 -0
  20. package/dist/engine/reverse-engineer/index.js +7 -0
  21. package/dist/engine/reverse-engineer/index.js.map +1 -0
  22. package/dist/engine/reverse-engineer/orchestrator.d.ts +5 -0
  23. package/dist/engine/reverse-engineer/orchestrator.d.ts.map +1 -0
  24. package/dist/engine/reverse-engineer/orchestrator.js +200 -0
  25. package/dist/engine/reverse-engineer/orchestrator.js.map +1 -0
  26. package/dist/engine/reverse-engineer/test-analyzer.d.ts +4 -0
  27. package/dist/engine/reverse-engineer/test-analyzer.d.ts.map +1 -0
  28. package/dist/engine/reverse-engineer/test-analyzer.js +130 -0
  29. package/dist/engine/reverse-engineer/test-analyzer.js.map +1 -0
  30. package/dist/engine/safety/atomic-writer.d.ts +22 -0
  31. package/dist/engine/safety/atomic-writer.d.ts.map +1 -0
  32. package/dist/engine/safety/atomic-writer.js +89 -0
  33. package/dist/engine/safety/atomic-writer.js.map +1 -0
  34. package/dist/engine/safety/circuit-breaker.d.ts +14 -0
  35. package/dist/engine/safety/circuit-breaker.d.ts.map +1 -0
  36. package/dist/engine/safety/circuit-breaker.js +63 -0
  37. package/dist/engine/safety/circuit-breaker.js.map +1 -0
  38. package/dist/engine/safety/file-mutex.d.ts +13 -0
  39. package/dist/engine/safety/file-mutex.d.ts.map +1 -0
  40. package/dist/engine/safety/file-mutex.js +108 -0
  41. package/dist/engine/safety/file-mutex.js.map +1 -0
  42. package/dist/engine/safety/health-monitor.d.ts +4 -0
  43. package/dist/engine/safety/health-monitor.d.ts.map +1 -0
  44. package/dist/engine/safety/health-monitor.js +95 -0
  45. package/dist/engine/safety/health-monitor.js.map +1 -0
  46. package/dist/engine/safety/index.d.ts +7 -0
  47. package/dist/engine/safety/index.d.ts.map +1 -0
  48. package/dist/engine/safety/index.js +8 -0
  49. package/dist/engine/safety/index.js.map +1 -0
  50. package/dist/engine/safety/path-sanitizer.d.ts +17 -0
  51. package/dist/engine/safety/path-sanitizer.d.ts.map +1 -0
  52. package/dist/engine/safety/path-sanitizer.js +36 -0
  53. package/dist/engine/safety/path-sanitizer.js.map +1 -0
  54. package/dist/engine/safety/transaction.d.ts +18 -0
  55. package/dist/engine/safety/transaction.d.ts.map +1 -0
  56. package/dist/engine/safety/transaction.js +70 -0
  57. package/dist/engine/safety/transaction.js.map +1 -0
  58. package/dist/engine/spec-kit-exporter.d.ts +6 -0
  59. package/dist/engine/spec-kit-exporter.d.ts.map +1 -0
  60. package/dist/engine/spec-kit-exporter.js +227 -0
  61. package/dist/engine/spec-kit-exporter.js.map +1 -0
  62. package/dist/engine/spec-migrator.d.ts +9 -0
  63. package/dist/engine/spec-migrator.d.ts.map +1 -1
  64. package/dist/engine/spec-migrator.js +70 -0
  65. package/dist/engine/spec-migrator.js.map +1 -1
  66. package/dist/engine/webhook/server.d.ts +4 -10
  67. package/dist/engine/webhook/server.d.ts.map +1 -1
  68. package/dist/engine/webhook/server.js +78 -24
  69. package/dist/engine/webhook/server.js.map +1 -1
  70. package/dist/index.js +4 -3
  71. package/dist/index.js.map +1 -1
  72. package/dist/storage/base-store.d.ts.map +1 -1
  73. package/dist/storage/base-store.js +3 -2
  74. package/dist/storage/base-store.js.map +1 -1
  75. package/dist/storage/trash-store.d.ts +10 -0
  76. package/dist/storage/trash-store.d.ts.map +1 -1
  77. package/dist/storage/trash-store.js +74 -0
  78. package/dist/storage/trash-store.js.map +1 -1
  79. package/dist/tools/check-config-health.d.ts.map +1 -1
  80. package/dist/tools/check-config-health.js +2 -1
  81. package/dist/tools/check-config-health.js.map +1 -1
  82. package/dist/tools/create-spec/spec-builder.js +1 -1
  83. package/dist/tools/create-spec/spec-builder.js.map +1 -1
  84. package/dist/tools/export-spec.d.ts +3 -0
  85. package/dist/tools/export-spec.d.ts.map +1 -0
  86. package/dist/tools/export-spec.js +110 -0
  87. package/dist/tools/export-spec.js.map +1 -0
  88. package/dist/tools/generate-teammate-prompt.d.ts.map +1 -1
  89. package/dist/tools/generate-teammate-prompt.js +7 -4
  90. package/dist/tools/generate-teammate-prompt.js.map +1 -1
  91. package/dist/tools/init-project/handler.d.ts.map +1 -1
  92. package/dist/tools/init-project/handler.js +11 -1
  93. package/dist/tools/init-project/handler.js.map +1 -1
  94. package/dist/tools/init-project/result-builder.d.ts.map +1 -1
  95. package/dist/tools/init-project/result-builder.js +1 -0
  96. package/dist/tools/init-project/result-builder.js.map +1 -1
  97. package/dist/tools/plan-team-distribution.d.ts.map +1 -1
  98. package/dist/tools/plan-team-distribution.js +6 -2
  99. package/dist/tools/plan-team-distribution.js.map +1 -1
  100. package/dist/tools/register-agent-tools.d.ts.map +1 -1
  101. package/dist/tools/register-agent-tools.js +32 -14
  102. package/dist/tools/register-agent-tools.js.map +1 -1
  103. package/dist/tools/register-changelog-tools.d.ts.map +1 -1
  104. package/dist/tools/register-changelog-tools.js +6 -2
  105. package/dist/tools/register-changelog-tools.js.map +1 -1
  106. package/dist/tools/register-ci-tools.d.ts.map +1 -1
  107. package/dist/tools/register-ci-tools.js +12 -3
  108. package/dist/tools/register-ci-tools.js.map +1 -1
  109. package/dist/tools/register-context-tools.d.ts.map +1 -1
  110. package/dist/tools/register-context-tools.js +32 -11
  111. package/dist/tools/register-context-tools.js.map +1 -1
  112. package/dist/tools/register-coverage-tools.d.ts.map +1 -1
  113. package/dist/tools/register-coverage-tools.js +2 -1
  114. package/dist/tools/register-coverage-tools.js.map +1 -1
  115. package/dist/tools/register-delete-tools.d.ts.map +1 -1
  116. package/dist/tools/register-delete-tools.js +9 -8
  117. package/dist/tools/register-delete-tools.js.map +1 -1
  118. package/dist/tools/register-event-tools.d.ts.map +1 -1
  119. package/dist/tools/register-event-tools.js +69 -33
  120. package/dist/tools/register-event-tools.js.map +1 -1
  121. package/dist/tools/register-export-tools.d.ts +3 -0
  122. package/dist/tools/register-export-tools.d.ts.map +1 -0
  123. package/dist/tools/register-export-tools.js +21 -0
  124. package/dist/tools/register-export-tools.js.map +1 -0
  125. package/dist/tools/register-facilitator-tools.d.ts.map +1 -1
  126. package/dist/tools/register-facilitator-tools.js +10 -2
  127. package/dist/tools/register-facilitator-tools.js.map +1 -1
  128. package/dist/tools/register-governance-tools.d.ts.map +1 -1
  129. package/dist/tools/register-governance-tools.js +4 -1
  130. package/dist/tools/register-governance-tools.js.map +1 -1
  131. package/dist/tools/register-hooks-tools.d.ts.map +1 -1
  132. package/dist/tools/register-hooks-tools.js +45 -18
  133. package/dist/tools/register-hooks-tools.js.map +1 -1
  134. package/dist/tools/register-ide-tools.js +1 -1
  135. package/dist/tools/register-ide-tools.js.map +1 -1
  136. package/dist/tools/register-learning-tools.d.ts.map +1 -1
  137. package/dist/tools/register-learning-tools.js +7 -1
  138. package/dist/tools/register-learning-tools.js.map +1 -1
  139. package/dist/tools/register-license-tools.d.ts.map +1 -1
  140. package/dist/tools/register-license-tools.js +6 -1
  141. package/dist/tools/register-license-tools.js.map +1 -1
  142. package/dist/tools/register-llm-provider-tools.d.ts.map +1 -1
  143. package/dist/tools/register-llm-provider-tools.js +13 -9
  144. package/dist/tools/register-llm-provider-tools.js.map +1 -1
  145. package/dist/tools/register-memory-tools.d.ts.map +1 -1
  146. package/dist/tools/register-memory-tools.js +17 -6
  147. package/dist/tools/register-memory-tools.js.map +1 -1
  148. package/dist/tools/register-migration-tools.d.ts.map +1 -1
  149. package/dist/tools/register-migration-tools.js +8 -1
  150. package/dist/tools/register-migration-tools.js.map +1 -1
  151. package/dist/tools/register-orchestrator-tools.d.ts.map +1 -1
  152. package/dist/tools/register-orchestrator-tools.js +15 -14
  153. package/dist/tools/register-orchestrator-tools.js.map +1 -1
  154. package/dist/tools/register-platform-tools/design-stack-tools.d.ts.map +1 -1
  155. package/dist/tools/register-platform-tools/design-stack-tools.js +62 -35
  156. package/dist/tools/register-platform-tools/design-stack-tools.js.map +1 -1
  157. package/dist/tools/register-platform-tools/lifecycle-infra-tools.d.ts.map +1 -1
  158. package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +72 -36
  159. package/dist/tools/register-platform-tools/lifecycle-infra-tools.js.map +1 -1
  160. package/dist/tools/register-readiness-tools.js +4 -4
  161. package/dist/tools/register-readiness-tools.js.map +1 -1
  162. package/dist/tools/register-runtime-security-tools.js +1 -1
  163. package/dist/tools/register-runtime-security-tools.js.map +1 -1
  164. package/dist/tools/register-scope-tools.d.ts.map +1 -1
  165. package/dist/tools/register-scope-tools.js +26 -6
  166. package/dist/tools/register-scope-tools.js.map +1 -1
  167. package/dist/tools/register-search-tools.js +2 -2
  168. package/dist/tools/register-search-tools.js.map +1 -1
  169. package/dist/tools/register-security-tools.d.ts.map +1 -1
  170. package/dist/tools/register-security-tools.js +4 -3
  171. package/dist/tools/register-security-tools.js.map +1 -1
  172. package/dist/tools/register-spec-tools/analysis-tools.d.ts.map +1 -1
  173. package/dist/tools/register-spec-tools/analysis-tools.js +36 -25
  174. package/dist/tools/register-spec-tools/analysis-tools.js.map +1 -1
  175. package/dist/tools/register-spec-tools/core-spec-tools.d.ts.map +1 -1
  176. package/dist/tools/register-spec-tools/core-spec-tools.js +42 -25
  177. package/dist/tools/register-spec-tools/core-spec-tools.js.map +1 -1
  178. package/dist/tools/register-stack-tools.d.ts.map +1 -1
  179. package/dist/tools/register-stack-tools.js +18 -10
  180. package/dist/tools/register-stack-tools.js.map +1 -1
  181. package/dist/tools/register-team-tools.d.ts.map +1 -1
  182. package/dist/tools/register-team-tools.js +17 -9
  183. package/dist/tools/register-team-tools.js.map +1 -1
  184. package/dist/tools/register-template-tools.d.ts.map +1 -1
  185. package/dist/tools/register-template-tools.js +13 -2
  186. package/dist/tools/register-template-tools.js.map +1 -1
  187. package/dist/tools/register-transform-tools.d.ts.map +1 -1
  188. package/dist/tools/register-transform-tools.js +3 -2
  189. package/dist/tools/register-transform-tools.js.map +1 -1
  190. package/dist/tools/register-workspace-tools.d.ts.map +1 -1
  191. package/dist/tools/register-workspace-tools.js +8 -3
  192. package/dist/tools/register-workspace-tools.js.map +1 -1
  193. package/dist/tools/reverse-engineer/handler.d.ts.map +1 -1
  194. package/dist/tools/reverse-engineer/handler.js +156 -128
  195. package/dist/tools/reverse-engineer/handler.js.map +1 -1
  196. package/dist/tools/schemas/github.d.ts.map +1 -1
  197. package/dist/tools/schemas/github.js +18 -9
  198. package/dist/tools/schemas/github.js.map +1 -1
  199. package/dist/tools/schemas/ide-config.js +1 -1
  200. package/dist/tools/schemas/ide-config.js.map +1 -1
  201. package/dist/tools/schemas/plugins-schemas.d.ts.map +1 -1
  202. package/dist/tools/schemas/plugins-schemas.js +15 -4
  203. package/dist/tools/schemas/plugins-schemas.js.map +1 -1
  204. package/dist/tools/schemas/registry.d.ts.map +1 -1
  205. package/dist/tools/schemas/registry.js +27 -10
  206. package/dist/tools/schemas/registry.js.map +1 -1
  207. package/dist/tools/schemas/session.d.ts.map +1 -1
  208. package/dist/tools/schemas/session.js +5 -3
  209. package/dist/tools/schemas/session.js.map +1 -1
  210. package/dist/tools/schemas/workers-schema.d.ts.map +1 -1
  211. package/dist/tools/schemas/workers-schema.js +16 -9
  212. package/dist/tools/schemas/workers-schema.js.map +1 -1
  213. package/dist/tools/validate-team-results.d.ts.map +1 -1
  214. package/dist/tools/validate-team-results.js +9 -3
  215. package/dist/tools/validate-team-results.js.map +1 -1
  216. package/dist/transports/http-transport.d.ts +7 -0
  217. package/dist/transports/http-transport.d.ts.map +1 -0
  218. package/dist/transports/http-transport.js +170 -0
  219. package/dist/transports/http-transport.js.map +1 -0
  220. package/dist/transports/index.d.ts +4 -0
  221. package/dist/transports/index.d.ts.map +1 -0
  222. package/dist/transports/index.js +4 -0
  223. package/dist/transports/index.js.map +1 -0
  224. package/dist/transports/transport-factory.d.ts +5 -0
  225. package/dist/transports/transport-factory.d.ts.map +1 -0
  226. package/dist/transports/transport-factory.js +48 -0
  227. package/dist/transports/transport-factory.js.map +1 -0
  228. package/dist/types/estimation.d.ts +1 -1
  229. package/dist/types/estimation.d.ts.map +1 -1
  230. package/dist/types/export.d.ts +24 -0
  231. package/dist/types/export.d.ts.map +1 -0
  232. package/dist/types/export.js +3 -0
  233. package/dist/types/export.js.map +1 -0
  234. package/dist/types/index.d.ts +5 -0
  235. package/dist/types/index.d.ts.map +1 -1
  236. package/dist/types/index.js +5 -0
  237. package/dist/types/index.js.map +1 -1
  238. package/dist/types/project/planu-config.d.ts +4 -0
  239. package/dist/types/project/planu-config.d.ts.map +1 -1
  240. package/dist/types/reverse-engineer.d.ts +90 -0
  241. package/dist/types/reverse-engineer.d.ts.map +1 -0
  242. package/dist/types/reverse-engineer.js +3 -0
  243. package/dist/types/reverse-engineer.js.map +1 -0
  244. package/dist/types/safe-schemas.d.ts +12 -0
  245. package/dist/types/safe-schemas.d.ts.map +1 -0
  246. package/dist/types/safe-schemas.js +27 -0
  247. package/dist/types/safe-schemas.js.map +1 -0
  248. package/dist/types/safety.d.ts +66 -0
  249. package/dist/types/safety.d.ts.map +1 -0
  250. package/dist/types/safety.js +3 -0
  251. package/dist/types/safety.js.map +1 -0
  252. package/dist/types/transport.d.ts +14 -0
  253. package/dist/types/transport.d.ts.map +1 -0
  254. package/dist/types/transport.js +2 -0
  255. package/dist/types/transport.js.map +1 -0
  256. package/package.json +11 -2
  257. package/src/config/license-plans.json +2 -1
@@ -0,0 +1,200 @@
1
+ // engine/reverse-engineer/orchestrator.ts — AC-7: Parallel analyzer orchestration
2
+ // AC-9: Spec enrichment from analysis results
3
+ // AC-10: Human-readable output summary
4
+ import { analyzeTestCoverage } from './test-analyzer.js';
5
+ import { buildDependencyGraph } from './dependency-graph.js';
6
+ import { detectApiRoutes } from './api-detector.js';
7
+ import { analyzeComplexity } from './complexity-analyzer.js';
8
+ import { analyzeConfig } from './config-analyzer.js';
9
+ const DEFAULT_OPTIONS = {
10
+ enableTest: true,
11
+ enableDeps: true,
12
+ enableApi: true,
13
+ enableComplexity: true,
14
+ enableConfig: true,
15
+ };
16
+ export async function runDeepAnalysis(projectPath, options) {
17
+ const opts = { ...DEFAULT_OPTIONS, ...options };
18
+ const start = Date.now();
19
+ // All analyzers are independent — run in parallel
20
+ const [testCoverage, dependencyGraph, apiRoutes, complexityMetrics, configAnalysis] = await Promise.all([
21
+ opts.enableTest
22
+ ? Promise.resolve(analyzeTestCoverage(projectPath))
23
+ : Promise.resolve(emptyTestCoverage()),
24
+ opts.enableDeps
25
+ ? Promise.resolve(buildDependencyGraph(projectPath))
26
+ : Promise.resolve(emptyDependencyGraph()),
27
+ opts.enableApi ? Promise.resolve(detectApiRoutes(projectPath)) : Promise.resolve([]),
28
+ opts.enableComplexity ? Promise.resolve(analyzeComplexity(projectPath)) : Promise.resolve([]),
29
+ opts.enableConfig
30
+ ? Promise.resolve(analyzeConfig(projectPath))
31
+ : Promise.resolve(emptyConfigReport()),
32
+ ]);
33
+ return {
34
+ testCoverage,
35
+ dependencyGraph,
36
+ apiRoutes,
37
+ complexityMetrics,
38
+ configAnalysis,
39
+ analysisTimeMs: Date.now() - start,
40
+ };
41
+ }
42
+ // --- AC-9: Spec enrichment helpers ---
43
+ function detectTags(result) {
44
+ const tags = [];
45
+ const tagMap = {
46
+ jest: 'vitest/jest',
47
+ vitest: 'vitest/jest',
48
+ 'next.config': 'nextjs',
49
+ 'vite.config': 'vite',
50
+ tsconfig: 'typescript',
51
+ docker: 'docker',
52
+ Docker: 'docker',
53
+ };
54
+ for (const cfg of result.configAnalysis.configFiles) {
55
+ for (const [key, tag] of Object.entries(tagMap)) {
56
+ if (cfg.includes(key)) {
57
+ tags.push(tag);
58
+ }
59
+ }
60
+ }
61
+ if (result.apiRoutes.length > 0) {
62
+ const methods = new Set(result.apiRoutes.map((r) => r.method));
63
+ if (methods.has('GET') && methods.has('POST')) {
64
+ tags.push('rest-api');
65
+ }
66
+ }
67
+ if (result.testCoverage.testedModules.length > 0) {
68
+ tags.push('has-tests');
69
+ }
70
+ return [...new Set(tags)];
71
+ }
72
+ function detectTechDebt(result) {
73
+ const items = [];
74
+ if (result.testCoverage.untestedModules.length > 0) {
75
+ items.push({
76
+ file: 'multiple files',
77
+ type: 'missing-tests',
78
+ description: `${result.testCoverage.untestedModules.length} modules without tests`,
79
+ severity: result.testCoverage.untestedModules.length > 10 ? 'high' : 'medium',
80
+ effort: 'large',
81
+ suggestion: 'Add tests for untested modules to improve coverage',
82
+ });
83
+ }
84
+ if (result.dependencyGraph.cycles.length > 0) {
85
+ items.push({
86
+ file: 'dependency graph',
87
+ type: 'anti-pattern',
88
+ description: `${result.dependencyGraph.cycles.length} circular dependency cycle(s) detected`,
89
+ severity: 'high',
90
+ effort: 'medium',
91
+ suggestion: 'Break circular dependencies by extracting shared interfaces',
92
+ });
93
+ }
94
+ const hotspots = result.complexityMetrics
95
+ .flatMap((m) => m.hotspots.map((h) => ({ ...h, file: m.file })))
96
+ .sort((a, b) => b.complexity - a.complexity)
97
+ .slice(0, 5);
98
+ if (hotspots.length > 0) {
99
+ items.push({
100
+ file: hotspots[0]?.file ?? 'unknown',
101
+ type: 'code-smell',
102
+ description: `${hotspots.length} high-complexity functions (top: ${hotspots[0]?.name} at ${hotspots[0]?.complexity})`,
103
+ severity: 'medium',
104
+ effort: 'medium',
105
+ suggestion: 'Refactor complex functions into smaller, focused units',
106
+ });
107
+ }
108
+ return items;
109
+ }
110
+ export function enrichSpecFromAnalysis(result) {
111
+ const affectedFiles = result.dependencyGraph.nodes
112
+ .slice()
113
+ .sort((a, b) => b.fanIn - a.fanIn)
114
+ .slice(0, 50)
115
+ .map((n) => n.file);
116
+ return { affectedFiles, tags: detectTags(result), techDebt: detectTechDebt(result) };
117
+ }
118
+ // --- AC-10: Output summary ---
119
+ function buildHealthLines(result) {
120
+ const lines = ['', '## Health Indicators'];
121
+ const { testCoverage } = result;
122
+ const total = testCoverage.testedModules.length + testCoverage.untestedModules.length;
123
+ const coveragePct = total > 0 ? Math.round((testCoverage.testedModules.length / total) * 100) : 0;
124
+ lines.push(`- Test coverage: ${coveragePct}% (${testCoverage.testedModules.length}/${total} modules)`);
125
+ lines.push(`- Circular dependencies: ${result.dependencyGraph.cycles.length}`);
126
+ if (result.complexityMetrics.length > 0) {
127
+ const avg = result.complexityMetrics.reduce((s, m) => s + m.avgComplexity, 0) /
128
+ result.complexityMetrics.length;
129
+ lines.push(`- Average complexity: ${avg.toFixed(1)}`);
130
+ }
131
+ lines.push(`- Config files: ${result.configAnalysis.configFiles.length}`);
132
+ lines.push(`- Environment variables: ${result.configAnalysis.envVars.length}`);
133
+ return lines;
134
+ }
135
+ export function generateAnalysisSummary(result) {
136
+ const lines = ['## Architecture Overview'];
137
+ const { nodes, hubs: hubList, orphans: orphanList } = result.dependencyGraph;
138
+ lines.push(`- ${nodes.length} modules analyzed, ${hubList.length} hub(s), ${orphanList.length} orphan(s)`);
139
+ if (result.apiRoutes.length > 0) {
140
+ const resources = [...new Set(result.apiRoutes.map((r) => r.resource))];
141
+ lines.push(`- ${result.apiRoutes.length} API routes across ${resources.length} resource(s): ${resources.slice(0, 5).join(', ')}`);
142
+ }
143
+ if (result.configAnalysis.infrastructure.length > 0) {
144
+ lines.push(`- Infrastructure: ${result.configAnalysis.infrastructure.join(', ')}`);
145
+ }
146
+ lines.push(...buildHealthLines(result));
147
+ // Top 5 risk areas
148
+ lines.push('');
149
+ lines.push('## Top 5 Risk Areas');
150
+ const riskAreas = result.complexityMetrics
151
+ .map((m) => ({
152
+ file: m.file,
153
+ complexity: m.avgComplexity,
154
+ maxFnLen: m.maxFunctionLength,
155
+ hasCoverage: result.testCoverage.testedModules.some((t) => m.file.includes(t) || t.includes(m.file)),
156
+ }))
157
+ .sort((a, b) => {
158
+ const scoreA = a.complexity * (a.hasCoverage ? 1 : 2);
159
+ const scoreB = b.complexity * (b.hasCoverage ? 1 : 2);
160
+ return scoreB - scoreA;
161
+ })
162
+ .slice(0, 5);
163
+ if (riskAreas.length === 0) {
164
+ lines.push('- No significant risk areas detected');
165
+ }
166
+ else {
167
+ for (const area of riskAreas) {
168
+ const coverageLabel = area.hasCoverage ? 'tested' : 'UNTESTED';
169
+ lines.push(`- **${area.file}**: complexity ${area.complexity.toFixed(1)}, max fn ${area.maxFnLen}L [${coverageLabel}]`);
170
+ }
171
+ }
172
+ // Suggested decomposition
173
+ lines.push('');
174
+ lines.push('## Suggested Spec Decomposition');
175
+ const hubs = result.dependencyGraph.hubs;
176
+ if (hubs.length > 0) {
177
+ lines.push(`- Hub modules (high fan-in) suggest natural spec boundaries: ${hubs.slice(0, 5).join(', ')}`);
178
+ }
179
+ if (result.apiRoutes.length > 0) {
180
+ const resources = [...new Set(result.apiRoutes.map((r) => r.resource))];
181
+ lines.push(`- API resources can be separate specs: ${resources.slice(0, 5).join(', ')}`);
182
+ }
183
+ if (result.dependencyGraph.orphans.length > 0) {
184
+ lines.push(`- Orphan modules (no dependents) are safe to refactor independently: ${result.dependencyGraph.orphans.slice(0, 5).join(', ')}`);
185
+ }
186
+ lines.push('');
187
+ lines.push(`*Analysis completed in ${result.analysisTimeMs}ms*`);
188
+ return lines.join('\n');
189
+ }
190
+ // --- Empty defaults ---
191
+ function emptyTestCoverage() {
192
+ return { testedModules: [], untestedModules: [], testToSourceRatio: 0 };
193
+ }
194
+ function emptyDependencyGraph() {
195
+ return { nodes: [], cycles: [], hubs: [], orphans: [] };
196
+ }
197
+ function emptyConfigReport() {
198
+ return { configFiles: [], envVars: [], featureFlags: [], infrastructure: [] };
199
+ }
200
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../../src/engine/reverse-engineer/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { TestCoverageReport } from '../../types/reverse-engineer.js';
2
+ export declare function isTestFile(filePath: string): boolean;
3
+ export declare function analyzeTestCoverage(rootDir: string): TestCoverageReport;
4
+ //# sourceMappingURL=test-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-analyzer.d.ts","sourceRoot":"","sources":["../../../src/engine/reverse-engineer/test-analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AA2C1E,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOpD;AAiED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAgCvE"}
@@ -0,0 +1,130 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const TEST_PATTERNS = [
4
+ /\.test\.\w+$/,
5
+ /\.spec\.\w+$/,
6
+ /_test\.\w+$/, // Go convention
7
+ /Test\.java$/, // JUnit convention
8
+ ];
9
+ const TEST_DIRS = new Set(['__tests__', 'test', 'tests', 'spec', 'specs']);
10
+ const SOURCE_EXTENSIONS = new Set([
11
+ '.ts',
12
+ '.tsx',
13
+ '.js',
14
+ '.jsx',
15
+ '.mjs',
16
+ '.cjs',
17
+ '.py',
18
+ '.go',
19
+ '.java',
20
+ '.kt',
21
+ '.rs',
22
+ '.rb',
23
+ '.cs',
24
+ '.cpp',
25
+ '.c',
26
+ '.swift',
27
+ ]);
28
+ const IGNORE_DIRS = new Set([
29
+ 'node_modules',
30
+ '.git',
31
+ 'dist',
32
+ 'build',
33
+ 'out',
34
+ '.next',
35
+ '.nuxt',
36
+ 'coverage',
37
+ 'vendor',
38
+ '__pycache__',
39
+ ]);
40
+ export function isTestFile(filePath) {
41
+ const basename = path.basename(filePath);
42
+ if (TEST_PATTERNS.some((p) => p.test(basename))) {
43
+ return true;
44
+ }
45
+ const parts = filePath.split(path.sep);
46
+ return parts.some((p) => TEST_DIRS.has(p));
47
+ }
48
+ function collectFiles(dir) {
49
+ const results = [];
50
+ const queue = [dir];
51
+ while (queue.length > 0) {
52
+ const current = queue.pop();
53
+ if (!current) {
54
+ continue;
55
+ }
56
+ let entries;
57
+ try {
58
+ entries = fs.readdirSync(current, { withFileTypes: true });
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ for (const entry of entries) {
64
+ if (IGNORE_DIRS.has(entry.name)) {
65
+ continue;
66
+ }
67
+ const full = path.join(current, entry.name);
68
+ if (entry.isDirectory()) {
69
+ queue.push(full);
70
+ }
71
+ else if (entry.isFile() && SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
72
+ results.push(full);
73
+ }
74
+ }
75
+ }
76
+ return results;
77
+ }
78
+ function mapTestToSource(testFile, sourceFiles, rootDir) {
79
+ const relative = path.relative(rootDir, testFile);
80
+ // Strip test dir prefix (tests/, test/, __tests__/)
81
+ const stripped = relative
82
+ .replace(/^(?:tests?|__tests__|specs?)[/\\]/, '')
83
+ .replace(/\.(?:test|spec)\./, '.')
84
+ .replace(/_test\./, '.')
85
+ .replace(/Test\.java$/, '.java');
86
+ // Try exact match
87
+ for (const src of sourceFiles) {
88
+ const srcRel = path.relative(rootDir, src);
89
+ if (srcRel === stripped) {
90
+ return srcRel;
91
+ }
92
+ }
93
+ // Try basename match
94
+ const targetBase = path.basename(stripped, path.extname(stripped));
95
+ for (const src of sourceFiles) {
96
+ const srcBase = path.basename(src, path.extname(src));
97
+ if (srcBase === targetBase) {
98
+ return path.relative(rootDir, src);
99
+ }
100
+ }
101
+ return undefined;
102
+ }
103
+ export function analyzeTestCoverage(rootDir) {
104
+ const allFiles = collectFiles(rootDir);
105
+ const testFiles = [];
106
+ const sourceFiles = [];
107
+ for (const f of allFiles) {
108
+ if (isTestFile(f)) {
109
+ testFiles.push(f);
110
+ }
111
+ else {
112
+ sourceFiles.push(f);
113
+ }
114
+ }
115
+ const testedSet = new Set();
116
+ for (const tf of testFiles) {
117
+ const mapped = mapTestToSource(tf, sourceFiles, rootDir);
118
+ if (mapped) {
119
+ testedSet.add(mapped);
120
+ }
121
+ }
122
+ const testedModules = [...testedSet].sort();
123
+ const untestedModules = sourceFiles
124
+ .map((f) => path.relative(rootDir, f))
125
+ .filter((f) => !testedSet.has(f))
126
+ .sort();
127
+ const testToSourceRatio = sourceFiles.length > 0 ? Math.round((testFiles.length / sourceFiles.length) * 100) / 100 : 0;
128
+ return { testedModules, untestedModules, testToSourceRatio };
129
+ }
130
+ //# sourceMappingURL=test-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-analyzer.js","sourceRoot":"","sources":["../../../src/engine/reverse-engineer/test-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { WriteOptions } from '../../types/safety.js';
2
+ /**
3
+ * Write JSON data atomically with backup rotation.
4
+ *
5
+ * 1. Rotate existing backups (if target exists).
6
+ * 2. Write to a `.tmp` sibling file.
7
+ * 3. Optionally verify the `.tmp` contents parse correctly.
8
+ * 4. Atomically rename `.tmp` to the target path.
9
+ *
10
+ * On failure during steps 2-4, the `.tmp` file is cleaned up silently.
11
+ */
12
+ export declare function writeJsonSafe(filePath: string, data: unknown, opts?: WriteOptions): Promise<void>;
13
+ /**
14
+ * Attempt to recover a file from its most recent backup.
15
+ *
16
+ * Checks `.bak.1`, `.bak.2`, `.bak.3` in order and copies the first
17
+ * one found back to the target path.
18
+ *
19
+ * @returns `true` if recovery succeeded, `false` if no backup exists.
20
+ */
21
+ export declare function recoverFromBackup(filePath: string, backupCount?: number): Promise<boolean>;
22
+ //# sourceMappingURL=atomic-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-writer.d.ts","sourceRoot":"","sources":["../../../src/engine/safety/atomic-writer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,WAAW,SAAuB,GACjC,OAAO,CAAC,OAAO,CAAC,CASlB"}
@@ -0,0 +1,89 @@
1
+ // atomic-writer.ts — Atomic JSON writes with backup rotation (SPEC-094 AC-1)
2
+ import { rename, copyFile, unlink, readFile, writeFile, mkdir } from 'node:fs/promises';
3
+ import { existsSync } from 'node:fs';
4
+ import { dirname } from 'node:path';
5
+ const DEFAULT_BACKUP_COUNT = 3;
6
+ /**
7
+ * Write JSON data atomically with backup rotation.
8
+ *
9
+ * 1. Rotate existing backups (if target exists).
10
+ * 2. Write to a `.tmp` sibling file.
11
+ * 3. Optionally verify the `.tmp` contents parse correctly.
12
+ * 4. Atomically rename `.tmp` to the target path.
13
+ *
14
+ * On failure during steps 2-4, the `.tmp` file is cleaned up silently.
15
+ */
16
+ export async function writeJsonSafe(filePath, data, opts) {
17
+ const backupCount = opts?.backupCount ?? DEFAULT_BACKUP_COUNT;
18
+ const verify = opts?.verify ?? true;
19
+ const tmpPath = `${filePath}.tmp`;
20
+ // Ensure parent directory exists
21
+ await mkdir(dirname(filePath), { recursive: true });
22
+ // Rotate backups if target already exists
23
+ if (existsSync(filePath)) {
24
+ await rotateBackups(filePath, backupCount);
25
+ await copyFile(filePath, `${filePath}.bak.1`);
26
+ }
27
+ // Serialize
28
+ const json = JSON.stringify(data, null, 2);
29
+ try {
30
+ // Write to temp file
31
+ await writeFile(tmpPath, json, 'utf-8');
32
+ // Verify round-trip if requested
33
+ if (verify) {
34
+ const readBack = await readFile(tmpPath, 'utf-8');
35
+ JSON.parse(readBack);
36
+ }
37
+ // Atomic rename
38
+ await rename(tmpPath, filePath);
39
+ }
40
+ catch (err) {
41
+ // Cleanup temp file silently
42
+ try {
43
+ await unlink(tmpPath);
44
+ }
45
+ catch {
46
+ // Ignore cleanup errors
47
+ }
48
+ throw err;
49
+ }
50
+ }
51
+ /**
52
+ * Attempt to recover a file from its most recent backup.
53
+ *
54
+ * Checks `.bak.1`, `.bak.2`, `.bak.3` in order and copies the first
55
+ * one found back to the target path.
56
+ *
57
+ * @returns `true` if recovery succeeded, `false` if no backup exists.
58
+ */
59
+ export async function recoverFromBackup(filePath, backupCount = DEFAULT_BACKUP_COUNT) {
60
+ for (let i = 1; i <= backupCount; i++) {
61
+ const bakPath = `${filePath}.bak.${i}`;
62
+ if (existsSync(bakPath)) {
63
+ await copyFile(bakPath, filePath);
64
+ return true;
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+ /**
70
+ * Rotate backup files: `.bak.{count-1}` -> `.bak.{count}`, etc.
71
+ *
72
+ * The oldest backup (`.bak.{count}`) is discarded if it exists.
73
+ */
74
+ async function rotateBackups(filePath, count) {
75
+ // Delete the oldest if it exists
76
+ const oldestPath = `${filePath}.bak.${count}`;
77
+ if (existsSync(oldestPath)) {
78
+ await unlink(oldestPath);
79
+ }
80
+ // Shift each backup up by one
81
+ for (let i = count - 1; i >= 1; i--) {
82
+ const src = `${filePath}.bak.${i}`;
83
+ const dst = `${filePath}.bak.${i + 1}`;
84
+ if (existsSync(src)) {
85
+ await rename(src, dst);
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=atomic-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-writer.js","sourceRoot":"","sources":["../../../src/engine/safety/atomic-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CircuitState, SafetyCircuitConfig } from '../../types/safety.js';
2
+ export declare class CircuitBreaker {
3
+ private readonly name;
4
+ private state;
5
+ private failureCount;
6
+ private lastFailureTime;
7
+ private readonly config;
8
+ constructor(name: string, config?: Partial<SafetyCircuitConfig>);
9
+ execute<T>(fn: () => Promise<T>, fallback?: T): Promise<T>;
10
+ getState(): CircuitState;
11
+ reset(): void;
12
+ getFailureCount(): number;
13
+ }
14
+ //# sourceMappingURL=circuit-breaker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../../src/engine/safety/circuit-breaker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAQ/E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;gBAE3C,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAKzD,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAqChE,QAAQ,IAAI,YAAY;IAIxB,KAAK,IAAI,IAAI;IAKb,eAAe,IAAI,MAAM;CAG1B"}
@@ -0,0 +1,63 @@
1
+ // SPEC-094 AC-5: Circuit breaker for storage operations
2
+ const DEFAULT_CONFIG = {
3
+ maxFailures: 3,
4
+ resetTimeoutMs: 60_000,
5
+ halfOpenMax: 1,
6
+ };
7
+ export class CircuitBreaker {
8
+ name;
9
+ state = 'closed';
10
+ failureCount = 0;
11
+ lastFailureTime = 0;
12
+ config;
13
+ constructor(name, config) {
14
+ this.name = name;
15
+ this.config = { ...DEFAULT_CONFIG, ...config };
16
+ }
17
+ async execute(fn, fallback) {
18
+ if (this.state === 'open') {
19
+ const elapsed = Date.now() - this.lastFailureTime;
20
+ if (elapsed >= this.config.resetTimeoutMs) {
21
+ this.state = 'half-open';
22
+ }
23
+ else {
24
+ if (fallback !== undefined) {
25
+ return fallback;
26
+ }
27
+ throw new Error(`Circuit open for ${this.name}`);
28
+ }
29
+ }
30
+ const wasHalfOpen = this.state === 'half-open';
31
+ try {
32
+ const result = await fn();
33
+ this.state = 'closed';
34
+ this.failureCount = 0;
35
+ return result;
36
+ }
37
+ catch (error) {
38
+ this.failureCount++;
39
+ this.lastFailureTime = Date.now();
40
+ if (wasHalfOpen) {
41
+ this.state = 'open';
42
+ }
43
+ else if (this.failureCount >= this.config.maxFailures) {
44
+ this.state = 'open';
45
+ }
46
+ if (fallback !== undefined) {
47
+ return fallback;
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ getState() {
53
+ return this.state;
54
+ }
55
+ reset() {
56
+ this.state = 'closed';
57
+ this.failureCount = 0;
58
+ }
59
+ getFailureCount() {
60
+ return this.failureCount;
61
+ }
62
+ }
63
+ //# sourceMappingURL=circuit-breaker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../../src/engine/safety/circuit-breaker.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAIxD,MAAM,cAAc,GAAkC;IACpD,WAAW,EAAE,CAAC;IACd,cAAc,EAAE,MAAM;IACtB,WAAW,EAAE,CAAC;CACf,CAAC;AAEF,MAAM,OAAO,cAAc;IACR,IAAI,CAAS;IACtB,KAAK,GAAiB,QAAQ,CAAC;IAC/B,YAAY,GAAG,CAAC,CAAC;IACjB,eAAe,GAAG,CAAC,CAAC;IACX,MAAM,CAAgC;IAEvD,YAAY,IAAY,EAAE,MAAqC;QAC7D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,OAAO,CAAI,EAAoB,EAAE,QAAY;QACjD,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC;YAClD,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC1C,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;oBAC3B,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC;QAE/C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;YACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;YACtB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAElC,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;YACtB,CAAC;iBAAM,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACxD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;YACtB,CAAC;YAED,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;QACtB,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import type { LockHandle } from '../../types/safety.js';
2
+ /**
3
+ * Acquires a file-based lock for a named resource.
4
+ * Polls until the lock is available or timeout expires.
5
+ * Stale locks (old timestamp or dead PID) are auto-released.
6
+ */
7
+ export declare function acquireLock(resource: string, timeoutMs?: number): Promise<LockHandle>;
8
+ /**
9
+ * Releases a previously acquired lock.
10
+ * No-op if the lock file was already removed.
11
+ */
12
+ export declare function releaseLock(handle: LockHandle): Promise<void>;
13
+ //# sourceMappingURL=file-mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-mutex.d.ts","sourceRoot":"","sources":["../../../src/engine/safety/file-mutex.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,uBAAuB,CAAC;AA4CzE;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,UAAU,CAAC,CAoDrB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnE"}