@burtson-labs/stealth-core-runtime 1.4.7
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 +201 -0
- package/README.md +46 -0
- package/dist/banditEngineProvider.d.ts +48 -0
- package/dist/banditEngineProvider.d.ts.map +1 -0
- package/dist/banditEngineProvider.js +1021 -0
- package/dist/banditEngineProvider.js.map +1 -0
- package/dist/embeddingCache.d.ts +23 -0
- package/dist/embeddingCache.d.ts.map +1 -0
- package/dist/embeddingCache.js +196 -0
- package/dist/embeddingCache.js.map +1 -0
- package/dist/embeddingClient.d.ts +35 -0
- package/dist/embeddingClient.d.ts.map +1 -0
- package/dist/embeddingClient.js +162 -0
- package/dist/embeddingClient.js.map +1 -0
- package/dist/executorAgent.d.ts +7 -0
- package/dist/executorAgent.d.ts.map +1 -0
- package/dist/executorAgent.js +95 -0
- package/dist/executorAgent.js.map +1 -0
- package/dist/extensionSystemPrompt.d.ts +80 -0
- package/dist/extensionSystemPrompt.d.ts.map +1 -0
- package/dist/extensionSystemPrompt.js +208 -0
- package/dist/extensionSystemPrompt.js.map +1 -0
- package/dist/gatewaySearchAdapter.d.ts +69 -0
- package/dist/gatewaySearchAdapter.d.ts.map +1 -0
- package/dist/gatewaySearchAdapter.js +131 -0
- package/dist/gatewaySearchAdapter.js.map +1 -0
- package/dist/goalInference.d.ts +26 -0
- package/dist/goalInference.d.ts.map +1 -0
- package/dist/goalInference.js +605 -0
- package/dist/goalInference.js.map +1 -0
- package/dist/hostTypes.d.ts +86 -0
- package/dist/hostTypes.d.ts.map +1 -0
- package/dist/hostTypes.js +3 -0
- package/dist/hostTypes.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/index.js.map +1 -0
- package/dist/internalTypes.d.ts +16 -0
- package/dist/internalTypes.d.ts.map +1 -0
- package/dist/internalTypes.js +20 -0
- package/dist/internalTypes.js.map +1 -0
- package/dist/ollamaEmbeddingClient.d.ts +45 -0
- package/dist/ollamaEmbeddingClient.d.ts.map +1 -0
- package/dist/ollamaEmbeddingClient.js +143 -0
- package/dist/ollamaEmbeddingClient.js.map +1 -0
- package/dist/pdfjsShim.d.ts +2 -0
- package/dist/pdfjsShim.d.ts.map +1 -0
- package/dist/pdfjsShim.js +80 -0
- package/dist/pdfjsShim.js.map +1 -0
- package/dist/runtime/actionRuntime.d.ts +13 -0
- package/dist/runtime/actionRuntime.d.ts.map +1 -0
- package/dist/runtime/actionRuntime.js +15 -0
- package/dist/runtime/actionRuntime.js.map +1 -0
- package/dist/runtime/actionServices.d.ts +72 -0
- package/dist/runtime/actionServices.d.ts.map +1 -0
- package/dist/runtime/actionServices.js +53 -0
- package/dist/runtime/actionServices.js.map +1 -0
- package/dist/runtime/adapters/connectorBus.d.ts +9 -0
- package/dist/runtime/adapters/connectorBus.d.ts.map +1 -0
- package/dist/runtime/adapters/connectorBus.js +20 -0
- package/dist/runtime/adapters/connectorBus.js.map +1 -0
- package/dist/runtime/adapters/fsAdapter.d.ts +6 -0
- package/dist/runtime/adapters/fsAdapter.d.ts.map +1 -0
- package/dist/runtime/adapters/fsAdapter.js +144 -0
- package/dist/runtime/adapters/fsAdapter.js.map +1 -0
- package/dist/runtime/adapters/llmAdapter.d.ts +4 -0
- package/dist/runtime/adapters/llmAdapter.d.ts.map +1 -0
- package/dist/runtime/adapters/llmAdapter.js +12 -0
- package/dist/runtime/adapters/llmAdapter.js.map +1 -0
- package/dist/runtime/adapters/shellAdapter.d.ts +6 -0
- package/dist/runtime/adapters/shellAdapter.d.ts.map +1 -0
- package/dist/runtime/adapters/shellAdapter.js +118 -0
- package/dist/runtime/adapters/shellAdapter.js.map +1 -0
- package/dist/runtime/additionalWrites.d.ts +22 -0
- package/dist/runtime/additionalWrites.d.ts.map +1 -0
- package/dist/runtime/additionalWrites.js +148 -0
- package/dist/runtime/additionalWrites.js.map +1 -0
- package/dist/runtime/artifactManager.d.ts +32 -0
- package/dist/runtime/artifactManager.d.ts.map +1 -0
- package/dist/runtime/artifactManager.js +154 -0
- package/dist/runtime/artifactManager.js.map +1 -0
- package/dist/runtime/autoHealer.d.ts +27 -0
- package/dist/runtime/autoHealer.d.ts.map +1 -0
- package/dist/runtime/autoHealer.js +583 -0
- package/dist/runtime/autoHealer.js.map +1 -0
- package/dist/runtime/changeTracker.d.ts +20 -0
- package/dist/runtime/changeTracker.d.ts.map +1 -0
- package/dist/runtime/changeTracker.js +147 -0
- package/dist/runtime/changeTracker.js.map +1 -0
- package/dist/runtime/contextBuilder.d.ts +85 -0
- package/dist/runtime/contextBuilder.d.ts.map +1 -0
- package/dist/runtime/contextBuilder.js +159 -0
- package/dist/runtime/contextBuilder.js.map +1 -0
- package/dist/runtime/coreRuntime.d.ts +7 -0
- package/dist/runtime/coreRuntime.d.ts.map +1 -0
- package/dist/runtime/coreRuntime.js +173 -0
- package/dist/runtime/coreRuntime.js.map +1 -0
- package/dist/runtime/createStealthRuntime.d.ts +4 -0
- package/dist/runtime/createStealthRuntime.d.ts.map +1 -0
- package/dist/runtime/createStealthRuntime.js +514 -0
- package/dist/runtime/createStealthRuntime.js.map +1 -0
- package/dist/runtime/diagnostics.d.ts +53 -0
- package/dist/runtime/diagnostics.d.ts.map +1 -0
- package/dist/runtime/diagnostics.js +396 -0
- package/dist/runtime/diagnostics.js.map +1 -0
- package/dist/runtime/diagnosticsServices.d.ts +51 -0
- package/dist/runtime/diagnosticsServices.d.ts.map +1 -0
- package/dist/runtime/diagnosticsServices.js +46 -0
- package/dist/runtime/diagnosticsServices.js.map +1 -0
- package/dist/runtime/diffManager.d.ts +20 -0
- package/dist/runtime/diffManager.d.ts.map +1 -0
- package/dist/runtime/diffManager.js +172 -0
- package/dist/runtime/diffManager.js.map +1 -0
- package/dist/runtime/diffPresenter.d.ts +8 -0
- package/dist/runtime/diffPresenter.d.ts.map +1 -0
- package/dist/runtime/diffPresenter.js +57 -0
- package/dist/runtime/diffPresenter.js.map +1 -0
- package/dist/runtime/embeddingClientResolver.d.ts +14 -0
- package/dist/runtime/embeddingClientResolver.d.ts.map +1 -0
- package/dist/runtime/embeddingClientResolver.js +54 -0
- package/dist/runtime/embeddingClientResolver.js.map +1 -0
- package/dist/runtime/embeddingManager.d.ts +22 -0
- package/dist/runtime/embeddingManager.d.ts.map +1 -0
- package/dist/runtime/embeddingManager.js +224 -0
- package/dist/runtime/embeddingManager.js.map +1 -0
- package/dist/runtime/eventBus.d.ts +7 -0
- package/dist/runtime/eventBus.d.ts.map +1 -0
- package/dist/runtime/eventBus.js +28 -0
- package/dist/runtime/eventBus.js.map +1 -0
- package/dist/runtime/executorServices.d.ts +46 -0
- package/dist/runtime/executorServices.d.ts.map +1 -0
- package/dist/runtime/executorServices.js +47 -0
- package/dist/runtime/executorServices.js.map +1 -0
- package/dist/runtime/extractionService.d.ts +11 -0
- package/dist/runtime/extractionService.d.ts.map +1 -0
- package/dist/runtime/extractionService.js +282 -0
- package/dist/runtime/extractionService.js.map +1 -0
- package/dist/runtime/feedbackService.d.ts +12 -0
- package/dist/runtime/feedbackService.d.ts.map +1 -0
- package/dist/runtime/feedbackService.js +111 -0
- package/dist/runtime/feedbackService.js.map +1 -0
- package/dist/runtime/goalEngine.d.ts +10 -0
- package/dist/runtime/goalEngine.d.ts.map +1 -0
- package/dist/runtime/goalEngine.js +429 -0
- package/dist/runtime/goalEngine.js.map +1 -0
- package/dist/runtime/goalFlowServices.d.ts +49 -0
- package/dist/runtime/goalFlowServices.d.ts.map +1 -0
- package/dist/runtime/goalFlowServices.js +45 -0
- package/dist/runtime/goalFlowServices.js.map +1 -0
- package/dist/runtime/goalReplay.d.ts +33 -0
- package/dist/runtime/goalReplay.d.ts.map +1 -0
- package/dist/runtime/goalReplay.js +58 -0
- package/dist/runtime/goalReplay.js.map +1 -0
- package/dist/runtime/goalRunner.d.ts +35 -0
- package/dist/runtime/goalRunner.d.ts.map +1 -0
- package/dist/runtime/goalRunner.js +42 -0
- package/dist/runtime/goalRunner.js.map +1 -0
- package/dist/runtime/healingEngine.d.ts +72 -0
- package/dist/runtime/healingEngine.d.ts.map +1 -0
- package/dist/runtime/healingEngine.js +969 -0
- package/dist/runtime/healingEngine.js.map +1 -0
- package/dist/runtime/healingServices.d.ts +62 -0
- package/dist/runtime/healingServices.d.ts.map +1 -0
- package/dist/runtime/healingServices.js +45 -0
- package/dist/runtime/healingServices.js.map +1 -0
- package/dist/runtime/helpers.d.ts +22 -0
- package/dist/runtime/helpers.d.ts.map +1 -0
- package/dist/runtime/helpers.js +694 -0
- package/dist/runtime/helpers.js.map +1 -0
- package/dist/runtime/hosts/actionHost.d.ts +82 -0
- package/dist/runtime/hosts/actionHost.d.ts.map +1 -0
- package/dist/runtime/hosts/actionHost.js +61 -0
- package/dist/runtime/hosts/actionHost.js.map +1 -0
- package/dist/runtime/hosts/baseServices.d.ts +51 -0
- package/dist/runtime/hosts/baseServices.d.ts.map +1 -0
- package/dist/runtime/hosts/baseServices.js +73 -0
- package/dist/runtime/hosts/baseServices.js.map +1 -0
- package/dist/runtime/hosts/embeddingServices.d.ts +25 -0
- package/dist/runtime/hosts/embeddingServices.d.ts.map +1 -0
- package/dist/runtime/hosts/embeddingServices.js +34 -0
- package/dist/runtime/hosts/embeddingServices.js.map +1 -0
- package/dist/runtime/hosts/goalFlowHost.d.ts +34 -0
- package/dist/runtime/hosts/goalFlowHost.d.ts.map +1 -0
- package/dist/runtime/hosts/goalFlowHost.js +35 -0
- package/dist/runtime/hosts/goalFlowHost.js.map +1 -0
- package/dist/runtime/hosts/goalFlowRuntime.d.ts +41 -0
- package/dist/runtime/hosts/goalFlowRuntime.d.ts.map +1 -0
- package/dist/runtime/hosts/goalFlowRuntime.js +31 -0
- package/dist/runtime/hosts/goalFlowRuntime.js.map +1 -0
- package/dist/runtime/hosts/providerHost.d.ts +19 -0
- package/dist/runtime/hosts/providerHost.d.ts.map +1 -0
- package/dist/runtime/hosts/providerHost.js +18 -0
- package/dist/runtime/hosts/providerHost.js.map +1 -0
- package/dist/runtime/hosts/rewriteHost.d.ts +84 -0
- package/dist/runtime/hosts/rewriteHost.d.ts.map +1 -0
- package/dist/runtime/hosts/rewriteHost.js +64 -0
- package/dist/runtime/hosts/rewriteHost.js.map +1 -0
- package/dist/runtime/hosts/workspaceHost.d.ts +113 -0
- package/dist/runtime/hosts/workspaceHost.d.ts.map +1 -0
- package/dist/runtime/hosts/workspaceHost.js +76 -0
- package/dist/runtime/hosts/workspaceHost.js.map +1 -0
- package/dist/runtime/index.d.ts +78 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +95 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/insight.d.ts +16 -0
- package/dist/runtime/insight.d.ts.map +1 -0
- package/dist/runtime/insight.js +11 -0
- package/dist/runtime/insight.js.map +1 -0
- package/dist/runtime/internalActions.d.ts +16 -0
- package/dist/runtime/internalActions.d.ts.map +1 -0
- package/dist/runtime/internalActions.js +302 -0
- package/dist/runtime/internalActions.js.map +1 -0
- package/dist/runtime/modelBehavior.d.ts +69 -0
- package/dist/runtime/modelBehavior.d.ts.map +1 -0
- package/dist/runtime/modelBehavior.js +514 -0
- package/dist/runtime/modelBehavior.js.map +1 -0
- package/dist/runtime/modelCapabilities.d.ts +139 -0
- package/dist/runtime/modelCapabilities.d.ts.map +1 -0
- package/dist/runtime/modelCapabilities.js +458 -0
- package/dist/runtime/modelCapabilities.js.map +1 -0
- package/dist/runtime/modelsDevCatalog.d.ts +34 -0
- package/dist/runtime/modelsDevCatalog.d.ts.map +1 -0
- package/dist/runtime/modelsDevCatalog.js +263 -0
- package/dist/runtime/modelsDevCatalog.js.map +1 -0
- package/dist/runtime/pendingInference.d.ts +18 -0
- package/dist/runtime/pendingInference.d.ts.map +1 -0
- package/dist/runtime/pendingInference.js +121 -0
- package/dist/runtime/pendingInference.js.map +1 -0
- package/dist/runtime/persistence.d.ts +21 -0
- package/dist/runtime/persistence.d.ts.map +1 -0
- package/dist/runtime/persistence.js +73 -0
- package/dist/runtime/persistence.js.map +1 -0
- package/dist/runtime/planContext.d.ts +42 -0
- package/dist/runtime/planContext.d.ts.map +1 -0
- package/dist/runtime/planContext.js +246 -0
- package/dist/runtime/planContext.js.map +1 -0
- package/dist/runtime/planGenerator.d.ts +21 -0
- package/dist/runtime/planGenerator.d.ts.map +1 -0
- package/dist/runtime/planGenerator.js +89 -0
- package/dist/runtime/planGenerator.js.map +1 -0
- package/dist/runtime/planPreparation.d.ts +64 -0
- package/dist/runtime/planPreparation.d.ts.map +1 -0
- package/dist/runtime/planPreparation.js +173 -0
- package/dist/runtime/planPreparation.js.map +1 -0
- package/dist/runtime/projectSummary.d.ts +3 -0
- package/dist/runtime/projectSummary.d.ts.map +1 -0
- package/dist/runtime/projectSummary.js +42 -0
- package/dist/runtime/projectSummary.js.map +1 -0
- package/dist/runtime/providerSettings.d.ts +28 -0
- package/dist/runtime/providerSettings.d.ts.map +1 -0
- package/dist/runtime/providerSettings.js +93 -0
- package/dist/runtime/providerSettings.js.map +1 -0
- package/dist/runtime/pythonActions.d.ts +78 -0
- package/dist/runtime/pythonActions.d.ts.map +1 -0
- package/dist/runtime/pythonActions.js +392 -0
- package/dist/runtime/pythonActions.js.map +1 -0
- package/dist/runtime/pythonBridge.d.ts +13 -0
- package/dist/runtime/pythonBridge.d.ts.map +1 -0
- package/dist/runtime/pythonBridge.js +117 -0
- package/dist/runtime/pythonBridge.js.map +1 -0
- package/dist/runtime/rewriteEngine.d.ts +46 -0
- package/dist/runtime/rewriteEngine.d.ts.map +1 -0
- package/dist/runtime/rewriteEngine.js +259 -0
- package/dist/runtime/rewriteEngine.js.map +1 -0
- package/dist/runtime/rewriteGenerator.d.ts +29 -0
- package/dist/runtime/rewriteGenerator.d.ts.map +1 -0
- package/dist/runtime/rewriteGenerator.js +1527 -0
- package/dist/runtime/rewriteGenerator.js.map +1 -0
- package/dist/runtime/rewriteHydration.d.ts +22 -0
- package/dist/runtime/rewriteHydration.d.ts.map +1 -0
- package/dist/runtime/rewriteHydration.js +265 -0
- package/dist/runtime/rewriteHydration.js.map +1 -0
- package/dist/runtime/rewriteOrchestration.d.ts +105 -0
- package/dist/runtime/rewriteOrchestration.d.ts.map +1 -0
- package/dist/runtime/rewriteOrchestration.js +130 -0
- package/dist/runtime/rewriteOrchestration.js.map +1 -0
- package/dist/runtime/rewritePayload.d.ts +18 -0
- package/dist/runtime/rewritePayload.d.ts.map +1 -0
- package/dist/runtime/rewritePayload.js +166 -0
- package/dist/runtime/rewritePayload.js.map +1 -0
- package/dist/runtime/rewriteRuntime.d.ts +13 -0
- package/dist/runtime/rewriteRuntime.d.ts.map +1 -0
- package/dist/runtime/rewriteRuntime.js +21 -0
- package/dist/runtime/rewriteRuntime.js.map +1 -0
- package/dist/runtime/rewriteServices.d.ts +70 -0
- package/dist/runtime/rewriteServices.d.ts.map +1 -0
- package/dist/runtime/rewriteServices.js +50 -0
- package/dist/runtime/rewriteServices.js.map +1 -0
- package/dist/runtime/runtimeHelpers.d.ts +9 -0
- package/dist/runtime/runtimeHelpers.d.ts.map +1 -0
- package/dist/runtime/runtimeHelpers.js +86 -0
- package/dist/runtime/runtimeHelpers.js.map +1 -0
- package/dist/runtime/sessionData.d.ts +4 -0
- package/dist/runtime/sessionData.d.ts.map +1 -0
- package/dist/runtime/sessionData.js +45 -0
- package/dist/runtime/sessionData.js.map +1 -0
- package/dist/runtime/sessionRuntime.d.ts +47 -0
- package/dist/runtime/sessionRuntime.d.ts.map +1 -0
- package/dist/runtime/sessionRuntime.js +128 -0
- package/dist/runtime/sessionRuntime.js.map +1 -0
- package/dist/runtime/stealthRuntimeTypes.d.ts +12 -0
- package/dist/runtime/stealthRuntimeTypes.d.ts.map +1 -0
- package/dist/runtime/stealthRuntimeTypes.js +3 -0
- package/dist/runtime/stealthRuntimeTypes.js.map +1 -0
- package/dist/runtime/stepExecutor.d.ts +22 -0
- package/dist/runtime/stepExecutor.d.ts.map +1 -0
- package/dist/runtime/stepExecutor.js +83 -0
- package/dist/runtime/stepExecutor.js.map +1 -0
- package/dist/runtime/stepLifecycle.d.ts +29 -0
- package/dist/runtime/stepLifecycle.d.ts.map +1 -0
- package/dist/runtime/stepLifecycle.js +122 -0
- package/dist/runtime/stepLifecycle.js.map +1 -0
- package/dist/runtime/stepMetadata.d.ts +6 -0
- package/dist/runtime/stepMetadata.d.ts.map +1 -0
- package/dist/runtime/stepMetadata.js +87 -0
- package/dist/runtime/stepMetadata.js.map +1 -0
- package/dist/runtime/taskQueue.d.ts +16 -0
- package/dist/runtime/taskQueue.d.ts.map +1 -0
- package/dist/runtime/taskQueue.js +103 -0
- package/dist/runtime/taskQueue.js.map +1 -0
- package/dist/runtime/telemetry.d.ts +6 -0
- package/dist/runtime/telemetry.d.ts.map +1 -0
- package/dist/runtime/telemetry.js +42 -0
- package/dist/runtime/telemetry.js.map +1 -0
- package/dist/runtime/telemetryHub.d.ts +61 -0
- package/dist/runtime/telemetryHub.d.ts.map +1 -0
- package/dist/runtime/telemetryHub.js +190 -0
- package/dist/runtime/telemetryHub.js.map +1 -0
- package/dist/runtime/textSanitizer.d.ts +4 -0
- package/dist/runtime/textSanitizer.d.ts.map +1 -0
- package/dist/runtime/textSanitizer.js +86 -0
- package/dist/runtime/textSanitizer.js.map +1 -0
- package/dist/runtime/typeCheckRunner.d.ts +33 -0
- package/dist/runtime/typeCheckRunner.d.ts.map +1 -0
- package/dist/runtime/typeCheckRunner.js +357 -0
- package/dist/runtime/typeCheckRunner.js.map +1 -0
- package/dist/runtime/types.d.ts +334 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +3 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/typescriptValidator.d.ts +18 -0
- package/dist/runtime/typescriptValidator.d.ts.map +1 -0
- package/dist/runtime/typescriptValidator.js +363 -0
- package/dist/runtime/typescriptValidator.js.map +1 -0
- package/dist/runtime/undoManager.d.ts +7 -0
- package/dist/runtime/undoManager.d.ts.map +1 -0
- package/dist/runtime/undoManager.js +56 -0
- package/dist/runtime/undoManager.js.map +1 -0
- package/dist/runtime/validationController.d.ts +11 -0
- package/dist/runtime/validationController.d.ts.map +1 -0
- package/dist/runtime/validationController.js +29 -0
- package/dist/runtime/validationController.js.map +1 -0
- package/dist/runtime/validationUtils.d.ts +17 -0
- package/dist/runtime/validationUtils.d.ts.map +1 -0
- package/dist/runtime/validationUtils.js +121 -0
- package/dist/runtime/validationUtils.js.map +1 -0
- package/dist/runtime/workspaceAssertions.d.ts +21 -0
- package/dist/runtime/workspaceAssertions.d.ts.map +1 -0
- package/dist/runtime/workspaceAssertions.js +183 -0
- package/dist/runtime/workspaceAssertions.js.map +1 -0
- package/dist/runtime/workspaceIndexService.d.ts +24 -0
- package/dist/runtime/workspaceIndexService.d.ts.map +1 -0
- package/dist/runtime/workspaceIndexService.js +133 -0
- package/dist/runtime/workspaceIndexService.js.map +1 -0
- package/dist/runtime/workspaceIndexer.d.ts +21 -0
- package/dist/runtime/workspaceIndexer.d.ts.map +1 -0
- package/dist/runtime/workspaceIndexer.js +95 -0
- package/dist/runtime/workspaceIndexer.js.map +1 -0
- package/dist/runtime/workspacePackages.d.ts +22 -0
- package/dist/runtime/workspacePackages.d.ts.map +1 -0
- package/dist/runtime/workspacePackages.js +198 -0
- package/dist/runtime/workspacePackages.js.map +1 -0
- package/dist/runtime/workspaceRuntime.d.ts +58 -0
- package/dist/runtime/workspaceRuntime.d.ts.map +1 -0
- package/dist/runtime/workspaceRuntime.js +86 -0
- package/dist/runtime/workspaceRuntime.js.map +1 -0
- package/dist/runtime/workspaceService.d.ts +14 -0
- package/dist/runtime/workspaceService.d.ts.map +1 -0
- package/dist/runtime/workspaceService.js +88 -0
- package/dist/runtime/workspaceService.js.map +1 -0
- package/dist/runtime/workspaceServices.d.ts +114 -0
- package/dist/runtime/workspaceServices.d.ts.map +1 -0
- package/dist/runtime/workspaceServices.js +114 -0
- package/dist/runtime/workspaceServices.js.map +1 -0
- package/dist/runtime/writeServices.d.ts +34 -0
- package/dist/runtime/writeServices.d.ts.map +1 -0
- package/dist/runtime/writeServices.js +32 -0
- package/dist/runtime/writeServices.js.map +1 -0
- package/dist/sharedPromptSections.d.ts +58 -0
- package/dist/sharedPromptSections.d.ts.map +1 -0
- package/dist/sharedPromptSections.js +94 -0
- package/dist/sharedPromptSections.js.map +1 -0
- package/dist/statusTypes.d.ts +13 -0
- package/dist/statusTypes.d.ts.map +1 -0
- package/dist/statusTypes.js +3 -0
- package/dist/statusTypes.js.map +1 -0
- package/dist/streamIdleTimeout.d.ts +38 -0
- package/dist/streamIdleTimeout.d.ts.map +1 -0
- package/dist/streamIdleTimeout.js +44 -0
- package/dist/streamIdleTimeout.js.map +1 -0
- package/dist/types/bandit.d.ts +113 -0
- package/dist/types/bandit.d.ts.map +1 -0
- package/dist/types/bandit.js +3 -0
- package/dist/types/bandit.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/workspaceIndex.d.ts +44 -0
- package/dist/workspaceIndex.d.ts.map +1 -0
- package/dist/workspaceIndex.js +258 -0
- package/dist/workspaceIndex.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,1527 @@
|
|
|
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.createRewriteGenerator = createRewriteGenerator;
|
|
37
|
+
const rewritePayload_1 = require("./rewritePayload");
|
|
38
|
+
const textSanitizer_1 = require("./textSanitizer");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const MAX_PRIMARY_REWRITE_CONTEXT = 20000;
|
|
41
|
+
const FILE_BLOCK_REGEX = /```files/i;
|
|
42
|
+
const FILE_HEADER_REGEX = /FILE:\s*/i;
|
|
43
|
+
function createRewriteGenerator(deps) {
|
|
44
|
+
async function generateRewrite(goal, relativePath, currentContent, projectSummary, instructions, hydration) {
|
|
45
|
+
const configuration = deps.getConfiguration();
|
|
46
|
+
const providerKind = deps.getProviderKind(configuration);
|
|
47
|
+
const apiKey = providerKind === 'bandit' ? await deps.fetchApiKey() : '';
|
|
48
|
+
if (providerKind === 'bandit' && !apiKey) {
|
|
49
|
+
return { ok: false, error: 'Bandit API key required to draft homepage updates.' };
|
|
50
|
+
}
|
|
51
|
+
const provider = await deps.createProvider(deps.buildProviderSettings(configuration, apiKey ?? ''));
|
|
52
|
+
const maxContent = MAX_PRIMARY_REWRITE_CONTEXT;
|
|
53
|
+
const trimmedContent = currentContent.length > maxContent ? `${currentContent.slice(0, maxContent)}\n/* trimmed */` : currentContent;
|
|
54
|
+
const hydrationBlocks = deps.buildHydrationBlocks(hydration, relativePath);
|
|
55
|
+
const expectsFilesBlock = shouldExpectFilesBlock(instructions);
|
|
56
|
+
const requiredFiles = extractRequiredFilesFromInstructions(instructions);
|
|
57
|
+
const requiredFileMap = new Map();
|
|
58
|
+
for (const file of requiredFiles) {
|
|
59
|
+
const normalized = normalizePathForCompare(file, (value) => deps.normalizeRelativePath(value));
|
|
60
|
+
if (!normalized) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (!requiredFileMap.has(normalized)) {
|
|
64
|
+
requiredFileMap.set(normalized, file);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
reconcileRequiredPrimaryPath(requiredFileMap, relativePath, (value) => deps.normalizeRelativePath(value));
|
|
68
|
+
const requiredFileKeys = Array.from(requiredFileMap.keys());
|
|
69
|
+
const formatMissingFiles = (missing) => missing.map((key) => requiredFileMap.get(key) ?? key);
|
|
70
|
+
const collectMissingRequired = (entries) => {
|
|
71
|
+
if (!expectsFilesBlock || requiredFileKeys.length === 0) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const normalizedEntries = entries
|
|
75
|
+
.map((entry) => ({
|
|
76
|
+
path: normalizePathForCompare(entry.path, (value) => deps.normalizeRelativePath(value)),
|
|
77
|
+
content: entry.content
|
|
78
|
+
}))
|
|
79
|
+
.filter((entry) => Boolean(entry.path));
|
|
80
|
+
return requiredFileKeys.filter((required) => {
|
|
81
|
+
const match = normalizedEntries.find((entry) => entry.path === required);
|
|
82
|
+
if (!match) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return match.content.trim().length === 0;
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
const requiredFileList = Array.from(requiredFileMap.values());
|
|
89
|
+
if (expectsFilesBlock && requiredFileList.length >= 2) {
|
|
90
|
+
const deterministicEntries = buildDomainExtractionFallback({
|
|
91
|
+
primaryPath: relativePath,
|
|
92
|
+
currentContent,
|
|
93
|
+
requiredFiles: requiredFileList,
|
|
94
|
+
normalizePath: (value) => deps.normalizeRelativePath(value)
|
|
95
|
+
});
|
|
96
|
+
if (deterministicEntries) {
|
|
97
|
+
const normalizedEntries = deterministicEntries.map((entry) => ({
|
|
98
|
+
path: deps.normalizeRelativePath(entry.path) ?? entry.path,
|
|
99
|
+
content: entry.content
|
|
100
|
+
}));
|
|
101
|
+
const primaryEntry = normalizedEntries[0];
|
|
102
|
+
const additionalWrites = normalizedEntries.slice(1).map((entry) => ({
|
|
103
|
+
path: entry.path,
|
|
104
|
+
content: (0, textSanitizer_1.sanitizeGeneratedSource)(entry.content)
|
|
105
|
+
}));
|
|
106
|
+
const sanitizedContent = (0, textSanitizer_1.sanitizeGeneratedSource)(primaryEntry?.content ?? '');
|
|
107
|
+
if (sanitizedContent.trim() &&
|
|
108
|
+
currentContent.length > 200 &&
|
|
109
|
+
sanitizedContent.length < currentContent.length * 0.3) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
error: `Deterministic rewrite is suspiciously short: ${sanitizedContent.length} chars for a ${currentContent.length}-char file.`
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
ok: Boolean(sanitizedContent.trim()) || additionalWrites.length > 0,
|
|
117
|
+
output: `Draft size: ${sanitizedContent.length} chars`,
|
|
118
|
+
data: {
|
|
119
|
+
content: sanitizedContent,
|
|
120
|
+
additionalWrites
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const userSections = [
|
|
126
|
+
`Goal: ${goal}`,
|
|
127
|
+
'',
|
|
128
|
+
`Project summary: ${projectSummary}`,
|
|
129
|
+
'',
|
|
130
|
+
`File path: ${relativePath}`,
|
|
131
|
+
''
|
|
132
|
+
];
|
|
133
|
+
if (instructions?.trim()) {
|
|
134
|
+
userSections.push(instructions.trim(), '');
|
|
135
|
+
}
|
|
136
|
+
if (requiredFileList.length > 0) {
|
|
137
|
+
userSections.push('Required FILE entries:', ...requiredFileList.map((file) => `- ${file}`), '');
|
|
138
|
+
}
|
|
139
|
+
userSections.push('Current file:', '```', trimmedContent, '```');
|
|
140
|
+
if (hydrationBlocks.length > 0) {
|
|
141
|
+
userSections.push('', ...hydrationBlocks);
|
|
142
|
+
}
|
|
143
|
+
const brandGuard = 'You are Bandit Stealth, a coding assistant built by Burtson Labs LLC. Never identify yourself as Gemma, Llama, or any other underlying model name.';
|
|
144
|
+
const systemPrompt = expectsFilesBlock
|
|
145
|
+
? `${brandGuard} Return ONLY a \`\`\`files code block with one or more FILE entries for every updated file. Do not include any other text.`
|
|
146
|
+
: `${brandGuard} Return the full updated file with no additional explanation, no Markdown fences, and no commentary.`;
|
|
147
|
+
const request = {
|
|
148
|
+
model: deps.getModel(configuration, providerKind),
|
|
149
|
+
messages: [
|
|
150
|
+
{
|
|
151
|
+
role: 'system',
|
|
152
|
+
content: systemPrompt
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
role: 'user',
|
|
156
|
+
content: userSections.join('\n')
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
temperature: configuration.get('temperature', 0.2),
|
|
160
|
+
stream: true
|
|
161
|
+
};
|
|
162
|
+
const topP = deps.getTopP(configuration);
|
|
163
|
+
if (typeof topP === 'number' && !Number.isNaN(topP)) {
|
|
164
|
+
request.options = { top_p: topP };
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const isReviewMode = deps.diffManager.isReviewModeEnabled();
|
|
168
|
+
const runChat = async (requestPayload, attempt) => {
|
|
169
|
+
let buffer = '';
|
|
170
|
+
if (isReviewMode && attempt === 0) {
|
|
171
|
+
await deps.diffManager.postDiffStream({ path: relativePath, kind: 'start', content: '' });
|
|
172
|
+
}
|
|
173
|
+
for await (const chunk of provider.chat(requestPayload)) {
|
|
174
|
+
if (deps.isCancelled()) {
|
|
175
|
+
throw new Error('Cancelled');
|
|
176
|
+
}
|
|
177
|
+
const content = chunk?.message?.content ?? '';
|
|
178
|
+
if (content) {
|
|
179
|
+
buffer += content;
|
|
180
|
+
await deps.diffManager.postDiffStream({ path: relativePath, kind: 'progress', content: buffer });
|
|
181
|
+
}
|
|
182
|
+
if (chunk?.done) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return buffer.trim();
|
|
187
|
+
};
|
|
188
|
+
let rawResponse = await runChat(request, 0);
|
|
189
|
+
let normalized = (0, textSanitizer_1.stripCodeFences)(rawResponse).replace(/\r\n/g, '\n');
|
|
190
|
+
let structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
191
|
+
let missingRequired = collectMissingRequired(structuredEntries);
|
|
192
|
+
const allowFallback = requiredFileKeys.length <= 1;
|
|
193
|
+
if (expectsFilesBlock && structuredEntries.length === 0 && allowFallback) {
|
|
194
|
+
const fallbackContent = extractFallbackFileContent(rawResponse, relativePath);
|
|
195
|
+
if (fallbackContent) {
|
|
196
|
+
normalized = buildFallbackFilesBlock(relativePath, fallbackContent);
|
|
197
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
198
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (expectsFilesBlock && (structuredEntries.length === 0 || missingRequired.length > 0)) {
|
|
202
|
+
const retryPrompt = missingRequired.length > 0
|
|
203
|
+
? [
|
|
204
|
+
`Your previous response did not include FILE entries for: ${formatMissingFiles(missingRequired).join(', ')}.`,
|
|
205
|
+
'Return ONLY a ```files block with FILE entries for every updated file. No other text.'
|
|
206
|
+
].join(' ')
|
|
207
|
+
: [
|
|
208
|
+
'Your previous response did not include the required ```files block.',
|
|
209
|
+
'Return ONLY a ```files block with FILE entries for every updated file. No other text.'
|
|
210
|
+
].join(' ');
|
|
211
|
+
const retryRequest = {
|
|
212
|
+
...request,
|
|
213
|
+
messages: [
|
|
214
|
+
{
|
|
215
|
+
role: 'system',
|
|
216
|
+
content: 'Return ONLY a ```files code block with one or more FILE entries for every updated file. Do not include any other text.'
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
role: 'user',
|
|
220
|
+
content: [...userSections, retryPrompt].join('\n')
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
};
|
|
224
|
+
rawResponse = await runChat(retryRequest, 1);
|
|
225
|
+
normalized = (0, textSanitizer_1.stripCodeFences)(rawResponse).replace(/\r\n/g, '\n');
|
|
226
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
227
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
228
|
+
if (structuredEntries.length === 0 && allowFallback) {
|
|
229
|
+
const fallbackContent = extractFallbackFileContent(rawResponse, relativePath);
|
|
230
|
+
if (fallbackContent) {
|
|
231
|
+
normalized = buildFallbackFilesBlock(relativePath, fallbackContent);
|
|
232
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
233
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (expectsFilesBlock && (structuredEntries.length === 0 || missingRequired.length > 0)) {
|
|
238
|
+
const retryFiles = requiredFileList.length > 0 ? requiredFileList : [relativePath];
|
|
239
|
+
const strictPrompt = [
|
|
240
|
+
'Your previous response was invalid.',
|
|
241
|
+
'You must respond with exactly this structure and nothing else:',
|
|
242
|
+
buildFilesBlockTemplate(retryFiles),
|
|
243
|
+
'Replace each <entire updated file> section with the full file contents.'
|
|
244
|
+
].join('\n\n');
|
|
245
|
+
const strictRequest = {
|
|
246
|
+
...request,
|
|
247
|
+
messages: [
|
|
248
|
+
{
|
|
249
|
+
role: 'system',
|
|
250
|
+
content: 'Return ONLY a ```files code block with one or more FILE entries for every updated file. Do not include any other text.'
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
role: 'user',
|
|
254
|
+
content: [...userSections, strictPrompt].join('\n')
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
};
|
|
258
|
+
rawResponse = await runChat(strictRequest, 2);
|
|
259
|
+
normalized = (0, textSanitizer_1.stripCodeFences)(rawResponse).replace(/\r\n/g, '\n');
|
|
260
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
261
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
262
|
+
if (structuredEntries.length === 0 && allowFallback) {
|
|
263
|
+
const fallbackContent = extractFallbackFileContent(rawResponse, relativePath);
|
|
264
|
+
if (fallbackContent) {
|
|
265
|
+
normalized = buildFallbackFilesBlock(relativePath, fallbackContent);
|
|
266
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
267
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (expectsFilesBlock && missingRequired.length > 0 && structuredEntries.length > 0) {
|
|
272
|
+
const primaryKey = normalizePathForCompare(relativePath, (value) => deps.normalizeRelativePath(value));
|
|
273
|
+
const isPrimaryMissing = primaryKey ? missingRequired.includes(primaryKey) : false;
|
|
274
|
+
if (isPrimaryMissing && missingRequired.length === 1) {
|
|
275
|
+
normalized = buildFilesBlockFromEntries([
|
|
276
|
+
{ path: relativePath, content: currentContent },
|
|
277
|
+
...structuredEntries
|
|
278
|
+
]);
|
|
279
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
280
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (expectsFilesBlock && (structuredEntries.length === 0 || missingRequired.length > 0)) {
|
|
284
|
+
const fallbackEntries = buildDomainExtractionFallback({
|
|
285
|
+
primaryPath: relativePath,
|
|
286
|
+
currentContent,
|
|
287
|
+
requiredFiles: requiredFileList,
|
|
288
|
+
normalizePath: (value) => deps.normalizeRelativePath(value)
|
|
289
|
+
});
|
|
290
|
+
if (fallbackEntries) {
|
|
291
|
+
normalized = buildFilesBlockFromEntries(fallbackEntries);
|
|
292
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
293
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (expectsFilesBlock && structuredEntries.length === 0) {
|
|
297
|
+
return {
|
|
298
|
+
ok: false,
|
|
299
|
+
error: 'Rewrite response missing ```files block with FILE entries.'
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (structuredEntries.length > 0) {
|
|
303
|
+
const reconciled = reconcilePrimaryStructuredEntries({
|
|
304
|
+
entries: structuredEntries,
|
|
305
|
+
primaryPath: relativePath,
|
|
306
|
+
normalizePath: (value) => deps.normalizeRelativePath(value)
|
|
307
|
+
});
|
|
308
|
+
if (reconciled) {
|
|
309
|
+
normalized = buildFilesBlockFromEntries(reconciled);
|
|
310
|
+
structuredEntries = (0, rewritePayload_1.parseStructuredFileOutputs)(normalized);
|
|
311
|
+
missingRequired = collectMissingRequired(structuredEntries);
|
|
312
|
+
}
|
|
313
|
+
const normalizedPrimary = normalizePathForCompare(relativePath, (value) => deps.normalizeRelativePath(value));
|
|
314
|
+
const normalizedEntries = structuredEntries
|
|
315
|
+
.map((entry) => normalizePathForCompare(entry.path, (value) => deps.normalizeRelativePath(value)))
|
|
316
|
+
.filter((entry) => Boolean(entry));
|
|
317
|
+
if (normalizedPrimary && !normalizedEntries.includes(normalizedPrimary)) {
|
|
318
|
+
return {
|
|
319
|
+
ok: false,
|
|
320
|
+
error: `Rewrite response missing primary FILE entry for ${relativePath}.`
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (expectsFilesBlock && missingRequired.length > 0) {
|
|
325
|
+
return {
|
|
326
|
+
ok: false,
|
|
327
|
+
error: `Rewrite response missing FILE entries for: ${formatMissingFiles(missingRequired).join(', ')}.`
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const payload = (0, rewritePayload_1.extractRewritePayload)(normalized, {
|
|
331
|
+
primaryPath: relativePath,
|
|
332
|
+
normalizePath: (value) => deps.normalizeRelativePath(value),
|
|
333
|
+
fileOpsStart: deps.fileOpsMarkers.start,
|
|
334
|
+
fileOpsEnd: deps.fileOpsMarkers.end
|
|
335
|
+
});
|
|
336
|
+
payload.content = (0, textSanitizer_1.sanitizeGeneratedSource)(payload.content);
|
|
337
|
+
payload.additionalWrites = payload.additionalWrites.map((entry) => ({
|
|
338
|
+
...entry,
|
|
339
|
+
content: (0, textSanitizer_1.sanitizeGeneratedSource)(entry.content)
|
|
340
|
+
}));
|
|
341
|
+
// Guard: reject if the model returned suspiciously little content compared to the original.
|
|
342
|
+
// A threshold of 30% catches truncated/hallucinated responses while allowing intentional
|
|
343
|
+
// file shrinkage (e.g. "delete this function"). Only applies to non-trivial files (>200 chars).
|
|
344
|
+
const MIN_SHRINK_RATIO = 0.3;
|
|
345
|
+
const MIN_ORIGINAL_FOR_GUARD = 200;
|
|
346
|
+
if (payload.content.trim() &&
|
|
347
|
+
currentContent.length > MIN_ORIGINAL_FOR_GUARD &&
|
|
348
|
+
payload.content.length < currentContent.length * MIN_SHRINK_RATIO) {
|
|
349
|
+
return {
|
|
350
|
+
ok: false,
|
|
351
|
+
error: `Rewrite is suspiciously short: model returned ${payload.content.length} chars for a ${currentContent.length}-char file. Likely a truncated response — retrying is recommended.`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
if (isReviewMode) {
|
|
355
|
+
await deps.diffManager.postDiffStream({ path: relativePath, kind: 'complete', content: payload.content });
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
ok: Boolean(payload.content.trim()) || payload.additionalWrites.length > 0,
|
|
359
|
+
output: `Draft size: ${payload.content.length} chars`,
|
|
360
|
+
data: {
|
|
361
|
+
content: payload.content,
|
|
362
|
+
additionalWrites: payload.additionalWrites
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return { generateRewrite };
|
|
371
|
+
}
|
|
372
|
+
function shouldExpectFilesBlock(instructions) {
|
|
373
|
+
if (!instructions) {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
return FILE_BLOCK_REGEX.test(instructions) || FILE_HEADER_REGEX.test(instructions) || /files block/i.test(instructions);
|
|
377
|
+
}
|
|
378
|
+
function buildFilesBlockTemplate(paths) {
|
|
379
|
+
const normalized = paths.filter((path) => typeof path === 'string' && path.trim().length > 0);
|
|
380
|
+
const entries = normalized.length > 0 ? normalized : ['<path to update>'];
|
|
381
|
+
const lines = ['```files'];
|
|
382
|
+
entries.forEach((path, index) => {
|
|
383
|
+
lines.push(`FILE: ${path}`);
|
|
384
|
+
lines.push('<entire updated file>');
|
|
385
|
+
if (index !== entries.length - 1) {
|
|
386
|
+
lines.push('');
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
lines.push('```');
|
|
390
|
+
return lines.join('\n');
|
|
391
|
+
}
|
|
392
|
+
function extractRequiredFilesFromInstructions(instructions) {
|
|
393
|
+
if (!instructions) {
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
const normalized = instructions.replace(/\r\n/g, '\n');
|
|
397
|
+
const lines = normalized.split('\n');
|
|
398
|
+
const files = [];
|
|
399
|
+
for (const line of lines) {
|
|
400
|
+
const match = line.match(/^\s*FILE:\s*(.+)$/i);
|
|
401
|
+
if (!match) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const candidate = match[1]?.trim();
|
|
405
|
+
if (!candidate || isPlaceholderFileEntry(candidate)) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
files.push(candidate);
|
|
409
|
+
}
|
|
410
|
+
return Array.from(new Set(files));
|
|
411
|
+
}
|
|
412
|
+
function isPlaceholderFileEntry(value) {
|
|
413
|
+
const trimmed = value.trim();
|
|
414
|
+
if (!trimmed) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
if (/[<>]/.test(trimmed)) {
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
const lower = trimmed.toLowerCase();
|
|
421
|
+
if (lower.includes('path to update') || lower.includes('path to new file')) {
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
if (lower.includes('entire updated file')) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
if (lower.includes('focus.primary.path') || lower.includes('focus.primary')) {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
function normalizePathForCompare(value, normalize) {
|
|
433
|
+
if (!value) {
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
const canonical = canonicalizeStructuredPath(value);
|
|
437
|
+
if (!canonical) {
|
|
438
|
+
return undefined;
|
|
439
|
+
}
|
|
440
|
+
const normalized = normalize(canonical) ?? canonical;
|
|
441
|
+
return normalized.replace(/\\/g, '/').toLowerCase();
|
|
442
|
+
}
|
|
443
|
+
function reconcileRequiredPrimaryPath(requiredFileMap, primaryPath, normalize) {
|
|
444
|
+
if (requiredFileMap.size === 0) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const normalizedPrimary = normalizePathForCompare(primaryPath, normalize);
|
|
448
|
+
if (!normalizedPrimary) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (requiredFileMap.has(normalizedPrimary)) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const primaryBaseName = path.posix.basename(normalizedPrimary);
|
|
455
|
+
const candidates = Array.from(requiredFileMap.keys()).filter((key) => path.posix.basename(key) === primaryBaseName);
|
|
456
|
+
const shouldReplaceOnlyEntry = requiredFileMap.size === 1;
|
|
457
|
+
const shouldReplaceByBasename = candidates.length === 1;
|
|
458
|
+
if (!shouldReplaceOnlyEntry && !shouldReplaceByBasename) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const keyToReplace = shouldReplaceOnlyEntry
|
|
462
|
+
? Array.from(requiredFileMap.keys())[0]
|
|
463
|
+
: candidates[0];
|
|
464
|
+
if (!keyToReplace) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
requiredFileMap.delete(keyToReplace);
|
|
468
|
+
requiredFileMap.set(normalizedPrimary, primaryPath);
|
|
469
|
+
}
|
|
470
|
+
function canonicalizeStructuredPath(rawPath) {
|
|
471
|
+
let value = rawPath.trim();
|
|
472
|
+
if (!value) {
|
|
473
|
+
return '';
|
|
474
|
+
}
|
|
475
|
+
value = value.replace(/^[*-]\s+/, '');
|
|
476
|
+
const markdownLinkMatch = value.match(/^\[[^\]]+\]\((.+)\)$/);
|
|
477
|
+
if (markdownLinkMatch?.[1]) {
|
|
478
|
+
value = markdownLinkMatch[1].trim();
|
|
479
|
+
}
|
|
480
|
+
let previous = '';
|
|
481
|
+
while (value && value !== previous) {
|
|
482
|
+
previous = value;
|
|
483
|
+
value = value.replace(/[;,]+$/g, '').trim();
|
|
484
|
+
value = value.replace(/^`{1,3}(.+?)`{1,3}$/s, '$1').trim();
|
|
485
|
+
value = value.replace(/^["'](.+)["']$/s, '$1').trim();
|
|
486
|
+
value = value.replace(/^\((.+)\)$/s, '$1').trim();
|
|
487
|
+
}
|
|
488
|
+
value = value.replace(/[;,]+$/g, '').trim();
|
|
489
|
+
return value.replace(/^\.\/+/, '');
|
|
490
|
+
}
|
|
491
|
+
function reconcilePrimaryStructuredEntries(params) {
|
|
492
|
+
const { entries, primaryPath, normalizePath } = params;
|
|
493
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
const normalizedPrimary = normalizePathForCompare(primaryPath, normalizePath);
|
|
497
|
+
if (!normalizedPrimary) {
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
const primaryBaseName = path.posix.basename(normalizedPrimary);
|
|
501
|
+
const normalizedEntries = entries.map((entry, index) => {
|
|
502
|
+
const canonicalPath = canonicalizeStructuredPath(entry.path) || entry.path.trim();
|
|
503
|
+
const normalizedPath = normalizePathForCompare(canonicalPath, normalizePath);
|
|
504
|
+
const fallback = canonicalPath.replace(/\\/g, '/').toLowerCase();
|
|
505
|
+
const baseName = path.posix.basename(normalizedPath ?? fallback);
|
|
506
|
+
return {
|
|
507
|
+
index,
|
|
508
|
+
entry,
|
|
509
|
+
canonicalPath,
|
|
510
|
+
normalizedPath,
|
|
511
|
+
fallback,
|
|
512
|
+
baseName
|
|
513
|
+
};
|
|
514
|
+
});
|
|
515
|
+
const alreadyContainsPrimary = normalizedEntries.some((entry) => entry.normalizedPath === normalizedPrimary || entry.fallback === normalizedPrimary);
|
|
516
|
+
if (alreadyContainsPrimary) {
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
const suffixMatches = normalizedEntries.filter((entry) => {
|
|
520
|
+
const candidate = entry.normalizedPath ?? entry.fallback;
|
|
521
|
+
if (!candidate) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
return candidate.endsWith(`/${normalizedPrimary}`) || normalizedPrimary.endsWith(`/${candidate}`);
|
|
525
|
+
});
|
|
526
|
+
const baseNameMatches = normalizedEntries.filter((entry) => entry.baseName === primaryBaseName);
|
|
527
|
+
const target = suffixMatches.length === 1
|
|
528
|
+
? suffixMatches[0]
|
|
529
|
+
: baseNameMatches.length === 1
|
|
530
|
+
? baseNameMatches[0]
|
|
531
|
+
: normalizedEntries.length === 1
|
|
532
|
+
? normalizedEntries[0]
|
|
533
|
+
: undefined;
|
|
534
|
+
if (!target || !target.entry.content.trim()) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
return entries.map((entry, index) => {
|
|
538
|
+
if (index === target.index) {
|
|
539
|
+
return { path: primaryPath, content: entry.content };
|
|
540
|
+
}
|
|
541
|
+
const canonicalPath = canonicalizeStructuredPath(entry.path);
|
|
542
|
+
return { path: canonicalPath || entry.path, content: entry.content };
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
function buildFallbackFilesBlock(relativePath, content) {
|
|
546
|
+
return ['```files', `FILE: ${relativePath}`, content, '```'].join('\n');
|
|
547
|
+
}
|
|
548
|
+
function buildFilesBlockFromEntries(entries) {
|
|
549
|
+
const lines = ['```files'];
|
|
550
|
+
entries.forEach((entry, index) => {
|
|
551
|
+
lines.push(`FILE: ${entry.path}`);
|
|
552
|
+
lines.push(entry.content.replace(/\r\n/g, '\n').replace(/\r/g, '\n'));
|
|
553
|
+
if (index !== entries.length - 1) {
|
|
554
|
+
lines.push('');
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
lines.push('```');
|
|
558
|
+
return lines.join('\n');
|
|
559
|
+
}
|
|
560
|
+
function buildDomainExtractionFallback(params) {
|
|
561
|
+
const { primaryPath, currentContent, requiredFiles, normalizePath } = params;
|
|
562
|
+
if (!currentContent || requiredFiles.length < 2) {
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
565
|
+
const extension = getFileExtension(primaryPath);
|
|
566
|
+
if (extension === 'cs') {
|
|
567
|
+
return buildCsharpDomainExtractionFallback(params);
|
|
568
|
+
}
|
|
569
|
+
if (extension === 'ts' || extension === 'tsx') {
|
|
570
|
+
return buildTypeScriptDomainExtractionFallback(params);
|
|
571
|
+
}
|
|
572
|
+
if (extension === 'py') {
|
|
573
|
+
return buildPythonDomainExtractionFallback(params);
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
function collectDomainCandidateFiles(params) {
|
|
578
|
+
const { primaryPath, requiredFiles, normalizePath, allowedExtensions } = params;
|
|
579
|
+
const normalizedPrimary = normalizePathForCompare(primaryPath, normalizePath);
|
|
580
|
+
return requiredFiles
|
|
581
|
+
.filter((filePath) => normalizePathForCompare(filePath, normalizePath) !== normalizedPrimary)
|
|
582
|
+
.filter((filePath) => /(^|[\\/])domains[\\/]/i.test(filePath))
|
|
583
|
+
.filter((filePath) => allowedExtensions.includes(getFileExtension(filePath)));
|
|
584
|
+
}
|
|
585
|
+
function buildCsharpDomainExtractionFallback(params) {
|
|
586
|
+
const { primaryPath, currentContent, requiredFiles, normalizePath } = params;
|
|
587
|
+
const candidateFiles = collectDomainCandidateFiles({
|
|
588
|
+
primaryPath,
|
|
589
|
+
requiredFiles,
|
|
590
|
+
normalizePath,
|
|
591
|
+
allowedExtensions: ['cs']
|
|
592
|
+
});
|
|
593
|
+
if (candidateFiles.length === 0) {
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
const namespaceMatch = currentContent.match(/\bnamespace\s+([A-Za-z0-9_.]+)\b/);
|
|
597
|
+
const namespaceValue = namespaceMatch?.[1];
|
|
598
|
+
if (!namespaceValue) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
const extractions = [];
|
|
602
|
+
for (const filePath of candidateFiles) {
|
|
603
|
+
const baseName = getFileBaseName(filePath);
|
|
604
|
+
const className = baseName.replace(/\.cs$/i, '');
|
|
605
|
+
if (!className) {
|
|
606
|
+
return null;
|
|
607
|
+
}
|
|
608
|
+
const range = findClassRange(currentContent, className);
|
|
609
|
+
if (!range) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
extractions.push({
|
|
613
|
+
path: filePath,
|
|
614
|
+
range: { start: range.start, end: range.end },
|
|
615
|
+
content: buildDomainFileContent(namespaceValue, range.content)
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (extractions.length === 0) {
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
const ranges = extractions.map((entry) => entry.range).sort((a, b) => b.start - a.start);
|
|
622
|
+
let updatedContent = currentContent;
|
|
623
|
+
for (const range of ranges) {
|
|
624
|
+
updatedContent = removeRange(updatedContent, range.start, range.end);
|
|
625
|
+
}
|
|
626
|
+
updatedContent = collapseExtraBlankLines(updatedContent);
|
|
627
|
+
return [
|
|
628
|
+
{ path: primaryPath, content: updatedContent },
|
|
629
|
+
...extractions.map((entry) => ({ path: entry.path, content: entry.content }))
|
|
630
|
+
];
|
|
631
|
+
}
|
|
632
|
+
function buildTypeScriptDomainExtractionFallback(params) {
|
|
633
|
+
const { primaryPath, currentContent, requiredFiles, normalizePath } = params;
|
|
634
|
+
const candidateFiles = collectDomainCandidateFiles({
|
|
635
|
+
primaryPath,
|
|
636
|
+
requiredFiles,
|
|
637
|
+
normalizePath,
|
|
638
|
+
allowedExtensions: ['ts', 'tsx']
|
|
639
|
+
});
|
|
640
|
+
if (candidateFiles.length === 0) {
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
const importBlock = extractTypeScriptImportBlock(currentContent);
|
|
644
|
+
const extractions = [];
|
|
645
|
+
for (const filePath of candidateFiles) {
|
|
646
|
+
const baseName = getFileBaseName(filePath);
|
|
647
|
+
const className = baseName.replace(/\.(ts|tsx)$/i, '');
|
|
648
|
+
if (!className) {
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
const range = findTypeScriptDeclarationRange(currentContent, className);
|
|
652
|
+
if (!range) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
const importPath = buildRelativeImportPath(primaryPath, filePath);
|
|
656
|
+
if (!importPath) {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
extractions.push({
|
|
660
|
+
path: filePath,
|
|
661
|
+
range: { start: range.start, end: range.end },
|
|
662
|
+
content: buildTypeScriptDomainFileContent(importBlock, ensureTypeScriptExport(range.content, range.kind)),
|
|
663
|
+
name: className,
|
|
664
|
+
kind: range.kind,
|
|
665
|
+
importPath
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
if (extractions.length === 0) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
const ranges = extractions.map((entry) => entry.range).sort((a, b) => b.start - a.start);
|
|
672
|
+
let updatedContent = currentContent;
|
|
673
|
+
for (const range of ranges) {
|
|
674
|
+
updatedContent = removeRange(updatedContent, range.start, range.end);
|
|
675
|
+
}
|
|
676
|
+
updatedContent = collapseExtraBlankLines(updatedContent);
|
|
677
|
+
for (const extraction of extractions) {
|
|
678
|
+
const importLine = buildTypeScriptImportLine(extraction);
|
|
679
|
+
updatedContent = insertTypeScriptImport(updatedContent, importLine, extraction.importPath, extraction.name);
|
|
680
|
+
}
|
|
681
|
+
return [
|
|
682
|
+
{ path: primaryPath, content: updatedContent },
|
|
683
|
+
...extractions.map((entry) => ({ path: entry.path, content: entry.content }))
|
|
684
|
+
];
|
|
685
|
+
}
|
|
686
|
+
function buildPythonDomainExtractionFallback(params) {
|
|
687
|
+
const { primaryPath, currentContent, requiredFiles, normalizePath } = params;
|
|
688
|
+
const candidateFiles = collectDomainCandidateFiles({
|
|
689
|
+
primaryPath,
|
|
690
|
+
requiredFiles,
|
|
691
|
+
normalizePath,
|
|
692
|
+
allowedExtensions: ['py']
|
|
693
|
+
});
|
|
694
|
+
if (candidateFiles.length === 0) {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
const importBlock = extractPythonImportBlock(currentContent);
|
|
698
|
+
const extractions = [];
|
|
699
|
+
for (const filePath of candidateFiles) {
|
|
700
|
+
const baseName = getFileBaseName(filePath);
|
|
701
|
+
const className = fileNameToClassName(baseName.replace(/\.py$/i, ''));
|
|
702
|
+
if (!className) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
const range = findPythonClassRange(currentContent, className);
|
|
706
|
+
if (!range) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
const importLine = buildPythonImportLine(primaryPath, filePath, className);
|
|
710
|
+
if (!importLine) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
extractions.push({
|
|
714
|
+
path: filePath,
|
|
715
|
+
range: { start: range.start, end: range.end },
|
|
716
|
+
content: buildPythonDomainFileContent(importBlock, range.content),
|
|
717
|
+
name: className,
|
|
718
|
+
importLine
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
if (extractions.length === 0) {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
const ranges = extractions.map((entry) => entry.range).sort((a, b) => b.start - a.start);
|
|
725
|
+
let updatedContent = currentContent;
|
|
726
|
+
for (const range of ranges) {
|
|
727
|
+
updatedContent = removeRange(updatedContent, range.start, range.end);
|
|
728
|
+
}
|
|
729
|
+
updatedContent = collapseExtraBlankLines(updatedContent);
|
|
730
|
+
for (const extraction of extractions) {
|
|
731
|
+
updatedContent = insertPythonImport(updatedContent, extraction.importLine);
|
|
732
|
+
}
|
|
733
|
+
return [
|
|
734
|
+
{ path: primaryPath, content: updatedContent },
|
|
735
|
+
...extractions.map((entry) => ({ path: entry.path, content: entry.content }))
|
|
736
|
+
];
|
|
737
|
+
}
|
|
738
|
+
function getFileBaseName(filePath) {
|
|
739
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
740
|
+
const parts = normalized.split('/');
|
|
741
|
+
return parts[parts.length - 1] ?? normalized;
|
|
742
|
+
}
|
|
743
|
+
function toPosixPath(value) {
|
|
744
|
+
return value.replace(/\\/g, '/');
|
|
745
|
+
}
|
|
746
|
+
function buildRelativeImportPath(fromPath, toPath) {
|
|
747
|
+
const fromDir = path.posix.dirname(toPosixPath(fromPath));
|
|
748
|
+
const toFile = toPosixPath(toPath);
|
|
749
|
+
let relative = path.posix.relative(fromDir, toFile);
|
|
750
|
+
if (!relative) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
if (!relative.startsWith('.')) {
|
|
754
|
+
relative = `./${relative}`;
|
|
755
|
+
}
|
|
756
|
+
return relative.replace(/\.[^.\\/]+$/i, '');
|
|
757
|
+
}
|
|
758
|
+
function findTypeScriptDeclarationRange(source, name) {
|
|
759
|
+
const pattern = new RegExp(`(^|\\n)([\\t ]*)(?:export\\s+)?(?:declare\\s+)?(class|interface|type|enum)\\s+${escapeRegex(name)}\\b`, 'm');
|
|
760
|
+
const match = pattern.exec(source);
|
|
761
|
+
if (!match) {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
const kind = match[3];
|
|
765
|
+
const lineStart = source.lastIndexOf('\n', match.index);
|
|
766
|
+
const start = lineStart === -1 ? 0 : lineStart + 1;
|
|
767
|
+
if (kind === 'type') {
|
|
768
|
+
const equalsIndex = source.indexOf('=', match.index + match[0].length);
|
|
769
|
+
if (equalsIndex < 0) {
|
|
770
|
+
return null;
|
|
771
|
+
}
|
|
772
|
+
const endIndex = findTypeScriptStatementEnd(source, equalsIndex + 1);
|
|
773
|
+
if (endIndex === null) {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
start,
|
|
778
|
+
end: endIndex,
|
|
779
|
+
content: source.slice(start, endIndex + 1),
|
|
780
|
+
kind
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
const braceIndex = source.indexOf('{', match.index + match[0].length);
|
|
784
|
+
if (braceIndex < 0) {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
const endIndex = findBalancedBraces(source, braceIndex);
|
|
788
|
+
if (endIndex === null) {
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
return {
|
|
792
|
+
start,
|
|
793
|
+
end: endIndex,
|
|
794
|
+
content: source.slice(start, endIndex + 1),
|
|
795
|
+
kind
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function findBalancedBraces(source, openIndex) {
|
|
799
|
+
let depth = 0;
|
|
800
|
+
let inSingle = false;
|
|
801
|
+
let inDouble = false;
|
|
802
|
+
let inTemplate = false;
|
|
803
|
+
let inLineComment = false;
|
|
804
|
+
let inBlockComment = false;
|
|
805
|
+
let escaped = false;
|
|
806
|
+
for (let i = openIndex; i < source.length; i += 1) {
|
|
807
|
+
const char = source[i];
|
|
808
|
+
const next = source[i + 1];
|
|
809
|
+
if (inLineComment) {
|
|
810
|
+
if (char === '\n') {
|
|
811
|
+
inLineComment = false;
|
|
812
|
+
}
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
if (inBlockComment) {
|
|
816
|
+
if (char === '*' && next === '/') {
|
|
817
|
+
inBlockComment = false;
|
|
818
|
+
i += 1;
|
|
819
|
+
}
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
if (inSingle) {
|
|
823
|
+
if (!escaped && char === "'") {
|
|
824
|
+
inSingle = false;
|
|
825
|
+
}
|
|
826
|
+
escaped = char === '\\' && !escaped;
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
if (inDouble) {
|
|
830
|
+
if (!escaped && char === '"') {
|
|
831
|
+
inDouble = false;
|
|
832
|
+
}
|
|
833
|
+
escaped = char === '\\' && !escaped;
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (inTemplate) {
|
|
837
|
+
if (!escaped && char === '`') {
|
|
838
|
+
inTemplate = false;
|
|
839
|
+
}
|
|
840
|
+
escaped = char === '\\' && !escaped;
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
if (char === '/' && next === '/') {
|
|
844
|
+
inLineComment = true;
|
|
845
|
+
i += 1;
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (char === '/' && next === '*') {
|
|
849
|
+
inBlockComment = true;
|
|
850
|
+
i += 1;
|
|
851
|
+
continue;
|
|
852
|
+
}
|
|
853
|
+
if (char === "'") {
|
|
854
|
+
inSingle = true;
|
|
855
|
+
escaped = false;
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
if (char === '"') {
|
|
859
|
+
inDouble = true;
|
|
860
|
+
escaped = false;
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
if (char === '`') {
|
|
864
|
+
inTemplate = true;
|
|
865
|
+
escaped = false;
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
if (char === '{') {
|
|
869
|
+
depth += 1;
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
if (char === '}') {
|
|
873
|
+
depth -= 1;
|
|
874
|
+
if (depth === 0) {
|
|
875
|
+
return i;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
function findTypeScriptStatementEnd(source, startIndex) {
|
|
882
|
+
let braceDepth = 0;
|
|
883
|
+
let bracketDepth = 0;
|
|
884
|
+
let parenDepth = 0;
|
|
885
|
+
let inSingle = false;
|
|
886
|
+
let inDouble = false;
|
|
887
|
+
let inTemplate = false;
|
|
888
|
+
let inLineComment = false;
|
|
889
|
+
let inBlockComment = false;
|
|
890
|
+
let escaped = false;
|
|
891
|
+
for (let i = startIndex; i < source.length; i += 1) {
|
|
892
|
+
const char = source[i];
|
|
893
|
+
const next = source[i + 1];
|
|
894
|
+
if (inLineComment) {
|
|
895
|
+
if (char === '\n') {
|
|
896
|
+
inLineComment = false;
|
|
897
|
+
}
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if (inBlockComment) {
|
|
901
|
+
if (char === '*' && next === '/') {
|
|
902
|
+
inBlockComment = false;
|
|
903
|
+
i += 1;
|
|
904
|
+
}
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
if (inSingle) {
|
|
908
|
+
if (!escaped && char === "'") {
|
|
909
|
+
inSingle = false;
|
|
910
|
+
}
|
|
911
|
+
escaped = char === '\\' && !escaped;
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
if (inDouble) {
|
|
915
|
+
if (!escaped && char === '"') {
|
|
916
|
+
inDouble = false;
|
|
917
|
+
}
|
|
918
|
+
escaped = char === '\\' && !escaped;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (inTemplate) {
|
|
922
|
+
if (!escaped && char === '`') {
|
|
923
|
+
inTemplate = false;
|
|
924
|
+
}
|
|
925
|
+
escaped = char === '\\' && !escaped;
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
if (char === '/' && next === '/') {
|
|
929
|
+
inLineComment = true;
|
|
930
|
+
i += 1;
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
if (char === '/' && next === '*') {
|
|
934
|
+
inBlockComment = true;
|
|
935
|
+
i += 1;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
if (char === "'") {
|
|
939
|
+
inSingle = true;
|
|
940
|
+
escaped = false;
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
if (char === '"') {
|
|
944
|
+
inDouble = true;
|
|
945
|
+
escaped = false;
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
if (char === '`') {
|
|
949
|
+
inTemplate = true;
|
|
950
|
+
escaped = false;
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
if (char === '{') {
|
|
954
|
+
braceDepth += 1;
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
if (char === '}') {
|
|
958
|
+
braceDepth = Math.max(0, braceDepth - 1);
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (char === '[') {
|
|
962
|
+
bracketDepth += 1;
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
if (char === ']') {
|
|
966
|
+
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
if (char === '(') {
|
|
970
|
+
parenDepth += 1;
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
if (char === ')') {
|
|
974
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
if (char === ';' && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
978
|
+
return i;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
function ensureTypeScriptExport(content, kind) {
|
|
984
|
+
const lines = content.replace(/\r\n/g, '\n').split('\n');
|
|
985
|
+
const declarationPattern = new RegExp(`\\b${kind}\\b`);
|
|
986
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
987
|
+
const line = lines[i];
|
|
988
|
+
if (!declarationPattern.test(line)) {
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
if (/\bexport\b/.test(line)) {
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
lines[i] = line.replace(/^(\s*)/, '$1export ');
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
return lines.join('\n');
|
|
998
|
+
}
|
|
999
|
+
function extractTypeScriptImportBlock(source) {
|
|
1000
|
+
const lines = source.replace(/\r\n/g, '\n').split('\n');
|
|
1001
|
+
let firstImport = -1;
|
|
1002
|
+
let lastImport = -1;
|
|
1003
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
1004
|
+
const line = lines[i];
|
|
1005
|
+
if (/^\s*import\b/.test(line)) {
|
|
1006
|
+
if (firstImport < 0) {
|
|
1007
|
+
firstImport = i;
|
|
1008
|
+
}
|
|
1009
|
+
lastImport = i;
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
if (firstImport >= 0) {
|
|
1013
|
+
if (!line.trim() || /^\s*\/[/*]/.test(line) || /^\s*\*/.test(line)) {
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
if (!line.trim() || /^\s*\/[/*]/.test(line) || /^\s*\*/.test(line)) {
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
if (/^\s*['"]use\s+/.test(line)) {
|
|
1022
|
+
continue;
|
|
1023
|
+
}
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
if (firstImport < 0 || lastImport < firstImport) {
|
|
1027
|
+
return '';
|
|
1028
|
+
}
|
|
1029
|
+
return lines.slice(firstImport, lastImport + 1).join('\n').trimEnd();
|
|
1030
|
+
}
|
|
1031
|
+
function buildTypeScriptDomainFileContent(importBlock, declarationContent) {
|
|
1032
|
+
const parts = [];
|
|
1033
|
+
if (importBlock.trim().length > 0) {
|
|
1034
|
+
parts.push(importBlock.trimEnd());
|
|
1035
|
+
}
|
|
1036
|
+
parts.push(declarationContent.trimEnd());
|
|
1037
|
+
return `${parts.join('\n\n').trimEnd()}\n`;
|
|
1038
|
+
}
|
|
1039
|
+
function buildTypeScriptImportLine(extraction) {
|
|
1040
|
+
const typeOnly = extraction.kind === 'interface' || extraction.kind === 'type';
|
|
1041
|
+
const keyword = typeOnly ? 'import type' : 'import';
|
|
1042
|
+
return `${keyword} { ${extraction.name} } from '${extraction.importPath}';`;
|
|
1043
|
+
}
|
|
1044
|
+
function insertTypeScriptImport(source, importLine, importPath, symbolName) {
|
|
1045
|
+
if (hasTypeScriptImport(source, importPath, symbolName)) {
|
|
1046
|
+
return source;
|
|
1047
|
+
}
|
|
1048
|
+
const lines = source.replace(/\r\n/g, '\n').split('\n');
|
|
1049
|
+
const insertIndex = findTypeScriptImportInsertIndex(lines);
|
|
1050
|
+
lines.splice(insertIndex, 0, importLine);
|
|
1051
|
+
return lines.join('\n');
|
|
1052
|
+
}
|
|
1053
|
+
function hasTypeScriptImport(source, importPath, symbolName) {
|
|
1054
|
+
const normalizedPath = toPosixPath(importPath);
|
|
1055
|
+
const symbolPattern = new RegExp(`\\b${escapeRegex(symbolName)}\\b`);
|
|
1056
|
+
return source
|
|
1057
|
+
.replace(/\r\n/g, '\n')
|
|
1058
|
+
.split('\n')
|
|
1059
|
+
.some((line) => {
|
|
1060
|
+
if (!/^\s*import\b/.test(line)) {
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
const hasPath = line.includes(`'${normalizedPath}'`) ||
|
|
1064
|
+
line.includes(`"${normalizedPath}"`) ||
|
|
1065
|
+
line.includes(`'${importPath}'`) ||
|
|
1066
|
+
line.includes(`"${importPath}"`);
|
|
1067
|
+
return hasPath && symbolPattern.test(line);
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
function findTypeScriptImportInsertIndex(lines) {
|
|
1071
|
+
let lastImport = -1;
|
|
1072
|
+
let index = 0;
|
|
1073
|
+
for (; index < lines.length; index += 1) {
|
|
1074
|
+
const line = lines[index];
|
|
1075
|
+
if (/^\s*import\b/.test(line)) {
|
|
1076
|
+
lastImport = index;
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
if (lastImport >= 0) {
|
|
1080
|
+
if (!line.trim() || /^\s*\/[/*]/.test(line) || /^\s*\*/.test(line)) {
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
if (!line.trim() || /^\s*\/[/*]/.test(line) || /^\s*\*/.test(line)) {
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
if (/^\s*['"]use\s+/.test(line)) {
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
return lastImport >= 0 ? lastImport + 1 : index;
|
|
1094
|
+
}
|
|
1095
|
+
function fileNameToClassName(baseName) {
|
|
1096
|
+
const sanitized = baseName.replace(/[^A-Za-z0-9_]/g, '_');
|
|
1097
|
+
if (sanitized.includes('_')) {
|
|
1098
|
+
return sanitized
|
|
1099
|
+
.split('_')
|
|
1100
|
+
.filter(Boolean)
|
|
1101
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
1102
|
+
.join('');
|
|
1103
|
+
}
|
|
1104
|
+
if (sanitized === sanitized.toLowerCase()) {
|
|
1105
|
+
return sanitized.charAt(0).toUpperCase() + sanitized.slice(1);
|
|
1106
|
+
}
|
|
1107
|
+
return sanitized;
|
|
1108
|
+
}
|
|
1109
|
+
function findPythonClassRange(source, className) {
|
|
1110
|
+
const normalized = source.replace(/\r\n/g, '\n');
|
|
1111
|
+
const lines = normalized.split('\n');
|
|
1112
|
+
const classPattern = new RegExp(`^\\s*class\\s+${escapeRegex(className)}\\b`);
|
|
1113
|
+
let classLine = -1;
|
|
1114
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
1115
|
+
if (classPattern.test(lines[i])) {
|
|
1116
|
+
classLine = i;
|
|
1117
|
+
break;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
if (classLine < 0) {
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
const classIndent = getLineIndent(lines[classLine]);
|
|
1124
|
+
let startLine = classLine;
|
|
1125
|
+
while (startLine > 0 && /^\s*@/.test(lines[startLine - 1])) {
|
|
1126
|
+
const decoratorIndent = getLineIndent(lines[startLine - 1]);
|
|
1127
|
+
if (decoratorIndent !== classIndent) {
|
|
1128
|
+
break;
|
|
1129
|
+
}
|
|
1130
|
+
startLine -= 1;
|
|
1131
|
+
}
|
|
1132
|
+
let endLine = lines.length - 1;
|
|
1133
|
+
for (let i = classLine + 1; i < lines.length; i += 1) {
|
|
1134
|
+
const line = lines[i];
|
|
1135
|
+
if (!line.trim()) {
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
const indent = getLineIndent(line);
|
|
1139
|
+
if (indent <= classIndent && !line.trim().startsWith('#')) {
|
|
1140
|
+
endLine = i - 1;
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
const lineOffsets = buildLineOffsets(lines);
|
|
1145
|
+
const start = lineOffsets[startLine];
|
|
1146
|
+
const end = lineOffsets[endLine] + Math.max(0, lines[endLine].length - 1);
|
|
1147
|
+
return {
|
|
1148
|
+
start,
|
|
1149
|
+
end,
|
|
1150
|
+
content: normalized.slice(start, end + 1)
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function getLineIndent(line) {
|
|
1154
|
+
const match = line.match(/^\s*/);
|
|
1155
|
+
return match ? match[0].length : 0;
|
|
1156
|
+
}
|
|
1157
|
+
function buildLineOffsets(lines) {
|
|
1158
|
+
const offsets = [];
|
|
1159
|
+
let offset = 0;
|
|
1160
|
+
for (const line of lines) {
|
|
1161
|
+
offsets.push(offset);
|
|
1162
|
+
offset += line.length + 1;
|
|
1163
|
+
}
|
|
1164
|
+
return offsets;
|
|
1165
|
+
}
|
|
1166
|
+
function buildPythonImportLine(primaryPath, domainPath, className) {
|
|
1167
|
+
const primaryDir = path.posix.dirname(toPosixPath(primaryPath));
|
|
1168
|
+
const domainFile = toPosixPath(domainPath);
|
|
1169
|
+
const relative = path.posix.relative(primaryDir, domainFile);
|
|
1170
|
+
if (!relative || relative.startsWith('..')) {
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
const modulePath = relative.replace(/\.py$/i, '').split('/').join('.');
|
|
1174
|
+
const importPath = modulePath.startsWith('.') ? modulePath : `.${modulePath}`;
|
|
1175
|
+
return `from ${importPath} import ${className}`;
|
|
1176
|
+
}
|
|
1177
|
+
function extractPythonImportBlock(source) {
|
|
1178
|
+
const normalized = source.replace(/\r\n/g, '\n');
|
|
1179
|
+
const lines = normalized.split('\n');
|
|
1180
|
+
let index = 0;
|
|
1181
|
+
if (lines[0]?.startsWith('#!')) {
|
|
1182
|
+
index = 1;
|
|
1183
|
+
}
|
|
1184
|
+
const docstringEnd = findPythonDocstringEnd(lines, index);
|
|
1185
|
+
if (docstringEnd !== null) {
|
|
1186
|
+
index = docstringEnd + 1;
|
|
1187
|
+
}
|
|
1188
|
+
while (index < lines.length && !lines[index].trim()) {
|
|
1189
|
+
index += 1;
|
|
1190
|
+
}
|
|
1191
|
+
let firstImport = -1;
|
|
1192
|
+
let lastImport = -1;
|
|
1193
|
+
for (let i = index; i < lines.length; i += 1) {
|
|
1194
|
+
const line = lines[i];
|
|
1195
|
+
if (/^\s*(from|import)\s+/.test(line)) {
|
|
1196
|
+
if (firstImport < 0) {
|
|
1197
|
+
firstImport = i;
|
|
1198
|
+
}
|
|
1199
|
+
lastImport = i;
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
if (firstImport >= 0) {
|
|
1203
|
+
if (!line.trim() || /^\s*#/.test(line)) {
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
if (firstImport < 0 || lastImport < firstImport) {
|
|
1211
|
+
return '';
|
|
1212
|
+
}
|
|
1213
|
+
return lines.slice(firstImport, lastImport + 1).join('\n').trimEnd();
|
|
1214
|
+
}
|
|
1215
|
+
function buildPythonDomainFileContent(importBlock, classContent) {
|
|
1216
|
+
const normalized = normalizeIndent(classContent);
|
|
1217
|
+
const parts = [];
|
|
1218
|
+
if (importBlock.trim().length > 0) {
|
|
1219
|
+
parts.push(importBlock.trimEnd());
|
|
1220
|
+
}
|
|
1221
|
+
parts.push(normalized.trimEnd());
|
|
1222
|
+
return `${parts.join('\n\n').trimEnd()}\n`;
|
|
1223
|
+
}
|
|
1224
|
+
function insertPythonImport(source, importLine) {
|
|
1225
|
+
const normalized = source.replace(/\r\n/g, '\n');
|
|
1226
|
+
const lines = normalized.split('\n');
|
|
1227
|
+
if (lines.some((line) => line.trim() === importLine.trim())) {
|
|
1228
|
+
return source;
|
|
1229
|
+
}
|
|
1230
|
+
let index = 0;
|
|
1231
|
+
if (lines[0]?.startsWith('#!')) {
|
|
1232
|
+
index = 1;
|
|
1233
|
+
}
|
|
1234
|
+
const docstringEnd = findPythonDocstringEnd(lines, index);
|
|
1235
|
+
if (docstringEnd !== null) {
|
|
1236
|
+
index = docstringEnd + 1;
|
|
1237
|
+
}
|
|
1238
|
+
while (index < lines.length && !lines[index].trim()) {
|
|
1239
|
+
index += 1;
|
|
1240
|
+
}
|
|
1241
|
+
let insertIndex = index;
|
|
1242
|
+
let lastFuture = -1;
|
|
1243
|
+
for (let i = index; i < lines.length; i += 1) {
|
|
1244
|
+
if (/^\s*from\s+__future__\s+import\s+/.test(lines[i])) {
|
|
1245
|
+
lastFuture = i;
|
|
1246
|
+
continue;
|
|
1247
|
+
}
|
|
1248
|
+
break;
|
|
1249
|
+
}
|
|
1250
|
+
if (lastFuture >= 0) {
|
|
1251
|
+
insertIndex = lastFuture + 1;
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
let lastImport = -1;
|
|
1255
|
+
for (let i = index; i < lines.length; i += 1) {
|
|
1256
|
+
const line = lines[i];
|
|
1257
|
+
if (/^\s*(from|import)\s+/.test(line)) {
|
|
1258
|
+
lastImport = i;
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
if (lastImport >= 0 && (!line.trim() || /^\s*#/.test(line))) {
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
break;
|
|
1265
|
+
}
|
|
1266
|
+
insertIndex = lastImport >= 0 ? lastImport + 1 : index;
|
|
1267
|
+
}
|
|
1268
|
+
lines.splice(insertIndex, 0, importLine);
|
|
1269
|
+
return lines.join('\n');
|
|
1270
|
+
}
|
|
1271
|
+
function findPythonDocstringEnd(lines, startIndex) {
|
|
1272
|
+
const firstLine = lines[startIndex];
|
|
1273
|
+
if (!firstLine) {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
const trimmed = firstLine.trim();
|
|
1277
|
+
const quote = trimmed.startsWith('"""') ? '"""' : trimmed.startsWith("'''") ? "'''" : null;
|
|
1278
|
+
if (!quote) {
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
if (trimmed.length > quote.length && trimmed.includes(quote, quote.length)) {
|
|
1282
|
+
return startIndex;
|
|
1283
|
+
}
|
|
1284
|
+
for (let i = startIndex + 1; i < lines.length; i += 1) {
|
|
1285
|
+
if (lines[i].includes(quote)) {
|
|
1286
|
+
return i;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
return lines.length - 1;
|
|
1290
|
+
}
|
|
1291
|
+
function findClassRange(source, className) {
|
|
1292
|
+
const pattern = new RegExp(`\\bclass\\s+${escapeRegex(className)}\\b`);
|
|
1293
|
+
const match = pattern.exec(source);
|
|
1294
|
+
if (!match) {
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
const braceIndex = source.indexOf('{', match.index + match[0].length);
|
|
1298
|
+
if (braceIndex < 0) {
|
|
1299
|
+
return null;
|
|
1300
|
+
}
|
|
1301
|
+
let depth = 0;
|
|
1302
|
+
for (let i = braceIndex; i < source.length; i += 1) {
|
|
1303
|
+
const char = source[i];
|
|
1304
|
+
if (char === '{') {
|
|
1305
|
+
depth += 1;
|
|
1306
|
+
}
|
|
1307
|
+
else if (char === '}') {
|
|
1308
|
+
depth -= 1;
|
|
1309
|
+
if (depth === 0) {
|
|
1310
|
+
const lineStart = source.lastIndexOf('\n', match.index);
|
|
1311
|
+
const start = lineStart === -1 ? 0 : lineStart + 1;
|
|
1312
|
+
return {
|
|
1313
|
+
start,
|
|
1314
|
+
end: i,
|
|
1315
|
+
content: source.slice(start, i + 1)
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return null;
|
|
1321
|
+
}
|
|
1322
|
+
function buildDomainFileContent(namespaceValue, classContent) {
|
|
1323
|
+
const normalized = normalizeIndent(classContent);
|
|
1324
|
+
const needsCollections = /\b(List|Dictionary|HashSet|IReadOnlyList|IReadOnlyDictionary)\s*</.test(normalized);
|
|
1325
|
+
const needsSystem = /\b(DateTime|DateOnly|TimeOnly|Guid|TimeSpan|Uri)\b/.test(normalized);
|
|
1326
|
+
const headerLines = [];
|
|
1327
|
+
if (needsSystem) {
|
|
1328
|
+
headerLines.push('using System;');
|
|
1329
|
+
}
|
|
1330
|
+
if (needsCollections) {
|
|
1331
|
+
headerLines.push('using System.Collections.Generic;');
|
|
1332
|
+
}
|
|
1333
|
+
if (headerLines.length > 0) {
|
|
1334
|
+
headerLines.push('');
|
|
1335
|
+
}
|
|
1336
|
+
return [
|
|
1337
|
+
...headerLines,
|
|
1338
|
+
`namespace ${namespaceValue}`,
|
|
1339
|
+
'{',
|
|
1340
|
+
indentBlock(normalized, ' '),
|
|
1341
|
+
'}',
|
|
1342
|
+
''
|
|
1343
|
+
].join('\n');
|
|
1344
|
+
}
|
|
1345
|
+
function normalizeIndent(block) {
|
|
1346
|
+
const lines = block.replace(/\r\n/g, '\n').split('\n');
|
|
1347
|
+
const nonEmpty = lines.filter((line) => line.trim().length > 0);
|
|
1348
|
+
if (nonEmpty.length === 0) {
|
|
1349
|
+
return block.trim();
|
|
1350
|
+
}
|
|
1351
|
+
const minIndent = Math.min(...nonEmpty.map((line) => {
|
|
1352
|
+
const match = line.match(/^\s*/);
|
|
1353
|
+
return match ? match[0].length : 0;
|
|
1354
|
+
}));
|
|
1355
|
+
return lines.map((line) => line.slice(minIndent)).join('\n').trim();
|
|
1356
|
+
}
|
|
1357
|
+
function indentBlock(content, indent) {
|
|
1358
|
+
return content
|
|
1359
|
+
.split('\n')
|
|
1360
|
+
.map((line) => (line.length > 0 ? `${indent}${line}` : line))
|
|
1361
|
+
.join('\n');
|
|
1362
|
+
}
|
|
1363
|
+
function removeRange(source, start, end) {
|
|
1364
|
+
const before = source.slice(0, start);
|
|
1365
|
+
const after = source.slice(end + 1);
|
|
1366
|
+
return `${before.replace(/[ \t]*$/, '')}${after}`;
|
|
1367
|
+
}
|
|
1368
|
+
function collapseExtraBlankLines(source) {
|
|
1369
|
+
return source.replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
|
|
1370
|
+
}
|
|
1371
|
+
function escapeRegex(value) {
|
|
1372
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1373
|
+
}
|
|
1374
|
+
function extractFallbackFileContent(rawResponse, relativePath) {
|
|
1375
|
+
if (!rawResponse) {
|
|
1376
|
+
return null;
|
|
1377
|
+
}
|
|
1378
|
+
const fenced = extractLargestCodeFence(rawResponse);
|
|
1379
|
+
if (fenced) {
|
|
1380
|
+
return fenced;
|
|
1381
|
+
}
|
|
1382
|
+
const normalized = rawResponse.replace(/\r\n/g, '\n').trim();
|
|
1383
|
+
if (!normalized) {
|
|
1384
|
+
return null;
|
|
1385
|
+
}
|
|
1386
|
+
const lines = normalized.split('\n');
|
|
1387
|
+
const startIndex = findCodeStartIndex(lines, relativePath);
|
|
1388
|
+
if (startIndex >= 0) {
|
|
1389
|
+
const trimmed = lines.slice(startIndex).join('\n').trim();
|
|
1390
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1391
|
+
}
|
|
1392
|
+
const stripped = stripLeadingNarrative(lines).join('\n').trim();
|
|
1393
|
+
if (stripped.length > 0 && looksLikeSourceFile(stripped, relativePath)) {
|
|
1394
|
+
return stripped;
|
|
1395
|
+
}
|
|
1396
|
+
if (looksLikeSourceFile(normalized, relativePath)) {
|
|
1397
|
+
return normalized;
|
|
1398
|
+
}
|
|
1399
|
+
return null;
|
|
1400
|
+
}
|
|
1401
|
+
function extractLargestCodeFence(rawResponse) {
|
|
1402
|
+
const fenceRegex = /```[a-zA-Z0-9_-]*\n([\s\S]*?)\n```/g;
|
|
1403
|
+
let match = null;
|
|
1404
|
+
let best = null;
|
|
1405
|
+
let bestLength = 0;
|
|
1406
|
+
while ((match = fenceRegex.exec(rawResponse)) !== null) {
|
|
1407
|
+
const content = match[1]?.trim() ?? '';
|
|
1408
|
+
if (content.length > bestLength) {
|
|
1409
|
+
best = content;
|
|
1410
|
+
bestLength = content.length;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return bestLength > 0 ? best : null;
|
|
1414
|
+
}
|
|
1415
|
+
function stripLeadingNarrative(lines) {
|
|
1416
|
+
let index = 0;
|
|
1417
|
+
while (index < lines.length) {
|
|
1418
|
+
const line = lines[index]?.trim() ?? '';
|
|
1419
|
+
if (!line) {
|
|
1420
|
+
index += 1;
|
|
1421
|
+
continue;
|
|
1422
|
+
}
|
|
1423
|
+
if (isNarrativeLine(line)) {
|
|
1424
|
+
index += 1;
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
break;
|
|
1428
|
+
}
|
|
1429
|
+
return lines.slice(index);
|
|
1430
|
+
}
|
|
1431
|
+
function isNarrativeLine(line) {
|
|
1432
|
+
const trimmed = line.trim();
|
|
1433
|
+
if (!trimmed) {
|
|
1434
|
+
return true;
|
|
1435
|
+
}
|
|
1436
|
+
if (/^\/[/*]/.test(trimmed)) {
|
|
1437
|
+
return false;
|
|
1438
|
+
}
|
|
1439
|
+
if (/^\s*(using|namespace|public|internal|private|protected)\b/.test(trimmed)) {
|
|
1440
|
+
return false;
|
|
1441
|
+
}
|
|
1442
|
+
const lower = trimmed.toLowerCase();
|
|
1443
|
+
if (lower.startsWith('sure') || lower.startsWith('okay') || lower.startsWith('here') || lower.startsWith('plan')) {
|
|
1444
|
+
return true;
|
|
1445
|
+
}
|
|
1446
|
+
if (lower.startsWith('steps') || lower.startsWith('explanation') || lower.startsWith('changes')) {
|
|
1447
|
+
return true;
|
|
1448
|
+
}
|
|
1449
|
+
if (lower.startsWith('goal:') || lower.startsWith('project summary:') || lower.startsWith('file path:')) {
|
|
1450
|
+
return true;
|
|
1451
|
+
}
|
|
1452
|
+
if (/^return only\b/.test(lower) || /^respond only\b/.test(lower)) {
|
|
1453
|
+
return true;
|
|
1454
|
+
}
|
|
1455
|
+
if (/^[-*]\s+/.test(trimmed) || /^\d+[).]\s+/.test(trimmed)) {
|
|
1456
|
+
return true;
|
|
1457
|
+
}
|
|
1458
|
+
return false;
|
|
1459
|
+
}
|
|
1460
|
+
function findCodeStartIndex(lines, relativePath) {
|
|
1461
|
+
const ext = getFileExtension(relativePath);
|
|
1462
|
+
const patterns = getCodeStartPatterns(ext);
|
|
1463
|
+
if (patterns.length === 0) {
|
|
1464
|
+
return -1;
|
|
1465
|
+
}
|
|
1466
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
1467
|
+
const line = lines[index];
|
|
1468
|
+
if (patterns.some((pattern) => pattern.test(line))) {
|
|
1469
|
+
return index;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return -1;
|
|
1473
|
+
}
|
|
1474
|
+
function looksLikeSourceFile(content, relativePath) {
|
|
1475
|
+
const ext = getFileExtension(relativePath);
|
|
1476
|
+
if (ext === 'cs' || ext === 'csx') {
|
|
1477
|
+
return /\bnamespace\b|\bclass\b|\busing\b/.test(content);
|
|
1478
|
+
}
|
|
1479
|
+
if (ext === 'csproj') {
|
|
1480
|
+
return /<Project\b/.test(content);
|
|
1481
|
+
}
|
|
1482
|
+
if (ext === 'sln') {
|
|
1483
|
+
return /Visual Studio Solution File/i.test(content);
|
|
1484
|
+
}
|
|
1485
|
+
if (ext === 'ts' || ext === 'tsx' || ext === 'js' || ext === 'jsx') {
|
|
1486
|
+
return /\bimport\b|\bexport\b|\bfunction\b|\bclass\b/.test(content);
|
|
1487
|
+
}
|
|
1488
|
+
return content.includes('\n') && content.length > 40;
|
|
1489
|
+
}
|
|
1490
|
+
function getFileExtension(relativePath) {
|
|
1491
|
+
const parts = relativePath.split('.');
|
|
1492
|
+
if (parts.length < 2) {
|
|
1493
|
+
return '';
|
|
1494
|
+
}
|
|
1495
|
+
return parts[parts.length - 1]?.toLowerCase() ?? '';
|
|
1496
|
+
}
|
|
1497
|
+
function getCodeStartPatterns(ext) {
|
|
1498
|
+
if (ext === 'cs' || ext === 'csx') {
|
|
1499
|
+
return [
|
|
1500
|
+
/^\s*using\s+/,
|
|
1501
|
+
/^\s*namespace\s+/,
|
|
1502
|
+
/^\s*(public|internal|private|protected)\s+(class|record|interface|struct|enum)\b/,
|
|
1503
|
+
/^\s*class\s+/
|
|
1504
|
+
];
|
|
1505
|
+
}
|
|
1506
|
+
if (ext === 'csproj') {
|
|
1507
|
+
return [/^\s*<Project\b/];
|
|
1508
|
+
}
|
|
1509
|
+
if (ext === 'sln') {
|
|
1510
|
+
return [/^Microsoft Visual Studio Solution File/i];
|
|
1511
|
+
}
|
|
1512
|
+
if (ext === 'ts' || ext === 'tsx' || ext === 'js' || ext === 'jsx') {
|
|
1513
|
+
return [
|
|
1514
|
+
/^\s*import\s+/,
|
|
1515
|
+
/^\s*export\s+/,
|
|
1516
|
+
/^\s*(const|let|var|function|class|interface|type)\b/
|
|
1517
|
+
];
|
|
1518
|
+
}
|
|
1519
|
+
if (ext === 'json') {
|
|
1520
|
+
return [/^\s*[{[]/];
|
|
1521
|
+
}
|
|
1522
|
+
if (ext === 'yaml' || ext === 'yml') {
|
|
1523
|
+
return [/^\s*[A-Za-z0-9_-]+\s*:/];
|
|
1524
|
+
}
|
|
1525
|
+
return [];
|
|
1526
|
+
}
|
|
1527
|
+
//# sourceMappingURL=rewriteGenerator.js.map
|