@paro.io/expert-shared-components 1.14.53 → 1.14.55

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 (26) hide show
  1. package/lib/components/TaxAxis/TaxAxisApi.d.ts +2 -0
  2. package/lib/components/TaxAxis/TaxAxisShell.js +138 -13
  3. package/lib/tax-axis/components/clientReport/ExecutiveSummary.d.ts +4 -1
  4. package/lib/tax-axis/components/clientReport/ExecutiveSummary.js +10 -6
  5. package/lib/tax-axis/components/clientReport/RecommendedStrategies.d.ts +6 -1
  6. package/lib/tax-axis/components/clientReport/RecommendedStrategies.js +26 -24
  7. package/lib/tax-axis/components/clientReport/StrategyCard.d.ts +1 -1
  8. package/lib/tax-axis/components/clientReport/StrategyCard.js +39 -23
  9. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +3 -1
  10. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +4 -4
  11. package/lib/tax-axis/components/dashboard/DashboardSummary.d.ts +6 -1
  12. package/lib/tax-axis/components/dashboard/DashboardSummary.js +14 -4
  13. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.d.ts +1 -1
  14. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +123 -91
  15. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +3 -2
  16. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +67 -19
  17. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +2 -0
  18. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +46 -10
  19. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +21 -1
  20. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +10 -1
  21. package/lib/tax-axis/components/processing/TaxAxisProcessing.d.ts +3 -1
  22. package/lib/tax-axis/components/processing/TaxAxisProcessing.js +77 -31
  23. package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +7 -0
  24. package/lib/tax-axis/lib/adapters/useEngineOutput.js +10 -4
  25. package/lib/tax-axis/lib/types/index.d.ts +10 -1
  26. package/package.json +1 -1
@@ -71,7 +71,7 @@ const TIER_DEFS = [
71
71
  },
72
72
  ];
73
73
  function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", }) {
74
- var _a, _b, _c;
74
+ var _a, _b, _c, _d, _e;
75
75
  const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(entityType !== null && entityType !== void 0 ? entityType : undefined), [entityType]);
76
76
  // Build tier defs dynamically from the doc spec list so they're always in sync.
77
77
  const tierDefs = (0, react_1.useMemo)(() => {
@@ -85,29 +85,62 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
85
85
  const [reviewDocId, setReviewDocId] = (0, react_1.useState)(null);
86
86
  // parsedData keyed by documentType (e.g. "profit_loss") — populated from poll results
87
87
  const [parsedDataByDocType, setParsedDataByDocType] = (0, react_1.useState)({});
88
- // On mount, fetch any already-parsed docs so the review modal has real data
88
+ // reviewedData keyed by documentType populated after CPA saves corrections; takes priority over parsedData in modal
89
+ const [reviewedDataByDocType, setReviewedDataByDocType] = (0, react_1.useState)({});
90
+ // On mount, restore card state from any already-uploaded documents in this session.
91
+ // This runs whenever the user re-enters the DOCUMENT_UPLOAD step (e.g. after an
92
+ // eval failure) so previously uploaded files appear as valid/failed instead of empty.
89
93
  (0, react_1.useEffect)(() => {
90
94
  if (!fetchUploadedDocuments)
91
95
  return;
92
96
  fetchUploadedDocuments().then((uploaded) => {
93
- const byType = {};
97
+ if (!uploaded.length)
98
+ return;
99
+ const parsedByType = {};
100
+ const reviewedByType = {};
101
+ const nextDocIds = {};
102
+ setDocs((prev) => prev.map((docState, idx) => {
103
+ // Match by documentType (canonical key) — find the most recently updated upload
104
+ const candidates = uploaded.filter((u) => String(u.documentType || '').toLowerCase() === (docState.documentType || docState.id).toLowerCase());
105
+ const match = candidates.sort((a, b) => new Date(String(b.updatedAt || 0)).getTime() - new Date(String(a.updatedAt || 0)).getTime())[0];
106
+ if (!match)
107
+ return docState;
108
+ // Populate uploadedDocIds for delete/review actions
109
+ if (match.documentId) {
110
+ nextDocIds[idx] = match.documentId;
111
+ }
112
+ const apiStatus = String(match.status || '').toUpperCase();
113
+ const nextStatus = apiStatus === 'PARSED' ? 'valid' :
114
+ apiStatus === 'FAILED' ? 'failed' :
115
+ apiStatus === 'PARSING' || apiStatus === 'UPLOADED' ? 'parsing' :
116
+ docState.status;
117
+ return Object.assign(Object.assign({}, docState), { status: nextStatus, fileName: match.fileName || docState.fileName, parseError: match.parseError || null });
118
+ }));
119
+ // Populate document ID map in one batch
120
+ setUploadedDocIds((prev) => (Object.assign(Object.assign({}, prev), nextDocIds)));
121
+ // Populate review modal data
94
122
  for (const doc of uploaded) {
95
- if (doc.parsedData && doc.documentType) {
96
- byType[doc.documentType] = doc.parsedData;
123
+ if (!doc.documentType)
124
+ continue;
125
+ if (doc.parsedData)
126
+ parsedByType[doc.documentType] = doc.parsedData;
127
+ if (doc.reviewedData && Object.keys(doc.reviewedData).length > 0) {
128
+ reviewedByType[doc.documentType] = doc.reviewedData;
97
129
  }
98
130
  }
99
- if (Object.keys(byType).length > 0) {
100
- setParsedDataByDocType(byType);
101
- }
131
+ if (Object.keys(parsedByType).length > 0)
132
+ setParsedDataByDocType(parsedByType);
133
+ if (Object.keys(reviewedByType).length > 0)
134
+ setReviewedDataByDocType(reviewedByType);
102
135
  }).catch(() => { });
103
136
  // eslint-disable-next-line react-hooks/exhaustive-deps
104
137
  }, []);
105
138
  const reviewDoc = reviewDocId
106
139
  ? (_a = docs.find((d) => d.id === reviewDocId)) !== null && _a !== void 0 ? _a : null
107
140
  : null;
108
- // The real parsedData for the document currently open in the review modal
141
+ // Prefer reviewedData (CPA-corrected) over parsedData (raw LLM extraction)
109
142
  const reviewParsedData = reviewDoc
110
- ? ((_c = (_b = parsedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _b !== void 0 ? _b : parsedDataByDocType[reviewDoc.id]) !== null && _c !== void 0 ? _c : null)
143
+ ? ((_e = (_d = (_c = (_b = reviewedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _b !== void 0 ? _b : reviewedDataByDocType[reviewDoc.id]) !== null && _c !== void 0 ? _c : parsedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _d !== void 0 ? _d : parsedDataByDocType[reviewDoc.id]) !== null && _e !== void 0 ? _e : null)
111
144
  : null;
112
145
  const pollForParseStatus = (idx, fileName, documentType) => __awaiter(this, void 0, void 0, function* () {
113
146
  if (!fetchUploadedDocuments)
@@ -331,6 +364,9 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
331
364
  const docId = uploadedDocIds[docs.indexOf(reviewDoc)];
332
365
  if (docId)
333
366
  yield onSaveReviewedField(docId, fields);
367
+ // Store locally so reopening the modal shows corrected values
368
+ const docTypeKey = reviewDoc.documentType || reviewDoc.id;
369
+ setReviewedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), { [docTypeKey]: fields })));
334
370
  })
335
371
  : undefined, onClose: () => setReviewDocId(null) }))));
336
372
  }
@@ -9,5 +9,25 @@ export interface TaxAxisPreparerWorkpaperProps extends TaxAxisScreenProps {
9
9
  liveStrategies?: Strategy[];
10
10
  /** When provided, bypasses local computeAllStrategies. Must accompany liveStrategies. */
11
11
  liveComputedMap?: ComputedMap;
12
+ /** Live cpa_workflow from engine output */
13
+ cpaWorkflow?: {
14
+ workpaper_codes?: string[] | null;
15
+ section_6694_notices?: Array<{
16
+ strategy_id: string;
17
+ position_strength: string;
18
+ notice: string;
19
+ }>;
20
+ prior_year_flags?: string[];
21
+ engagement_recommendations?: string[];
22
+ };
23
+ /** Live risk disclosures from engine output */
24
+ riskDisclosures?: string[];
25
+ /** Live business profile from engine output */
26
+ businessProfile?: {
27
+ confidence_tier?: string;
28
+ data_years?: number;
29
+ data_quality_flags?: string[];
30
+ effective_tax_rate?: number;
31
+ };
12
32
  }
13
- export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
33
+ export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap, cpaWorkflow, riskDisclosures, businessProfile }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
@@ -32,7 +32,7 @@ const ReportToolbar_1 = require("../shared/ReportToolbar");
32
32
  const EngagementHeader_1 = require("./EngagementHeader");
33
33
  const Section6694Summary_1 = require("./Section6694Summary");
34
34
  const PriorityGroup_1 = require("./PriorityGroup");
35
- function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap }) {
35
+ function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap, cpaWorkflow, riskDisclosures, businessProfile }) {
36
36
  const [expanded, setExpanded] = (0, react_1.useState)({});
37
37
  const [printMode, setPrintMode] = (0, react_1.useState)(false);
38
38
  const toggle = (rank, section) => setExpanded(prev => (Object.assign(Object.assign({}, prev), { [rank + "-" + section]: !prev[rank + "-" + section] })));
@@ -168,6 +168,15 @@ function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrat
168
168
  "$" + interactionAdj.toLocaleString() + " ",
169
169
  react_1.default.createElement("span", { style: { fontWeight: 400, fontSize: 10 } }, "(\u221215%)")),
170
170
  react_1.default.createElement("td", { colSpan: 2 })))))),
171
+ (cpaWorkflow === null || cpaWorkflow === void 0 ? void 0 : cpaWorkflow.engagement_recommendations) && cpaWorkflow.engagement_recommendations.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24 }) },
172
+ react_1.default.createElement("div", { style: sectionTitle }, "CPA ENGAGEMENT NOTES"),
173
+ cpaWorkflow.engagement_recommendations.map((rec, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 12, color: palette_1.P.gray700, lineHeight: 1.7, fontFamily: palette_1.P.body, padding: '8px 0', borderTop: i > 0 ? '1px solid ' + palette_1.P.gray100 : 'none' } }, rec))))),
174
+ riskDisclosures && riskDisclosures.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24, borderColor: '#FDBA74' }) },
175
+ react_1.default.createElement("div", { style: Object.assign(Object.assign({}, sectionTitle), { color: palette_1.P.orange }) }, "RISK DISCLOSURES"),
176
+ riskDisclosures.map((r, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 11, color: palette_1.P.gray600, lineHeight: 1.65, fontFamily: palette_1.P.body, padding: '6px 0', borderTop: i > 0 ? '1px solid ' + palette_1.P.gray100 : 'none' } }, r))))),
177
+ (businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_quality_flags) && businessProfile.data_quality_flags.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24, borderColor: '#FDBA74' }) },
178
+ react_1.default.createElement("div", { style: Object.assign(Object.assign({}, sectionTitle), { color: palette_1.P.orange }) }, "DATA QUALITY FLAGS"),
179
+ businessProfile.data_quality_flags.map((f, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 11, color: palette_1.P.gray600, padding: '4px 0', fontFamily: palette_1.P.body } }, f))))),
171
180
  react_1.default.createElement("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 0", borderTop: "1px solid " + palette_1.P.gray200, fontSize: 11, color: palette_1.P.gray500, fontFamily: palette_1.P.body } },
172
181
  react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 6 } },
173
182
  react_1.default.createElement("div", { style: { width: 16, height: 16, borderRadius: 4, background: palette_1.P.navy, display: "flex", alignItems: "center", justifyContent: "center" } },
@@ -3,5 +3,7 @@ import { ClientProfile, TaxAxisScreenProps } from "../../lib/types";
3
3
  export interface TaxAxisProcessingProps extends TaxAxisScreenProps {
4
4
  onComplete: () => void;
5
5
  profile?: ClientProfile;
6
+ /** Set to true by the shell poller when stage===REPORT_READY is detected. */
7
+ reportReady?: boolean;
6
8
  }
7
- export declare function TaxAxisProcessing({ onComplete, profile, userContext: _userContext, }: TaxAxisProcessingProps): React.JSX.Element;
9
+ export declare function TaxAxisProcessing({ onComplete, profile, reportReady, userContext: _userContext, }: TaxAxisProcessingProps): React.JSX.Element;
@@ -26,21 +26,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.TaxAxisProcessing = TaxAxisProcessing;
27
27
  const react_1 = __importStar(require("react"));
28
28
  const ProcessingStages_1 = require("./ProcessingStages");
29
+ const CRAWL_CEILING = 80; // hold here until reportReady
30
+ const CRAWL_TICK_MS = 180; // interval between crawl ticks
31
+ const CRAWL_STEP = 0.35; // % added each tick (reaches 80% in ~41s)
32
+ const FINISH_MS = 600; // ms to animate from current% → 100% once ready
33
+ const STAGE_ADVANCE_MS = 3200; // how often the displayed stage advances
29
34
  function buildStages(profile) {
30
35
  var _a;
31
36
  if (!profile) {
32
37
  return [
33
38
  "Parsing source documents",
34
39
  "Injecting IRS 2026 parameters",
35
- "Screening 25 eligible strategies",
40
+ "Screening eligible strategies",
36
41
  "Computing deterministic tax math",
37
42
  "Generating IRS citations",
38
43
  ];
39
44
  }
40
- const entity = profile.entity || "your";
45
+ const entity = profile.entity || "your business";
41
46
  const stateCount = ((_a = profile.states) === null || _a === void 0 ? void 0 : _a.length) || 1;
42
47
  const bizName = profile.bizName || "your business";
43
- // Verbatim from mock (App.jsx:1473-1477)
44
48
  const base = [
45
49
  "Parsing source documents",
46
50
  "Injecting IRS 2026 parameters",
@@ -53,53 +57,95 @@ function buildStages(profile) {
53
57
  if (entity === "S-Corporation") {
54
58
  base.push("Benchmarking officer salary against BLS data");
55
59
  }
56
- base.push("Screening 25 eligible strategies", "Computing deterministic tax math", "Cross-validating source documents", "Generating IRS citations", `Assembling TaxAxis report for ${bizName}`);
60
+ base.push("Screening 30 eligible strategies", "Computing deterministic tax math", "Cross-validating source documents", "Generating IRS citations", `Assembling TaxAxis report for ${bizName}`);
57
61
  return base;
58
62
  }
59
- function TaxAxisProcessing({ onComplete, profile, userContext: _userContext = "expert", }) {
63
+ function TaxAxisProcessing({ onComplete, profile, reportReady = false, userContext: _userContext = "expert", }) {
60
64
  const stages = (0, react_1.useMemo)(() => buildStages(profile), [profile]);
61
65
  const [progress, setProgress] = (0, react_1.useState)(0);
62
- // Staged timer from mock (App.jsx:1481). setInterval advances one stage
63
- // per tick; after the final stage, a 1000ms delay fires onComplete.
64
- // Target: ~8s total. Dynamic path: 10 stages × 700ms = 7s + 1s nav = 8s.
65
- // Fallback path (no profile): 5 stages × 1400ms = 7s + 1s nav = 8s.
66
- const stageInterval = stages.length <= 5 ? 1400 : 700;
66
+ const [stageIdx, setStageIdx] = (0, react_1.useState)(0);
67
+ const finishingRef = (0, react_1.useRef)(false);
68
+ const completedRef = (0, react_1.useRef)(false);
69
+ // Track current progress in a ref so the finish animation can read it synchronously
70
+ // without relying on the async functional-updater pattern.
71
+ const progressRef = (0, react_1.useRef)(0);
72
+ const setProgressSync = (v) => {
73
+ progressRef.current = v;
74
+ setProgress(v);
75
+ };
76
+ // ── Crawl: 0 → 80% — skipped entirely if reportReady already true on mount ──
67
77
  (0, react_1.useEffect)(() => {
68
- let i = 0;
69
- let navTimer = null;
78
+ if (reportReady || finishingRef.current)
79
+ return;
70
80
  const iv = setInterval(() => {
71
- i++;
72
- setProgress(i);
73
- if (i >= stages.length) {
81
+ if (finishingRef.current) {
74
82
  clearInterval(iv);
75
- navTimer = setTimeout(onComplete, 1000);
83
+ return;
84
+ }
85
+ const next = Math.min(progressRef.current + CRAWL_STEP, CRAWL_CEILING);
86
+ setProgressSync(next);
87
+ if (next >= CRAWL_CEILING)
88
+ clearInterval(iv);
89
+ }, CRAWL_TICK_MS);
90
+ return () => clearInterval(iv);
91
+ // reportReady intentionally in deps: if it arrives before mount effect runs, skip crawl
92
+ }, [reportReady]);
93
+ // ── Stage labels: advance every STAGE_ADVANCE_MS ─────────────────
94
+ (0, react_1.useEffect)(() => {
95
+ const iv = setInterval(() => {
96
+ setStageIdx((i) => (i + 1 < stages.length ? i + 1 : i));
97
+ }, STAGE_ADVANCE_MS);
98
+ return () => clearInterval(iv);
99
+ }, [stages.length]);
100
+ // ── Finish: reportReady → fast fill to 100%, then onComplete ─────
101
+ (0, react_1.useEffect)(() => {
102
+ if (!reportReady || finishingRef.current || completedRef.current)
103
+ return;
104
+ finishingRef.current = true;
105
+ setStageIdx(stages.length - 1);
106
+ // Read current progress synchronously from ref — not from stale state closure
107
+ const startPct = progressRef.current;
108
+ const startTime = Date.now();
109
+ const frame = () => {
110
+ const elapsed = Date.now() - startTime;
111
+ const t = Math.min(elapsed / FINISH_MS, 1);
112
+ const eased = t < 1 ? t * (2 - t) : 1;
113
+ setProgressSync(startPct + (100 - startPct) * eased);
114
+ if (t < 1) {
115
+ requestAnimationFrame(frame);
116
+ }
117
+ else {
118
+ setProgressSync(100);
119
+ if (!completedRef.current) {
120
+ completedRef.current = true;
121
+ setTimeout(onComplete, 150);
122
+ }
76
123
  }
77
- }, stageInterval);
78
- return () => {
79
- clearInterval(iv);
80
- if (navTimer !== null)
81
- clearTimeout(navTimer);
82
124
  };
83
- }, [stages.length, stageInterval, onComplete]);
84
- const pct = Math.round((progress / stages.length) * 100);
85
- const title = (profile === null || profile === void 0 ? void 0 : profile.bizName)
86
- ? `Analyzing ${profile.bizName}`
87
- : "Running Analysis";
125
+ requestAnimationFrame(frame);
126
+ // eslint-disable-next-line react-hooks/exhaustive-deps
127
+ }, [reportReady, stages.length]);
128
+ const pct = Math.round(progress);
129
+ const title = (profile === null || profile === void 0 ? void 0 : profile.bizName) ? `Analyzing ${profile.bizName}` : "Running Analysis";
130
+ const isFinishing = finishingRef.current;
88
131
  return (react_1.default.createElement("div", { className: "pt-[60px] text-center" },
89
132
  react_1.default.createElement("div", { className: "relative w-[72px] h-[72px] mx-auto mb-7" },
90
133
  react_1.default.createElement("div", { className: "absolute inset-0 rounded-full animate-ping", style: {
91
134
  background: "radial-gradient(circle, #248384, transparent 70%)",
92
135
  opacity: 0.15,
136
+ animationDuration: isFinishing ? "0.4s" : "1.4s",
93
137
  } }),
94
138
  react_1.default.createElement("div", { className: "absolute inset-0 w-[72px] h-[72px] rounded-full bg-tax-axis-surface flex items-center justify-center", style: { border: "2px solid rgba(36,131,132,0.4)" } },
95
- react_1.default.createElement("span", { className: "text-[28px] font-bold text-tax-axis-teal-light font-tax-axis-mono" }, pct))),
139
+ react_1.default.createElement("span", { className: "font-bold text-tax-axis-teal-light font-tax-axis-mono", style: { fontSize: pct === 100 ? 20 : 28 } }, pct === 100 ? "✓" : pct))),
96
140
  react_1.default.createElement("h2", { className: "text-[22px] font-bold text-white font-tax-axis-head mb-1" }, title),
97
- react_1.default.createElement("p", { className: "text-[13px] text-tax-axis-text-3 font-tax-axis-body mb-7" }, "Deterministic \u00B7 Temperature 0 \u00B7 IRS-cited"),
141
+ react_1.default.createElement("p", { className: "text-[13px] text-tax-axis-text-3 font-tax-axis-body mb-7" }, isFinishing ? "Report ready — loading your results…" : "Deterministic · Temperature 0 · IRS-cited"),
98
142
  react_1.default.createElement("div", { className: "max-w-[360px] mx-auto mb-6 h-0.5 bg-tax-axis-surface-2 rounded-sm overflow-hidden" },
99
- react_1.default.createElement("div", { className: "h-full rounded-sm transition-[width] duration-[400ms]", style: {
100
- width: `${pct}%`,
143
+ react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
144
+ width: `${progress}%`,
101
145
  background: "linear-gradient(90deg, #248384, #A1E5E6)",
102
146
  boxShadow: "0 0 8px #248384",
147
+ transition: isFinishing ? "none" : "width 0.18s linear",
103
148
  } })),
104
- react_1.default.createElement(ProcessingStages_1.ProcessingStages, { stages: stages, progress: progress })));
149
+ react_1.default.createElement(ProcessingStages_1.ProcessingStages, { stages: stages, progress: stageIdx + 1 }),
150
+ pct >= CRAWL_CEILING && !isFinishing && (react_1.default.createElement("p", { className: "text-[11px] text-tax-axis-text-4 font-tax-axis-mono mt-4 animate-pulse" }, "Finalizing analysis\u2026"))));
105
151
  }
@@ -1,4 +1,9 @@
1
1
  import type { Strategy, ComputedMap } from "../types";
2
+ export interface SourceDocumentRef {
3
+ field_label: string;
4
+ value_display: string;
5
+ source_hint: string;
6
+ }
2
7
  export interface EngineCalculationTrace {
3
8
  strategy_id: string;
4
9
  branch_executed: string | null;
@@ -16,6 +21,8 @@ export interface EngineCalculationTrace {
16
21
  forms_required: string[];
17
22
  deadline_flag: string | null;
18
23
  amt_flag: boolean;
24
+ source_documents?: SourceDocumentRef[];
25
+ specialist_note?: string | null;
19
26
  }
20
27
  export interface EngineStrategyAnalysis {
21
28
  strategy_id: string;
@@ -71,6 +71,7 @@ function resolveTimelineBucket(strategyId, roadmap) {
71
71
  }
72
72
  // ── CalculationTrace → StrategyTraceStep[] ───────────────────────────
73
73
  function traceFromEngine(trace) {
74
+ var _a, _b;
74
75
  const steps = [];
75
76
  // Emit formula as step 1
76
77
  if (trace.formula) {
@@ -83,7 +84,7 @@ function traceFromEngine(trace) {
83
84
  });
84
85
  }
85
86
  // Emit confidence interval as step 2 when present
86
- if (trace.confidence_interval) {
87
+ if (((_a = trace.confidence_interval) === null || _a === void 0 ? void 0 : _a.low) != null && ((_b = trace.confidence_interval) === null || _b === void 0 ? void 0 : _b.high) != null) {
87
88
  steps.push({
88
89
  n: 2,
89
90
  step: "Confidence range",
@@ -95,7 +96,7 @@ function traceFromEngine(trace) {
95
96
  return steps;
96
97
  }
97
98
  function adaptEngineOutput(engineOutput) {
98
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
99
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
99
100
  const strategies = [];
100
101
  const computedMap = new Map();
101
102
  for (const analysis of engineOutput.strategy_analysis) {
@@ -108,6 +109,7 @@ function adaptEngineOutput(engineOutput) {
108
109
  const lo = (_b = (_a = ci === null || ci === void 0 ? void 0 : ci.low) !== null && _a !== void 0 ? _a : template === null || template === void 0 ? void 0 : template.lo) !== null && _b !== void 0 ? _b : 0;
109
110
  const hi = (_d = (_c = ci === null || ci === void 0 ? void 0 : ci.high) !== null && _c !== void 0 ? _c : template === null || template === void 0 ? void 0 : template.hi) !== null && _d !== void 0 ? _d : 0;
110
111
  const timelineBucket = resolveTimelineBucket(analysis.strategy_id, engineOutput.implementation_roadmap);
112
+ const clientSummaryEntry = engineOutput.client_summary.strategies.find((cs) => cs.strategy_name === analysis.strategy_name);
111
113
  const strategy = {
112
114
  rank: rank !== null && rank !== void 0 ? rank : 99,
113
115
  code: (_e = template === null || template === void 0 ? void 0 : template.code) !== null && _e !== void 0 ? _e : analysis.strategy_id,
@@ -131,8 +133,12 @@ function adaptEngineOutput(engineOutput) {
131
133
  preferIndustry: template === null || template === void 0 ? void 0 : template.preferIndustry,
132
134
  minEmployees: template === null || template === void 0 ? void 0 : template.minEmployees,
133
135
  needsOwnerComp: template === null || template === void 0 ? void 0 : template.needsOwnerComp,
134
- clientBrief: (_q = (_p = engineOutput.client_summary.strategies.find((cs) => cs.strategy_name === analysis.strategy_name)) === null || _p === void 0 ? void 0 : _p.why_it_applies) !== null && _q !== void 0 ? _q : template === null || template === void 0 ? void 0 : template.clientBrief,
135
- action: (_s = (_r = engineOutput.client_summary.strategies.find((cs) => cs.strategy_name === analysis.strategy_name)) === null || _r === void 0 ? void 0 : _r.next_step) !== null && _s !== void 0 ? _s : template === null || template === void 0 ? void 0 : template.action,
136
+ clientBrief: (_p = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.why_it_applies) !== null && _p !== void 0 ? _p : template === null || template === void 0 ? void 0 : template.clientBrief,
137
+ action: (_q = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.next_step) !== null && _q !== void 0 ? _q : template === null || template === void 0 ? void 0 : template.action,
138
+ sourceDocuments: (_r = trace === null || trace === void 0 ? void 0 : trace.source_documents) !== null && _r !== void 0 ? _r : [],
139
+ quickWin: analysis.quick_win,
140
+ positionStrength: (_s = trace === null || trace === void 0 ? void 0 : trace.position_strength) !== null && _s !== void 0 ? _s : undefined,
141
+ specialistNote: (_t = trace === null || trace === void 0 ? void 0 : trace.specialist_note) !== null && _t !== void 0 ? _t : undefined,
136
142
  };
137
143
  strategies.push(strategy);
138
144
  computedMap.set(strategy.rank, {
@@ -12,6 +12,11 @@ export interface StrategySource {
12
12
  value: string;
13
13
  field: string;
14
14
  }
15
+ export interface SourceDocumentRef {
16
+ field_label: string;
17
+ value_display: string;
18
+ source_hint: string;
19
+ }
15
20
  export interface StrategyTraceStep {
16
21
  n: number;
17
22
  step: string;
@@ -38,14 +43,18 @@ export interface Strategy {
38
43
  needsOwnerComp?: boolean;
39
44
  clientBrief?: string;
40
45
  action?: string;
46
+ abstract?: string;
41
47
  authority?: string;
42
48
  forms?: string;
43
49
  warning?: string | null;
44
- abstract?: string;
45
50
  sources?: StrategySource[];
46
51
  trace?: StrategyTraceStep[];
47
52
  cost?: string;
48
53
  timelineBucket?: string;
54
+ sourceDocuments?: SourceDocumentRef[];
55
+ quickWin?: boolean;
56
+ positionStrength?: string;
57
+ specialistNote?: string;
49
58
  }
50
59
  export interface ClientProfile {
51
60
  bizName: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paro.io/expert-shared-components",
3
- "version": "1.14.53",
3
+ "version": "1.14.55",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {