@contractspec/bundle.workspace 0.0.0-canary-20260113173657 → 0.0.0-canary-20260119222405

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 (29) hide show
  1. package/dist/index.d.mts +6 -3
  2. package/dist/index.mjs +4 -1
  3. package/dist/services/import/import-service.d.mts +47 -0
  4. package/dist/services/import/import-service.d.mts.map +1 -0
  5. package/dist/services/import/import-service.mjs +196 -0
  6. package/dist/services/import/import-service.mjs.map +1 -0
  7. package/dist/services/import/index.d.mts +3 -0
  8. package/dist/services/import/index.mjs +5 -0
  9. package/dist/services/import/report-service.d.mts +31 -0
  10. package/dist/services/import/report-service.d.mts.map +1 -0
  11. package/dist/services/import/report-service.mjs +124 -0
  12. package/dist/services/import/report-service.mjs.map +1 -0
  13. package/dist/services/import/verify-service.d.mts +67 -0
  14. package/dist/services/import/verify-service.d.mts.map +1 -0
  15. package/dist/services/import/verify-service.mjs +105 -0
  16. package/dist/services/import/verify-service.mjs.map +1 -0
  17. package/dist/services/index.d.mts +5 -1
  18. package/dist/services/index.mjs +4 -0
  19. package/dist/services/openapi/import-service.d.mts +2 -2
  20. package/dist/services/openapi/import-service.d.mts.map +1 -1
  21. package/dist/services/openapi/import-service.mjs +3 -6
  22. package/dist/services/openapi/import-service.mjs.map +1 -1
  23. package/dist/services/openapi/sync-service.d.mts +2 -2
  24. package/dist/services/openapi/sync-service.d.mts.map +1 -1
  25. package/dist/services/openapi/sync-service.mjs.map +1 -1
  26. package/dist/services/rulesync.d.mts.map +1 -1
  27. package/dist/services/rulesync.mjs +4 -3
  28. package/dist/services/rulesync.mjs.map +1 -1
  29. package/package.json +9 -8
package/dist/index.d.mts CHANGED
@@ -55,7 +55,7 @@ import { ClaudeCodeAdapter, claudeCodeAdapter } from "./services/agent-guide/ada
55
55
  import { CursorCLIAdapter, cursorCLIAdapter } from "./services/agent-guide/adapters/cursor-cli.mjs";
56
56
  import { GenericMCPAdapter, genericMCPAdapter } from "./services/agent-guide/adapters/generic-mcp.mjs";
57
57
  import { agentAdapters, getAgentAdapter, listAgentTypes } from "./services/agent-guide/adapters/index.mjs";
58
- import { VerificationIssue, formatVerificationReport, verifyImplementationAgainstParsedSpec } from "./services/llm/verify-static.mjs";
58
+ import { VerificationIssue as VerificationIssue$1, formatVerificationReport, verifyImplementationAgainstParsedSpec } from "./services/llm/verify-static.mjs";
59
59
  import { exportSpecForLLM, generateCursorRulesFromParsedSpec, generateFeatureContextMarkdown, generateGuideFromParsedSpec } from "./services/llm/index.mjs";
60
60
  import { AIGenerator } from "./services/create/ai-generator.mjs";
61
61
  import { generateOperationSpec } from "./templates/operation.template.mjs";
@@ -74,7 +74,7 @@ import { generateWorkflowRunnerTemplate } from "./templates/workflow-runner.temp
74
74
  import { FeatureSpecParams, generateFeatureSpec } from "./templates/feature.template.mjs";
75
75
  import { index_d_exports as index_d_exports$6 } from "./templates/index.mjs";
76
76
  import { SpecCreatorService, createSpecCreator } from "./services/create/index.mjs";
77
- import { AIReviewResult, BehaviorCheck, FieldMapping, FieldMatchType, IntentAlignment, SemanticVerificationResult, StructureCheck, VerifyConfig, VerifyInput, VerifyOptions, VerifyResult } from "./services/verify/types.mjs";
77
+ import { AIReviewResult, BehaviorCheck, FieldMapping, FieldMatchType, IntentAlignment, SemanticVerificationResult, StructureCheck, VerifyConfig, VerifyInput, VerifyOptions as VerifyOptions$1, VerifyResult as VerifyResult$1 } from "./services/verify/types.mjs";
78
78
  import { VerifyService, createVerifyService, verifyService } from "./services/verify/verify-service.mjs";
79
79
  import { verifyStructure } from "./services/verify/structure-verifier.mjs";
80
80
  import { verifyBehavior } from "./services/verify/behavior-verifier.mjs";
@@ -108,6 +108,9 @@ import { GapAnalysisResult, analyzeGap } from "./services/gap.mjs";
108
108
  import { GenerateArtifactsResult, generateArtifacts } from "./services/generate-artifacts.mjs";
109
109
  import { ExtractOptions, extractContracts } from "./services/extract.mjs";
110
110
  import { index_d_exports as index_d_exports$10 } from "./services/vibe/index.mjs";
111
+ import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./services/import/import-service.mjs";
112
+ import { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts } from "./services/import/verify-service.mjs";
113
+ import { ReportOptions, generateCliReport, generateMarkdownReport } from "./services/import/report-service.mjs";
111
114
  import "./services/index.mjs";
112
115
  import { index_d_exports as index_d_exports$2 } from "./formatters/index.mjs";
113
116
  import { AIClient } from "./ai/client.mjs";
@@ -122,4 +125,4 @@ import { index_d_exports as index_d_exports$5 } from "./ai/prompts/index.mjs";
122
125
  import "./ai/index.mjs";
123
126
  import { index_d_exports as index_d_exports$8 } from "./utils/index.mjs";
124
127
  import * as module from "@contractspec/module.workspace";
125
- export { AIClient, AIGenerator, AIReviewResult, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentAdapter, AgentConfig, AgentGuideConfig, AgentGuideService, type AgentMode, AgentOrchestrator, AgentProvider, AgentResult, AgentTask, AiAdapter, AiGenerateOptions, AiGenerateResult, AiGenerateStructuredOptions, type AiProvider, AiValidationResult, AnalyzeDepsOptions, AnalyzeDepsResult, BehaviorCheck, BlueprintValidationResult, BuildSpecOptions, BuildSpecResult, BuildTarget, BuildTargetResult, CHECK_CATEGORY_LABELS, CICheckCategory, CICheckCategorySummary, CICheckOptions, CICheckResult, CIFormatOptions, CIIssue, CIIssueSeverity, CIOutputFormat, CI_CHECK_CATEGORY_LABELS, CacheEntryMeta, CacheKeyString, CacheLookupResult, CacheMissReason, CacheStats, CacheStorageAdapter, CheckCategory, CheckContext, CheckResult, CheckStatus, ClaudeCodeAdapter, ClaudeCodeAgent, CleanOptions, CleanResult, CompareSpecsOptions, CompareSpecsResult, type Config, CoverageByType, CreateAdaptersOptions, CreateRegeneratorOptions, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, DiagramOptions, DiagramType, DiscoverOptions, DiscoveryOptions, DocsServiceOptions, DocsServiceResult, DoctorOptions, DoctorPromptCallbacks, DoctorResult, ExtendedWorkspaceInfo, ExtractOptions, FULL_DEPENDENCIES, FeatureSpecParams, FieldMapping, FieldMatchType, FileStat, FileSystemCacheStorage, FixAction, FixResult, type FixStrategyType, type FixableIssue, FormatOptions, FormatterOptions, FsAdapter, GapAnalysisResult, GenerateArtifactsResult, GenericMCPAdapter, GitAdapter, GitCleanOptions, GitLogEntry, GuideOptions, GuideResult, ImplementationSource, ImplementationStatus, ImplementationValidationResult, ImplementationValidatorOptions, InMemoryCacheStorage, IntegrityAnalysisOptions, IntegrityAnalysisResult, IntegrityIssue, IntentAlignment, KeyValueStore, LayerDiscoveryOptions, LayerDiscoveryResult, LayerInventory, LayerLocation, OpenApiExportOptions as LegacyOpenApiExportOptions, OpenApiExportResult as LegacyOpenApiExportResult, ListSpecsOptions, LogLevel, LoggerAdapter, MINIMAL_DEPENDENCIES, MetaRepoInfo, MonorepoConfig, OpenAICodexAgent, OpenApiExportServiceOptions, OpenApiExportServiceResult, OpenApiImportServiceOptions, OpenApiImportServiceResult, OpenApiSyncServiceOptions, OpenApiSyncServiceResult, OpenApiValidateServiceOptions, OpenApiValidateServiceResult, PackageInstallResult, PackageManager, ProgressReporter, ProgressUpdate, QuickstartDependency, QuickstartMode, QuickstartOptions, QuickstartPromptCallbacks, QuickstartResult, RegistryClient, RegistryClientOptions, RepositoryType, ResolvedImplementation, ResolverOptions, RuleSyncOptions, RuleSyncPort, RuleSyncResult, RuleSyncService, RunTestsResult, SETUP_TARGET_LABELS, SemanticVerificationResult, SetupFileResult, SetupOptions, SetupPromptCallbacks, SetupResult, SetupScope, SetupTarget, SimpleAgent, SpecCreatorService, SpecImplementationResult, SpecInventory, SpecLocation, SpecReferenceMatch, SpecVersionAnalysis, StructureCheck, SubmoduleInfo, SyncBuildFn, SyncSpecsOptions, SyncSpecsResult, SyncSpecsRunResult, SyncValidateFn, TenantValidationContext, TenantValidationResult, TestGeneratorOptions, TestGeneratorService, TestServiceOptions, TestServiceResult, ValidateImplementationOptions, ValidateImplementationResult, ValidateSpecOptions, ValidateSpecResult, VerificationCacheConfig, VerificationCacheEntry, VerificationCacheKey, VerificationCacheService, VerificationIssue, VerifyConfig, VerifyInput, VerifyOptions, VerifyResult, VerifyService, ViewAudience, WatchBuildFn, WatchEvent, WatchEventHandler, WatchEventType, WatchOptions, WatchSpecsOptions, WatchValidateFn, Watcher, WatcherAdapter, WorkspaceAdapters, WorkspaceConfigInfo, WorkspaceInfo, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, index_d_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, index_d_exports$1 as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, index_d_exports$2 as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, index_d_exports$3 as hooks, index_d_exports$4 as impact, importFromOpenApiService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, index_d_exports$5 as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, index_d_exports$6 as templates, toKebabCase, index_d_exports$7 as upgrade, index_d_exports$8 as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, index_d_exports$9 as versioning, index_d_exports$10 as vibe, watchSpecs };
128
+ export { AIClient, AIGenerator, AIReviewResult, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentAdapter, AgentConfig, AgentGuideConfig, AgentGuideService, type AgentMode, AgentOrchestrator, AgentProvider, AgentResult, AgentTask, AiAdapter, AiGenerateOptions, AiGenerateResult, AiGenerateStructuredOptions, type AiProvider, AiValidationResult, AnalyzeDepsOptions, AnalyzeDepsResult, BehaviorCheck, BlueprintValidationResult, BuildSpecOptions, BuildSpecResult, BuildTarget, BuildTargetResult, CHECK_CATEGORY_LABELS, CICheckCategory, CICheckCategorySummary, CICheckOptions, CICheckResult, CIFormatOptions, CIIssue, CIIssueSeverity, CIOutputFormat, CI_CHECK_CATEGORY_LABELS, CacheEntryMeta, CacheKeyString, CacheLookupResult, CacheMissReason, CacheStats, CacheStorageAdapter, CheckCategory, CheckContext, CheckResult, CheckStatus, ClaudeCodeAdapter, ClaudeCodeAgent, CleanOptions, CleanResult, CompareSpecsOptions, CompareSpecsResult, type Config, CoverageByType, CreateAdaptersOptions, CreateRegeneratorOptions, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, DiagramOptions, DiagramType, DiscoverOptions, DiscoveryOptions, DocsServiceOptions, DocsServiceResult, DoctorOptions, DoctorPromptCallbacks, DoctorResult, EndpointVerification, ExtendedWorkspaceInfo, ExtractOptions, FULL_DEPENDENCIES, FeatureSpecParams, FieldMapping, FieldMatchType, FileStat, FileSystemCacheStorage, FixAction, FixResult, type FixStrategyType, type FixableIssue, FormatOptions, FormatterOptions, FsAdapter, GapAnalysisResult, GenerateArtifactsResult, GenericMCPAdapter, GitAdapter, GitCleanOptions, GitLogEntry, GuideOptions, GuideResult, ImplementationSource, ImplementationStatus, ImplementationValidationResult, ImplementationValidatorOptions, ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, VerificationIssue as ImportVerificationIssue, VerifyOptions as ImportVerifyOptions, VerifyResult as ImportVerifyResult, InMemoryCacheStorage, IntegrityAnalysisOptions, IntegrityAnalysisResult, IntegrityIssue, IntentAlignment, KeyValueStore, LayerDiscoveryOptions, LayerDiscoveryResult, LayerInventory, LayerLocation, OpenApiExportOptions as LegacyOpenApiExportOptions, OpenApiExportResult as LegacyOpenApiExportResult, ListSpecsOptions, LogLevel, LoggerAdapter, MINIMAL_DEPENDENCIES, MetaRepoInfo, MonorepoConfig, OpenAICodexAgent, OpenApiExportServiceOptions, OpenApiExportServiceResult, OpenApiImportServiceOptions, OpenApiImportServiceResult, OpenApiSyncServiceOptions, OpenApiSyncServiceResult, OpenApiValidateServiceOptions, OpenApiValidateServiceResult, PackageInstallResult, PackageManager, ProgressReporter, ProgressUpdate, QuickstartDependency, QuickstartMode, QuickstartOptions, QuickstartPromptCallbacks, QuickstartResult, RegistryClient, RegistryClientOptions, ReportOptions, RepositoryType, ResolvedImplementation, ResolverOptions, RuleSyncOptions, RuleSyncPort, RuleSyncResult, RuleSyncService, RunTestsResult, SETUP_TARGET_LABELS, SemanticVerificationResult, SetupFileResult, SetupOptions, SetupPromptCallbacks, SetupResult, SetupScope, SetupTarget, SimpleAgent, SpecCreatorService, SpecImplementationResult, SpecInventory, SpecLocation, SpecReferenceMatch, SpecVersionAnalysis, StructureCheck, SubmoduleInfo, SyncBuildFn, SyncSpecsOptions, SyncSpecsResult, SyncSpecsRunResult, SyncValidateFn, TenantValidationContext, TenantValidationResult, TestGeneratorOptions, TestGeneratorService, TestServiceOptions, TestServiceResult, ValidateImplementationOptions, ValidateImplementationResult, ValidateSpecOptions, ValidateSpecResult, VerificationCacheConfig, VerificationCacheEntry, VerificationCacheKey, VerificationCacheService, VerificationIssue$1 as VerificationIssue, VerifyConfig, VerifyInput, VerifyOptions$1 as VerifyOptions, VerifyResult$1 as VerifyResult, VerifyService, ViewAudience, WatchBuildFn, WatchEvent, WatchEventHandler, WatchEventType, WatchOptions, WatchSpecsOptions, WatchValidateFn, Watcher, WatcherAdapter, WorkspaceAdapters, WorkspaceConfigInfo, WorkspaceInfo, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, index_d_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, index_d_exports$1 as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, index_d_exports$2 as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateCliReport, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMarkdownReport, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, index_d_exports$3 as hooks, index_d_exports$4 as impact, importFromOpenApiService, importFromSourceService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, index_d_exports$5 as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, index_d_exports$6 as templates, toKebabCase, index_d_exports$7 as upgrade, index_d_exports$8 as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifyImportedContracts, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, index_d_exports$9 as versioning, index_d_exports$10 as vibe, watchSpecs };
package/dist/index.mjs CHANGED
@@ -100,6 +100,9 @@ import { generateView } from "./services/view/index.mjs";
100
100
  import { analyzeGap } from "./services/gap.mjs";
101
101
  import { extractContracts } from "./services/extract.mjs";
102
102
  import { vibe_exports } from "./services/vibe/index.mjs";
103
+ import { importFromSourceService } from "./services/import/import-service.mjs";
104
+ import { verifyImportedContracts } from "./services/import/verify-service.mjs";
105
+ import { generateCliReport, generateMarkdownReport } from "./services/import/report-service.mjs";
103
106
  import "./services/index.mjs";
104
107
  import { formatters_exports } from "./formatters/index.mjs";
105
108
  import { AIClient } from "./ai/client.mjs";
@@ -107,4 +110,4 @@ import { prompts_exports } from "./ai/prompts/index.mjs";
107
110
  import "./ai/index.mjs";
108
111
  import * as module from "@contractspec/module.workspace";
109
112
 
110
- export { AIClient, AIGenerator, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentGuideService, AgentOrchestrator, CHECK_CATEGORY_LABELS, CI_CHECK_CATEGORY_LABELS, ClaudeCodeAdapter, ClaudeCodeAgent, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, FULL_DEPENDENCIES, FileSystemCacheStorage, GenericMCPAdapter, InMemoryCacheStorage, MINIMAL_DEPENDENCIES, OpenAICodexAgent, RegistryClient, RuleSyncService, SETUP_TARGET_LABELS, SimpleAgent, SpecCreatorService, TestGeneratorService, VerificationCacheService, VerifyService, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, features_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, fix_exports as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, formatters_exports as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, hooks_exports as hooks, impact_exports as impact, importFromOpenApiService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, prompts_exports as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, templates_exports as templates, toKebabCase, upgrade_exports as upgrade, utils_exports as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, versioning_exports as versioning, vibe_exports as vibe, watchSpecs };
113
+ export { AIClient, AIGenerator, ALL_CHECK_CATEGORIES, ALL_CI_CHECK_CATEGORIES, ALL_SETUP_TARGETS, AgentGuideService, AgentOrchestrator, CHECK_CATEGORY_LABELS, CI_CHECK_CATEGORY_LABELS, ClaudeCodeAdapter, ClaudeCodeAgent, CursorAgent, CursorCLIAdapter, DEFAULT_CACHE_CONFIG, DEFAULT_SPEC_PATTERNS, FULL_DEPENDENCIES, FileSystemCacheStorage, GenericMCPAdapter, InMemoryCacheStorage, MINIMAL_DEPENDENCIES, OpenAICodexAgent, RegistryClient, RuleSyncService, SETUP_TARGET_LABELS, SimpleAgent, SpecCreatorService, TestGeneratorService, VerificationCacheService, VerifyService, WorkspaceStateCacheStorage, addToRegistry, agentAdapters, agentGuideService, analyzeDeps, analyzeGap, analyzeIntegrity, buildSpec, cacheKeyToString, claudeCodeAdapter, cleanArtifacts, compareSpecs, computeContentHash, createAgentGuideService, createConsoleLoggerAdapter, createEmptyLayerInventory, createFileSystemCacheStorage, createInMemoryCacheStorage, createNodeAdapters, createNodeAiAdapter, createNodeFsAdapter, createNodeGitAdapter, createNodeWatcherAdapter, createNoopLoggerAdapter, createQuickAIReview, createRegeneratorService, createSpecCreator, createVerificationCacheService, createVerifyService, createWorkspaceStateCacheStorage, cursorCLIAdapter, deepMergeOverwrite, deepMergePreserve, detectPackageManager, detectRepositoryType, determineStatus, discoverAllImplementations, discoverImplementationsForSpec, discoverLayers, exportGraphAsDot, exportOpenApi, exportSpecForLLM, extractContracts, extractSpecReferences, features_exports as features, filterIssuesBySeverity, filterIssuesByType, findAllConfigFiles, findMetaRepoRoot, findPackageRoot, findWorkspaceRoot, fix_exports as fix, formatCheckResult, formatDoctorSummary, formatFiles, formatJson, formatQuickstartPreview, formatVerificationReport, formatWorkspaceInfo, formatters_exports as formatters, generateAgentsMd, generateAppBlueprintSpec, generateArtifacts, generateClaudeMcpConfig, generateCliReport, generateComponentTemplate, generateContractsrcConfig, generateCursorMcpConfig, generateCursorRules, generateCursorRulesFromParsedSpec, generateDataViewSpec, generateDocsFromSpecs, generateEventSpec, generateExperimentSpec, generateFeatureContextMarkdown, generateFeatureSpec, generateGuideFromParsedSpec, generateHandlerTemplate, generateIntegrationSpec, generateKnowledgeSpaceSpec, generateMarkdownReport, generateMermaidDiagram, generateMigrationSpec, generateOperationSpec, generatePresentationSpec, generateTelemetrySpec, generateTestTemplate, generateView, generateVscodeSettings, generateWorkflowRunnerTemplate, generateWorkflowSpec, genericMCPAdapter, getAIProvider, getAgentAdapter, getAllLayerLocations, getAllSpecs, getApiKey, getClaudeDesktopConfigPath, getContractNode, getConventionPaths, getDependencies, getDevDependencies, getExecCommand, getExtendedWorkspaceInfo, getGraphStats, getImplementationSummary, getInstallCommand, getMetaRepoInfo, getPackageName, getProductionDependencies, getRecommendedModels, getRunCommand, getSpecKeyVariants, getWorkspaceInfo, getWorkspacePackages, groupSpecsByType, hooks_exports as hooks, impact_exports as impact, importFromOpenApiService, importFromSourceService, inferImplementationType, isContractSpecInstalled, isMonorepo, listAgentTypes, listFromRegistry, listSpecs, listTests, loadWorkspaceConfig, mergeMonorepoConfigs, module, parseExplicitImplementations, parseGitModules, prompts_exports as prompts, resolveAllImplementations, resolveImplementations, resolveRegistryUrl, runCIChecks, runDoctor, runQuickstart, runSetup, runTestSpecs, runTests, safeParseJson, searchRegistry, stringToCacheKey, syncSpecs, syncWithOpenApiService, templates_exports as templates, toKebabCase, upgrade_exports as upgrade, utils_exports as utils, validateAgainstOpenApiService, validateBlueprint, validateImplementationFiles, validateImplementationWithAgent, validateProvider, validateSpec, validateSpecs, validateTenantConfig, verifyBehavior, verifyImplementationAgainstParsedSpec, verifyImportedContracts, verifySemanticFields, verifyService, verifyStructure, verifyWithAI, verifyWithAIEnhanced, versioning_exports as versioning, vibe_exports as vibe, watchSpecs };
@@ -0,0 +1,47 @@
1
+ import { FsAdapter } from "../../ports/fs.mjs";
2
+ import { LoggerAdapter } from "../../ports/logger.mjs";
3
+ import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
4
+ import { ImportIR } from "@contractspec/lib.source-extractors";
5
+ import { GenerationResult } from "@contractspec/lib.source-extractors/codegen";
6
+
7
+ //#region src/services/import/import-service.d.ts
8
+
9
+ /**
10
+ * Options for the import service.
11
+ */
12
+ interface ImportServiceOptions {
13
+ /** Limit extraction to specific paths */
14
+ scope?: string[];
15
+ /** Force specific framework */
16
+ framework?: string;
17
+ /** Dry run mode - don't write files */
18
+ dryRun?: boolean;
19
+ /** Analysis only - extract IR without generating code */
20
+ analyzeOnly?: boolean;
21
+ /** Output directory for generated contracts */
22
+ outputDir?: string;
23
+ }
24
+ /**
25
+ * Result of the import service.
26
+ */
27
+ interface ImportServiceResult {
28
+ success: boolean;
29
+ ir?: ImportIR;
30
+ generation?: GenerationResult;
31
+ report: string;
32
+ errors?: string[];
33
+ }
34
+ /**
35
+ * Adapters needed by the import service.
36
+ */
37
+ interface ImportServiceAdapters {
38
+ fs: FsAdapter;
39
+ logger: LoggerAdapter;
40
+ }
41
+ /**
42
+ * Import contracts from source code.
43
+ */
44
+ declare function importFromSourceService(config: ResolvedContractsrcConfig, options: ImportServiceOptions, adapters: ImportServiceAdapters, cwd?: string): Promise<ImportServiceResult>;
45
+ //#endregion
46
+ export { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService };
47
+ //# sourceMappingURL=import-service.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/import/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAkEA;;;AAGY,UAtCK,oBAAA,CAsCL;EAED;EAAR,KAAA,CAAA,EAAA,MAAA,EAAA;EAAO;;;;;;;;;;;;UAxBO,mBAAA;;OAEV;eACQ;;;;;;;UAQE,qBAAA;MACX;UACI;;;;;iBAMY,uBAAA,SACZ,oCACC,gCACC,sCAET,QAAQ"}
@@ -0,0 +1,196 @@
1
+ import { dirname, join } from "path";
2
+ import { detectFramework, extractFromProject } from "@contractspec/lib.source-extractors";
3
+ import { registerAllExtractors } from "@contractspec/lib.source-extractors/extractors";
4
+ import { generateOperations, generateRegistry, generateSchemas } from "@contractspec/lib.source-extractors/codegen";
5
+
6
+ //#region src/services/import/import-service.ts
7
+ /**
8
+ * Import contracts from source code.
9
+ */
10
+ async function importFromSourceService(config, options, adapters, cwd) {
11
+ const { fs, logger } = adapters;
12
+ const rootPath = cwd ?? process.cwd();
13
+ registerAllExtractors();
14
+ logger.info(`Scanning source code in ${rootPath}...`);
15
+ const extractorFs = {
16
+ readFile: (path$1) => fs.readFile(path$1),
17
+ glob: (pattern, opts) => fs.glob({
18
+ pattern,
19
+ cwd: opts?.cwd
20
+ }),
21
+ exists: (path$1) => fs.exists(path$1)
22
+ };
23
+ const project = await detectFramework(rootPath, {
24
+ readFile: (path$1) => fs.readFile(path$1),
25
+ glob: (pattern) => fs.glob({ pattern })
26
+ });
27
+ if (project.frameworks.length === 0) {
28
+ logger.warn("No supported frameworks detected");
29
+ return {
30
+ success: false,
31
+ report: generateNoFrameworkReport(),
32
+ errors: ["No supported frameworks detected in project"]
33
+ };
34
+ }
35
+ logger.info(`Detected frameworks: ${project.frameworks.map((f) => f.name).join(", ")}`);
36
+ const { extractorRegistry } = await import("@contractspec/lib.source-extractors");
37
+ for (const extractor of extractorRegistry.getAll()) if ("setFs" in extractor && typeof extractor.setFs === "function") extractor.setFs(extractorFs);
38
+ const extractResult = await extractFromProject(project, {
39
+ scope: options.scope,
40
+ framework: options.framework
41
+ });
42
+ if (!extractResult.success || !extractResult.ir) return {
43
+ success: false,
44
+ report: generateErrorReport(extractResult.errors ?? []),
45
+ errors: extractResult.errors?.map((e) => e.message)
46
+ };
47
+ const ir = extractResult.ir;
48
+ logger.info(`Extracted ${ir.endpoints.length} endpoints, ${ir.schemas.length} schemas`);
49
+ if (options.analyzeOnly) return {
50
+ success: true,
51
+ ir,
52
+ report: generateAnalysisReport(ir)
53
+ };
54
+ const outputDir = options.outputDir ?? join(config.outputDir, "generated");
55
+ const generationOptions = {
56
+ outputDir,
57
+ defaultAuth: "user"
58
+ };
59
+ const operationFiles = generateOperations(ir, generationOptions);
60
+ const schemaFiles = generateSchemas(ir, generationOptions);
61
+ const registryFile = generateRegistry(operationFiles);
62
+ const allFiles = [
63
+ ...operationFiles,
64
+ ...schemaFiles,
65
+ registryFile
66
+ ];
67
+ if (!options.dryRun) for (const file of allFiles) {
68
+ const fullPath = join(outputDir, file.path);
69
+ const dir = dirname(fullPath);
70
+ if (!await fs.exists(dir)) await fs.mkdir(dir);
71
+ await fs.writeFile(fullPath, file.content);
72
+ logger.info(`Created: ${fullPath}`);
73
+ }
74
+ else for (const file of allFiles) logger.info(`[DRY RUN] Would create: ${join(outputDir, file.path)}`);
75
+ const generationResult = {
76
+ files: allFiles,
77
+ operationsGenerated: operationFiles.length,
78
+ schemasGenerated: schemaFiles.length,
79
+ warnings: []
80
+ };
81
+ return {
82
+ success: true,
83
+ ir,
84
+ generation: generationResult,
85
+ report: generateSuccessReport(ir, generationResult, options)
86
+ };
87
+ }
88
+ /**
89
+ * Generate report when no frameworks are detected.
90
+ */
91
+ function generateNoFrameworkReport() {
92
+ return `# Import Report
93
+
94
+ ## ❌ No Supported Frameworks Detected
95
+
96
+ No supported frameworks were detected in the project.
97
+
98
+ ### Supported Frameworks
99
+
100
+ - NestJS
101
+ - Express
102
+ - Fastify
103
+ - Hono
104
+ - Elysia
105
+ - tRPC
106
+ - Next.js API Routes
107
+
108
+ Please ensure your project uses one of these frameworks and has the appropriate dependencies installed.
109
+ `;
110
+ }
111
+ /**
112
+ * Generate error report.
113
+ */
114
+ function generateErrorReport(errors) {
115
+ return `# Import Report
116
+
117
+ ## ❌ Extraction Failed
118
+
119
+ ${errors.map((e) => `- ${e.message}`).join("\n")}
120
+ `;
121
+ }
122
+ /**
123
+ * Generate analysis-only report.
124
+ */
125
+ function generateAnalysisReport(ir) {
126
+ return `# Import Analysis Report
127
+
128
+ ## Summary
129
+
130
+ - **Files Scanned**: ${ir.stats.filesScanned}
131
+ - **Endpoints Found**: ${ir.stats.endpointsFound}
132
+ - **Schemas Found**: ${ir.stats.schemasFound}
133
+ - **Errors Found**: ${ir.stats.errorsFound}
134
+ - **Events Found**: ${ir.stats.eventsFound}
135
+
136
+ ## Confidence Breakdown
137
+
138
+ | Level | Count |
139
+ |-------|-------|
140
+ | High | ${ir.stats.highConfidence} |
141
+ | Medium | ${ir.stats.mediumConfidence} |
142
+ | Low/Ambiguous | ${ir.stats.lowConfidence} |
143
+
144
+ ## Detected Frameworks
145
+
146
+ ${ir.project.frameworks.map((f) => `- ${f.name} (${f.confidence})`).join("\n")}
147
+
148
+ ## Endpoints
149
+
150
+ ${ir.endpoints.map((e) => `- \`${e.method} ${e.path}\` - ${e.confidence.level}`).join("\n")}
151
+
152
+ ## Ambiguities (Require Review)
153
+
154
+ ${ir.ambiguities.length > 0 ? ir.ambiguities.map((a) => `- ${a.description}`).join("\n") : "None"}
155
+ `;
156
+ }
157
+ /**
158
+ * Generate success report.
159
+ */
160
+ function generateSuccessReport(ir, gen, options) {
161
+ return `# Import Report${options.dryRun ? " (Dry Run)" : ""}
162
+
163
+ ## ✅ Import Successful
164
+
165
+ ### Extraction Summary
166
+
167
+ - **Files Scanned**: ${ir.stats.filesScanned}
168
+ - **Endpoints Found**: ${ir.stats.endpointsFound}
169
+ - **Schemas Found**: ${ir.stats.schemasFound}
170
+
171
+ ### Generation Summary
172
+
173
+ - **Operations Generated**: ${gen.operationsGenerated}
174
+ - **Schemas Generated**: ${gen.schemasGenerated}
175
+ - **Total Files**: ${gen.files.length}
176
+
177
+ ### Confidence Breakdown
178
+
179
+ | Level | Count |
180
+ |-------|-------|
181
+ | High | ${ir.stats.highConfidence} |
182
+ | Medium | ${ir.stats.mediumConfidence} |
183
+ | Low/Ambiguous | ${ir.stats.lowConfidence} |
184
+
185
+ ### Next Steps
186
+
187
+ 1. Review generated contracts in \`${options.outputDir ?? "generated/"}\`
188
+ 2. Fill in TODO placeholders with business context
189
+ 3. Run \`contractspec validate\` to verify contracts
190
+ 4. Move stable contracts from \`generated/\` to \`curated/\`
191
+ `;
192
+ }
193
+
194
+ //#endregion
195
+ export { importFromSourceService };
196
+ //# sourceMappingURL=import-service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-service.mjs","names":["path"],"sources":["../../../src/services/import/import-service.ts"],"sourcesContent":["/**\n * Import service for source-extractors.\n *\n * Integrates source extraction into the workspace bundle.\n */\n\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\nimport {\n detectFramework,\n extractFromProject,\n type ExtractOptions,\n type ImportIR,\n} from '@contractspec/lib.source-extractors';\nimport {\n type ExtractorFsAdapter,\n registerAllExtractors,\n} from '@contractspec/lib.source-extractors/extractors';\nimport {\n generateOperations,\n generateRegistry,\n generateSchemas,\n type GenerationOptions,\n type GenerationResult,\n} from '@contractspec/lib.source-extractors/codegen';\nimport { dirname, join } from 'path';\n\n/**\n * Options for the import service.\n */\nexport interface ImportServiceOptions {\n /** Limit extraction to specific paths */\n scope?: string[];\n /** Force specific framework */\n framework?: string;\n /** Dry run mode - don't write files */\n dryRun?: boolean;\n /** Analysis only - extract IR without generating code */\n analyzeOnly?: boolean;\n /** Output directory for generated contracts */\n outputDir?: string;\n}\n\n/**\n * Result of the import service.\n */\nexport interface ImportServiceResult {\n success: boolean;\n ir?: ImportIR;\n generation?: GenerationResult;\n report: string;\n errors?: string[];\n}\n\n/**\n * Adapters needed by the import service.\n */\nexport interface ImportServiceAdapters {\n fs: FsAdapter;\n logger: LoggerAdapter;\n}\n\n/**\n * Import contracts from source code.\n */\nexport async function importFromSourceService(\n config: ResolvedContractsrcConfig,\n options: ImportServiceOptions,\n adapters: ImportServiceAdapters,\n cwd?: string\n): Promise<ImportServiceResult> {\n const { fs, logger } = adapters;\n const rootPath = cwd ?? process.cwd();\n\n // Register all extractors\n registerAllExtractors();\n\n logger.info(`Scanning source code in ${rootPath}...`);\n\n // Create adapter bridge\n const extractorFs: ExtractorFsAdapter = {\n readFile: (path) => fs.readFile(path),\n glob: (pattern, opts) => fs.glob({ pattern, cwd: opts?.cwd }),\n exists: (path) => fs.exists(path),\n };\n\n // Detect frameworks\n const project = await detectFramework(rootPath, {\n readFile: (path) => fs.readFile(path),\n glob: (pattern) => fs.glob({ pattern }),\n });\n\n if (project.frameworks.length === 0) {\n logger.warn('No supported frameworks detected');\n return {\n success: false,\n report: generateNoFrameworkReport(),\n errors: ['No supported frameworks detected in project'],\n };\n }\n\n logger.info(\n `Detected frameworks: ${project.frameworks.map((f) => f.name).join(', ')}`\n );\n\n // Set up extractors with fs adapter\n const { extractorRegistry } =\n await import('@contractspec/lib.source-extractors');\n for (const extractor of extractorRegistry.getAll()) {\n if ('setFs' in extractor && typeof extractor.setFs === 'function') {\n extractor.setFs(extractorFs);\n }\n }\n\n // Extract contracts\n const extractOptions: ExtractOptions = {\n scope: options.scope,\n framework: options.framework,\n };\n\n const extractResult = await extractFromProject(project, extractOptions);\n\n if (!extractResult.success || !extractResult.ir) {\n return {\n success: false,\n report: generateErrorReport(extractResult.errors ?? []),\n errors: extractResult.errors?.map((e) => e.message),\n };\n }\n\n const ir = extractResult.ir;\n\n logger.info(\n `Extracted ${ir.endpoints.length} endpoints, ${ir.schemas.length} schemas`\n );\n\n // If analyze-only mode, just return the IR\n if (options.analyzeOnly) {\n return {\n success: true,\n ir,\n report: generateAnalysisReport(ir),\n };\n }\n\n // Generate code\n const outputDir = options.outputDir ?? join(config.outputDir, 'generated');\n const generationOptions: GenerationOptions = {\n outputDir,\n defaultAuth: 'user',\n };\n\n const operationFiles = generateOperations(ir, generationOptions);\n const schemaFiles = generateSchemas(ir, generationOptions);\n const registryFile = generateRegistry(operationFiles);\n\n const allFiles = [...operationFiles, ...schemaFiles, registryFile];\n\n // Write files if not dry-run\n if (!options.dryRun) {\n for (const file of allFiles) {\n const fullPath = join(outputDir, file.path);\n const dir = dirname(fullPath);\n\n if (!(await fs.exists(dir))) {\n await fs.mkdir(dir);\n }\n\n await fs.writeFile(fullPath, file.content);\n logger.info(`Created: ${fullPath}`);\n }\n } else {\n for (const file of allFiles) {\n logger.info(`[DRY RUN] Would create: ${join(outputDir, file.path)}`);\n }\n }\n\n const generationResult: GenerationResult = {\n files: allFiles,\n operationsGenerated: operationFiles.length,\n schemasGenerated: schemaFiles.length,\n warnings: [],\n };\n\n return {\n success: true,\n ir,\n generation: generationResult,\n report: generateSuccessReport(ir, generationResult, options),\n };\n}\n\n/**\n * Generate report when no frameworks are detected.\n */\nfunction generateNoFrameworkReport(): string {\n return `# Import Report\n\n## ❌ No Supported Frameworks Detected\n\nNo supported frameworks were detected in the project.\n\n### Supported Frameworks\n\n- NestJS\n- Express\n- Fastify\n- Hono\n- Elysia\n- tRPC\n- Next.js API Routes\n\nPlease ensure your project uses one of these frameworks and has the appropriate dependencies installed.\n`;\n}\n\n/**\n * Generate error report.\n */\nfunction generateErrorReport(errors: { message: string }[]): string {\n return `# Import Report\n\n## ❌ Extraction Failed\n\n${errors.map((e) => `- ${e.message}`).join('\\n')}\n`;\n}\n\n/**\n * Generate analysis-only report.\n */\nfunction generateAnalysisReport(ir: ImportIR): string {\n return `# Import Analysis Report\n\n## Summary\n\n- **Files Scanned**: ${ir.stats.filesScanned}\n- **Endpoints Found**: ${ir.stats.endpointsFound}\n- **Schemas Found**: ${ir.stats.schemasFound}\n- **Errors Found**: ${ir.stats.errorsFound}\n- **Events Found**: ${ir.stats.eventsFound}\n\n## Confidence Breakdown\n\n| Level | Count |\n|-------|-------|\n| High | ${ir.stats.highConfidence} |\n| Medium | ${ir.stats.mediumConfidence} |\n| Low/Ambiguous | ${ir.stats.lowConfidence} |\n\n## Detected Frameworks\n\n${ir.project.frameworks.map((f) => `- ${f.name} (${f.confidence})`).join('\\n')}\n\n## Endpoints\n\n${ir.endpoints.map((e) => `- \\`${e.method} ${e.path}\\` - ${e.confidence.level}`).join('\\n')}\n\n## Ambiguities (Require Review)\n\n${ir.ambiguities.length > 0 ? ir.ambiguities.map((a) => `- ${a.description}`).join('\\n') : 'None'}\n`;\n}\n\n/**\n * Generate success report.\n */\nfunction generateSuccessReport(\n ir: ImportIR,\n gen: GenerationResult,\n options: ImportServiceOptions\n): string {\n const mode = options.dryRun ? ' (Dry Run)' : '';\n return `# Import Report${mode}\n\n## ✅ Import Successful\n\n### Extraction Summary\n\n- **Files Scanned**: ${ir.stats.filesScanned}\n- **Endpoints Found**: ${ir.stats.endpointsFound}\n- **Schemas Found**: ${ir.stats.schemasFound}\n\n### Generation Summary\n\n- **Operations Generated**: ${gen.operationsGenerated}\n- **Schemas Generated**: ${gen.schemasGenerated}\n- **Total Files**: ${gen.files.length}\n\n### Confidence Breakdown\n\n| Level | Count |\n|-------|-------|\n| High | ${ir.stats.highConfidence} |\n| Medium | ${ir.stats.mediumConfidence} |\n| Low/Ambiguous | ${ir.stats.lowConfidence} |\n\n### Next Steps\n\n1. Review generated contracts in \\`${options.outputDir ?? 'generated/'}\\`\n2. Fill in TODO placeholders with business context\n3. Run \\`contractspec validate\\` to verify contracts\n4. Move stable contracts from \\`generated/\\` to \\`curated/\\`\n`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./import-service.mjs";
2
+ import { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts } from "./verify-service.mjs";
3
+ import { ReportOptions, generateCliReport, generateMarkdownReport } from "./report-service.mjs";
@@ -0,0 +1,5 @@
1
+ import { importFromSourceService } from "./import-service.mjs";
2
+ import { verifyImportedContracts } from "./verify-service.mjs";
3
+ import { generateCliReport, generateMarkdownReport } from "./report-service.mjs";
4
+
5
+ export { };
@@ -0,0 +1,31 @@
1
+ import { VerifyResult } from "./verify-service.mjs";
2
+ import { ImportIR } from "@contractspec/lib.source-extractors";
3
+
4
+ //#region src/services/import/report-service.d.ts
5
+
6
+ /**
7
+ * Options for report generation.
8
+ */
9
+ interface ReportOptions {
10
+ /** Include endpoint details */
11
+ includeEndpoints?: boolean;
12
+ /** Include schema details */
13
+ includeSchemas?: boolean;
14
+ /** Include verification issues */
15
+ includeIssues?: boolean;
16
+ /** Include ambiguities */
17
+ includeAmbiguities?: boolean;
18
+ /** Include statistics */
19
+ includeStats?: boolean;
20
+ }
21
+ /**
22
+ * Generate a markdown report from IR and optional verification.
23
+ */
24
+ declare function generateMarkdownReport(ir: ImportIR, verification?: VerifyResult, options?: ReportOptions): string;
25
+ /**
26
+ * Generate CLI-friendly report output.
27
+ */
28
+ declare function generateCliReport(ir: ImportIR, verification?: VerifyResult): string;
29
+ //#endregion
30
+ export { ReportOptions, generateCliReport, generateMarkdownReport };
31
+ //# sourceMappingURL=report-service.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-service.d.mts","names":[],"sources":["../../../src/services/import/report-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAoKgB,UAxJC,aAAA,CAwJgB;;;;;;;;;;;;;;;iBAxIjB,sBAAA,KACV,yBACW,wBACN;;;;iBAqIK,iBAAA,KACV,yBACW"}
@@ -0,0 +1,124 @@
1
+ //#region src/services/import/report-service.ts
2
+ /**
3
+ * Generate a markdown report from IR and optional verification.
4
+ */
5
+ function generateMarkdownReport(ir, verification, options = {}) {
6
+ const lines = [];
7
+ lines.push("# Import Report");
8
+ lines.push("");
9
+ lines.push(`**Generated**: ${(/* @__PURE__ */ new Date()).toISOString()}`);
10
+ lines.push("");
11
+ lines.push("## Summary");
12
+ lines.push("");
13
+ lines.push(`| Metric | Count |`);
14
+ lines.push(`|--------|-------|`);
15
+ lines.push(`| Files Scanned | ${ir.stats.filesScanned} |`);
16
+ lines.push(`| Endpoints Found | ${ir.stats.endpointsFound} |`);
17
+ lines.push(`| Schemas Found | ${ir.stats.schemasFound} |`);
18
+ lines.push(`| Errors Found | ${ir.stats.errorsFound} |`);
19
+ lines.push(`| Events Found | ${ir.stats.eventsFound} |`);
20
+ lines.push("");
21
+ if (options.includeStats !== false) {
22
+ lines.push("### Confidence");
23
+ lines.push("");
24
+ lines.push(`| Level | Count |`);
25
+ lines.push(`|-------|-------|`);
26
+ lines.push(`| High | ${ir.stats.highConfidence} |`);
27
+ lines.push(`| Medium | ${ir.stats.mediumConfidence} |`);
28
+ lines.push(`| Low/Ambiguous | ${ir.stats.lowConfidence} |`);
29
+ lines.push("");
30
+ }
31
+ lines.push("### Frameworks Detected");
32
+ lines.push("");
33
+ for (const fw of ir.project.frameworks) lines.push(`- **${fw.name}** (${fw.confidence})`);
34
+ lines.push("");
35
+ if (options.includeEndpoints !== false && ir.endpoints.length > 0) {
36
+ lines.push("## Endpoints");
37
+ lines.push("");
38
+ lines.push("| Method | Path | Kind | Confidence |");
39
+ lines.push("|--------|------|------|------------|");
40
+ for (const ep of ir.endpoints) lines.push(`| ${ep.method} | \`${ep.path}\` | ${ep.kind} | ${ep.confidence.level} |`);
41
+ lines.push("");
42
+ }
43
+ if (options.includeSchemas !== false && ir.schemas.length > 0) {
44
+ lines.push("## Schemas");
45
+ lines.push("");
46
+ lines.push("| Name | Type | Confidence |");
47
+ lines.push("|------|------|------------|");
48
+ for (const schema of ir.schemas) lines.push(`| ${schema.name} | ${schema.schemaType} | ${schema.confidence.level} |`);
49
+ lines.push("");
50
+ }
51
+ if (verification && options.includeIssues !== false) {
52
+ lines.push("## Verification");
53
+ lines.push("");
54
+ lines.push(`| Status | Count |`);
55
+ lines.push(`|--------|-------|`);
56
+ lines.push(`| Valid | ${verification.summary.validEndpoints} |`);
57
+ lines.push(`| Warnings | ${verification.summary.warningEndpoints} |`);
58
+ lines.push(`| Errors | ${verification.summary.errorEndpoints} |`);
59
+ lines.push("");
60
+ const issueEndpoints = verification.endpointResults.filter((r) => r.issues.length > 0);
61
+ if (issueEndpoints.length > 0) {
62
+ lines.push("### Issues");
63
+ lines.push("");
64
+ for (const result of issueEndpoints) {
65
+ lines.push(`#### ${result.endpoint.method} ${result.endpoint.path}`);
66
+ for (const issue of result.issues) {
67
+ const icon = issue.severity === "error" ? "❌" : issue.severity === "warning" ? "⚠️" : "ℹ️";
68
+ lines.push(`- ${icon} **${issue.code}**: ${issue.message}`);
69
+ if (issue.suggestion) lines.push(` - *Suggestion*: ${issue.suggestion}`);
70
+ }
71
+ lines.push("");
72
+ }
73
+ }
74
+ }
75
+ if (options.includeAmbiguities !== false && ir.ambiguities.length > 0) {
76
+ lines.push("## Ambiguities (Require Review)");
77
+ lines.push("");
78
+ for (const amb of ir.ambiguities) {
79
+ lines.push(`- **${amb.type}** (${amb.itemId}): ${amb.description}`);
80
+ if (amb.suggestion) lines.push(` - *Suggestion*: ${amb.suggestion}`);
81
+ }
82
+ lines.push("");
83
+ }
84
+ lines.push("## Next Steps");
85
+ lines.push("");
86
+ lines.push("1. Review generated contracts in the output directory");
87
+ lines.push("2. Fill in TODO placeholders with business context");
88
+ lines.push("3. Run `contractspec validate` to verify contracts");
89
+ lines.push("4. Move stable contracts from `generated/` to `curated/`");
90
+ lines.push("");
91
+ return lines.join("\n");
92
+ }
93
+ /**
94
+ * Generate CLI-friendly report output.
95
+ */
96
+ function generateCliReport(ir, verification) {
97
+ const lines = [];
98
+ lines.push("");
99
+ lines.push("📊 Summary");
100
+ lines.push(` Files scanned: ${ir.stats.filesScanned}`);
101
+ lines.push(` Endpoints: ${ir.stats.endpointsFound}`);
102
+ lines.push(` Schemas: ${ir.stats.schemasFound}`);
103
+ lines.push("");
104
+ lines.push("📈 Confidence");
105
+ lines.push(` High: ${ir.stats.highConfidence}`);
106
+ lines.push(` Medium: ${ir.stats.mediumConfidence}`);
107
+ lines.push(` Low: ${ir.stats.lowConfidence}`);
108
+ lines.push("");
109
+ lines.push("🔧 Frameworks");
110
+ for (const fw of ir.project.frameworks) lines.push(` • ${fw.name}`);
111
+ lines.push("");
112
+ if (verification) {
113
+ lines.push("✅ Verification");
114
+ lines.push(` Valid: ${verification.summary.validEndpoints}`);
115
+ lines.push(` Warnings: ${verification.summary.warningEndpoints}`);
116
+ lines.push(` Errors: ${verification.summary.errorEndpoints}`);
117
+ lines.push("");
118
+ }
119
+ return lines.join("\n");
120
+ }
121
+
122
+ //#endregion
123
+ export { generateCliReport, generateMarkdownReport };
124
+ //# sourceMappingURL=report-service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-service.mjs","names":[],"sources":["../../../src/services/import/report-service.ts"],"sourcesContent":["/**\n * Report service for imported contracts.\n *\n * Generates markdown and CLI reports from IR and verification results.\n */\n\nimport type { ImportIR } from '@contractspec/lib.source-extractors';\nimport type { VerifyResult } from './verify-service';\n\n/**\n * Options for report generation.\n */\nexport interface ReportOptions {\n /** Include endpoint details */\n includeEndpoints?: boolean;\n /** Include schema details */\n includeSchemas?: boolean;\n /** Include verification issues */\n includeIssues?: boolean;\n /** Include ambiguities */\n includeAmbiguities?: boolean;\n /** Include statistics */\n includeStats?: boolean;\n}\n\n/**\n * Generate a markdown report from IR and optional verification.\n */\nexport function generateMarkdownReport(\n ir: ImportIR,\n verification?: VerifyResult,\n options: ReportOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push('# Import Report');\n lines.push('');\n lines.push(`**Generated**: ${new Date().toISOString()}`);\n lines.push('');\n\n // Summary section\n lines.push('## Summary');\n lines.push('');\n lines.push(`| Metric | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Files Scanned | ${ir.stats.filesScanned} |`);\n lines.push(`| Endpoints Found | ${ir.stats.endpointsFound} |`);\n lines.push(`| Schemas Found | ${ir.stats.schemasFound} |`);\n lines.push(`| Errors Found | ${ir.stats.errorsFound} |`);\n lines.push(`| Events Found | ${ir.stats.eventsFound} |`);\n lines.push('');\n\n // Confidence breakdown\n if (options.includeStats !== false) {\n lines.push('### Confidence');\n lines.push('');\n lines.push(`| Level | Count |`);\n lines.push(`|-------|-------|`);\n lines.push(`| High | ${ir.stats.highConfidence} |`);\n lines.push(`| Medium | ${ir.stats.mediumConfidence} |`);\n lines.push(`| Low/Ambiguous | ${ir.stats.lowConfidence} |`);\n lines.push('');\n }\n\n // Frameworks detected\n lines.push('### Frameworks Detected');\n lines.push('');\n for (const fw of ir.project.frameworks) {\n lines.push(`- **${fw.name}** (${fw.confidence})`);\n }\n lines.push('');\n\n // Endpoints section\n if (options.includeEndpoints !== false && ir.endpoints.length > 0) {\n lines.push('## Endpoints');\n lines.push('');\n lines.push('| Method | Path | Kind | Confidence |');\n lines.push('|--------|------|------|------------|');\n for (const ep of ir.endpoints) {\n lines.push(\n `| ${ep.method} | \\`${ep.path}\\` | ${ep.kind} | ${ep.confidence.level} |`\n );\n }\n lines.push('');\n }\n\n // Schemas section\n if (options.includeSchemas !== false && ir.schemas.length > 0) {\n lines.push('## Schemas');\n lines.push('');\n lines.push('| Name | Type | Confidence |');\n lines.push('|------|------|------------|');\n for (const schema of ir.schemas) {\n lines.push(\n `| ${schema.name} | ${schema.schemaType} | ${schema.confidence.level} |`\n );\n }\n lines.push('');\n }\n\n // Verification results\n if (verification && options.includeIssues !== false) {\n lines.push('## Verification');\n lines.push('');\n lines.push(`| Status | Count |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Valid | ${verification.summary.validEndpoints} |`);\n lines.push(`| Warnings | ${verification.summary.warningEndpoints} |`);\n lines.push(`| Errors | ${verification.summary.errorEndpoints} |`);\n lines.push('');\n\n const issueEndpoints = verification.endpointResults.filter(\n (r) => r.issues.length > 0\n );\n if (issueEndpoints.length > 0) {\n lines.push('### Issues');\n lines.push('');\n for (const result of issueEndpoints) {\n lines.push(`#### ${result.endpoint.method} ${result.endpoint.path}`);\n for (const issue of result.issues) {\n const icon =\n issue.severity === 'error'\n ? '❌'\n : issue.severity === 'warning'\n ? '⚠️'\n : 'ℹ️';\n lines.push(`- ${icon} **${issue.code}**: ${issue.message}`);\n if (issue.suggestion) {\n lines.push(` - *Suggestion*: ${issue.suggestion}`);\n }\n }\n lines.push('');\n }\n }\n }\n\n // Ambiguities section\n if (options.includeAmbiguities !== false && ir.ambiguities.length > 0) {\n lines.push('## Ambiguities (Require Review)');\n lines.push('');\n for (const amb of ir.ambiguities) {\n lines.push(`- **${amb.type}** (${amb.itemId}): ${amb.description}`);\n if (amb.suggestion) {\n lines.push(` - *Suggestion*: ${amb.suggestion}`);\n }\n }\n lines.push('');\n }\n\n // Next steps\n lines.push('## Next Steps');\n lines.push('');\n lines.push('1. Review generated contracts in the output directory');\n lines.push('2. Fill in TODO placeholders with business context');\n lines.push('3. Run `contractspec validate` to verify contracts');\n lines.push('4. Move stable contracts from `generated/` to `curated/`');\n lines.push('');\n\n return lines.join('\\n');\n}\n\n/**\n * Generate CLI-friendly report output.\n */\nexport function generateCliReport(\n ir: ImportIR,\n verification?: VerifyResult\n): string {\n const lines: string[] = [];\n\n // Summary\n lines.push('');\n lines.push('📊 Summary');\n lines.push(` Files scanned: ${ir.stats.filesScanned}`);\n lines.push(` Endpoints: ${ir.stats.endpointsFound}`);\n lines.push(` Schemas: ${ir.stats.schemasFound}`);\n lines.push('');\n\n // Confidence\n lines.push('📈 Confidence');\n lines.push(` High: ${ir.stats.highConfidence}`);\n lines.push(` Medium: ${ir.stats.mediumConfidence}`);\n lines.push(` Low: ${ir.stats.lowConfidence}`);\n lines.push('');\n\n // Frameworks\n lines.push('🔧 Frameworks');\n for (const fw of ir.project.frameworks) {\n lines.push(` • ${fw.name}`);\n }\n lines.push('');\n\n // Verification\n if (verification) {\n lines.push('✅ Verification');\n lines.push(` Valid: ${verification.summary.validEndpoints}`);\n lines.push(` Warnings: ${verification.summary.warningEndpoints}`);\n lines.push(` Errors: ${verification.summary.errorEndpoints}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { FsAdapter } from "../../ports/fs.mjs";
2
+ import { LoggerAdapter } from "../../ports/logger.mjs";
3
+ import { Ambiguity, EndpointCandidate, ImportIR } from "@contractspec/lib.source-extractors";
4
+
5
+ //#region src/services/import/verify-service.d.ts
6
+
7
+ /**
8
+ * Verification result for a single endpoint.
9
+ */
10
+ interface EndpointVerification {
11
+ endpoint: EndpointCandidate;
12
+ status: 'valid' | 'warning' | 'error';
13
+ issues: VerificationIssue[];
14
+ }
15
+ /**
16
+ * A single verification issue.
17
+ */
18
+ interface VerificationIssue {
19
+ code: string;
20
+ message: string;
21
+ severity: 'error' | 'warning' | 'info';
22
+ suggestion?: string;
23
+ }
24
+ /**
25
+ * Options for verification.
26
+ */
27
+ interface VerifyOptions {
28
+ /** Check for duplicate endpoints */
29
+ checkDuplicates?: boolean;
30
+ /** Check for conflicting paths */
31
+ checkConflicts?: boolean;
32
+ /** Validate schema completeness */
33
+ validateSchemas?: boolean;
34
+ /** Compare against existing specs */
35
+ compareExisting?: boolean;
36
+ /** Path to existing specs */
37
+ existingSpecsPath?: string;
38
+ }
39
+ /**
40
+ * Result of verification.
41
+ */
42
+ interface VerifyResult {
43
+ valid: boolean;
44
+ endpointResults: EndpointVerification[];
45
+ ambiguities: Ambiguity[];
46
+ summary: {
47
+ totalEndpoints: number;
48
+ validEndpoints: number;
49
+ warningEndpoints: number;
50
+ errorEndpoints: number;
51
+ totalIssues: number;
52
+ };
53
+ }
54
+ /**
55
+ * Adapters for verification service.
56
+ */
57
+ interface VerifyServiceAdapters {
58
+ fs: FsAdapter;
59
+ logger: LoggerAdapter;
60
+ }
61
+ /**
62
+ * Verify extracted contracts from IR.
63
+ */
64
+ declare function verifyImportedContracts(ir: ImportIR, options: VerifyOptions, adapters: VerifyServiceAdapters): Promise<VerifyResult>;
65
+ //#endregion
66
+ export { EndpointVerification, VerificationIssue, VerifyOptions, VerifyResult, verifyImportedContracts };
67
+ //# sourceMappingURL=verify-service.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-service.d.mts","names":[],"sources":["../../../src/services/import/verify-service.ts"],"sourcesContent":[],"mappings":";;;;;;AAoDA;AAgBA;AAQA;AACM,UA5DW,oBAAA,CA4DX;EACK,QAAA,EA5DC,iBA4DD;EACC,MAAA,EAAA,OAAA,GAAA,SAAA,GAAA,OAAA;EACD,MAAA,EA5DD,iBA4DC,EAAA;;;;;UAtDM,iBAAA;;;;;;;;;UAUA,aAAA;;;;;;;;;;;;;;;UAgBA,YAAA;;mBAEE;eACJ;;;;;;;;;;;;UAaE,qBAAA;MACX;UACI;;;;;iBAMY,uBAAA,KAChB,mBACK,yBACC,wBACT,QAAQ"}
@@ -0,0 +1,105 @@
1
+ //#region src/services/import/verify-service.ts
2
+ /**
3
+ * Verify extracted contracts from IR.
4
+ */
5
+ async function verifyImportedContracts(ir, options, adapters) {
6
+ const { logger } = adapters;
7
+ const endpointResults = [];
8
+ const ambiguities = [...ir.ambiguities];
9
+ logger.info(`Verifying ${ir.endpoints.length} endpoints...`);
10
+ for (const endpoint of ir.endpoints) {
11
+ const issues = [];
12
+ if (endpoint.confidence.level === "low" || endpoint.confidence.level === "ambiguous") issues.push({
13
+ code: "LOW_CONFIDENCE",
14
+ message: `Endpoint has ${endpoint.confidence.level} confidence`,
15
+ severity: "warning",
16
+ suggestion: "Review source code and add explicit schema annotations"
17
+ });
18
+ if (!endpoint.input && (endpoint.method === "POST" || endpoint.method === "PUT" || endpoint.method === "PATCH")) issues.push({
19
+ code: "MISSING_INPUT_SCHEMA",
20
+ message: "Command endpoint missing input schema",
21
+ severity: "warning",
22
+ suggestion: "Add Zod schema or class-validator DTO"
23
+ });
24
+ if (!endpoint.output) issues.push({
25
+ code: "MISSING_OUTPUT_SCHEMA",
26
+ message: "Endpoint missing output schema",
27
+ severity: "info",
28
+ suggestion: "Infer from return type or add explicit schema"
29
+ });
30
+ if (options.checkDuplicates) {
31
+ if (ir.endpoints.filter((e) => e.id !== endpoint.id && e.path === endpoint.path && e.method === endpoint.method).length > 0) issues.push({
32
+ code: "DUPLICATE_ENDPOINT",
33
+ message: `Duplicate ${endpoint.method} ${endpoint.path} found`,
34
+ severity: "error"
35
+ });
36
+ }
37
+ if (options.checkConflicts) {
38
+ const conflicts = findPathConflicts(endpoint, ir.endpoints);
39
+ for (const conflict of conflicts) issues.push({
40
+ code: "PATH_CONFLICT",
41
+ message: `Path may conflict with ${conflict.method} ${conflict.path}`,
42
+ severity: "warning"
43
+ });
44
+ }
45
+ const status = issues.some((i) => i.severity === "error") ? "error" : issues.some((i) => i.severity === "warning") ? "warning" : "valid";
46
+ endpointResults.push({
47
+ endpoint,
48
+ status,
49
+ issues
50
+ });
51
+ }
52
+ if (options.validateSchemas) {
53
+ for (const schema of ir.schemas) if (!schema.fields || schema.fields.length === 0) ambiguities.push({
54
+ type: "schema",
55
+ itemId: schema.id,
56
+ description: `Schema ${schema.name} has no extracted fields`,
57
+ suggestion: "Review schema definition and add explicit field types",
58
+ source: schema.source
59
+ });
60
+ }
61
+ const summary = {
62
+ totalEndpoints: endpointResults.length,
63
+ validEndpoints: endpointResults.filter((r) => r.status === "valid").length,
64
+ warningEndpoints: endpointResults.filter((r) => r.status === "warning").length,
65
+ errorEndpoints: endpointResults.filter((r) => r.status === "error").length,
66
+ totalIssues: endpointResults.reduce((sum, r) => sum + r.issues.length, 0)
67
+ };
68
+ logger.info(`Verification complete: ${summary.validEndpoints} valid, ${summary.warningEndpoints} warnings, ${summary.errorEndpoints} errors`);
69
+ return {
70
+ valid: summary.errorEndpoints === 0,
71
+ endpointResults,
72
+ ambiguities,
73
+ summary
74
+ };
75
+ }
76
+ /**
77
+ * Find path conflicts (e.g., /users/:id vs /users/profile).
78
+ */
79
+ function findPathConflicts(endpoint, allEndpoints) {
80
+ const conflicts = [];
81
+ const endpointParts = endpoint.path.split("/").filter(Boolean);
82
+ for (const other of allEndpoints) {
83
+ if (other.id === endpoint.id) continue;
84
+ if (other.method !== endpoint.method) continue;
85
+ const otherParts = other.path.split("/").filter(Boolean);
86
+ if (otherParts.length !== endpointParts.length) continue;
87
+ let mightConflict = true;
88
+ for (let i = 0; i < endpointParts.length; i++) {
89
+ const a = endpointParts[i] ?? "";
90
+ const b = otherParts[i] ?? "";
91
+ const aIsParam = a.startsWith(":") || a.startsWith("{");
92
+ const bIsParam = b.startsWith(":") || b.startsWith("{");
93
+ if (!aIsParam && !bIsParam && a !== b) {
94
+ mightConflict = false;
95
+ break;
96
+ }
97
+ }
98
+ if (mightConflict && endpoint.path !== other.path) conflicts.push(other);
99
+ }
100
+ return conflicts;
101
+ }
102
+
103
+ //#endregion
104
+ export { verifyImportedContracts };
105
+ //# sourceMappingURL=verify-service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-service.mjs","names":[],"sources":["../../../src/services/import/verify-service.ts"],"sourcesContent":["/**\n * Verify service for imported contracts.\n *\n * Validates extracted contracts against existing codebase and specs.\n */\n\nimport type {\n ImportIR,\n EndpointCandidate,\n Ambiguity,\n} from '@contractspec/lib.source-extractors';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\n\n/**\n * Verification result for a single endpoint.\n */\nexport interface EndpointVerification {\n endpoint: EndpointCandidate;\n status: 'valid' | 'warning' | 'error';\n issues: VerificationIssue[];\n}\n\n/**\n * A single verification issue.\n */\nexport interface VerificationIssue {\n code: string;\n message: string;\n severity: 'error' | 'warning' | 'info';\n suggestion?: string;\n}\n\n/**\n * Options for verification.\n */\nexport interface VerifyOptions {\n /** Check for duplicate endpoints */\n checkDuplicates?: boolean;\n /** Check for conflicting paths */\n checkConflicts?: boolean;\n /** Validate schema completeness */\n validateSchemas?: boolean;\n /** Compare against existing specs */\n compareExisting?: boolean;\n /** Path to existing specs */\n existingSpecsPath?: string;\n}\n\n/**\n * Result of verification.\n */\nexport interface VerifyResult {\n valid: boolean;\n endpointResults: EndpointVerification[];\n ambiguities: Ambiguity[];\n summary: {\n totalEndpoints: number;\n validEndpoints: number;\n warningEndpoints: number;\n errorEndpoints: number;\n totalIssues: number;\n };\n}\n\n/**\n * Adapters for verification service.\n */\nexport interface VerifyServiceAdapters {\n fs: FsAdapter;\n logger: LoggerAdapter;\n}\n\n/**\n * Verify extracted contracts from IR.\n */\nexport async function verifyImportedContracts(\n ir: ImportIR,\n options: VerifyOptions,\n adapters: VerifyServiceAdapters\n): Promise<VerifyResult> {\n const { logger } = adapters;\n const endpointResults: EndpointVerification[] = [];\n const ambiguities: Ambiguity[] = [...ir.ambiguities];\n\n logger.info(`Verifying ${ir.endpoints.length} endpoints...`);\n\n // Check each endpoint\n for (const endpoint of ir.endpoints) {\n const issues: VerificationIssue[] = [];\n\n // Check confidence level\n if (\n endpoint.confidence.level === 'low' ||\n endpoint.confidence.level === 'ambiguous'\n ) {\n issues.push({\n code: 'LOW_CONFIDENCE',\n message: `Endpoint has ${endpoint.confidence.level} confidence`,\n severity: 'warning',\n suggestion: 'Review source code and add explicit schema annotations',\n });\n }\n\n // Check for missing input schema\n if (\n !endpoint.input &&\n (endpoint.method === 'POST' ||\n endpoint.method === 'PUT' ||\n endpoint.method === 'PATCH')\n ) {\n issues.push({\n code: 'MISSING_INPUT_SCHEMA',\n message: 'Command endpoint missing input schema',\n severity: 'warning',\n suggestion: 'Add Zod schema or class-validator DTO',\n });\n }\n\n // Check for missing output schema\n if (!endpoint.output) {\n issues.push({\n code: 'MISSING_OUTPUT_SCHEMA',\n message: 'Endpoint missing output schema',\n severity: 'info',\n suggestion: 'Infer from return type or add explicit schema',\n });\n }\n\n // Check for duplicate paths\n if (options.checkDuplicates) {\n const duplicates = ir.endpoints.filter(\n (e) =>\n e.id !== endpoint.id &&\n e.path === endpoint.path &&\n e.method === endpoint.method\n );\n if (duplicates.length > 0) {\n issues.push({\n code: 'DUPLICATE_ENDPOINT',\n message: `Duplicate ${endpoint.method} ${endpoint.path} found`,\n severity: 'error',\n });\n }\n }\n\n // Check for path conflicts\n if (options.checkConflicts) {\n const conflicts = findPathConflicts(endpoint, ir.endpoints);\n for (const conflict of conflicts) {\n issues.push({\n code: 'PATH_CONFLICT',\n message: `Path may conflict with ${conflict.method} ${conflict.path}`,\n severity: 'warning',\n });\n }\n }\n\n const status = issues.some((i) => i.severity === 'error')\n ? 'error'\n : issues.some((i) => i.severity === 'warning')\n ? 'warning'\n : 'valid';\n\n endpointResults.push({ endpoint, status, issues });\n }\n\n // Validate schemas if requested\n if (options.validateSchemas) {\n for (const schema of ir.schemas) {\n if (!schema.fields || schema.fields.length === 0) {\n ambiguities.push({\n type: 'schema',\n itemId: schema.id,\n description: `Schema ${schema.name} has no extracted fields`,\n suggestion: 'Review schema definition and add explicit field types',\n source: schema.source,\n });\n }\n }\n }\n\n const summary = {\n totalEndpoints: endpointResults.length,\n validEndpoints: endpointResults.filter((r) => r.status === 'valid').length,\n warningEndpoints: endpointResults.filter((r) => r.status === 'warning')\n .length,\n errorEndpoints: endpointResults.filter((r) => r.status === 'error').length,\n totalIssues: endpointResults.reduce((sum, r) => sum + r.issues.length, 0),\n };\n\n logger.info(\n `Verification complete: ${summary.validEndpoints} valid, ` +\n `${summary.warningEndpoints} warnings, ${summary.errorEndpoints} errors`\n );\n\n return {\n valid: summary.errorEndpoints === 0,\n endpointResults,\n ambiguities,\n summary,\n };\n}\n\n/**\n * Find path conflicts (e.g., /users/:id vs /users/profile).\n */\nfunction findPathConflicts(\n endpoint: EndpointCandidate,\n allEndpoints: EndpointCandidate[]\n): EndpointCandidate[] {\n const conflicts: EndpointCandidate[] = [];\n\n const endpointParts = endpoint.path.split('/').filter(Boolean);\n\n for (const other of allEndpoints) {\n if (other.id === endpoint.id) continue;\n if (other.method !== endpoint.method) continue;\n\n const otherParts = other.path.split('/').filter(Boolean);\n if (otherParts.length !== endpointParts.length) continue;\n\n let mightConflict = true;\n for (let i = 0; i < endpointParts.length; i++) {\n const a = endpointParts[i] ?? '';\n const b = otherParts[i] ?? '';\n\n const aIsParam = a.startsWith(':') || a.startsWith('{');\n const bIsParam = b.startsWith(':') || b.startsWith('{');\n\n if (!aIsParam && !bIsParam && a !== b) {\n mightConflict = false;\n break;\n }\n }\n\n if (mightConflict && endpoint.path !== other.path) {\n conflicts.push(other);\n }\n }\n\n return conflicts;\n}\n"],"mappings":"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"}
@@ -100,4 +100,8 @@ import { ViewAudience, generateView } from "./view/index.mjs";
100
100
  import { GapAnalysisResult, analyzeGap } from "./gap.mjs";
101
101
  import { GenerateArtifactsResult, generateArtifacts } from "./generate-artifacts.mjs";
102
102
  import { ExtractOptions, extractContracts } from "./extract.mjs";
103
- import { index_d_exports as index_d_exports$6 } from "./vibe/index.mjs";
103
+ import { index_d_exports as index_d_exports$6 } from "./vibe/index.mjs";
104
+ import { ImportServiceAdapters, ImportServiceOptions, ImportServiceResult, importFromSourceService } from "./import/import-service.mjs";
105
+ import { EndpointVerification, VerificationIssue as VerificationIssue$1, VerifyOptions as VerifyOptions$1, VerifyResult as VerifyResult$1, verifyImportedContracts } from "./import/verify-service.mjs";
106
+ import { ReportOptions, generateCliReport, generateMarkdownReport } from "./import/report-service.mjs";
107
+ import "./import/index.mjs";
@@ -96,5 +96,9 @@ import { generateView } from "./view/index.mjs";
96
96
  import { analyzeGap } from "./gap.mjs";
97
97
  import { extractContracts } from "./extract.mjs";
98
98
  import { vibe_exports } from "./vibe/index.mjs";
99
+ import { importFromSourceService } from "./import/import-service.mjs";
100
+ import { verifyImportedContracts } from "./import/verify-service.mjs";
101
+ import { generateCliReport, generateMarkdownReport } from "./import/report-service.mjs";
102
+ import "./import/index.mjs";
99
103
 
100
104
  export { };
@@ -1,14 +1,14 @@
1
1
  import { FsAdapter } from "../../ports/fs.mjs";
2
2
  import { LoggerAdapter } from "../../ports/logger.mjs";
3
3
  import { OpenApiImportServiceOptions, OpenApiImportServiceResult } from "./types.mjs";
4
- import { ContractsrcConfig } from "@contractspec/lib.contracts";
4
+ import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
5
5
 
6
6
  //#region src/services/openapi/import-service.d.ts
7
7
 
8
8
  /**
9
9
  * Import ContractSpec specs from an OpenAPI document.
10
10
  */
11
- declare function importFromOpenApiService(contractspecOptions: ContractsrcConfig, options: OpenApiImportServiceOptions, adapters: {
11
+ declare function importFromOpenApiService(contractspecOptions: ResolvedContractsrcConfig, options: OpenApiImportServiceOptions, adapters: {
12
12
  fs: FsAdapter;
13
13
  logger: LoggerAdapter;
14
14
  }): Promise<OpenApiImportServiceResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AA2DqC,iBAHf,wBAAA,CAGe,mBAAA,EAFd,iBAEc,EAAA,OAAA,EAD1B,2BAC0B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,0BAAD,CAAA"}
1
+ {"version":3,"file":"import-service.d.mts","names":[],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAwDqC,iBAHf,wBAAA,CAGe,mBAAA,EAFd,yBAEc,EAAA,OAAA,EAD1B,2BAC0B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,0BAAD,CAAA"}
@@ -10,14 +10,11 @@ import { importFromOpenApi, parseOpenApi } from "@contractspec/lib.contracts-tra
10
10
  */
11
11
  function getOutputDir(type, options, config) {
12
12
  if (options.outputDir) return options.outputDir;
13
- const baseDir = config.outputDir ?? "src";
14
- const conventions = config.conventions ?? {
15
- operations: "operations",
16
- events: "events"
17
- };
13
+ const baseDir = config.outputDir;
14
+ const conventions = config.conventions;
18
15
  switch (type) {
19
16
  case "operation": return join(baseDir, conventions.operations.split("|")[0] ?? "operations");
20
- case "event": return join(baseDir, conventions.events ?? "events");
17
+ case "event": return join(baseDir, conventions.events);
21
18
  case "model": return join(baseDir, "models");
22
19
  default: return baseDir;
23
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"import-service.mjs","names":["path"],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":["/**\n * OpenAPI import service - imports specs from OpenAPI documents.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiImportServiceOptions,\n OpenApiImportServiceResult,\n} from './types';\nimport { dirname, join, basename } from 'path';\nimport type { ContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Get output directory for spec type\n */\nfunction getOutputDir(\n type: 'operation' | 'event' | 'model',\n options: OpenApiImportServiceOptions,\n config: ContractsrcConfig\n): string {\n // If outputDir is explicitly set in options, use it for all types\n if (options.outputDir) {\n return options.outputDir;\n }\n\n // Default base\n const baseDir = config.outputDir ?? 'src';\n const conventions = config.conventions ?? {\n operations: 'operations',\n events: 'events',\n };\n\n switch (type) {\n case 'operation':\n // Conventions usually format like \"operations/**\" or \"operations\"\n return join(\n baseDir,\n conventions.operations.split('|')[0] ?? 'operations'\n );\n case 'event':\n return join(baseDir, conventions.events ?? 'events');\n case 'model':\n return join(baseDir, 'models'); // Standardize on 'models' for now\n default:\n return baseDir;\n }\n}\n\n/**\n * Import ContractSpec specs from an OpenAPI document.\n */\nexport async function importFromOpenApiService(\n contractspecOptions: ContractsrcConfig,\n options: OpenApiImportServiceOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiImportServiceResult> {\n const { fs, logger } = adapters;\n const {\n source,\n\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n dryRun = false,\n } = options;\n\n logger.info(`Importing from OpenAPI: ${source}`);\n\n // Parse the OpenAPI document\n // Use globalThis.fetch because adapters don't have networking yet\n // but we use fs.readFile for local files\n const parseResult = await parseOpenApi(source, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n if (parseResult.warnings.length > 0) {\n for (const warning of parseResult.warnings) {\n logger.warn(`Parse warning: ${warning}`);\n }\n }\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${parseResult.info.title} v${parseResult.info.version}`\n );\n\n // Import operations\n const importResult = importFromOpenApi(parseResult, contractspecOptions, {\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n });\n\n logger.info(\n `Import result: ${importResult.summary.imported} imported, ${importResult.summary.skipped} skipped, ${importResult.summary.errors} errors`\n );\n\n const files: OpenApiImportServiceResult['files'] = [];\n const skippedOperations: OpenApiImportServiceResult['skippedOperations'] = [];\n const errorMessages: OpenApiImportServiceResult['errorMessages'] = [];\n\n // Write imported specs\n const specsByDir = new Map<\n string,\n { file: string; name: string; type: 'operation' | 'event' | 'model' }[]\n >();\n\n for (const spec of importResult.operationSpecs) {\n // Determine type FIRST to resolve output directory\n let type: 'operation' | 'event' | 'model' = 'operation';\n let match: RegExpMatchArray | null = null;\n if (spec.code.includes('defineEvent(')) {\n type = 'event';\n match = spec.code.match(/export const (\\w+)\\s*=\\s*defineEvent/);\n } else if (\n (spec.code.includes('defineSchemaModel(') ||\n spec.code.includes('new EnumType(') ||\n spec.code.includes('ScalarTypeEnum.') ||\n spec.code.includes('new ZodSchemaType(') ||\n spec.code.includes('z.enum(') ||\n spec.code.includes('new JsonSchemaType(') ||\n spec.code.includes('new GraphQLSchemaType(')) &&\n !spec.code.includes('defineCommand(') &&\n !spec.code.includes('defineQuery(')\n ) {\n type = 'model';\n } else {\n type = 'operation';\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*define(?:Command|Query)/\n );\n }\n\n // Resolve output directory based on type\n const targetDir = getOutputDir(type, options, contractspecOptions);\n const filePath = join(targetDir, spec.fileName);\n\n if (!match && type === 'model') {\n if (spec.code.includes('new ZodSchemaType(')) {\n match = spec.code.match(/export const (\\w+)\\s*=\\s*new ZodSchemaType\\(/);\n } else if (spec.code.includes('new JsonSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new JsonSchemaType\\(/\n );\n } else if (spec.code.includes('new GraphQLSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new GraphQLSchemaType\\(/\n );\n }\n if (!match) {\n match = spec.code.match(/export const (\\w+)\\s*=/);\n }\n }\n\n if (dryRun) {\n logger.info(`[DRY RUN] Would create: ${filePath}`);\n } else {\n // Ensure directory exists\n const dir = dirname(filePath);\n const exists = await fs.exists(dir);\n if (!exists) {\n await fs.mkdir(dir);\n }\n\n // Write spec file\n await fs.writeFile(filePath, spec.code);\n logger.info(`Created: ${filePath}`);\n }\n\n files.push({\n path: filePath,\n operationId: spec.source.sourceId,\n specName: spec.fileName.replace('.ts', ''),\n });\n\n if (match) {\n const dir = dirname(filePath);\n const existing = specsByDir.get(dir) || [];\n existing.push({\n file: basename(filePath),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n name: match[1]!,\n type,\n });\n specsByDir.set(dir, existing);\n }\n }\n\n // Generate registries\n if (!dryRun && files.length > 0) {\n for (const [dir, specs] of specsByDir.entries()) {\n if (specs.length === 0) continue;\n\n // Detect dominant type\n const types = specs.map((s) => s.type);\n const isOperations = types.every((t) => t === 'operation');\n const isEvents = types.every((t) => t === 'event');\n const isModels = types.every((t) => t === 'model');\n\n // Generate Registry File\n let registryCode = `/**\\n * Auto-generated registry file.\\n */\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n registryCode += `import { ${s.name} } from '${importPath}';\\n`;\n });\n registryCode += '\\n';\n\n let hasRegistry = false;\n if (isOperations) {\n registryCode += `import { OperationSpecRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const operationRegistry = new OperationSpecRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `operationRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isEvents) {\n registryCode += `import { EventRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const eventRegistry = new EventRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `eventRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isModels) {\n registryCode += `import { ModelRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const modelRegistry = new ModelRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `modelRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n }\n\n if (hasRegistry) {\n const registryPath = join(dir, 'registry.ts');\n await fs.writeFile(registryPath, registryCode);\n logger.info(`Created/Updated registry: ${registryPath}`);\n }\n\n // Generate Index File\n let indexCode = `/**\\n * Auto-generated barrel file.\\n */\\n\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n indexCode += `export * from '${importPath}';\\n`;\n });\n\n if (hasRegistry) {\n indexCode += `export * from './registry';\\n`;\n }\n\n const indexPath = join(dir, 'index.ts');\n await fs.writeFile(indexPath, indexCode);\n logger.info(`Created/Updated index: ${indexPath}`);\n }\n }\n\n // Record skipped operations\n for (const skipped of importResult.skipped) {\n skippedOperations.push({\n operationId: skipped.sourceId,\n reason: skipped.reason,\n });\n logger.debug(`Skipped: ${skipped.sourceId} - ${skipped.reason}`);\n }\n\n // Record errors\n for (const error of importResult.errors) {\n errorMessages.push({\n operationId: error.sourceId,\n error: error.error,\n });\n logger.error(`Error: ${error.sourceId} - ${error.error}`);\n }\n\n return {\n imported: importResult.summary.imported,\n skipped: importResult.summary.skipped,\n errors: importResult.summary.errors,\n files,\n skippedOperations,\n errorMessages,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"import-service.mjs","names":["path"],"sources":["../../../src/services/openapi/import-service.ts"],"sourcesContent":["/**\n * OpenAPI import service - imports specs from OpenAPI documents.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiImportServiceOptions,\n OpenApiImportServiceResult,\n} from './types';\nimport { dirname, join, basename } from 'path';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Get output directory for spec type\n */\nfunction getOutputDir(\n type: 'operation' | 'event' | 'model',\n options: OpenApiImportServiceOptions,\n config: ResolvedContractsrcConfig\n): string {\n // If outputDir is explicitly set in options, use it for all types\n if (options.outputDir) {\n return options.outputDir;\n }\n\n // Default base\n const baseDir = config.outputDir;\n const conventions = config.conventions;\n\n switch (type) {\n case 'operation':\n // Conventions usually format like \"operations/**\" or \"operations\"\n return join(\n baseDir,\n conventions.operations.split('|')[0] ?? 'operations'\n );\n case 'event':\n return join(baseDir, conventions.events);\n case 'model':\n return join(baseDir, 'models'); // Standardize on 'models' for now\n default:\n return baseDir;\n }\n}\n\n/**\n * Import ContractSpec specs from an OpenAPI document.\n */\nexport async function importFromOpenApiService(\n contractspecOptions: ResolvedContractsrcConfig,\n options: OpenApiImportServiceOptions,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiImportServiceResult> {\n const { fs, logger } = adapters;\n const {\n source,\n\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n dryRun = false,\n } = options;\n\n logger.info(`Importing from OpenAPI: ${source}`);\n\n // Parse the OpenAPI document\n // Use globalThis.fetch because adapters don't have networking yet\n // but we use fs.readFile for local files\n const parseResult = await parseOpenApi(source, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n if (parseResult.warnings.length > 0) {\n for (const warning of parseResult.warnings) {\n logger.warn(`Parse warning: ${warning}`);\n }\n }\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${parseResult.info.title} v${parseResult.info.version}`\n );\n\n // Import operations\n const importResult = importFromOpenApi(parseResult, contractspecOptions, {\n prefix,\n tags,\n exclude,\n defaultStability,\n defaultOwners,\n defaultAuth,\n });\n\n logger.info(\n `Import result: ${importResult.summary.imported} imported, ${importResult.summary.skipped} skipped, ${importResult.summary.errors} errors`\n );\n\n const files: OpenApiImportServiceResult['files'] = [];\n const skippedOperations: OpenApiImportServiceResult['skippedOperations'] = [];\n const errorMessages: OpenApiImportServiceResult['errorMessages'] = [];\n\n // Write imported specs\n const specsByDir = new Map<\n string,\n { file: string; name: string; type: 'operation' | 'event' | 'model' }[]\n >();\n\n for (const spec of importResult.operationSpecs) {\n // Determine type FIRST to resolve output directory\n let type: 'operation' | 'event' | 'model' = 'operation';\n let match: RegExpMatchArray | null = null;\n if (spec.code.includes('defineEvent(')) {\n type = 'event';\n match = spec.code.match(/export const (\\w+)\\s*=\\s*defineEvent/);\n } else if (\n (spec.code.includes('defineSchemaModel(') ||\n spec.code.includes('new EnumType(') ||\n spec.code.includes('ScalarTypeEnum.') ||\n spec.code.includes('new ZodSchemaType(') ||\n spec.code.includes('z.enum(') ||\n spec.code.includes('new JsonSchemaType(') ||\n spec.code.includes('new GraphQLSchemaType(')) &&\n !spec.code.includes('defineCommand(') &&\n !spec.code.includes('defineQuery(')\n ) {\n type = 'model';\n } else {\n type = 'operation';\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*define(?:Command|Query)/\n );\n }\n\n // Resolve output directory based on type\n const targetDir = getOutputDir(type, options, contractspecOptions);\n const filePath = join(targetDir, spec.fileName);\n\n if (!match && type === 'model') {\n if (spec.code.includes('new ZodSchemaType(')) {\n match = spec.code.match(/export const (\\w+)\\s*=\\s*new ZodSchemaType\\(/);\n } else if (spec.code.includes('new JsonSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new JsonSchemaType\\(/\n );\n } else if (spec.code.includes('new GraphQLSchemaType(')) {\n match = spec.code.match(\n /export const (\\w+)\\s*=\\s*new GraphQLSchemaType\\(/\n );\n }\n if (!match) {\n match = spec.code.match(/export const (\\w+)\\s*=/);\n }\n }\n\n if (dryRun) {\n logger.info(`[DRY RUN] Would create: ${filePath}`);\n } else {\n // Ensure directory exists\n const dir = dirname(filePath);\n const exists = await fs.exists(dir);\n if (!exists) {\n await fs.mkdir(dir);\n }\n\n // Write spec file\n await fs.writeFile(filePath, spec.code);\n logger.info(`Created: ${filePath}`);\n }\n\n files.push({\n path: filePath,\n operationId: spec.source.sourceId,\n specName: spec.fileName.replace('.ts', ''),\n });\n\n if (match) {\n const dir = dirname(filePath);\n const existing = specsByDir.get(dir) || [];\n existing.push({\n file: basename(filePath),\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n name: match[1]!,\n type,\n });\n specsByDir.set(dir, existing);\n }\n }\n\n // Generate registries\n if (!dryRun && files.length > 0) {\n for (const [dir, specs] of specsByDir.entries()) {\n if (specs.length === 0) continue;\n\n // Detect dominant type\n const types = specs.map((s) => s.type);\n const isOperations = types.every((t) => t === 'operation');\n const isEvents = types.every((t) => t === 'event');\n const isModels = types.every((t) => t === 'model');\n\n // Generate Registry File\n let registryCode = `/**\\n * Auto-generated registry file.\\n */\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n registryCode += `import { ${s.name} } from '${importPath}';\\n`;\n });\n registryCode += '\\n';\n\n let hasRegistry = false;\n if (isOperations) {\n registryCode += `import { OperationSpecRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const operationRegistry = new OperationSpecRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `operationRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isEvents) {\n registryCode += `import { EventRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const eventRegistry = new EventRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `eventRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n } else if (isModels) {\n registryCode += `import { ModelRegistry } from '@contractspec/lib.contracts';\\n\\n`;\n registryCode += `export const modelRegistry = new ModelRegistry();\\n`;\n specs.forEach((s) => {\n registryCode += `modelRegistry.register(${s.name});\\n`;\n });\n hasRegistry = true;\n }\n\n if (hasRegistry) {\n const registryPath = join(dir, 'registry.ts');\n await fs.writeFile(registryPath, registryCode);\n logger.info(`Created/Updated registry: ${registryPath}`);\n }\n\n // Generate Index File\n let indexCode = `/**\\n * Auto-generated barrel file.\\n */\\n\\n`;\n specs.forEach((s) => {\n const importPath = `./${basename(s.file, '.ts')}`;\n indexCode += `export * from '${importPath}';\\n`;\n });\n\n if (hasRegistry) {\n indexCode += `export * from './registry';\\n`;\n }\n\n const indexPath = join(dir, 'index.ts');\n await fs.writeFile(indexPath, indexCode);\n logger.info(`Created/Updated index: ${indexPath}`);\n }\n }\n\n // Record skipped operations\n for (const skipped of importResult.skipped) {\n skippedOperations.push({\n operationId: skipped.sourceId,\n reason: skipped.reason,\n });\n logger.debug(`Skipped: ${skipped.sourceId} - ${skipped.reason}`);\n }\n\n // Record errors\n for (const error of importResult.errors) {\n errorMessages.push({\n operationId: error.sourceId,\n error: error.error,\n });\n logger.error(`Error: ${error.sourceId} - ${error.error}`);\n }\n\n return {\n imported: importResult.summary.imported,\n skipped: importResult.summary.skipped,\n errors: importResult.summary.errors,\n files,\n skippedOperations,\n errorMessages,\n };\n}\n"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  import { FsAdapter } from "../../ports/fs.mjs";
2
2
  import { LoggerAdapter } from "../../ports/logger.mjs";
3
3
  import { OpenApiSyncServiceOptions, OpenApiSyncServiceResult } from "./types.mjs";
4
- import { ContractsrcConfig } from "@contractspec/lib.contracts";
4
+ import { ResolvedContractsrcConfig } from "@contractspec/lib.contracts";
5
5
 
6
6
  //#region src/services/openapi/sync-service.d.ts
7
7
 
8
8
  /**
9
9
  * Sync ContractSpec specs with OpenAPI sources.
10
10
  */
11
- declare function syncWithOpenApiService(options: OpenApiSyncServiceOptions, config: ContractsrcConfig, adapters: {
11
+ declare function syncWithOpenApiService(options: OpenApiSyncServiceOptions, config: ResolvedContractsrcConfig, adapters: {
12
12
  fs: FsAdapter;
13
13
  logger: LoggerAdapter;
14
14
  }): Promise<OpenApiSyncServiceResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBqC,iBAHf,sBAAA,CAGe,OAAA,EAF1B,yBAE0B,EAAA,MAAA,EAD3B,iBAC2B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,wBAAD,CAAA"}
1
+ {"version":3,"file":"sync-service.d.mts","names":[],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBqC,iBAHf,sBAAA,CAGe,OAAA,EAF1B,yBAE0B,EAAA,MAAA,EAD3B,yBAC2B,EAAA,QAAA,EAAA;EAC1B,EAAA,EADO,SACP;EAAR,MAAA,EADkC,aAClC;CAAO,CAAA,EAAP,OAAO,CAAC,wBAAD,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sync-service.mjs","names":["path"],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":["/**\n * OpenAPI sync service - syncs specs with OpenAPI sources.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiSyncServiceOptions,\n OpenApiSyncServiceResult,\n} from './types';\nimport { dirname, join } from 'path';\nimport type { ContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Sync ContractSpec specs with OpenAPI sources.\n */\nexport async function syncWithOpenApiService(\n options: OpenApiSyncServiceOptions,\n config: ContractsrcConfig,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiSyncServiceResult> {\n const { fs, logger } = adapters;\n const {\n sources: optSources,\n sourceName,\n interactive,\n force,\n dryRun,\n } = options;\n const { outputDir } = config;\n\n // Determine which sources to sync\n let sourcesToSync = optSources ?? config.openapi?.sources ?? [];\n\n if (sourceName) {\n sourcesToSync = sourcesToSync.filter((s) => s.name === sourceName);\n if (sourcesToSync.length === 0) {\n throw new Error(`Source not found: ${sourceName}`);\n }\n }\n\n if (sourcesToSync.length === 0) {\n logger.warn(\n 'No OpenAPI sources configured. Add sources to .contractsrc.json'\n );\n return {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n }\n\n const result: OpenApiSyncServiceResult = {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n\n for (const source of sourcesToSync) {\n logger.info(`Syncing with source: ${source.name}`);\n\n // Get source URL or file\n const sourceLocation = source.url ?? source.file;\n if (!sourceLocation) {\n logger.warn(`Source ${source.name} has no url or file configured`);\n continue;\n }\n\n // Parse the OpenAPI document\n const parseResult = await parseOpenApi(sourceLocation, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${source.name}`\n );\n\n // Import operations to get the new specs\n const importResult = importFromOpenApi(parseResult, config, {\n prefix: source.prefix,\n tags: source.tags,\n exclude: source.exclude,\n defaultStability: source.defaultStability,\n defaultAuth: source.defaultAuth,\n });\n\n // Process each imported spec\n for (const imported of importResult.operationSpecs) {\n const filePath = join(outputDir, imported.fileName);\n const exists = await fs.exists(filePath);\n\n if (!exists) {\n // New spec - add it\n if (!dryRun) {\n const dir = dirname(filePath);\n await fs.mkdir(dir);\n await fs.writeFile(filePath, imported.code);\n }\n\n result.added++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'added',\n path: filePath,\n });\n logger.info(`Added: ${imported.source.sourceId}`);\n } else {\n // Existing spec - check for differences\n const existingCode = await fs.readFile(filePath);\n\n if (existingCode === imported.code) {\n // No changes\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n } else {\n // Differences detected\n if (force === 'openapi') {\n // Overwrite with OpenAPI version\n if (!dryRun) {\n await fs.writeFile(filePath, imported.code);\n }\n result.updated++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'updated',\n path: filePath,\n });\n logger.info(`Updated: ${imported.source.sourceId}`);\n } else if (force === 'contractspec') {\n // Keep ContractSpec version\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n logger.info(`Kept: ${imported.source.sourceId}`);\n } else if (interactive) {\n // Would prompt for resolution in CLI\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(\n `Conflict: ${imported.source.sourceId} - needs resolution`\n );\n } else {\n // Default: report conflict\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(`Conflict: ${imported.source.sourceId}`);\n }\n }\n }\n }\n }\n\n logger.info(\n `Sync complete: ${result.added} added, ${result.updated} updated, ${result.unchanged} unchanged, ${result.conflicts} conflicts`\n );\n\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sync-service.mjs","names":["path"],"sources":["../../../src/services/openapi/sync-service.ts"],"sourcesContent":["/**\n * OpenAPI sync service - syncs specs with OpenAPI sources.\n */\n\nimport {\n importFromOpenApi,\n parseOpenApi,\n} from '@contractspec/lib.contracts-transformers/openapi';\nimport type { FsAdapter } from '../../ports/fs';\nimport type { LoggerAdapter } from '../../ports/logger';\nimport type {\n OpenApiSyncServiceOptions,\n OpenApiSyncServiceResult,\n} from './types';\nimport { dirname, join } from 'path';\nimport type { ResolvedContractsrcConfig } from '@contractspec/lib.contracts';\n\n/**\n * Sync ContractSpec specs with OpenAPI sources.\n */\nexport async function syncWithOpenApiService(\n options: OpenApiSyncServiceOptions,\n config: ResolvedContractsrcConfig,\n adapters: { fs: FsAdapter; logger: LoggerAdapter }\n): Promise<OpenApiSyncServiceResult> {\n const { fs, logger } = adapters;\n const {\n sources: optSources,\n sourceName,\n interactive,\n force,\n dryRun,\n } = options;\n const { outputDir } = config;\n\n // Determine which sources to sync\n let sourcesToSync = optSources ?? config.openapi?.sources ?? [];\n\n if (sourceName) {\n sourcesToSync = sourcesToSync.filter((s) => s.name === sourceName);\n if (sourcesToSync.length === 0) {\n throw new Error(`Source not found: ${sourceName}`);\n }\n }\n\n if (sourcesToSync.length === 0) {\n logger.warn(\n 'No OpenAPI sources configured. Add sources to .contractsrc.json'\n );\n return {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n }\n\n const result: OpenApiSyncServiceResult = {\n added: 0,\n updated: 0,\n unchanged: 0,\n conflicts: 0,\n changes: [],\n };\n\n for (const source of sourcesToSync) {\n logger.info(`Syncing with source: ${source.name}`);\n\n // Get source URL or file\n const sourceLocation = source.url ?? source.file;\n if (!sourceLocation) {\n logger.warn(`Source ${source.name} has no url or file configured`);\n continue;\n }\n\n // Parse the OpenAPI document\n const parseResult = await parseOpenApi(sourceLocation, {\n fetch: globalThis.fetch,\n readFile: (path) => fs.readFile(path),\n });\n\n logger.info(\n `Parsed ${parseResult.operations.length} operations from ${source.name}`\n );\n\n // Import operations to get the new specs\n const importResult = importFromOpenApi(parseResult, config, {\n prefix: source.prefix,\n tags: source.tags,\n exclude: source.exclude,\n defaultStability: source.defaultStability,\n defaultAuth: source.defaultAuth,\n });\n\n // Process each imported spec\n for (const imported of importResult.operationSpecs) {\n const filePath = join(outputDir, imported.fileName);\n const exists = await fs.exists(filePath);\n\n if (!exists) {\n // New spec - add it\n if (!dryRun) {\n const dir = dirname(filePath);\n await fs.mkdir(dir);\n await fs.writeFile(filePath, imported.code);\n }\n\n result.added++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'added',\n path: filePath,\n });\n logger.info(`Added: ${imported.source.sourceId}`);\n } else {\n // Existing spec - check for differences\n const existingCode = await fs.readFile(filePath);\n\n if (existingCode === imported.code) {\n // No changes\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n } else {\n // Differences detected\n if (force === 'openapi') {\n // Overwrite with OpenAPI version\n if (!dryRun) {\n await fs.writeFile(filePath, imported.code);\n }\n result.updated++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'updated',\n path: filePath,\n });\n logger.info(`Updated: ${imported.source.sourceId}`);\n } else if (force === 'contractspec') {\n // Keep ContractSpec version\n result.unchanged++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'unchanged',\n path: filePath,\n });\n logger.info(`Kept: ${imported.source.sourceId}`);\n } else if (interactive) {\n // Would prompt for resolution in CLI\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(\n `Conflict: ${imported.source.sourceId} - needs resolution`\n );\n } else {\n // Default: report conflict\n result.conflicts++;\n result.changes.push({\n operationId: imported.source.sourceId,\n action: 'conflict',\n path: filePath,\n });\n logger.warn(`Conflict: ${imported.source.sourceId}`);\n }\n }\n }\n }\n }\n\n logger.info(\n `Sync complete: ${result.added} added, ${result.updated} updated, ${result.unchanged} unchanged, ${result.conflicts} conflicts`\n );\n\n return result;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":[],"mappings":";;;;;;AAkByB,cAFZ,eAAA,YAA2B,YAEf,CAAA;EACI,iBAAA,EAAA;EAGP,iBAAA,MAAA;EAA0B,WAAA,CAAA,EAAA,EAJvB,SAIuB,EAAA,MAAA,EAHnB,aAGmB;EAAR,IAAA,CAAA,OAAA,EAAlB,eAAkB,CAAA,EAAA,OAAA,CAAQ,cAAR,CAAA;EAyER,cAAA,CAAA,OAAA,EAAA,eAAA,CAAA,EAAkB,OAAlB,CAAA,MAAA,CAAA;EAAkB,QAAA,iBAAA"}
1
+ {"version":3,"file":"rulesync.d.mts","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":[],"mappings":";;;;;;AAkByB,cAFZ,eAAA,YAA2B,YAEf,CAAA;EACI,iBAAA,EAAA;EAGP,iBAAA,MAAA;EAA0B,WAAA,CAAA,EAAA,EAJvB,SAIuB,EAAA,MAAA,EAHnB,aAGmB;EAAR,IAAA,CAAA,OAAA,EAAlB,eAAkB,CAAA,EAAA,OAAA,CAAQ,cAAR,CAAA;EA0ER,cAAA,CAAA,OAAA,EAAA,eAAA,CAAA,EAAkB,OAAlB,CAAA,MAAA,CAAA;EAAkB,QAAA,iBAAA"}
@@ -5,7 +5,8 @@ var RuleSyncService = class {
5
5
  this.logger = logger;
6
6
  }
7
7
  async sync(options) {
8
- const { config, cwd, targets = config.targets } = options;
8
+ const { config, cwd } = options;
9
+ const targets = options.targets ?? config.targets ?? [];
9
10
  if (!config.enabled && !options.targets) return {
10
11
  success: true,
11
12
  files: [],
@@ -13,7 +14,7 @@ var RuleSyncService = class {
13
14
  };
14
15
  this.logger.info(`Synchronizing rules for targets: ${targets.join(", ")}...`);
15
16
  try {
16
- const rulesDir = this.fs.join(cwd, config.rulesDir);
17
+ const rulesDir = this.fs.join(cwd, config.rulesDir ?? ".rules");
17
18
  if (!await this.fs.exists(rulesDir)) return {
18
19
  success: false,
19
20
  files: [],
@@ -47,7 +48,7 @@ var RuleSyncService = class {
47
48
  async generateConfig(options) {
48
49
  const { config } = options;
49
50
  const rulesyncConfig = {
50
- rules: config.rules.map((r) => this.fs.join(config.rulesDir, r)),
51
+ rules: (config.rules ?? []).map((r) => this.fs.join(config.rulesDir ?? ".rules", r)),
51
52
  targets: options.targets || config.targets
52
53
  };
53
54
  return JSON.stringify(rulesyncConfig, null, 2);
@@ -1 +1 @@
1
- {"version":3,"file":"rulesync.mjs","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":["/**\n * Service for synchronizing AI agent rules.\n */\n\nimport type {\n RuleSyncPort,\n RuleSyncOptions,\n RuleSyncResult,\n} from '../ports/rulesync';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n// We import rulesync dynamically to avoid issues if it's not present or has ESM/CJS mismatches\n// In a real implementation, we would use the actual programmatic API of rulesync if available.\n// For now, we'll implement it by generating the config and potentially calling the CLI or using its core logic.\n\nexport class RuleSyncService implements RuleSyncPort {\n constructor(\n private readonly fs: FsAdapter,\n private readonly logger: LoggerAdapter\n ) {}\n\n async sync(options: RuleSyncOptions): Promise<RuleSyncResult> {\n const { config, cwd, targets = config.targets } = options;\n\n if (!config.enabled && !options.targets) {\n return {\n success: true,\n files: [],\n logs: ['Rule synchronization is disabled.'],\n };\n }\n\n this.logger.info(\n `Synchronizing rules for targets: ${targets.join(', ')}...`\n );\n\n try {\n // 1. Ensure rules directory exists\n const rulesDir = this.fs.join(cwd, config.rulesDir);\n const rulesDirExists = await this.fs.exists(rulesDir);\n if (!rulesDirExists) {\n return {\n success: false,\n files: [],\n errors: [`Rules directory not found: ${rulesDir}`],\n };\n }\n\n // 2. Implementation choice:\n // If ejectMode is true, we just copy rules to targets if possible,\n // but usually rulesync is better for merging and formatting.\n\n // For now, let's implement the logic that leverages 'rulesync' patterns.\n // We generate a temporary rulesync.config.json if needed, or use their API.\n\n const rsConfig = await this.generateConfig(options);\n\n // In a real-world scenario, we would call the rulesync programmatic API here:\n // const { sync } = await import('rulesync');\n // await sync({ config: JSON.parse(rsConfig), cwd });\n\n this.logger.debug(`Generated rulesync config: ${rsConfig}`);\n\n // For this implementation, we'll simulate the file generation matching rulesync's behavior\n // until we have the full API details of the library.\n\n const files: string[] = [];\n for (const target of targets) {\n const targetFile = this.getTargetFileName(target);\n if (targetFile) {\n const fullPath = this.fs.join(cwd, targetFile);\n // Logic to aggregate rules from config.rulesDir and write to fullPath\n // would go here. rulesync handles this by parsing the files and\n // combining them based on the target.\n files.push(fullPath);\n }\n }\n\n return {\n success: true,\n files,\n logs: [`Successfully synchronized rules to ${files.length} targets.`],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error(`Rule synchronization failed: ${message}`);\n return {\n success: false,\n files: [],\n errors: [message],\n };\n }\n }\n\n async generateConfig(options: RuleSyncOptions): Promise<string> {\n const { config } = options;\n\n // Convert our ContractSpec RuleSyncConfig to rulesync's config format\n const rulesyncConfig = {\n rules: config.rules.map((r: string) => this.fs.join(config.rulesDir, r)),\n targets: options.targets || config.targets,\n // Add other rulesync specific options here\n };\n\n return JSON.stringify(rulesyncConfig, null, 2);\n }\n\n private getTargetFileName(target: string): string | undefined {\n switch (target) {\n case 'cursor':\n return '.cursorrules';\n case 'windsurf':\n return '.windsurfrules';\n case 'cline':\n return '.clinerules';\n case 'claude-code':\n return 'CLAUDE.md';\n case 'copilot':\n return '.github/copilot-instructions.md';\n case 'subagent':\n return '.subagent';\n case 'skill':\n return '.skill';\n default:\n return undefined;\n }\n }\n}\n"],"mappings":";AAgBA,IAAa,kBAAb,MAAqD;CACnD,YACE,AAAiB,IACjB,AAAiB,QACjB;EAFiB;EACA;;CAGnB,MAAM,KAAK,SAAmD;EAC5D,MAAM,EAAE,QAAQ,KAAK,UAAU,OAAO,YAAY;AAElD,MAAI,CAAC,OAAO,WAAW,CAAC,QAAQ,QAC9B,QAAO;GACL,SAAS;GACT,OAAO,EAAE;GACT,MAAM,CAAC,oCAAoC;GAC5C;AAGH,OAAK,OAAO,KACV,oCAAoC,QAAQ,KAAK,KAAK,CAAC,KACxD;AAED,MAAI;GAEF,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,OAAO,SAAS;AAEnD,OAAI,CADmB,MAAM,KAAK,GAAG,OAAO,SAAS,CAEnD,QAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,8BAA8B,WAAW;IACnD;GAUH,MAAM,WAAW,MAAM,KAAK,eAAe,QAAQ;AAMnD,QAAK,OAAO,MAAM,8BAA8B,WAAW;GAK3D,MAAM,QAAkB,EAAE;AAC1B,QAAK,MAAM,UAAU,SAAS;IAC5B,MAAM,aAAa,KAAK,kBAAkB,OAAO;AACjD,QAAI,YAAY;KACd,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,WAAW;AAI9C,WAAM,KAAK,SAAS;;;AAIxB,UAAO;IACL,SAAS;IACT;IACA,MAAM,CAAC,sCAAsC,MAAM,OAAO,WAAW;IACtE;WACM,OAAO;GACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAK,OAAO,MAAM,gCAAgC,UAAU;AAC5D,UAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,QAAQ;IAClB;;;CAIL,MAAM,eAAe,SAA2C;EAC9D,MAAM,EAAE,WAAW;EAGnB,MAAM,iBAAiB;GACrB,OAAO,OAAO,MAAM,KAAK,MAAc,KAAK,GAAG,KAAK,OAAO,UAAU,EAAE,CAAC;GACxE,SAAS,QAAQ,WAAW,OAAO;GAEpC;AAED,SAAO,KAAK,UAAU,gBAAgB,MAAM,EAAE;;CAGhD,AAAQ,kBAAkB,QAAoC;AAC5D,UAAQ,QAAR;GACE,KAAK,SACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,KAAK,cACH,QAAO;GACT,KAAK,UACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,QACE"}
1
+ {"version":3,"file":"rulesync.mjs","names":[],"sources":["../../src/services/rulesync.ts"],"sourcesContent":["/**\n * Service for synchronizing AI agent rules.\n */\n\nimport type {\n RuleSyncPort,\n RuleSyncOptions,\n RuleSyncResult,\n} from '../ports/rulesync';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n// We import rulesync dynamically to avoid issues if it's not present or has ESM/CJS mismatches\n// In a real implementation, we would use the actual programmatic API of rulesync if available.\n// For now, we'll implement it by generating the config and potentially calling the CLI or using its core logic.\n\nexport class RuleSyncService implements RuleSyncPort {\n constructor(\n private readonly fs: FsAdapter,\n private readonly logger: LoggerAdapter\n ) {}\n\n async sync(options: RuleSyncOptions): Promise<RuleSyncResult> {\n const { config, cwd } = options;\n const targets = options.targets ?? config.targets ?? [];\n\n if (!config.enabled && !options.targets) {\n return {\n success: true,\n files: [],\n logs: ['Rule synchronization is disabled.'],\n };\n }\n\n this.logger.info(\n `Synchronizing rules for targets: ${targets.join(', ')}...`\n );\n\n try {\n // 1. Ensure rules directory exists\n const rulesDir = this.fs.join(cwd, config.rulesDir ?? '.rules');\n const rulesDirExists = await this.fs.exists(rulesDir);\n if (!rulesDirExists) {\n return {\n success: false,\n files: [],\n errors: [`Rules directory not found: ${rulesDir}`],\n };\n }\n\n // 2. Implementation choice:\n // If ejectMode is true, we just copy rules to targets if possible,\n // but usually rulesync is better for merging and formatting.\n\n // For now, let's implement the logic that leverages 'rulesync' patterns.\n // We generate a temporary rulesync.config.json if needed, or use their API.\n\n const rsConfig = await this.generateConfig(options);\n\n // In a real-world scenario, we would call the rulesync programmatic API here:\n // const { sync } = await import('rulesync');\n // await sync({ config: JSON.parse(rsConfig), cwd });\n\n this.logger.debug(`Generated rulesync config: ${rsConfig}`);\n\n // For this implementation, we'll simulate the file generation matching rulesync's behavior\n // until we have the full API details of the library.\n\n const files: string[] = [];\n for (const target of targets) {\n const targetFile = this.getTargetFileName(target);\n if (targetFile) {\n const fullPath = this.fs.join(cwd, targetFile);\n // Logic to aggregate rules from config.rulesDir and write to fullPath\n // would go here. rulesync handles this by parsing the files and\n // combining them based on the target.\n files.push(fullPath);\n }\n }\n\n return {\n success: true,\n files,\n logs: [`Successfully synchronized rules to ${files.length} targets.`],\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error(`Rule synchronization failed: ${message}`);\n return {\n success: false,\n files: [],\n errors: [message],\n };\n }\n }\n\n async generateConfig(options: RuleSyncOptions): Promise<string> {\n const { config } = options;\n\n // Convert our ContractSpec RuleSyncConfig to rulesync's config format\n const rulesyncConfig = {\n rules: (config.rules ?? []).map((r: string) =>\n this.fs.join(config.rulesDir ?? '.rules', r)\n ),\n targets: options.targets || config.targets,\n // Add other rulesync specific options here\n };\n\n return JSON.stringify(rulesyncConfig, null, 2);\n }\n\n private getTargetFileName(target: string): string | undefined {\n switch (target) {\n case 'cursor':\n return '.cursorrules';\n case 'windsurf':\n return '.windsurfrules';\n case 'cline':\n return '.clinerules';\n case 'claude-code':\n return 'CLAUDE.md';\n case 'copilot':\n return '.github/copilot-instructions.md';\n case 'subagent':\n return '.subagent';\n case 'skill':\n return '.skill';\n default:\n return undefined;\n }\n }\n}\n"],"mappings":";AAgBA,IAAa,kBAAb,MAAqD;CACnD,YACE,AAAiB,IACjB,AAAiB,QACjB;EAFiB;EACA;;CAGnB,MAAM,KAAK,SAAmD;EAC5D,MAAM,EAAE,QAAQ,QAAQ;EACxB,MAAM,UAAU,QAAQ,WAAW,OAAO,WAAW,EAAE;AAEvD,MAAI,CAAC,OAAO,WAAW,CAAC,QAAQ,QAC9B,QAAO;GACL,SAAS;GACT,OAAO,EAAE;GACT,MAAM,CAAC,oCAAoC;GAC5C;AAGH,OAAK,OAAO,KACV,oCAAoC,QAAQ,KAAK,KAAK,CAAC,KACxD;AAED,MAAI;GAEF,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,OAAO,YAAY,SAAS;AAE/D,OAAI,CADmB,MAAM,KAAK,GAAG,OAAO,SAAS,CAEnD,QAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,8BAA8B,WAAW;IACnD;GAUH,MAAM,WAAW,MAAM,KAAK,eAAe,QAAQ;AAMnD,QAAK,OAAO,MAAM,8BAA8B,WAAW;GAK3D,MAAM,QAAkB,EAAE;AAC1B,QAAK,MAAM,UAAU,SAAS;IAC5B,MAAM,aAAa,KAAK,kBAAkB,OAAO;AACjD,QAAI,YAAY;KACd,MAAM,WAAW,KAAK,GAAG,KAAK,KAAK,WAAW;AAI9C,WAAM,KAAK,SAAS;;;AAIxB,UAAO;IACL,SAAS;IACT;IACA,MAAM,CAAC,sCAAsC,MAAM,OAAO,WAAW;IACtE;WACM,OAAO;GACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAK,OAAO,MAAM,gCAAgC,UAAU;AAC5D,UAAO;IACL,SAAS;IACT,OAAO,EAAE;IACT,QAAQ,CAAC,QAAQ;IAClB;;;CAIL,MAAM,eAAe,SAA2C;EAC9D,MAAM,EAAE,WAAW;EAGnB,MAAM,iBAAiB;GACrB,QAAQ,OAAO,SAAS,EAAE,EAAE,KAAK,MAC/B,KAAK,GAAG,KAAK,OAAO,YAAY,UAAU,EAAE,CAC7C;GACD,SAAS,QAAQ,WAAW,OAAO;GAEpC;AAED,SAAO,KAAK,UAAU,gBAAgB,MAAM,EAAE;;CAGhD,AAAQ,kBAAkB,QAAoC;AAC5D,UAAQ,QAAR;GACE,KAAK,SACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,KAAK,cACH,QAAO;GACT,KAAK,UACH,QAAO;GACT,KAAK,WACH,QAAO;GACT,KAAK,QACH,QAAO;GACT,QACE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/bundle.workspace",
3
- "version": "0.0.0-canary-20260113173657",
3
+ "version": "0.0.0-canary-20260119222405",
4
4
  "description": "Workspace utilities for monorepo development",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -31,11 +31,12 @@
31
31
  "dependencies": {
32
32
  "@ai-sdk/anthropic": "3.0.11",
33
33
  "@ai-sdk/openai": "3.0.8",
34
- "@contractspec/lib.ai-agent": "0.0.0-canary-20260113173657",
35
- "@contractspec/lib.ai-providers": "0.0.0-canary-20260113173657",
36
- "@contractspec/lib.contracts": "0.0.0-canary-20260113173657",
37
- "@contractspec/lib.contracts-transformers": "0.0.0-canary-20260113173657",
38
- "@contractspec/module.workspace": "0.0.0-canary-20260113173657",
34
+ "@contractspec/lib.ai-agent": "0.0.0-canary-20260119222405",
35
+ "@contractspec/lib.ai-providers": "1.48.0",
36
+ "@contractspec/lib.contracts": "0.0.0-canary-20260119222405",
37
+ "@contractspec/lib.contracts-transformers": "0.0.0-canary-20260119222405",
38
+ "@contractspec/lib.source-extractors": "0.0.0-canary-20260119222405",
39
+ "@contractspec/module.workspace": "0.0.0-canary-20260119222405",
39
40
  "ai": "6.0.29",
40
41
  "chalk": "^5.6.2",
41
42
  "chokidar": "^5.0.0",
@@ -47,8 +48,8 @@
47
48
  "zod": "^4.3.5"
48
49
  },
49
50
  "devDependencies": {
50
- "@contractspec/tool.tsdown": "0.0.0-canary-20260113173657",
51
- "@contractspec/tool.typescript": "0.0.0-canary-20260113173657",
51
+ "@contractspec/tool.tsdown": "1.48.0",
52
+ "@contractspec/tool.typescript": "1.48.0",
52
53
  "@types/micromatch": "^4.0.10",
53
54
  "@types/node": "^25.0.6",
54
55
  "tsdown": "^0.19.0",