@thomasminh1995/depverdict 0.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +518 -0
- package/bin/depverdict.js +7 -0
- package/bin/upgradelens.js +7 -0
- package/docs/GR-01-Semantic-Grounding-Failure-Analysis.md +309 -0
- package/docs/GR-02-Versioned-Action-Evaluation-Criteria.md +187 -0
- package/docs/GR-03-Extractive-Contract-Safety-Experiment.md +242 -0
- package/docs/GR-04-Versioned-Production-Extractive-Contract.md +154 -0
- package/docs/IA-01-Repository-Usage-Discovery.md +122 -0
- package/docs/IA-02-Repository-Impact-Analysis.md +118 -0
- package/docs/IA-03-Repository-Impact-Evidence.md +160 -0
- package/docs/IA-04-CLI-Orchestration.md +235 -0
- package/docs/IA-05-Real-Provider-Validation.md +235 -0
- package/docs/IA-05-VinGrade-Validation.md +339 -0
- package/docs/MVP-01.md +48 -0
- package/docs/MVP-02-Architecture.md +536 -0
- package/docs/MVP-02-CLI-HTTP-Runtime.md +50 -0
- package/docs/MVP-02-HTTP-Lifecycle.md +37 -0
- package/docs/MVP-02-Knowledge-Manifest-Generation.md +75 -0
- package/docs/MVP-02-Knowledge-Manifest.md +279 -0
- package/docs/MVP-02-Knowledge-Research-Orchestration.md +62 -0
- package/docs/MVP-02-Knowledge-Store.md +87 -0
- package/docs/MVP-02-PyPI-Registry-Adapter.md +97 -0
- package/docs/MVP-02-Research-Planning.md +196 -0
- package/docs/MVP-02-Source-Provenance.md +81 -0
- package/docs/MVP-02-npm-Registry-Adapter.md +99 -0
- package/docs/RR-01-End-to-End-and-Real-Provider-Validation.md +393 -0
- package/docs/RR-01-RERUN-Extractive-Contract-Validation.md +566 -0
- package/docs/RR-02-Full-Product-Workflow-and-Developer-CLI-UX-Review.md +35 -0
- package/docs/RR02-FIX-01-Persistent-Qualification-Resolution.md +32 -0
- package/docs/RR02-FIX-02-Stage-aware-CLI-Progress-and-Heartbeat.md +28 -0
- package/docs/RR02-FIX-03-npm-Capture-Evidence-Exclusion.md +33 -0
- package/docs/RR02-FIX-03A-Complete-Package-Exclusion-and-Evidence-Commit.md +223 -0
- package/docs/RR02-FIX-04-Event-loop-safe-Heartbeat.md +393 -0
- package/docs/RR02-FIX-05-Materialize-Persisted-Qualification.md +207 -0
- package/docs/RR02-RERUN-CLI-Qualification-Progress-UX-and-Package-Validation.md +342 -0
- package/docs/VinGrade-MVP-02-Validation.md +480 -0
- package/docs/VinGrade-RC02-Live-Validation.md +273 -0
- package/docs/ai-capability-discovery.md +573 -0
- package/docs/ai-engineering-production-readiness.md +390 -0
- package/docs/ai-engineering-review.md +251 -0
- package/docs/ai-runtime-governance-discovery.md +754 -0
- package/docs/architecture-overview.md +78 -0
- package/docs/cli-progress.md +111 -0
- package/docs/decisions/diff-01-brand-distribution-identity.md +450 -0
- package/docs/decisions/diff-02-identity-compatibility-contract.md +274 -0
- package/docs/decisions/diff-03-repository-docs-community-migration.md +165 -0
- package/docs/decisions/diff-04-release-evidence-gap-acceptance.md +110 -0
- package/docs/discovery/mvp-05-ai-migration-planning-discovery.md +350 -0
- package/docs/gateway-runtime-discovery.md +614 -0
- package/docs/live-ai-validation.md +299 -0
- package/docs/migration-planning-qualification-resolution.md +99 -0
- package/docs/migrations/upgradelens-to-depverdict.md +97 -0
- package/docs/mp-r03-deterministic-upgrade-decision-architecture.md +135 -0
- package/docs/mp-r04-evidence-bounded-migration-handoff-architecture.md +116 -0
- package/docs/mp-r05-product-completion-and-decision-first-cli-architecture.md +162 -0
- package/docs/mvp-05-deterministic-context-runtime.md +127 -0
- package/docs/mvp-05-migration-checklist-contract.md +166 -0
- package/docs/mvp-05-migration-checklist-orchestration.md +105 -0
- package/docs/mvp-05-migration-evaluation-and-qualification.md +135 -0
- package/docs/mvp-05-provider-neutral-generator.md +79 -0
- package/docs/ollama-local-smoke-validation.md +156 -0
- package/docs/openai-compatible-runtime-discovery.md +789 -0
- package/docs/openrouter-one-dependency-validation.md +205 -0
- package/docs/oss-02-package-guard-hardening-architecture.md +131 -0
- package/docs/oss-04-public-ci-package-metadata-architecture.md +142 -0
- package/docs/package-content-policy.md +98 -0
- package/docs/releases/v0.5.0-technical-preview.md +114 -0
- package/docs/releases/v0.6.0-alpha.1-depverdict-preview.md +101 -0
- package/docs/reviews/diff-02-identity-contract-compatibility.md +413 -0
- package/docs/reviews/diff-03-repository-docs-community-migration.md +364 -0
- package/docs/reviews/diff-04-depverdict-distribution-identity-readiness-rereview.md +453 -0
- package/docs/reviews/diff-04-fix-post-rename-identity-release-remediation.md +310 -0
- package/docs/reviews/diff-05-final-preview-distribution-qualification.md +561 -0
- package/docs/reviews/mvp-05-final-product-value-workflow-rereview.md +471 -0
- package/docs/reviews/mvp-05-product-workflow-review.md +605 -0
- package/docs/reviews/oss-01-duplicate-artifact-investigation-cleanup.md +411 -0
- package/docs/reviews/oss-02-package-guard-hardening.md +303 -0
- package/docs/reviews/oss-03-community-scaffolding.md +378 -0
- package/docs/reviews/oss-04-public-ci-package-metadata.md +439 -0
- package/docs/reviews/oss-05-technical-preview-qualification.md +482 -0
- package/docs/reviews/upgradelens-vs-upgradedepdetective-source-comparison.md +355 -0
- package/docs/reviews/v0.5.0-pre-release-smoke.md +263 -0
- package/docs/reviews/v0.5.0-version-bump-release-verification.md +306 -0
- package/docs/runtime-contract-discovery.md +521 -0
- package/docs/structured-output-compatibility-report.md +100 -0
- package/docs/ts-fix-01-exact-duplicate-occurrence-target-selection-architecture.md +111 -0
- package/docs/version-analysis-architecture.md +827 -0
- package/eval/README.md +86 -0
- package/eval/datasets/generic/declared-constraint.json +59 -0
- package/eval/datasets/generic/evidence-conflict.json +73 -0
- package/eval/datasets/generic/major-breaking-release.json +66 -0
- package/eval/datasets/generic/missing-evidence.json +46 -0
- package/eval/datasets/generic/patch-release-low.json +59 -0
- package/eval/datasets/node/axios-patch-low.json +59 -0
- package/eval/datasets/node/react-major-breaking.json +66 -0
- package/eval/datasets/node/react-minor-compatibility.json +66 -0
- package/eval/datasets/python/fastapi-deprecation.json +66 -0
- package/eval/datasets/python/pydantic-major-breaking.json +66 -0
- package/eval/migration-planning/golden-dataset-v2.json +306 -0
- package/eval/migration-planning/golden-dataset.json +214 -0
- package/eval/schemas/expected-result.schema.json +88 -0
- package/eval/schemas/golden-case.schema.json +181 -0
- package/package.json +57 -0
- package/schemas/ai-scorecard.schema.json +132 -0
- package/schemas/benchmark-report.schema.json +189 -0
- package/schemas/benchmark.schema.json +55 -0
- package/schemas/capability-profile.schema.json +44 -0
- package/schemas/conformance-report.schema.json +150 -0
- package/schemas/deployment-profile.schema.json +64 -0
- package/schemas/evaluation-report.schema.json +158 -0
- package/schemas/knowledge-evidence-bundle.schema.json +150 -0
- package/schemas/knowledge-manifest.schema.json +548 -0
- package/schemas/metrics.schema.json +178 -0
- package/schemas/migration-checklist-extractive-candidate.schema.json +42 -0
- package/schemas/migration-checklist.schema.json +706 -0
- package/schemas/migration-evaluation-dataset-v2.schema.json +208 -0
- package/schemas/migration-evaluation-dataset.schema.json +204 -0
- package/schemas/migration-planning-qualification-record.schema.json +234 -0
- package/schemas/project-manifest.schema.json +308 -0
- package/schemas/qualification-record.schema.json +56 -0
- package/schemas/repository-impact-evidence.schema.json +232 -0
- package/schemas/repository-impact.schema.json +202 -0
- package/schemas/upgrade-decision.schema.json +273 -0
- package/schemas/usage-index.schema.json +179 -0
- package/schemas/version-analysis.schema.json +449 -0
- package/src/ai-runtime-debug.js +325 -0
- package/src/ai-runtime-error.js +42 -0
- package/src/ai-runtime.js +174 -0
- package/src/ai-scorecard.js +204 -0
- package/src/ai-version-analysis.js +484 -0
- package/src/artifact-root-compatibility.js +91 -0
- package/src/benchmark-report.js +111 -0
- package/src/benchmark-runner.js +191 -0
- package/src/canonical-json.js +69 -0
- package/src/cli.js +1299 -0
- package/src/conformance-report.js +158 -0
- package/src/conformance-runner.js +253 -0
- package/src/constants.js +73 -0
- package/src/cooperative-scheduler.js +79 -0
- package/src/dependencies.js +44 -0
- package/src/dependency-ai-context.js +625 -0
- package/src/detectors.js +253 -0
- package/src/discovery.js +234 -0
- package/src/ecosystem-version-adapter.js +294 -0
- package/src/environment-compatibility.js +77 -0
- package/src/evaluation-comparator.js +158 -0
- package/src/evaluation-report.js +76 -0
- package/src/evaluation-runner.js +248 -0
- package/src/evidence-source-adapter.js +472 -0
- package/src/files.js +89 -0
- package/src/governance-diagnostics.js +64 -0
- package/src/governance-loader.js +63 -0
- package/src/governance-metadata.js +346 -0
- package/src/governance-validator.js +360 -0
- package/src/http/bounded-fetch.js +278 -0
- package/src/http/cli-http-runtime.js +44 -0
- package/src/impact/input-loader.js +157 -0
- package/src/impact/matcher.js +40 -0
- package/src/impact/repository-impact.js +199 -0
- package/src/impact/runtime.js +24 -0
- package/src/impact/status.js +62 -0
- package/src/impact/writer.js +30 -0
- package/src/impact-evidence/input-loader.js +202 -0
- package/src/impact-evidence/repository-impact-evidence.js +234 -0
- package/src/impact-evidence/runtime.js +16 -0
- package/src/impact-evidence/writer.js +30 -0
- package/src/index.js +563 -0
- package/src/installed-version-baseline.js +196 -0
- package/src/knowledge-cache.js +324 -0
- package/src/knowledge-evidence-bundle.js +101 -0
- package/src/knowledge-evidence-producer.js +233 -0
- package/src/knowledge-manifest-builder.js +188 -0
- package/src/knowledge-manifest-writer.js +32 -0
- package/src/knowledge-manifest.js +255 -0
- package/src/knowledge-research.js +615 -0
- package/src/metrics-engine.js +205 -0
- package/src/migration-checklist/ai-candidate.js +320 -0
- package/src/migration-checklist/assembler.js +37 -0
- package/src/migration-checklist/context-runtime.js +828 -0
- package/src/migration-checklist/evaluation/action-criteria.js +244 -0
- package/src/migration-checklist/evaluation/comparator-v2.js +332 -0
- package/src/migration-checklist/evaluation/comparator.js +279 -0
- package/src/migration-checklist/evaluation/dataset-v2.js +227 -0
- package/src/migration-checklist/evaluation/dataset.js +336 -0
- package/src/migration-checklist/evaluation/extractive-fixtures-v2.js +148 -0
- package/src/migration-checklist/evaluation/metrics-v2.js +226 -0
- package/src/migration-checklist/evaluation/metrics.js +158 -0
- package/src/migration-checklist/evaluation/qualification-v2.js +321 -0
- package/src/migration-checklist/evaluation/qualification.js +239 -0
- package/src/migration-checklist/evaluation/runner-v2.js +294 -0
- package/src/migration-checklist/evaluation/runner.js +194 -0
- package/src/migration-checklist/evaluation/scorecard-v2.js +106 -0
- package/src/migration-checklist/evaluation/scorecard.js +86 -0
- package/src/migration-checklist/extractive-candidate.js +166 -0
- package/src/migration-checklist/extractive-prompt.js +62 -0
- package/src/migration-checklist/generator.js +702 -0
- package/src/migration-checklist/grounding-policy.js +117 -0
- package/src/migration-checklist/input-loader.js +613 -0
- package/src/migration-checklist/migration-checklist.js +635 -0
- package/src/migration-checklist/presentation.js +292 -0
- package/src/migration-checklist/progress.js +96 -0
- package/src/migration-checklist/prompt.js +83 -0
- package/src/migration-checklist/qualification-guard.js +462 -0
- package/src/migration-checklist/qualification-resolution.js +122 -0
- package/src/migration-checklist/qualification-store.js +225 -0
- package/src/migration-checklist/runtime.js +205 -0
- package/src/migration-checklist/verification.js +134 -0
- package/src/migration-checklist/writer.js +35 -0
- package/src/openai-compatible-provider.js +451 -0
- package/src/orchestration/failure-log.js +32 -0
- package/src/orchestration/pipeline.js +200 -0
- package/src/orchestration/progress-events.js +337 -0
- package/src/orchestration/progress-reporter.js +131 -0
- package/src/orchestration/text-writer.js +22 -0
- package/src/portable.js +13 -0
- package/src/product-completion.js +249 -0
- package/src/project-manifest-input.js +90 -0
- package/src/project-manifest.js +141 -0
- package/src/python-requirements.js +137 -0
- package/src/registry/npm-packument.js +256 -0
- package/src/registry/npm-registry-adapter.js +262 -0
- package/src/registry/pypi-project.js +300 -0
- package/src/registry/pypi-registry-adapter.js +235 -0
- package/src/registry/sanitize-registry-body.js +51 -0
- package/src/renderers/console.js +160 -0
- package/src/renderers/impact-presentation.js +278 -0
- package/src/renderers/markdown.js +172 -0
- package/src/research-plan.js +455 -0
- package/src/runtime-conformance.js +275 -0
- package/src/source-provenance.js +393 -0
- package/src/source-url.js +62 -0
- package/src/structured-output-schema.js +66 -0
- package/src/target-selector.js +306 -0
- package/src/upgrade-decision/input-loader.js +107 -0
- package/src/upgrade-decision/presentation.js +43 -0
- package/src/upgrade-decision/runtime.js +21 -0
- package/src/upgrade-decision/upgrade-decision.js +626 -0
- package/src/upgrade-decision/writer.js +30 -0
- package/src/usage/analyzer-registry.js +63 -0
- package/src/usage/coverage.js +116 -0
- package/src/usage/input-loader.js +139 -0
- package/src/usage/js/analyzer.js +240 -0
- package/src/usage/js/parser.js +21 -0
- package/src/usage/runtime.js +187 -0
- package/src/usage/scope.js +44 -0
- package/src/usage/source-files.js +50 -0
- package/src/usage/usage-index.js +217 -0
- package/src/usage/writer.js +31 -0
- package/src/version-analysis-loader.js +203 -0
- package/src/version-analysis-manifest.js +314 -0
- package/src/version-analysis-writer.js +30 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
2
|
+
import { compareText } from '../portable.js';
|
|
3
|
+
import { validateMigrationChecklist } from './migration-checklist.js';
|
|
4
|
+
|
|
5
|
+
function deepFreeze(value) {
|
|
6
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
7
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
8
|
+
return Object.freeze(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function inlineCode(value) {
|
|
12
|
+
return `\`${String(value).replaceAll('`', '\\`')}\``;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function headingText(value) {
|
|
16
|
+
return String(value).replace(/[\r\n]+/g, ' ').replaceAll('\\', '\\\\').replaceAll('#', '\\#');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function qualificationPresentation(decision, checklist) {
|
|
20
|
+
if (!decision || typeof decision.status !== 'string'
|
|
21
|
+
|| typeof decision.executionAllowed !== 'boolean'
|
|
22
|
+
|| !Array.isArray(decision.limitations)) {
|
|
23
|
+
throw new TypeError('Migration Checklist presentation requires a normalized qualification decision.');
|
|
24
|
+
}
|
|
25
|
+
if (!decision.executionAllowed) {
|
|
26
|
+
throw new TypeError('Migration Checklist presentation cannot render a blocked qualification decision.');
|
|
27
|
+
}
|
|
28
|
+
if (canonicalJson(decision.limitations) !== canonicalJson(checklist.limitations)) {
|
|
29
|
+
throw new TypeError('Migration Checklist qualification decision and artifact limitations do not match.');
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
status: decision.status,
|
|
33
|
+
qualificationId: decision.qualificationId,
|
|
34
|
+
sourceKind: decision.sourceKind,
|
|
35
|
+
sourcePath: decision.sourcePath,
|
|
36
|
+
runtimeIdentity: structuredClone(decision.runtimeIdentity),
|
|
37
|
+
experimentalOverrideUsed: decision.experimentalOverrideUsed,
|
|
38
|
+
limitations: structuredClone(decision.limitations),
|
|
39
|
+
nextAction: decision.nextAction
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Map only validated artifact fields into stable presentation data. */
|
|
44
|
+
export function buildMigrationChecklistViewModel(checklist, { qualificationDecision } = {}) {
|
|
45
|
+
validateMigrationChecklist(checklist);
|
|
46
|
+
const dependencies = checklist.dependencies.map((record) => ({
|
|
47
|
+
analysisResultId: record.analysisResultId,
|
|
48
|
+
packageId: record.dependency.packageId,
|
|
49
|
+
name: record.dependency.declaredName,
|
|
50
|
+
projectId: record.dependency.projectId,
|
|
51
|
+
manifest: record.dependency.manifest,
|
|
52
|
+
status: record.status,
|
|
53
|
+
handoffStatus: record.handoff.status,
|
|
54
|
+
decisionStatus: record.decision.status,
|
|
55
|
+
decisionId: record.decisionId,
|
|
56
|
+
targetOrigin: record.decision.targetOrigin,
|
|
57
|
+
recommendationDriver: record.decision.recommendationDriver,
|
|
58
|
+
decisionReasonCodes: [...record.decision.reasonCodes],
|
|
59
|
+
analysisStatus: record.analysisStatus,
|
|
60
|
+
installedVersion: record.versions.installedVersion ?? record.versions.currentVersion,
|
|
61
|
+
currentVersion: record.versions.currentVersion,
|
|
62
|
+
currentVersionLabel: record.versions.currentVersion === null
|
|
63
|
+
? 'unknown current version' : record.versions.currentVersion,
|
|
64
|
+
targetVersion: record.versions.targetVersion,
|
|
65
|
+
targetVersionLabel: record.versions.targetPolicy === 'registryLatest'
|
|
66
|
+
? `${record.versions.targetVersion ?? 'unknown'} (registry latest fact)`
|
|
67
|
+
: (record.versions.targetVersion ?? 'unknown target version'),
|
|
68
|
+
targetPolicy: record.versions.targetPolicy,
|
|
69
|
+
affectedAreas: structuredClone(record.handoff.affectedAreas),
|
|
70
|
+
coverage: structuredClone(record.handoff.coverage),
|
|
71
|
+
verification: structuredClone(record.handoff.verification),
|
|
72
|
+
officialEvidence: structuredClone(record.handoff.officialEvidence),
|
|
73
|
+
preconditions: structuredClone(record.handoff.preconditions),
|
|
74
|
+
recovery: structuredClone(record.handoff.recovery),
|
|
75
|
+
reviewQuestions: [...record.handoff.reviewQuestions],
|
|
76
|
+
missingInformation: structuredClone(record.handoff.missingInformation),
|
|
77
|
+
nextStep: structuredClone(record.handoff.nextStep),
|
|
78
|
+
humanReviewRequired: record.handoff.humanReviewRequired,
|
|
79
|
+
findings: record.findings.map((finding) => ({
|
|
80
|
+
id: finding.id,
|
|
81
|
+
summary: finding.summary,
|
|
82
|
+
status: finding.status,
|
|
83
|
+
eligibilityReasonCode: finding.eligibility.reasonCode,
|
|
84
|
+
evidenceRefs: [...finding.evidenceRefs],
|
|
85
|
+
items: finding.items.map((item) => ({
|
|
86
|
+
id: item.id,
|
|
87
|
+
kind: item.kind,
|
|
88
|
+
basis: item.basis,
|
|
89
|
+
label: item.basis === 'AI_AUTHORED'
|
|
90
|
+
? 'AI-selected official guidance'
|
|
91
|
+
: item.kind === 'REVIEW_CANDIDATE_USAGE'
|
|
92
|
+
? 'Candidate review location'
|
|
93
|
+
: 'Manual-review item',
|
|
94
|
+
instruction: item.instruction,
|
|
95
|
+
evidenceRefs: [...item.evidenceRefs],
|
|
96
|
+
candidateLocations: structuredClone(item.candidateLocations),
|
|
97
|
+
requiresHumanReview: item.requiresHumanReview
|
|
98
|
+
}))
|
|
99
|
+
})),
|
|
100
|
+
limitations: structuredClone(record.limitations)
|
|
101
|
+
})).sort((left, right) => (
|
|
102
|
+
compareText(left.projectId, right.projectId)
|
|
103
|
+
|| compareText(left.packageId, right.packageId)
|
|
104
|
+
|| compareText(left.analysisResultId, right.analysisResultId)
|
|
105
|
+
));
|
|
106
|
+
return deepFreeze({
|
|
107
|
+
repositoryName: checklist.repository.name,
|
|
108
|
+
status: checklist.status,
|
|
109
|
+
experimental: true,
|
|
110
|
+
qualification: qualificationPresentation(qualificationDecision, checklist),
|
|
111
|
+
humanReviewRequired: true,
|
|
112
|
+
summary: structuredClone(checklist.summary),
|
|
113
|
+
dependencies,
|
|
114
|
+
limitations: structuredClone(checklist.limitations)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function renderMigrationChecklistConsole({ viewModel, artifactPath }) {
|
|
119
|
+
const summary = viewModel.summary;
|
|
120
|
+
const heading = summary.groundedActionCount === 0
|
|
121
|
+
? '! Migration checklist contains no grounded action'
|
|
122
|
+
: summary.limitationCount > 0
|
|
123
|
+
? '✓ Migration checklist created with limitations'
|
|
124
|
+
: '✓ Migration checklist created';
|
|
125
|
+
const lines = [
|
|
126
|
+
heading,
|
|
127
|
+
'',
|
|
128
|
+
` ${summary.findingCount} breaking findings represented`,
|
|
129
|
+
` ${summary.aiAuthoredItemCount} AI-selected official guidance items`,
|
|
130
|
+
` ${summary.candidateLocationCount} candidate review locations`,
|
|
131
|
+
` ${summary.handoffStatusCounts.ACTIONABLE_WITH_REVIEW} actionable handoffs require review`,
|
|
132
|
+
` ${summary.handoffStatusCounts.INVESTIGATION_REQUIRED} investigation handoffs`,
|
|
133
|
+
` ${summary.requiresHumanReviewItemCount} checklist items require human review`,
|
|
134
|
+
` Provider qualification: ${viewModel.qualification.status}`,
|
|
135
|
+
` Qualification ID: ${viewModel.qualification.qualificationId ?? 'none'}`,
|
|
136
|
+
` Qualification source: ${viewModel.qualification.sourceKind}`,
|
|
137
|
+
` Experimental override: ${viewModel.qualification.experimentalOverrideUsed ? 'YES' : 'NO'}`,
|
|
138
|
+
` Runtime identity: ${viewModel.qualification.runtimeIdentity.provider} / ${viewModel.qualification.runtimeIdentity.model} / ${viewModel.qualification.runtimeIdentity.adapter}`,
|
|
139
|
+
' Human review required: YES'
|
|
140
|
+
];
|
|
141
|
+
if (viewModel.qualification.sourcePath) {
|
|
142
|
+
lines.splice(9, 0, ` Qualification path: ${viewModel.qualification.sourcePath}`);
|
|
143
|
+
}
|
|
144
|
+
if (viewModel.qualification.nextAction !== 'NONE') {
|
|
145
|
+
lines.push(` Next action: ${viewModel.qualification.nextAction}`);
|
|
146
|
+
}
|
|
147
|
+
if (summary.groundedActionCount === 0) {
|
|
148
|
+
lines.push(
|
|
149
|
+
'',
|
|
150
|
+
' Selected official evidence did not yield an explicit grounded migration action.',
|
|
151
|
+
' Manual review is required.'
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
lines.push('', ` Checklist ${artifactPath}`, '');
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function renderItem(item) {
|
|
159
|
+
const lines = [
|
|
160
|
+
`- **${item.label} — requires human review:** ${item.instruction}`,
|
|
161
|
+
` - Evidence references: ${item.evidenceRefs.length > 0
|
|
162
|
+
? item.evidenceRefs.map(inlineCode).join(', ') : 'None'}`
|
|
163
|
+
];
|
|
164
|
+
for (const location of item.candidateLocations) {
|
|
165
|
+
lines.push(
|
|
166
|
+
` - Candidate review location: ${inlineCode(location.symbol)} in ${inlineCode(location.file)}; impact evidence ${inlineCode(location.impactEvidenceId)}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return lines;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function renderDependency(dependency) {
|
|
173
|
+
const lines = [
|
|
174
|
+
`### ${inlineCode(dependency.name)} (${inlineCode(dependency.packageId)})`,
|
|
175
|
+
'',
|
|
176
|
+
`- Checklist status: ${inlineCode(dependency.status)}`,
|
|
177
|
+
`- Handoff status: ${inlineCode(dependency.handoffStatus)}`,
|
|
178
|
+
`- Upgrade decision: ${inlineCode(dependency.decisionStatus)}`,
|
|
179
|
+
`- Decision ID: ${inlineCode(dependency.decisionId)}`,
|
|
180
|
+
`- Target origin: ${inlineCode(dependency.targetOrigin)}`,
|
|
181
|
+
`- Recommendation driver: ${inlineCode(dependency.recommendationDriver ?? 'none')}`,
|
|
182
|
+
`- Manifest: ${inlineCode(dependency.manifest)}`,
|
|
183
|
+
`- Installed version: ${dependency.installedVersion ?? 'unknown'}`,
|
|
184
|
+
`- Current version: ${dependency.currentVersionLabel}`,
|
|
185
|
+
`- Target version: ${dependency.targetVersionLabel}`,
|
|
186
|
+
`- Usage coverage: ${inlineCode(`${dependency.coverage.status} / ${dependency.coverage.reasonCode ?? 'none'}`)}`,
|
|
187
|
+
`- Next step: ${inlineCode(dependency.nextStep.code)} — ${dependency.nextStep.message}`,
|
|
188
|
+
''
|
|
189
|
+
];
|
|
190
|
+
if (dependency.affectedAreas.length === 0) {
|
|
191
|
+
lines.push('Affected areas: none verified. This is not proof that source adaptation is unnecessary.', '');
|
|
192
|
+
} else {
|
|
193
|
+
lines.push('Affected areas to inspect before proposing a patch:');
|
|
194
|
+
for (const area of dependency.affectedAreas) {
|
|
195
|
+
lines.push(
|
|
196
|
+
`- ${inlineCode(area.file)} — symbol ${inlineCode(area.symbol)}; finding ${inlineCode(area.findingId)}; impact evidence ${inlineCode(area.impactEvidenceId)}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
lines.push('');
|
|
200
|
+
}
|
|
201
|
+
if (dependency.verification.status === 'AVAILABLE') {
|
|
202
|
+
lines.push('Project-derived verification commands:');
|
|
203
|
+
for (const command of dependency.verification.commands) {
|
|
204
|
+
lines.push(
|
|
205
|
+
`- ${inlineCode(command.command)} from ${inlineCode(command.source.path)}; run in ${inlineCode(command.workingDirectory)}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
lines.push('');
|
|
209
|
+
} else if (dependency.verification.status !== 'NOT_APPLICABLE') {
|
|
210
|
+
lines.push(`${inlineCode('VERIFICATION_COMMAND_UNAVAILABLE')}: no supported project-derived verification command is available.`, '');
|
|
211
|
+
}
|
|
212
|
+
if (dependency.officialEvidence.length > 0) {
|
|
213
|
+
lines.push('Official evidence metadata:');
|
|
214
|
+
for (const evidence of dependency.officialEvidence) {
|
|
215
|
+
lines.push(
|
|
216
|
+
`- ${inlineCode(evidence.id)} — ${evidence.kind}; `
|
|
217
|
+
+ `${evidence.authority}/${evidence.trust}; `
|
|
218
|
+
+ `releases ${evidence.releaseVersions.join(', ')}; locator ${inlineCode(evidence.locator)}`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
lines.push('');
|
|
222
|
+
}
|
|
223
|
+
if (dependency.reviewQuestions.length > 0) {
|
|
224
|
+
lines.push('Investigation questions:');
|
|
225
|
+
for (const question of dependency.reviewQuestions) lines.push(`- ${question}`);
|
|
226
|
+
lines.push('');
|
|
227
|
+
}
|
|
228
|
+
if (dependency.missingInformation.length > 0) {
|
|
229
|
+
lines.push('Missing information:');
|
|
230
|
+
for (const item of dependency.missingInformation) {
|
|
231
|
+
lines.push(`- ${inlineCode(item.code)}: ${item.message}`);
|
|
232
|
+
}
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
if (dependency.findings.length === 0) lines.push('No grounded breaking-change record is available.', '');
|
|
236
|
+
for (const finding of dependency.findings) {
|
|
237
|
+
lines.push(
|
|
238
|
+
`#### ${headingText(finding.summary)}`,
|
|
239
|
+
'',
|
|
240
|
+
`- Finding ID: ${inlineCode(finding.id)}`,
|
|
241
|
+
`- Eligibility: ${inlineCode(finding.eligibilityReasonCode)}`,
|
|
242
|
+
`- Evidence references: ${finding.evidenceRefs.length > 0
|
|
243
|
+
? finding.evidenceRefs.map(inlineCode).join(', ') : 'None'}`,
|
|
244
|
+
''
|
|
245
|
+
);
|
|
246
|
+
for (const item of finding.items) lines.push(...renderItem(item));
|
|
247
|
+
lines.push('');
|
|
248
|
+
}
|
|
249
|
+
if (dependency.limitations.length > 0) {
|
|
250
|
+
lines.push('Limitations:');
|
|
251
|
+
for (const item of dependency.limitations) lines.push(`- ${inlineCode(item.code)}: ${item.message}`);
|
|
252
|
+
lines.push('');
|
|
253
|
+
}
|
|
254
|
+
return lines;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function renderMigrationChecklistMarkdownSection({ viewModel }) {
|
|
258
|
+
const lines = [
|
|
259
|
+
'## Migration Checklist',
|
|
260
|
+
'',
|
|
261
|
+
'> Experimental evidence-grounded checklist. Every AI-selected official guidance item requires human review.',
|
|
262
|
+
'>',
|
|
263
|
+
'> Checklist coverage marked COMPLETE applies only to the grounded records represented here. It does not mean the upgrade is safe or the migration is complete.',
|
|
264
|
+
'>',
|
|
265
|
+
'> Coding Agents must inspect every listed affected source area before designing or applying a patch.',
|
|
266
|
+
'',
|
|
267
|
+
`- Checklist status: ${inlineCode(viewModel.status)}`,
|
|
268
|
+
`- Provider qualification: ${inlineCode(viewModel.qualification.status)}`,
|
|
269
|
+
`- Qualification ID: ${inlineCode(viewModel.qualification.qualificationId ?? 'none')}`,
|
|
270
|
+
`- Qualification source: ${inlineCode(viewModel.qualification.sourceKind)}`,
|
|
271
|
+
`- Qualification path: ${inlineCode(viewModel.qualification.sourcePath ?? 'none')}`,
|
|
272
|
+
`- Experimental override: **${viewModel.qualification.experimentalOverrideUsed ? 'YES' : 'NO'}**`,
|
|
273
|
+
`- Runtime identity: ${inlineCode(`${viewModel.qualification.runtimeIdentity.provider} / ${viewModel.qualification.runtimeIdentity.model} / ${viewModel.qualification.runtimeIdentity.adapter}`)}`,
|
|
274
|
+
'- Human review required: **YES**',
|
|
275
|
+
`- AI-selected official guidance items: ${viewModel.summary.aiAuthoredItemCount}`,
|
|
276
|
+
`- Candidate review locations: ${viewModel.summary.candidateLocationCount}`,
|
|
277
|
+
''
|
|
278
|
+
];
|
|
279
|
+
if (viewModel.qualification.nextAction !== 'NONE') {
|
|
280
|
+
lines.splice(11, 0, `- Next action: ${inlineCode(viewModel.qualification.nextAction)}`);
|
|
281
|
+
}
|
|
282
|
+
if (viewModel.dependencies.length === 0) lines.push('No migration checklist dependency records.', '');
|
|
283
|
+
else for (const dependency of viewModel.dependencies) lines.push(...renderDependency(dependency));
|
|
284
|
+
if (viewModel.limitations.length > 0) {
|
|
285
|
+
lines.push('### Migration Checklist Limitations', '');
|
|
286
|
+
for (const item of viewModel.limitations) {
|
|
287
|
+
lines.push(`- ${inlineCode(item.code)}: ${item.message}`);
|
|
288
|
+
}
|
|
289
|
+
lines.push('');
|
|
290
|
+
}
|
|
291
|
+
return `${lines.join('\n')}\n`;
|
|
292
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export const MIGRATION_PROGRESS_EVENTS = Object.freeze([
|
|
2
|
+
'stage:start',
|
|
3
|
+
'stage:progress',
|
|
4
|
+
'stage:complete',
|
|
5
|
+
'stage:failed',
|
|
6
|
+
'stage:cancelled',
|
|
7
|
+
'migration:context-start',
|
|
8
|
+
'migration:context-complete',
|
|
9
|
+
'migration:abstained',
|
|
10
|
+
'migration:trust-rejected',
|
|
11
|
+
'migration:fallback',
|
|
12
|
+
'migration:artifact-written'
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
const EVENT_SET = new Set(MIGRATION_PROGRESS_EVENTS);
|
|
16
|
+
const MODES = new Set(['auto', 'interactive', 'plain']);
|
|
17
|
+
|
|
18
|
+
function elapsedSeconds(milliseconds) {
|
|
19
|
+
return `${(Math.max(0, milliseconds) / 1000).toFixed(1)}s`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function selectedMode(stream, mode) {
|
|
23
|
+
if (!MODES.has(mode)) throw new TypeError('Migration progress mode must be auto, interactive, or plain.');
|
|
24
|
+
return mode === 'auto' ? (stream.isTTY ? 'interactive' : 'plain') : mode;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function plainLine(event) {
|
|
28
|
+
if (event.type === 'stage:start') {
|
|
29
|
+
return `[MIGRATION_CHECKLIST] START contexts=${event.total} qualification=${event.qualificationStatus} qualificationId=${event.qualificationId ?? 'none'} experimentalOverride=${event.experimentalOverrideUsed ? 'yes' : 'no'}`;
|
|
30
|
+
}
|
|
31
|
+
if (event.type === 'migration:context-start') {
|
|
32
|
+
return `[MIGRATION_CHECKLIST] CONTEXT_START package=${event.packageName} processed=${event.processed}/${event.total}`;
|
|
33
|
+
}
|
|
34
|
+
if (['migration:context-complete', 'migration:abstained', 'migration:trust-rejected', 'migration:fallback'].includes(event.type)) {
|
|
35
|
+
return `[MIGRATION_CHECKLIST] CONTEXT package=${event.packageName} status=${event.outcome} processed=${event.processed}/${event.total}${event.reasonCode ? ` reason=${event.reasonCode}` : ''}`;
|
|
36
|
+
}
|
|
37
|
+
if (event.type === 'migration:artifact-written') {
|
|
38
|
+
return `[MIGRATION_CHECKLIST] ARTIFACT path=${event.artifactPath}`;
|
|
39
|
+
}
|
|
40
|
+
if (event.type === 'stage:complete') {
|
|
41
|
+
return `[MIGRATION_CHECKLIST] COMPLETE generated=${event.generated} abstained=${event.abstained} rejected=${event.rejected} failed=${event.failed} qualification=${event.qualificationStatus} qualificationId=${event.qualificationId ?? 'none'} experimentalOverride=${event.experimentalOverrideUsed ? 'yes' : 'no'}`;
|
|
42
|
+
}
|
|
43
|
+
if (event.type === 'stage:failed') {
|
|
44
|
+
return `[MIGRATION_CHECKLIST] FAILED reason=${event.reasonCode} qualification=${event.qualificationStatus} qualificationId=${event.qualificationId ?? 'none'} experimentalOverride=${event.experimentalOverrideUsed ? 'yes' : 'no'}`;
|
|
45
|
+
}
|
|
46
|
+
if (event.type === 'stage:cancelled') {
|
|
47
|
+
return `[MIGRATION_CHECKLIST] CANCELLED reason=${event.reasonCode}`;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function interactiveLine(event, startedAt, now) {
|
|
53
|
+
if (event.type === 'stage:start') {
|
|
54
|
+
return `● Building migration checklist ${elapsedSeconds(now - startedAt)}\n 0/${event.total} breaking findings processed\n Provider qualification: ${event.qualificationStatus}\n Qualification ID: ${event.qualificationId ?? 'none'}\n Experimental override: ${event.experimentalOverrideUsed ? 'YES' : 'NO'}`;
|
|
55
|
+
}
|
|
56
|
+
if (['migration:context-complete', 'migration:abstained', 'migration:trust-rejected', 'migration:fallback'].includes(event.type)) {
|
|
57
|
+
return ` ${event.processed}/${event.total} ${event.packageName}: ${event.outcome}`;
|
|
58
|
+
}
|
|
59
|
+
if (event.type === 'migration:artifact-written') return ` Checklist: ${event.artifactPath}`;
|
|
60
|
+
if (event.type === 'stage:complete') {
|
|
61
|
+
return `✓ Migration checklist completed ${elapsedSeconds(now - startedAt)}\n ${event.processed}/${event.total} breaking findings processed\n ${event.generated} grounded actions; ${event.abstained} abstained; ${event.rejected + event.failed} fallbacks\n Provider qualification: ${event.qualificationStatus}\n Qualification ID: ${event.qualificationId ?? 'none'}\n Experimental override: ${event.experimentalOverrideUsed ? 'YES' : 'NO'}`;
|
|
62
|
+
}
|
|
63
|
+
if (event.type === 'stage:failed') {
|
|
64
|
+
return `✗ Migration checklist failed ${elapsedSeconds(now - startedAt)}\n Reason: ${event.reasonCode}\n Provider qualification: ${event.qualificationStatus}\n Qualification ID: ${event.qualificationId ?? 'none'}\n Experimental override: ${event.experimentalOverrideUsed ? 'YES' : 'NO'}`;
|
|
65
|
+
}
|
|
66
|
+
if (event.type === 'stage:cancelled') {
|
|
67
|
+
return `■ Migration checklist cancelled ${elapsedSeconds(now - startedAt)}`;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Render stable line-oriented progress. Interactive mode intentionally uses no cursor control. */
|
|
73
|
+
export function createMigrationProgressReporter(stream, {
|
|
74
|
+
mode = 'auto',
|
|
75
|
+
clock = () => Date.now()
|
|
76
|
+
} = {}) {
|
|
77
|
+
if (!stream || typeof stream.write !== 'function') {
|
|
78
|
+
throw new TypeError('Migration progress reporter requires a writable stream.');
|
|
79
|
+
}
|
|
80
|
+
const activeMode = selectedMode(stream, mode);
|
|
81
|
+
let startedAt = null;
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
mode: activeMode,
|
|
84
|
+
handle(event) {
|
|
85
|
+
if (!event || !EVENT_SET.has(event.type)) {
|
|
86
|
+
throw new TypeError('Unknown Migration Checklist progress event.');
|
|
87
|
+
}
|
|
88
|
+
const now = clock();
|
|
89
|
+
if (event.type === 'stage:start') startedAt = now;
|
|
90
|
+
const line = activeMode === 'plain'
|
|
91
|
+
? plainLine(event)
|
|
92
|
+
: interactiveLine(event, startedAt ?? now, now);
|
|
93
|
+
if (line) stream.write(`${line}\n`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { MIGRATION_CHECKLIST_CANDIDATE_SCHEMA } from './ai-candidate.js';
|
|
2
|
+
|
|
3
|
+
export const MIGRATION_PLANNING_TASK = 'migration-planning.v1';
|
|
4
|
+
export const MIGRATION_PLANNING_PROMPT_VERSION = '1';
|
|
5
|
+
export const MIGRATION_PLANNING_SCHEMA_NAME = 'upgradelens_migration_checklist_candidate';
|
|
6
|
+
|
|
7
|
+
function promptEvidence(evidence) {
|
|
8
|
+
return {
|
|
9
|
+
id: evidence.id,
|
|
10
|
+
sourceId: evidence.sourceId,
|
|
11
|
+
kind: evidence.kind,
|
|
12
|
+
authority: evidence.authority,
|
|
13
|
+
trust: evidence.trust,
|
|
14
|
+
retrievedAt: evidence.retrievedAt,
|
|
15
|
+
contentDigest: evidence.contentDigest,
|
|
16
|
+
locator: evidence.locator,
|
|
17
|
+
releaseVersions: [...evidence.releaseVersions],
|
|
18
|
+
content: evidence.content
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Build the minimal model-visible projection. Locations and source URLs stay deterministic. */
|
|
23
|
+
export function buildMigrationChecklistPromptContext(context) {
|
|
24
|
+
return {
|
|
25
|
+
contextId: context.contextId,
|
|
26
|
+
dependency: {
|
|
27
|
+
packageId: context.dependency.packageId,
|
|
28
|
+
declaredName: context.dependency.declaredName,
|
|
29
|
+
normalizedName: context.dependency.normalizedName,
|
|
30
|
+
ecosystem: context.dependency.ecosystem,
|
|
31
|
+
registry: context.dependency.registry
|
|
32
|
+
},
|
|
33
|
+
versions: structuredClone(context.versions),
|
|
34
|
+
analysisResultId: context.analysisResultId,
|
|
35
|
+
finding: structuredClone(context.finding),
|
|
36
|
+
evidence: context.evidence.map(promptEvidence),
|
|
37
|
+
evidenceAllowlist: [...context.evidenceAllowlist],
|
|
38
|
+
eligibility: structuredClone(context.eligibility),
|
|
39
|
+
locationEligibility: structuredClone(context.locationEligibility),
|
|
40
|
+
requiresHumanReview: true,
|
|
41
|
+
humanReviewReasons: [...context.humanReviewReasons],
|
|
42
|
+
limitations: structuredClone(context.limitations)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function buildMigrationChecklistPrompt({
|
|
47
|
+
context,
|
|
48
|
+
outputSchema = MIGRATION_CHECKLIST_CANDIDATE_SCHEMA,
|
|
49
|
+
promptVersion = MIGRATION_PLANNING_PROMPT_VERSION
|
|
50
|
+
}) {
|
|
51
|
+
const modelContext = buildMigrationChecklistPromptContext(context);
|
|
52
|
+
return {
|
|
53
|
+
promptVersion,
|
|
54
|
+
system: [
|
|
55
|
+
'You are the UpgradeLens evidence transformation component for a human-review migration checklist.',
|
|
56
|
+
'Use only the bounded selected evidence in the supplied context; do not use outside knowledge.',
|
|
57
|
+
'Identify only explicit migration actions and paraphrase them as short review drafts.',
|
|
58
|
+
'This is not autonomous planning. Abstain when the evidence does not explicitly state an action.',
|
|
59
|
+
'Return only JSON that satisfies the structured output schema.'
|
|
60
|
+
].join('\n'),
|
|
61
|
+
user: [
|
|
62
|
+
'Rules:',
|
|
63
|
+
'- Keep the exact package and target-version scope supplied in the context.',
|
|
64
|
+
'- Each instruction must cite selected evidence and include a short verbatim supporting excerpt copied from that same evidence record.',
|
|
65
|
+
'- An exact excerpt is required; do not paraphrase the excerpt and do not cite an id outside evidenceAllowlist.',
|
|
66
|
+
'- Return ABSTAIN when evidence only describes a change, is ambiguous, has unclear version scope, or gives no explicit migration action.',
|
|
67
|
+
'- Do not create an action merely to complete the response.',
|
|
68
|
+
'- Do not emit identity, status, eligibility, item id, finding id, package identity, approval, or completion state.',
|
|
69
|
+
'- Do not create or mention URLs, repository files, symbols, locations, source snippets, code, patches, diffs, or commands.',
|
|
70
|
+
'- Do not invent replacement APIs, packages, flags, config keys, prerequisites, or dependency ordering.',
|
|
71
|
+
'- Do not create rollback plans, effort estimates, numeric confidence, or safety/ready/verified/complete claims.',
|
|
72
|
+
'- Unknown currentVersion remains unknown. registryLatest is a registry fact, not a recommendation.',
|
|
73
|
+
'- Unsupported or absent usage coverage does not mean unused, not impacted, or safe to upgrade.',
|
|
74
|
+
'- All generated drafts require human review.',
|
|
75
|
+
'',
|
|
76
|
+
'Structured output schema:',
|
|
77
|
+
JSON.stringify(outputSchema),
|
|
78
|
+
'',
|
|
79
|
+
'Migration Checklist Context:',
|
|
80
|
+
JSON.stringify(modelContext)
|
|
81
|
+
].join('\n')
|
|
82
|
+
};
|
|
83
|
+
}
|