playwright-intelligence-engine 0.0.0-stage → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +229 -3
- package/bin/pw-intel.js +37 -0
- package/dist/authoring/author.d.ts +83 -0
- package/dist/authoring/author.d.ts.map +1 -0
- package/dist/authoring/generation-contract.d.ts +90 -0
- package/dist/authoring/generation-contract.d.ts.map +1 -0
- package/dist/authoring/hybrid-author.d.ts +6 -0
- package/dist/authoring/hybrid-author.d.ts.map +1 -0
- package/dist/authoring/index.d.ts +7 -0
- package/dist/authoring/index.d.ts.map +1 -0
- package/dist/authoring/llm-author.d.ts +28 -0
- package/dist/authoring/llm-author.d.ts.map +1 -0
- package/dist/authoring/naming/index.d.ts +4 -0
- package/dist/authoring/naming/index.d.ts.map +1 -0
- package/dist/authoring/naming/name-plan.d.ts +45 -0
- package/dist/authoring/naming/name-plan.d.ts.map +1 -0
- package/dist/authoring/naming/name-planner.d.ts +25 -0
- package/dist/authoring/naming/name-planner.d.ts.map +1 -0
- package/dist/authoring/naming/naming-linter.d.ts +20 -0
- package/dist/authoring/naming/naming-linter.d.ts.map +1 -0
- package/dist/authoring/template-author.d.ts +6 -0
- package/dist/authoring/template-author.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/collectors/collector-interface.d.ts +7 -0
- package/dist/collectors/collector-interface.d.ts.map +1 -0
- package/dist/collectors/environment-collector.d.ts +12 -0
- package/dist/collectors/environment-collector.d.ts.map +1 -0
- package/dist/collectors/error-collector.d.ts +18 -0
- package/dist/collectors/error-collector.d.ts.map +1 -0
- package/dist/collectors/git-diff-collector.d.ts +20 -0
- package/dist/collectors/git-diff-collector.d.ts.map +1 -0
- package/dist/collectors/live-browser-collector.d.ts +45 -0
- package/dist/collectors/live-browser-collector.d.ts.map +1 -0
- package/dist/collectors/network-collector.d.ts +28 -0
- package/dist/collectors/network-collector.d.ts.map +1 -0
- package/dist/collectors/static-ast-collector.d.ts +32 -0
- package/dist/collectors/static-ast-collector.d.ts.map +1 -0
- package/dist/collectors/trace-collector.d.ts +12 -0
- package/dist/collectors/trace-collector.d.ts.map +1 -0
- package/dist/config/project-config.d.ts +33 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/core/errors/engine-errors.d.ts +34 -0
- package/dist/core/errors/engine-errors.d.ts.map +1 -0
- package/dist/core/types/diagnostic-context.d.ts +151 -0
- package/dist/core/types/diagnostic-context.d.ts.map +1 -0
- package/dist/core/types/repair-evidence.d.ts +56 -0
- package/dist/core/types/repair-evidence.d.ts.map +1 -0
- package/dist/core/version.d.ts +13 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/diagnostics/diagnostic-contract.d.ts +52 -0
- package/dist/diagnostics/diagnostic-contract.d.ts.map +1 -0
- package/dist/diagnostics/diagnostic-report.d.ts +11 -0
- package/dist/diagnostics/diagnostic-report.d.ts.map +1 -0
- package/dist/diagnostics/evidence-correlator.d.ts +22 -0
- package/dist/diagnostics/evidence-correlator.d.ts.map +1 -0
- package/dist/diagnostics/external-failure-evidence.d.ts +18 -0
- package/dist/diagnostics/external-failure-evidence.d.ts.map +1 -0
- package/dist/diagnostics/failure-category.d.ts +4 -0
- package/dist/diagnostics/failure-category.d.ts.map +1 -0
- package/dist/diagnostics/failure-classifier.d.ts +58 -0
- package/dist/diagnostics/failure-classifier.d.ts.map +1 -0
- package/dist/evaluation/evaluation-scorecard.d.ts +72 -0
- package/dist/evaluation/evaluation-scorecard.d.ts.map +1 -0
- package/dist/evaluation/repository-inspector.d.ts +21 -0
- package/dist/evaluation/repository-inspector.d.ts.map +1 -0
- package/dist/evaluation/repository-runner.d.ts +24 -0
- package/dist/evaluation/repository-runner.d.ts.map +1 -0
- package/dist/evidence/evidence-model.d.ts +88 -0
- package/dist/evidence/evidence-model.d.ts.map +1 -0
- package/dist/evidence/evidence-normalizer.d.ts +19 -0
- package/dist/evidence/evidence-normalizer.d.ts.map +1 -0
- package/dist/evidence/evidence-redactor.d.ts +37 -0
- package/dist/evidence/evidence-redactor.d.ts.map +1 -0
- package/dist/framework/config-adapter.d.ts +28 -0
- package/dist/framework/config-adapter.d.ts.map +1 -0
- package/dist/gate/index.d.ts +21 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/oracle.d.ts +26 -0
- package/dist/gate/oracle.d.ts.map +1 -0
- package/dist/gate/quality.d.ts +27 -0
- package/dist/gate/quality.d.ts.map +1 -0
- package/dist/gate/safety.d.ts +28 -0
- package/dist/gate/safety.d.ts.map +1 -0
- package/dist/generator/architecture-generator.d.ts +55 -0
- package/dist/generator/architecture-generator.d.ts.map +1 -0
- package/dist/generator/assertion-quality-gate.d.ts +18 -0
- package/dist/generator/assertion-quality-gate.d.ts.map +1 -0
- package/dist/generator/candidate-writer.d.ts +34 -0
- package/dist/generator/candidate-writer.d.ts.map +1 -0
- package/dist/generator/test-generator.d.ts +26 -0
- package/dist/generator/test-generator.d.ts.map +1 -0
- package/dist/governance/audit-log.d.ts +23 -0
- package/dist/governance/audit-log.d.ts.map +1 -0
- package/dist/governance/governance-policy.d.ts +24 -0
- package/dist/governance/governance-policy.d.ts.map +1 -0
- package/dist/governance/team-dashboard.d.ts +51 -0
- package/dist/governance/team-dashboard.d.ts.map +1 -0
- package/dist/governance/workflow-audit.d.ts +13 -0
- package/dist/governance/workflow-audit.d.ts.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20318 -0
- package/dist/integrations/ci-summary.d.ts +14 -0
- package/dist/integrations/ci-summary.d.ts.map +1 -0
- package/dist/integrations/playwright-report-adapter.d.ts +22 -0
- package/dist/integrations/playwright-report-adapter.d.ts.map +1 -0
- package/dist/integrations/quality-gate.d.ts +35 -0
- package/dist/integrations/quality-gate.d.ts.map +1 -0
- package/dist/integrations/sarif-report.d.ts +48 -0
- package/dist/integrations/sarif-report.d.ts.map +1 -0
- package/dist/intelligence/autonomous-repair-workflow.d.ts +31 -0
- package/dist/intelligence/autonomous-repair-workflow.d.ts.map +1 -0
- package/dist/intelligence/business-intent.d.ts +58 -0
- package/dist/intelligence/business-intent.d.ts.map +1 -0
- package/dist/intelligence/evidence-bundle.d.ts +364 -0
- package/dist/intelligence/evidence-bundle.d.ts.map +1 -0
- package/dist/intelligence/failure-clustering.d.ts +38 -0
- package/dist/intelligence/failure-clustering.d.ts.map +1 -0
- package/dist/intelligence/generation-agent.d.ts +120 -0
- package/dist/intelligence/generation-agent.d.ts.map +1 -0
- package/dist/intelligence/generation-verifier.d.ts +151 -0
- package/dist/intelligence/generation-verifier.d.ts.map +1 -0
- package/dist/intelligence/llm-proposal.d.ts +377 -0
- package/dist/intelligence/llm-proposal.d.ts.map +1 -0
- package/dist/intelligence/locator-disambiguation-engine.d.ts +38 -0
- package/dist/intelligence/locator-disambiguation-engine.d.ts.map +1 -0
- package/dist/intelligence/model-contract.d.ts +86 -0
- package/dist/intelligence/model-contract.d.ts.map +1 -0
- package/dist/intelligence/model-provider.d.ts +75 -0
- package/dist/intelligence/model-provider.d.ts.map +1 -0
- package/dist/intelligence/project-intelligence.d.ts +22 -0
- package/dist/intelligence/project-intelligence.d.ts.map +1 -0
- package/dist/intelligence/repair-agent.d.ts +46 -0
- package/dist/intelligence/repair-agent.d.ts.map +1 -0
- package/dist/intelligence/repository-profile.d.ts +131 -0
- package/dist/intelligence/repository-profile.d.ts.map +1 -0
- package/dist/intelligence/suite-intelligence.d.ts +59 -0
- package/dist/intelligence/suite-intelligence.d.ts.map +1 -0
- package/dist/intelligence/test-intelligence.d.ts +44 -0
- package/dist/intelligence/test-intelligence.d.ts.map +1 -0
- package/dist/intelligence/trace-proposal-workflow.d.ts +30 -0
- package/dist/intelligence/trace-proposal-workflow.d.ts.map +1 -0
- package/dist/intelligence/verified-llm-repair-workflow.d.ts +21 -0
- package/dist/intelligence/verified-llm-repair-workflow.d.ts.map +1 -0
- package/dist/intelligence/workflow-planner.d.ts +278 -0
- package/dist/intelligence/workflow-planner.d.ts.map +1 -0
- package/dist/mcp/server.d.ts +32 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/memory/stability-ledger.d.ts +46 -0
- package/dist/memory/stability-ledger.d.ts.map +1 -0
- package/dist/perception/app-model.d.ts +55 -0
- package/dist/perception/app-model.d.ts.map +1 -0
- package/dist/perception/crawler.d.ts +18 -0
- package/dist/perception/crawler.d.ts.map +1 -0
- package/dist/perception/index.d.ts +3 -0
- package/dist/perception/index.d.ts.map +1 -0
- package/dist/repair/approval-service.d.ts +139 -0
- package/dist/repair/approval-service.d.ts.map +1 -0
- package/dist/repair/assertion-hasher.d.ts +62 -0
- package/dist/repair/assertion-hasher.d.ts.map +1 -0
- package/dist/repair/ast-patcher.d.ts +36 -0
- package/dist/repair/ast-patcher.d.ts.map +1 -0
- package/dist/repair/browser-operation-executor.d.ts +27 -0
- package/dist/repair/browser-operation-executor.d.ts.map +1 -0
- package/dist/repair/diff-allowlist.d.ts +74 -0
- package/dist/repair/diff-allowlist.d.ts.map +1 -0
- package/dist/repair/intent-validator.d.ts +157 -0
- package/dist/repair/intent-validator.d.ts.map +1 -0
- package/dist/repair/repair-operations.d.ts +40 -0
- package/dist/repair/repair-operations.d.ts.map +1 -0
- package/dist/repair/repair-planner.d.ts +98 -0
- package/dist/repair/repair-planner.d.ts.map +1 -0
- package/dist/repair/repair-workflow.d.ts +42 -0
- package/dist/repair/repair-workflow.d.ts.map +1 -0
- package/dist/repair/safe-operation-compiler.d.ts +15 -0
- package/dist/repair/safe-operation-compiler.d.ts.map +1 -0
- package/dist/repair/source-mapper.d.ts +19 -0
- package/dist/repair/source-mapper.d.ts.map +1 -0
- package/dist/repair/statement-patcher.d.ts +75 -0
- package/dist/repair/statement-patcher.d.ts.map +1 -0
- package/dist/repair/verification-gates.d.ts +25 -0
- package/dist/repair/verification-gates.d.ts.map +1 -0
- package/dist/repair/workflow-plan.d.ts +35 -0
- package/dist/repair/workflow-plan.d.ts.map +1 -0
- package/dist/repair/workspace-promoter.d.ts +43 -0
- package/dist/repair/workspace-promoter.d.ts.map +1 -0
- package/dist/reproduce/diagnostic-rerunner.d.ts +40 -0
- package/dist/reproduce/diagnostic-rerunner.d.ts.map +1 -0
- package/dist/reproduce/direct-browser-investigator.d.ts +41 -0
- package/dist/reproduce/direct-browser-investigator.d.ts.map +1 -0
- package/dist/reproduce/interactive-workflow-runner.d.ts +43 -0
- package/dist/reproduce/interactive-workflow-runner.d.ts.map +1 -0
- package/dist/sandbox/dependency-strategy.d.ts +45 -0
- package/dist/sandbox/dependency-strategy.d.ts.map +1 -0
- package/dist/sandbox/execution-runner.d.ts +81 -0
- package/dist/sandbox/execution-runner.d.ts.map +1 -0
- package/dist/sandbox/worktree-manager.d.ts +51 -0
- package/dist/sandbox/worktree-manager.d.ts.map +1 -0
- package/dist/selector/abstention-policy.d.ts +34 -0
- package/dist/selector/abstention-policy.d.ts.map +1 -0
- package/dist/selector/candidate-extractor.d.ts +71 -0
- package/dist/selector/candidate-extractor.d.ts.map +1 -0
- package/dist/selector/live-locator-verifier.d.ts +28 -0
- package/dist/selector/live-locator-verifier.d.ts.map +1 -0
- package/dist/selector/repair-candidate-ranker.d.ts +10 -0
- package/dist/selector/repair-candidate-ranker.d.ts.map +1 -0
- package/dist/selector/selector-scorer.d.ts +43 -0
- package/dist/selector/selector-scorer.d.ts.map +1 -0
- package/dist/trace/adapters/adapter-registry.d.ts +18 -0
- package/dist/trace/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/trace/adapters/trace-adapter.d.ts +21 -0
- package/dist/trace/adapters/trace-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/unknown-adapter.d.ts +10 -0
- package/dist/trace/adapters/unknown-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v10-adapter.d.ts +10 -0
- package/dist/trace/adapters/v10-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v4-adapter.d.ts +11 -0
- package/dist/trace/adapters/v4-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v8-adapter.d.ts +10 -0
- package/dist/trace/adapters/v8-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v9-adapter.d.ts +10 -0
- package/dist/trace/adapters/v9-adapter.d.ts.map +1 -0
- package/dist/trace/archive-reader.d.ts +44 -0
- package/dist/trace/archive-reader.d.ts.map +1 -0
- package/dist/trace/snapshot-resolver.d.ts +55 -0
- package/dist/trace/snapshot-resolver.d.ts.map +1 -0
- package/dist/trace/trace-parser.d.ts +50 -0
- package/dist/trace/trace-parser.d.ts.map +1 -0
- package/dist/trace/version-detector.d.ts +20 -0
- package/dist/trace/version-detector.d.ts.map +1 -0
- package/package.json +76 -6
- package/skills/README.md +20 -0
- package/skills/pie-failure-investigation/SKILL.md +16 -0
- package/skills/pie-quality-engineer/SKILL.md +66 -0
- package/skills/pie-release-readiness/SKILL.md +22 -0
- package/skills/pie-repair-review/SKILL.md +21 -0
- package/skills/pie-trace-to-repair/SKILL.md +35 -0
- package/src/authoring/author.ts +81 -0
- package/src/authoring/generation-contract.ts +283 -0
- package/src/authoring/hybrid-author.ts +115 -0
- package/src/authoring/index.ts +7 -0
- package/src/authoring/llm-author.ts +282 -0
- package/src/authoring/naming/index.ts +4 -0
- package/src/authoring/naming/name-plan.ts +28 -0
- package/src/authoring/naming/name-planner.ts +339 -0
- package/src/authoring/naming/naming-linter.ts +292 -0
- package/src/authoring/template-author.ts +39 -0
- package/src/cli/index.ts +1172 -0
- package/src/collectors/collector-interface.ts +8 -0
- package/src/collectors/environment-collector.ts +103 -0
- package/src/collectors/error-collector.ts +177 -0
- package/src/collectors/git-diff-collector.ts +190 -0
- package/src/collectors/live-browser-collector.ts +412 -0
- package/src/collectors/network-collector.ts +90 -0
- package/src/collectors/static-ast-collector.ts +226 -0
- package/src/collectors/trace-collector.ts +66 -0
- package/src/config/project-config.ts +114 -0
- package/src/core/errors/engine-errors.ts +90 -0
- package/src/core/types/diagnostic-context.ts +94 -0
- package/src/core/types/repair-evidence.ts +45 -0
- package/src/core/version.ts +25 -0
- package/src/diagnostics/diagnostic-contract.ts +79 -0
- package/src/diagnostics/diagnostic-report.ts +204 -0
- package/src/diagnostics/evidence-correlator.ts +117 -0
- package/src/diagnostics/external-failure-evidence.ts +72 -0
- package/src/diagnostics/failure-category.ts +40 -0
- package/src/diagnostics/failure-classifier.ts +701 -0
- package/src/evaluation/evaluation-scorecard.ts +198 -0
- package/src/evaluation/repository-inspector.ts +143 -0
- package/src/evaluation/repository-runner.ts +197 -0
- package/src/evidence/evidence-model.ts +76 -0
- package/src/evidence/evidence-normalizer.ts +322 -0
- package/src/evidence/evidence-redactor.ts +218 -0
- package/src/framework/config-adapter.ts +131 -0
- package/src/gate/index.ts +43 -0
- package/src/gate/oracle.ts +69 -0
- package/src/gate/quality.ts +101 -0
- package/src/gate/safety.ts +94 -0
- package/src/generator/architecture-generator.ts +582 -0
- package/src/generator/assertion-quality-gate.ts +88 -0
- package/src/generator/candidate-writer.ts +288 -0
- package/src/generator/test-generator.ts +52 -0
- package/src/governance/audit-log.ts +115 -0
- package/src/governance/governance-policy.ts +72 -0
- package/src/governance/team-dashboard.ts +189 -0
- package/src/governance/workflow-audit.ts +72 -0
- package/src/index.ts +107 -0
- package/src/integrations/ci-summary.ts +37 -0
- package/src/integrations/playwright-report-adapter.ts +173 -0
- package/src/integrations/quality-gate.ts +95 -0
- package/src/integrations/sarif-report.ts +110 -0
- package/src/intelligence/autonomous-repair-workflow.ts +139 -0
- package/src/intelligence/business-intent.ts +163 -0
- package/src/intelligence/evidence-bundle.ts +300 -0
- package/src/intelligence/failure-clustering.ts +134 -0
- package/src/intelligence/generation-agent.ts +561 -0
- package/src/intelligence/generation-verifier.ts +1115 -0
- package/src/intelligence/llm-proposal.ts +519 -0
- package/src/intelligence/locator-disambiguation-engine.ts +331 -0
- package/src/intelligence/model-contract.ts +205 -0
- package/src/intelligence/model-provider.ts +348 -0
- package/src/intelligence/project-intelligence.ts +140 -0
- package/src/intelligence/repair-agent.ts +297 -0
- package/src/intelligence/repository-profile.ts +796 -0
- package/src/intelligence/suite-intelligence.ts +305 -0
- package/src/intelligence/test-intelligence.ts +136 -0
- package/src/intelligence/trace-proposal-workflow.ts +318 -0
- package/src/intelligence/verified-llm-repair-workflow.ts +48 -0
- package/src/intelligence/workflow-planner.ts +966 -0
- package/src/mcp/server.ts +970 -0
- package/src/memory/stability-ledger.ts +243 -0
- package/src/perception/app-model.ts +32 -0
- package/src/perception/crawler.ts +263 -0
- package/src/perception/index.ts +3 -0
- package/src/repair/approval-service.ts +541 -0
- package/src/repair/assertion-hasher.ts +386 -0
- package/src/repair/ast-patcher.ts +223 -0
- package/src/repair/browser-operation-executor.ts +263 -0
- package/src/repair/diff-allowlist.ts +612 -0
- package/src/repair/intent-validator.ts +761 -0
- package/src/repair/repair-operations.ts +65 -0
- package/src/repair/repair-planner.ts +467 -0
- package/src/repair/repair-workflow.ts +241 -0
- package/src/repair/safe-operation-compiler.ts +68 -0
- package/src/repair/source-mapper.ts +156 -0
- package/src/repair/statement-patcher.ts +544 -0
- package/src/repair/verification-gates.ts +46 -0
- package/src/repair/workflow-plan.ts +59 -0
- package/src/repair/workspace-promoter.ts +313 -0
- package/src/reproduce/diagnostic-rerunner.ts +287 -0
- package/src/reproduce/direct-browser-investigator.ts +208 -0
- package/src/reproduce/interactive-workflow-runner.ts +828 -0
- package/src/sandbox/dependency-strategy.ts +215 -0
- package/src/sandbox/execution-runner.ts +408 -0
- package/src/sandbox/worktree-manager.ts +287 -0
- package/src/selector/abstention-policy.ts +175 -0
- package/src/selector/candidate-extractor.ts +343 -0
- package/src/selector/live-locator-verifier.ts +139 -0
- package/src/selector/repair-candidate-ranker.ts +92 -0
- package/src/selector/selector-scorer.ts +344 -0
- package/src/trace/adapters/adapter-registry.ts +49 -0
- package/src/trace/adapters/trace-adapter.ts +28 -0
- package/src/trace/adapters/unknown-adapter.ts +50 -0
- package/src/trace/adapters/v10-adapter.ts +39 -0
- package/src/trace/adapters/v4-adapter.ts +31 -0
- package/src/trace/adapters/v8-adapter.ts +42 -0
- package/src/trace/adapters/v9-adapter.ts +39 -0
- package/src/trace/archive-reader.ts +246 -0
- package/src/trace/snapshot-resolver.ts +308 -0
- package/src/trace/trace-parser.ts +467 -0
- package/src/trace/version-detector.ts +81 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { AgentResponseParseResult, EvidenceBundle, parseAgentResponse, parseLlmRepairProposal, ProposalParseResult } from './llm-proposal.js';
|
|
2
|
+
import { AnthropicResponsePayload, createModelResponseDiagnostics, ModelCapabilities, ModelResponseDiagnostics, ModelResponseEnvelope, normalizeAnthropicResponse, normalizeOpenAiResponse, OpenAiCompatibleResponsePayload } from './model-contract.js';
|
|
3
|
+
|
|
4
|
+
export interface ProposalProvider {
|
|
5
|
+
propose(bundle: EvidenceBundle): Promise<ProposalParseResult>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface AgentStepRequest {
|
|
9
|
+
bundle: EvidenceBundle;
|
|
10
|
+
deterministicCategory: string;
|
|
11
|
+
deterministicConfidence: number;
|
|
12
|
+
observation: unknown;
|
|
13
|
+
stepIndex: number;
|
|
14
|
+
maxSteps: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AgentStepProvider {
|
|
18
|
+
proposeStep(input: AgentStepRequest): Promise<AgentResponseParseResult>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface OpenAiCompatibleProviderOptions {
|
|
22
|
+
endpoint: string;
|
|
23
|
+
model: string;
|
|
24
|
+
apiKey?: string | undefined;
|
|
25
|
+
timeoutMs?: number | undefined;
|
|
26
|
+
maxOutputTokens?: number | undefined;
|
|
27
|
+
capabilities?: Partial<ModelCapabilities> | undefined;
|
|
28
|
+
fetchImpl?: typeof fetch | undefined;
|
|
29
|
+
onUsage?: ((usage: ModelUsage) => void) | undefined;
|
|
30
|
+
onResponse?: ((diagnostics: ModelResponseDiagnostics) => void) | undefined;
|
|
31
|
+
captureResponsePreview?: boolean | undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ModelUsage {
|
|
35
|
+
provider: 'openai-compatible' | 'anthropic-compatible';
|
|
36
|
+
model: string;
|
|
37
|
+
inputTokens?: number | undefined;
|
|
38
|
+
outputTokens?: number | undefined;
|
|
39
|
+
totalTokens?: number | undefined;
|
|
40
|
+
estimatedCostUsd?: number | undefined;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface AnthropicCompatibleProviderOptions {
|
|
45
|
+
endpoint: string;
|
|
46
|
+
model: string;
|
|
47
|
+
apiKey?: string | undefined;
|
|
48
|
+
timeoutMs?: number | undefined;
|
|
49
|
+
anthropicVersion?: string | undefined;
|
|
50
|
+
maxTokens?: number | undefined;
|
|
51
|
+
inputCostPerMillionTokens?: number | undefined;
|
|
52
|
+
outputCostPerMillionTokens?: number | undefined;
|
|
53
|
+
fetchImpl?: typeof fetch | undefined;
|
|
54
|
+
capabilities?: Partial<ModelCapabilities> | undefined;
|
|
55
|
+
onUsage?: ((usage: ModelUsage) => void) | undefined;
|
|
56
|
+
onResponse?: ((diagnostics: ModelResponseDiagnostics) => void) | undefined;
|
|
57
|
+
captureResponsePreview?: boolean | undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Calls any OpenAI-compatible JSON model endpoint. The provider sends only the
|
|
62
|
+
* normalized, redaction-aware evidence bundle and accepts only the strict PIE
|
|
63
|
+
* proposal schema in return.
|
|
64
|
+
*/
|
|
65
|
+
export class OpenAiCompatibleProposalProvider implements ProposalProvider, AgentStepProvider {
|
|
66
|
+
private readonly options: OpenAiCompatibleProviderOptions;
|
|
67
|
+
|
|
68
|
+
public constructor(options: OpenAiCompatibleProviderOptions) {
|
|
69
|
+
this.options = options;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public getCapabilities(): ModelCapabilities {
|
|
73
|
+
return {
|
|
74
|
+
transport: 'openai-compatible',
|
|
75
|
+
structuredOutput: 'json_object',
|
|
76
|
+
reasoning: 'unknown',
|
|
77
|
+
toolCalls: 'native',
|
|
78
|
+
...this.options.capabilities,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public async propose(bundle: EvidenceBundle): Promise<ProposalParseResult> {
|
|
83
|
+
if (!bundle.redactionComplete) {
|
|
84
|
+
return { isValid: false, errors: ['Evidence bundle is not marked redaction-complete'] };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs ?? 30_000);
|
|
89
|
+
const started = Date.now();
|
|
90
|
+
try {
|
|
91
|
+
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
92
|
+
const response = await fetchImpl(this.options.endpoint, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
signal: controller.signal,
|
|
95
|
+
headers: {
|
|
96
|
+
'content-type': 'application/json',
|
|
97
|
+
...(this.options.apiKey ? { authorization: `Bearer ${this.options.apiKey}` } : {}),
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify({
|
|
100
|
+
model: this.options.model,
|
|
101
|
+
temperature: 0,
|
|
102
|
+
...(this.options.maxOutputTokens !== undefined ? { max_tokens: this.options.maxOutputTokens } : {}),
|
|
103
|
+
response_format: { type: 'json_object' },
|
|
104
|
+
messages: [
|
|
105
|
+
{
|
|
106
|
+
role: 'system',
|
|
107
|
+
content: proposalSystemPrompt(),
|
|
108
|
+
},
|
|
109
|
+
{ role: 'user', content: JSON.stringify(bundle) },
|
|
110
|
+
],
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!response.ok) return { isValid: false, errors: [`Model endpoint returned HTTP ${response.status}`] };
|
|
115
|
+
const payload = await response.json() as OpenAiCompatibleResponsePayload;
|
|
116
|
+
const envelope = normalizeOpenAiResponse(payload);
|
|
117
|
+
this.recordUsage(envelope, started);
|
|
118
|
+
const result = !envelope.finalText
|
|
119
|
+
? { isValid: false, errors: ['Model endpoint returned no final JSON content'] }
|
|
120
|
+
: parseLlmRepairProposal(envelope.finalText);
|
|
121
|
+
this.options.onResponse?.(createModelResponseDiagnostics(payload, envelope, 'proposal', result.errors, result.normalizationNotes ?? [], [], this.options.captureResponsePreview ?? false));
|
|
122
|
+
return result;
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const message = error instanceof Error && error.name === 'AbortError' ? 'Model request timed out' : 'Model request failed';
|
|
125
|
+
return { isValid: false, errors: [message] };
|
|
126
|
+
} finally {
|
|
127
|
+
clearTimeout(timeout);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public async proposeStep(input: AgentStepRequest): Promise<AgentResponseParseResult> {
|
|
132
|
+
if (!input.bundle.redactionComplete) return { isValid: false, errors: ['Evidence bundle is not marked redaction-complete'] };
|
|
133
|
+
const controller = new AbortController();
|
|
134
|
+
const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs ?? 30_000);
|
|
135
|
+
const started = Date.now();
|
|
136
|
+
try {
|
|
137
|
+
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
138
|
+
const response = await fetchImpl(this.options.endpoint, {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
signal: controller.signal,
|
|
141
|
+
headers: {
|
|
142
|
+
'content-type': 'application/json',
|
|
143
|
+
...(this.options.apiKey ? { authorization: `Bearer ${this.options.apiKey}` } : {}),
|
|
144
|
+
},
|
|
145
|
+
body: JSON.stringify({
|
|
146
|
+
model: this.options.model,
|
|
147
|
+
temperature: 0,
|
|
148
|
+
...(this.options.maxOutputTokens !== undefined ? { max_tokens: this.options.maxOutputTokens } : {}),
|
|
149
|
+
response_format: { type: 'json_object' },
|
|
150
|
+
messages: [
|
|
151
|
+
{ role: 'system', content: agentSystemPrompt() },
|
|
152
|
+
{ role: 'user', content: JSON.stringify({
|
|
153
|
+
...input,
|
|
154
|
+
bundle: input.stepIndex === 0 ? input.bundle : compactAgentBundle(input.bundle),
|
|
155
|
+
}) },
|
|
156
|
+
],
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) return { isValid: false, errors: [`Model endpoint returned HTTP ${response.status}`] };
|
|
160
|
+
const payload = await response.json() as OpenAiCompatibleResponsePayload;
|
|
161
|
+
const envelope = normalizeOpenAiResponse(payload);
|
|
162
|
+
this.recordUsage(envelope, started);
|
|
163
|
+
const result = !envelope.finalText
|
|
164
|
+
? { isValid: false, errors: ['Model endpoint returned no final agent JSON content'] }
|
|
165
|
+
: parseAgentResponse(envelope.finalText);
|
|
166
|
+
this.options.onResponse?.(createModelResponseDiagnostics(
|
|
167
|
+
payload,
|
|
168
|
+
envelope,
|
|
169
|
+
'agent_step',
|
|
170
|
+
result.errors,
|
|
171
|
+
result.normalizationNotes ?? [],
|
|
172
|
+
result.protocolMetadata ? Object.keys(result.protocolMetadata) : [],
|
|
173
|
+
this.options.captureResponsePreview ?? false,
|
|
174
|
+
));
|
|
175
|
+
return result;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const message = error instanceof Error && error.name === 'AbortError' ? 'Model request timed out' : 'Model request failed';
|
|
178
|
+
return { isValid: false, errors: [message] };
|
|
179
|
+
} finally {
|
|
180
|
+
clearTimeout(timeout);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private recordUsage(envelope: ModelResponseEnvelope, started: number): void {
|
|
185
|
+
this.options.onUsage?.({
|
|
186
|
+
provider: 'openai-compatible',
|
|
187
|
+
model: this.options.model,
|
|
188
|
+
inputTokens: envelope.usage?.inputTokens,
|
|
189
|
+
outputTokens: envelope.usage?.outputTokens,
|
|
190
|
+
totalTokens: envelope.usage?.totalTokens,
|
|
191
|
+
durationMs: Date.now() - started,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Calls an Anthropic Messages-compatible endpoint without coupling PIE to an SDK. */
|
|
197
|
+
export class AnthropicCompatibleProposalProvider implements ProposalProvider, AgentStepProvider {
|
|
198
|
+
private readonly options: AnthropicCompatibleProviderOptions;
|
|
199
|
+
|
|
200
|
+
public constructor(options: AnthropicCompatibleProviderOptions) {
|
|
201
|
+
this.options = options;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public getCapabilities(): ModelCapabilities {
|
|
205
|
+
return {
|
|
206
|
+
transport: 'anthropic-compatible',
|
|
207
|
+
structuredOutput: 'prompt_only',
|
|
208
|
+
reasoning: 'separate_channel',
|
|
209
|
+
toolCalls: 'native',
|
|
210
|
+
...this.options.capabilities,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public async propose(bundle: EvidenceBundle): Promise<ProposalParseResult> {
|
|
215
|
+
if (!bundle.redactionComplete) return { isValid: false, errors: ['Evidence bundle is not marked redaction-complete'] };
|
|
216
|
+
const controller = new AbortController();
|
|
217
|
+
const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs ?? 30_000);
|
|
218
|
+
const started = Date.now();
|
|
219
|
+
try {
|
|
220
|
+
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
221
|
+
const response = await fetchImpl(this.options.endpoint, {
|
|
222
|
+
method: 'POST',
|
|
223
|
+
signal: controller.signal,
|
|
224
|
+
headers: {
|
|
225
|
+
'content-type': 'application/json',
|
|
226
|
+
...(this.options.apiKey ? { 'x-api-key': this.options.apiKey } : {}),
|
|
227
|
+
'anthropic-version': this.options.anthropicVersion ?? '2023-06-01',
|
|
228
|
+
},
|
|
229
|
+
body: JSON.stringify({
|
|
230
|
+
model: this.options.model,
|
|
231
|
+
...(this.options.maxTokens !== undefined ? { max_tokens: this.options.maxTokens } : {}),
|
|
232
|
+
temperature: 0,
|
|
233
|
+
system: proposalSystemPrompt(),
|
|
234
|
+
messages: [{ role: 'user', content: JSON.stringify(bundle) }],
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
if (!response.ok) return { isValid: false, errors: [`Model endpoint returned HTTP ${response.status}`] };
|
|
238
|
+
const payload = await response.json() as AnthropicResponsePayload;
|
|
239
|
+
const envelope = normalizeAnthropicResponse(payload);
|
|
240
|
+
this.recordAnthropicUsage(envelope, started);
|
|
241
|
+
const result = !envelope.finalText
|
|
242
|
+
? { isValid: false, errors: ['Model endpoint returned no final JSON content'] }
|
|
243
|
+
: parseLlmRepairProposal(envelope.finalText);
|
|
244
|
+
this.options.onResponse?.(createModelResponseDiagnostics(payload, envelope, 'proposal', result.errors, result.normalizationNotes ?? [], [], this.options.captureResponsePreview ?? false));
|
|
245
|
+
return result;
|
|
246
|
+
} catch (error) {
|
|
247
|
+
const message = error instanceof Error && error.name === 'AbortError' ? 'Model request timed out' : 'Model request failed';
|
|
248
|
+
return { isValid: false, errors: [message] };
|
|
249
|
+
} finally {
|
|
250
|
+
clearTimeout(timeout);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public async proposeStep(input: AgentStepRequest): Promise<AgentResponseParseResult> {
|
|
255
|
+
if (!input.bundle.redactionComplete) return { isValid: false, errors: ['Evidence bundle is not marked redaction-complete'] };
|
|
256
|
+
const controller = new AbortController();
|
|
257
|
+
const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs ?? 30_000);
|
|
258
|
+
const started = Date.now();
|
|
259
|
+
try {
|
|
260
|
+
const fetchImpl = this.options.fetchImpl ?? fetch;
|
|
261
|
+
const response = await fetchImpl(this.options.endpoint, {
|
|
262
|
+
method: 'POST',
|
|
263
|
+
signal: controller.signal,
|
|
264
|
+
headers: {
|
|
265
|
+
'content-type': 'application/json',
|
|
266
|
+
...(this.options.apiKey ? { 'x-api-key': this.options.apiKey } : {}),
|
|
267
|
+
'anthropic-version': this.options.anthropicVersion ?? '2023-06-01',
|
|
268
|
+
},
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
model: this.options.model,
|
|
271
|
+
...(this.options.maxTokens !== undefined ? { max_tokens: this.options.maxTokens } : {}),
|
|
272
|
+
temperature: 0,
|
|
273
|
+
system: agentSystemPrompt(),
|
|
274
|
+
messages: [{ role: 'user', content: JSON.stringify(input) }],
|
|
275
|
+
}),
|
|
276
|
+
});
|
|
277
|
+
if (!response.ok) return { isValid: false, errors: [`Model endpoint returned HTTP ${response.status}`] };
|
|
278
|
+
const payload = await response.json() as AnthropicResponsePayload;
|
|
279
|
+
const envelope = normalizeAnthropicResponse(payload);
|
|
280
|
+
this.recordAnthropicUsage(envelope, started);
|
|
281
|
+
const result = !envelope.finalText
|
|
282
|
+
? { isValid: false, errors: ['Model endpoint returned no final agent JSON content'] }
|
|
283
|
+
: parseAgentResponse(envelope.finalText);
|
|
284
|
+
this.options.onResponse?.(createModelResponseDiagnostics(
|
|
285
|
+
payload,
|
|
286
|
+
envelope,
|
|
287
|
+
'agent_step',
|
|
288
|
+
result.errors,
|
|
289
|
+
result.normalizationNotes ?? [],
|
|
290
|
+
result.protocolMetadata ? Object.keys(result.protocolMetadata) : [],
|
|
291
|
+
this.options.captureResponsePreview ?? false,
|
|
292
|
+
));
|
|
293
|
+
return result;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const message = error instanceof Error && error.name === 'AbortError' ? 'Model request timed out' : 'Model request failed';
|
|
296
|
+
return { isValid: false, errors: [message] };
|
|
297
|
+
} finally {
|
|
298
|
+
clearTimeout(timeout);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private recordAnthropicUsage(envelope: ModelResponseEnvelope, started: number): void {
|
|
303
|
+
const inputTokens = envelope.usage?.inputTokens;
|
|
304
|
+
const outputTokens = envelope.usage?.outputTokens;
|
|
305
|
+
const totalTokens = envelope.usage?.totalTokens;
|
|
306
|
+
const estimatedCostUsd = inputTokens === undefined && outputTokens === undefined
|
|
307
|
+
? undefined
|
|
308
|
+
: (inputTokens ?? 0) / 1_000_000 * (this.options.inputCostPerMillionTokens ?? 0) + (outputTokens ?? 0) / 1_000_000 * (this.options.outputCostPerMillionTokens ?? 0);
|
|
309
|
+
this.options.onUsage?.({ provider: 'anthropic-compatible', model: this.options.model, inputTokens, outputTokens, totalTokens, estimatedCostUsd, durationMs: Date.now() - started });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function proposalSystemPrompt(): string {
|
|
314
|
+
return 'Return exactly one JSON object and nothing else. Do not use Markdown, code fences, or chain-of-thought. Use exactly these required top-level keys: proposalVersion:"1", decision:"PROPOSE" or "ABSTAIN", failureKind, confidence (0..1), reasoningSummary (short), operations (array of PIE allowlisted operations), requiredVerification (string array), and evidenceReferences (string array). For replace_locator use only kind, target, locator, and optional reason. The replace_locator target must be exactly the failed selector string from diagnostic.failedAction.selector, never a callId, source location, property name, or file path. The locator must be a complete PIE expression rooted at page. or this.page. (for example page.getByRole(...) or this.page.locator(...)). Do not return filePath, line, column, oldText, newText, patches, source code, or extra keys. If evidence is insufficient, return decision ABSTAIN with one abstain operation.';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function agentSystemPrompt(): string {
|
|
318
|
+
return 'Return exactly one JSON object and nothing else. Do not use Markdown, code fences, or chain-of-thought. Use protocolVersion "2" and no extra keys. For STEP, include every required key: responseType:"STEP", status:"CONTINUE", decision (one of INSPECT_EVIDENCE, INSPECT_BROWSER_STATE, INSPECT_REPOSITORY, READ_SOURCE_FILE, SEARCH_REPOSITORY, DISCOVER_SOURCE_MAPPING, RANK_LOCATOR_CANDIDATES, BUILD_REPAIR_PROPOSAL, RUN_TARGET_TEST, VERIFY_REPAIR, ABSTAIN), confidence (number 0..1), reasoningSummary (short summary), evidenceReferences (string array), action (an object exactly like {"kind":"inspect_evidence"}; action must never be a string; kind must be one of inspect_evidence, inspect_browser_state, inspect_repository, read_source_file, search_repository, discover_source_mapping, rank_locator_candidates, build_repair_proposal, run_target_test, verify_repair, abstain), and requiredObservation (short string). For repository actions use only path, query, testFile, configPath, and other allowlisted action fields. For FINAL, include every required key: responseType:"FINAL", status (PROPOSAL_READY, VERIFIED_READY_FOR_APPROVAL, ABSTAIN, BLOCKED, or REJECTED), classification:{category,confidence}, reasoningSummary, evidenceReferences, and humanApprovalRequired:boolean. Include proposal only for a valid proposal and use proposalVersion:"1", decision PROPOSE or ABSTAIN, failureKind, confidence, reasoningSummary, operations, requiredVerification, and evidenceReferences. Every operation must use only the PIE allowlisted repair schema. If evidence is insufficient, return FINAL ABSTAIN. Keep summaries concise and never invent tools, source edits, file paths, or unsupported fields.';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function compactAgentBundle(bundle: EvidenceBundle): EvidenceBundle {
|
|
322
|
+
const clip = (value: string | undefined, limit: number): string | undefined => {
|
|
323
|
+
if (value === undefined || value.length <= limit) return value;
|
|
324
|
+
return `${value.slice(0, limit)}\n[PIE evidence clipped after ${limit} characters]`;
|
|
325
|
+
};
|
|
326
|
+
const diagnostic = bundle.diagnostic;
|
|
327
|
+
return {
|
|
328
|
+
...bundle,
|
|
329
|
+
sourceContext: bundle.sourceContext.map((source) => ({ ...source, content: clip(source.content, 2500) ?? '' })),
|
|
330
|
+
diagnostic: diagnostic ? {
|
|
331
|
+
...diagnostic,
|
|
332
|
+
failedAction: {
|
|
333
|
+
...diagnostic.failedAction,
|
|
334
|
+
errorStack: clip(diagnostic.failedAction.errorStack, 2500),
|
|
335
|
+
logs: diagnostic.failedAction.logs?.slice(0, 20).map((log) => clip(log, 500) ?? ''),
|
|
336
|
+
},
|
|
337
|
+
snapshots: {
|
|
338
|
+
before: clip(diagnostic.snapshots.before, 5000),
|
|
339
|
+
action: clip(diagnostic.snapshots.action, 7000),
|
|
340
|
+
after: clip(diagnostic.snapshots.after, 5000),
|
|
341
|
+
},
|
|
342
|
+
networkEvents: diagnostic.networkEvents.slice(0, 20),
|
|
343
|
+
consoleEvents: diagnostic.consoleEvents.slice(0, 20).map((event) => ({ ...event, text: clip(event.text, 500) ?? '' })),
|
|
344
|
+
} : undefined,
|
|
345
|
+
limitations: [...new Set([...bundle.limitations, 'Evidence was compacted after the first agent step'])],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { buildRepositoryProfile, computeRepositoryProfileFingerprint, isLikelyProjectRoot, isLikelyRepositoryContainer, RepositoryConventionProfile } from './repository-profile.js';
|
|
4
|
+
import { effectiveReliabilityScore, StabilityLedger, StabilityLedgerData, RepairFeedbackOutcome } from '../memory/stability-ledger.js';
|
|
5
|
+
|
|
6
|
+
export interface ProjectIntelligenceSnapshot {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
profile?: RepositoryConventionProfile | undefined;
|
|
9
|
+
ledger: StabilityLedgerData;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function readProfile(projectRoot: string): Promise<RepositoryConventionProfile | undefined> {
|
|
13
|
+
try {
|
|
14
|
+
const raw = await fs.readFile(path.join(projectRoot, '.pie', 'repository-profile.json'), 'utf8');
|
|
15
|
+
return JSON.parse(raw) as RepositoryConventionProfile;
|
|
16
|
+
} catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Loads project-scoped memory without requiring a cloud service or model. */
|
|
22
|
+
export async function loadProjectIntelligence(projectRoot = process.cwd()): Promise<ProjectIntelligenceSnapshot> {
|
|
23
|
+
const root = path.resolve(projectRoot);
|
|
24
|
+
const ledger = new StabilityLedger(root);
|
|
25
|
+
await ledger.init();
|
|
26
|
+
return {
|
|
27
|
+
projectRoot: root,
|
|
28
|
+
profile: await readProfile(root),
|
|
29
|
+
ledger: ledger.getSnapshot(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the small set of equivalent Playwright page-property prefixes that
|
|
35
|
+
* appear when a selector moves between a Page Object and a generated ranking
|
|
36
|
+
* expression. The locator itself remains unchanged; only the lookup key is
|
|
37
|
+
* normalized for project memory.
|
|
38
|
+
*/
|
|
39
|
+
function selectorLookupVariants(selector: string): string[] {
|
|
40
|
+
const trimmed = selector.trim();
|
|
41
|
+
if (!trimmed) return [];
|
|
42
|
+
const variants = new Set<string>([trimmed]);
|
|
43
|
+
const pageProperty = /^(?:this\.)?(?:page|_page|browserPage)\b/;
|
|
44
|
+
if (pageProperty.test(trimmed)) {
|
|
45
|
+
variants.add(trimmed.replace(pageProperty, 'page'));
|
|
46
|
+
variants.add(trimmed.replace(pageProperty, 'this.page'));
|
|
47
|
+
}
|
|
48
|
+
return [...variants];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Creates a profile once, then returns the same project-scoped intelligence snapshot. */
|
|
52
|
+
export async function bootstrapProjectIntelligence(projectRoot = process.cwd()): Promise<ProjectIntelligenceSnapshot> {
|
|
53
|
+
const root = path.resolve(projectRoot);
|
|
54
|
+
const profilePath = path.join(root, '.pie', 'repository-profile.json');
|
|
55
|
+
const existing = await readProfile(root);
|
|
56
|
+
if (!existing && !(await isLikelyProjectRoot(root)) && (await isLikelyRepositoryContainer(root))) {
|
|
57
|
+
// Evaluation and workspace containers are not repositories. Avoid
|
|
58
|
+
// recursively profiling every child repository when invoked from one.
|
|
59
|
+
return loadProjectIntelligence(root);
|
|
60
|
+
}
|
|
61
|
+
let profile = existing;
|
|
62
|
+
let shouldWrite = false;
|
|
63
|
+
if (!profile) {
|
|
64
|
+
profile = await buildRepositoryProfile(root);
|
|
65
|
+
shouldWrite = true;
|
|
66
|
+
} else if (!profile.sourceFingerprint) {
|
|
67
|
+
// Migrate profiles created before source-change detection was introduced.
|
|
68
|
+
profile = await buildRepositoryProfile(root);
|
|
69
|
+
shouldWrite = true;
|
|
70
|
+
} else {
|
|
71
|
+
const currentFingerprint = await computeRepositoryProfileFingerprint(root);
|
|
72
|
+
if (currentFingerprint !== profile.sourceFingerprint) {
|
|
73
|
+
profile = await buildRepositoryProfile(root);
|
|
74
|
+
shouldWrite = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (shouldWrite) {
|
|
78
|
+
await fs.mkdir(path.dirname(profilePath), { recursive: true });
|
|
79
|
+
await fs.writeFile(profilePath, `${JSON.stringify(profile, null, 2)}\n`, 'utf8');
|
|
80
|
+
}
|
|
81
|
+
const snapshot = await loadProjectIntelligence(root);
|
|
82
|
+
return { ...snapshot, profile };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function getHistoricalSelectorScore(snapshot: ProjectIntelligenceSnapshot | undefined, selector: string): number | undefined {
|
|
86
|
+
if (!snapshot) return undefined;
|
|
87
|
+
for (const variant of selectorLookupVariants(selector)) {
|
|
88
|
+
const score = snapshot.ledger.selectors[variant]?.reliabilityScore;
|
|
89
|
+
if (score !== undefined) return score;
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Reads project memory with time decay for ranking while retaining raw history for audit. */
|
|
95
|
+
export function getDecayedHistoricalSelectorScore(snapshot: ProjectIntelligenceSnapshot | undefined, selector: string, now = Date.now()): number | undefined {
|
|
96
|
+
if (!snapshot) return undefined;
|
|
97
|
+
for (const variant of selectorLookupVariants(selector)) {
|
|
98
|
+
const record = snapshot.ledger.selectors[variant];
|
|
99
|
+
if (record) return effectiveReliabilityScore(record, now);
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function shouldLearnFromFailure(category: string): boolean {
|
|
105
|
+
return new Set(['LOCATOR_DRIFT', 'AMBIGUOUS_MATCH', 'TIMING_RACE', 'DYNAMIC_CONTENT_SLOW']).has(category);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function recordProjectFailure(
|
|
109
|
+
projectRoot: string,
|
|
110
|
+
selector: string | undefined,
|
|
111
|
+
category: string,
|
|
112
|
+
): Promise<void> {
|
|
113
|
+
if (!selector || !shouldLearnFromFailure(category)) return;
|
|
114
|
+
const ledger = new StabilityLedger(path.resolve(projectRoot));
|
|
115
|
+
await ledger.init();
|
|
116
|
+
await ledger.recordFailure(selector, category);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Records a selector that passed semantic and isolated execution checks. */
|
|
120
|
+
export async function recordProjectSemanticVerification(projectRoot: string, selector: string | undefined): Promise<void> {
|
|
121
|
+
if (!selector) return;
|
|
122
|
+
const ledger = new StabilityLedger(path.resolve(projectRoot));
|
|
123
|
+
await ledger.init();
|
|
124
|
+
await ledger.recordSemanticVerification(selector);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Records that an operator accepted a verified repair for this project. */
|
|
128
|
+
export async function recordProjectRepairAccepted(projectRoot: string, selector: string | undefined): Promise<void> {
|
|
129
|
+
if (!selector) return;
|
|
130
|
+
const ledger = new StabilityLedger(path.resolve(projectRoot));
|
|
131
|
+
await ledger.init();
|
|
132
|
+
await ledger.recordRepairAccepted(selector);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function recordProjectRepairFeedback(projectRoot: string, selector: string | undefined, outcome: RepairFeedbackOutcome): Promise<void> {
|
|
136
|
+
if (!selector) return;
|
|
137
|
+
const ledger = new StabilityLedger(path.resolve(projectRoot));
|
|
138
|
+
await ledger.init();
|
|
139
|
+
await ledger.recordRepairFeedback(selector, outcome);
|
|
140
|
+
}
|