@mergesignal/shared 0.3.0 → 0.4.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.
Files changed (92) hide show
  1. package/dist/deriveScanNarrative.js +1 -1
  2. package/dist/engineWireRegression.test.js +2 -2
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/narrativeParity.test.js +19 -18
  7. package/dist/presentGitHubPrComment.d.ts +3 -4
  8. package/dist/presentGitHubPrComment.d.ts.map +1 -1
  9. package/dist/presentGitHubPrComment.js +15 -61
  10. package/dist/presentation/compose/narrativeCompose.d.ts +16 -0
  11. package/dist/presentation/compose/narrativeCompose.d.ts.map +1 -0
  12. package/dist/presentation/compose/narrativeCompose.js +167 -0
  13. package/dist/presentation/dto/githubAndCliPresentation.d.ts +53 -0
  14. package/dist/presentation/dto/githubAndCliPresentation.d.ts.map +1 -0
  15. package/dist/presentation/dto/githubAndCliPresentation.js +1 -0
  16. package/dist/presentation/dto/scanCardPresentation.d.ts +25 -0
  17. package/dist/presentation/dto/scanCardPresentation.d.ts.map +1 -0
  18. package/dist/presentation/dto/scanCardPresentation.js +1 -0
  19. package/dist/presentation/dto/scanDetailsPresentation.d.ts +111 -0
  20. package/dist/presentation/dto/scanDetailsPresentation.d.ts.map +1 -0
  21. package/dist/presentation/dto/scanDetailsPresentation.js +1 -0
  22. package/dist/presentation/dto/types.d.ts +24 -0
  23. package/dist/presentation/dto/types.d.ts.map +1 -0
  24. package/dist/presentation/dto/types.js +22 -0
  25. package/dist/presentation/fixtures/scanResultFixtures.d.ts +5 -0
  26. package/dist/presentation/fixtures/scanResultFixtures.d.ts.map +1 -0
  27. package/dist/presentation/fixtures/scanResultFixtures.js +83 -0
  28. package/dist/presentation/index.d.ts +25 -0
  29. package/dist/presentation/index.d.ts.map +1 -0
  30. package/dist/presentation/index.js +13 -0
  31. package/dist/presentation/orchestration/buildScanCardPresentation.d.ts +11 -0
  32. package/dist/presentation/orchestration/buildScanCardPresentation.d.ts.map +1 -0
  33. package/dist/presentation/orchestration/buildScanCardPresentation.js +44 -0
  34. package/dist/presentation/orchestration/buildScanDetailsPresentation.d.ts +14 -0
  35. package/dist/presentation/orchestration/buildScanDetailsPresentation.d.ts.map +1 -0
  36. package/dist/presentation/orchestration/buildScanDetailsPresentation.js +19 -0
  37. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts +15 -0
  38. package/dist/presentation/orchestration/buildScanPresentationBundle.d.ts.map +1 -0
  39. package/dist/presentation/orchestration/buildScanPresentationBundle.js +23 -0
  40. package/dist/presentation/orchestration/scanPresentationBundle.d.ts +15 -0
  41. package/dist/presentation/orchestration/scanPresentationBundle.d.ts.map +1 -0
  42. package/dist/presentation/orchestration/scanPresentationBundle.js +1 -0
  43. package/dist/presentation/presentation.test.d.ts +2 -0
  44. package/dist/presentation/presentation.test.d.ts.map +1 -0
  45. package/dist/presentation/presentation.test.js +95 -0
  46. package/dist/presentation/presenters/presentCliScanSummary.d.ts +6 -0
  47. package/dist/presentation/presenters/presentCliScanSummary.d.ts.map +1 -0
  48. package/dist/presentation/presenters/presentCliScanSummary.js +30 -0
  49. package/dist/presentation/presenters/presentGitHubCheckRun.d.ts +8 -0
  50. package/dist/presentation/presenters/presentGitHubCheckRun.d.ts.map +1 -0
  51. package/dist/presentation/presenters/presentGitHubCheckRun.js +32 -0
  52. package/dist/presentation/presenters/presentGitHubPrComment.d.ts +4 -0
  53. package/dist/presentation/presenters/presentGitHubPrComment.d.ts.map +1 -0
  54. package/dist/presentation/presenters/presentGitHubPrComment.js +40 -0
  55. package/dist/presentation/presenters/presentPipelineScanCard.d.ts +3 -0
  56. package/dist/presentation/presenters/presentPipelineScanCard.d.ts.map +1 -0
  57. package/dist/presentation/presenters/presentPipelineScanCard.js +23 -0
  58. package/dist/presentation/presenters/presentScanCard.d.ts +7 -0
  59. package/dist/presentation/presenters/presentScanCard.d.ts.map +1 -0
  60. package/dist/presentation/presenters/presentScanCard.js +43 -0
  61. package/dist/presentation/presenters/presentScanDetails.d.ts +9 -0
  62. package/dist/presentation/presenters/presentScanDetails.d.ts.map +1 -0
  63. package/dist/presentation/presenters/presentScanDetails.js +177 -0
  64. package/dist/presentation/profile/derivePresentationProfile.d.ts +12 -0
  65. package/dist/presentation/profile/derivePresentationProfile.d.ts.map +1 -0
  66. package/dist/presentation/profile/derivePresentationProfile.js +86 -0
  67. package/dist/presentation/profile/presentationProfile.d.ts +9 -0
  68. package/dist/presentation/profile/presentationProfile.d.ts.map +1 -0
  69. package/dist/presentation/profile/presentationProfile.js +1 -0
  70. package/dist/presentation/render/renderCliScanSummaryText.d.ts +3 -0
  71. package/dist/presentation/render/renderCliScanSummaryText.d.ts.map +1 -0
  72. package/dist/presentation/render/renderCliScanSummaryText.js +30 -0
  73. package/dist/presentation/render/renderGitHubCheckRunMarkdown.d.ts +3 -0
  74. package/dist/presentation/render/renderGitHubCheckRunMarkdown.d.ts.map +1 -0
  75. package/dist/presentation/render/renderGitHubCheckRunMarkdown.js +23 -0
  76. package/dist/presentation/render/renderGitHubPrCommentMarkdown.d.ts +3 -0
  77. package/dist/presentation/render/renderGitHubPrCommentMarkdown.d.ts.map +1 -0
  78. package/dist/presentation/render/renderGitHubPrCommentMarkdown.js +24 -0
  79. package/dist/scanCardSummary.d.ts +4 -35
  80. package/dist/scanCardSummary.d.ts.map +1 -1
  81. package/dist/scanCardSummary.js +12 -63
  82. package/dist/scanCardSummary.test.js +56 -75
  83. package/dist/scanDetailViewModel.d.ts +1 -0
  84. package/dist/scanDetailViewModel.d.ts.map +1 -1
  85. package/dist/scanDetailViewModel.js +1 -1
  86. package/dist/scanSurfaceCopy.d.ts +25 -0
  87. package/dist/scanSurfaceCopy.d.ts.map +1 -1
  88. package/dist/scanSurfaceCopy.js +25 -0
  89. package/package.json +1 -1
  90. package/dist/presentScanCardSummary.d.ts +0 -16
  91. package/dist/presentScanCardSummary.d.ts.map +0 -1
  92. package/dist/presentScanCardSummary.js +0 -212
@@ -0,0 +1,23 @@
1
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
2
+ import { normalizeGeneratedText, } from "../../normalizeGeneratedText.js";
3
+ export function presentPipelineScanCard(pipelineStatus) {
4
+ const isRunning = pipelineStatus === "queued" || pipelineStatus === "running";
5
+ const headline = isRunning
6
+ ? scanSurfaceCopy.pipeline.scanRunning
7
+ : scanSurfaceCopy.pipeline.analysisIncomplete;
8
+ return {
9
+ pipeline: {
10
+ status: pipelineStatus,
11
+ headline: normalizeGeneratedText(headline),
12
+ subheadline: isRunning
13
+ ? scanSurfaceCopy.pipeline.scanIncomplete
14
+ : undefined,
15
+ },
16
+ headline: normalizeGeneratedText(headline),
17
+ changedPackages: [],
18
+ keyPoints: [],
19
+ affectedAreas: [],
20
+ verificationActions: [],
21
+ evidence: [],
22
+ };
23
+ }
@@ -0,0 +1,7 @@
1
+ import type { ScanCardPresentation } from "../dto/scanCardPresentation.js";
2
+ import type { ScanPresentationBundle } from "../orchestration/scanPresentationBundle.js";
3
+ export type PresentScanCardContext = {
4
+ includeFindingCounts?: boolean;
5
+ };
6
+ export declare function presentScanCard(bundle: ScanPresentationBundle, ctx?: PresentScanCardContext): ScanCardPresentation;
7
+ //# sourceMappingURL=presentScanCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentScanCard.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentScanCard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAgB3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAEzF,MAAM,MAAM,sBAAsB,GAAG;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAsBF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,sBAAsB,EAC9B,GAAG,GAAE,sBAA2B,GAC/B,oBAAoB,CAyBtB"}
@@ -0,0 +1,43 @@
1
+ import { aggregateFindingCounts } from "../dto/types.js";
2
+ import { composeAffectedAreaLabels, composeEvidenceRows, composeHeadline, composeKeyPoints, composeSubheadline, composeSupportingContext, composeVerificationActions, evidenceContextFromProfile, } from "../compose/narrativeCompose.js";
3
+ import { normalizeGeneratedText, normalizeGeneratedTextNullable, } from "../../normalizeGeneratedText.js";
4
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
5
+ function normalizeCard(p) {
6
+ return {
7
+ ...p,
8
+ headline: normalizeGeneratedText(p.headline),
9
+ subheadline: normalizeGeneratedTextNullable(p.subheadline) ?? undefined,
10
+ keyPoints: p.keyPoints.map((k) => normalizeGeneratedText(k)),
11
+ affectedAreas: p.affectedAreas.map((a) => normalizeGeneratedText(a)),
12
+ verificationActions: p.verificationActions.map((v) => normalizeGeneratedText(v)),
13
+ evidence: p.evidence.map((e) => ({
14
+ label: normalizeGeneratedText(e.label),
15
+ value: normalizeGeneratedText(e.value),
16
+ })),
17
+ supportingContext: p.supportingContext?.map((s) => normalizeGeneratedText(s)),
18
+ };
19
+ }
20
+ export function presentScanCard(bundle, ctx = {}) {
21
+ const { facts, profile, result } = bundle;
22
+ const presentation = {
23
+ status: profile.status,
24
+ density: profile.density,
25
+ confidence: profile.confidence,
26
+ evidenceContext: evidenceContextFromProfile(bundle),
27
+ headline: composeHeadline(bundle),
28
+ subheadline: composeSubheadline(bundle) ?? undefined,
29
+ changedPackages: facts.changedPackages.all,
30
+ primaryPackage: facts.changedPackages.primary ?? undefined,
31
+ keyPoints: composeKeyPoints(bundle, 3),
32
+ affectedAreas: composeAffectedAreaLabels(bundle, 2),
33
+ verificationActions: composeVerificationActions(bundle, 2),
34
+ evidence: composeEvidenceRows(bundle, 3),
35
+ supportingContext: composeSupportingContext(bundle),
36
+ riskIndex: facts.riskIndex,
37
+ findingCounts: ctx.includeFindingCounts
38
+ ? aggregateFindingCounts(result.findings)
39
+ : null,
40
+ actionLabel: scanSurfaceCopy.presentation.actionLabelReview,
41
+ };
42
+ return normalizeCard(presentation);
43
+ }
@@ -0,0 +1,9 @@
1
+ import type { ScanDetailsPresentation } from "../dto/scanDetailsPresentation.js";
2
+ import type { ScanPresentationBundle } from "../orchestration/scanPresentationBundle.js";
3
+ export type PresentScanDetailsContext = {
4
+ scanId: string;
5
+ methodologyVersion?: string | null;
6
+ prNumber?: number | null;
7
+ };
8
+ export declare function presentScanDetails(bundle: ScanPresentationBundle, ctx: PresentScanDetailsContext): ScanDetailsPresentation;
9
+ //# sourceMappingURL=presentScanDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentScanDetails.d.ts","sourceRoot":"","sources":["../../../src/presentation/presenters/presentScanDetails.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAEzF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAoHF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,GAAG,EAAE,yBAAyB,GAC7B,uBAAuB,CAgFzB"}
@@ -0,0 +1,177 @@
1
+ import { deriveDetailReachChip } from "../../formatCardExposureDisplay.js";
2
+ import { MERGE_POSTURE_LABEL } from "../../riskVocabulary.js";
3
+ import { deriveVerdictLineFromFacts, presentScanDetailViewModel, } from "../../scanDetailViewModel.js";
4
+ import { composeHeadline, composeKeyPoints, composeSubheadline, composeSupportingContext, composeVerificationActions, evidenceContextFromProfile, } from "../compose/narrativeCompose.js";
5
+ import { normalizeGeneratedText, normalizeGeneratedTextNullable, } from "../../normalizeGeneratedText.js";
6
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
7
+ function mapOperationalImpact(vm) {
8
+ const oi = vm.operationalImpact;
9
+ if (oi.status === "hidden") {
10
+ return { status: "hidden", items: [] };
11
+ }
12
+ if (oi.status === "rich") {
13
+ return {
14
+ status: "rich",
15
+ items: oi.items.map((item) => ({
16
+ message: item.message,
17
+ where: item.where,
18
+ verify: item.verify,
19
+ affectedFiles: item.affectedFiles,
20
+ })),
21
+ };
22
+ }
23
+ return {
24
+ status: "compact",
25
+ items: oi.items,
26
+ fallbackMessage: oi.fallbackMessage,
27
+ };
28
+ }
29
+ function mapRecommendations(vm) {
30
+ const items = vm.recommendedActions.items.map((item) => ({
31
+ rank: item.rank,
32
+ title: item.title,
33
+ priority: item.priority === "high" ||
34
+ item.priority === "medium" ||
35
+ item.priority === "low"
36
+ ? item.priority
37
+ : "medium",
38
+ rationale: item.detail?.why,
39
+ }));
40
+ return { items };
41
+ }
42
+ function mapEvidence(bundle, vm) {
43
+ const defaultCollapsed = bundle.profile.priority === "pr_intelligence" &&
44
+ bundle.profile.density === "rich";
45
+ const ev = vm.evidence;
46
+ if (!ev) {
47
+ return {
48
+ defaultCollapsed,
49
+ attentionAreas: [],
50
+ findings: [],
51
+ findingsOverflowCount: 0,
52
+ };
53
+ }
54
+ return {
55
+ defaultCollapsed,
56
+ attentionAreas: ev.attentionAreas.map((area) => ({
57
+ problemLabel: area.problemLabel,
58
+ problemDescription: area.problemDescription,
59
+ packages: area.packages.map((p) => ({
60
+ name: p.name,
61
+ version: p.version,
62
+ direct: p.direct,
63
+ severity: p.severity,
64
+ evidence: p.evidence,
65
+ })),
66
+ overflowCount: area.overflowCount,
67
+ })),
68
+ findings: ev.findings.map((f) => ({
69
+ id: f.id,
70
+ severity: f.severity,
71
+ title: f.title,
72
+ description: f.description,
73
+ packageName: f.packageName,
74
+ recommendation: f.recommendation,
75
+ source: f.source,
76
+ })),
77
+ findingsOverflowCount: ev.findingsOverflowCount,
78
+ topology: ev.topology
79
+ ? {
80
+ summaryLine: ev.topology.summaryLine,
81
+ deepest: ev.topology.deepest,
82
+ }
83
+ : undefined,
84
+ };
85
+ }
86
+ function mapUsage(bundle) {
87
+ const { facts } = bundle;
88
+ if (facts.packageUsage.length === 0 && facts.frameworks.length === 0) {
89
+ return undefined;
90
+ }
91
+ return {
92
+ summary: facts.packageUsage[0]
93
+ ? `${facts.packageUsage.length} package(s) with usage data`
94
+ : undefined,
95
+ items: facts.packageUsage.map((row) => ({
96
+ packageName: row.packageName,
97
+ paths: row.paths,
98
+ areas: row.areas,
99
+ criticalPaths: row.criticalPaths,
100
+ })),
101
+ frameworks: facts.frameworks,
102
+ };
103
+ }
104
+ export function presentScanDetails(bundle, ctx) {
105
+ const { facts, profile, result } = bundle;
106
+ const vm = presentScanDetailViewModel(facts, result, {
107
+ scanId: ctx.scanId,
108
+ status: "done",
109
+ methodologyVersion: ctx.methodologyVersion,
110
+ prNumber: ctx.prNumber,
111
+ repoContext: { status: "hidden" },
112
+ });
113
+ const headline = composeHeadline(bundle);
114
+ const subheadline = composeSubheadline(bundle);
115
+ const keyPoints = composeKeyPoints(bundle, 6);
116
+ const verificationTitles = composeVerificationActions(bundle, 6);
117
+ const supportingLines = composeSupportingContext(bundle);
118
+ const supportingContext = supportingLines
119
+ ? {
120
+ title: scanSurfaceCopy.scanDetail.topologyCollapsedHint,
121
+ lines: supportingLines,
122
+ }
123
+ : undefined;
124
+ const posture = profile.status;
125
+ const postureLabel = MERGE_POSTURE_LABEL[posture];
126
+ return {
127
+ evidenceContext: evidenceContextFromProfile(bundle),
128
+ status: profile.status,
129
+ density: profile.density,
130
+ confidence: profile.confidence,
131
+ hero: {
132
+ headline: normalizeGeneratedText(headline),
133
+ subheadline: normalizeGeneratedTextNullable(subheadline) ?? undefined,
134
+ verdictLine: deriveVerdictLineFromFacts(facts, result),
135
+ scopeChip: deriveDetailReachChip(result.totalScore) ?? undefined,
136
+ postureLabel,
137
+ riskIndex: facts.riskIndex,
138
+ },
139
+ narrative: {
140
+ keyPoints: keyPoints.map((k) => normalizeGeneratedText(k)),
141
+ changedPackages: facts.changedPackages.all,
142
+ primaryPackage: facts.changedPackages.primary ?? undefined,
143
+ },
144
+ usage: mapUsage(bundle),
145
+ verification: {
146
+ actions: verificationTitles.map((title) => ({
147
+ title: normalizeGeneratedText(title),
148
+ })),
149
+ },
150
+ signalSummary: vm.signalSummary
151
+ ? {
152
+ riskIndex: vm.signalSummary.score,
153
+ band: vm.signalSummary.overallBand === "moderate"
154
+ ? "medium"
155
+ : vm.signalSummary.overallBand === "high"
156
+ ? "high"
157
+ : "low",
158
+ layers: vm.signalSummary.layers.map((l) => ({
159
+ layer: l.layer,
160
+ score: l.score,
161
+ band: l.concernLabel,
162
+ label: l.label,
163
+ })),
164
+ }
165
+ : undefined,
166
+ operationalImpact: mapOperationalImpact(vm),
167
+ recommendations: mapRecommendations(vm),
168
+ evidence: mapEvidence(bundle, vm),
169
+ supportingContext,
170
+ metadata: {
171
+ scanId: ctx.scanId,
172
+ generatedAt: result.generatedAt,
173
+ methodologyVersion: ctx.methodologyVersion,
174
+ changedPackagesSummary: facts.changedPackages.primary ?? facts.changedPackages.all.join(", "),
175
+ },
176
+ };
177
+ }
@@ -0,0 +1,12 @@
1
+ import type { ScanNarrativeFacts } from "../../scanNarrativeFacts.js";
2
+ import type { PipelineStatus } from "../dto/types.js";
3
+ import type { PresentationProfile } from "./presentationProfile.js";
4
+ type DerivePresentationProfileContext = {
5
+ pipelineStatus: PipelineStatus;
6
+ decision?: string | null;
7
+ totalScore?: number | null;
8
+ };
9
+ /** INTERNAL - only called from buildScanPresentationBundle */
10
+ export declare function derivePresentationProfile(facts: ScanNarrativeFacts, ctx: DerivePresentationProfileContext): PresentationProfile | null;
11
+ export {};
12
+ //# sourceMappingURL=derivePresentationProfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derivePresentationProfile.d.ts","sourceRoot":"","sources":["../../../src/presentation/profile/derivePresentationProfile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,KAAK,gCAAgC,GAAG;IACtC,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AA+FF,8DAA8D;AAC9D,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,gCAAgC,GACpC,mBAAmB,GAAG,IAAI,CAsB5B"}
@@ -0,0 +1,86 @@
1
+ import { mergePostureFromDecision } from "../../riskVocabulary.js";
2
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
3
+ function statusFromScore(totalScore) {
4
+ if (totalScore == null || !Number.isFinite(totalScore))
5
+ return "needs_review";
6
+ if (totalScore <= 30)
7
+ return "safe";
8
+ if (totalScore <= 60)
9
+ return "needs_review";
10
+ return "risky";
11
+ }
12
+ function resolveStatus(facts, ctx) {
13
+ const fromFacts = facts.mergePosture;
14
+ if (fromFacts)
15
+ return fromFacts;
16
+ const fromDecision = mergePostureFromDecision(ctx.decision ?? undefined);
17
+ if (fromDecision)
18
+ return fromDecision;
19
+ return statusFromScore(ctx.totalScore ?? facts.riskIndex);
20
+ }
21
+ function hasStrongPrIntelligence(facts) {
22
+ return (facts.availability.tiersPresent.tier1 &&
23
+ facts.availability.repoIntelligenceParse === "ok");
24
+ }
25
+ function hasHighSeverityFindings(facts) {
26
+ return facts.reviewerGuidance.some((g) => g.kind === "finding" &&
27
+ (g.priority === "critical" || g.priority === "high"));
28
+ }
29
+ function hasRuntimeUsage(facts) {
30
+ if (facts.runtimeSurface?.kind === "runtime")
31
+ return true;
32
+ return facts.packageUsage.some((u) => u.paths.length > 0 || u.criticalPaths.length > 0);
33
+ }
34
+ function deriveDensity(facts, priority) {
35
+ if (priority === "limited") {
36
+ return hasHighSeverityFindings(facts) ? "standard" : "minimal";
37
+ }
38
+ const runtime = facts.runtimeSurface?.kind === "runtime";
39
+ const wideOrModerate = facts.blastRadius?.level === "wide" ||
40
+ facts.blastRadius?.level === "moderate";
41
+ const hasAreas = facts.affectedAreas.length > 0;
42
+ const hasRuntimePaths = hasRuntimeUsage(facts);
43
+ if (runtime && (wideOrModerate || hasAreas || hasRuntimePaths)) {
44
+ return "rich";
45
+ }
46
+ const buildOnly = facts.runtimeSurface?.kind === "build" ||
47
+ facts.reachability?.kind === "build_only";
48
+ const narrowBlast = !facts.blastRadius || facts.blastRadius.level === "narrow";
49
+ if (buildOnly && narrowBlast && !hasAreas) {
50
+ return "minimal";
51
+ }
52
+ return "standard";
53
+ }
54
+ function deriveConfidence(facts, priority) {
55
+ if (priority === "limited")
56
+ return "low";
57
+ const decisionConf = facts.confidence.decision;
58
+ if (decisionConf === "high" || decisionConf === "medium")
59
+ return "high";
60
+ const sparseUsage = facts.packageUsage.length === 0 ||
61
+ facts.packageUsage.every((u) => u.paths.length === 0 && u.criticalPaths.length === 0);
62
+ if (sparseUsage)
63
+ return "medium";
64
+ return "high";
65
+ }
66
+ /** INTERNAL - only called from buildScanPresentationBundle */
67
+ export function derivePresentationProfile(facts, ctx) {
68
+ if (ctx.pipelineStatus !== "done")
69
+ return null;
70
+ const priority = hasStrongPrIntelligence(facts)
71
+ ? "pr_intelligence"
72
+ : "limited";
73
+ const status = resolveStatus(facts, ctx);
74
+ const density = deriveDensity(facts, priority);
75
+ const confidence = deriveConfidence(facts, priority);
76
+ const degradedMessage = priority === "limited"
77
+ ? scanSurfaceCopy.presentation.limitedContextMessage
78
+ : undefined;
79
+ return {
80
+ status,
81
+ density,
82
+ confidence,
83
+ priority,
84
+ degradedMessage,
85
+ };
86
+ }
@@ -0,0 +1,9 @@
1
+ import type { PresentationConfidence, PresentationDensity, PresentationPriority, PresentationStatus } from "../dto/types.js";
2
+ export type PresentationProfile = {
3
+ status: PresentationStatus;
4
+ density: PresentationDensity;
5
+ confidence: PresentationConfidence;
6
+ priority: PresentationPriority;
7
+ degradedMessage?: string;
8
+ };
9
+ //# sourceMappingURL=presentationProfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presentationProfile.d.ts","sourceRoot":"","sources":["../../../src/presentation/profile/presentationProfile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,UAAU,EAAE,sBAAsB,CAAC;IACnC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { CliScanPresentation } from "../dto/githubAndCliPresentation.js";
2
+ export declare function renderCliScanSummaryText(p: CliScanPresentation): string;
3
+ //# sourceMappingURL=renderCliScanSummaryText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderCliScanSummaryText.d.ts","sourceRoot":"","sources":["../../../src/presentation/render/renderCliScanSummaryText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,mBAAmB,GAAG,MAAM,CA+BvE"}
@@ -0,0 +1,30 @@
1
+ import { scanSurfaceCopy } from "../../scanSurfaceCopy.js";
2
+ export function renderCliScanSummaryText(p) {
3
+ const lines = [
4
+ `MergeSignal - ${p.header.repoLabel}`,
5
+ "",
6
+ p.headline,
7
+ ];
8
+ if (p.subheadline)
9
+ lines.push(p.subheadline);
10
+ lines.push("", `Status: ${p.status} | Density: ${p.density} | Confidence: ${p.confidence}`);
11
+ if (p.metrics) {
12
+ lines.push(`Risk index: ${p.metrics.riskIndex} (${scanSurfaceCopy.actions.riskIndexDirectionShort})`, p.metrics.layerLine, `Findings: ${p.metrics.findingCount} | Recommendations: ${p.metrics.recommendationCount}`);
13
+ }
14
+ if (p.keyPoints.length > 0) {
15
+ lines.push("", "Key points:");
16
+ for (const point of p.keyPoints)
17
+ lines.push(` - ${point}`);
18
+ }
19
+ if (p.verificationActions.length > 0) {
20
+ lines.push("", "Verify:");
21
+ for (const action of p.verificationActions)
22
+ lines.push(` - ${action}`);
23
+ }
24
+ if (p.supportingContext?.length) {
25
+ lines.push("", "Supporting context:");
26
+ for (const line of p.supportingContext)
27
+ lines.push(` - ${line}`);
28
+ }
29
+ return lines.join("\n");
30
+ }
@@ -0,0 +1,3 @@
1
+ import type { GitHubCheckRunPresentation } from "../dto/githubAndCliPresentation.js";
2
+ export declare function renderGitHubCheckRunMarkdown(p: GitHubCheckRunPresentation): string;
3
+ //# sourceMappingURL=renderGitHubCheckRunMarkdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderGitHubCheckRunMarkdown.d.ts","sourceRoot":"","sources":["../../../src/presentation/render/renderGitHubCheckRunMarkdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAErF,wBAAgB,4BAA4B,CAC1C,CAAC,EAAE,0BAA0B,GAC5B,MAAM,CAuBR"}
@@ -0,0 +1,23 @@
1
+ import { normalizeGeneratedText } from "../../normalizeGeneratedText.js";
2
+ export function renderGitHubCheckRunMarkdown(p) {
3
+ const parts = [
4
+ `**${normalizeGeneratedText(p.title)}**`,
5
+ "",
6
+ p.summaryLead,
7
+ "",
8
+ ];
9
+ for (const section of p.sections) {
10
+ if (section.id === "footer") {
11
+ parts.push(section.bullets.join("\n"));
12
+ continue;
13
+ }
14
+ if (section.title) {
15
+ parts.push(`### ${section.title}`, "");
16
+ }
17
+ for (const bullet of section.bullets) {
18
+ parts.push(`- ${normalizeGeneratedText(bullet)}`);
19
+ }
20
+ parts.push("");
21
+ }
22
+ return parts.join("\n").trimEnd();
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { GitHubPrCommentPresentation } from "../dto/githubAndCliPresentation.js";
2
+ export declare function renderGitHubPrCommentMarkdown(p: GitHubPrCommentPresentation): string;
3
+ //# sourceMappingURL=renderGitHubPrCommentMarkdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderGitHubPrCommentMarkdown.d.ts","sourceRoot":"","sources":["../../../src/presentation/render/renderGitHubPrCommentMarkdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAoBtF,wBAAgB,6BAA6B,CAC3C,CAAC,EAAE,2BAA2B,GAC7B,MAAM,CAmBR"}
@@ -0,0 +1,24 @@
1
+ import { normalizeGeneratedText } from "../../normalizeGeneratedText.js";
2
+ function renderGuidanceBlock(message, where, action) {
3
+ return [
4
+ normalizeGeneratedText(message),
5
+ "",
6
+ "**Where it shows up**",
7
+ "",
8
+ normalizeGeneratedText(where),
9
+ "",
10
+ "**What to do**",
11
+ "",
12
+ normalizeGeneratedText(action),
13
+ ].join("\n");
14
+ }
15
+ export function renderGitHubPrCommentMarkdown(p) {
16
+ const parts = [`**${normalizeGeneratedText(p.title)}**`];
17
+ if (p.introLines.length > 0) {
18
+ parts.push("", p.introLines.map((l) => normalizeGeneratedText(l)).join("\n"));
19
+ }
20
+ for (const block of p.guidanceBlocks) {
21
+ parts.push("", renderGuidanceBlock(block.message, block.where ?? "See scan detail.", block.action ?? "Review before merge."));
22
+ }
23
+ return parts.join("\n\n---\n\n").trimEnd();
24
+ }
@@ -1,6 +1,4 @@
1
- import type { CatalogPhrase } from "./cardObservationCatalog.js";
2
- import type { NarrativeAvailabilityMode } from "./scanNarrativeFacts.js";
3
- import { type MergePosture } from "./riskVocabulary.js";
1
+ import type { ScanCardPresentation } from "./presentation/dto/scanCardPresentation.js";
4
2
  import type { Finding, ScanResult } from "./types.js";
5
3
  export type ScanPipelineStatus = "queued" | "running" | "done" | "failed";
6
4
  export type ScanCardPresentationState = "not_scanned" | "scanning" | "analysis_failed" | "ready" | "stale";
@@ -11,38 +9,9 @@ export type FindingCountSummary = {
11
9
  medium: number;
12
10
  low: number;
13
11
  };
14
- export type ScanCardSummary = {
15
- mergePosture: MergePosture | null;
16
- riskIndex: number | null;
17
- riskIndexBand: RiskIndexBand | null;
18
- headline: string;
19
- /** @deprecated Use operationalObservations */
20
- summaryLine: string | null;
21
- findingCounts: FindingCountSummary | null;
22
- /** @deprecated Use affectedAreas */
23
- topAffectedAreas: string[];
24
- /** Catalog-mapped topology observations (0–3). Tier 3 repo context — legacy wire field. */
25
- operationalObservations: CatalogPhrase[];
26
- /** Optional quiet subline when exactly one observation is shown. */
27
- supportingLine: string | null;
28
- narrativeMode: NarrativeAvailabilityMode;
29
- codeIntelligenceAvailable: boolean;
30
- changedPackagesDisplay: string | null;
31
- runtimeSurfaceLabel: string | null;
32
- reachabilityLabel: string | null;
33
- blastRadiusLabel: string | null;
34
- affectedAreas: string[];
35
- primaryInsight: string | null;
36
- structuralOnlyDisclaimer: string | null;
37
- /** One-line usage hint from packageUsage paths or areas. */
38
- usageSummary: string | null;
39
- /** Single verification prompt from changed-scope guidance or usage. */
40
- verificationLine: string | null;
41
- /** Optional blast factor subline when factors exist. */
42
- blastRadiusDetail: string | null;
43
- /** Short framework list (max 2 on card). */
44
- frameworksSummary: string | null;
45
- };
12
+ /** @deprecated Use ScanCardPresentation */
13
+ export type ScanCardSummary = ScanCardPresentation;
14
+ export { ScanCardPresentation };
46
15
  export declare const SCAN_CARD_SCANNING_SUMMARY = "Waiting for results...";
47
16
  export type PipelineCompletionEvidence = {
48
17
  scannedAt?: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"scanCardSummary.d.ts","sourceRoot":"","sources":["../src/scanCardSummary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scanCardSummary.d.ts","sourceRoot":"","sources":["../src/scanCardSummary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAMvF,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1E,MAAM,MAAM,yBAAyB,GACjC,aAAa,GACb,UAAU,GACV,iBAAiB,GACjB,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAGhC,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAEnE,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAsBF,wFAAwF;AACxF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,0BAA0B,GACnC,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,QAAQ,EAAE,0BAA0B,GACnC,kBAAkB,CAKpB;AAED,8EAA8E;AAC9E,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC9B,OAAO,CAST;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAEvE;AAED,mFAAmF;AACnF,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,aAAa,GAAG,IAAI,CAKtB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,GAAG,SAAS,GACrC,mBAAmB,CAgBrB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACrC,cAAc,EAAE,kBAAkB,GACjC,eAAe,CAOjB;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,2FAA2F;AAC3F,wBAAgB,qCAAqC,CACnD,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,cAAc,EAAE,kBAAkB,GACjC,eAAe,CAuBjB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,sBAAsB,GAC5B,eAAe,CAcjB"}