memor-code-cli 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/IntentionalStructure/index.d.ts +13 -0
- package/dist/IntentionalStructure/index.d.ts.map +1 -0
- package/dist/IntentionalStructure/index.js +46 -0
- package/dist/IntentionalStructure/index.js.map +1 -0
- package/dist/IntentionalStructure/parseCompose.d.ts +13 -0
- package/dist/IntentionalStructure/parseCompose.d.ts.map +1 -0
- package/dist/IntentionalStructure/parseCompose.js +234 -0
- package/dist/IntentionalStructure/parseCompose.js.map +1 -0
- package/dist/IntentionalStructure/parseDeployConfigs.d.ts +7 -0
- package/dist/IntentionalStructure/parseDeployConfigs.d.ts.map +1 -0
- package/dist/IntentionalStructure/parseDeployConfigs.js +168 -0
- package/dist/IntentionalStructure/parseDeployConfigs.js.map +1 -0
- package/dist/IntentionalStructure/parseEnvWiring.d.ts +7 -0
- package/dist/IntentionalStructure/parseEnvWiring.d.ts.map +1 -0
- package/dist/IntentionalStructure/parseEnvWiring.js +159 -0
- package/dist/IntentionalStructure/parseEnvWiring.js.map +1 -0
- package/dist/IntentionalStructure/parseWorkspaces.d.ts +8 -0
- package/dist/IntentionalStructure/parseWorkspaces.d.ts.map +1 -0
- package/dist/IntentionalStructure/parseWorkspaces.js +179 -0
- package/dist/IntentionalStructure/parseWorkspaces.js.map +1 -0
- package/dist/IntentionalStructure/types.d.ts +34 -0
- package/dist/IntentionalStructure/types.d.ts.map +1 -0
- package/dist/IntentionalStructure/types.js +8 -0
- package/dist/IntentionalStructure/types.js.map +1 -0
- package/dist/RepoTypeDetection/applyRepoModeConsistency.d.ts +11 -0
- package/dist/RepoTypeDetection/applyRepoModeConsistency.d.ts.map +1 -0
- package/dist/RepoTypeDetection/applyRepoModeConsistency.js +53 -0
- package/dist/RepoTypeDetection/applyRepoModeConsistency.js.map +1 -0
- package/dist/RepoTypeDetection/detectAppArchetype.d.ts +12 -0
- package/dist/RepoTypeDetection/detectAppArchetype.d.ts.map +1 -0
- package/dist/RepoTypeDetection/detectAppArchetype.js +162 -0
- package/dist/RepoTypeDetection/detectAppArchetype.js.map +1 -0
- package/dist/RepoTypeDetection/detectPackageArchetype.d.ts +10 -0
- package/dist/RepoTypeDetection/detectPackageArchetype.d.ts.map +1 -0
- package/dist/RepoTypeDetection/detectPackageArchetype.js +149 -0
- package/dist/RepoTypeDetection/detectPackageArchetype.js.map +1 -0
- package/dist/RepoTypeDetection/detectRepoCenterSystems.d.ts +11 -0
- package/dist/RepoTypeDetection/detectRepoCenterSystems.d.ts.map +1 -0
- package/dist/RepoTypeDetection/detectRepoCenterSystems.js +123 -0
- package/dist/RepoTypeDetection/detectRepoCenterSystems.js.map +1 -0
- package/dist/RepoTypeDetection/detectRepoMode.d.ts +16 -0
- package/dist/RepoTypeDetection/detectRepoMode.d.ts.map +1 -0
- package/dist/RepoTypeDetection/detectRepoMode.js +338 -0
- package/dist/RepoTypeDetection/detectRepoMode.js.map +1 -0
- package/dist/RepoTypeDetection/detectRepoSignals.d.ts +13 -0
- package/dist/RepoTypeDetection/detectRepoSignals.d.ts.map +1 -0
- package/dist/RepoTypeDetection/detectRepoSignals.js +451 -0
- package/dist/RepoTypeDetection/detectRepoSignals.js.map +1 -0
- package/dist/RepoTypeDetection/inferSupportRole.d.ts +8 -0
- package/dist/RepoTypeDetection/inferSupportRole.d.ts.map +1 -0
- package/dist/RepoTypeDetection/inferSupportRole.js +177 -0
- package/dist/RepoTypeDetection/inferSupportRole.js.map +1 -0
- package/dist/RuntimeInference/detectEnvConsumers.d.ts +7 -0
- package/dist/RuntimeInference/detectEnvConsumers.d.ts.map +1 -0
- package/dist/RuntimeInference/detectEnvConsumers.js +108 -0
- package/dist/RuntimeInference/detectEnvConsumers.js.map +1 -0
- package/dist/RuntimeInference/detectHttpEdges.d.ts +4 -0
- package/dist/RuntimeInference/detectHttpEdges.d.ts.map +1 -0
- package/dist/RuntimeInference/detectHttpEdges.js +146 -0
- package/dist/RuntimeInference/detectHttpEdges.js.map +1 -0
- package/dist/RuntimeInference/detectOrmConsumers.d.ts +5 -0
- package/dist/RuntimeInference/detectOrmConsumers.d.ts.map +1 -0
- package/dist/RuntimeInference/detectOrmConsumers.js +117 -0
- package/dist/RuntimeInference/detectOrmConsumers.js.map +1 -0
- package/dist/RuntimeInference/detectProxyRewrites.d.ts +5 -0
- package/dist/RuntimeInference/detectProxyRewrites.d.ts.map +1 -0
- package/dist/RuntimeInference/detectProxyRewrites.js +137 -0
- package/dist/RuntimeInference/detectProxyRewrites.js.map +1 -0
- package/dist/RuntimeInference/detectTrpcEdges.d.ts +4 -0
- package/dist/RuntimeInference/detectTrpcEdges.d.ts.map +1 -0
- package/dist/RuntimeInference/detectTrpcEdges.js +137 -0
- package/dist/RuntimeInference/detectTrpcEdges.js.map +1 -0
- package/dist/RuntimeInference/index.d.ts +17 -0
- package/dist/RuntimeInference/index.d.ts.map +1 -0
- package/dist/RuntimeInference/index.js +32 -0
- package/dist/RuntimeInference/index.js.map +1 -0
- package/dist/RuntimeInference/types.d.ts +8 -0
- package/dist/RuntimeInference/types.d.ts.map +1 -0
- package/dist/RuntimeInference/types.js +3 -0
- package/dist/RuntimeInference/types.js.map +1 -0
- package/dist/SystemSynthesis/index.d.ts +27 -0
- package/dist/SystemSynthesis/index.d.ts.map +1 -0
- package/dist/SystemSynthesis/index.js +31 -0
- package/dist/SystemSynthesis/index.js.map +1 -0
- package/dist/SystemSynthesis/mergeLayerOutputs.d.ts +13 -0
- package/dist/SystemSynthesis/mergeLayerOutputs.d.ts.map +1 -0
- package/dist/SystemSynthesis/mergeLayerOutputs.js +220 -0
- package/dist/SystemSynthesis/mergeLayerOutputs.js.map +1 -0
- package/dist/SystemSynthesis/stampDeterministic.d.ts +11 -0
- package/dist/SystemSynthesis/stampDeterministic.d.ts.map +1 -0
- package/dist/SystemSynthesis/stampDeterministic.js +177 -0
- package/dist/SystemSynthesis/stampDeterministic.js.map +1 -0
- package/dist/SystemSynthesis/synthesize.d.ts +15 -0
- package/dist/SystemSynthesis/synthesize.d.ts.map +1 -0
- package/dist/SystemSynthesis/synthesize.js +258 -0
- package/dist/SystemSynthesis/synthesize.js.map +1 -0
- package/dist/SystemSynthesis/types.d.ts +110 -0
- package/dist/SystemSynthesis/types.d.ts.map +1 -0
- package/dist/SystemSynthesis/types.js +12 -0
- package/dist/SystemSynthesis/types.js.map +1 -0
- package/dist/amGeneration/buildFlowGraph.d.ts +39 -0
- package/dist/amGeneration/buildFlowGraph.d.ts.map +1 -0
- package/dist/amGeneration/buildFlowGraph.js +643 -0
- package/dist/amGeneration/buildFlowGraph.js.map +1 -0
- package/dist/amGeneration/enrichAMEdges.d.ts +16 -0
- package/dist/amGeneration/enrichAMEdges.d.ts.map +1 -0
- package/dist/amGeneration/enrichAMEdges.js +291 -0
- package/dist/amGeneration/enrichAMEdges.js.map +1 -0
- package/dist/amGeneration/generateAM.d.ts +23 -0
- package/dist/amGeneration/generateAM.d.ts.map +1 -0
- package/dist/amGeneration/generateAM.js +131 -0
- package/dist/amGeneration/generateAM.js.map +1 -0
- package/dist/amGeneration/generateAMForRepo.d.ts +6 -0
- package/dist/amGeneration/generateAMForRepo.d.ts.map +1 -0
- package/dist/amGeneration/generateAMForRepo.js +130 -0
- package/dist/amGeneration/generateAMForRepo.js.map +1 -0
- package/dist/amGeneration/generateFlows.d.ts +27 -0
- package/dist/amGeneration/generateFlows.d.ts.map +1 -0
- package/dist/amGeneration/generateFlows.js +320 -0
- package/dist/amGeneration/generateFlows.js.map +1 -0
- package/dist/amGeneration/promptBuilder.d.ts +24 -0
- package/dist/amGeneration/promptBuilder.d.ts.map +1 -0
- package/dist/amGeneration/promptBuilder.js +299 -0
- package/dist/amGeneration/promptBuilder.js.map +1 -0
- package/dist/amGeneration/selectStrategicFiles.d.ts +42 -0
- package/dist/amGeneration/selectStrategicFiles.d.ts.map +1 -0
- package/dist/amGeneration/selectStrategicFiles.js +672 -0
- package/dist/amGeneration/selectStrategicFiles.js.map +1 -0
- package/dist/amGeneration/types.d.ts +83 -0
- package/dist/amGeneration/types.d.ts.map +1 -0
- package/dist/amGeneration/types.js +9 -0
- package/dist/amGeneration/types.js.map +1 -0
- package/dist/amSections.d.ts +29 -0
- package/dist/amSections.d.ts.map +1 -0
- package/dist/amSections.js +424 -0
- package/dist/amSections.js.map +1 -0
- package/dist/analysis/analysisCache.d.ts +4 -0
- package/dist/analysis/analysisCache.d.ts.map +1 -0
- package/dist/analysis/analysisCache.js +92 -0
- package/dist/analysis/analysisCache.js.map +1 -0
- package/dist/analysis/buildBranchStory.d.ts +95 -0
- package/dist/analysis/buildBranchStory.d.ts.map +1 -0
- package/dist/analysis/buildBranchStory.js +1264 -0
- package/dist/analysis/buildBranchStory.js.map +1 -0
- package/dist/analysis/buildDetailedFileXRay.d.ts +49 -0
- package/dist/analysis/buildDetailedFileXRay.d.ts.map +1 -0
- package/dist/analysis/buildDetailedFileXRay.js +607 -0
- package/dist/analysis/buildDetailedFileXRay.js.map +1 -0
- package/dist/analysis/buildFileXRay.d.ts +35 -0
- package/dist/analysis/buildFileXRay.d.ts.map +1 -0
- package/dist/analysis/buildFileXRay.js +305 -0
- package/dist/analysis/buildFileXRay.js.map +1 -0
- package/dist/analysis/classifySilentKiller.d.ts +14 -0
- package/dist/analysis/classifySilentKiller.d.ts.map +1 -0
- package/dist/analysis/classifySilentKiller.js +235 -0
- package/dist/analysis/classifySilentKiller.js.map +1 -0
- package/dist/analysis/diffChunks.d.ts +21 -0
- package/dist/analysis/diffChunks.d.ts.map +1 -0
- package/dist/analysis/diffChunks.js +302 -0
- package/dist/analysis/diffChunks.js.map +1 -0
- package/dist/analysis/extractRouteMap.d.ts +49 -0
- package/dist/analysis/extractRouteMap.d.ts.map +1 -0
- package/dist/analysis/extractRouteMap.js +354 -0
- package/dist/analysis/extractRouteMap.js.map +1 -0
- package/dist/analysis/generateFileInsight.d.ts +19 -0
- package/dist/analysis/generateFileInsight.d.ts.map +1 -0
- package/dist/analysis/generateFileInsight.js +103 -0
- package/dist/analysis/generateFileInsight.js.map +1 -0
- package/dist/analysis/llmXRay.d.ts +39 -0
- package/dist/analysis/llmXRay.d.ts.map +1 -0
- package/dist/analysis/llmXRay.js +208 -0
- package/dist/analysis/llmXRay.js.map +1 -0
- package/dist/analysis/simulateFailure.d.ts +44 -0
- package/dist/analysis/simulateFailure.d.ts.map +1 -0
- package/dist/analysis/simulateFailure.js +407 -0
- package/dist/analysis/simulateFailure.js.map +1 -0
- package/dist/anthropic.d.ts +3 -0
- package/dist/anthropic.d.ts.map +1 -0
- package/dist/anthropic.js +16 -0
- package/dist/anthropic.js.map +1 -0
- package/dist/app/buildAppPage.d.ts +34 -0
- package/dist/app/buildAppPage.d.ts.map +1 -0
- package/dist/app/buildAppPage.js +3085 -0
- package/dist/app/buildAppPage.js.map +1 -0
- package/dist/app-bundle.js +122 -0
- package/dist/buildAppData.d.ts +3 -0
- package/dist/buildAppData.d.ts.map +1 -0
- package/dist/buildAppData.js +207 -0
- package/dist/buildAppData.js.map +1 -0
- package/dist/builders/analyzeRepo.d.ts +25 -0
- package/dist/builders/analyzeRepo.d.ts.map +1 -0
- package/dist/builders/analyzeRepo.js +873 -0
- package/dist/builders/analyzeRepo.js.map +1 -0
- package/dist/builders/buildSystemConnections.d.ts +3 -0
- package/dist/builders/buildSystemConnections.d.ts.map +1 -0
- package/dist/builders/buildSystemConnections.js +388 -0
- package/dist/builders/buildSystemConnections.js.map +1 -0
- package/dist/builders/buildTextSummary.d.ts +61 -0
- package/dist/builders/buildTextSummary.d.ts.map +1 -0
- package/dist/builders/buildTextSummary.js +178 -0
- package/dist/builders/buildTextSummary.js.map +1 -0
- package/dist/builders/deriveRecommendedStartPath.d.ts +11 -0
- package/dist/builders/deriveRecommendedStartPath.d.ts.map +1 -0
- package/dist/builders/deriveRecommendedStartPath.js +140 -0
- package/dist/builders/deriveRecommendedStartPath.js.map +1 -0
- package/dist/builders/deriveRuntimeRole.d.ts +4 -0
- package/dist/builders/deriveRuntimeRole.d.ts.map +1 -0
- package/dist/builders/deriveRuntimeRole.js +30 -0
- package/dist/builders/deriveRuntimeRole.js.map +1 -0
- package/dist/builders/detectRunCommands.d.ts +16 -0
- package/dist/builders/detectRunCommands.d.ts.map +1 -0
- package/dist/builders/detectRunCommands.js +285 -0
- package/dist/builders/detectRunCommands.js.map +1 -0
- package/dist/builders/generateSystemNarrative.d.ts +12 -0
- package/dist/builders/generateSystemNarrative.d.ts.map +1 -0
- package/dist/builders/generateSystemNarrative.js +474 -0
- package/dist/builders/generateSystemNarrative.js.map +1 -0
- package/dist/builders/gitLogParser.d.ts +15 -0
- package/dist/builders/gitLogParser.d.ts.map +1 -0
- package/dist/builders/gitLogParser.js +116 -0
- package/dist/builders/gitLogParser.js.map +1 -0
- package/dist/builders/readRepoContext.d.ts +30 -0
- package/dist/builders/readRepoContext.d.ts.map +1 -0
- package/dist/builders/readRepoContext.js +323 -0
- package/dist/builders/readRepoContext.js.map +1 -0
- package/dist/builders/readSystemReadme.d.ts +39 -0
- package/dist/builders/readSystemReadme.d.ts.map +1 -0
- package/dist/builders/readSystemReadme.js +133 -0
- package/dist/builders/readSystemReadme.js.map +1 -0
- package/dist/builders/systemRanking.d.ts +24 -0
- package/dist/builders/systemRanking.d.ts.map +1 -0
- package/dist/builders/systemRanking.js +153 -0
- package/dist/builders/systemRanking.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +170 -0
- package/dist/cli.js.map +1 -0
- package/dist/detectors/applyRunnableConfidenceGate.d.ts +8 -0
- package/dist/detectors/applyRunnableConfidenceGate.d.ts.map +1 -0
- package/dist/detectors/applyRunnableConfidenceGate.js +166 -0
- package/dist/detectors/applyRunnableConfidenceGate.js.map +1 -0
- package/dist/detectors/classifySystemType.d.ts +17 -0
- package/dist/detectors/classifySystemType.d.ts.map +1 -0
- package/dist/detectors/classifySystemType.js +460 -0
- package/dist/detectors/classifySystemType.js.map +1 -0
- package/dist/detectors/detectAppInternalUnits.d.ts +20 -0
- package/dist/detectors/detectAppInternalUnits.d.ts.map +1 -0
- package/dist/detectors/detectAppInternalUnits.js +454 -0
- package/dist/detectors/detectAppInternalUnits.js.map +1 -0
- package/dist/detectors/detectBlocks.d.ts +6 -0
- package/dist/detectors/detectBlocks.d.ts.map +1 -0
- package/dist/detectors/detectBlocks.js +354 -0
- package/dist/detectors/detectBlocks.js.map +1 -0
- package/dist/detectors/detectComposeServices.d.ts +23 -0
- package/dist/detectors/detectComposeServices.d.ts.map +1 -0
- package/dist/detectors/detectComposeServices.js +255 -0
- package/dist/detectors/detectComposeServices.js.map +1 -0
- package/dist/detectors/detectEntryPoints.d.ts +6 -0
- package/dist/detectors/detectEntryPoints.d.ts.map +1 -0
- package/dist/detectors/detectEntryPoints.js +376 -0
- package/dist/detectors/detectEntryPoints.js.map +1 -0
- package/dist/detectors/detectSubsystems.d.ts +6 -0
- package/dist/detectors/detectSubsystems.d.ts.map +1 -0
- package/dist/detectors/detectSubsystems.js +376 -0
- package/dist/detectors/detectSubsystems.js.map +1 -0
- package/dist/detectors/detectSystemCandidates.d.ts +3 -0
- package/dist/detectors/detectSystemCandidates.d.ts.map +1 -0
- package/dist/detectors/detectSystemCandidates.js +577 -0
- package/dist/detectors/detectSystemCandidates.js.map +1 -0
- package/dist/devWatcher.d.ts +14 -0
- package/dist/devWatcher.d.ts.map +1 -0
- package/dist/devWatcher.js +96 -0
- package/dist/devWatcher.js.map +1 -0
- package/dist/graph/buildCodebaseGraph.d.ts +3 -0
- package/dist/graph/buildCodebaseGraph.d.ts.map +1 -0
- package/dist/graph/buildCodebaseGraph.js +602 -0
- package/dist/graph/buildCodebaseGraph.js.map +1 -0
- package/dist/graph/buildLLMPayload.d.ts +89 -0
- package/dist/graph/buildLLMPayload.d.ts.map +1 -0
- package/dist/graph/buildLLMPayload.js +715 -0
- package/dist/graph/buildLLMPayload.js.map +1 -0
- package/dist/graph/callLLM.d.ts +16 -0
- package/dist/graph/callLLM.d.ts.map +1 -0
- package/dist/graph/callLLM.js +274 -0
- package/dist/graph/callLLM.js.map +1 -0
- package/dist/graph/types.d.ts +76 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +5 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/walkExports.d.ts +2 -0
- package/dist/graph/walkExports.d.ts.map +1 -0
- package/dist/graph/walkExports.js +172 -0
- package/dist/graph/walkExports.js.map +1 -0
- package/dist/heuristics/file-patterns.json +325 -0
- package/dist/heuristics/known-packages.json +1022 -0
- package/dist/heuristics/loader.d.ts +121 -0
- package/dist/heuristics/loader.d.ts.map +1 -0
- package/dist/heuristics/loader.js +196 -0
- package/dist/heuristics/loader.js.map +1 -0
- package/dist/heuristics/repo-mode-signals.json +248 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +356 -0
- package/dist/mcp.js.map +1 -0
- package/dist/scanner/buildImportGraph.d.ts +23 -0
- package/dist/scanner/buildImportGraph.d.ts.map +1 -0
- package/dist/scanner/buildImportGraph.js +186 -0
- package/dist/scanner/buildImportGraph.js.map +1 -0
- package/dist/scanner/detectDBOps.d.ts +21 -0
- package/dist/scanner/detectDBOps.d.ts.map +1 -0
- package/dist/scanner/detectDBOps.js +346 -0
- package/dist/scanner/detectDBOps.js.map +1 -0
- package/dist/scanner/detectOutbound.d.ts +6 -0
- package/dist/scanner/detectOutbound.d.ts.map +1 -0
- package/dist/scanner/detectOutbound.js +101 -0
- package/dist/scanner/detectOutbound.js.map +1 -0
- package/dist/scanner/detectRepoPurpose.d.ts +19 -0
- package/dist/scanner/detectRepoPurpose.d.ts.map +1 -0
- package/dist/scanner/detectRepoPurpose.js +335 -0
- package/dist/scanner/detectRepoPurpose.js.map +1 -0
- package/dist/scanner/detectRoutes.d.ts +22 -0
- package/dist/scanner/detectRoutes.d.ts.map +1 -0
- package/dist/scanner/detectRoutes.js +406 -0
- package/dist/scanner/detectRoutes.js.map +1 -0
- package/dist/scanner/filterNoise.d.ts +4 -0
- package/dist/scanner/filterNoise.d.ts.map +1 -0
- package/dist/scanner/filterNoise.js +95 -0
- package/dist/scanner/filterNoise.js.map +1 -0
- package/dist/scanner/loadTsAliases.d.ts +20 -0
- package/dist/scanner/loadTsAliases.d.ts.map +1 -0
- package/dist/scanner/loadTsAliases.js +135 -0
- package/dist/scanner/loadTsAliases.js.map +1 -0
- package/dist/scanner/routeHandlers.d.ts +15 -0
- package/dist/scanner/routeHandlers.d.ts.map +1 -0
- package/dist/scanner/routeHandlers.js +154 -0
- package/dist/scanner/routeHandlers.js.map +1 -0
- package/dist/scanner/scanRepo.d.ts +10 -0
- package/dist/scanner/scanRepo.d.ts.map +1 -0
- package/dist/scanner/scanRepo.js +165 -0
- package/dist/scanner/scanRepo.js.map +1 -0
- package/dist/scanner/walkImports.d.ts +14 -0
- package/dist/scanner/walkImports.d.ts.map +1 -0
- package/dist/scanner/walkImports.js +162 -0
- package/dist/scanner/walkImports.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +956 -0
- package/dist/server.js.map +1 -0
- package/dist/session/diff.d.ts +4 -0
- package/dist/session/diff.d.ts.map +1 -0
- package/dist/session/diff.js +150 -0
- package/dist/session/diff.js.map +1 -0
- package/dist/session/snapshot.d.ts +5 -0
- package/dist/session/snapshot.d.ts.map +1 -0
- package/dist/session/snapshot.js +114 -0
- package/dist/session/snapshot.js.map +1 -0
- package/dist/session/store.d.ts +8 -0
- package/dist/session/store.d.ts.map +1 -0
- package/dist/session/store.js +101 -0
- package/dist/session/store.js.map +1 -0
- package/dist/session/types.d.ts +46 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +4 -0
- package/dist/session/types.js.map +1 -0
- package/dist/types.d.ts +350 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/file.d.ts +5 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +76 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/path.d.ts +7 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +62 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/text.d.ts +5 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +29 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/viewBuilders/buildSystemFolders.d.ts +39 -0
- package/dist/viewBuilders/buildSystemFolders.d.ts.map +1 -0
- package/dist/viewBuilders/buildSystemFolders.js +198 -0
- package/dist/viewBuilders/buildSystemFolders.js.map +1 -0
- package/dist/watcher/repoWatcher.d.ts +17 -0
- package/dist/watcher/repoWatcher.d.ts.map +1 -0
- package/dist/watcher/repoWatcher.js +87 -0
- package/dist/watcher/repoWatcher.js.map +1 -0
- package/package.json +102 -0
- package/public/memor_logo.svg +18 -0
- package/public/memor_transparent_logo.svg +25 -0
- package/public/tIcons/bun.svg +1 -0
- package/public/tIcons/css.svg +1 -0
- package/public/tIcons/docker.svg +3 -0
- package/public/tIcons/expressjs.svg +1 -0
- package/public/tIcons/html5.svg +6 -0
- package/public/tIcons/javascript.svg +1 -0
- package/public/tIcons/jest.svg +4 -0
- package/public/tIcons/json.svg +1 -0
- package/public/tIcons/markdown-light.svg +1 -0
- package/public/tIcons/nestjs.svg +1 -0
- package/public/tIcons/nextjs_icon_dark.svg +1 -0
- package/public/tIcons/npm.svg +1 -0
- package/public/tIcons/pnpm.svg +1 -0
- package/public/tIcons/prisma.svg +1 -0
- package/public/tIcons/react_dark.svg +11 -0
- package/public/tIcons/supabase.svg +15 -0
- package/public/tIcons/tailwindcss.svg +1 -0
- package/public/tIcons/turborepo-icon-light.svg +1 -0
- package/public/tIcons/typescript.svg +1 -0
- package/public/tIcons/vite.svg +1 -0
- package/public/tIcons/yarn.svg +1 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,956 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.startAppServer = startAppServer;
|
|
37
|
+
const http = __importStar(require("http"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const url = __importStar(require("url"));
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const buildFileXRay_1 = require("./analysis/buildFileXRay");
|
|
43
|
+
const llmXRay_1 = require("./analysis/llmXRay");
|
|
44
|
+
const buildDetailedFileXRay_1 = require("./analysis/buildDetailedFileXRay");
|
|
45
|
+
const repoWatcher_1 = require("./watcher/repoWatcher");
|
|
46
|
+
const generateAMForRepo_1 = require("./amGeneration/generateAMForRepo");
|
|
47
|
+
const enrichAMEdges_1 = require("./amGeneration/enrichAMEdges");
|
|
48
|
+
const selectStrategicFiles_1 = require("./amGeneration/selectStrategicFiles");
|
|
49
|
+
const generateFileInsight_1 = require("./analysis/generateFileInsight");
|
|
50
|
+
const extractRouteMap_1 = require("./analysis/extractRouteMap");
|
|
51
|
+
const generateFlows_1 = require("./amGeneration/generateFlows");
|
|
52
|
+
const buildFlowGraph_1 = require("./amGeneration/buildFlowGraph");
|
|
53
|
+
const buildBranchStory_1 = require("./analysis/buildBranchStory");
|
|
54
|
+
// If path is a directory, resolve to its index file so X-Ray doesn't fail on folders.
|
|
55
|
+
function resolveFilePath(absPath) {
|
|
56
|
+
try {
|
|
57
|
+
if (fs.statSync(absPath).isDirectory()) {
|
|
58
|
+
for (const candidate of ["index.ts", "index.tsx", "index.js", "index.mjs"]) {
|
|
59
|
+
const resolved = path.join(absPath, candidate);
|
|
60
|
+
if (fs.existsSync(resolved))
|
|
61
|
+
return resolved;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch { /* path doesn't exist — let downstream handle it */ }
|
|
66
|
+
return absPath;
|
|
67
|
+
}
|
|
68
|
+
// Runtime API key — loaded from ~/.memor/config.json on start, updated via /api/set-key
|
|
69
|
+
let runtimeApiKey;
|
|
70
|
+
// No bundled key — AI calls go through api.memor.dev when the user has no personal key.
|
|
71
|
+
const CONFIG_PATH = path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".memor", "config.json");
|
|
72
|
+
function loadSavedKey() {
|
|
73
|
+
try {
|
|
74
|
+
const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
|
|
75
|
+
if (typeof cfg.apiKey === "string" && cfg.apiKey.length > 10) {
|
|
76
|
+
runtimeApiKey = cfg.apiKey;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch { /* no config yet — fine */ }
|
|
80
|
+
}
|
|
81
|
+
function saveKey(key) {
|
|
82
|
+
try {
|
|
83
|
+
const dir = path.dirname(CONFIG_PATH);
|
|
84
|
+
if (!fs.existsSync(dir))
|
|
85
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
86
|
+
const existing = (() => {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify({ ...existing, apiKey: key }, null, 2), "utf8");
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore write errors */ }
|
|
97
|
+
}
|
|
98
|
+
loadSavedKey();
|
|
99
|
+
function getApiKey() {
|
|
100
|
+
return runtimeApiKey || process.env.ANTHROPIC_API_KEY || "memor-proxy";
|
|
101
|
+
}
|
|
102
|
+
function readBody(req) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
const chunks = [];
|
|
105
|
+
req.on("data", (c) => chunks.push(c));
|
|
106
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
107
|
+
req.on("error", reject);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function startAppServer(html, port, onReady, repoRoot) {
|
|
111
|
+
const server = http.createServer((req, res) => {
|
|
112
|
+
if (req.url === "/favicon.ico") {
|
|
113
|
+
res.writeHead(204);
|
|
114
|
+
res.end();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// ── /app-bundle.js — serve frontend bundle fresh from disk ───────────
|
|
118
|
+
if (req.url === "/app-bundle.js") {
|
|
119
|
+
res.setHeader("Cache-Control", "no-store");
|
|
120
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
121
|
+
const candidates = [
|
|
122
|
+
path.join(__dirname, "app-bundle.js"),
|
|
123
|
+
path.join(__dirname, "..", "dist", "app-bundle.js"),
|
|
124
|
+
];
|
|
125
|
+
for (const p of candidates) {
|
|
126
|
+
try {
|
|
127
|
+
res.writeHead(200);
|
|
128
|
+
res.end(fs.readFileSync(p, "utf-8"));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
catch { }
|
|
132
|
+
}
|
|
133
|
+
res.writeHead(404);
|
|
134
|
+
res.end("// bundle not found");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// ── /api/am — serve current architecture-map.json ────────────
|
|
138
|
+
if (req.url === "/api/am") {
|
|
139
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
140
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
141
|
+
if (!repoRoot) {
|
|
142
|
+
res.writeHead(503);
|
|
143
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
(async () => {
|
|
147
|
+
const amPath = path.join(repoRoot, ".memor", "architecture-map.json");
|
|
148
|
+
try {
|
|
149
|
+
const am = JSON.parse(fs.readFileSync(amPath, "utf8"));
|
|
150
|
+
// Attach evidence files to flows deterministically
|
|
151
|
+
if (am.flows?.length > 0) {
|
|
152
|
+
try {
|
|
153
|
+
const routeMap = (0, extractRouteMap_1.extractRouteMap)(repoRoot);
|
|
154
|
+
am.flows = (0, generateFlows_1.attachEvidenceFiles)(am.flows, routeMap, repoRoot);
|
|
155
|
+
}
|
|
156
|
+
catch { /* non-fatal */ }
|
|
157
|
+
}
|
|
158
|
+
// Strip key_files that don't exist on disk (LLM often hallucinates file paths)
|
|
159
|
+
if (am.systems?.length > 0) {
|
|
160
|
+
for (const sys of am.systems) {
|
|
161
|
+
if (Array.isArray(sys.key_files)) {
|
|
162
|
+
sys.key_files = sys.key_files.filter((f) => fs.existsSync(path.join(repoRoot, f)));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Enrich missing edges deterministically from key_file imports
|
|
167
|
+
try {
|
|
168
|
+
const manifests = await (0, selectStrategicFiles_1.readWorkspaceManifests)(repoRoot);
|
|
169
|
+
const enriched = (0, enrichAMEdges_1.enrichAMEdges)(am, repoRoot, manifests);
|
|
170
|
+
res.writeHead(200);
|
|
171
|
+
res.end(JSON.stringify(enriched));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
res.writeHead(200);
|
|
175
|
+
res.end(JSON.stringify(am));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
res.writeHead(404);
|
|
180
|
+
res.end(JSON.stringify({ error: "No architecture map generated yet" }));
|
|
181
|
+
}
|
|
182
|
+
})();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// ── /api/branch-story — git diff → spatial change graph ─────────────────
|
|
186
|
+
if (req.url?.startsWith("/api/branch-story")) {
|
|
187
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
188
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
189
|
+
res.setHeader("Cache-Control", "no-store");
|
|
190
|
+
if (!repoRoot) {
|
|
191
|
+
res.writeHead(503);
|
|
192
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const parsed = url.parse(req.url, true);
|
|
196
|
+
const base = parsed.query.base || "main"; // Target: what to diff against
|
|
197
|
+
const source = parsed.query.source || "working"; // Source: working tree or a branch
|
|
198
|
+
// Two-phase: ?enrich=1 runs the LLM comprehension layer (role/change/threads).
|
|
199
|
+
// Without it, the story is purely deterministic and returns at git-status speed.
|
|
200
|
+
const enrich = parsed.query.enrich === "1";
|
|
201
|
+
const apiKey = enrich ? getApiKey() : undefined;
|
|
202
|
+
let am = null;
|
|
203
|
+
try {
|
|
204
|
+
am = JSON.parse(fs.readFileSync(path.join(repoRoot, ".memor", "architecture-map.json"), "utf8"));
|
|
205
|
+
}
|
|
206
|
+
catch { }
|
|
207
|
+
(0, buildBranchStory_1.buildBranchStoryForSource)(repoRoot, base, apiKey, am, source)
|
|
208
|
+
.then(story => { res.writeHead(200); res.end(JSON.stringify(story)); })
|
|
209
|
+
.catch(e => { res.writeHead(500); res.end(JSON.stringify({ error: String(e) })); });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// ── /api/fetch — pull the latest remote refs so peer PR branches are current ──
|
|
213
|
+
if (req.url === "/api/fetch" && req.method === "POST") {
|
|
214
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
215
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
216
|
+
if (!repoRoot) {
|
|
217
|
+
res.writeHead(503);
|
|
218
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
// Read-only network op (updates remote-tracking refs; never touches the working tree).
|
|
223
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" fetch origin --prune`, { stdio: ["pipe", "pipe", "pipe"], timeout: 30000 });
|
|
224
|
+
res.writeHead(200);
|
|
225
|
+
res.end(JSON.stringify({ ok: true }));
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
res.writeHead(200);
|
|
229
|
+
res.end(JSON.stringify({ ok: false, error: String(e).slice(0, 200) }));
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// ── /api/branches — list local + remote branches for the Source/Target selectors ──
|
|
234
|
+
if (req.url?.startsWith("/api/branches")) {
|
|
235
|
+
const wantCounts = url.parse(req.url, true).query.counts === "1";
|
|
236
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
237
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
238
|
+
res.setHeader("Cache-Control", "no-store");
|
|
239
|
+
if (!repoRoot) {
|
|
240
|
+
res.writeHead(503);
|
|
241
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const current = (() => {
|
|
246
|
+
try {
|
|
247
|
+
return (0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --abbrev-ref HEAD`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return "";
|
|
251
|
+
}
|
|
252
|
+
})();
|
|
253
|
+
// The default branch we judge "merged" against (main, else master).
|
|
254
|
+
const defaultBranch = (() => {
|
|
255
|
+
for (const c of ["main", "master"]) {
|
|
256
|
+
try {
|
|
257
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --verify ${c}`, { stdio: "pipe" });
|
|
258
|
+
return c;
|
|
259
|
+
}
|
|
260
|
+
catch { }
|
|
261
|
+
}
|
|
262
|
+
return current || "main";
|
|
263
|
+
})();
|
|
264
|
+
// Branches with commits NOT in the default branch (ahead > 0) — the live/open ones.
|
|
265
|
+
// `--no-merged` is a single reachability check (fast, no per-branch loop).
|
|
266
|
+
const notMerged = new Set();
|
|
267
|
+
for (const flag of ["", "-r"]) {
|
|
268
|
+
try {
|
|
269
|
+
const out = (0, child_process_1.execSync)(`git -C "${repoRoot}" branch ${flag} --no-merged ${defaultBranch} --format="%(refname:short)"`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], maxBuffer: 2_000_000 }).trim();
|
|
270
|
+
for (const n of out.split("\n").filter(Boolean))
|
|
271
|
+
notMerged.add(n.replace(/^origin\//, "").trim());
|
|
272
|
+
}
|
|
273
|
+
catch { }
|
|
274
|
+
}
|
|
275
|
+
// name + committer date (epoch) for local and remote branches, newest first
|
|
276
|
+
const raw = (0, child_process_1.execSync)(`git -C "${repoRoot}" for-each-ref --sort=-committerdate --format="%(refname:short)|%(committerdate:unix)" refs/heads refs/remotes`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], maxBuffer: 2_000_000 }).trim();
|
|
277
|
+
const seen = new Set();
|
|
278
|
+
const branches = raw.split("\n").filter(Boolean).map(l => {
|
|
279
|
+
const [name, ts] = l.split("|");
|
|
280
|
+
const shortName = name.replace(/^origin\//, "");
|
|
281
|
+
// The default branch is the comparison base — never a valid Source. Force merged=true
|
|
282
|
+
// so it's hidden from Source (a stale local main can otherwise read as "not merged").
|
|
283
|
+
const merged = shortName === defaultBranch ? true : !notMerged.has(shortName);
|
|
284
|
+
return { name: shortName, raw: name, lastCommit: Number(ts) || 0, isCurrent: name === current, merged };
|
|
285
|
+
}).filter(b => {
|
|
286
|
+
if (b.raw.endsWith("/HEAD"))
|
|
287
|
+
return false; // skip origin/HEAD symref
|
|
288
|
+
if (b.name === "origin" || b.name === "HEAD")
|
|
289
|
+
return false; // phantom remote noise
|
|
290
|
+
if (seen.has(b.name))
|
|
291
|
+
return false; // dedupe local/remote of same name
|
|
292
|
+
seen.add(b.name);
|
|
293
|
+
return true;
|
|
294
|
+
});
|
|
295
|
+
// Optional: ahead-count vs the default branch, for the open (non-merged) branches only
|
|
296
|
+
// — used by the "Review a Pull Request" modal. Computed on demand (?counts=1) to keep
|
|
297
|
+
// the regular mount fast.
|
|
298
|
+
let out = branches;
|
|
299
|
+
if (wantCounts) {
|
|
300
|
+
// Count ahead vs the REMOTE default (origin/main) to match the actual review baseline,
|
|
301
|
+
// not a possibly-stale local main.
|
|
302
|
+
const tgt = (() => {
|
|
303
|
+
try {
|
|
304
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --verify origin/${defaultBranch}`, { stdio: "pipe" });
|
|
305
|
+
return `origin/${defaultBranch}`;
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
return defaultBranch;
|
|
309
|
+
}
|
|
310
|
+
})();
|
|
311
|
+
out = branches.map(b => {
|
|
312
|
+
if (b.merged)
|
|
313
|
+
return b;
|
|
314
|
+
try {
|
|
315
|
+
const n = (0, child_process_1.execSync)(`git -C "${repoRoot}" rev-list --count ${tgt}..${b.raw}`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
316
|
+
return { ...b, ahead: parseInt(n, 10) || 0 };
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return b;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
// When the remote refs were last fetched (FETCH_HEAD mtime) — drives "fetched Xm ago".
|
|
324
|
+
const fetchedAt = (() => {
|
|
325
|
+
try {
|
|
326
|
+
return Math.floor(fs.statSync(path.join(repoRoot, ".git", "FETCH_HEAD")).mtimeMs);
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
})();
|
|
332
|
+
res.writeHead(200);
|
|
333
|
+
res.end(JSON.stringify({ current, defaultBranch, fetchedAt, branches: out }));
|
|
334
|
+
}
|
|
335
|
+
catch (e) {
|
|
336
|
+
res.writeHead(200);
|
|
337
|
+
res.end(JSON.stringify({ current: "", branches: [] }));
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// ── /api/commit-log — commits between base..HEAD with per-commit file lists ─
|
|
342
|
+
if (req.url?.startsWith("/api/commit-log")) {
|
|
343
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
344
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
345
|
+
res.setHeader("Cache-Control", "no-store");
|
|
346
|
+
if (!repoRoot) {
|
|
347
|
+
res.writeHead(503);
|
|
348
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const parsed = url.parse(req.url, true);
|
|
352
|
+
const base = parsed.query.base || "main";
|
|
353
|
+
try {
|
|
354
|
+
// Single pass: pretty header lines interleaved with name-status file lines
|
|
355
|
+
const raw = (0, child_process_1.execSync)(`git -C "${repoRoot}" log ${base}..HEAD --pretty=format:">>C<<%H<<%s<<%an<<%ai" --name-status`, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
356
|
+
const commits = [];
|
|
357
|
+
if (raw) {
|
|
358
|
+
let current = null;
|
|
359
|
+
for (const line of raw.split("\n")) {
|
|
360
|
+
if (line.startsWith(">>C<<")) {
|
|
361
|
+
if (current)
|
|
362
|
+
commits.push(current);
|
|
363
|
+
const [, sha, message, author, date] = line.split("<<");
|
|
364
|
+
current = { sha, shortSha: sha.slice(0, 7), message: message ?? "", author: author ?? "", date: date ?? "", files: [] };
|
|
365
|
+
}
|
|
366
|
+
else if (current && line.trim()) {
|
|
367
|
+
const parts = line.split("\t");
|
|
368
|
+
const s = parts[0]?.[0];
|
|
369
|
+
const filePath = parts[parts.length - 1];
|
|
370
|
+
if (filePath && s) {
|
|
371
|
+
const status = s === "A" ? "added" : s === "D" ? "deleted" : "modified";
|
|
372
|
+
current.files.push({ path: filePath, status });
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (current)
|
|
377
|
+
commits.push(current);
|
|
378
|
+
}
|
|
379
|
+
res.writeHead(200);
|
|
380
|
+
res.end(JSON.stringify({ commits }));
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
res.writeHead(200);
|
|
384
|
+
res.end(JSON.stringify({ commits: [] }));
|
|
385
|
+
}
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
// ── /api/branch-diff — raw git diff for a single file ────────────────────
|
|
389
|
+
if (req.url?.startsWith("/api/branch-diff")) {
|
|
390
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
391
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
392
|
+
res.setHeader("Cache-Control", "no-store");
|
|
393
|
+
if (!repoRoot) {
|
|
394
|
+
res.writeHead(503);
|
|
395
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const parsed = url.parse(req.url, true);
|
|
399
|
+
const file = parsed.query.file || "";
|
|
400
|
+
const rawBase = parsed.query.base || "main";
|
|
401
|
+
const source = parsed.query.source || "working";
|
|
402
|
+
const isWorking = !source || source === "working";
|
|
403
|
+
// Prefer origin/<base> over a stale local target (match the branch-story baseline).
|
|
404
|
+
const base = (() => {
|
|
405
|
+
if (/^(HEAD|origin\/)/.test(rawBase) || /[~^]/.test(rawBase) || /^[0-9a-f]{7,40}$/.test(rawBase))
|
|
406
|
+
return rawBase;
|
|
407
|
+
for (const c of [`origin/${rawBase}`, rawBase]) {
|
|
408
|
+
try {
|
|
409
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --verify ${c}`, { stdio: "pipe" });
|
|
410
|
+
return c;
|
|
411
|
+
}
|
|
412
|
+
catch { }
|
|
413
|
+
}
|
|
414
|
+
return rawBase;
|
|
415
|
+
})();
|
|
416
|
+
// Resolve source to a concrete ref. Prefer origin/<branch> over the local branch —
|
|
417
|
+
// the local copy may be stale (force-pushed, rebased) and produce a different diff
|
|
418
|
+
// than what the brief was computed from. Matching the brief's baseline is critical
|
|
419
|
+
// so that chunk indices align and inference points show the right diff slice.
|
|
420
|
+
const srcRef = isWorking ? "" : (() => {
|
|
421
|
+
for (const c of [`origin/${source}`, source]) {
|
|
422
|
+
try {
|
|
423
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --verify ${c}`, { stdio: "pipe" });
|
|
424
|
+
return c;
|
|
425
|
+
}
|
|
426
|
+
catch { }
|
|
427
|
+
}
|
|
428
|
+
return source;
|
|
429
|
+
})();
|
|
430
|
+
// Match the changeset baseline: diff against the merge-base of Target and Source.
|
|
431
|
+
let diffBase = base;
|
|
432
|
+
try {
|
|
433
|
+
const otherRef = isWorking ? "HEAD" : srcRef;
|
|
434
|
+
diffBase = (0, child_process_1.execSync)(`git -C "${repoRoot}" merge-base ${base} ${otherRef}`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim() || base;
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
diffBase = (0, buildBranchStory_1.resolveMergeBase)(repoRoot, base) ?? base;
|
|
438
|
+
}
|
|
439
|
+
const diff = (0, buildBranchStory_1.getFileDiffRaw)(repoRoot, file, diffBase, srcRef);
|
|
440
|
+
res.writeHead(200);
|
|
441
|
+
res.end(JSON.stringify({ diff }));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
// ── /api/default-branch — detect the repo's default branch ─────────────
|
|
445
|
+
if (req.url === "/api/default-branch") {
|
|
446
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
447
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
448
|
+
res.setHeader("Cache-Control", "no-store");
|
|
449
|
+
let defaultBranch = "main";
|
|
450
|
+
if (repoRoot) {
|
|
451
|
+
try {
|
|
452
|
+
// Try the remote HEAD ref first (most reliable)
|
|
453
|
+
const ref = (0, child_process_1.execSync)(`git -C "${repoRoot}" symbolic-ref refs/remotes/origin/HEAD`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
454
|
+
defaultBranch = ref.replace(/^refs\/remotes\/origin\//, "");
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
// Fall back: check which of main/master/develop actually exists
|
|
458
|
+
for (const candidate of ["main", "master", "develop", "trunk"]) {
|
|
459
|
+
try {
|
|
460
|
+
(0, child_process_1.execSync)(`git -C "${repoRoot}" rev-parse --verify ${candidate}`, { stdio: "pipe" });
|
|
461
|
+
defaultBranch = candidate;
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
catch { /* try next */ }
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
res.writeHead(200);
|
|
469
|
+
res.end(JSON.stringify({ defaultBranch }));
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
// ── /api/am-freshness — how many commits since last AM generation ────────
|
|
473
|
+
if (req.url === "/api/am-freshness") {
|
|
474
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
475
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
476
|
+
res.setHeader("Cache-Control", "no-store");
|
|
477
|
+
if (!repoRoot) {
|
|
478
|
+
res.writeHead(200);
|
|
479
|
+
res.end(JSON.stringify({ commitsBehind: 0 }));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
const amPath = path.join(repoRoot, ".memor", "architecture-map.json");
|
|
484
|
+
const am = JSON.parse(fs.readFileSync(amPath, "utf8"));
|
|
485
|
+
const commit = am._meta?.generatedAtCommit;
|
|
486
|
+
if (!commit) {
|
|
487
|
+
// Old map with no stored commit — use file mtime as rough proxy
|
|
488
|
+
const stat = fs.statSync(amPath);
|
|
489
|
+
const since = stat.mtime.toISOString();
|
|
490
|
+
res.writeHead(200);
|
|
491
|
+
res.end(JSON.stringify({ commitsBehind: null, generatedAt: since, noCommitStored: true }));
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
let commitsBehind = 0;
|
|
495
|
+
try {
|
|
496
|
+
const out = (0, child_process_1.execSync)(`git -C "${repoRoot}" rev-list --count ${commit}..HEAD`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
497
|
+
commitsBehind = parseInt(out) || 0;
|
|
498
|
+
}
|
|
499
|
+
catch { /* git not available or commit not found */ }
|
|
500
|
+
res.writeHead(200);
|
|
501
|
+
res.end(JSON.stringify({ commitsBehind, generatedAt: am._meta?.generatedAt }));
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
// No architecture map at all — not stale, just missing
|
|
505
|
+
res.writeHead(200);
|
|
506
|
+
res.end(JSON.stringify({ commitsBehind: 0 }));
|
|
507
|
+
}
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
// ── /api/xray-detail?file=relative/path — typed AST signatures ───
|
|
511
|
+
if (req.url?.startsWith("/api/xray-detail")) {
|
|
512
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
513
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
514
|
+
if (!repoRoot) {
|
|
515
|
+
res.writeHead(503);
|
|
516
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const parsed = url.parse(req.url, true);
|
|
520
|
+
const fileRel = parsed.query.file;
|
|
521
|
+
if (!fileRel) {
|
|
522
|
+
res.writeHead(400);
|
|
523
|
+
res.end(JSON.stringify({ error: "Missing ?file= parameter" }));
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const absPath = path.resolve(repoRoot, fileRel);
|
|
527
|
+
if (!absPath.startsWith(path.resolve(repoRoot))) {
|
|
528
|
+
res.writeHead(403);
|
|
529
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
try {
|
|
533
|
+
const detail = (0, buildDetailedFileXRay_1.buildDetailedFileXRay)(absPath, repoRoot);
|
|
534
|
+
res.writeHead(200);
|
|
535
|
+
res.end(JSON.stringify(detail));
|
|
536
|
+
}
|
|
537
|
+
catch (e) {
|
|
538
|
+
res.writeHead(500);
|
|
539
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
540
|
+
}
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
// ── /api/xray?file=relative/path/to/file.ts ──────────────────
|
|
544
|
+
if (req.url?.startsWith("/api/xray") && !req.url.startsWith("/api/xray-llm")) {
|
|
545
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
546
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
547
|
+
if (!repoRoot) {
|
|
548
|
+
res.writeHead(503);
|
|
549
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
const parsed = url.parse(req.url, true);
|
|
553
|
+
const fileRel = parsed.query.file;
|
|
554
|
+
if (!fileRel) {
|
|
555
|
+
res.writeHead(400);
|
|
556
|
+
res.end(JSON.stringify({ error: "Missing ?file= parameter" }));
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
// Safety: resolve and ensure file is under repoRoot
|
|
560
|
+
const absPath = path.resolve(repoRoot, fileRel);
|
|
561
|
+
if (!absPath.startsWith(path.resolve(repoRoot))) {
|
|
562
|
+
res.writeHead(403);
|
|
563
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
const xray = (0, buildFileXRay_1.buildFileXRay)(absPath, repoRoot);
|
|
568
|
+
res.writeHead(200);
|
|
569
|
+
res.end(JSON.stringify(xray));
|
|
570
|
+
}
|
|
571
|
+
catch (e) {
|
|
572
|
+
res.writeHead(500);
|
|
573
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
574
|
+
}
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
// ── /api/events — SSE stream for live code-change notifications ──
|
|
578
|
+
if (req.url === "/api/events") {
|
|
579
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
580
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
581
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
582
|
+
res.setHeader("Connection", "keep-alive");
|
|
583
|
+
res.writeHead(200);
|
|
584
|
+
res.write("data: {\"type\":\"connected\"}\n\n");
|
|
585
|
+
(0, repoWatcher_1.addSSEClient)(res);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
// ── /api/repo-root — return the repo root path ───────────────
|
|
589
|
+
if (req.url === "/api/repo-root" && req.method === "GET") {
|
|
590
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
591
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
592
|
+
res.writeHead(200);
|
|
593
|
+
res.end(JSON.stringify({ repoRoot: repoRoot ?? "" }));
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
// ── /api/key-status — check if API key is available ──────────
|
|
597
|
+
if (req.url === "/api/key-status" && req.method === "GET") {
|
|
598
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
599
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
600
|
+
res.writeHead(200);
|
|
601
|
+
const source = runtimeApiKey ? "runtime" : process.env.ANTHROPIC_API_KEY ? "env" : "none";
|
|
602
|
+
res.end(JSON.stringify({ hasKey: source !== "none", source }));
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
// ── /api/set-key — store API key in memory for this session ───
|
|
606
|
+
if (req.url === "/api/set-key" && req.method === "POST") {
|
|
607
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
608
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
609
|
+
readBody(req).then((raw) => {
|
|
610
|
+
try {
|
|
611
|
+
const { key } = JSON.parse(raw);
|
|
612
|
+
if (typeof key === "string" && key.trim().length > 10) {
|
|
613
|
+
runtimeApiKey = key.trim();
|
|
614
|
+
saveKey(runtimeApiKey);
|
|
615
|
+
res.writeHead(200);
|
|
616
|
+
res.end(JSON.stringify({ ok: true }));
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
res.writeHead(400);
|
|
620
|
+
res.end(JSON.stringify({ error: "invalid key" }));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
catch {
|
|
624
|
+
res.writeHead(400);
|
|
625
|
+
res.end(JSON.stringify({ error: "bad request" }));
|
|
626
|
+
}
|
|
627
|
+
}).catch(() => { res.writeHead(500); res.end("{}"); });
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
// ── /api/generate-am — trigger AM (re)generation ──────────────
|
|
631
|
+
if (req.url === "/api/generate-am" && req.method === "POST") {
|
|
632
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
633
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
634
|
+
if (!repoRoot) {
|
|
635
|
+
res.writeHead(503);
|
|
636
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
const apiKey = getApiKey();
|
|
640
|
+
if (!apiKey) {
|
|
641
|
+
res.writeHead(503);
|
|
642
|
+
res.end(JSON.stringify({ error: "ANTHROPIC_API_KEY not set" }));
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
// Respond immediately — generation runs in background
|
|
646
|
+
res.writeHead(202);
|
|
647
|
+
res.end(JSON.stringify({ status: "generating" }));
|
|
648
|
+
(0, generateAMForRepo_1.generateAMForRepo)(repoRoot, apiKey, (step) => {
|
|
649
|
+
if (step.startsWith("am-intel:")) {
|
|
650
|
+
try {
|
|
651
|
+
(0, repoWatcher_1.broadcast)({ type: "am-intel", data: JSON.parse(step.slice(9)) });
|
|
652
|
+
}
|
|
653
|
+
catch { }
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
(0, repoWatcher_1.broadcast)({ type: "am-progress", step });
|
|
657
|
+
}
|
|
658
|
+
})
|
|
659
|
+
.then(() => (0, repoWatcher_1.broadcast)({ type: "am-ready" }))
|
|
660
|
+
.catch((e) => {
|
|
661
|
+
console.error("[memor] AM generation failed:", e.message);
|
|
662
|
+
(0, repoWatcher_1.broadcast)({ type: "am-error", error: e.message });
|
|
663
|
+
});
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
// ── /api/xray-llm?file=relative/path — LLM narrative X-Ray ──
|
|
667
|
+
if (req.url?.startsWith("/api/xray-llm")) {
|
|
668
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
669
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
670
|
+
if (!repoRoot) {
|
|
671
|
+
res.writeHead(503);
|
|
672
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const parsed = url.parse(req.url, true);
|
|
676
|
+
const fileRel = parsed.query.file;
|
|
677
|
+
if (!fileRel) {
|
|
678
|
+
res.writeHead(400);
|
|
679
|
+
res.end(JSON.stringify({ error: "Missing ?file= parameter" }));
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
const absPath = resolveFilePath(path.resolve(repoRoot, fileRel));
|
|
683
|
+
if (!absPath.startsWith(path.resolve(repoRoot))) {
|
|
684
|
+
res.writeHead(403);
|
|
685
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
(0, llmXRay_1.generateLLMXRay)(absPath, repoRoot)
|
|
689
|
+
.then((xray) => {
|
|
690
|
+
res.writeHead(200);
|
|
691
|
+
res.end(JSON.stringify(xray));
|
|
692
|
+
})
|
|
693
|
+
.catch((e) => {
|
|
694
|
+
const status = e.message.includes("ANTHROPIC_API_KEY") ? 503
|
|
695
|
+
: e.message.includes("too large") || e.message.includes("only supports") ? 400
|
|
696
|
+
: 500;
|
|
697
|
+
res.writeHead(status);
|
|
698
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
699
|
+
});
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
// ── /api/generate-flows — deterministic route map → Haiku → patch AM ────
|
|
703
|
+
if (req.url === "/api/generate-flows" && req.method === "POST") {
|
|
704
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
705
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
706
|
+
if (!repoRoot) {
|
|
707
|
+
res.writeHead(503);
|
|
708
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const apiKey = getApiKey();
|
|
712
|
+
if (!apiKey) {
|
|
713
|
+
res.writeHead(503);
|
|
714
|
+
res.end(JSON.stringify({ error: "ANTHROPIC_API_KEY not set" }));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
const amPath = path.join(repoRoot, ".memor", "architecture-map.json");
|
|
718
|
+
let am;
|
|
719
|
+
try {
|
|
720
|
+
am = JSON.parse(fs.readFileSync(amPath, "utf8"));
|
|
721
|
+
}
|
|
722
|
+
catch {
|
|
723
|
+
res.writeHead(404);
|
|
724
|
+
res.end(JSON.stringify({ error: "No architecture map found — generate AM first" }));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
// Respond immediately, run in background
|
|
728
|
+
res.writeHead(202);
|
|
729
|
+
res.end(JSON.stringify({ status: "generating" }));
|
|
730
|
+
Promise.resolve().then(async () => {
|
|
731
|
+
try {
|
|
732
|
+
const systemIds = (am.systems ?? []).map((s) => s.id);
|
|
733
|
+
const externalIds = (am.external ?? []).map((e) => e.id);
|
|
734
|
+
// L1–L4 deterministic pipeline
|
|
735
|
+
const candidates = await (0, buildFlowGraph_1.buildFlowGraph)(repoRoot, am, (step) => {
|
|
736
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-progress", step });
|
|
737
|
+
});
|
|
738
|
+
if (candidates.length === 0) {
|
|
739
|
+
// Fallback to legacy route-map path
|
|
740
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-progress", step: "No entry points found — falling back to route map…" });
|
|
741
|
+
const routeMap = (0, extractRouteMap_1.extractRouteMap)(repoRoot);
|
|
742
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-progress", step: `Found ${routeMap.apiRoutes.length} routes — narrating with LLM…` });
|
|
743
|
+
const flows = await (0, generateFlows_1.generateFlows)(routeMap, systemIds, externalIds, apiKey, repoRoot);
|
|
744
|
+
am.flows = flows;
|
|
745
|
+
fs.writeFileSync(amPath, JSON.stringify(am, null, 2), "utf8");
|
|
746
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-ready", count: flows.length });
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-progress", step: `Narrating ${candidates.length} flows with LLM…` });
|
|
750
|
+
const flows = await (0, generateFlows_1.generateFlows)(candidates, systemIds, externalIds, apiKey, repoRoot);
|
|
751
|
+
am.flows = flows;
|
|
752
|
+
fs.writeFileSync(amPath, JSON.stringify(am, null, 2), "utf8");
|
|
753
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-ready", count: flows.length });
|
|
754
|
+
}
|
|
755
|
+
catch (e) {
|
|
756
|
+
console.error("[memor] Flow generation failed:", e.message);
|
|
757
|
+
(0, repoWatcher_1.broadcast)({ type: "flows-error", error: e.message });
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
// ── /api/ai-file-insight?file=relative/path — description + suggestions ──
|
|
763
|
+
if (req.url?.startsWith("/api/ai-file-insight")) {
|
|
764
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
765
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
766
|
+
if (!repoRoot) {
|
|
767
|
+
res.writeHead(503);
|
|
768
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const apiKey = getApiKey();
|
|
772
|
+
if (!apiKey) {
|
|
773
|
+
res.writeHead(503);
|
|
774
|
+
res.end(JSON.stringify({ error: "ANTHROPIC_API_KEY not set" }));
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
const parsed = url.parse(req.url, true);
|
|
778
|
+
const fileRel = parsed.query.file;
|
|
779
|
+
if (!fileRel) {
|
|
780
|
+
res.writeHead(400);
|
|
781
|
+
res.end(JSON.stringify({ error: "Missing ?file= parameter" }));
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const absPath = resolveFilePath(path.resolve(repoRoot, fileRel));
|
|
785
|
+
if (!absPath.startsWith(path.resolve(repoRoot))) {
|
|
786
|
+
res.writeHead(403);
|
|
787
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
// Build the deterministic X-Ray first, then feed its structured summary to LLM
|
|
791
|
+
// (covers the whole file with far fewer tokens than raw lines)
|
|
792
|
+
let xrayData;
|
|
793
|
+
try {
|
|
794
|
+
xrayData = (0, buildDetailedFileXRay_1.buildDetailedFileXRay)(absPath, repoRoot);
|
|
795
|
+
}
|
|
796
|
+
catch (e) {
|
|
797
|
+
res.writeHead(500);
|
|
798
|
+
res.end(JSON.stringify({ error: `X-Ray failed: ${String(e)}` }));
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
(0, generateFileInsight_1.generateFileInsight)(absPath, repoRoot, apiKey, xrayData)
|
|
802
|
+
.then(insight => { res.writeHead(200); res.end(JSON.stringify(insight)); })
|
|
803
|
+
.catch((e) => { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); });
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
// ── /api/git-changes — staged + working-tree changes ─────────
|
|
807
|
+
if (req.url?.startsWith("/api/git-changes")) {
|
|
808
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
809
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
810
|
+
if (!repoRoot) {
|
|
811
|
+
res.writeHead(503);
|
|
812
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
try {
|
|
816
|
+
const parseFiles = (out) => out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
817
|
+
let files = [];
|
|
818
|
+
try {
|
|
819
|
+
const staged = parseFiles((0, child_process_1.execSync)("git diff --name-only --cached", { cwd: repoRoot, encoding: "utf-8" }));
|
|
820
|
+
files.push(...staged);
|
|
821
|
+
}
|
|
822
|
+
catch { }
|
|
823
|
+
try {
|
|
824
|
+
const unstaged = parseFiles((0, child_process_1.execSync)("git diff --name-only", { cwd: repoRoot, encoding: "utf-8" }));
|
|
825
|
+
files.push(...unstaged);
|
|
826
|
+
}
|
|
827
|
+
catch { }
|
|
828
|
+
// Deduplicate and filter to JS/TS source files
|
|
829
|
+
const sourceRe = /\.(ts|tsx|js|jsx|mjs|cjs)$/;
|
|
830
|
+
const unique = [...new Set(files)].filter((f) => sourceRe.test(f));
|
|
831
|
+
res.writeHead(200);
|
|
832
|
+
res.end(JSON.stringify({ files: unique }));
|
|
833
|
+
}
|
|
834
|
+
catch (e) {
|
|
835
|
+
res.writeHead(500);
|
|
836
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
837
|
+
}
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
// ── /api/file-slice?file=rel/path&from=N&to=N — raw source lines ─
|
|
841
|
+
if (req.url?.startsWith("/api/file-slice")) {
|
|
842
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
843
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
844
|
+
if (!repoRoot) {
|
|
845
|
+
res.writeHead(503);
|
|
846
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const parsed = url.parse(req.url, true);
|
|
850
|
+
const fileRel = parsed.query.file;
|
|
851
|
+
const from = Math.max(1, parseInt(parsed.query.from ?? "1", 10));
|
|
852
|
+
const to = parseInt(parsed.query.to ?? "0", 10);
|
|
853
|
+
if (!fileRel || !to) {
|
|
854
|
+
res.writeHead(400);
|
|
855
|
+
res.end(JSON.stringify({ error: "Missing ?file=, ?from=, ?to= params" }));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const absPath = path.resolve(repoRoot, fileRel);
|
|
859
|
+
if (!absPath.startsWith(path.resolve(repoRoot))) {
|
|
860
|
+
res.writeHead(403);
|
|
861
|
+
res.end(JSON.stringify({ error: "Path traversal not allowed" }));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
try {
|
|
865
|
+
const lines = fs.readFileSync(absPath, "utf8").split("\n");
|
|
866
|
+
const sliced = lines.slice(from - 1, Math.min(to, from + 299)).join("\n"); // max 300 lines
|
|
867
|
+
res.writeHead(200);
|
|
868
|
+
res.end(JSON.stringify({ code: sliced, from, to: Math.min(to, from + 299) }));
|
|
869
|
+
}
|
|
870
|
+
catch {
|
|
871
|
+
res.writeHead(404);
|
|
872
|
+
res.end(JSON.stringify({ error: "File not found" }));
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
// ── /api/git-head — files changed in HEAD commit ──────────────
|
|
877
|
+
if (req.url?.startsWith("/api/git-head")) {
|
|
878
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
879
|
+
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
880
|
+
if (!repoRoot) {
|
|
881
|
+
res.writeHead(503);
|
|
882
|
+
res.end(JSON.stringify({ error: "repoRoot not set" }));
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
const out = (0, child_process_1.execSync)("git diff-tree --no-commit-id -r --name-only HEAD", {
|
|
887
|
+
cwd: repoRoot, encoding: "utf-8",
|
|
888
|
+
});
|
|
889
|
+
const sourceRe = /\.(ts|tsx|js|jsx|mjs|cjs)$/;
|
|
890
|
+
const files = out.split("\n").map((l) => l.trim()).filter(Boolean).filter((f) => sourceRe.test(f));
|
|
891
|
+
res.writeHead(200);
|
|
892
|
+
res.end(JSON.stringify({ files }));
|
|
893
|
+
}
|
|
894
|
+
catch (e) {
|
|
895
|
+
res.writeHead(500);
|
|
896
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
897
|
+
}
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
// ── /tIcons/* — serve tech stack SVG icons ────────────────────
|
|
901
|
+
if (req.url?.startsWith("/tIcons/")) {
|
|
902
|
+
const iconName = req.url.slice("/tIcons/".length).replace(/[^a-zA-Z0-9_.\-]/g, "");
|
|
903
|
+
const iconPath = path.join(__dirname, "..", "public", "tIcons", iconName);
|
|
904
|
+
try {
|
|
905
|
+
const svg = fs.readFileSync(iconPath, "utf8");
|
|
906
|
+
res.writeHead(200, { "Content-Type": "image/svg+xml", "Cache-Control": "public, max-age=86400" });
|
|
907
|
+
res.end(svg);
|
|
908
|
+
}
|
|
909
|
+
catch {
|
|
910
|
+
res.writeHead(404);
|
|
911
|
+
res.end("");
|
|
912
|
+
}
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
// ── Main app HTML ─────────────────────────────────────────────
|
|
916
|
+
res.writeHead(200, {
|
|
917
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
918
|
+
"Cache-Control": "no-store",
|
|
919
|
+
});
|
|
920
|
+
res.end(html);
|
|
921
|
+
});
|
|
922
|
+
const BASE_PORT = port;
|
|
923
|
+
let currentPort = port;
|
|
924
|
+
function tryListen() {
|
|
925
|
+
server.listen(currentPort, () => {
|
|
926
|
+
if (currentPort !== BASE_PORT) {
|
|
927
|
+
console.log(` Port ${BASE_PORT} was in use — started on ${currentPort} instead.`);
|
|
928
|
+
}
|
|
929
|
+
onReady(`http://localhost:${currentPort}`);
|
|
930
|
+
if (repoRoot)
|
|
931
|
+
(0, repoWatcher_1.startRepoWatcher)(repoRoot);
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
server.on("error", (err) => {
|
|
935
|
+
if (err.code === "EADDRINUSE") {
|
|
936
|
+
if (currentPort < BASE_PORT + 4) {
|
|
937
|
+
currentPort++;
|
|
938
|
+
server.close(() => tryListen());
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
console.error(`\n ✗ Ports ${BASE_PORT}–${BASE_PORT + 4} are all in use.`);
|
|
942
|
+
console.error(` Kill the other memor instance, or run with --port <number>.\n`);
|
|
943
|
+
process.exit(1);
|
|
944
|
+
}
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
throw err;
|
|
948
|
+
});
|
|
949
|
+
tryListen();
|
|
950
|
+
process.on("SIGINT", () => {
|
|
951
|
+
server.close();
|
|
952
|
+
console.log("\n Memor stopped.");
|
|
953
|
+
process.exit(0);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
//# sourceMappingURL=server.js.map
|