scai 0.1.178 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -267
- package/dist/__tests__/CommitSuggesterCmd.test.js +112 -0
- package/dist/__tests__/CommitSuggesterCmd.test.js.map +1 -0
- package/dist/__tests__/EvalReportCmd.test.js +645 -0
- package/dist/__tests__/EvalReportCmd.test.js.map +1 -0
- package/dist/__tests__/ModelCmd.test.js +64 -0
- package/dist/__tests__/ModelCmd.test.js.map +1 -0
- package/dist/__tests__/agents/agentActions.test.js +345 -0
- package/dist/__tests__/agents/agentActions.test.js.map +1 -0
- package/dist/__tests__/agents/agentFeedback.test.js +118 -0
- package/dist/__tests__/agents/agentFeedback.test.js.map +1 -0
- package/dist/__tests__/agents/agentGeneralScope.test.js +74 -0
- package/dist/__tests__/agents/agentGeneralScope.test.js.map +1 -0
- package/dist/__tests__/agents/agentLoop.test.js +1723 -0
- package/dist/__tests__/agents/agentLoop.test.js.map +1 -0
- package/dist/__tests__/agents/agentPolicyState.test.js +948 -0
- package/dist/__tests__/agents/agentPolicyState.test.js.map +1 -0
- package/dist/__tests__/agents/agentReadEvidence.test.js +170 -0
- package/dist/__tests__/agents/agentReadEvidence.test.js.map +1 -0
- package/dist/__tests__/agents/agentReadPersistence.test.js +129 -0
- package/dist/__tests__/agents/agentReadPersistence.test.js.map +1 -0
- package/dist/__tests__/agents/agentResumeCheckpoint.test.js +90 -0
- package/dist/__tests__/agents/agentResumeCheckpoint.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchBatchPlanner.test.js +289 -0
- package/dist/__tests__/agents/agentSearchBatchPlanner.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchOwnership.test.js +166 -0
- package/dist/__tests__/agents/agentSearchOwnership.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchRanking.test.js +139 -0
- package/dist/__tests__/agents/agentSearchRanking.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchRouting.test.js +584 -0
- package/dist/__tests__/agents/agentSearchRouting.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchScoring.test.js +23 -0
- package/dist/__tests__/agents/agentSearchScoring.test.js.map +1 -0
- package/dist/__tests__/agents/agentSearchShared.test.js +78 -0
- package/dist/__tests__/agents/agentSearchShared.test.js.map +1 -0
- package/dist/__tests__/agents/agentStateMachine.test.js +58 -0
- package/dist/__tests__/agents/agentStateMachine.test.js.map +1 -0
- package/dist/__tests__/agents/agentTaskPersistence.test.js +156 -0
- package/dist/__tests__/agents/agentTaskPersistence.test.js.map +1 -0
- package/dist/__tests__/agents/agentTools.test.js +69 -0
- package/dist/__tests__/agents/agentTools.test.js.map +1 -0
- package/dist/__tests__/agents/agentTransform.test.js +779 -0
- package/dist/__tests__/agents/agentTransform.test.js.map +1 -0
- package/dist/__tests__/agents/analysisPlanGenStep.test.js +157 -0
- package/dist/__tests__/agents/analysisPlanGenStep.test.js.map +1 -0
- package/dist/__tests__/agents/answerOnlyCompletion.test.js +75 -0
- package/dist/__tests__/agents/answerOnlyCompletion.test.js.map +1 -0
- package/dist/__tests__/agents/decideNextAction.test.js +1662 -0
- package/dist/__tests__/agents/decideNextAction.test.js.map +1 -0
- package/dist/__tests__/agents/deriveFocusFromSearchStep.test.js +258 -0
- package/dist/__tests__/agents/deriveFocusFromSearchStep.test.js.map +1 -0
- package/dist/__tests__/agents/evidenceVerifierStep.test.js +113 -0
- package/dist/__tests__/agents/evidenceVerifierStep.test.js.map +1 -0
- package/dist/__tests__/agents/executionPolicyResolver.test.js +208 -0
- package/dist/__tests__/agents/executionPolicyResolver.test.js.map +1 -0
- package/dist/__tests__/agents/fileCheckStep.test.js +299 -0
- package/dist/__tests__/agents/fileCheckStep.test.js.map +1 -0
- package/dist/__tests__/agents/giveUpEvaluatorStep.test.js +35 -0
- package/dist/__tests__/agents/giveUpEvaluatorStep.test.js.map +1 -0
- package/dist/__tests__/agents/guardState.test.js +297 -0
- package/dist/__tests__/agents/guardState.test.js.map +1 -0
- package/dist/__tests__/agents/mainAgentHeuristics.test.js +72 -0
- package/dist/__tests__/agents/mainAgentHeuristics.test.js.map +1 -0
- package/dist/__tests__/agents/objectiveEvaluatorStep.test.js +60 -0
- package/dist/__tests__/agents/objectiveEvaluatorStep.test.js.map +1 -0
- package/dist/__tests__/agents/outerLoopRecoveryEvaluator.test.js +207 -0
- package/dist/__tests__/agents/outerLoopRecoveryEvaluator.test.js.map +1 -0
- package/dist/__tests__/agents/prompting.test.js +363 -0
- package/dist/__tests__/agents/prompting.test.js.map +1 -0
- package/dist/__tests__/agents/readinessGateStep.test.js +180 -0
- package/dist/__tests__/agents/readinessGateStep.test.js.map +1 -0
- package/dist/__tests__/agents/reasonNextStep.test.js +56 -0
- package/dist/__tests__/agents/reasonNextStep.test.js.map +1 -0
- package/dist/__tests__/agents/reasonNextTaskStep.test.js +284 -0
- package/dist/__tests__/agents/reasonNextTaskStep.test.js.map +1 -0
- package/dist/__tests__/agents/resolveAgentTargetClassification.test.js +170 -0
- package/dist/__tests__/agents/resolveAgentTargetClassification.test.js.map +1 -0
- package/dist/__tests__/agents/resolveProgressState.test.js +526 -0
- package/dist/__tests__/agents/resolveProgressState.test.js.map +1 -0
- package/dist/__tests__/agents/resumeCheckpoint.test.js +50 -0
- package/dist/__tests__/agents/resumeCheckpoint.test.js.map +1 -0
- package/dist/__tests__/agents/routingDecisionStep.test.js +134 -0
- package/dist/__tests__/agents/routingDecisionStep.test.js.map +1 -0
- package/dist/__tests__/agents/scopeClassificationStep.test.js +118 -0
- package/dist/__tests__/agents/scopeClassificationStep.test.js.map +1 -0
- package/dist/__tests__/agents/searchContext.test.js +97 -0
- package/dist/__tests__/agents/searchContext.test.js.map +1 -0
- package/dist/__tests__/agents/selectRelevantSourcesStep.test.js +73 -0
- package/dist/__tests__/agents/selectRelevantSourcesStep.test.js.map +1 -0
- package/dist/__tests__/agents/structuredOutput.test.js +45 -0
- package/dist/__tests__/agents/structuredOutput.test.js.map +1 -0
- package/dist/__tests__/agents/transformPlanGenStep.fallback.test.js +59 -0
- package/dist/__tests__/agents/transformPlanGenStep.fallback.test.js.map +1 -0
- package/dist/__tests__/agents/transformPlanGenStep.test.js +92 -0
- package/dist/__tests__/agents/transformPlanGenStep.test.js.map +1 -0
- package/dist/__tests__/agents/understandIntentStep.test.js +237 -0
- package/dist/__tests__/agents/understandIntentStep.test.js.map +1 -0
- package/dist/__tests__/agents/understandResumeContext.test.js +65 -0
- package/dist/__tests__/agents/understandResumeContext.test.js.map +1 -0
- package/dist/__tests__/agents/understandScope.test.js +227 -0
- package/dist/__tests__/agents/understandScope.test.js.map +1 -0
- package/dist/__tests__/agents/validateChangesStep.test.js +52 -0
- package/dist/__tests__/agents/validateChangesStep.test.js.map +1 -0
- package/dist/__tests__/askCommandTaskBinding.test.js +176 -0
- package/dist/__tests__/askCommandTaskBinding.test.js.map +1 -0
- package/dist/__tests__/commandVisibility.test.js +25 -0
- package/dist/__tests__/commandVisibility.test.js.map +1 -0
- package/dist/__tests__/config.devOutput.test.js +82 -0
- package/dist/__tests__/config.devOutput.test.js.map +1 -0
- package/dist/__tests__/currentContext.test.js +43 -0
- package/dist/__tests__/currentContext.test.js.map +1 -0
- package/dist/__tests__/daemonWorker.test.js +51 -0
- package/dist/__tests__/daemonWorker.test.js.map +1 -0
- package/dist/__tests__/dialogState.test.js +113 -0
- package/dist/__tests__/dialogState.test.js.map +1 -0
- package/dist/__tests__/evalCommands.test.js +506 -0
- package/dist/__tests__/evalCommands.test.js.map +1 -0
- package/dist/__tests__/evalCommandsSummary.test.js +68 -0
- package/dist/__tests__/evalCommandsSummary.test.js.map +1 -0
- package/dist/__tests__/example.test.js +1 -0
- package/dist/__tests__/example.test.js.map +1 -0
- package/dist/__tests__/factory.commitCommand.test.js +45 -0
- package/dist/__tests__/factory.commitCommand.test.js.map +1 -0
- package/dist/__tests__/factory.devOutputCommand.test.js +122 -0
- package/dist/__tests__/factory.devOutputCommand.test.js.map +1 -0
- package/dist/__tests__/factory.evalCommands.test.js +38 -0
- package/dist/__tests__/factory.evalCommands.test.js.map +1 -0
- package/dist/__tests__/factory.planCommand.test.js +35 -0
- package/dist/__tests__/factory.planCommand.test.js.map +1 -0
- package/dist/__tests__/factory.setupCommand.test.js +34 -0
- package/dist/__tests__/factory.setupCommand.test.js.map +1 -0
- package/dist/__tests__/factory.statusCommand.test.js +54 -0
- package/dist/__tests__/factory.statusCommand.test.js.map +1 -0
- package/dist/__tests__/fileRules/queryTokenRules.test.js +35 -0
- package/dist/__tests__/fileRules/queryTokenRules.test.js.map +1 -0
- package/dist/__tests__/fileRules/searchPathClassification.test.js +57 -0
- package/dist/__tests__/fileRules/searchPathClassification.test.js.map +1 -0
- package/dist/__tests__/generate.ollamaRecovery.test.js +344 -0
- package/dist/__tests__/generate.ollamaRecovery.test.js.map +1 -0
- package/dist/__tests__/index.modelStartup.test.js +24 -0
- package/dist/__tests__/index.modelStartup.test.js.map +1 -0
- package/dist/__tests__/indexCmd.test.js +85 -0
- package/dist/__tests__/indexCmd.test.js.map +1 -0
- package/dist/__tests__/indexSlashCommand.test.js +50 -0
- package/dist/__tests__/indexSlashCommand.test.js.map +1 -0
- package/dist/__tests__/ollamaService.test.js +103 -0
- package/dist/__tests__/ollamaService.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/codeTransformModule.small-file.test.js +68 -0
- package/dist/__tests__/pipeline/modules/codeTransformModule.small-file.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/commitSuggesterModule.test.js +68 -0
- package/dist/__tests__/pipeline/modules/commitSuggesterModule.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/fileSearchModule.test.js +284 -0
- package/dist/__tests__/pipeline/modules/fileSearchModule.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/finalAnswerModule.test.js +1139 -0
- package/dist/__tests__/pipeline/modules/finalAnswerModule.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/readFileModule.test.js +146 -0
- package/dist/__tests__/pipeline/modules/readFileModule.test.js.map +1 -0
- package/dist/__tests__/pipeline/modules/semanticAnalysisModule.test.js +192 -0
- package/dist/__tests__/pipeline/modules/semanticAnalysisModule.test.js.map +1 -0
- package/dist/__tests__/repoIdentity.test.js +31 -0
- package/dist/__tests__/repoIdentity.test.js.map +1 -0
- package/dist/__tests__/resumeContext.test.js +87 -0
- package/dist/__tests__/resumeContext.test.js.map +1 -0
- package/dist/__tests__/resumeState.test.js +239 -0
- package/dist/__tests__/resumeState.test.js.map +1 -0
- package/dist/__tests__/search/SearchOrchestrator.test.js +836 -0
- package/dist/__tests__/search/SearchOrchestrator.test.js.map +1 -0
- package/dist/__tests__/shellDialogUi.test.js +52 -0
- package/dist/__tests__/shellDialogUi.test.js.map +1 -0
- package/dist/__tests__/shellSession.test.js +102 -0
- package/dist/__tests__/shellSession.test.js.map +1 -0
- package/dist/__tests__/statusOwner.test.js +215 -0
- package/dist/__tests__/statusOwner.test.js.map +1 -0
- package/dist/__tests__/testing/contextEval.test.js +244 -0
- package/dist/__tests__/testing/contextEval.test.js.map +1 -0
- package/dist/__tests__/testing/harnessArtifacts.test.js +124 -0
- package/dist/__tests__/testing/harnessArtifacts.test.js.map +1 -0
- package/dist/__tests__/testing/llmTraceSession.test.js +67 -0
- package/dist/__tests__/testing/llmTraceSession.test.js.map +1 -0
- package/dist/__tests__/testing/registerDevCliCommands.test.js +35 -0
- package/dist/__tests__/testing/registerDevCliCommands.test.js.map +1 -0
- package/dist/__tests__/testing/runDiagnosis.test.js +159 -0
- package/dist/__tests__/testing/runDiagnosis.test.js.map +1 -0
- package/dist/__tests__/testing/runtimeLogReader.test.js +66 -0
- package/dist/__tests__/testing/runtimeLogReader.test.js.map +1 -0
- package/dist/__tests__/testing/testCommands.test.js +53 -0
- package/dist/__tests__/testing/testCommands.test.js.map +1 -0
- package/dist/__tests__/utils/compileSearchQuery.test.js +38 -0
- package/dist/__tests__/utils/compileSearchQuery.test.js.map +1 -0
- package/dist/__tests__/utils/consolePresentation.test.js +105 -0
- package/dist/__tests__/utils/consolePresentation.test.js.map +1 -0
- package/dist/__tests__/utils/extractFileReferences.test.js +41 -0
- package/dist/__tests__/utils/extractFileReferences.test.js.map +1 -0
- package/dist/__tests__/utils/log.test.js +34 -0
- package/dist/__tests__/utils/log.test.js.map +1 -0
- package/dist/__tests__/utils/runtimeLogger.test.js +200 -0
- package/dist/__tests__/utils/runtimeLogger.test.js.map +1 -0
- package/dist/__tests__/utils/spinner.test.js +31 -0
- package/dist/__tests__/utils/spinner.test.js.map +1 -0
- package/dist/__tests__/utils/verifyFocusPreference.test.js +41 -0
- package/dist/__tests__/utils/verifyFocusPreference.test.js.map +1 -0
- package/dist/agent/actions/index.js +301 -0
- package/dist/agent/actions/index.js.map +1 -0
- package/dist/agent/actions/normalize.js +360 -0
- package/dist/agent/actions/normalize.js.map +1 -0
- package/dist/agent/actions/schemas.js +129 -0
- package/dist/agent/actions/schemas.js.map +1 -0
- package/dist/agent/evidence/index.js +320 -0
- package/dist/agent/evidence/index.js.map +1 -0
- package/dist/agent/feedback/index.js +187 -0
- package/dist/agent/feedback/index.js.map +1 -0
- package/dist/agent/finalization/index.js +35 -0
- package/dist/agent/finalization/index.js.map +1 -0
- package/dist/agent/index.js +126 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/logging/index.js +350 -0
- package/dist/agent/logging/index.js.map +1 -0
- package/dist/agent/persistence/boot.js +58 -0
- package/dist/agent/persistence/boot.js.map +1 -0
- package/dist/agent/persistence/currentTask.js +36 -0
- package/dist/agent/persistence/currentTask.js.map +1 -0
- package/dist/agent/persistence/hydrate.js +42 -0
- package/dist/agent/persistence/hydrate.js.map +1 -0
- package/dist/agent/persistence/index.js +15 -0
- package/dist/agent/persistence/index.js.map +1 -0
- package/dist/agent/persistence/snapshots.js +97 -0
- package/dist/agent/persistence/snapshots.js.map +1 -0
- package/dist/agent/persistence/steps.js +95 -0
- package/dist/agent/persistence/steps.js.map +1 -0
- package/dist/agent/persistence/tasks.js +195 -0
- package/dist/agent/persistence/tasks.js.map +1 -0
- package/dist/agent/persistence/turns.js +92 -0
- package/dist/agent/persistence/turns.js.map +1 -0
- package/dist/agent/policy/ambiguityResolution.js +226 -0
- package/dist/agent/policy/ambiguityResolution.js.map +1 -0
- package/dist/agent/policy/contracts.js +2 -0
- package/dist/agent/policy/contracts.js.map +1 -0
- package/dist/agent/policy/coveragePolicy.js +309 -0
- package/dist/agent/policy/coveragePolicy.js.map +1 -0
- package/dist/agent/policy/endDecisionPolicy.js +31 -0
- package/dist/agent/policy/endDecisionPolicy.js.map +1 -0
- package/dist/agent/policy/index.js +344 -0
- package/dist/agent/policy/index.js.map +1 -0
- package/dist/agent/policy/loopReview.js +778 -0
- package/dist/agent/policy/loopReview.js.map +1 -0
- package/dist/agent/policy/readinessPolicy.js +108 -0
- package/dist/agent/policy/readinessPolicy.js.map +1 -0
- package/dist/agent/policy/resolutionPipeline.js +356 -0
- package/dist/agent/policy/resolutionPipeline.js.map +1 -0
- package/dist/agent/policy/targetClassification.js +33 -0
- package/dist/agent/policy/targetClassification.js.map +1 -0
- package/dist/agent/prompting/actionChoice.js +90 -0
- package/dist/agent/prompting/actionChoice.js.map +1 -0
- package/dist/agent/prompting/finalAnswer.js +38 -0
- package/dist/agent/prompting/finalAnswer.js.map +1 -0
- package/dist/agent/prompting/index.js +14 -0
- package/dist/agent/prompting/index.js.map +1 -0
- package/dist/agent/prompting/plan.js +59 -0
- package/dist/agent/prompting/plan.js.map +1 -0
- package/dist/agent/prompting/transform.js +175 -0
- package/dist/agent/prompting/transform.js.map +1 -0
- package/dist/agent/prompting/understand.js +70 -0
- package/dist/agent/prompting/understand.js.map +1 -0
- package/dist/agent/read/freshness.js +29 -0
- package/dist/agent/read/freshness.js.map +1 -0
- package/dist/agent/read/fullReadPrompt.js +43 -0
- package/dist/agent/read/fullReadPrompt.js.map +1 -0
- package/dist/agent/read/index.js +140 -0
- package/dist/agent/read/index.js.map +1 -0
- package/dist/agent/read/persistence.js +88 -0
- package/dist/agent/read/persistence.js.map +1 -0
- package/dist/agent/read/summarizeReadEvidence.js +733 -0
- package/dist/agent/read/summarizeReadEvidence.js.map +1 -0
- package/dist/agent/read/targetResolution.js +126 -0
- package/dist/agent/read/targetResolution.js.map +1 -0
- package/dist/agent/resume/checkpoint.js +41 -0
- package/dist/agent/resume/checkpoint.js.map +1 -0
- package/dist/agent/runtime/lifecycle.js +67 -0
- package/dist/agent/runtime/lifecycle.js.map +1 -0
- package/dist/agent/runtime/progress.js +178 -0
- package/dist/agent/runtime/progress.js.map +1 -0
- package/dist/agent/runtime/runAgentLoop.js +402 -0
- package/dist/agent/runtime/runAgentLoop.js.map +1 -0
- package/dist/agent/runtime/runAgentPlanOnly.js +127 -0
- package/dist/agent/runtime/runAgentPlanOnly.js.map +1 -0
- package/dist/agent/runtime/understand.js +336 -0
- package/dist/agent/runtime/understand.js.map +1 -0
- package/dist/agent/search/batchPlanner.js +274 -0
- package/dist/agent/search/batchPlanner.js.map +1 -0
- package/dist/agent/search/candidateRetentionPolicy.js +184 -0
- package/dist/agent/search/candidateRetentionPolicy.js.map +1 -0
- package/dist/agent/search/directory.js +51 -0
- package/dist/agent/search/directory.js.map +1 -0
- package/dist/agent/search/exactTarget.js +151 -0
- package/dist/agent/search/exactTarget.js.map +1 -0
- package/dist/agent/search/fragment.js +110 -0
- package/dist/agent/search/fragment.js.map +1 -0
- package/dist/agent/search/index.js +166 -0
- package/dist/agent/search/index.js.map +1 -0
- package/dist/agent/search/laneClassifier.js +119 -0
- package/dist/agent/search/laneClassifier.js.map +1 -0
- package/dist/agent/search/limits.js +10 -0
- package/dist/agent/search/limits.js.map +1 -0
- package/dist/agent/search/ranking.js +22 -0
- package/dist/agent/search/ranking.js.map +1 -0
- package/dist/agent/search/regex.js +83 -0
- package/dist/agent/search/regex.js.map +1 -0
- package/dist/agent/search/routePolicy.js +11 -0
- package/dist/agent/search/routePolicy.js.map +1 -0
- package/dist/agent/search/searchContext.js +128 -0
- package/dist/agent/search/searchContext.js.map +1 -0
- package/dist/agent/search/semantic.js +113 -0
- package/dist/agent/search/semantic.js.map +1 -0
- package/dist/agent/search/semanticIndexSearch.js +202 -0
- package/dist/agent/search/semanticIndexSearch.js.map +1 -0
- package/dist/agent/search/shared.js +283 -0
- package/dist/agent/search/shared.js.map +1 -0
- package/dist/agent/search/shell.js +202 -0
- package/dist/agent/search/shell.js.map +1 -0
- package/dist/agent/search/snippetEvidence.js +57 -0
- package/dist/agent/search/snippetEvidence.js.map +1 -0
- package/dist/agent/search/types.js +2 -0
- package/dist/agent/search/types.js.map +1 -0
- package/dist/agent/state/index.js +99 -0
- package/dist/agent/state/index.js.map +1 -0
- package/dist/agent/state/memory.js +56 -0
- package/dist/agent/state/memory.js.map +1 -0
- package/dist/agent/structuredOutput/index.js +28 -0
- package/dist/agent/structuredOutput/index.js.map +1 -0
- package/dist/agent/tools/index.js +199 -0
- package/dist/agent/tools/index.js.map +1 -0
- package/dist/agent/transform/index.js +519 -0
- package/dist/agent/transform/index.js.map +1 -0
- package/dist/agent/transform/syntax.js +49 -0
- package/dist/agent/transform/syntax.js.map +1 -0
- package/dist/agent/types.js +20 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/agents/actionRegistry.js +114 -0
- package/dist/agents/actionRegistry.js.map +1 -0
- package/dist/agents/agent.js +5 -0
- package/dist/agents/agent.js.map +1 -0
- package/dist/agents/agentActions.js +5 -0
- package/dist/agents/agentActions.js.map +1 -0
- package/dist/agents/agentEvidence.js +5 -0
- package/dist/agents/agentEvidence.js.map +1 -0
- package/dist/agents/agentFeedback.js +5 -0
- package/dist/agents/agentFeedback.js.map +1 -0
- package/dist/agents/agentLogging.js +5 -0
- package/dist/agents/agentLogging.js.map +1 -0
- package/dist/agents/agentLoop.js +5 -0
- package/dist/agents/agentLoop.js.map +1 -0
- package/dist/agents/agentMemory.js +5 -0
- package/dist/agents/agentMemory.js.map +1 -0
- package/dist/agents/agentPlanMode.js +5 -0
- package/dist/agents/agentPlanMode.js.map +1 -0
- package/dist/agents/agentPolicyState.js +5 -0
- package/dist/agents/agentPolicyState.js.map +1 -0
- package/dist/agents/agentProgress.js +93 -0
- package/dist/agents/agentProgress.js.map +1 -0
- package/dist/agents/agentSchemas.js +5 -0
- package/dist/agents/agentSchemas.js.map +1 -0
- package/dist/agents/agentSearchScoring.js +5 -0
- package/dist/agents/agentSearchScoring.js.map +1 -0
- package/dist/agents/agentStateMachine.js +5 -0
- package/dist/agents/agentStateMachine.js.map +1 -0
- package/dist/agents/agentTools.js +5 -0
- package/dist/agents/agentTools.js.map +1 -0
- package/dist/agents/agentTypes.js +5 -0
- package/dist/agents/agentTypes.js.map +1 -0
- package/dist/agents/agentUnderstand.js +5 -0
- package/dist/agents/agentUnderstand.js.map +1 -0
- package/dist/agents/analysisPlanGenStep.js +194 -17
- package/dist/agents/analysisPlanGenStep.js.map +1 -0
- package/dist/agents/answerOnlyCompletion.js +32 -0
- package/dist/agents/answerOnlyCompletion.js.map +1 -0
- package/dist/agents/collaboratorStep.js +1 -0
- package/dist/agents/collaboratorStep.js.map +1 -0
- package/dist/agents/decideNextAction.js +444 -0
- package/dist/agents/decideNextAction.js.map +1 -0
- package/dist/agents/deriveFocusFromSearchStep.js +83 -0
- package/dist/agents/deriveFocusFromSearchStep.js.map +1 -0
- package/dist/agents/evidenceVerifierStep.js +104 -13
- package/dist/agents/evidenceVerifierStep.js.map +1 -0
- package/dist/agents/fileCheckStep.js +381 -12
- package/dist/agents/fileCheckStep.js.map +1 -0
- package/dist/agents/giveUpEvaluatorStep.js +63 -0
- package/dist/agents/giveUpEvaluatorStep.js.map +1 -0
- package/dist/agents/guardPolicy.js +20 -0
- package/dist/agents/guardPolicy.js.map +1 -0
- package/dist/agents/guards/executionPolicyResolver.js +165 -0
- package/dist/agents/guards/executionPolicyResolver.js.map +1 -0
- package/dist/agents/guards/guardState.js +195 -0
- package/dist/agents/guards/guardState.js.map +1 -0
- package/dist/agents/guards/resolveProgressState.js +403 -0
- package/dist/agents/guards/resolveProgressState.js.map +1 -0
- package/dist/agents/infoPlanGenStep.js +66 -8
- package/dist/agents/infoPlanGenStep.js.map +1 -0
- package/dist/agents/integrateFeedbackStep.js +1 -0
- package/dist/agents/integrateFeedbackStep.js.map +1 -0
- package/dist/agents/iterationFileSelector.js +8 -7
- package/dist/agents/iterationFileSelector.js.map +1 -0
- package/dist/agents/mainAgentActivityLog.js +85 -0
- package/dist/agents/mainAgentActivityLog.js.map +1 -0
- package/dist/agents/mainAgentHeuristics.js +173 -0
- package/dist/agents/mainAgentHeuristics.js.map +1 -0
- package/dist/agents/mainAgentVerify.js +159 -0
- package/dist/agents/mainAgentVerify.js.map +1 -0
- package/dist/agents/objectiveEvaluatorStep.js +103 -0
- package/dist/agents/objectiveEvaluatorStep.js.map +1 -0
- package/dist/agents/outerLoopRecoveryEvaluator.js +108 -0
- package/dist/agents/outerLoopRecoveryEvaluator.js.map +1 -0
- package/dist/agents/readinessGateStep.js +95 -9
- package/dist/agents/readinessGateStep.js.map +1 -0
- package/dist/agents/reasonNextStep.js +9 -8
- package/dist/agents/reasonNextStep.js.map +1 -0
- package/dist/agents/reasonNextTaskStep.js +267 -144
- package/dist/agents/reasonNextTaskStep.js.map +1 -0
- package/dist/agents/researchPlanGenStep.js +61 -25
- package/dist/agents/researchPlanGenStep.js.map +1 -0
- package/dist/agents/resolveAgentTargetClassification.js +5 -0
- package/dist/agents/resolveAgentTargetClassification.js.map +1 -0
- package/dist/agents/resolveExecutionModeStep.js +1 -0
- package/dist/agents/resolveExecutionModeStep.js.map +1 -0
- package/dist/agents/resolveExplicitTargetsStep.js +74 -0
- package/dist/agents/resolveExplicitTargetsStep.js.map +1 -0
- package/dist/agents/routingDecisionStep.js +58 -11
- package/dist/agents/routingDecisionStep.js.map +1 -0
- package/dist/agents/scopeClassificationStep.js +66 -3
- package/dist/agents/scopeClassificationStep.js.map +1 -0
- package/dist/agents/selectRelevantSourcesStep.js +13 -5
- package/dist/agents/selectRelevantSourcesStep.js.map +1 -0
- package/dist/agents/structuralPreloadStep.js +3 -4
- package/dist/agents/structuralPreloadStep.js.map +1 -0
- package/dist/agents/transformPlanGenStep.js +105 -18
- package/dist/agents/transformPlanGenStep.js.map +1 -0
- package/dist/agents/understandIntentStep.js +237 -17
- package/dist/agents/understandIntentStep.js.map +1 -0
- package/dist/agents/validateChangesStep.js +16 -2
- package/dist/agents/validateChangesStep.js.map +1 -0
- package/dist/agents/writeFileStep.js +1 -0
- package/dist/agents/writeFileStep.js.map +1 -0
- package/dist/commands/AskCmd.js +139 -44
- package/dist/commands/AskCmd.js.map +1 -0
- package/dist/commands/BackupCmd.js +1 -0
- package/dist/commands/BackupCmd.js.map +1 -0
- package/dist/commands/ChangeLogUpdateCmd.js +1 -0
- package/dist/commands/ChangeLogUpdateCmd.js.map +1 -0
- package/dist/commands/CommitSuggesterCmd.js +55 -13
- package/dist/commands/CommitSuggesterCmd.js.map +1 -0
- package/dist/commands/DaemonCmd.js +52 -14
- package/dist/commands/DaemonCmd.js.map +1 -0
- package/dist/commands/DeleteIndex.js +1 -0
- package/dist/commands/DeleteIndex.js.map +1 -0
- package/dist/commands/EvalReportCmd.js +374 -0
- package/dist/commands/EvalReportCmd.js.map +1 -0
- package/dist/commands/FindCmd.js +1 -0
- package/dist/commands/FindCmd.js.map +1 -0
- package/dist/commands/GitCmd.js +1 -0
- package/dist/commands/GitCmd.js.map +1 -0
- package/dist/commands/IndexCmd.js +11 -79
- package/dist/commands/IndexCmd.js.map +1 -0
- package/dist/commands/InspectCmd.js +1 -0
- package/dist/commands/InspectCmd.js.map +1 -0
- package/dist/commands/ModelCmd.js +24 -0
- package/dist/commands/ModelCmd.js.map +1 -0
- package/dist/commands/ReadlineSingleton.js +1 -0
- package/dist/commands/ReadlineSingleton.js.map +1 -0
- package/dist/commands/ResetDbCmd.js +18 -1
- package/dist/commands/ResetDbCmd.js.map +1 -0
- package/dist/commands/ReviewCmd.js +1 -0
- package/dist/commands/ReviewCmd.js.map +1 -0
- package/dist/commands/StatusCmd.js +22 -0
- package/dist/commands/StatusCmd.js.map +1 -0
- package/dist/commands/StopDaemonCmd.js +1 -0
- package/dist/commands/StopDaemonCmd.js.map +1 -0
- package/dist/commands/SummaryCmd.js +1 -0
- package/dist/commands/SummaryCmd.js.map +1 -0
- package/dist/commands/SwitchCmd.js +9 -15
- package/dist/commands/SwitchCmd.js.map +1 -0
- package/dist/commands/TasksCmd.js +142 -57
- package/dist/commands/TasksCmd.js.map +1 -0
- package/dist/commands/TestCmd.js +66 -0
- package/dist/commands/TestCmd.js.map +1 -0
- package/dist/commands/WorkflowCmd.js +1 -0
- package/dist/commands/WorkflowCmd.js.map +1 -0
- package/dist/commands/commandVisibility.js +27 -0
- package/dist/commands/commandVisibility.js.map +1 -0
- package/dist/commands/evalCommands.js +1337 -0
- package/dist/commands/evalCommands.js.map +1 -0
- package/dist/commands/factory.js +206 -38
- package/dist/commands/factory.js.map +1 -0
- package/dist/config.js +62 -11
- package/dist/config.js.map +1 -0
- package/dist/constants.js +21 -3
- package/dist/constants.js.map +1 -0
- package/dist/context.js +33 -32
- package/dist/context.js.map +1 -0
- package/dist/daemon/daemonQueues.js +1 -20
- package/dist/daemon/daemonQueues.js.map +1 -0
- package/dist/daemon/daemonWorker.js +26 -37
- package/dist/daemon/daemonWorker.js.map +1 -0
- package/dist/daemon/generateSummaries.js +1 -0
- package/dist/daemon/generateSummaries.js.map +1 -0
- package/dist/daemon/runFolderCapsuleBatch.js +1 -0
- package/dist/daemon/runFolderCapsuleBatch.js.map +1 -0
- package/dist/daemon/runIndexingBatch.js +1 -0
- package/dist/daemon/runIndexingBatch.js.map +1 -0
- package/dist/daemon/runKgBatch.js +9 -1
- package/dist/daemon/runKgBatch.js.map +1 -0
- package/dist/db/backup.js +1 -0
- package/dist/db/backup.js.map +1 -0
- package/dist/db/client.js +18 -3
- package/dist/db/client.js.map +1 -0
- package/dist/db/fileIndex.js +110 -152
- package/dist/db/fileIndex.js.map +1 -0
- package/dist/db/functionExtractors/extractFromJava.js +1 -0
- package/dist/db/functionExtractors/extractFromJava.js.map +1 -0
- package/dist/db/functionExtractors/extractFromJs.js +1 -0
- package/dist/db/functionExtractors/extractFromJs.js.map +1 -0
- package/dist/db/functionExtractors/extractFromTs.js +1 -0
- package/dist/db/functionExtractors/extractFromTs.js.map +1 -0
- package/dist/db/functionExtractors/extractFromXML.js +1 -0
- package/dist/db/functionExtractors/extractFromXML.js.map +1 -0
- package/dist/db/functionExtractors/index.js +1 -0
- package/dist/db/functionExtractors/index.js.map +1 -0
- package/dist/db/functionIndex.js +9 -0
- package/dist/db/functionIndex.js.map +1 -0
- package/dist/db/schema.js +314 -99
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sqlTemplates.js +1 -0
- package/dist/db/sqlTemplates.js.map +1 -0
- package/dist/fileRules/builtins.js +1 -0
- package/dist/fileRules/builtins.js.map +1 -0
- package/dist/fileRules/classifyFile.js +1 -0
- package/dist/fileRules/classifyFile.js.map +1 -0
- package/dist/fileRules/codeAllowedExtensions.js +1 -0
- package/dist/fileRules/codeAllowedExtensions.js.map +1 -0
- package/dist/fileRules/detectFileType.js +1 -0
- package/dist/fileRules/detectFileType.js.map +1 -0
- package/dist/fileRules/fileClassifier.js +1 -0
- package/dist/fileRules/fileClassifier.js.map +1 -0
- package/dist/fileRules/fileExceptions.js +1 -0
- package/dist/fileRules/fileExceptions.js.map +1 -0
- package/dist/fileRules/ignoredExtensions.js +1 -0
- package/dist/fileRules/ignoredExtensions.js.map +1 -0
- package/dist/fileRules/ignoredPaths.js +48 -5
- package/dist/fileRules/ignoredPaths.js.map +1 -0
- package/dist/fileRules/queryTokenRules.js +176 -0
- package/dist/fileRules/queryTokenRules.js.map +1 -0
- package/dist/fileRules/searchPathClassification.js +58 -0
- package/dist/fileRules/searchPathClassification.js.map +1 -0
- package/dist/fileRules/shouldIgnoreFiles.js +1 -0
- package/dist/fileRules/shouldIgnoreFiles.js.map +1 -0
- package/dist/fileRules/stopWords.js +9 -0
- package/dist/fileRules/stopWords.js.map +1 -0
- package/dist/fileRules/wellKnownRepoFiles.js +1 -0
- package/dist/fileRules/wellKnownRepoFiles.js.map +1 -0
- package/dist/git/commitSummary.js +227 -0
- package/dist/git/commitSummary.js.map +1 -0
- package/dist/github/api.js +1 -0
- package/dist/github/api.js.map +1 -0
- package/dist/github/auth.js +1 -0
- package/dist/github/auth.js.map +1 -0
- package/dist/github/github.js +1 -0
- package/dist/github/github.js.map +1 -0
- package/dist/github/githubAuthCheck.js +1 -0
- package/dist/github/githubAuthCheck.js.map +1 -0
- package/dist/github/postComments.js +1 -0
- package/dist/github/postComments.js.map +1 -0
- package/dist/github/repo.js +15 -24
- package/dist/github/repo.js.map +1 -0
- package/dist/github/token.js +1 -0
- package/dist/github/token.js.map +1 -0
- package/dist/github/types.js +1 -0
- package/dist/github/types.js.map +1 -0
- package/dist/index.js +318 -37
- package/dist/index.js.map +1 -0
- package/dist/lib/generate.js +264 -20
- package/dist/lib/generate.js.map +1 -0
- package/dist/lib/generateFolderCapsules.js +1 -0
- package/dist/lib/generateFolderCapsules.js.map +1 -0
- package/dist/lib/ollamaModelPolicy.js +59 -0
- package/dist/lib/ollamaModelPolicy.js.map +1 -0
- package/dist/lib/spinner.js +29 -9
- package/dist/lib/spinner.js.map +1 -0
- package/dist/modelSetup.js +25 -78
- package/dist/modelSetup.js.map +1 -0
- package/dist/pipeline/modules/changeLogModule.js +10 -1
- package/dist/pipeline/modules/changeLogModule.js.map +1 -0
- package/dist/pipeline/modules/cleanupModule.js +1 -0
- package/dist/pipeline/modules/cleanupModule.js.map +1 -0
- package/dist/pipeline/modules/codeTransformModule.js +10 -16
- package/dist/pipeline/modules/codeTransformModule.js.map +1 -0
- package/dist/pipeline/modules/commentModule.js +12 -0
- package/dist/pipeline/modules/commentModule.js.map +1 -0
- package/dist/pipeline/modules/commitSuggesterModule.js +82 -12
- package/dist/pipeline/modules/commitSuggesterModule.js.map +1 -0
- package/dist/pipeline/modules/contextReviewModule.js +12 -1
- package/dist/pipeline/modules/contextReviewModule.js.map +1 -0
- package/dist/pipeline/modules/dialogAnswerModule.js +58 -0
- package/dist/pipeline/modules/dialogAnswerModule.js.map +1 -0
- package/dist/pipeline/modules/fileSearchModule.js +5 -143
- package/dist/pipeline/modules/fileSearchModule.js.map +1 -0
- package/dist/pipeline/modules/finalAnswerModule.js +1176 -151
- package/dist/pipeline/modules/finalAnswerModule.js.map +1 -0
- package/dist/pipeline/modules/kgModule.js +18 -1
- package/dist/pipeline/modules/kgModule.js.map +1 -0
- package/dist/pipeline/modules/planAnswerModule.js +99 -0
- package/dist/pipeline/modules/planAnswerModule.js.map +1 -0
- package/dist/pipeline/modules/readFileModule.js +300 -0
- package/dist/pipeline/modules/readFileModule.js.map +1 -0
- package/dist/pipeline/modules/reviewModule.js +10 -1
- package/dist/pipeline/modules/reviewModule.js.map +1 -0
- package/dist/pipeline/modules/searchDbModule.js +159 -0
- package/dist/pipeline/modules/searchDbModule.js.map +1 -0
- package/dist/pipeline/modules/searchListDirectoryModule.js +62 -0
- package/dist/pipeline/modules/searchListDirectoryModule.js.map +1 -0
- package/dist/pipeline/modules/searchModuleShared.js +71 -0
- package/dist/pipeline/modules/searchModuleShared.js.map +1 -0
- package/dist/pipeline/modules/searchRegexModule.js +59 -0
- package/dist/pipeline/modules/searchRegexModule.js.map +1 -0
- package/dist/pipeline/modules/semanticAnalysisModule.js +185 -28
- package/dist/pipeline/modules/semanticAnalysisModule.js.map +1 -0
- package/dist/pipeline/modules/summaryModule.js +11 -1
- package/dist/pipeline/modules/summaryModule.js.map +1 -0
- package/dist/pipeline/registry/moduleRegistry.js +9 -0
- package/dist/pipeline/registry/moduleRegistry.js.map +1 -0
- package/dist/pipeline/runModulePipeline.js +1 -0
- package/dist/pipeline/runModulePipeline.js.map +1 -0
- package/dist/scripts/dbScriptSupport.js +172 -0
- package/dist/scripts/dbScriptSupport.js.map +1 -0
- package/dist/scripts/dbcheck.js +173 -267
- package/dist/scripts/dbcheck.js.map +1 -0
- package/dist/scripts/dboverview.js +161 -0
- package/dist/scripts/dboverview.js.map +1 -0
- package/dist/scripts/migrateDb.js +1 -0
- package/dist/scripts/migrateDb.js.map +1 -0
- package/dist/search/SearchOrchestrator.js +928 -0
- package/dist/search/SearchOrchestrator.js.map +1 -0
- package/dist/search/sharedRankingPolicy.js +283 -0
- package/dist/search/sharedRankingPolicy.js.map +1 -0
- package/dist/setup/reindexOwner.js +97 -0
- package/dist/setup/reindexOwner.js.map +1 -0
- package/dist/setup/setupOwner.js +100 -0
- package/dist/setup/setupOwner.js.map +1 -0
- package/dist/shell/dialogUi.js +81 -0
- package/dist/shell/dialogUi.js.map +1 -0
- package/dist/shellSession.js +126 -0
- package/dist/shellSession.js.map +1 -0
- package/dist/status/statusOwner.js +239 -0
- package/dist/status/statusOwner.js.map +1 -0
- package/dist/testing/contextEval.js +514 -0
- package/dist/testing/contextEval.js.map +1 -0
- package/dist/testing/fixtures/transform/small-file.input.js +5 -0
- package/dist/testing/fixtures/transform/small-file.input.js.map +1 -0
- package/dist/testing/harnessArtifacts.js +112 -0
- package/dist/testing/harnessArtifacts.js.map +1 -0
- package/dist/testing/llmTraceSession.js +67 -0
- package/dist/testing/llmTraceSession.js.map +1 -0
- package/dist/testing/registerDevCliCommands.js +43 -0
- package/dist/testing/registerDevCliCommands.js.map +1 -0
- package/dist/testing/runDiagnosis.js +248 -0
- package/dist/testing/runDiagnosis.js.map +1 -0
- package/dist/testing/runtimeLogReader.js +144 -0
- package/dist/testing/runtimeLogReader.js.map +1 -0
- package/dist/testing/testCommands.js +35 -303
- package/dist/testing/testCommands.js.map +1 -0
- package/dist/testing/testRegistry.js +233 -0
- package/dist/testing/testRegistry.js.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/buildContextualPrompt.js +26 -75
- package/dist/utils/buildContextualPrompt.js.map +1 -0
- package/dist/utils/changeLogPrompt.js +1 -0
- package/dist/utils/changeLogPrompt.js.map +1 -0
- package/dist/utils/checkModel.js +17 -92
- package/dist/utils/checkModel.js.map +1 -0
- package/dist/utils/commentMap.js +1 -0
- package/dist/utils/commentMap.js.map +1 -0
- package/dist/utils/compileSearchQuery.js +23 -9
- package/dist/utils/compileSearchQuery.js.map +1 -0
- package/dist/utils/consolePresentation.js +208 -0
- package/dist/utils/consolePresentation.js.map +1 -0
- package/dist/utils/contentUtils.js +17 -2
- package/dist/utils/contentUtils.js.map +1 -0
- package/dist/utils/debugContext.js +1 -0
- package/dist/utils/debugContext.js.map +1 -0
- package/dist/utils/dialogState.js +201 -0
- package/dist/utils/dialogState.js.map +1 -0
- package/dist/utils/editor.js +1 -0
- package/dist/utils/editor.js.map +1 -0
- package/dist/utils/executionEvidence.js +50 -0
- package/dist/utils/executionEvidence.js.map +1 -0
- package/dist/utils/extractFileReferences.js +140 -6
- package/dist/utils/extractFileReferences.js.map +1 -0
- package/dist/utils/fileEvidenceCache.js +50 -0
- package/dist/utils/fileEvidenceCache.js.map +1 -0
- package/dist/utils/fileTree.js +1 -0
- package/dist/utils/fileTree.js.map +1 -0
- package/dist/utils/loadRelevantFolderCapsules.js +35 -5
- package/dist/utils/loadRelevantFolderCapsules.js.map +1 -0
- package/dist/utils/log.js +10 -1
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/normalizeData.js +1 -0
- package/dist/utils/normalizeData.js.map +1 -0
- package/dist/utils/ollamaModelStatus.js +28 -0
- package/dist/utils/ollamaModelStatus.js.map +1 -0
- package/dist/utils/ollamaService.js +294 -0
- package/dist/utils/ollamaService.js.map +1 -0
- package/dist/utils/outputFormatter.js +1 -0
- package/dist/utils/outputFormatter.js.map +1 -0
- package/dist/utils/parseTaggedContent.js +1 -0
- package/dist/utils/parseTaggedContent.js.map +1 -0
- package/dist/utils/planActions.js +27 -46
- package/dist/utils/planActions.js.map +1 -0
- package/dist/utils/promptBuilderHelper.js +1 -0
- package/dist/utils/promptBuilderHelper.js.map +1 -0
- package/dist/utils/promptLogHelper.js +29 -13
- package/dist/utils/promptLogHelper.js.map +1 -0
- package/dist/utils/queryAnchors.js +71 -0
- package/dist/utils/queryAnchors.js.map +1 -0
- package/dist/utils/repoIdentity.js +82 -0
- package/dist/utils/repoIdentity.js.map +1 -0
- package/dist/utils/repoKey.js +1 -0
- package/dist/utils/repoKey.js.map +1 -0
- package/dist/utils/resolveTargetsToFiles.js +1 -0
- package/dist/utils/resolveTargetsToFiles.js.map +1 -0
- package/dist/utils/resumeContext.js +219 -0
- package/dist/utils/resumeContext.js.map +1 -0
- package/dist/utils/resumeState.js +310 -0
- package/dist/utils/resumeState.js.map +1 -0
- package/dist/utils/rollingPlan.js +118 -0
- package/dist/utils/rollingPlan.js.map +1 -0
- package/dist/utils/runQueryWithDaemonControl.js +11 -3
- package/dist/utils/runQueryWithDaemonControl.js.map +1 -0
- package/dist/utils/runtimeLogger.js +252 -0
- package/dist/utils/runtimeLogger.js.map +1 -0
- package/dist/utils/sanitizeQuery.js +1 -0
- package/dist/utils/sanitizeQuery.js.map +1 -0
- package/dist/utils/sharedUtils.js +1 -0
- package/dist/utils/sharedUtils.js.map +1 -0
- package/dist/utils/sleep.js +1 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/splitCodeIntoChunk.js +1 -0
- package/dist/utils/splitCodeIntoChunk.js.map +1 -0
- package/dist/utils/time.js +66 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/verifyFocusPreference.js +107 -0
- package/dist/utils/verifyFocusPreference.js.map +1 -0
- package/dist/utils/vscode.js +1 -0
- package/dist/utils/vscode.js.map +1 -0
- package/dist/workflow/workflowResolver.js +1 -0
- package/dist/workflow/workflowResolver.js.map +1 -0
- package/dist/workflow/workflowRunner.js +1 -0
- package/dist/workflow/workflowRunner.js.map +1 -0
- package/package.json +3 -3
- package/dist/agents/MainAgent.js +0 -1886
- package/dist/agents/contextReviewStep.js +0 -101
- package/dist/agents/finalPlanGenStep.js +0 -107
- package/dist/agents/structuralAnalysisStep.js +0 -46
- package/dist/agents/validationAnalysisStep.js +0 -87
- package/dist/pipeline/modules/chunkManagerModule.js +0 -24
- package/dist/pipeline/modules/cleanGeneratedTestsModule.js +0 -33
- package/dist/pipeline/modules/fileReaderModule.js +0 -72
- package/dist/pipeline/modules/gatherInfoModule.js +0 -181
- package/dist/pipeline/modules/generateTestsModule.js +0 -68
- package/dist/pipeline/modules/preserveCodeModule.js +0 -195
- package/dist/pipeline/modules/refactorModule.js +0 -40
- package/dist/pipeline/modules/repairTestsModule.js +0 -48
- package/dist/pipeline/modules/runTestsModule.js +0 -37
package/dist/agents/MainAgent.js
DELETED
|
@@ -1,1886 +0,0 @@
|
|
|
1
|
-
import { builtInModules } from "../pipeline/registry/moduleRegistry.js";
|
|
2
|
-
import { logInputOutput } from "../utils/promptLogHelper.js";
|
|
3
|
-
import { infoPlanGenStep } from "./infoPlanGenStep.js";
|
|
4
|
-
import { understandIntentStep } from "./understandIntentStep.js";
|
|
5
|
-
import { transformPlanGenStep } from "./transformPlanGenStep.js";
|
|
6
|
-
import { getDbForRepo } from "../db/client.js";
|
|
7
|
-
import { writeFileStep } from "./writeFileStep.js";
|
|
8
|
-
import { resolveExecutionModeStep } from "./resolveExecutionModeStep.js";
|
|
9
|
-
import { fileCheckStep } from "./fileCheckStep.js";
|
|
10
|
-
import { analysisPlanGenStep } from "./analysisPlanGenStep.js";
|
|
11
|
-
import { readinessGateStep } from "./readinessGateStep.js";
|
|
12
|
-
import { scopeClassificationStep } from "./scopeClassificationStep.js";
|
|
13
|
-
import { routingDecisionStep } from "./routingDecisionStep.js";
|
|
14
|
-
import { evidenceVerifierStep } from "./evidenceVerifierStep.js";
|
|
15
|
-
import { validateChangesStep } from './validateChangesStep.js';
|
|
16
|
-
import { reasonNextTaskStep } from './reasonNextTaskStep.js';
|
|
17
|
-
import { collaboratorStep } from './collaboratorStep.js';
|
|
18
|
-
import { integrateFeedbackStep } from './integrateFeedbackStep.js';
|
|
19
|
-
import { researchPlanGenStep } from "./researchPlanGenStep.js";
|
|
20
|
-
import { selectRelevantSourcesStep } from "./selectRelevantSourcesStep.js";
|
|
21
|
-
import { iterationFileSelector } from "./iterationFileSelector.js";
|
|
22
|
-
import { finalAnswerModule } from "../pipeline/modules/finalAnswerModule.js";
|
|
23
|
-
import { reasonNextStep } from "./reasonNextStep.js";
|
|
24
|
-
import { buildLightContext } from "../utils/buildContextualPrompt.js";
|
|
25
|
-
import { semanticSearchFiles } from "../db/fileIndex.js";
|
|
26
|
-
import { NUM_TOPFILES, RELATED_FILES_LIMIT } from "../constants.js";
|
|
27
|
-
import { structuralPreloadStep } from "./structuralPreloadStep.js";
|
|
28
|
-
import { extractFileReferences } from "../utils/extractFileReferences.js";
|
|
29
|
-
import { PREFILTER_STOP_WORDS } from "../fileRules/stopWords.js";
|
|
30
|
-
import { MAX_WELL_KNOWN_REPO_FILES, WELL_KNOWN_REPO_FILE_BASENAMES } from "../fileRules/wellKnownRepoFiles.js";
|
|
31
|
-
import { isPathIgnoredByFolderGlobs } from "../fileRules/ignoredPaths.js";
|
|
32
|
-
import { canExecutePhase, canExecuteRoute, canExecuteScope } from "./guardPolicy.js";
|
|
33
|
-
import chalk from "chalk";
|
|
34
|
-
import path from "path";
|
|
35
|
-
import fs from "fs";
|
|
36
|
-
/* ───────────────────────── registry ───────────────────────── */
|
|
37
|
-
const MODULE_REGISTRY = Object.fromEntries(Object.entries(builtInModules).map(([name, mod]) => [name, mod]));
|
|
38
|
-
function resolveModuleForAction(action) {
|
|
39
|
-
return MODULE_REGISTRY[action];
|
|
40
|
-
}
|
|
41
|
-
/* ───────────────────────── agent ───────────────────────── */
|
|
42
|
-
/**
|
|
43
|
-
* MainAgent is the core orchestrator of the SCAI agent system.
|
|
44
|
-
* It manages the execution flow, coordinates steps, and handles context management.
|
|
45
|
-
*
|
|
46
|
-
* The agent follows a multi-phase execution model:
|
|
47
|
-
* 1. Boot: Determine intent and execution mode
|
|
48
|
-
* 2. Precheck: File existence validation
|
|
49
|
-
* 3. Scope: Determine where to act and what actions are allowed
|
|
50
|
-
* 4. Grounding & Readiness Loop: Acquire evidence and verify readiness
|
|
51
|
-
* 5. Analysis: Perform in-depth analysis
|
|
52
|
-
* 6. Transform: Generate and execute transformations
|
|
53
|
-
* 7. Finalize: Complete the task and persist data
|
|
54
|
-
*/
|
|
55
|
-
export class MainAgent {
|
|
56
|
-
/**
|
|
57
|
-
* Creates a new MainAgent instance.
|
|
58
|
-
*
|
|
59
|
-
* @param context - The structured context for the agent.
|
|
60
|
-
* @param ui - The UI interface for agent communication.
|
|
61
|
-
*/
|
|
62
|
-
constructor(context, ui) {
|
|
63
|
-
this.runCount = 0;
|
|
64
|
-
this.verboseAgentLogs = process.env.SCAI_VERBOSE_AGENT_LOGS === "1";
|
|
65
|
-
this.hasPrintedHeader = false;
|
|
66
|
-
this.activity = {
|
|
67
|
-
searches: [],
|
|
68
|
-
lists: [],
|
|
69
|
-
reads: [],
|
|
70
|
-
};
|
|
71
|
-
this.context = context;
|
|
72
|
-
this.query = context.initContext?.userQuery ?? "";
|
|
73
|
-
this.ui = ui;
|
|
74
|
-
}
|
|
75
|
-
/* ───────────── main run ───────────── */
|
|
76
|
-
async run() {
|
|
77
|
-
try {
|
|
78
|
-
this.runCount = 0;
|
|
79
|
-
this.printHeader("Boot & Scope");
|
|
80
|
-
await this.runBoot();
|
|
81
|
-
await this.runScope();
|
|
82
|
-
this.printHeader("Search");
|
|
83
|
-
await this.runSearch();
|
|
84
|
-
this.printHeader("Verify");
|
|
85
|
-
await this.runVerify();
|
|
86
|
-
this.printHeader("Research");
|
|
87
|
-
await this.runResearch();
|
|
88
|
-
const canProceedToExecution = this.isResearchGateSatisfied();
|
|
89
|
-
if (canProceedToExecution) {
|
|
90
|
-
this.printHeader("Plan");
|
|
91
|
-
await this.runPlan();
|
|
92
|
-
this.printHeader("Execute");
|
|
93
|
-
await this.runWorkLoop();
|
|
94
|
-
}
|
|
95
|
-
this.printHeader("Finalize");
|
|
96
|
-
await this.runFinalize();
|
|
97
|
-
}
|
|
98
|
-
finally {
|
|
99
|
-
this.ui.stop(); // ← guaranteed cleanup
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/* ───────────── boot ───────────── */
|
|
103
|
-
async runBoot() {
|
|
104
|
-
var _a;
|
|
105
|
-
await understandIntentStep.run({ context: this.context });
|
|
106
|
-
// Boot the task and get the real DB taskId
|
|
107
|
-
this.taskId = bootTaskForRepo(this.context, getDbForRepo(), (phase, step, ms, desc) => this.logLine(phase, step, ms, desc, { highlight: true }));
|
|
108
|
-
(_a = this.context).task || (_a.task = {
|
|
109
|
-
id: this.taskId,
|
|
110
|
-
projectId: 0,
|
|
111
|
-
status: "active",
|
|
112
|
-
initialQuery: this.context.initContext?.userQuery ?? "",
|
|
113
|
-
createdAt: new Date().toISOString(),
|
|
114
|
-
updatedAt: new Date().toISOString(),
|
|
115
|
-
taskSteps: [],
|
|
116
|
-
});
|
|
117
|
-
this.context.task.id = this.taskId;
|
|
118
|
-
this.userOutput(`Boot complete (taskId=${this.taskId}).`);
|
|
119
|
-
}
|
|
120
|
-
/* ───────────── scope ───────────── */
|
|
121
|
-
async runScope() {
|
|
122
|
-
await scopeClassificationStep.run(this.context);
|
|
123
|
-
await resolveExecutionModeStep.run(this.context);
|
|
124
|
-
await routingDecisionStep.run(this.context);
|
|
125
|
-
const routing = this.context.analysis?.routingDecision;
|
|
126
|
-
const scope = this.context.analysis?.scopeType ?? "unknown";
|
|
127
|
-
if (routing) {
|
|
128
|
-
this.userOutput(`Routing: ${routing.decision} (scope=${scope}, search=${routing.allowSearch}, research=${routing.allowResearch}, transform=${routing.allowTransform}, scopeLocked=${routing.scopeLocked}).`);
|
|
129
|
-
}
|
|
130
|
-
this.userOutput("Scope classification complete.");
|
|
131
|
-
}
|
|
132
|
-
/* ───────────── search ───────────── */
|
|
133
|
-
/**
|
|
134
|
-
* Seeds initial candidate files using semantic retrieval + deterministic prefilter.
|
|
135
|
-
* Example: query mentions "MainAgent" -> relatedFiles are narrowed before grounding.
|
|
136
|
-
*/
|
|
137
|
-
async runSearch() {
|
|
138
|
-
const { rawUserQuery, retrievalQuery } = this.resolveInitialRetrievalQueries();
|
|
139
|
-
this.userOutput("I’ll start by identifying likely files from semantic search before analyzing content.");
|
|
140
|
-
const t = this.startTimer();
|
|
141
|
-
try {
|
|
142
|
-
const results = await this.fetchInitialRetrievalResults(retrievalQuery);
|
|
143
|
-
const promptArgs = this.buildInitialRetrievalPromptArgs(results, retrievalQuery);
|
|
144
|
-
const seededContext = await buildLightContext(promptArgs);
|
|
145
|
-
const mergedRelatedCount = this.mergeSeededInitialContext(rawUserQuery, seededContext);
|
|
146
|
-
const prefilter = this.applyDeterministicPreGroundingPrefilter(retrievalQuery);
|
|
147
|
-
const repoDefaults = this.injectWellKnownRepoFiles(prefilter.after);
|
|
148
|
-
this.recordSearch(retrievalQuery, path.basename(process.cwd()));
|
|
149
|
-
this.recordListEntries(Array.from(new Set(results.map(result => path.dirname(this.formatPathForLog(result.path)))))
|
|
150
|
-
.slice(0, 2)
|
|
151
|
-
.map(dir => dir === "." ? process.cwd() : dir));
|
|
152
|
-
this.logLine("ANALYSIS", "initialRetrieval", t(), `${results.length} result(s), ${mergedRelatedCount} candidate file(s), prefilter ${prefilter.before} -> ${prefilter.after}, defaults +${repoDefaults.added} (${repoDefaults.reason})`);
|
|
153
|
-
this.flushActivity();
|
|
154
|
-
}
|
|
155
|
-
catch (err) {
|
|
156
|
-
this.logLine("ANALYSIS", "initialRetrieval", t(), `failed: ${String(err)}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
/* ───────────── verify ───────────── */
|
|
160
|
-
/**
|
|
161
|
-
* Wave-based verify loop (evidence -> readiness -> optional info acquisition).
|
|
162
|
-
* Example: if readiness stays not-ready, run an info plan and try another wave.
|
|
163
|
-
*/
|
|
164
|
-
async runVerify() {
|
|
165
|
-
let ready = false;
|
|
166
|
-
const maxGroundingWaves = this.getGroundingWaveBudget();
|
|
167
|
-
let groundingWave = 0;
|
|
168
|
-
let stagnantWaves = 0;
|
|
169
|
-
const MAX_STAGNANT_WAVES = 2;
|
|
170
|
-
while (groundingWave < maxGroundingWaves) {
|
|
171
|
-
groundingWave++;
|
|
172
|
-
this.pruneMissingVerifyPaths();
|
|
173
|
-
this.logLine("ANALYSIS", "groundingWave", undefined, `wave ${groundingWave}/${maxGroundingWaves}`);
|
|
174
|
-
const beforeFocus = this.captureVerifyFocusSnapshot();
|
|
175
|
-
const beforeWorking = new Set((this.context.workingFiles ?? []).map(file => file.path));
|
|
176
|
-
const beforeSelected = new Set(this.context.analysis?.focus?.selectedFiles ?? []);
|
|
177
|
-
const beforeCandidate = new Set(this.context.analysis?.focus?.candidateFiles ?? []);
|
|
178
|
-
const structuralBefore = new Set(Object.entries(this.context.analysis?.fileAnalysis ?? {})
|
|
179
|
-
.filter(([_, analysis]) => !!analysis?.structural)
|
|
180
|
-
.map(([filePath]) => filePath));
|
|
181
|
-
// ---------------- EVIDENCE PIPELINE ----------------
|
|
182
|
-
// -------- STRUCTURAL PRELOAD --------
|
|
183
|
-
const t0 = this.startTimer();
|
|
184
|
-
await structuralPreloadStep.run({ query: this.query, context: this.context });
|
|
185
|
-
const structuralAfter = Object.entries(this.context.analysis?.fileAnalysis ?? {})
|
|
186
|
-
.filter(([_, analysis]) => !!analysis?.structural)
|
|
187
|
-
.map(([filePath]) => filePath);
|
|
188
|
-
const newStructural = structuralAfter.filter(filePath => !structuralBefore.has(filePath));
|
|
189
|
-
this.logLine("ANALYSIS", "structuralPreload", t0());
|
|
190
|
-
const t1 = this.startTimer();
|
|
191
|
-
await evidenceVerifierStep.run({ query: this.query, context: this.context });
|
|
192
|
-
const verifyEntries = Object.entries(this.context.analysis?.verify?.byFile ?? {});
|
|
193
|
-
this.logLine("ANALYSIS", "collectAnalysisEvidence", t1());
|
|
194
|
-
const t2 = this.startTimer();
|
|
195
|
-
await fileCheckStep(this.context);
|
|
196
|
-
const selectedAfterCheck = this.context.analysis?.focus?.selectedFiles ?? [];
|
|
197
|
-
const candidateAfterCheck = this.context.analysis?.focus?.candidateFiles ?? [];
|
|
198
|
-
const addedSelected = selectedAfterCheck.filter(filePath => !beforeSelected.has(filePath));
|
|
199
|
-
const addedCandidate = candidateAfterCheck.filter(filePath => !beforeCandidate.has(filePath));
|
|
200
|
-
this.logLine("ANALYSIS", "fileCheckStep", t2());
|
|
201
|
-
const t3 = this.startTimer();
|
|
202
|
-
await selectRelevantSourcesStep.run({ query: this.query, context: this.context });
|
|
203
|
-
const workingAfter = this.context.workingFiles ?? [];
|
|
204
|
-
const newWorking = workingAfter
|
|
205
|
-
.map(file => file.path)
|
|
206
|
-
.filter(filePath => !beforeWorking.has(filePath));
|
|
207
|
-
this.logLine("ANALYSIS", "selectRelevantSources", t3());
|
|
208
|
-
// ---------------- READINESS GATE ----------------
|
|
209
|
-
const t4 = this.startTimer();
|
|
210
|
-
await readinessGateStep.run(this.context);
|
|
211
|
-
const readiness = this.context.analysis?.readiness;
|
|
212
|
-
const selectedCount = this.context.analysis?.focus?.selectedFiles?.length ?? 0;
|
|
213
|
-
this.logLine("ANALYSIS", "readinessGate", t4(), `decision=${readiness?.decision ?? "unknown"}, confidence=${(readiness?.confidence ?? 0).toFixed(2)}, selected=${selectedCount}`);
|
|
214
|
-
this.userOutput("I mapped the verify wave. Next I’ll analyze selected files and refine scope if needed.");
|
|
215
|
-
this.recordReadEntries(newStructural);
|
|
216
|
-
this.recordReadEntries(verifyEntries.map(([filePath]) => filePath));
|
|
217
|
-
this.recordReadEntries(addedSelected);
|
|
218
|
-
this.recordListEntries(addedCandidate);
|
|
219
|
-
this.recordReadEntries(newWorking);
|
|
220
|
-
this.flushActivity();
|
|
221
|
-
ready = this.context.analysis?.readiness?.decision === "ready";
|
|
222
|
-
if (ready) {
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
// ---------------- INFORMATION ACQUISITION ----------------
|
|
226
|
-
const canRouteSearchExpansion = canExecuteRoute(this.context, "search-expand");
|
|
227
|
-
if (!canRouteSearchExpansion) {
|
|
228
|
-
this.logLine("PLAN", "infoPlanGen", undefined, "skipped (routing disallows search expansion)", { highlight: false });
|
|
229
|
-
}
|
|
230
|
-
else if (canExecutePhase(this.context, "planning") &&
|
|
231
|
-
canExecuteScope(this.context, "planning")) {
|
|
232
|
-
const t = this.startTimer();
|
|
233
|
-
await infoPlanGenStep.run(this.context);
|
|
234
|
-
const infoPlan = this.context.analysis?.planSuggestion?.plan ?? { steps: [] };
|
|
235
|
-
for (const step of infoPlan.steps) {
|
|
236
|
-
const stepIO = { query: this.query };
|
|
237
|
-
await this.executeStep(step, stepIO);
|
|
238
|
-
}
|
|
239
|
-
this.logLine("PLAN", "infoPlanGen", t(), undefined, { highlight: false });
|
|
240
|
-
}
|
|
241
|
-
const afterFocus = this.captureVerifyFocusSnapshot();
|
|
242
|
-
const hasFocusGrowth = this.logVerifyFocusDelta(beforeFocus, afterFocus);
|
|
243
|
-
stagnantWaves = hasFocusGrowth ? 0 : stagnantWaves + 1;
|
|
244
|
-
if (this.shouldStopVerifyForSaturation(stagnantWaves, MAX_STAGNANT_WAVES))
|
|
245
|
-
break;
|
|
246
|
-
this.logLine("HASINFO", "Not ready — looping back to evidence collection", undefined, undefined, { highlight: false });
|
|
247
|
-
}
|
|
248
|
-
// Grounding is the phase boundary that decides whether execution may start.
|
|
249
|
-
if (!this.isWorkLoopReady())
|
|
250
|
-
return;
|
|
251
|
-
this.ensureTaskForWorkLoop();
|
|
252
|
-
this.recalibrateRoutingAfterVerify();
|
|
253
|
-
// Research gate is evaluated after runResearch() in run().
|
|
254
|
-
}
|
|
255
|
-
/* ───────────── research ───────────── */
|
|
256
|
-
/**
|
|
257
|
-
* Seeds explicit research task steps for complex repo-wide lanes.
|
|
258
|
-
* Example: enqueue research-impact-map, research-symbol-trace, and research-risk-check.
|
|
259
|
-
*/
|
|
260
|
-
async runResearch() {
|
|
261
|
-
var _a, _b;
|
|
262
|
-
if (!canExecuteRoute(this.context, "research")) {
|
|
263
|
-
this.logLine("RESEARCH", "taskStepSeed", undefined, "skipped (route disallows research)");
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
if (!this.context.task)
|
|
267
|
-
return;
|
|
268
|
-
(_a = this.context.task).taskSteps || (_a.taskSteps = []);
|
|
269
|
-
await researchPlanGenStep.run(this.context);
|
|
270
|
-
const generatedSteps = (this.context.analysis?.planSuggestion?.plan?.steps ?? [])
|
|
271
|
-
.filter(step => typeof step.action === "string" && step.action.startsWith("research-"))
|
|
272
|
-
.map(step => {
|
|
273
|
-
const action = step.action;
|
|
274
|
-
const defaultFilePath = action === "research-impact-map"
|
|
275
|
-
? "__research__/impact-map"
|
|
276
|
-
: action === "research-symbol-trace"
|
|
277
|
-
? "__research__/symbol-trace"
|
|
278
|
-
: action === "research-risk-check"
|
|
279
|
-
? "__research__/risk-check"
|
|
280
|
-
: "__research__/architecture-synthesis";
|
|
281
|
-
return {
|
|
282
|
-
action,
|
|
283
|
-
filePath: step.targetFile || defaultFilePath,
|
|
284
|
-
notes: step.description || `Run ${step.action}`,
|
|
285
|
-
};
|
|
286
|
-
});
|
|
287
|
-
const fallbackResearchSteps = [
|
|
288
|
-
{
|
|
289
|
-
action: "research-impact-map",
|
|
290
|
-
filePath: "__research__/impact-map",
|
|
291
|
-
notes: "Map cross-file impact before code changes.",
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
action: "research-symbol-trace",
|
|
295
|
-
filePath: "__research__/symbol-trace",
|
|
296
|
-
notes: "Trace key symbols across related files.",
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
action: "research-risk-check",
|
|
300
|
-
filePath: "__research__/risk-check",
|
|
301
|
-
notes: "Record risks, assumptions, and constraints before edits.",
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
action: "research-architecture-synthesis",
|
|
305
|
-
filePath: "__research__/architecture-synthesis",
|
|
306
|
-
notes: "Synthesize architecture summary, shared patterns, hotspots, and coupling points.",
|
|
307
|
-
},
|
|
308
|
-
];
|
|
309
|
-
const researchSteps = generatedSteps.length > 0 ? generatedSteps : fallbackResearchSteps;
|
|
310
|
-
let seededCount = 0;
|
|
311
|
-
for (const step of researchSteps) {
|
|
312
|
-
const exists = this.context.task.taskSteps.some(s => s.filePath === step.filePath && s.action === step.action);
|
|
313
|
-
if (exists)
|
|
314
|
-
continue;
|
|
315
|
-
this.context.task.taskSteps.push({
|
|
316
|
-
taskId: this.context.task.id,
|
|
317
|
-
filePath: step.filePath,
|
|
318
|
-
action: step.action,
|
|
319
|
-
status: "pending",
|
|
320
|
-
notes: step.notes,
|
|
321
|
-
result: { phase: "research", seededBy: "runResearch" },
|
|
322
|
-
});
|
|
323
|
-
seededCount++;
|
|
324
|
-
}
|
|
325
|
-
const plannedResearchSteps = this.context.task.taskSteps
|
|
326
|
-
.filter(s => typeof s.action === "string" && s.action.startsWith("research-"))
|
|
327
|
-
.map(s => ({
|
|
328
|
-
action: s.action,
|
|
329
|
-
filePath: s.filePath,
|
|
330
|
-
status: s.status,
|
|
331
|
-
notes: s.notes,
|
|
332
|
-
}));
|
|
333
|
-
logInputOutput("runResearch", "output", {
|
|
334
|
-
source: generatedSteps.length > 0 ? "generated" : "fallback",
|
|
335
|
-
seededCount,
|
|
336
|
-
totalResearchSteps: plannedResearchSteps.length,
|
|
337
|
-
steps: plannedResearchSteps,
|
|
338
|
-
});
|
|
339
|
-
(_b = this.context).analysis || (_b.analysis = {});
|
|
340
|
-
this.context.analysis.planSuggestion = undefined;
|
|
341
|
-
this.logLine("RESEARCH", "taskStepSeed", undefined, `${seededCount} research step(s) added (${generatedSteps.length > 0 ? "generated" : "fallback"})`);
|
|
342
|
-
}
|
|
343
|
-
/* ───────────── plan ───────────── */
|
|
344
|
-
/**
|
|
345
|
-
* Seeds ordered execution task steps from selected files + research/verify artifacts.
|
|
346
|
-
* Example: prioritize files that are both selected and research-touched.
|
|
347
|
-
*/
|
|
348
|
-
async runPlan() {
|
|
349
|
-
var _a, _b;
|
|
350
|
-
if (!this.context.task)
|
|
351
|
-
return;
|
|
352
|
-
if (!canExecutePhase(this.context, "planning") || !canExecuteScope(this.context, "planning"))
|
|
353
|
-
return;
|
|
354
|
-
(_a = this.context).analysis || (_a.analysis = {});
|
|
355
|
-
(_b = this.context.task).taskSteps || (_b.taskSteps = []);
|
|
356
|
-
const existingExecutionPaths = new Set(this.context.task.taskSteps
|
|
357
|
-
.filter(step => !!step.filePath &&
|
|
358
|
-
!step.filePath.startsWith("__research__/"))
|
|
359
|
-
.map(step => step.filePath));
|
|
360
|
-
const selectedFiles = this.context.analysis.focus?.selectedFiles ?? [];
|
|
361
|
-
const touchedFromResearch = this.context.analysis.researchArtifacts?.touchedFiles ?? [];
|
|
362
|
-
const route = this.context.analysis.routingDecision;
|
|
363
|
-
const useFocusedSelectedPlanOnly = this.context.analysis.readiness?.decision === "ready" &&
|
|
364
|
-
(route?.decision === "has-info") &&
|
|
365
|
-
(route?.scopeLocked ?? false) &&
|
|
366
|
-
(route?.allowSearch === false) &&
|
|
367
|
-
selectedFiles.length > 0;
|
|
368
|
-
const verifyMinConfidence = this.getVerifyConfidenceThresholdForPlan();
|
|
369
|
-
const verifyEntries = Object.entries(this.context.analysis.verify?.byFile ?? {});
|
|
370
|
-
const verifyRelevantFiles = verifyEntries
|
|
371
|
-
.filter(([_, verify]) => verify?.isRelevant &&
|
|
372
|
-
(verify.fileConfidence ?? 0) >= verifyMinConfidence)
|
|
373
|
-
.map(([filePath]) => filePath);
|
|
374
|
-
const verifySkippedLowConfidenceCount = verifyEntries.filter(([_, verify]) => !!verify?.isRelevant &&
|
|
375
|
-
(verify.fileConfidence ?? 0) < verifyMinConfidence).length;
|
|
376
|
-
const rankPath = (filePath) => {
|
|
377
|
-
const inSelected = selectedFiles.includes(filePath);
|
|
378
|
-
const inResearchTouched = touchedFromResearch.includes(filePath);
|
|
379
|
-
const inVerify = verifyRelevantFiles.includes(filePath);
|
|
380
|
-
if (inSelected && inResearchTouched)
|
|
381
|
-
return 0;
|
|
382
|
-
if (inSelected)
|
|
383
|
-
return 1;
|
|
384
|
-
if (inResearchTouched)
|
|
385
|
-
return 2;
|
|
386
|
-
if (inVerify)
|
|
387
|
-
return 3;
|
|
388
|
-
return 4;
|
|
389
|
-
};
|
|
390
|
-
const plannedPathsSource = useFocusedSelectedPlanOnly
|
|
391
|
-
? Array.from(new Set(selectedFiles))
|
|
392
|
-
: Array.from(new Set([
|
|
393
|
-
...selectedFiles,
|
|
394
|
-
...touchedFromResearch,
|
|
395
|
-
...verifyRelevantFiles,
|
|
396
|
-
]));
|
|
397
|
-
const plannedPaths = plannedPathsSource
|
|
398
|
-
.filter(filePath => !!filePath && !filePath.startsWith("__research__/") && fs.existsSync(filePath))
|
|
399
|
-
.sort((a, b) => rankPath(a) - rankPath(b))
|
|
400
|
-
.slice(0, 16);
|
|
401
|
-
this.ensureWorkingFilesLoaded(plannedPaths, "Planned for execution");
|
|
402
|
-
let seededCount = 0;
|
|
403
|
-
const seeded = [];
|
|
404
|
-
for (const filePath of plannedPaths) {
|
|
405
|
-
if (existingExecutionPaths.has(filePath))
|
|
406
|
-
continue;
|
|
407
|
-
const rank = rankPath(filePath);
|
|
408
|
-
const notes = rank === 0
|
|
409
|
-
? "Plan priority: selected + research-touched"
|
|
410
|
-
: rank === 1
|
|
411
|
-
? "Plan priority: selected file"
|
|
412
|
-
: rank === 2
|
|
413
|
-
? "Plan priority: research-touched file"
|
|
414
|
-
: "Plan priority: verify-relevant file";
|
|
415
|
-
this.context.task.taskSteps.push({
|
|
416
|
-
taskId: this.context.task.id,
|
|
417
|
-
filePath,
|
|
418
|
-
status: "pending",
|
|
419
|
-
notes,
|
|
420
|
-
result: {
|
|
421
|
-
phase: "plan",
|
|
422
|
-
seededBy: "runPlan",
|
|
423
|
-
priorityRank: rank,
|
|
424
|
-
},
|
|
425
|
-
});
|
|
426
|
-
seeded.push({ filePath, rank, notes });
|
|
427
|
-
seededCount++;
|
|
428
|
-
}
|
|
429
|
-
logInputOutput("runPlan", "output", {
|
|
430
|
-
seededCount,
|
|
431
|
-
totalPlannedPaths: plannedPaths.length,
|
|
432
|
-
selectedFileCount: selectedFiles.length,
|
|
433
|
-
researchTouchedCount: touchedFromResearch.length,
|
|
434
|
-
verifyRelevantCount: verifyRelevantFiles.length,
|
|
435
|
-
focusedSelectedOnly: useFocusedSelectedPlanOnly,
|
|
436
|
-
verifyMinConfidence,
|
|
437
|
-
verifySkippedLowConfidenceCount,
|
|
438
|
-
seeded,
|
|
439
|
-
});
|
|
440
|
-
this.logLine("PLAN", "taskStepSeed", undefined, `${seededCount} execution step(s) planned`);
|
|
441
|
-
this.recordReadEntries(seeded.map(step => step.filePath));
|
|
442
|
-
this.flushActivity();
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Sets minimum verify confidence before a file can be plan-seeded from verify-only signal.
|
|
446
|
-
* Example: single-file lanes require higher confidence than repo-wide lanes.
|
|
447
|
-
*/
|
|
448
|
-
getVerifyConfidenceThresholdForPlan() {
|
|
449
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
450
|
-
if (scope === "single-file")
|
|
451
|
-
return 0.45;
|
|
452
|
-
if (scope === "multi-file")
|
|
453
|
-
return 0.35;
|
|
454
|
-
return 0.3;
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Re-routes after verify when evidence converges on selected files with high confidence.
|
|
458
|
-
* Example: selected files strongly verified => disable expansion/research and lock focused execution.
|
|
459
|
-
*/
|
|
460
|
-
recalibrateRoutingAfterVerify() {
|
|
461
|
-
var _a;
|
|
462
|
-
(_a = this.context).analysis || (_a.analysis = {});
|
|
463
|
-
const routing = this.context.analysis.routingDecision;
|
|
464
|
-
if (!routing)
|
|
465
|
-
return;
|
|
466
|
-
const intentCategory = (this.context.analysis.intent?.intentCategory ?? "").toLowerCase();
|
|
467
|
-
const isEditLikeIntent = intentCategory === "codingtask" ||
|
|
468
|
-
intentCategory === "refactortask" ||
|
|
469
|
-
intentCategory === "request" ||
|
|
470
|
-
intentCategory === "docsandcomments";
|
|
471
|
-
const canWrite = this.context.executionControl?.constraints?.allowFileWrites ?? false;
|
|
472
|
-
if (!isEditLikeIntent || !canWrite) {
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
const selectedFiles = this.context.analysis.focus?.selectedFiles ?? [];
|
|
476
|
-
if (selectedFiles.length === 0)
|
|
477
|
-
return;
|
|
478
|
-
const readinessConfidence = this.context.analysis.readiness?.confidence ?? 0;
|
|
479
|
-
const intentConfidence = this.context.analysis.intent?.confidence ?? 0;
|
|
480
|
-
const minFileConfidence = 0.28;
|
|
481
|
-
const strongSelected = selectedFiles.filter(filePath => {
|
|
482
|
-
const verify = this.context.analysis?.verify?.byFile?.[filePath];
|
|
483
|
-
return verify?.isRelevant === true && (verify.fileConfidence ?? 0) >= minFileConfidence;
|
|
484
|
-
});
|
|
485
|
-
const convergedSingle = selectedFiles.length === 1 &&
|
|
486
|
-
strongSelected.length === 1 &&
|
|
487
|
-
readinessConfidence >= 0.9 &&
|
|
488
|
-
intentConfidence >= 0.8;
|
|
489
|
-
const convergedMulti = selectedFiles.length >= 2 &&
|
|
490
|
-
strongSelected.length >= 2 &&
|
|
491
|
-
readinessConfidence >= 0.9 &&
|
|
492
|
-
intentConfidence >= 0.75;
|
|
493
|
-
if (!convergedSingle && !convergedMulti)
|
|
494
|
-
return;
|
|
495
|
-
routing.decision = "has-info";
|
|
496
|
-
routing.allowSearch = false;
|
|
497
|
-
routing.allowResearch = false;
|
|
498
|
-
routing.scopeLocked = true;
|
|
499
|
-
routing.rationale = `${routing.rationale}; postVerify=focused-selection(${strongSelected.length})`;
|
|
500
|
-
this.logLine("TASK", "Routing recalibrated", undefined, `focused=${selectedFiles.length} selected, strong=${strongSelected.length}`);
|
|
501
|
-
}
|
|
502
|
-
/* ───────────── work loop ───────────── */
|
|
503
|
-
async runWorkLoop() {
|
|
504
|
-
if (this.context.task.status !== "active")
|
|
505
|
-
return;
|
|
506
|
-
this.ensureTaskForWorkLoop();
|
|
507
|
-
const MAX_TASK_STEPS = this.getTaskStepBudget();
|
|
508
|
-
let stepCount = 0;
|
|
509
|
-
while (stepCount < MAX_TASK_STEPS &&
|
|
510
|
-
this.context.task.status === "active") {
|
|
511
|
-
const nextAction = await this.resolveNextTaskAction();
|
|
512
|
-
if (nextAction === "request-feedback") {
|
|
513
|
-
this.persistTaskStatus("paused");
|
|
514
|
-
this.logLine("TASK", "Execution paused — awaiting user clarification", undefined, undefined, { highlight: false });
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
if (nextAction === "complete") {
|
|
518
|
-
this.persistTaskStatus("completed");
|
|
519
|
-
this.logLine("TASK", "All selected files processed — task complete", undefined, undefined, { highlight: false });
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const taskStep = await iterationFileSelector.run(this.context);
|
|
523
|
-
if (!taskStep) {
|
|
524
|
-
this.persistTaskStatus("completed");
|
|
525
|
-
this.logLine("TASK", "No eligible taskStep found — task complete", undefined, undefined, { highlight: false });
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
stepCount++;
|
|
529
|
-
this.startTaskStep(taskStep, stepCount);
|
|
530
|
-
// ---------------------------
|
|
531
|
-
// Step-level iterations
|
|
532
|
-
// ---------------------------
|
|
533
|
-
const stepAction = await this.runStepIterations(taskStep);
|
|
534
|
-
if (stepAction === "expand-scope") {
|
|
535
|
-
this.applyScopeExpansionRouteHint();
|
|
536
|
-
}
|
|
537
|
-
this.finishTaskStep(taskStep, stepCount, stepAction);
|
|
538
|
-
}
|
|
539
|
-
this.logLine("TASK", "Max task step limit reached — stopping work loop", undefined, undefined, { highlight: false });
|
|
540
|
-
}
|
|
541
|
-
/* ───────────── finalize ───────────── */
|
|
542
|
-
async runFinalize() {
|
|
543
|
-
await finalAnswerModule.run({ query: this.query, context: this.context });
|
|
544
|
-
persistTaskData(this.context, this.taskId, getDbForRepo(), this.logLine.bind(this));
|
|
545
|
-
this.logLine("TASK", "Finalize complete", undefined, undefined, { highlight: false });
|
|
546
|
-
}
|
|
547
|
-
/* ───────────── step iterations ───────────── */
|
|
548
|
-
/**
|
|
549
|
-
* Iterates one task step until it completes, needs feedback, or asks for redo.
|
|
550
|
-
* Example: validation failure sets nextAction=redo-step and re-runs iteration.
|
|
551
|
-
*/
|
|
552
|
-
async runStepIterations(taskStep) {
|
|
553
|
-
const MAX_ITERATIONS = 5;
|
|
554
|
-
let loopCount = 0;
|
|
555
|
-
const getNextIterationAction = () => {
|
|
556
|
-
const nextAction = taskStep.result?.stepReasoning?.nextAction;
|
|
557
|
-
if (!["continue", "redo-step", "expand-scope", "request-feedback", "complete"].includes(nextAction ?? "")) {
|
|
558
|
-
return "continue";
|
|
559
|
-
}
|
|
560
|
-
return nextAction;
|
|
561
|
-
};
|
|
562
|
-
while (loopCount < MAX_ITERATIONS) {
|
|
563
|
-
this.runCount++;
|
|
564
|
-
loopCount++;
|
|
565
|
-
if (taskStep.result?.stepReasoning)
|
|
566
|
-
taskStep.result.stepReasoning.nextAction = undefined;
|
|
567
|
-
await this.runWorkIteration(taskStep);
|
|
568
|
-
const nextAction = getNextIterationAction();
|
|
569
|
-
this.logLine("STEP-LOOP", `nextAction = ${nextAction}`);
|
|
570
|
-
if (nextAction === "complete")
|
|
571
|
-
return "complete";
|
|
572
|
-
if (nextAction === "request-feedback")
|
|
573
|
-
return "request-feedback";
|
|
574
|
-
if (nextAction === "redo-step")
|
|
575
|
-
continue;
|
|
576
|
-
if (nextAction === "expand-scope")
|
|
577
|
-
return "expand-scope";
|
|
578
|
-
}
|
|
579
|
-
return "continue";
|
|
580
|
-
}
|
|
581
|
-
/* ───────────── work iteration ───────────── */
|
|
582
|
-
/**
|
|
583
|
-
* Executes one analyze/transform/validate pass for the current task step.
|
|
584
|
-
* Example: generate analysis plan, run one transform step, then validate.
|
|
585
|
-
*/
|
|
586
|
-
async runWorkIteration(taskStep) {
|
|
587
|
-
if (!this.context.analysis)
|
|
588
|
-
this.context.analysis = {};
|
|
589
|
-
if (taskStep.action?.startsWith("research-")) {
|
|
590
|
-
await this.executeResearchTaskStep(taskStep);
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
if (canExecutePhase(this.context, "analysis") && canExecuteScope(this.context, "analysis")) {
|
|
594
|
-
const tAnalysis = this.startTimer();
|
|
595
|
-
await analysisPlanGenStep.run(this.context);
|
|
596
|
-
this.logLine("PLAN", "analysisPlanGen", tAnalysis(), undefined, { highlight: false });
|
|
597
|
-
const analysisPlan = this.context.analysis?.planSuggestion?.plan ?? { steps: [] };
|
|
598
|
-
for (const step of analysisPlan.steps) {
|
|
599
|
-
const tStep = this.startTimer();
|
|
600
|
-
await this.executeStep(step, { query: this.query });
|
|
601
|
-
this.logLine("PLANNING-STEP", step.action || "unnamedStep", tStep());
|
|
602
|
-
}
|
|
603
|
-
if (this.context.analysis)
|
|
604
|
-
this.context.analysis.planSuggestion = undefined;
|
|
605
|
-
}
|
|
606
|
-
if (canExecutePhase(this.context, "transform") &&
|
|
607
|
-
canExecuteScope(this.context, "transform") &&
|
|
608
|
-
canExecuteRoute(this.context, "transform")) {
|
|
609
|
-
const tTransform = this.startTimer();
|
|
610
|
-
await transformPlanGenStep.run(this.context);
|
|
611
|
-
this.logLine("PLAN", "transformPlanGen", tTransform(), undefined, { highlight: false });
|
|
612
|
-
const transformPlan = this.context.analysis?.planSuggestion?.plan ?? { steps: [] };
|
|
613
|
-
const firstStep = transformPlan.steps[0];
|
|
614
|
-
if (firstStep) {
|
|
615
|
-
const tStep = this.startTimer();
|
|
616
|
-
await this.executeStep(firstStep, { query: this.query });
|
|
617
|
-
this.logLine("PLANNING-STEP", `#1 (only) - ${firstStep.action || "unnamedStep"}`, tStep());
|
|
618
|
-
}
|
|
619
|
-
if (this.context.analysis)
|
|
620
|
-
this.context.analysis.planSuggestion = undefined;
|
|
621
|
-
if (canExecutePhase(this.context, "write") && canExecuteScope(this.context, "write")) {
|
|
622
|
-
const tWrite = this.startTimer();
|
|
623
|
-
await writeFileStep.run({ query: this.query, context: this.context });
|
|
624
|
-
this.logLine("WRITE", "writeFileStep", tWrite());
|
|
625
|
-
}
|
|
626
|
-
const tValidate = this.startTimer();
|
|
627
|
-
await validateChangesStep.run(this.context);
|
|
628
|
-
this.logLine("VALIDATION", "validateChangesStep", tValidate());
|
|
629
|
-
}
|
|
630
|
-
const tReason = this.startTimer();
|
|
631
|
-
await reasonNextStep.run(this.context, taskStep);
|
|
632
|
-
this.logLine("REASONING", "reasonNextStep", tReason());
|
|
633
|
-
const tCollab = this.startTimer();
|
|
634
|
-
await collaboratorStep.run(this.context);
|
|
635
|
-
this.logLine("FEEDBACK", "collaboratorStep", tCollab());
|
|
636
|
-
const tIntegrate = this.startTimer();
|
|
637
|
-
await integrateFeedbackStep.run(this.context);
|
|
638
|
-
this.logLine("FEEDBACK", "integrateFeedbackStep", tIntegrate());
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Executes deterministic research steps and marks them complete.
|
|
642
|
-
* Example: research-impact-map summarizes affected files and seeds understanding notes.
|
|
643
|
-
*/
|
|
644
|
-
async executeResearchTaskStep(taskStep) {
|
|
645
|
-
var _a, _b;
|
|
646
|
-
const selectedFiles = this.context.analysis?.focus?.selectedFiles ?? [];
|
|
647
|
-
const candidateFiles = this.context.analysis?.focus?.candidateFiles ?? [];
|
|
648
|
-
const fileAnalysis = this.context.analysis?.fileAnalysis ?? {};
|
|
649
|
-
const researchTerms = this.buildResearchTerms();
|
|
650
|
-
const researchPaths = this.collectResearchPaths(24);
|
|
651
|
-
const corpus = this.loadResearchCorpus(researchPaths, 12, 12000);
|
|
652
|
-
const understanding = (_b = ((_a = this.context).analysis || (_a.analysis = {}))).understanding || (_b.understanding = {
|
|
653
|
-
assumptions: [],
|
|
654
|
-
constraints: [],
|
|
655
|
-
risks: [],
|
|
656
|
-
sharedPatterns: [],
|
|
657
|
-
hotspots: [],
|
|
658
|
-
couplingPoints: [],
|
|
659
|
-
});
|
|
660
|
-
const addUnique = (arr, value) => {
|
|
661
|
-
if (!arr)
|
|
662
|
-
return;
|
|
663
|
-
if (!arr.includes(value))
|
|
664
|
-
arr.push(value);
|
|
665
|
-
};
|
|
666
|
-
let summary = "";
|
|
667
|
-
let collectedData = {
|
|
668
|
-
selectedFiles: selectedFiles.slice(0, 12),
|
|
669
|
-
selectedFileCount: selectedFiles.length,
|
|
670
|
-
candidateFileCount: candidateFiles.length,
|
|
671
|
-
researchTerms,
|
|
672
|
-
corpusFilesRead: corpus.length,
|
|
673
|
-
corpusPaths: corpus.map(f => f.path).slice(0, 12),
|
|
674
|
-
};
|
|
675
|
-
switch (taskStep.action) {
|
|
676
|
-
case "research-impact-map": {
|
|
677
|
-
const touched = selectedFiles.length;
|
|
678
|
-
const impactRows = corpus
|
|
679
|
-
.map(file => {
|
|
680
|
-
const termHits = this.computeTermHits(file.content, researchTerms);
|
|
681
|
-
const termHitTotal = Object.values(termHits).reduce((acc, n) => acc + n, 0);
|
|
682
|
-
const importCount = this.countRegex(file.content, /\bimport\b|\brequire\s*\(/g);
|
|
683
|
-
const exportCount = this.countRegex(file.content, /\bexport\b|module\.exports/g);
|
|
684
|
-
const score = termHitTotal * 3 + importCount * 2 + exportCount;
|
|
685
|
-
return {
|
|
686
|
-
filePath: file.path,
|
|
687
|
-
score,
|
|
688
|
-
termHits,
|
|
689
|
-
importCount,
|
|
690
|
-
exportCount,
|
|
691
|
-
lineCount: file.lineCount,
|
|
692
|
-
};
|
|
693
|
-
})
|
|
694
|
-
.sort((a, b) => b.score - a.score)
|
|
695
|
-
.slice(0, 8);
|
|
696
|
-
summary = `Impact map across ${touched} selected file(s).`;
|
|
697
|
-
addUnique(understanding.constraints, `Refactor impact spans ${touched} file(s).`);
|
|
698
|
-
collectedData = {
|
|
699
|
-
...collectedData,
|
|
700
|
-
touchedFiles: selectedFiles.slice(0, 20),
|
|
701
|
-
impactSignals: [
|
|
702
|
-
`selected=${selectedFiles.length}`,
|
|
703
|
-
`candidates=${candidateFiles.length}`,
|
|
704
|
-
],
|
|
705
|
-
impactMap: impactRows,
|
|
706
|
-
};
|
|
707
|
-
break;
|
|
708
|
-
}
|
|
709
|
-
case "research-symbol-trace": {
|
|
710
|
-
const structuralSymbols = Object.values(fileAnalysis)
|
|
711
|
-
.flatMap(fa => fa.structural?.functions?.map(fn => fn.name).filter(Boolean) ?? [])
|
|
712
|
-
.slice(0, 24);
|
|
713
|
-
const fallbackSymbols = corpus
|
|
714
|
-
.flatMap(file => Array.from(file.content.matchAll(/\b(function|class|const|let|var)\s+([A-Za-z_]\w*)/g)).map(m => m[2]))
|
|
715
|
-
.filter(Boolean);
|
|
716
|
-
const symbolPool = Array.from(new Set([...structuralSymbols, ...fallbackSymbols])).slice(0, 18);
|
|
717
|
-
const traceRows = symbolPool
|
|
718
|
-
.map(symbol => {
|
|
719
|
-
const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
720
|
-
const re = new RegExp(`\\b${escaped}\\b`, "g");
|
|
721
|
-
const files = corpus
|
|
722
|
-
.map(file => ({ filePath: file.path, count: this.countRegex(file.content, re) }))
|
|
723
|
-
.filter(item => item.count > 0);
|
|
724
|
-
return {
|
|
725
|
-
symbol,
|
|
726
|
-
occurrenceCount: files.reduce((acc, f) => acc + f.count, 0),
|
|
727
|
-
files: files.slice(0, 8),
|
|
728
|
-
};
|
|
729
|
-
})
|
|
730
|
-
.filter(row => row.occurrenceCount > 0)
|
|
731
|
-
.sort((a, b) => b.occurrenceCount - a.occurrenceCount)
|
|
732
|
-
.slice(0, 10);
|
|
733
|
-
summary = traceRows.length
|
|
734
|
-
? `Traced ${traceRows.length} symbol(s) from corpus.`
|
|
735
|
-
: "No structural symbols found; symbol trace used filename-level anchors.";
|
|
736
|
-
addUnique(understanding.assumptions, "Symbol trace coverage is partial and based on current selected files.");
|
|
737
|
-
collectedData = {
|
|
738
|
-
...collectedData,
|
|
739
|
-
tracedSymbols: traceRows.map(s => s.symbol),
|
|
740
|
-
symbolTrace: traceRows,
|
|
741
|
-
analyzedFileCount: Object.values(fileAnalysis).filter(fa => fa?.semanticAnalyzed).length,
|
|
742
|
-
};
|
|
743
|
-
break;
|
|
744
|
-
}
|
|
745
|
-
case "research-risk-check": {
|
|
746
|
-
const riskPatterns = [
|
|
747
|
-
{ id: "empty-catch", description: "Empty catch blocks", pattern: /catch\s*\(\s*[^)]*\)\s*\{\s*\}/g },
|
|
748
|
-
{ id: "console-error", description: "Console error logging", pattern: /\bconsole\.error\s*\(/g },
|
|
749
|
-
{ id: "forced-exit", description: "Process exit usage", pattern: /\bprocess\.exit\s*\(/g },
|
|
750
|
-
{ id: "throws-string", description: "Throwing non-Error values", pattern: /\bthrow\s+['"`]/g },
|
|
751
|
-
];
|
|
752
|
-
const riskRows = riskPatterns
|
|
753
|
-
.map(risk => {
|
|
754
|
-
const perFile = corpus
|
|
755
|
-
.map(file => ({ filePath: file.path, count: this.countRegex(file.content, risk.pattern) }))
|
|
756
|
-
.filter(hit => hit.count > 0);
|
|
757
|
-
return {
|
|
758
|
-
id: risk.id,
|
|
759
|
-
description: risk.description,
|
|
760
|
-
totalHits: perFile.reduce((acc, hit) => acc + hit.count, 0),
|
|
761
|
-
files: perFile.slice(0, 8),
|
|
762
|
-
};
|
|
763
|
-
})
|
|
764
|
-
.filter(risk => risk.totalHits > 0);
|
|
765
|
-
summary = "Recorded baseline risks/assumptions/constraints before transformation.";
|
|
766
|
-
addUnique(understanding.risks, "Cross-file regressions are possible without full symbol coverage.");
|
|
767
|
-
addUnique(understanding.risks, "Validation should run after each transform step.");
|
|
768
|
-
for (const risk of riskRows) {
|
|
769
|
-
addUnique(understanding.risks, `${risk.description}: ${risk.totalHits} hit(s)`);
|
|
770
|
-
}
|
|
771
|
-
collectedData = {
|
|
772
|
-
...collectedData,
|
|
773
|
-
risks: understanding.risks?.slice(0, 12) ?? [],
|
|
774
|
-
assumptions: understanding.assumptions?.slice(0, 12) ?? [],
|
|
775
|
-
constraints: understanding.constraints?.slice(0, 12) ?? [],
|
|
776
|
-
riskSignals: riskRows,
|
|
777
|
-
};
|
|
778
|
-
break;
|
|
779
|
-
}
|
|
780
|
-
case "research-architecture-synthesis": {
|
|
781
|
-
const analyzedPaths = Object.entries(fileAnalysis)
|
|
782
|
-
.filter(([_, fa]) => fa?.semanticAnalyzed)
|
|
783
|
-
.map(([filePath]) => filePath);
|
|
784
|
-
const architectureFiles = (analyzedPaths.length > 0 ? analyzedPaths : corpus.map(file => file.path)).slice(0, 8);
|
|
785
|
-
understanding.problemStatement =
|
|
786
|
-
`Summarize repository architecture and identify weak coupling points across ${selectedFiles.length} scoped file(s).`;
|
|
787
|
-
for (const p of architectureFiles) {
|
|
788
|
-
const base = path.basename(p);
|
|
789
|
-
if (base.toLowerCase().includes("registry")) {
|
|
790
|
-
addUnique(understanding.hotspots, `${base}: central registry point with broad module fan-in.`);
|
|
791
|
-
addUnique(understanding.couplingPoints, `${base}: centralized module registration coupling.`);
|
|
792
|
-
}
|
|
793
|
-
if (base.toLowerCase().includes("module")) {
|
|
794
|
-
addUnique(understanding.sharedPatterns, `${base}: module-oriented pipeline pattern.`);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
addUnique(understanding.sharedPatterns, "Pipeline modules follow a shared Module/ModuleIO contract.");
|
|
798
|
-
addUnique(understanding.couplingPoints, "Shared config/model utilities create cross-module coupling.");
|
|
799
|
-
addUnique(understanding.hotspots, "Core orchestration and registry layers are high-impact change zones.");
|
|
800
|
-
summary = `Architecture synthesis completed from ${architectureFiles.length} analyzed file(s).`;
|
|
801
|
-
const priorResearch = (this.context.task?.taskSteps ?? [])
|
|
802
|
-
.filter(step => step.action?.startsWith("research-") && step.status === "completed")
|
|
803
|
-
.map(step => ({
|
|
804
|
-
action: step.action,
|
|
805
|
-
summary: step.result?.research?.summary,
|
|
806
|
-
}));
|
|
807
|
-
collectedData = {
|
|
808
|
-
...collectedData,
|
|
809
|
-
architectureInputFiles: architectureFiles,
|
|
810
|
-
priorResearchSummaries: priorResearch,
|
|
811
|
-
problemStatement: understanding.problemStatement ?? "",
|
|
812
|
-
sharedPatterns: understanding.sharedPatterns?.slice(0, 12) ?? [],
|
|
813
|
-
hotspots: understanding.hotspots?.slice(0, 12) ?? [],
|
|
814
|
-
couplingPoints: understanding.couplingPoints?.slice(0, 12) ?? [],
|
|
815
|
-
};
|
|
816
|
-
break;
|
|
817
|
-
}
|
|
818
|
-
default: {
|
|
819
|
-
summary = `Unknown research action: ${taskStep.action}`;
|
|
820
|
-
collectedData = {
|
|
821
|
-
...collectedData,
|
|
822
|
-
warning: "No handler for research action",
|
|
823
|
-
};
|
|
824
|
-
break;
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
const completedAt = new Date().toISOString();
|
|
828
|
-
const researchEntry = {
|
|
829
|
-
action: taskStep.action,
|
|
830
|
-
summary,
|
|
831
|
-
collectedData,
|
|
832
|
-
selectedFileCount: selectedFiles.length,
|
|
833
|
-
completedAt,
|
|
834
|
-
};
|
|
835
|
-
taskStep.result || (taskStep.result = {});
|
|
836
|
-
taskStep.result.research = researchEntry;
|
|
837
|
-
taskStep.result.stepReasoning = {
|
|
838
|
-
nextAction: "complete",
|
|
839
|
-
rationale: `Research step completed: ${summary}`,
|
|
840
|
-
confidence: 0.95,
|
|
841
|
-
};
|
|
842
|
-
taskStep.status = "completed";
|
|
843
|
-
this.persistResearchArtifact(researchEntry);
|
|
844
|
-
logInputOutput("runResearchStep", "output", {
|
|
845
|
-
research: researchEntry,
|
|
846
|
-
stepReasoning: taskStep.result.stepReasoning,
|
|
847
|
-
status: taskStep.status,
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* Persists normalized research outputs into analysis.researchArtifacts.
|
|
852
|
-
* Example: latestByAction["research-risk-check"] stores current risk findings.
|
|
853
|
-
*/
|
|
854
|
-
persistResearchArtifact(entry) {
|
|
855
|
-
var _a, _b;
|
|
856
|
-
(_a = this.context).analysis || (_a.analysis = {});
|
|
857
|
-
const store = (_b = this.context.analysis).researchArtifacts || (_b.researchArtifacts = {
|
|
858
|
-
latestByAction: {},
|
|
859
|
-
history: [],
|
|
860
|
-
touchedFiles: [],
|
|
861
|
-
lastUpdatedAt: entry.completedAt,
|
|
862
|
-
});
|
|
863
|
-
store.latestByAction || (store.latestByAction = {});
|
|
864
|
-
store.history || (store.history = []);
|
|
865
|
-
store.touchedFiles || (store.touchedFiles = []);
|
|
866
|
-
store.latestByAction[entry.action] = entry;
|
|
867
|
-
store.history.push(entry);
|
|
868
|
-
const data = entry.collectedData ?? {};
|
|
869
|
-
const touched = this.extractPathsFromResearchData(data);
|
|
870
|
-
const merged = new Set([...(store.touchedFiles ?? []), ...touched]);
|
|
871
|
-
store.touchedFiles = Array.from(merged);
|
|
872
|
-
store.lastUpdatedAt = entry.completedAt;
|
|
873
|
-
}
|
|
874
|
-
/**
|
|
875
|
-
* Extracts file paths from heterogeneous research payloads.
|
|
876
|
-
* Example: impactMap rows and architectureInputFiles are both merged into touchedFiles.
|
|
877
|
-
*/
|
|
878
|
-
extractPathsFromResearchData(data) {
|
|
879
|
-
const paths = new Set();
|
|
880
|
-
const addPath = (value) => {
|
|
881
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
882
|
-
paths.add(value);
|
|
883
|
-
}
|
|
884
|
-
};
|
|
885
|
-
const addPathArray = (value) => {
|
|
886
|
-
if (!Array.isArray(value))
|
|
887
|
-
return;
|
|
888
|
-
for (const item of value) {
|
|
889
|
-
addPath(item);
|
|
890
|
-
}
|
|
891
|
-
};
|
|
892
|
-
addPathArray(data.corpusPaths);
|
|
893
|
-
addPathArray(data.touchedFiles);
|
|
894
|
-
addPathArray(data.architectureInputFiles);
|
|
895
|
-
if (Array.isArray(data.impactMap)) {
|
|
896
|
-
for (const row of data.impactMap) {
|
|
897
|
-
addPath(row.filePath);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
if (Array.isArray(data.symbolTrace)) {
|
|
901
|
-
for (const row of data.symbolTrace) {
|
|
902
|
-
const files = row.files;
|
|
903
|
-
if (!Array.isArray(files))
|
|
904
|
-
continue;
|
|
905
|
-
for (const fileRow of files) {
|
|
906
|
-
addPath(fileRow.filePath);
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
if (Array.isArray(data.riskSignals)) {
|
|
911
|
-
for (const row of data.riskSignals) {
|
|
912
|
-
const files = row.files;
|
|
913
|
-
if (!Array.isArray(files))
|
|
914
|
-
continue;
|
|
915
|
-
for (const fileRow of files) {
|
|
916
|
-
addPath(fileRow.filePath);
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
return Array.from(paths);
|
|
921
|
-
}
|
|
922
|
-
/**
|
|
923
|
-
* Builds lightweight query terms for deterministic research scanning.
|
|
924
|
-
* Example: "error handling test suite" -> ["error","handling","test","suite"].
|
|
925
|
-
*/
|
|
926
|
-
buildResearchTerms() {
|
|
927
|
-
const query = this.context.analysis?.intent?.normalizedQuery ??
|
|
928
|
-
this.context.initContext?.userQuery ??
|
|
929
|
-
this.query;
|
|
930
|
-
const stopWords = new Set([
|
|
931
|
-
"the", "and", "for", "with", "from", "this", "that", "what", "how",
|
|
932
|
-
"is", "are", "was", "were", "can", "could", "should", "would", "into",
|
|
933
|
-
"about", "across", "repo", "codebase", "please",
|
|
934
|
-
]);
|
|
935
|
-
return Array.from(new Set(query
|
|
936
|
-
.toLowerCase()
|
|
937
|
-
.split(/[^a-z0-9_]+/g)
|
|
938
|
-
.filter(token => token.length >= 3 && !stopWords.has(token)))).slice(0, 10);
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Collects research candidate paths from selected, candidate, related, and working files.
|
|
942
|
-
* Example: selected files are prioritized before broader related file pool.
|
|
943
|
-
*/
|
|
944
|
-
collectResearchPaths(maxPaths) {
|
|
945
|
-
const focus = this.context.analysis?.focus;
|
|
946
|
-
const workingPaths = (this.context.workingFiles ?? []).map(file => file.path);
|
|
947
|
-
const related = this.context.initContext?.relatedFiles ?? [];
|
|
948
|
-
const combined = [
|
|
949
|
-
...(focus?.selectedFiles ?? []),
|
|
950
|
-
...(focus?.candidateFiles ?? []),
|
|
951
|
-
...workingPaths,
|
|
952
|
-
...related,
|
|
953
|
-
];
|
|
954
|
-
const unique = Array.from(new Set(combined));
|
|
955
|
-
return unique
|
|
956
|
-
.filter(filePath => !filePath.startsWith("__research__/") && fs.existsSync(filePath))
|
|
957
|
-
.slice(0, maxPaths);
|
|
958
|
-
}
|
|
959
|
-
/**
|
|
960
|
-
* Reads a bounded corpus from candidate paths.
|
|
961
|
-
* Example: read first 12 files, max 12k chars per file, skipping binary payloads.
|
|
962
|
-
*/
|
|
963
|
-
loadResearchCorpus(filePaths, maxFiles, maxCharsPerFile) {
|
|
964
|
-
const corpus = [];
|
|
965
|
-
for (const filePath of filePaths.slice(0, maxFiles)) {
|
|
966
|
-
try {
|
|
967
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
968
|
-
if (raw.includes("\u0000"))
|
|
969
|
-
continue;
|
|
970
|
-
const content = raw.slice(0, maxCharsPerFile);
|
|
971
|
-
corpus.push({
|
|
972
|
-
path: filePath,
|
|
973
|
-
content,
|
|
974
|
-
lineCount: content.split("\n").length,
|
|
975
|
-
charCount: content.length,
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
catch {
|
|
979
|
-
// Ignore unreadable files and continue.
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
return corpus;
|
|
983
|
-
}
|
|
984
|
-
/**
|
|
985
|
-
* Counts regex matches safely.
|
|
986
|
-
* Example: countRegex(code, /import/g) -> number of import occurrences.
|
|
987
|
-
*/
|
|
988
|
-
countRegex(content, pattern) {
|
|
989
|
-
const source = pattern.source;
|
|
990
|
-
const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
|
|
991
|
-
const re = new RegExp(source, flags);
|
|
992
|
-
return Array.from(content.matchAll(re)).length;
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* Computes per-term match counts for a file body.
|
|
996
|
-
* Example: terms ["error","test"] -> { error: 4, test: 2 }.
|
|
997
|
-
*/
|
|
998
|
-
computeTermHits(content, terms) {
|
|
999
|
-
const hits = {};
|
|
1000
|
-
for (const term of terms) {
|
|
1001
|
-
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1002
|
-
const count = this.countRegex(content, new RegExp(`\\b${escaped}\\b`, "gi"));
|
|
1003
|
-
if (count > 0) {
|
|
1004
|
-
hits[term] = count;
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
return hits;
|
|
1008
|
-
}
|
|
1009
|
-
/* ───────────── step executor ───────────── */
|
|
1010
|
-
/**
|
|
1011
|
-
* Executes a single step using its corresponding module.
|
|
1012
|
-
*
|
|
1013
|
-
* @param step - The step to execute.
|
|
1014
|
-
* @param input - The input data for the step.
|
|
1015
|
-
* @returns A promise resolving to the output of the step.
|
|
1016
|
-
* @throws If the module is not found or execution fails.
|
|
1017
|
-
*/
|
|
1018
|
-
async executeStep(step, input) {
|
|
1019
|
-
const stop = this.startTimer();
|
|
1020
|
-
this.context.currentStep = step;
|
|
1021
|
-
const mod = resolveModuleForAction(step.action);
|
|
1022
|
-
if (!mod) {
|
|
1023
|
-
this.logLine("EXECUTE", step.action, stop(), "skipped (missing module)");
|
|
1024
|
-
return { query: input.query, content: input.content, data: { skipped: true } };
|
|
1025
|
-
}
|
|
1026
|
-
try {
|
|
1027
|
-
const stepTarget = step.targetFile ? this.formatPathForLog(step.targetFile) : undefined;
|
|
1028
|
-
this.ui.update(stepTarget ? `Running ${step.action} on ${stepTarget}` : `Running ${step.action}`);
|
|
1029
|
-
const output = await mod.run({ query: step.description ?? input.query, content: input.data ?? input.content, context: this.context });
|
|
1030
|
-
const errors = Array.isArray(output.data?.errors)
|
|
1031
|
-
? output.data.errors.filter((e) => typeof e === "string" && e.trim().length > 0)
|
|
1032
|
-
: [];
|
|
1033
|
-
if (errors.length > 0) {
|
|
1034
|
-
const detail = errors.slice(0, 2).join(" | ");
|
|
1035
|
-
this.logLine("EXECUTE", step.action, stop(), `completed with errors: ${detail}`);
|
|
1036
|
-
console.error(`[${step.action}] ${errors.join(" | ")}`);
|
|
1037
|
-
}
|
|
1038
|
-
return output;
|
|
1039
|
-
}
|
|
1040
|
-
catch (err) {
|
|
1041
|
-
this.logLine("EXECUTE", step.action, stop(), "failed");
|
|
1042
|
-
throw err;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
/* ───────────── extracted from runSearch ───────────── */
|
|
1046
|
-
resolveInitialRetrievalQueries() {
|
|
1047
|
-
const rawUserQuery = this.context.initContext?.userQuery ?? this.query;
|
|
1048
|
-
const retrievalQuery = this.context.analysis?.intent?.normalizedQuery?.trim() || rawUserQuery;
|
|
1049
|
-
return { rawUserQuery, retrievalQuery };
|
|
1050
|
-
}
|
|
1051
|
-
async fetchInitialRetrievalResults(retrievalQuery) {
|
|
1052
|
-
return semanticSearchFiles(retrievalQuery, RELATED_FILES_LIMIT, this.context.analysis?.intent ?? {});
|
|
1053
|
-
}
|
|
1054
|
-
mapSearchResultToTopFile(result) {
|
|
1055
|
-
return {
|
|
1056
|
-
id: result.id,
|
|
1057
|
-
path: result.path,
|
|
1058
|
-
summary: result.summary ?? undefined,
|
|
1059
|
-
bm25Score: result.bm25Score,
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
mapSearchResultToRelatedFile(result) {
|
|
1063
|
-
return {
|
|
1064
|
-
id: result.id,
|
|
1065
|
-
path: result.path,
|
|
1066
|
-
summary: result.summary ?? undefined,
|
|
1067
|
-
bm25Score: result.bm25Score,
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
buildInitialRetrievalPromptArgs(results, retrievalQuery) {
|
|
1071
|
-
const topFiles = results
|
|
1072
|
-
.slice(0, NUM_TOPFILES)
|
|
1073
|
-
.map(result => this.mapSearchResultToTopFile(result));
|
|
1074
|
-
const relatedFiles = results
|
|
1075
|
-
.slice(NUM_TOPFILES)
|
|
1076
|
-
.map(result => this.mapSearchResultToRelatedFile(result));
|
|
1077
|
-
const queryExpansionTerms = results.find(result => Array.isArray(result.queryExpansionTerms))?.queryExpansionTerms;
|
|
1078
|
-
return {
|
|
1079
|
-
topFiles,
|
|
1080
|
-
relatedFiles,
|
|
1081
|
-
query: retrievalQuery,
|
|
1082
|
-
queryExpansionTerms,
|
|
1083
|
-
};
|
|
1084
|
-
}
|
|
1085
|
-
mergeSeededInitialContext(rawUserQuery, seededContext) {
|
|
1086
|
-
// Merge retrieval seed into initContext without losing previously discovered files.
|
|
1087
|
-
// Example: keep old relatedFiles and append newly seeded files from buildLightContext.
|
|
1088
|
-
const existingInit = this.context.initContext ?? { userQuery: rawUserQuery };
|
|
1089
|
-
const seededInit = seededContext.initContext;
|
|
1090
|
-
const mergedRelatedFiles = Array.from(new Set([
|
|
1091
|
-
...(existingInit.relatedFiles ?? []),
|
|
1092
|
-
...(seededInit?.relatedFiles ?? []),
|
|
1093
|
-
]));
|
|
1094
|
-
const mergedScores = {
|
|
1095
|
-
...(existingInit.relatedFileScores ?? {}),
|
|
1096
|
-
...(seededInit?.relatedFileScores ?? {}),
|
|
1097
|
-
};
|
|
1098
|
-
const mergedQueryExpansionTerms = Array.from(new Set([
|
|
1099
|
-
...(existingInit.queryExpansionTerms ?? []),
|
|
1100
|
-
...(seededInit?.queryExpansionTerms ?? []),
|
|
1101
|
-
]));
|
|
1102
|
-
this.context.initContext = {
|
|
1103
|
-
...existingInit,
|
|
1104
|
-
...(seededInit ?? {}),
|
|
1105
|
-
userQuery: rawUserQuery,
|
|
1106
|
-
relatedFiles: mergedRelatedFiles,
|
|
1107
|
-
relatedFileScores: mergedScores,
|
|
1108
|
-
queryExpansionTerms: mergedQueryExpansionTerms,
|
|
1109
|
-
folderCapsules: (seededInit?.folderCapsules?.length
|
|
1110
|
-
? seededInit.folderCapsules
|
|
1111
|
-
: existingInit.folderCapsules) ?? [],
|
|
1112
|
-
};
|
|
1113
|
-
return mergedRelatedFiles.length;
|
|
1114
|
-
}
|
|
1115
|
-
applyDeterministicPreGroundingPrefilter(retrievalQuery) {
|
|
1116
|
-
// Rank and cap retrieval candidates before grounding to reduce noisy evidence passes.
|
|
1117
|
-
// Example: explicit filename anchors are always kept even if BM25 score is low.
|
|
1118
|
-
const init = this.context.initContext;
|
|
1119
|
-
if (!init?.relatedFiles?.length)
|
|
1120
|
-
return { before: 0, after: 0 };
|
|
1121
|
-
const before = init.relatedFiles.length;
|
|
1122
|
-
const scored = scoreCandidateFiles(init.relatedFiles, init.relatedFileScores ?? {}, retrievalQuery);
|
|
1123
|
-
if (scored.length === 0)
|
|
1124
|
-
return { before, after: before };
|
|
1125
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
1126
|
-
const baseKeepCount = scope === "single-file" ? 6 : 10;
|
|
1127
|
-
const keepCount = Math.min(Math.max(3, baseKeepCount), scored.length);
|
|
1128
|
-
const selected = new Set(scored
|
|
1129
|
-
.slice(0, keepCount)
|
|
1130
|
-
.map(item => item.filePath));
|
|
1131
|
-
for (const item of scored) {
|
|
1132
|
-
if (item.reasons.includes("exact-filename") || item.reasons.includes("path-anchor")) {
|
|
1133
|
-
selected.add(item.filePath);
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
init.relatedFiles = scored
|
|
1137
|
-
.filter(item => selected.has(item.filePath))
|
|
1138
|
-
.map(item => item.filePath);
|
|
1139
|
-
init.relatedFileScores = Object.fromEntries(Object.entries(init.relatedFileScores ?? {})
|
|
1140
|
-
.filter(([filePath]) => selected.has(filePath)));
|
|
1141
|
-
logInputOutput("deterministicPreGroundingPrefilter", "output", {
|
|
1142
|
-
retrievalQuery,
|
|
1143
|
-
scope,
|
|
1144
|
-
before,
|
|
1145
|
-
after: init.relatedFiles.length,
|
|
1146
|
-
keepCount,
|
|
1147
|
-
files: scored.map(item => ({
|
|
1148
|
-
file: item.filePath,
|
|
1149
|
-
score: Number(item.score.toFixed(2)),
|
|
1150
|
-
bm25Raw: item.bm25Raw,
|
|
1151
|
-
kept: selected.has(item.filePath),
|
|
1152
|
-
reasons: item.reasons,
|
|
1153
|
-
})),
|
|
1154
|
-
});
|
|
1155
|
-
return { before, after: init.relatedFiles.length };
|
|
1156
|
-
}
|
|
1157
|
-
injectWellKnownRepoFiles(currentCount) {
|
|
1158
|
-
// Add high-signal repo root files when scope is broad or retrieval is sparse.
|
|
1159
|
-
// Example: on repo-wide queries, include package.json/README if present.
|
|
1160
|
-
const init = this.context.initContext;
|
|
1161
|
-
if (!init)
|
|
1162
|
-
return { added: 0, reason: "none" };
|
|
1163
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
1164
|
-
const shouldInjectByScope = scope === "repo-wide";
|
|
1165
|
-
const shouldInjectByFallback = currentCount < 3;
|
|
1166
|
-
if (!shouldInjectByScope && !shouldInjectByFallback) {
|
|
1167
|
-
return { added: 0, reason: "none" };
|
|
1168
|
-
}
|
|
1169
|
-
const reason = shouldInjectByScope ? "scope" : "fallback";
|
|
1170
|
-
const candidates = WELL_KNOWN_REPO_FILE_BASENAMES
|
|
1171
|
-
.map(fileName => path.join(process.cwd(), fileName))
|
|
1172
|
-
.filter(filePath => fs.existsSync(filePath))
|
|
1173
|
-
.slice(0, MAX_WELL_KNOWN_REPO_FILES);
|
|
1174
|
-
if (candidates.length === 0)
|
|
1175
|
-
return { added: 0, reason };
|
|
1176
|
-
const existing = new Set(init.relatedFiles ?? []);
|
|
1177
|
-
let added = 0;
|
|
1178
|
-
for (const filePath of candidates) {
|
|
1179
|
-
if (existing.has(filePath))
|
|
1180
|
-
continue;
|
|
1181
|
-
existing.add(filePath);
|
|
1182
|
-
added++;
|
|
1183
|
-
}
|
|
1184
|
-
init.relatedFiles = Array.from(existing);
|
|
1185
|
-
return { added, reason };
|
|
1186
|
-
}
|
|
1187
|
-
/**
|
|
1188
|
-
* Captures focus sizes before/after a verify wave for growth tracking.
|
|
1189
|
-
* Example: selected=3,candidate=7 before wave; selected=4,candidate=9 after wave.
|
|
1190
|
-
*/
|
|
1191
|
-
captureVerifyFocusSnapshot() {
|
|
1192
|
-
return {
|
|
1193
|
-
selected: this.context.analysis?.focus?.selectedFiles?.length ?? 0,
|
|
1194
|
-
candidate: this.context.analysis?.focus?.candidateFiles?.length ?? 0,
|
|
1195
|
-
};
|
|
1196
|
-
}
|
|
1197
|
-
/**
|
|
1198
|
-
* Logs selected/candidate deltas for a verify wave and returns whether focus grew.
|
|
1199
|
-
* Example: selected 3->4 (+1), candidate 7->9 (+2) => growth=true.
|
|
1200
|
-
*/
|
|
1201
|
-
logVerifyFocusDelta(before, after) {
|
|
1202
|
-
const selectedDelta = after.selected - before.selected;
|
|
1203
|
-
const candidateDelta = after.candidate - before.candidate;
|
|
1204
|
-
this.logLine("ANALYSIS", "groundingDelta", undefined, `selected ${before.selected}->${after.selected} (${selectedDelta >= 0 ? "+" : ""}${selectedDelta}), candidate ${before.candidate}->${after.candidate} (${candidateDelta >= 0 ? "+" : ""}${candidateDelta})`);
|
|
1205
|
-
return selectedDelta > 0 || candidateDelta > 0;
|
|
1206
|
-
}
|
|
1207
|
-
/**
|
|
1208
|
-
* Stops verify loop when focus has not grown for too many consecutive waves.
|
|
1209
|
-
* Example: 2 stagnant waves in a row => stop early to avoid useless loops.
|
|
1210
|
-
*/
|
|
1211
|
-
shouldStopVerifyForSaturation(stagnantWaves, maxStagnantWaves) {
|
|
1212
|
-
if (stagnantWaves < maxStagnantWaves)
|
|
1213
|
-
return false;
|
|
1214
|
-
this.logLine("ANALYSIS", "groundingSaturated", undefined, `No focus growth for ${stagnantWaves} consecutive wave(s); stopping early`);
|
|
1215
|
-
return true;
|
|
1216
|
-
}
|
|
1217
|
-
/**
|
|
1218
|
-
* Drops missing files from retrieval/focus sets to avoid verifier ENOENT noise.
|
|
1219
|
-
* Example: if DB points to deleted explainModule.ts, remove it before evidence pass.
|
|
1220
|
-
*/
|
|
1221
|
-
pruneMissingVerifyPaths() {
|
|
1222
|
-
const init = this.context.initContext;
|
|
1223
|
-
const focus = this.context.analysis?.focus;
|
|
1224
|
-
if (!init && !focus)
|
|
1225
|
-
return;
|
|
1226
|
-
const existsOrResearch = (filePath) => {
|
|
1227
|
-
if (filePath.startsWith("__research__/"))
|
|
1228
|
-
return true;
|
|
1229
|
-
if (isPathIgnoredByFolderGlobs(filePath))
|
|
1230
|
-
return false;
|
|
1231
|
-
return fs.existsSync(filePath);
|
|
1232
|
-
};
|
|
1233
|
-
let removedRelated = 0;
|
|
1234
|
-
let removedSelected = 0;
|
|
1235
|
-
let removedCandidate = 0;
|
|
1236
|
-
if (init?.relatedFiles?.length) {
|
|
1237
|
-
const existing = init.relatedFiles;
|
|
1238
|
-
init.relatedFiles = existing.filter(filePath => {
|
|
1239
|
-
const keep = existsOrResearch(filePath);
|
|
1240
|
-
return keep;
|
|
1241
|
-
});
|
|
1242
|
-
removedRelated = existing.length - init.relatedFiles.length;
|
|
1243
|
-
if (removedRelated > 0 && init.relatedFileScores) {
|
|
1244
|
-
init.relatedFileScores = Object.fromEntries(Object.entries(init.relatedFileScores).filter(([filePath]) => init.relatedFiles?.includes(filePath)));
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
if (focus?.selectedFiles?.length) {
|
|
1248
|
-
const existing = focus.selectedFiles;
|
|
1249
|
-
focus.selectedFiles = existing.filter(filePath => {
|
|
1250
|
-
const keep = existsOrResearch(filePath);
|
|
1251
|
-
return keep;
|
|
1252
|
-
});
|
|
1253
|
-
removedSelected = existing.length - focus.selectedFiles.length;
|
|
1254
|
-
}
|
|
1255
|
-
if (focus?.candidateFiles?.length) {
|
|
1256
|
-
const existing = focus.candidateFiles;
|
|
1257
|
-
focus.candidateFiles = existing.filter(filePath => {
|
|
1258
|
-
const keep = existsOrResearch(filePath);
|
|
1259
|
-
return keep;
|
|
1260
|
-
});
|
|
1261
|
-
removedCandidate = existing.length - focus.candidateFiles.length;
|
|
1262
|
-
}
|
|
1263
|
-
if (removedRelated + removedSelected + removedCandidate > 0) {
|
|
1264
|
-
this.logLine("ANALYSIS", "verifyPruneMissing", undefined, `removed related=${removedRelated}, selected=${removedSelected}, candidate=${removedCandidate}`);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
/**
|
|
1268
|
-
* Route-aware grounding budget.
|
|
1269
|
-
* Example: repo-wide + needs-info => allow up to 4 verification waves.
|
|
1270
|
-
*/
|
|
1271
|
-
getGroundingWaveBudget() {
|
|
1272
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
1273
|
-
const decision = this.context.analysis?.routingDecision?.decision ?? "has-info";
|
|
1274
|
-
const allowSearch = this.context.analysis?.routingDecision?.allowSearch ?? true;
|
|
1275
|
-
let budget = 2;
|
|
1276
|
-
if (!allowSearch || scope === "none")
|
|
1277
|
-
budget = 1;
|
|
1278
|
-
else if (scope === "single-file" && decision === "has-info")
|
|
1279
|
-
budget = 2;
|
|
1280
|
-
else if (scope === "multi-file")
|
|
1281
|
-
budget = 3;
|
|
1282
|
-
else if (scope === "repo-wide" && decision === "needs-info")
|
|
1283
|
-
budget = 4;
|
|
1284
|
-
this.logLine("ANALYSIS", "groundingBudget", undefined, `scope=${scope}, decision=${decision}, search=${allowSearch}, maxWaves=${budget}`);
|
|
1285
|
-
return budget;
|
|
1286
|
-
}
|
|
1287
|
-
/**
|
|
1288
|
-
* Dynamic task-step cap by route complexity.
|
|
1289
|
-
* Example: research-required lanes get 10 steps instead of 5.
|
|
1290
|
-
*/
|
|
1291
|
-
getTaskStepBudget() {
|
|
1292
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
1293
|
-
if (canExecuteRoute(this.context, "research"))
|
|
1294
|
-
return 10;
|
|
1295
|
-
if (scope === "multi-file")
|
|
1296
|
-
return 7;
|
|
1297
|
-
if (scope === "single-file")
|
|
1298
|
-
return 5;
|
|
1299
|
-
return 6;
|
|
1300
|
-
}
|
|
1301
|
-
/**
|
|
1302
|
-
* Blocks execution if repo-wide complex tasks lack minimum research signal.
|
|
1303
|
-
* Example: require at least two analyzed files plus one understanding signal.
|
|
1304
|
-
*/
|
|
1305
|
-
isResearchGateSatisfied() {
|
|
1306
|
-
if (!canExecuteRoute(this.context, "research"))
|
|
1307
|
-
return true;
|
|
1308
|
-
const scope = this.context.analysis?.scopeType ?? "repo-wide";
|
|
1309
|
-
const researchPlanCount = this.context.task?.taskSteps?.filter(s => typeof s.action === "string" && s.action.startsWith("research-")).length ?? 0;
|
|
1310
|
-
const pendingResearchCount = this.context.task?.taskSteps?.filter(s => typeof s.action === "string" &&
|
|
1311
|
-
s.action.startsWith("research-") &&
|
|
1312
|
-
s.status !== "completed").length ?? 0;
|
|
1313
|
-
const requiredResearchSteps = scope === "repo-wide"
|
|
1314
|
-
? 4
|
|
1315
|
-
: scope === "multi-file"
|
|
1316
|
-
? 3
|
|
1317
|
-
: 1;
|
|
1318
|
-
const hasResearchPlan = researchPlanCount >= requiredResearchSteps;
|
|
1319
|
-
if (!hasResearchPlan) {
|
|
1320
|
-
this.context.task.status = "deferred";
|
|
1321
|
-
this.context.task.reason =
|
|
1322
|
-
`Research phase required before execution ` +
|
|
1323
|
-
`(scope=${scope}, researchSteps=${researchPlanCount}, required=${requiredResearchSteps})`;
|
|
1324
|
-
this.persistTaskDataForRun();
|
|
1325
|
-
this.logLine("TASK", "Research gate blocked work loop", undefined, this.context.task.reason, { highlight: true });
|
|
1326
|
-
return false;
|
|
1327
|
-
}
|
|
1328
|
-
if (pendingResearchCount > 0) {
|
|
1329
|
-
this.logLine("TASK", "Research gate queued", undefined, `researchSteps=${researchPlanCount}, pendingResearch=${pendingResearchCount}`);
|
|
1330
|
-
return true;
|
|
1331
|
-
}
|
|
1332
|
-
const understanding = this.context.analysis?.understanding;
|
|
1333
|
-
const understandingSignals = (understanding?.assumptions?.length ?? 0) +
|
|
1334
|
-
(understanding?.constraints?.length ?? 0) +
|
|
1335
|
-
(understanding?.risks?.length ?? 0);
|
|
1336
|
-
if (understandingSignals > 0) {
|
|
1337
|
-
this.logLine("TASK", "Research gate passed", undefined, `researchSteps=${researchPlanCount}, understandingSignals=${understandingSignals}`);
|
|
1338
|
-
return true;
|
|
1339
|
-
}
|
|
1340
|
-
this.context.task.status = "deferred";
|
|
1341
|
-
this.context.task.reason = `Research completed but produced insufficient understanding signals (${understandingSignals}).`;
|
|
1342
|
-
this.persistTaskDataForRun();
|
|
1343
|
-
this.logLine("TASK", "Research gate blocked work loop", undefined, this.context.task.reason, { highlight: true });
|
|
1344
|
-
return false;
|
|
1345
|
-
}
|
|
1346
|
-
/* ───────────── extracted from runWorkLoop ───────────── */
|
|
1347
|
-
isWorkLoopReady() {
|
|
1348
|
-
const readinessDecision = this.context.analysis?.readiness?.decision;
|
|
1349
|
-
const readinessConfidence = this.context.analysis?.readiness?.confidence ?? 0;
|
|
1350
|
-
if (readinessDecision === "ready")
|
|
1351
|
-
return true;
|
|
1352
|
-
this.context.task.status = "deferred";
|
|
1353
|
-
this.context.task.reason = `Readiness not achieved (decision=${readinessDecision}, confidence=${readinessConfidence})`;
|
|
1354
|
-
this.persistTaskDataForRun();
|
|
1355
|
-
this.logLine("TASK", "Cannot start work loop — agent needs more evidence to safely proceed", undefined, `Readiness: ${readinessDecision}, Confidence: ${readinessConfidence}`, { highlight: true });
|
|
1356
|
-
return false;
|
|
1357
|
-
}
|
|
1358
|
-
ensureTaskForWorkLoop() {
|
|
1359
|
-
if (!this.context.task) {
|
|
1360
|
-
throw new Error("runWorkLoop: missing task");
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
async resolveNextTaskAction() {
|
|
1364
|
-
await reasonNextTaskStep.run(this.context);
|
|
1365
|
-
const nextAction = this.context.analysis?.iterationReasoning?.nextAction;
|
|
1366
|
-
if (nextAction === "request-feedback" || nextAction === "complete")
|
|
1367
|
-
return nextAction;
|
|
1368
|
-
return "continue";
|
|
1369
|
-
}
|
|
1370
|
-
persistTaskDataForRun() {
|
|
1371
|
-
persistTaskData(this.context, this.taskId, getDbForRepo(), this.logLine.bind(this));
|
|
1372
|
-
}
|
|
1373
|
-
persistTaskStatus(status) {
|
|
1374
|
-
this.context.task.status = status;
|
|
1375
|
-
this.persistTaskDataForRun();
|
|
1376
|
-
}
|
|
1377
|
-
applyScopeExpansionRouteHint() {
|
|
1378
|
-
var _a;
|
|
1379
|
-
(_a = this.context).analysis || (_a.analysis = {});
|
|
1380
|
-
const route = this.context.analysis.routingDecision;
|
|
1381
|
-
if (!route)
|
|
1382
|
-
return;
|
|
1383
|
-
route.decision = "needs-info";
|
|
1384
|
-
route.allowSearch = true;
|
|
1385
|
-
route.scopeLocked = false;
|
|
1386
|
-
route.rationale = `${route.rationale}; stepReasoning=expand-scope`;
|
|
1387
|
-
this.logLine("TASK", "Route updated from step reasoning", undefined, "expand-scope requested; re-enabled search expansion");
|
|
1388
|
-
}
|
|
1389
|
-
startTaskStep(taskStep, stepCount) {
|
|
1390
|
-
const hydration = this.ensureWorkingFilesLoaded([taskStep.filePath], "Current task step");
|
|
1391
|
-
const db = getDbForRepo();
|
|
1392
|
-
this.ensureTaskIdentityForPersistence(db);
|
|
1393
|
-
this.context.task.currentStep = taskStep;
|
|
1394
|
-
taskStep.taskId = this.taskId;
|
|
1395
|
-
taskStep.stepIndex = stepCount;
|
|
1396
|
-
taskStep.status = "pending";
|
|
1397
|
-
persistTaskStepInsert(taskStep, db);
|
|
1398
|
-
const displayPath = this.formatTaskStepDisplayPath(taskStep.filePath);
|
|
1399
|
-
this.printHeader(`Step ${stepCount}`);
|
|
1400
|
-
this.userOutput(`Now processing ${this.formatPathForLog(displayPath)}.`);
|
|
1401
|
-
this.recordReadEntries(hydration.loadedFromDisk);
|
|
1402
|
-
this.flushActivity();
|
|
1403
|
-
taskStep.startTime = Date.now();
|
|
1404
|
-
persistTaskStepStart(taskStep, db);
|
|
1405
|
-
}
|
|
1406
|
-
finishTaskStep(taskStep, stepCount, stepAction) {
|
|
1407
|
-
const db = getDbForRepo();
|
|
1408
|
-
this.ensureTaskIdentityForPersistence(db);
|
|
1409
|
-
const displayPath = this.formatTaskStepDisplayPath(taskStep.filePath);
|
|
1410
|
-
taskStep.endTime = Date.now();
|
|
1411
|
-
if (stepAction === "complete") {
|
|
1412
|
-
taskStep.status = "completed";
|
|
1413
|
-
persistTaskStepCompletion(taskStep, db);
|
|
1414
|
-
this.logLine("STEP-DONE", `Completed taskStep ${stepCount}`, undefined, displayPath, { highlight: false });
|
|
1415
|
-
return;
|
|
1416
|
-
}
|
|
1417
|
-
taskStep.status = "pending";
|
|
1418
|
-
persistTaskStepCompletion(taskStep, db);
|
|
1419
|
-
this.logLine("STEP", `Pending taskStep ${stepCount}`, undefined, displayPath);
|
|
1420
|
-
}
|
|
1421
|
-
/**
|
|
1422
|
-
* Normalizes internal pseudo-paths for user-facing step logs.
|
|
1423
|
-
* Example: "__research__/symbol-trace" -> "research/symbol-trace".
|
|
1424
|
-
*/
|
|
1425
|
-
formatTaskStepDisplayPath(filePath) {
|
|
1426
|
-
return filePath.startsWith("__research__/")
|
|
1427
|
-
? filePath.replace("__research__/", "research/")
|
|
1428
|
-
: filePath;
|
|
1429
|
-
}
|
|
1430
|
-
/* ----------------------------------- */
|
|
1431
|
-
/* ------------- helpers ------------- */
|
|
1432
|
-
/* ----------------------------------- */
|
|
1433
|
-
/* ───────────── timers ───────────── */
|
|
1434
|
-
/**
|
|
1435
|
-
* Creates a timer function that measures execution time.
|
|
1436
|
-
*
|
|
1437
|
-
* @returns A function that returns the elapsed time in milliseconds.
|
|
1438
|
-
*/
|
|
1439
|
-
startTimer() {
|
|
1440
|
-
const start = Date.now();
|
|
1441
|
-
return () => Date.now() - start;
|
|
1442
|
-
}
|
|
1443
|
-
/* ───────────── spinner helpers ───────────── */
|
|
1444
|
-
/**
|
|
1445
|
-
* Executes a function while pausing the UI spinner.
|
|
1446
|
-
*
|
|
1447
|
-
* @param fn - The function to execute while spinner is paused.
|
|
1448
|
-
*/
|
|
1449
|
-
withSpinnerPaused(fn) {
|
|
1450
|
-
this.ui.pause(() => { process.stdout.write('\r\x1b[K'); fn(); });
|
|
1451
|
-
}
|
|
1452
|
-
logLine(phase, step, ms, desc, options) {
|
|
1453
|
-
if (!this.verboseAgentLogs) {
|
|
1454
|
-
// Keep only key transitions when verbose logging is disabled.
|
|
1455
|
-
if (phase === "STEP-DONE" && desc) {
|
|
1456
|
-
this.userOutput(`Completed ${this.formatPathForLog(desc)}.`);
|
|
1457
|
-
}
|
|
1458
|
-
else if (phase === "TASK" && step.includes("Execution paused")) {
|
|
1459
|
-
this.userOutput("Execution paused; waiting for user clarification.");
|
|
1460
|
-
}
|
|
1461
|
-
else if (phase === "TASK" && step.includes("All selected files processed")) {
|
|
1462
|
-
this.userOutput("All selected files processed.");
|
|
1463
|
-
}
|
|
1464
|
-
else if (phase === "TASK" && step.includes("No eligible taskStep found")) {
|
|
1465
|
-
this.userOutput("No eligible task step found.");
|
|
1466
|
-
}
|
|
1467
|
-
else if (phase === "TASK" && step.includes("Finalize complete")) {
|
|
1468
|
-
this.userOutput("Finalize complete.");
|
|
1469
|
-
}
|
|
1470
|
-
else if (phase === "RESEARCH" && step === "taskStepSeed" && desc?.includes("skipped")) {
|
|
1471
|
-
this.userOutput("Research skipped for this route.");
|
|
1472
|
-
}
|
|
1473
|
-
else if (phase === "RESEARCH" && step === "taskStepSeed" && desc) {
|
|
1474
|
-
this.userOutput(desc);
|
|
1475
|
-
}
|
|
1476
|
-
return;
|
|
1477
|
-
}
|
|
1478
|
-
this.withSpinnerPaused(() => {
|
|
1479
|
-
const suffix = desc ? ` — ${desc}` : "";
|
|
1480
|
-
const timing = typeof ms === "number" ? ` (${ms}ms)` : "";
|
|
1481
|
-
let line = `[AGENT] ${phase} :: ${step}${suffix}${timing}`;
|
|
1482
|
-
// Coloring rules
|
|
1483
|
-
if (phase === "NEW STEP" || phase === "STEP") {
|
|
1484
|
-
line = chalk.green(line);
|
|
1485
|
-
}
|
|
1486
|
-
else if (options?.highlight) {
|
|
1487
|
-
line = chalk.green(line);
|
|
1488
|
-
}
|
|
1489
|
-
// Print a blank line **before** NEW STEP only
|
|
1490
|
-
if (phase === "NEW STEP")
|
|
1491
|
-
console.log();
|
|
1492
|
-
process.stdout.write("\r\x1b[K");
|
|
1493
|
-
console.log(line);
|
|
1494
|
-
});
|
|
1495
|
-
}
|
|
1496
|
-
userOutput(message) {
|
|
1497
|
-
this.withSpinnerPaused(() => {
|
|
1498
|
-
console.log(message);
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
printHeader(title) {
|
|
1502
|
-
this.withSpinnerPaused(() => {
|
|
1503
|
-
if (this.hasPrintedHeader)
|
|
1504
|
-
console.log("");
|
|
1505
|
-
console.log(chalk.bold(`== ${title} ==`));
|
|
1506
|
-
this.hasPrintedHeader = true;
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
/**
|
|
1510
|
-
* Ensures workingFiles has file capsules with code for the given paths.
|
|
1511
|
-
* Example: planned verify-relevant files are hydrated before transform starts.
|
|
1512
|
-
*/
|
|
1513
|
-
ensureWorkingFilesLoaded(paths, reason) {
|
|
1514
|
-
var _a;
|
|
1515
|
-
(_a = this.context).workingFiles || (_a.workingFiles = []);
|
|
1516
|
-
const indexByPath = new Map(this.context.workingFiles.map(file => [file.path, file]));
|
|
1517
|
-
const loadedFromDisk = [];
|
|
1518
|
-
const alreadyLoaded = [];
|
|
1519
|
-
const skippedMissing = [];
|
|
1520
|
-
for (const filePath of paths) {
|
|
1521
|
-
if (!filePath || filePath.startsWith("__research__/"))
|
|
1522
|
-
continue;
|
|
1523
|
-
if (!fs.existsSync(filePath)) {
|
|
1524
|
-
skippedMissing.push(filePath);
|
|
1525
|
-
continue;
|
|
1526
|
-
}
|
|
1527
|
-
const existing = indexByPath.get(filePath);
|
|
1528
|
-
if (existing && typeof existing.code === "string" && existing.code.length > 0) {
|
|
1529
|
-
alreadyLoaded.push(filePath);
|
|
1530
|
-
continue;
|
|
1531
|
-
}
|
|
1532
|
-
let code;
|
|
1533
|
-
try {
|
|
1534
|
-
code = fs.readFileSync(filePath, "utf-8");
|
|
1535
|
-
loadedFromDisk.push(filePath);
|
|
1536
|
-
}
|
|
1537
|
-
catch {
|
|
1538
|
-
code = undefined;
|
|
1539
|
-
}
|
|
1540
|
-
if (existing) {
|
|
1541
|
-
existing.code = code;
|
|
1542
|
-
existing.selectionReason || (existing.selectionReason = reason);
|
|
1543
|
-
}
|
|
1544
|
-
else {
|
|
1545
|
-
const capsule = { path: filePath, code, selectionReason: reason };
|
|
1546
|
-
this.context.workingFiles.push(capsule);
|
|
1547
|
-
indexByPath.set(filePath, capsule);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
return { loadedFromDisk, alreadyLoaded, skippedMissing };
|
|
1551
|
-
}
|
|
1552
|
-
formatPathForLog(filePath) {
|
|
1553
|
-
if (!filePath)
|
|
1554
|
-
return "(none)";
|
|
1555
|
-
if (filePath.startsWith("__research__/")) {
|
|
1556
|
-
return filePath.replace("__research__/", "research/");
|
|
1557
|
-
}
|
|
1558
|
-
const normalized = path.normalize(filePath);
|
|
1559
|
-
const relative = path.relative(process.cwd(), normalized);
|
|
1560
|
-
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) {
|
|
1561
|
-
return relative || path.basename(normalized);
|
|
1562
|
-
}
|
|
1563
|
-
return normalized;
|
|
1564
|
-
}
|
|
1565
|
-
describeFileList(paths, maxItems = 4) {
|
|
1566
|
-
const unique = Array.from(new Set(paths.filter(Boolean)));
|
|
1567
|
-
if (unique.length === 0)
|
|
1568
|
-
return "none";
|
|
1569
|
-
const shown = unique.slice(0, maxItems).map(filePath => this.formatPathForLog(filePath));
|
|
1570
|
-
const extra = unique.length - shown.length;
|
|
1571
|
-
if (extra > 0)
|
|
1572
|
-
shown.push(`+${extra} more`);
|
|
1573
|
-
return shown.join(", ");
|
|
1574
|
-
}
|
|
1575
|
-
recordSearch(query, scope) {
|
|
1576
|
-
const normalizedScope = scope || "repo";
|
|
1577
|
-
this.activity.searches.push(`Searched for ${query} in ${normalizedScope}`);
|
|
1578
|
-
}
|
|
1579
|
-
recordListEntries(entries) {
|
|
1580
|
-
for (const entry of entries) {
|
|
1581
|
-
const normalized = entry.replace(/\\/g, "/");
|
|
1582
|
-
const asDir = normalized.endsWith("/") || path.extname(normalized) === ""
|
|
1583
|
-
? normalized
|
|
1584
|
-
: path.dirname(normalized);
|
|
1585
|
-
const display = asDir === "." ? "repo root" : this.formatPathForLog(asDir);
|
|
1586
|
-
this.activity.lists.push(`Listed files in ${display}`);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
recordReadEntries(paths) {
|
|
1590
|
-
for (const filePath of paths) {
|
|
1591
|
-
if (!filePath || filePath.startsWith("__research__/"))
|
|
1592
|
-
continue;
|
|
1593
|
-
this.activity.reads.push(`Read ${this.formatPathForLog(filePath)}`);
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
flushActivity() {
|
|
1597
|
-
const searches = Array.from(new Set(this.activity.searches));
|
|
1598
|
-
const lists = Array.from(new Set(this.activity.lists));
|
|
1599
|
-
const reads = Array.from(new Set(this.activity.reads));
|
|
1600
|
-
if (searches.length === 0 && lists.length === 0 && reads.length === 0) {
|
|
1601
|
-
return;
|
|
1602
|
-
}
|
|
1603
|
-
const parts = [];
|
|
1604
|
-
if (searches.length > 0) {
|
|
1605
|
-
parts.push(`${searches.length} search${searches.length === 1 ? "" : "es"}`);
|
|
1606
|
-
}
|
|
1607
|
-
if (lists.length > 0) {
|
|
1608
|
-
parts.push(`${lists.length} director${lists.length === 1 ? "y" : "ies"}`);
|
|
1609
|
-
}
|
|
1610
|
-
if (reads.length > 0) {
|
|
1611
|
-
parts.push(`${reads.length} file${reads.length === 1 ? "" : "s"}`);
|
|
1612
|
-
}
|
|
1613
|
-
this.userOutput(`Explored ${parts.join(", ")}`);
|
|
1614
|
-
for (const line of searches.slice(0, 2))
|
|
1615
|
-
this.userOutput(line);
|
|
1616
|
-
for (const line of lists.slice(0, 3))
|
|
1617
|
-
this.userOutput(line);
|
|
1618
|
-
for (const line of reads.slice(0, 6))
|
|
1619
|
-
this.userOutput(line);
|
|
1620
|
-
this.activity = { searches: [], lists: [], reads: [] };
|
|
1621
|
-
}
|
|
1622
|
-
/**
|
|
1623
|
-
* Ensures the current task id exists in the active DB before step persistence.
|
|
1624
|
-
* Example: if repo/db context switched, re-create task row and rebind step taskIds.
|
|
1625
|
-
*/
|
|
1626
|
-
ensureTaskIdentityForPersistence(db) {
|
|
1627
|
-
var _a;
|
|
1628
|
-
const activeTaskId = this.taskId ?? this.context.task?.id;
|
|
1629
|
-
if (!activeTaskId) {
|
|
1630
|
-
this.taskId = bootTaskForRepo(this.context, db, this.logLine.bind(this));
|
|
1631
|
-
this.context.task.id = this.taskId;
|
|
1632
|
-
return;
|
|
1633
|
-
}
|
|
1634
|
-
const row = db.prepare("SELECT id FROM tasks WHERE id = ?").get(activeTaskId);
|
|
1635
|
-
if (row?.id) {
|
|
1636
|
-
this.taskId = activeTaskId;
|
|
1637
|
-
this.context.task.id = activeTaskId;
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1640
|
-
const reboundTaskId = bootTaskForRepo(this.context, db, this.logLine.bind(this));
|
|
1641
|
-
this.taskId = reboundTaskId;
|
|
1642
|
-
this.context.task.id = reboundTaskId;
|
|
1643
|
-
(_a = this.context.task).taskSteps || (_a.taskSteps = []);
|
|
1644
|
-
for (const step of this.context.task.taskSteps) {
|
|
1645
|
-
step.taskId = reboundTaskId;
|
|
1646
|
-
}
|
|
1647
|
-
this.logLine("TASK", "taskId rebound", undefined, `previous=${activeTaskId}, rebound=${reboundTaskId}`);
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
function scoreCandidateFiles(filePaths, relatedFileScores, retrievalQuery) {
|
|
1651
|
-
const explicitRefs = extractFileReferences(retrievalQuery, { lowercase: true });
|
|
1652
|
-
const explicitBasenames = new Set(explicitRefs.map(ref => path.basename(ref)));
|
|
1653
|
-
const symbolAnchors = extractSymbolAnchors(retrievalQuery);
|
|
1654
|
-
const scored = filePaths.map(filePath => {
|
|
1655
|
-
const fileLower = filePath.toLowerCase();
|
|
1656
|
-
const basename = path.basename(filePath).toLowerCase();
|
|
1657
|
-
let score = 0;
|
|
1658
|
-
const reasons = [];
|
|
1659
|
-
if (explicitBasenames.has(basename)) {
|
|
1660
|
-
score += 100;
|
|
1661
|
-
reasons.push("exact-filename");
|
|
1662
|
-
}
|
|
1663
|
-
if (explicitRefs.some(ref => fileLower.includes(ref))) {
|
|
1664
|
-
score += 60;
|
|
1665
|
-
reasons.push("path-anchor");
|
|
1666
|
-
}
|
|
1667
|
-
for (const anchor of symbolAnchors) {
|
|
1668
|
-
if (basename.includes(anchor)) {
|
|
1669
|
-
score += 40;
|
|
1670
|
-
reasons.push(`symbol:${anchor}:filename`);
|
|
1671
|
-
}
|
|
1672
|
-
else if (fileLower.includes(anchor)) {
|
|
1673
|
-
score += 20;
|
|
1674
|
-
reasons.push(`symbol:${anchor}:path`);
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
const bm25Raw = relatedFileScores[filePath];
|
|
1678
|
-
if (typeof bm25Raw === "number" && Number.isFinite(bm25Raw)) {
|
|
1679
|
-
const prior = Math.max(0, Math.min(20, -bm25Raw));
|
|
1680
|
-
score += prior;
|
|
1681
|
-
reasons.push(`bm25-prior:${prior.toFixed(2)}`);
|
|
1682
|
-
}
|
|
1683
|
-
return { filePath, score, bm25Raw, reasons };
|
|
1684
|
-
});
|
|
1685
|
-
return scored.sort((a, b) => {
|
|
1686
|
-
if (b.score !== a.score)
|
|
1687
|
-
return b.score - a.score;
|
|
1688
|
-
const aBm25 = typeof a.bm25Raw === "number" ? a.bm25Raw : Number.POSITIVE_INFINITY;
|
|
1689
|
-
const bBm25 = typeof b.bm25Raw === "number" ? b.bm25Raw : Number.POSITIVE_INFINITY;
|
|
1690
|
-
return aBm25 - bBm25;
|
|
1691
|
-
});
|
|
1692
|
-
}
|
|
1693
|
-
function extractSymbolAnchors(query) {
|
|
1694
|
-
const matches = query.match(/[A-Za-z_][A-Za-z0-9_]{2,}/g) ?? [];
|
|
1695
|
-
const out = new Set();
|
|
1696
|
-
for (const token of matches) {
|
|
1697
|
-
const lowered = token.toLowerCase();
|
|
1698
|
-
const looksLikeSymbol = /[A-Z]/.test(token) ||
|
|
1699
|
-
token.includes("_") ||
|
|
1700
|
-
token.endsWith("Step") ||
|
|
1701
|
-
token.endsWith("Module");
|
|
1702
|
-
if (!looksLikeSymbol)
|
|
1703
|
-
continue;
|
|
1704
|
-
if (PREFILTER_STOP_WORDS.has(lowered))
|
|
1705
|
-
continue;
|
|
1706
|
-
out.add(lowered);
|
|
1707
|
-
}
|
|
1708
|
-
return Array.from(out);
|
|
1709
|
-
}
|
|
1710
|
-
// All helper functions (persistTaskData, bootTaskForRepo, persistTaskStep*) remain unchanged
|
|
1711
|
-
/* ───────────── FOLDER CAPSULES SUMMARY HELPER ───────────── */
|
|
1712
|
-
/**
|
|
1713
|
-
* Generates a human-readable summary of folder capsules and logs it.
|
|
1714
|
-
*
|
|
1715
|
-
* @param context - The structured context containing folder capsules.
|
|
1716
|
-
*/
|
|
1717
|
-
export function logFolderCapsulesSummary(context) {
|
|
1718
|
-
const capsules = context.initContext?.folderCapsules;
|
|
1719
|
-
if (!capsules?.length)
|
|
1720
|
-
return;
|
|
1721
|
-
// Ensure analysis exists
|
|
1722
|
-
context.analysis ?? (context.analysis = {});
|
|
1723
|
-
// Helper: truncate text to max length
|
|
1724
|
-
const truncate = (text, max = 120) => text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
1725
|
-
// Build human-readable summary (1–2 lines per folder)
|
|
1726
|
-
const humanReadable = capsules.map(fc => {
|
|
1727
|
-
const conf = Math.round((fc.confidence ?? 0) * 100) / 100; // round to 2 decimals
|
|
1728
|
-
const header = `- ${fc.path} (${fc.stats?.fileCount ?? 0} files, conf ${conf})`;
|
|
1729
|
-
// Line 2: summary + optional first key file reason
|
|
1730
|
-
const summaryText = fc.summary ? truncate(fc.summary.trim()) : "";
|
|
1731
|
-
const key = fc.keyFiles?.[0];
|
|
1732
|
-
let body = "";
|
|
1733
|
-
if (summaryText || key) {
|
|
1734
|
-
body += " ";
|
|
1735
|
-
if (summaryText)
|
|
1736
|
-
body += summaryText;
|
|
1737
|
-
if (key) {
|
|
1738
|
-
const keyHint = `Key: ${key.path.split("/").pop()} — ${truncate(key.reason)}`;
|
|
1739
|
-
body += summaryText ? `[${keyHint}]` : keyHint;
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
return body ? `${header}\n${body}` : header;
|
|
1743
|
-
}).join("\n\n"); // extra newline for readability
|
|
1744
|
-
logInputOutput('FolderCapsule summarized', 'output', context.analysis.folderCapsulesHuman = humanReadable);
|
|
1745
|
-
}
|
|
1746
|
-
/**
|
|
1747
|
-
* Persist updated task data for the current run.
|
|
1748
|
-
* Only writes fields that exist in the tasks table.
|
|
1749
|
-
*
|
|
1750
|
-
* @param context - The structured context containing task data.
|
|
1751
|
-
* @param taskId - The ID of the task to update.
|
|
1752
|
-
* @param db - The database client.
|
|
1753
|
-
* @param logLine - Function to log execution details.
|
|
1754
|
-
*/
|
|
1755
|
-
export function persistTaskData(context, taskId, db, logLine) {
|
|
1756
|
-
if (!taskId)
|
|
1757
|
-
return;
|
|
1758
|
-
const now = new Date().toISOString();
|
|
1759
|
-
const fieldsToUpdate = {};
|
|
1760
|
-
// Persist initial query
|
|
1761
|
-
if (context.initContext?.userQuery) {
|
|
1762
|
-
fieldsToUpdate.initial_query = context.initContext.userQuery;
|
|
1763
|
-
}
|
|
1764
|
-
// Persist intent data
|
|
1765
|
-
const intent = context.analysis?.intent;
|
|
1766
|
-
if (intent) {
|
|
1767
|
-
fieldsToUpdate.normalized_query = intent.normalizedQuery;
|
|
1768
|
-
fieldsToUpdate.intent_category = intent.intentCategory;
|
|
1769
|
-
fieldsToUpdate.agreed_intent = intent.intent;
|
|
1770
|
-
fieldsToUpdate.intent_confidence = intent.confidence;
|
|
1771
|
-
}
|
|
1772
|
-
// Persist focus / file selection
|
|
1773
|
-
if (context.analysis?.focus?.selectedFiles?.length) {
|
|
1774
|
-
fieldsToUpdate.relevant_files_json = JSON.stringify(context.analysis.focus.selectedFiles);
|
|
1775
|
-
}
|
|
1776
|
-
if (context.analysis?.focus?.candidateFiles?.length) {
|
|
1777
|
-
fieldsToUpdate.missing_files_json = JSON.stringify(context.analysis.focus.candidateFiles);
|
|
1778
|
-
}
|
|
1779
|
-
// ✅ Persist final answer → tasks.summary
|
|
1780
|
-
if (context.analysis?.finalAnswer) {
|
|
1781
|
-
fieldsToUpdate.summary = context.analysis.finalAnswer;
|
|
1782
|
-
}
|
|
1783
|
-
const setClause = Object.keys(fieldsToUpdate)
|
|
1784
|
-
.map(key => `${key} = ?`)
|
|
1785
|
-
.join(", ");
|
|
1786
|
-
if (!setClause)
|
|
1787
|
-
return;
|
|
1788
|
-
db.prepare(`UPDATE tasks SET ${setClause}, updated_at = ? WHERE id = ?`).run(...Object.values(fieldsToUpdate), now, taskId);
|
|
1789
|
-
logLine("TASK", "persistTaskData", undefined, `task ${taskId} updated with run data`);
|
|
1790
|
-
}
|
|
1791
|
-
/**
|
|
1792
|
-
* Ensure global_state, project, and task exist for this repo.
|
|
1793
|
-
* Returns the created taskId
|
|
1794
|
-
*
|
|
1795
|
-
* @param context - The structured context.
|
|
1796
|
-
* @param db - The database client.
|
|
1797
|
-
* @param logLine - Function to log execution details.
|
|
1798
|
-
* @returns The ID of the created task.
|
|
1799
|
-
*/
|
|
1800
|
-
export function bootTaskForRepo(context, db, logLine) {
|
|
1801
|
-
const now = new Date().toISOString();
|
|
1802
|
-
// --- Ensure global_state exists ---
|
|
1803
|
-
db.prepare(`
|
|
1804
|
-
INSERT INTO global_state(id, created_at, updated_at)
|
|
1805
|
-
VALUES(1, ?, ?)
|
|
1806
|
-
ON CONFLICT(id) DO NOTHING
|
|
1807
|
-
`).run(now, now);
|
|
1808
|
-
// --- Ensure project exists ---
|
|
1809
|
-
const repoPath = process.cwd(); // or pass in from context/init
|
|
1810
|
-
let projectRow = db.prepare(`SELECT id FROM projects WHERE repo_path = ?`).get(repoPath);
|
|
1811
|
-
let projectId;
|
|
1812
|
-
if (!projectRow) {
|
|
1813
|
-
const result = db.prepare(`
|
|
1814
|
-
INSERT INTO projects(repo_path, name, created_at, updated_at)
|
|
1815
|
-
VALUES(?, ?, ?, ?)
|
|
1816
|
-
`).run(repoPath, "Default Project", now, now);
|
|
1817
|
-
projectId = result.lastInsertRowid;
|
|
1818
|
-
}
|
|
1819
|
-
else {
|
|
1820
|
-
projectId = projectRow.id;
|
|
1821
|
-
}
|
|
1822
|
-
// --- Create task ---
|
|
1823
|
-
const userQuery = context.initContext?.userQuery ?? "unknown query";
|
|
1824
|
-
const result = db.prepare(`
|
|
1825
|
-
INSERT INTO tasks(project_id, initial_query, created_at, updated_at)
|
|
1826
|
-
VALUES(?, ?, ?, ?)
|
|
1827
|
-
`).run(projectId, userQuery, now, now);
|
|
1828
|
-
const taskId = result.lastInsertRowid;
|
|
1829
|
-
logLine("TASK", `created task id = ${taskId}`);
|
|
1830
|
-
return taskId;
|
|
1831
|
-
}
|
|
1832
|
-
export function persistTaskStepInsert(taskStep, db) {
|
|
1833
|
-
if (taskStep.id)
|
|
1834
|
-
return;
|
|
1835
|
-
const nowIso = new Date().toISOString();
|
|
1836
|
-
const result = db.prepare(`
|
|
1837
|
-
INSERT INTO task_steps (
|
|
1838
|
-
task_id,
|
|
1839
|
-
file_path,
|
|
1840
|
-
action,
|
|
1841
|
-
status,
|
|
1842
|
-
step_index,
|
|
1843
|
-
start_time,
|
|
1844
|
-
result_json,
|
|
1845
|
-
notes,
|
|
1846
|
-
created_at,
|
|
1847
|
-
updated_at
|
|
1848
|
-
)
|
|
1849
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1850
|
-
`).run(taskStep.taskId, taskStep.filePath, taskStep.action ?? null, taskStep.status, taskStep.stepIndex ?? null, taskStep.startTime ?? null, taskStep.result != null ? JSON.stringify(taskStep.result) : null, taskStep.notes ?? null, nowIso, nowIso);
|
|
1851
|
-
taskStep.id = result.lastInsertRowid;
|
|
1852
|
-
}
|
|
1853
|
-
export function persistTaskStepStart(taskStep, db) {
|
|
1854
|
-
if (!taskStep.id)
|
|
1855
|
-
return;
|
|
1856
|
-
if (!taskStep.startTime) {
|
|
1857
|
-
taskStep.startTime = Date.now();
|
|
1858
|
-
}
|
|
1859
|
-
db.prepare(`
|
|
1860
|
-
UPDATE task_steps
|
|
1861
|
-
SET
|
|
1862
|
-
start_time = ?,
|
|
1863
|
-
action = ?,
|
|
1864
|
-
notes = ?,
|
|
1865
|
-
updated_at = ?
|
|
1866
|
-
WHERE id = ?
|
|
1867
|
-
`).run(taskStep.startTime, taskStep.action ?? null, taskStep.notes ?? null, new Date().toISOString(), taskStep.id);
|
|
1868
|
-
}
|
|
1869
|
-
export function persistTaskStepCompletion(taskStep, db) {
|
|
1870
|
-
if (!taskStep.id)
|
|
1871
|
-
return;
|
|
1872
|
-
if (!taskStep.endTime) {
|
|
1873
|
-
taskStep.endTime = Date.now();
|
|
1874
|
-
}
|
|
1875
|
-
db.prepare(`
|
|
1876
|
-
UPDATE task_steps
|
|
1877
|
-
SET
|
|
1878
|
-
status = ?,
|
|
1879
|
-
end_time = ?,
|
|
1880
|
-
action = ?,
|
|
1881
|
-
result_json = ?,
|
|
1882
|
-
notes = ?,
|
|
1883
|
-
updated_at = ?
|
|
1884
|
-
WHERE id = ?
|
|
1885
|
-
`).run(taskStep.status, taskStep.endTime, taskStep.action ?? null, taskStep.result != null ? JSON.stringify(taskStep.result) : null, taskStep.notes ?? null, new Date().toISOString(), taskStep.id);
|
|
1886
|
-
}
|