spec-gen-cli 1.0.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.
- package/LICENSE +21 -0
- package/README.md +1078 -0
- package/dist/api/analyze.d.ts +17 -0
- package/dist/api/analyze.d.ts.map +1 -0
- package/dist/api/analyze.js +109 -0
- package/dist/api/analyze.js.map +1 -0
- package/dist/api/drift.d.ts +21 -0
- package/dist/api/drift.d.ts.map +1 -0
- package/dist/api/drift.js +145 -0
- package/dist/api/drift.js.map +1 -0
- package/dist/api/generate.d.ts +18 -0
- package/dist/api/generate.d.ts.map +1 -0
- package/dist/api/generate.js +251 -0
- package/dist/api/generate.js.map +1 -0
- package/dist/api/index.d.ts +39 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +32 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/init.d.ts +18 -0
- package/dist/api/init.d.ts.map +1 -0
- package/dist/api/init.js +82 -0
- package/dist/api/init.js.map +1 -0
- package/dist/api/run.d.ts +19 -0
- package/dist/api/run.d.ts.map +1 -0
- package/dist/api/run.js +291 -0
- package/dist/api/run.js.map +1 -0
- package/dist/api/specs.d.ts +49 -0
- package/dist/api/specs.d.ts.map +1 -0
- package/dist/api/specs.js +136 -0
- package/dist/api/specs.js.map +1 -0
- package/dist/api/types.d.ts +176 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +9 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/verify.d.ts +20 -0
- package/dist/api/verify.d.ts.map +1 -0
- package/dist/api/verify.js +117 -0
- package/dist/api/verify.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +27 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -0
- package/dist/cli/commands/analyze.js +485 -0
- package/dist/cli/commands/analyze.js.map +1 -0
- package/dist/cli/commands/drift.d.ts +9 -0
- package/dist/cli/commands/drift.d.ts.map +1 -0
- package/dist/cli/commands/drift.js +540 -0
- package/dist/cli/commands/drift.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +9 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +633 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +171 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +638 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +574 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/run.d.ts +24 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +546 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/verify.d.ts +9 -0
- package/dist/cli/commands/verify.d.ts.map +1 -0
- package/dist/cli/commands/verify.js +417 -0
- package/dist/cli/commands/verify.js.map +1 -0
- package/dist/cli/commands/view.d.ts +9 -0
- package/dist/cli/commands/view.d.ts.map +1 -0
- package/dist/cli/commands/view.js +511 -0
- package/dist/cli/commands/view.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +83 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/analyzer/architecture-writer.d.ts +67 -0
- package/dist/core/analyzer/architecture-writer.d.ts.map +1 -0
- package/dist/core/analyzer/architecture-writer.js +209 -0
- package/dist/core/analyzer/architecture-writer.js.map +1 -0
- package/dist/core/analyzer/artifact-generator.d.ts +222 -0
- package/dist/core/analyzer/artifact-generator.d.ts.map +1 -0
- package/dist/core/analyzer/artifact-generator.js +726 -0
- package/dist/core/analyzer/artifact-generator.js.map +1 -0
- package/dist/core/analyzer/call-graph.d.ts +83 -0
- package/dist/core/analyzer/call-graph.d.ts.map +1 -0
- package/dist/core/analyzer/call-graph.js +827 -0
- package/dist/core/analyzer/call-graph.js.map +1 -0
- package/dist/core/analyzer/code-shaper.d.ts +33 -0
- package/dist/core/analyzer/code-shaper.d.ts.map +1 -0
- package/dist/core/analyzer/code-shaper.js +149 -0
- package/dist/core/analyzer/code-shaper.js.map +1 -0
- package/dist/core/analyzer/dependency-graph.d.ts +179 -0
- package/dist/core/analyzer/dependency-graph.d.ts.map +1 -0
- package/dist/core/analyzer/dependency-graph.js +574 -0
- package/dist/core/analyzer/dependency-graph.js.map +1 -0
- package/dist/core/analyzer/duplicate-detector.d.ts +52 -0
- package/dist/core/analyzer/duplicate-detector.d.ts.map +1 -0
- package/dist/core/analyzer/duplicate-detector.js +279 -0
- package/dist/core/analyzer/duplicate-detector.js.map +1 -0
- package/dist/core/analyzer/embedding-service.d.ts +50 -0
- package/dist/core/analyzer/embedding-service.d.ts.map +1 -0
- package/dist/core/analyzer/embedding-service.js +104 -0
- package/dist/core/analyzer/embedding-service.js.map +1 -0
- package/dist/core/analyzer/file-walker.d.ts +78 -0
- package/dist/core/analyzer/file-walker.d.ts.map +1 -0
- package/dist/core/analyzer/file-walker.js +531 -0
- package/dist/core/analyzer/file-walker.js.map +1 -0
- package/dist/core/analyzer/import-parser.d.ts +91 -0
- package/dist/core/analyzer/import-parser.d.ts.map +1 -0
- package/dist/core/analyzer/import-parser.js +720 -0
- package/dist/core/analyzer/import-parser.js.map +1 -0
- package/dist/core/analyzer/index.d.ts +10 -0
- package/dist/core/analyzer/index.d.ts.map +1 -0
- package/dist/core/analyzer/index.js +10 -0
- package/dist/core/analyzer/index.js.map +1 -0
- package/dist/core/analyzer/refactor-analyzer.d.ts +80 -0
- package/dist/core/analyzer/refactor-analyzer.d.ts.map +1 -0
- package/dist/core/analyzer/refactor-analyzer.js +339 -0
- package/dist/core/analyzer/refactor-analyzer.js.map +1 -0
- package/dist/core/analyzer/repository-mapper.d.ts +150 -0
- package/dist/core/analyzer/repository-mapper.d.ts.map +1 -0
- package/dist/core/analyzer/repository-mapper.js +731 -0
- package/dist/core/analyzer/repository-mapper.js.map +1 -0
- package/dist/core/analyzer/signature-extractor.d.ts +31 -0
- package/dist/core/analyzer/signature-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/signature-extractor.js +387 -0
- package/dist/core/analyzer/signature-extractor.js.map +1 -0
- package/dist/core/analyzer/significance-scorer.d.ts +79 -0
- package/dist/core/analyzer/significance-scorer.d.ts.map +1 -0
- package/dist/core/analyzer/significance-scorer.js +407 -0
- package/dist/core/analyzer/significance-scorer.js.map +1 -0
- package/dist/core/analyzer/subgraph-extractor.d.ts +43 -0
- package/dist/core/analyzer/subgraph-extractor.d.ts.map +1 -0
- package/dist/core/analyzer/subgraph-extractor.js +129 -0
- package/dist/core/analyzer/subgraph-extractor.js.map +1 -0
- package/dist/core/analyzer/vector-index.d.ts +63 -0
- package/dist/core/analyzer/vector-index.d.ts.map +1 -0
- package/dist/core/analyzer/vector-index.js +169 -0
- package/dist/core/analyzer/vector-index.js.map +1 -0
- package/dist/core/drift/drift-detector.d.ts +102 -0
- package/dist/core/drift/drift-detector.d.ts.map +1 -0
- package/dist/core/drift/drift-detector.js +597 -0
- package/dist/core/drift/drift-detector.js.map +1 -0
- package/dist/core/drift/git-diff.d.ts +55 -0
- package/dist/core/drift/git-diff.d.ts.map +1 -0
- package/dist/core/drift/git-diff.js +356 -0
- package/dist/core/drift/git-diff.js.map +1 -0
- package/dist/core/drift/index.d.ts +12 -0
- package/dist/core/drift/index.d.ts.map +1 -0
- package/dist/core/drift/index.js +9 -0
- package/dist/core/drift/index.js.map +1 -0
- package/dist/core/drift/spec-mapper.d.ts +73 -0
- package/dist/core/drift/spec-mapper.d.ts.map +1 -0
- package/dist/core/drift/spec-mapper.js +353 -0
- package/dist/core/drift/spec-mapper.js.map +1 -0
- package/dist/core/generator/adr-generator.d.ts +32 -0
- package/dist/core/generator/adr-generator.d.ts.map +1 -0
- package/dist/core/generator/adr-generator.js +192 -0
- package/dist/core/generator/adr-generator.js.map +1 -0
- package/dist/core/generator/index.d.ts +9 -0
- package/dist/core/generator/index.d.ts.map +1 -0
- package/dist/core/generator/index.js +12 -0
- package/dist/core/generator/index.js.map +1 -0
- package/dist/core/generator/mapping-generator.d.ts +54 -0
- package/dist/core/generator/mapping-generator.d.ts.map +1 -0
- package/dist/core/generator/mapping-generator.js +239 -0
- package/dist/core/generator/mapping-generator.js.map +1 -0
- package/dist/core/generator/openspec-compat.d.ts +160 -0
- package/dist/core/generator/openspec-compat.d.ts.map +1 -0
- package/dist/core/generator/openspec-compat.js +523 -0
- package/dist/core/generator/openspec-compat.js.map +1 -0
- package/dist/core/generator/openspec-format-generator.d.ts +111 -0
- package/dist/core/generator/openspec-format-generator.d.ts.map +1 -0
- package/dist/core/generator/openspec-format-generator.js +817 -0
- package/dist/core/generator/openspec-format-generator.js.map +1 -0
- package/dist/core/generator/openspec-writer.d.ts +131 -0
- package/dist/core/generator/openspec-writer.d.ts.map +1 -0
- package/dist/core/generator/openspec-writer.js +379 -0
- package/dist/core/generator/openspec-writer.js.map +1 -0
- package/dist/core/generator/prompts.d.ts +35 -0
- package/dist/core/generator/prompts.d.ts.map +1 -0
- package/dist/core/generator/prompts.js +212 -0
- package/dist/core/generator/prompts.js.map +1 -0
- package/dist/core/generator/spec-pipeline.d.ts +94 -0
- package/dist/core/generator/spec-pipeline.d.ts.map +1 -0
- package/dist/core/generator/spec-pipeline.js +474 -0
- package/dist/core/generator/spec-pipeline.js.map +1 -0
- package/dist/core/generator/stages/stage1-survey.d.ts +19 -0
- package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -0
- package/dist/core/generator/stages/stage1-survey.js +105 -0
- package/dist/core/generator/stages/stage1-survey.js.map +1 -0
- package/dist/core/generator/stages/stage2-entities.d.ts +11 -0
- package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -0
- package/dist/core/generator/stages/stage2-entities.js +67 -0
- package/dist/core/generator/stages/stage2-entities.js.map +1 -0
- package/dist/core/generator/stages/stage3-services.d.ts +11 -0
- package/dist/core/generator/stages/stage3-services.d.ts.map +1 -0
- package/dist/core/generator/stages/stage3-services.js +75 -0
- package/dist/core/generator/stages/stage3-services.js.map +1 -0
- package/dist/core/generator/stages/stage4-api.d.ts +11 -0
- package/dist/core/generator/stages/stage4-api.d.ts.map +1 -0
- package/dist/core/generator/stages/stage4-api.js +65 -0
- package/dist/core/generator/stages/stage4-api.js.map +1 -0
- package/dist/core/generator/stages/stage5-architecture.d.ts +10 -0
- package/dist/core/generator/stages/stage5-architecture.d.ts.map +1 -0
- package/dist/core/generator/stages/stage5-architecture.js +62 -0
- package/dist/core/generator/stages/stage5-architecture.js.map +1 -0
- package/dist/core/generator/stages/stage6-adr.d.ts +8 -0
- package/dist/core/generator/stages/stage6-adr.d.ts.map +1 -0
- package/dist/core/generator/stages/stage6-adr.js +41 -0
- package/dist/core/generator/stages/stage6-adr.js.map +1 -0
- package/dist/core/services/chat-agent.d.ts +45 -0
- package/dist/core/services/chat-agent.d.ts.map +1 -0
- package/dist/core/services/chat-agent.js +310 -0
- package/dist/core/services/chat-agent.js.map +1 -0
- package/dist/core/services/chat-tools.d.ts +32 -0
- package/dist/core/services/chat-tools.d.ts.map +1 -0
- package/dist/core/services/chat-tools.js +270 -0
- package/dist/core/services/chat-tools.js.map +1 -0
- package/dist/core/services/config-manager.d.ts +61 -0
- package/dist/core/services/config-manager.d.ts.map +1 -0
- package/dist/core/services/config-manager.js +143 -0
- package/dist/core/services/config-manager.js.map +1 -0
- package/dist/core/services/gitignore-manager.d.ts +29 -0
- package/dist/core/services/gitignore-manager.d.ts.map +1 -0
- package/dist/core/services/gitignore-manager.js +106 -0
- package/dist/core/services/gitignore-manager.js.map +1 -0
- package/dist/core/services/index.d.ts +8 -0
- package/dist/core/services/index.d.ts.map +1 -0
- package/dist/core/services/index.js +8 -0
- package/dist/core/services/index.js.map +1 -0
- package/dist/core/services/llm-service.d.ts +336 -0
- package/dist/core/services/llm-service.d.ts.map +1 -0
- package/dist/core/services/llm-service.js +1155 -0
- package/dist/core/services/llm-service.js.map +1 -0
- package/dist/core/services/mcp-handlers/analysis.d.ts +42 -0
- package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/analysis.js +300 -0
- package/dist/core/services/mcp-handlers/analysis.js.map +1 -0
- package/dist/core/services/mcp-handlers/graph.d.ts +65 -0
- package/dist/core/services/mcp-handlers/graph.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/graph.js +509 -0
- package/dist/core/services/mcp-handlers/graph.js.map +1 -0
- package/dist/core/services/mcp-handlers/semantic.d.ts +38 -0
- package/dist/core/services/mcp-handlers/semantic.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/semantic.js +172 -0
- package/dist/core/services/mcp-handlers/semantic.js.map +1 -0
- package/dist/core/services/mcp-handlers/utils.d.ts +21 -0
- package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -0
- package/dist/core/services/mcp-handlers/utils.js +62 -0
- package/dist/core/services/mcp-handlers/utils.js.map +1 -0
- package/dist/core/services/project-detector.d.ts +32 -0
- package/dist/core/services/project-detector.d.ts.map +1 -0
- package/dist/core/services/project-detector.js +111 -0
- package/dist/core/services/project-detector.js.map +1 -0
- package/dist/core/verifier/index.d.ts +5 -0
- package/dist/core/verifier/index.d.ts.map +1 -0
- package/dist/core/verifier/index.js +5 -0
- package/dist/core/verifier/index.js.map +1 -0
- package/dist/core/verifier/verification-engine.d.ts +226 -0
- package/dist/core/verifier/verification-engine.d.ts.map +1 -0
- package/dist/core/verifier/verification-engine.js +681 -0
- package/dist/core/verifier/verification-engine.js.map +1 -0
- package/dist/types/index.d.ts +252 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/pipeline.d.ts +148 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +5 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/utils/errors.d.ts +51 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +128 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +149 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +331 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/progress.d.ts +142 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +280 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/prompts.d.ts +53 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +199 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/shutdown.d.ts +89 -0
- package/dist/utils/shutdown.d.ts.map +1 -0
- package/dist/utils/shutdown.js +237 -0
- package/dist/utils/shutdown.js.map +1 -0
- package/package.json +114 -0
- package/src/viewer/InteractiveGraphViewer.jsx +1486 -0
- package/src/viewer/app/index.html +17 -0
- package/src/viewer/app/main.jsx +13 -0
- package/src/viewer/components/ArchitectureView.jsx +177 -0
- package/src/viewer/components/ChatPanel.jsx +448 -0
- package/src/viewer/components/ClusterGraph.jsx +441 -0
- package/src/viewer/components/FilterBar.jsx +179 -0
- package/src/viewer/components/FlatGraph.jsx +275 -0
- package/src/viewer/components/MicroComponents.jsx +83 -0
- package/src/viewer/hooks/usePanZoom.js +79 -0
- package/src/viewer/utils/constants.js +47 -0
- package/src/viewer/utils/graph-helpers.js +291 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for each generation stage.
|
|
3
|
+
* These are used by the stage functions to construct LLM requests.
|
|
4
|
+
*/
|
|
5
|
+
export const PROMPTS = {
|
|
6
|
+
stage1_survey: `You are a senior software architect performing a codebase audit.
|
|
7
|
+
Your task is to categorize this project based on the analysis data provided.
|
|
8
|
+
|
|
9
|
+
Respond with a JSON object containing:
|
|
10
|
+
- projectCategory: One of ["web-frontend", "web-backend", "api-service", "cli-tool", "library", "mobile-app", "desktop-app", "data-pipeline", "ml-service", "monorepo", "other"]
|
|
11
|
+
- primaryLanguage: The main language
|
|
12
|
+
- frameworks: Array of detected frameworks
|
|
13
|
+
- architecturePattern: One of ["layered", "hexagonal", "microservices", "monolith", "serverless", "event-driven", "mvc", "other"]
|
|
14
|
+
- domainSummary: One sentence describing what this system does
|
|
15
|
+
- suggestedDomains: Array of domain names for OpenSpec specs (e.g., ["user", "order", "auth", "api"])
|
|
16
|
+
- confidence: 0-1 score of how confident you are
|
|
17
|
+
- schemaFiles: Array of file paths (from the provided file list) that define data models, types, entities, or interfaces — these will be used for entity extraction. Include files regardless of their name, based on their content role.
|
|
18
|
+
- serviceFiles: Array of file paths containing business logic, services, processors, analyzers, pipelines, or domain operations — used for service analysis. Do not filter by name conventions; look at what the file does.
|
|
19
|
+
- apiFiles: Array of file paths that expose public interfaces: HTTP routes, CLI command handlers, GraphQL resolvers, message consumers, or external-facing APIs.
|
|
20
|
+
|
|
21
|
+
For schemaFiles/serviceFiles/apiFiles: use the exact file paths from the provided analysis. Return [] if none apply.
|
|
22
|
+
|
|
23
|
+
Example output:
|
|
24
|
+
{
|
|
25
|
+
"projectCategory": "api-service",
|
|
26
|
+
"primaryLanguage": "TypeScript",
|
|
27
|
+
"frameworks": ["Express", "Prisma"],
|
|
28
|
+
"architecturePattern": "layered",
|
|
29
|
+
"domainSummary": "REST API managing e-commerce orders and inventory.",
|
|
30
|
+
"suggestedDomains": ["order", "product", "auth"],
|
|
31
|
+
"confidence": 0.85,
|
|
32
|
+
"schemaFiles": ["src/models/order.ts", "src/types/product.ts"],
|
|
33
|
+
"serviceFiles": ["src/services/order-service.ts", "src/core/inventory.ts"],
|
|
34
|
+
"apiFiles": ["src/routes/orders.ts", "src/cli/commands/create.ts"]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Respond ONLY with valid JSON.`,
|
|
38
|
+
stage2_entities: (projectCategory, frameworks) => `You are analyzing the core data models of a ${projectCategory} built with ${frameworks.join(', ')}.
|
|
39
|
+
|
|
40
|
+
For each entity you identify, extract in OpenSpec format:
|
|
41
|
+
- name: The entity name (e.g., "User", "Order")
|
|
42
|
+
- description: What this entity represents in the business domain
|
|
43
|
+
- properties: Array of {name, type, description, required}
|
|
44
|
+
- relationships: Array of {targetEntity, type, description}
|
|
45
|
+
- validations: Array of validation rules as strings (these become Requirements)
|
|
46
|
+
- scenarios: Array of {name, given, when, then, and?} - observable behaviors in Given/When/Then format
|
|
47
|
+
|
|
48
|
+
Focus on BUSINESS entities, not framework internals.
|
|
49
|
+
Be precise - only include what you can verify from the code.
|
|
50
|
+
|
|
51
|
+
Example output:
|
|
52
|
+
[{
|
|
53
|
+
"name": "Order",
|
|
54
|
+
"description": "Represents a customer purchase transaction.",
|
|
55
|
+
"properties": [
|
|
56
|
+
{"name": "id", "type": "string", "description": "Unique identifier", "required": true},
|
|
57
|
+
{"name": "status", "type": "OrderStatus", "description": "Current lifecycle state", "required": true}
|
|
58
|
+
],
|
|
59
|
+
"relationships": [{"targetEntity": "User", "type": "belongs-to", "description": "Order belongs to a customer"}],
|
|
60
|
+
"validations": ["Total must be positive", "Status transitions: pending → confirmed → shipped"],
|
|
61
|
+
"scenarios": [{"name": "Place order", "given": "User with items in cart", "when": "submitOrder() is called", "then": "Order created with status 'pending' and inventory reserved"}],
|
|
62
|
+
"location": ""
|
|
63
|
+
}]
|
|
64
|
+
|
|
65
|
+
Respond with a JSON array of entities. Respond ONLY with valid JSON.`,
|
|
66
|
+
stage3_services: (projectCategory, entities, suggestedDomains) => `You are analyzing the logic and processing layer of a ${projectCategory}.
|
|
67
|
+
|
|
68
|
+
Known entities: ${entities.join(', ')}
|
|
69
|
+
Available domains: ${suggestedDomains.join(', ')}
|
|
70
|
+
|
|
71
|
+
For each service/module, identify:
|
|
72
|
+
- name: Service name
|
|
73
|
+
- purpose: What capability or responsibility it encapsulates
|
|
74
|
+
- operations: Array of {name, description, inputs, outputs, scenarios, functionName} - key operations/methods that become Requirements with Scenarios. Cover all meaningful operations that represent distinct business behaviors.
|
|
75
|
+
- operations[].functionName: The exact function or method name as written in the source code that implements this operation (e.g. "runStage2", "buildSpecMap"). Leave empty string if uncertain.
|
|
76
|
+
- dependencies: Array of other services/repositories it uses
|
|
77
|
+
- sideEffects: Array of external interactions (file I/O, network calls, database, queues, etc.)
|
|
78
|
+
- domain: Which domain OWNS this service (where it lives in the codebase, not who uses it) — use ONLY one of the available domains listed above
|
|
79
|
+
|
|
80
|
+
Focus on WHAT the service does, not HOW it's implemented.
|
|
81
|
+
Express operations as requirements (SHALL/MUST/SHOULD) with testable scenarios.
|
|
82
|
+
|
|
83
|
+
Example output:
|
|
84
|
+
[{
|
|
85
|
+
"name": "OrderService",
|
|
86
|
+
"purpose": "Manages order lifecycle: placement, validation, and fulfillment.",
|
|
87
|
+
"operations": [
|
|
88
|
+
{
|
|
89
|
+
"name": "placeOrder",
|
|
90
|
+
"description": "Validates cart contents and creates a new order record.",
|
|
91
|
+
"inputs": ["userId: string", "items: CartItem[]"],
|
|
92
|
+
"outputs": ["orderId: string"],
|
|
93
|
+
"functionName": "placeOrder",
|
|
94
|
+
"scenarios": [{"name": "Valid order", "given": "In-stock items in cart", "when": "placeOrder is called", "then": "Order persisted and inventory reserved"}]
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"dependencies": ["InventoryService", "OrderRepository"],
|
|
98
|
+
"sideEffects": ["Writes to orders table", "Sends confirmation email via queue"],
|
|
99
|
+
"domain": "order"
|
|
100
|
+
}]
|
|
101
|
+
|
|
102
|
+
Respond with a JSON array of services. Respond ONLY with valid JSON.`,
|
|
103
|
+
stage4_api: `Extract the public API surface of this application.
|
|
104
|
+
|
|
105
|
+
For each endpoint/interface, structure as:
|
|
106
|
+
- method: HTTP method or interface type
|
|
107
|
+
- path: Route path or interface signature
|
|
108
|
+
- purpose: What it does (becomes requirement description)
|
|
109
|
+
- authentication: Required auth (if detectable)
|
|
110
|
+
- requestSchema: Expected input as JSON object
|
|
111
|
+
- responseSchema: Expected output as JSON object
|
|
112
|
+
- scenarios: Array of {name, given, when, then, and?} - example request/response flows
|
|
113
|
+
- relatedEntity: Which domain entity it operates on
|
|
114
|
+
|
|
115
|
+
Example output:
|
|
116
|
+
[{
|
|
117
|
+
"method": "POST",
|
|
118
|
+
"path": "/api/orders",
|
|
119
|
+
"purpose": "Create a new order from the current cart.",
|
|
120
|
+
"authentication": "Bearer JWT",
|
|
121
|
+
"requestSchema": {"userId": "string", "items": "CartItem[]"},
|
|
122
|
+
"responseSchema": {"orderId": "string", "status": "pending"},
|
|
123
|
+
"scenarios": [{"name": "Create order", "given": "Authenticated user with valid cart", "when": "POST /api/orders is called", "then": "201 Created with orderId in response body"}],
|
|
124
|
+
"relatedEntity": "Order"
|
|
125
|
+
}]
|
|
126
|
+
|
|
127
|
+
Respond with a JSON array of endpoints. Respond ONLY with valid JSON.`,
|
|
128
|
+
stage5_architecture: (survey) => `Based on the analysis data, synthesize a complete architecture overview for OpenSpec.
|
|
129
|
+
|
|
130
|
+
Project context: ${survey.domainSummary}
|
|
131
|
+
Architecture pattern: ${survey.architecturePattern}
|
|
132
|
+
Domains: ${survey.suggestedDomains.join(', ')}
|
|
133
|
+
|
|
134
|
+
Include:
|
|
135
|
+
- systemPurpose: 2-3 sentences on what this system does and why
|
|
136
|
+
- architectureStyle: The overall architecture pattern with justification
|
|
137
|
+
- layerMap: Array of {name, purpose, components} - how code is organized
|
|
138
|
+
- dataFlow: How data moves through the system (entry to persistence) as a string
|
|
139
|
+
- integrations: Array of external systems this interacts with
|
|
140
|
+
- securityModel: Authentication/authorization approach as a string
|
|
141
|
+
- keyDecisions: Array of observable architectural decisions as strings
|
|
142
|
+
|
|
143
|
+
Express each key architectural aspect clearly.
|
|
144
|
+
Base all conclusions on the code evidence provided.
|
|
145
|
+
Where uncertain, say so explicitly.
|
|
146
|
+
|
|
147
|
+
Example output:
|
|
148
|
+
{
|
|
149
|
+
"systemPurpose": "A REST API for e-commerce order management. It allows customers to browse products, place orders, and track fulfillment.",
|
|
150
|
+
"architectureStyle": "Layered architecture: HTTP routes → service layer → repository pattern over PostgreSQL.",
|
|
151
|
+
"layerMap": [
|
|
152
|
+
{"name": "API", "purpose": "HTTP routing and input validation", "components": ["routes/orders.ts", "routes/products.ts"]},
|
|
153
|
+
{"name": "Service", "purpose": "Business logic and orchestration", "components": ["services/order-service.ts"]}
|
|
154
|
+
],
|
|
155
|
+
"dataFlow": "HTTP request → route handler → service → repository → PostgreSQL; async email notifications via Redis queue",
|
|
156
|
+
"integrations": ["PostgreSQL", "Redis", "SendGrid"],
|
|
157
|
+
"securityModel": "JWT Bearer tokens issued at login; route middleware enforces authentication on all /api/* routes",
|
|
158
|
+
"keyDecisions": ["Use Prisma ORM for type-safe database access", "Redis queue for async email notifications to avoid request latency"]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
Respond with a JSON object. Respond ONLY with valid JSON.`,
|
|
162
|
+
stage6_adr: (architecture) => `You are a senior software architect creating Architecture Decision Records (ADRs).
|
|
163
|
+
|
|
164
|
+
For each key decision listed below, produce a complete ADR with:
|
|
165
|
+
- id: Sequential like "ADR-001", "ADR-002", etc.
|
|
166
|
+
- title: The decision as a clear statement (e.g., "Use TypeORM for database access")
|
|
167
|
+
- status: "accepted" (these are observed decisions already implemented in the code)
|
|
168
|
+
- context: 2-3 sentences on why this decision was needed
|
|
169
|
+
- decision: 1-2 sentences clearly stating what was decided
|
|
170
|
+
- consequences: Array of 2-4 consequences (include both positive and negative)
|
|
171
|
+
- alternatives: Array of 1-3 alternatives that could have been chosen instead
|
|
172
|
+
- relatedLayers: Array of architecture layer names affected (from: ${architecture.layerMap.map(l => l.name).join(', ')})
|
|
173
|
+
- relatedDomains: Array of domain names affected
|
|
174
|
+
|
|
175
|
+
Architecture context:
|
|
176
|
+
- System purpose: ${architecture.systemPurpose}
|
|
177
|
+
- Architecture style: ${architecture.architectureStyle}
|
|
178
|
+
- Layers: ${architecture.layerMap.map(l => `${l.name} (${l.purpose})`).join(', ')}
|
|
179
|
+
- Data flow: ${architecture.dataFlow}
|
|
180
|
+
- Security model: ${architecture.securityModel}
|
|
181
|
+
- External integrations: ${architecture.integrations.join(', ') || 'None'}
|
|
182
|
+
|
|
183
|
+
Key decisions to expand into full ADRs:
|
|
184
|
+
${architecture.keyDecisions.map((d, i) => `${i + 1}. ${d}`).join('\n')}
|
|
185
|
+
|
|
186
|
+
Base all conclusions on the code evidence provided. Where uncertain, say so explicitly.
|
|
187
|
+
Respond with a JSON array of ADR objects. Respond ONLY with valid JSON.`,
|
|
188
|
+
stage3_subspec_system: `You are generating sub-specifications for the logical blocks of an orchestrator function.
|
|
189
|
+
|
|
190
|
+
For each sub-block provided, generate a focused specification:
|
|
191
|
+
- name: short camelCase identifier (e.g. "entityExtraction", "schemaValidation")
|
|
192
|
+
- callee: exact function/method name as written in source code
|
|
193
|
+
- purpose: one sentence describing what this block does
|
|
194
|
+
- operations: array of {name, description, inputs, outputs, scenarios, functionName}
|
|
195
|
+
- Express operations as requirements using SHALL/MUST/SHOULD keywords
|
|
196
|
+
- Include at least one testable scenario per operation
|
|
197
|
+
|
|
198
|
+
Focus on WHAT each block does, not HOW it is implemented.
|
|
199
|
+
Respond ONLY with a valid JSON array of sub-specification objects.`,
|
|
200
|
+
stage3_subspec: (orchestratorName, orchestratorPurpose, callees) => `Orchestrator function: ${orchestratorName}
|
|
201
|
+
Purpose: ${orchestratorPurpose}
|
|
202
|
+
|
|
203
|
+
Sub-blocks to specify:
|
|
204
|
+
${callees.map((c, i) => `${i + 1}. ${c.name}` +
|
|
205
|
+
(c.signature ? `\n Signature: ${c.signature}` : '') +
|
|
206
|
+
(c.docstring ? `\n Doc: ${c.docstring}` : '') +
|
|
207
|
+
(c.subcallees.length > 0 ? `\n Calls: ${c.subcallees.join(', ')}` : '')).join('\n')}
|
|
208
|
+
|
|
209
|
+
Generate one sub-specification per sub-block listed above.
|
|
210
|
+
Respond ONLY with a valid JSON array of {name, callee, purpose, operations} objects.`,
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/core/generator/prompts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA+Ba;IAE5B,eAAe,EAAE,CAAC,eAAuB,EAAE,UAAoB,EAAE,EAAE,CAAC,+CAA+C,eAAe,eAAe,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;qEA2BnG;IAEnE,eAAe,EAAE,CAAC,eAAuB,EAAE,QAAkB,EAAE,gBAA0B,EAAE,EAAE,CAAC,yDAAyD,eAAe;;kBAEtJ,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;qBAChB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qEAiCqB;IAEnE,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;sEAwBwD;IAEpE,mBAAmB,EAAE,CAAC,MAA0F,EAAE,EAAE,CAAC;;mBAEpG,MAAM,CAAC,aAAa;wBACf,MAAM,CAAC,mBAAmB;WACvC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0DA6Ba;IAExD,UAAU,EAAE,CAAC,YAA0M,EAAE,EAAE,CAAC;;;;;;;;;;qEAUzJ,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;oBAIlG,YAAY,CAAC,aAAa;wBACtB,YAAY,CAAC,iBAAiB;YAC1C,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;eAClE,YAAY,CAAC,QAAQ;oBAChB,YAAY,CAAC,aAAa;2BACnB,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM;;;EAGvE,YAAY,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;wEAGE;IAEtE,qBAAqB,EAAE;;;;;;;;;;;mEAW0C;IAEjE,cAAc,EAAE,CACd,gBAAwB,EACxB,mBAA2B,EAC3B,OAA8F,EAC9F,EAAE,CAAC,0BAA0B,gBAAgB;WACtC,mBAAmB;;;EAG5B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACrB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE;QACrB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC1E,CAAC,IAAI,CAAC,IAAI,CAAC;;;qFAGyE;CACpF,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec Generation Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the multi-step LLM process to generate accurate specifications
|
|
5
|
+
* in OpenSpec format from code analysis.
|
|
6
|
+
*/
|
|
7
|
+
import type { LLMService } from '../services/llm-service.js';
|
|
8
|
+
import type { RepoStructure, LLMContext } from '../analyzer/artifact-generator.js';
|
|
9
|
+
import type { DependencyGraphResult } from '../analyzer/dependency-graph.js';
|
|
10
|
+
import type { PipelineResult, StageResult, PipelineOptions, PipelineContext, ServiceSubSpec } from '../../types/pipeline.js';
|
|
11
|
+
export type { ProjectCategory, ArchitecturePattern, ProjectSurveyResult, EntityProperty, EntityRelationship, Scenario, ExtractedEntity, ServiceOperation, ServiceSubSpec, ExtractedService, ExtractedEndpoint, ArchitectureLayer, ArchitectureSynthesis, EnrichedADR, PipelineResult, StageResult, PipelineOptions, PipelineContext, } from '../../types/pipeline.js';
|
|
12
|
+
/**
|
|
13
|
+
* Spec Generation Pipeline
|
|
14
|
+
*/
|
|
15
|
+
export declare class SpecGenerationPipeline implements PipelineContext {
|
|
16
|
+
llm: LLMService;
|
|
17
|
+
options: Required<Omit<PipelineOptions, 'progress'>>;
|
|
18
|
+
private progress?;
|
|
19
|
+
/** Set at the start of run() and used by stage methods for graph-based prompts */
|
|
20
|
+
private currentLLMContext?;
|
|
21
|
+
constructor(llm: LLMService, options: PipelineOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Run the complete pipeline
|
|
24
|
+
*/
|
|
25
|
+
run(repoStructure: RepoStructure, llmContext: LLMContext, depGraph?: DependencyGraphResult): Promise<PipelineResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a stage should run
|
|
28
|
+
*/
|
|
29
|
+
private shouldRunStage;
|
|
30
|
+
/**
|
|
31
|
+
* Split file content into chunks, breaking only on blank lines (function/class boundaries).
|
|
32
|
+
* A chunk is emitted when its size exceeds maxChars and a blank line is encountered.
|
|
33
|
+
* overlapLines trailing lines from the previous chunk are prepended to the next one,
|
|
34
|
+
* preserving context (e.g. class declaration visible when processing its methods).
|
|
35
|
+
*/
|
|
36
|
+
chunkContent(content: string, maxChars: number, overlapLines?: number): string[];
|
|
37
|
+
/**
|
|
38
|
+
* For a large file, try to build a graph-based prompt section.
|
|
39
|
+
* Returns null when no call graph data is available or the file has no god functions
|
|
40
|
+
* (caller should fall back to raw source chunking).
|
|
41
|
+
*
|
|
42
|
+
* When file content is provided, appends a stripped skeleton when it achieves
|
|
43
|
+
* a meaningful size reduction (≥ 20%), giving the LLM both topology and
|
|
44
|
+
* internal control-flow structure.
|
|
45
|
+
*/
|
|
46
|
+
graphPromptFor(filePath: string, content?: string): string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Generate sub-specifications for the direct callees of god functions in a file.
|
|
49
|
+
* Makes a single batched LLM call covering all callees at once.
|
|
50
|
+
* Returns [] when no graph data or no god functions are found.
|
|
51
|
+
*/
|
|
52
|
+
generateSubSpecs(filePath: string, parentName: string, parentPurpose: string): Promise<ServiceSubSpec[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Get schema files from LLM context
|
|
55
|
+
*/
|
|
56
|
+
private getSchemaFiles;
|
|
57
|
+
/**
|
|
58
|
+
* Get service files from LLM context
|
|
59
|
+
*/
|
|
60
|
+
private getServiceFiles;
|
|
61
|
+
/**
|
|
62
|
+
* Get API files from LLM context
|
|
63
|
+
*/
|
|
64
|
+
private getApiFiles;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve file paths identified by Stage 1 LLM to actual file content.
|
|
67
|
+
* First looks in phase2_deep (already in memory); if not found and rootPath is set,
|
|
68
|
+
* reads the file from disk so that files outside the top-20 scored set can still
|
|
69
|
+
* be analyzed in later stages.
|
|
70
|
+
* Falls back to the provided heuristic list if no paths resolve.
|
|
71
|
+
*/
|
|
72
|
+
private resolveFiles;
|
|
73
|
+
/**
|
|
74
|
+
* Get default survey when stage is skipped
|
|
75
|
+
*/
|
|
76
|
+
private getDefaultSurvey;
|
|
77
|
+
/**
|
|
78
|
+
* Get default architecture when stage is skipped
|
|
79
|
+
*/
|
|
80
|
+
private getDefaultArchitecture;
|
|
81
|
+
/**
|
|
82
|
+
* Save intermediate result
|
|
83
|
+
*/
|
|
84
|
+
saveResult(name: string, data: unknown): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Load previous stage result (for resume)
|
|
87
|
+
*/
|
|
88
|
+
loadStageResult<T>(stage: string): Promise<StageResult<T> | null>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Run the spec generation pipeline
|
|
92
|
+
*/
|
|
93
|
+
export declare function runSpecGenerationPipeline(llm: LLMService, repoStructure: RepoStructure, llmContext: LLMContext, options: PipelineOptions, depGraph?: DependencyGraphResult): Promise<PipelineResult>;
|
|
94
|
+
//# sourceMappingURL=spec-pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-pipeline.d.ts","sourceRoot":"","sources":["../../../src/core/generator/spec-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAGnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAS7E,OAAO,KAAK,EAQV,cAAc,EACd,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACf,MAAM,yBAAyB,CAAC;AAGjC,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,WAAW,EACX,cAAc,EACd,WAAW,EACX,eAAe,EACf,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAMjC;;GAEG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAC5D,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC,CAAC;IACrD,OAAO,CAAC,QAAQ,CAAC,CAAoB;IACrC,kFAAkF;IAClF,OAAO,CAAC,iBAAiB,CAAC,CAAa;gBAE3B,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,eAAe;IAcrD;;OAEG;IACG,GAAG,CACP,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,cAAc,CAAC;IAyL1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,SAAK,GAAG,MAAM,EAAE;IA6B5E;;;;;;;;OAQG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAuBjE;;;;OAIG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,cAAc,EAAE,CAAC;IAwE5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,WAAW;IAgBnB;;;;;;OAMG;YACW,YAAY;IAuC1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5D;;OAEG;IACG,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CASxE;AAMD;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,UAAU,EACf,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,eAAe,EACxB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAGzB"}
|