pxengine 0.1.104 → 0.1.106

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/dist/index.cjs CHANGED
@@ -38701,27 +38701,39 @@ function normalizeConfidence(c) {
38701
38701
  if (v.startsWith("l")) return "Low";
38702
38702
  return void 0;
38703
38703
  }
38704
+ function coerceItem(it, cardConfidence) {
38705
+ if (typeof it === "string") {
38706
+ const idx = it.indexOf(":");
38707
+ if (idx > 0 && idx < 60) {
38708
+ return {
38709
+ label: it.slice(0, idx).trim(),
38710
+ value: it.slice(idx + 1).trim(),
38711
+ confidence: normalizeConfidence(cardConfidence)
38712
+ };
38713
+ }
38714
+ return { label: it, value: "", confidence: normalizeConfidence(cardConfidence) };
38715
+ }
38716
+ return {
38717
+ label: it?.label ?? it?.finding ?? it?.metric ?? it?.title ?? it?.insight ?? "",
38718
+ value: it?.value ?? it?.data_point ?? it?.detail ?? it?.description ?? "",
38719
+ confidence: normalizeConfidence(it?.confidence ?? cardConfidence)
38720
+ };
38721
+ }
38704
38722
  function resolveItems(props) {
38705
38723
  const cardConfidence = props.confidence;
38706
- if (Array.isArray(props.insights) && props.insights.length > 0) {
38707
- return props.insights.map((it) => ({
38708
- label: it?.label ?? "",
38709
- value: it?.value ?? "",
38710
- confidence: normalizeConfidence(it?.confidence ?? cardConfidence)
38711
- }));
38712
- }
38713
- if (Array.isArray(props.key_findings) && props.key_findings.length > 0) {
38714
- return props.key_findings.map((f) => ({
38715
- label: f?.finding ?? f?.label ?? "",
38716
- value: f?.data_point ?? f?.value ?? "",
38717
- confidence: normalizeConfidence(f?.confidence ?? cardConfidence)
38718
- }));
38719
- }
38720
- return [];
38724
+ const source = [
38725
+ props.insights,
38726
+ props.key_findings,
38727
+ props.key_insights,
38728
+ props.findings,
38729
+ props.items
38730
+ ].find((a) => Array.isArray(a) && a.length > 0);
38731
+ if (!source) return [];
38732
+ return source.map((it) => coerceItem(it, cardConfidence));
38721
38733
  }
38722
38734
  var InsightSummaryCard = (props) => {
38723
38735
  const { title, className } = props;
38724
- const summary = props.summary ?? props.executive_summary;
38736
+ const summary = props.summary ?? props.executive_summary ?? props.thesis ?? props.subtitle;
38725
38737
  const items = resolveItems(props);
38726
38738
  return /* @__PURE__ */ (0, import_jsx_runtime134.jsxs)(
38727
38739
  "div",
@@ -39289,7 +39301,7 @@ var ExportModal = ({ formats, title, onClose }) => {
39289
39301
  );
39290
39302
  })
39291
39303
  ] }),
39292
- /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("p", { className: "text-xs text-zinc-600 mt-4 text-center", children: "Download links expire in 7 days" })
39304
+ /* @__PURE__ */ (0, import_jsx_runtime147.jsx)("p", { className: "text-xs text-zinc-600 mt-4 text-center", children: "Download links expire in 90 days" })
39293
39305
  ] })
39294
39306
  ] });
39295
39307
  };
@@ -39859,6 +39871,19 @@ var ExpandIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg", {
39859
39871
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
39860
39872
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
39861
39873
  ] });
39874
+ var ShareIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
39875
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
39876
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
39877
+ ] });
39878
+ var CheckIcon2 = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("polyline", { points: "20 6 9 17 4 12" }) });
39879
+ var RefreshIcon = () => /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: [
39880
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("polyline", { points: "23 4 23 10 17 10" }),
39881
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("path", { d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10" })
39882
+ ] });
39883
+ function formatTemplateLabel(templateId) {
39884
+ if (!templateId) return null;
39885
+ return templateId.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
39886
+ }
39862
39887
  var FullscreenPreviewModal = ({ url, title, onClose }) => {
39863
39888
  (0, import_react78.useEffect)(() => {
39864
39889
  const onKey = (e) => {
@@ -39904,7 +39929,7 @@ var FullscreenPreviewModal = ({ url, title, onClose }) => {
39904
39929
  };
39905
39930
  var ResearchReportJobCard = (props) => {
39906
39931
  const {
39907
- job_id: _job_id,
39932
+ job_id,
39908
39933
  title: initialTitle,
39909
39934
  status: initialStatus,
39910
39935
  topic: _initialTopic,
@@ -39915,11 +39940,18 @@ var ResearchReportJobCard = (props) => {
39915
39940
  executive_summary: initialSummary,
39916
39941
  key_findings: _initialFindings,
39917
39942
  html_url: initialHtmlUrl,
39943
+ generation_mode: initialGenerationMode,
39944
+ template_id: initialTemplateId,
39945
+ template_version_id: initialTemplateVersionId,
39946
+ review_status: initialReviewStatus,
39918
39947
  theme: initialTheme,
39919
39948
  error: initialError,
39920
39949
  progress: initialProgress,
39921
39950
  pollUrl,
39922
39951
  authToken,
39952
+ shareUrl,
39953
+ approveUrl,
39954
+ regenerateUrl,
39923
39955
  className,
39924
39956
  onComplete,
39925
39957
  onFailed,
@@ -39934,11 +39966,23 @@ var ResearchReportJobCard = (props) => {
39934
39966
  const [wordCount, setWordCount] = (0, import_react78.useState)(initialWordCount ?? 0);
39935
39967
  const [summary, setSummary] = (0, import_react78.useState)(initialSummary || "");
39936
39968
  const [htmlUrl, setHtmlUrl] = (0, import_react78.useState)(initialHtmlUrl || "");
39969
+ const [generationMode, setGenerationMode] = (0, import_react78.useState)(
39970
+ initialGenerationMode || (initialHtmlUrl ? "template" : "")
39971
+ );
39972
+ const [templateId, setTemplateId] = (0, import_react78.useState)(initialTemplateId || "");
39973
+ const [templateVersionId, setTemplateVersionId] = (0, import_react78.useState)(initialTemplateVersionId || "");
39974
+ const [reviewStatus, setReviewStatus] = (0, import_react78.useState)(
39975
+ initialReviewStatus || (initialHtmlUrl ? "pending_review" : "")
39976
+ );
39937
39977
  const [theme, setTheme] = (0, import_react78.useState)(initialTheme || DEFAULT_THEME);
39938
39978
  const [error, setError] = (0, import_react78.useState)(initialError);
39939
39979
  const [progress, setProgress] = (0, import_react78.useState)(initialProgress);
39940
39980
  const [showPreview, setShowPreview] = (0, import_react78.useState)(false);
39941
39981
  const [previewScale, setPreviewScale] = (0, import_react78.useState)(1);
39982
+ const [copied, setCopied] = (0, import_react78.useState)(false);
39983
+ const [approving, setApproving] = (0, import_react78.useState)(false);
39984
+ const [regenerating, setRegenerating] = (0, import_react78.useState)(false);
39985
+ const [approveError, setApproveError] = (0, import_react78.useState)(null);
39942
39986
  const previewRef = (0, import_react78.useRef)(null);
39943
39987
  const intervalRef = (0, import_react78.useRef)(null);
39944
39988
  const onCompleteRef = (0, import_react78.useRef)(onComplete);
@@ -39956,6 +40000,18 @@ var ResearchReportJobCard = (props) => {
39956
40000
  (0, import_react78.useEffect)(() => {
39957
40001
  if (initialHtmlUrl) setHtmlUrl(initialHtmlUrl);
39958
40002
  }, [initialHtmlUrl]);
40003
+ (0, import_react78.useEffect)(() => {
40004
+ if (initialGenerationMode) setGenerationMode(initialGenerationMode);
40005
+ }, [initialGenerationMode]);
40006
+ (0, import_react78.useEffect)(() => {
40007
+ if (initialTemplateId) setTemplateId(initialTemplateId);
40008
+ }, [initialTemplateId]);
40009
+ (0, import_react78.useEffect)(() => {
40010
+ if (initialTemplateVersionId) setTemplateVersionId(initialTemplateVersionId);
40011
+ }, [initialTemplateVersionId]);
40012
+ (0, import_react78.useEffect)(() => {
40013
+ if (initialReviewStatus) setReviewStatus(initialReviewStatus);
40014
+ }, [initialReviewStatus]);
39959
40015
  (0, import_react78.useEffect)(() => {
39960
40016
  if (initialDepth) setDepth(initialDepth);
39961
40017
  }, [initialDepth]);
@@ -40023,6 +40079,10 @@ var ResearchReportJobCard = (props) => {
40023
40079
  setWordCount(output.word_count || 0);
40024
40080
  setSummary(output.executive_summary || "");
40025
40081
  setHtmlUrl(output.html_url || "");
40082
+ if (output.generation_mode) setGenerationMode(output.generation_mode);
40083
+ if (output.template_id) setTemplateId(output.template_id);
40084
+ if (output.template_version_id) setTemplateVersionId(output.template_version_id);
40085
+ if (output.review_status) setReviewStatus(output.review_status);
40026
40086
  if (output.theme) {
40027
40087
  setTheme(output.theme);
40028
40088
  }
@@ -40204,6 +40264,120 @@ var ResearchReportJobCard = (props) => {
40204
40264
  window.open(htmlUrl, "_blank", "noopener,noreferrer");
40205
40265
  }
40206
40266
  };
40267
+ const resolveShareLink = () => {
40268
+ if (shareUrl) return shareUrl;
40269
+ if (typeof window !== "undefined" && job_id) {
40270
+ return `${window.location.origin}/r/${job_id}`;
40271
+ }
40272
+ return htmlUrl;
40273
+ };
40274
+ const handleShare = async () => {
40275
+ const link = resolveShareLink();
40276
+ if (!link) return;
40277
+ try {
40278
+ await navigator.clipboard.writeText(link);
40279
+ setCopied(true);
40280
+ setTimeout(() => setCopied(false), 2e3);
40281
+ } catch {
40282
+ window.open(link, "_blank", "noopener,noreferrer");
40283
+ }
40284
+ };
40285
+ const canApprove = generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
40286
+ const canRegenerate = generationMode === "template" && reviewStatus === "pending_review" && Boolean(job_id);
40287
+ const canShare = Boolean(hasHTML || job_id) && (generationMode !== "template" || reviewStatus !== "pending_review");
40288
+ const handleApprove = async () => {
40289
+ if (!job_id || approving) return;
40290
+ const endpoint = approveUrl || `/api/reports/${job_id}/approve`;
40291
+ setApproving(true);
40292
+ setApproveError(null);
40293
+ try {
40294
+ const headers = { "Content-Type": "application/json" };
40295
+ if (authToken) headers.Authorization = `Bearer ${authToken}`;
40296
+ const res = await fetch(endpoint, {
40297
+ method: "POST",
40298
+ headers,
40299
+ body: JSON.stringify({ label: title })
40300
+ });
40301
+ if (!res.ok) {
40302
+ const err = await res.json().catch(() => ({}));
40303
+ throw new Error(err.detail || err.error || `Approve failed (${res.status})`);
40304
+ }
40305
+ const data = await res.json();
40306
+ const newStatus = data.review_status || "approved";
40307
+ setReviewStatus(newStatus);
40308
+ if (data.template_version_id) setTemplateVersionId(data.template_version_id);
40309
+ if (data.template_id) setTemplateId(data.template_id);
40310
+ if (onCompleteRef.current) {
40311
+ onCompleteRef.current({
40312
+ title,
40313
+ depth,
40314
+ section_count: sectionCount,
40315
+ source_count: sourceCount,
40316
+ word_count: wordCount,
40317
+ executive_summary: summary,
40318
+ html_url: htmlUrl,
40319
+ generation_mode: generationMode,
40320
+ template_id: data.template_id || templateId,
40321
+ template_version_id: data.template_version_id || templateVersionId,
40322
+ review_status: newStatus,
40323
+ theme
40324
+ });
40325
+ }
40326
+ } catch (e) {
40327
+ setApproveError(e instanceof Error ? e.message : "Could not save report version");
40328
+ } finally {
40329
+ setApproving(false);
40330
+ }
40331
+ };
40332
+ const handleRegenerate = async () => {
40333
+ if (!job_id || regenerating) return;
40334
+ const endpoint = regenerateUrl || `/api/reports/${job_id}/regenerate`;
40335
+ setRegenerating(true);
40336
+ setApproveError(null);
40337
+ try {
40338
+ const headers = { "Content-Type": "application/json" };
40339
+ if (authToken) headers.Authorization = `Bearer ${authToken}`;
40340
+ const res = await fetch(endpoint, {
40341
+ method: "POST",
40342
+ headers,
40343
+ body: JSON.stringify({})
40344
+ });
40345
+ if (!res.ok) {
40346
+ const err = await res.json().catch(() => ({}));
40347
+ throw new Error(err.detail || err.error || `Regenerate failed (${res.status})`);
40348
+ }
40349
+ const data = await res.json();
40350
+ const out = data.output || data;
40351
+ if (out.html_url) setHtmlUrl(out.html_url);
40352
+ if (data.template_id || out.template_id) setTemplateId(data.template_id || out.template_id);
40353
+ setReviewStatus("pending_review");
40354
+ setTemplateVersionId("");
40355
+ if (out.section_count !== void 0) setSectionCount(out.section_count);
40356
+ if (out.title) setTitle(out.title);
40357
+ if (onCompleteRef.current) {
40358
+ onCompleteRef.current({
40359
+ title: out.title || title,
40360
+ depth,
40361
+ section_count: out.section_count ?? sectionCount,
40362
+ source_count: sourceCount,
40363
+ word_count: wordCount,
40364
+ executive_summary: summary,
40365
+ html_url: out.html_url || htmlUrl,
40366
+ generation_mode: "template",
40367
+ template_id: data.template_id || out.template_id || templateId,
40368
+ template_version_id: void 0,
40369
+ review_status: "pending_review",
40370
+ theme
40371
+ });
40372
+ }
40373
+ } catch (e) {
40374
+ setApproveError(e instanceof Error ? e.message : "Could not switch template");
40375
+ } finally {
40376
+ setRegenerating(false);
40377
+ }
40378
+ };
40379
+ const templateLabel = formatTemplateLabel(templateId);
40380
+ const isApproved = reviewStatus === "approved";
40207
40381
  return /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(import_jsx_runtime148.Fragment, { children: [
40208
40382
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: cn("w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "bg-zinc-900 border border-zinc-800 rounded-2xl overflow-hidden", children: [
40209
40383
  /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
@@ -40237,10 +40411,53 @@ var ResearchReportJobCard = (props) => {
40237
40411
  depth && sectionCount > 0 && " \xB7 ",
40238
40412
  sectionCount > 0 && `${sectionCount} sections`,
40239
40413
  sourceCount > 0 && ` \xB7 ${sourceCount} sources`,
40240
- wordCount > 0 && ` \xB7 ${formatWordCount(wordCount)} words`
40241
- ] })
40414
+ wordCount > 0 && ` \xB7 ${formatWordCount(wordCount)} words`,
40415
+ templateLabel && ` \xB7 ${templateLabel}`
40416
+ ] }),
40417
+ generationMode === "template" && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "text-xs mt-1", children: isApproved ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-emerald-400/90", children: "Approved \u2014 future reports use this format" }) : reviewStatus === "pending_review" ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "text-amber-400/90", children: "Review this report, then approve to lock the layout" }) : null })
40242
40418
  ] }),
40243
- /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center gap-1.5 flex-shrink-0", children: [
40419
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)("div", { className: "flex items-center gap-1.5 flex-shrink-0 flex-wrap justify-end", children: [
40420
+ canRegenerate && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
40421
+ "button",
40422
+ {
40423
+ onClick: handleRegenerate,
40424
+ disabled: regenerating || approving,
40425
+ title: "Try another report template with the same data",
40426
+ className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-zinc-700 bg-zinc-800 hover:border-zinc-500 text-zinc-300 text-xs font-medium transition-colors disabled:opacity-50",
40427
+ children: [
40428
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(RefreshIcon, {}),
40429
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: regenerating ? "Switching..." : "Regenerate" })
40430
+ ]
40431
+ }
40432
+ ),
40433
+ canApprove && /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
40434
+ "button",
40435
+ {
40436
+ onClick: handleApprove,
40437
+ disabled: approving,
40438
+ title: "Approve and save this report format for future runs",
40439
+ className: "flex items-center gap-1.5 px-2.5 h-7 rounded-lg border border-emerald-700/50 bg-emerald-950/40 hover:border-emerald-500 text-emerald-300 text-xs font-medium transition-colors disabled:opacity-50",
40440
+ children: [
40441
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}),
40442
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { children: approving ? "Saving..." : "Approve" })
40443
+ ]
40444
+ }
40445
+ ),
40446
+ isApproved && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("span", { className: "flex items-center justify-center w-7 h-7 rounded-lg border border-emerald-500/40 bg-emerald-500/10 text-emerald-400", title: "Format saved", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}) }),
40447
+ /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(
40448
+ "button",
40449
+ {
40450
+ onClick: handleShare,
40451
+ disabled: !canShare,
40452
+ title: !canShare && reviewStatus === "pending_review" ? "Approve the report to enable sharing" : copied ? "Copied!" : "Copy shareable link",
40453
+ className: cn(
40454
+ "w-7 h-7 rounded-lg border flex items-center justify-center transition-all",
40455
+ copied ? "border-green-500/40 bg-green-500/10 text-green-400" : "border-zinc-700 bg-zinc-800 text-zinc-400 hover:border-zinc-500 hover:text-zinc-200",
40456
+ "disabled:opacity-30 disabled:cursor-not-allowed"
40457
+ ),
40458
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(CheckIcon2, {}) : /* @__PURE__ */ (0, import_jsx_runtime148.jsx)(ShareIcon2, {})
40459
+ }
40460
+ ),
40244
40461
  /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
40245
40462
  "button",
40246
40463
  {
@@ -40271,6 +40488,7 @@ var ResearchReportJobCard = (props) => {
40271
40488
  )
40272
40489
  ] })
40273
40490
  ] }),
40491
+ approveError && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("p", { className: "mt-3 text-xs text-red-400/90", children: approveError }),
40274
40492
  hasHTML && !compact && /* @__PURE__ */ (0, import_jsx_runtime148.jsx)("div", { className: "mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime148.jsxs)(
40275
40493
  "div",
40276
40494
  {
@@ -43744,7 +43962,7 @@ function PlatformMetricsBanner({
43744
43962
  return /* @__PURE__ */ (0, import_jsx_runtime173.jsxs)(
43745
43963
  "div",
43746
43964
  {
43747
- className: "\n grid grid-cols-1 gap-3 rounded-xl py-4 px-4 shadow-sm\n md:flex md:overflow-x-auto md:gap-6 md:rounded-l-xl md:py-4 md:px-4 md:items-center md:gap-0 md:px-0 md:ml-8\n ",
43965
+ className: "\r\n grid grid-cols-1 gap-3 rounded-xl py-4 px-4 shadow-sm\r\n md:flex md:overflow-x-auto md:gap-6 md:rounded-l-xl md:py-4 md:px-4 md:items-center md:gap-0 md:px-0 md:ml-8\r\n ",
43748
43966
  style: { backgroundColor: bgColor },
43749
43967
  children: [
43750
43968
  /* @__PURE__ */ (0, import_jsx_runtime173.jsxs)("div", { className: "flex flex-col items-center md:min-w-0", children: [