mrvn-cli 0.5.24 → 0.5.25

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.
@@ -20841,20 +20841,38 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
20841
20841
  }
20842
20842
  }
20843
20843
  if (options.applyUpdates) {
20844
- const assessmentSummary = buildAssessmentSummary(
20844
+ const newEntry = buildAssessmentSummary(
20845
20845
  commentSummary,
20846
20846
  commentAnalysisProgress,
20847
20847
  signals,
20848
20848
  children,
20849
20849
  linkedIssues
20850
20850
  );
20851
+ const existingHistory = Array.isArray(fm.assessmentHistory) ? fm.assessmentHistory : [];
20852
+ const legacySummary = fm.assessmentSummary;
20853
+ const allEntries = [newEntry, ...existingHistory];
20854
+ if (legacySummary?.generatedAt) {
20855
+ allEntries.push(legacySummary);
20856
+ }
20857
+ const MAX_HISTORY = 100;
20858
+ const seen = /* @__PURE__ */ new Set();
20859
+ const assessmentHistory = allEntries.filter((entry) => {
20860
+ if (!entry.generatedAt) return false;
20861
+ if (seen.has(entry.generatedAt)) return false;
20862
+ seen.add(entry.generatedAt);
20863
+ return true;
20864
+ }).sort((a, b) => (b.generatedAt ?? "").localeCompare(a.generatedAt ?? "")).slice(0, MAX_HISTORY);
20851
20865
  try {
20852
- store.update(fm.id, {
20853
- assessmentSummary,
20854
- lastAssessedAt: assessmentSummary.generatedAt
20855
- });
20866
+ const payload = {
20867
+ assessmentHistory,
20868
+ lastAssessedAt: newEntry.generatedAt
20869
+ };
20870
+ if (fm.assessmentSummary !== void 0) {
20871
+ payload.assessmentSummary = void 0;
20872
+ }
20873
+ store.update(fm.id, payload);
20856
20874
  } catch (err) {
20857
- errors.push(`Failed to persist assessment summary: ${err instanceof Error ? err.message : String(err)}`);
20875
+ errors.push(`Failed to persist assessment history: ${err instanceof Error ? err.message : String(err)}`);
20858
20876
  }
20859
20877
  }
20860
20878
  return {
@@ -22981,8 +22999,30 @@ function inline(text) {
22981
22999
  s = s.replace(/__([^_]+)__/g, "<strong>$1</strong>");
22982
23000
  s = s.replace(/\*([^*]+)\*/g, "<em>$1</em>");
22983
23001
  s = s.replace(/_([^_]+)_/g, "<em>$1</em>");
23002
+ s = linkArtifactIds(s);
22984
23003
  return s;
22985
23004
  }
23005
+ var ID_PREFIX_TO_TYPE = (() => {
23006
+ const entries = [];
23007
+ for (const [type, prefix] of Object.entries(CORE_ID_PREFIXES)) {
23008
+ entries.push([prefix, type]);
23009
+ }
23010
+ for (const reg of COMMON_REGISTRATIONS) {
23011
+ if (!entries.some(([p]) => p === reg.idPrefix)) {
23012
+ entries.push([reg.idPrefix, reg.type]);
23013
+ }
23014
+ }
23015
+ entries.sort((a, b) => b[0].length - a[0].length);
23016
+ return new Map(entries);
23017
+ })();
23018
+ function linkArtifactIds(html) {
23019
+ return html.replace(/\b([A-Z]{1,3})-(\d{3,})\b/g, (match, prefix, num) => {
23020
+ const type = ID_PREFIX_TO_TYPE.get(prefix);
23021
+ if (!type) return match;
23022
+ const id = `${prefix}-${num}`;
23023
+ return `<a href="/docs/${type}/${id}" class="artifact-link">${match}</a>`;
23024
+ });
23025
+ }
22986
23026
  function layout(opts, body) {
22987
23027
  const switcherHtml = opts.personaSwitcherHtml ?? "";
22988
23028
  let navHtml;
@@ -23694,6 +23734,75 @@ tr:hover td {
23694
23734
  margin: 0.75rem 0;
23695
23735
  }
23696
23736
 
23737
+ /* Artifact cross-links */
23738
+ a.artifact-link {
23739
+ color: var(--accent);
23740
+ text-decoration: none;
23741
+ font-weight: 500;
23742
+ border-bottom: 1px dotted var(--accent);
23743
+ }
23744
+ a.artifact-link:hover {
23745
+ border-bottom-style: solid;
23746
+ }
23747
+
23748
+ /* Assessment timeline */
23749
+ .assessment-timeline {
23750
+ margin-top: 1.5rem;
23751
+ }
23752
+ .assessment-timeline h3 {
23753
+ font-size: 1rem;
23754
+ font-weight: 600;
23755
+ margin-bottom: 0.75rem;
23756
+ }
23757
+ .assessment-entry {
23758
+ background: var(--bg-card);
23759
+ border: 1px solid var(--border);
23760
+ border-radius: var(--radius);
23761
+ padding: 0.75rem 1rem;
23762
+ margin-bottom: 0.75rem;
23763
+ }
23764
+ .assessment-entry.assessment-latest {
23765
+ border-left: 3px solid var(--accent);
23766
+ }
23767
+ .assessment-header {
23768
+ display: flex;
23769
+ align-items: center;
23770
+ gap: 0.5rem;
23771
+ margin-bottom: 0.5rem;
23772
+ }
23773
+ .assessment-date {
23774
+ font-size: 0.8rem;
23775
+ color: var(--text-dim);
23776
+ font-family: var(--mono);
23777
+ }
23778
+ .assessment-comment {
23779
+ font-size: 0.875rem;
23780
+ line-height: 1.6;
23781
+ margin-bottom: 0.5rem;
23782
+ }
23783
+ .assessment-stat {
23784
+ font-size: 0.8rem;
23785
+ color: var(--text-dim);
23786
+ margin-bottom: 0.25rem;
23787
+ }
23788
+ .assessment-stat strong {
23789
+ color: var(--text);
23790
+ }
23791
+ .assessment-signals {
23792
+ list-style: none;
23793
+ padding: 0;
23794
+ margin: 0.5rem 0 0;
23795
+ }
23796
+ .assessment-signals li {
23797
+ font-size: 0.8rem;
23798
+ padding: 0.15rem 0;
23799
+ }
23800
+ .progress-bar-inline {
23801
+ font-family: var(--mono);
23802
+ font-size: 0.75rem;
23803
+ letter-spacing: -0.5px;
23804
+ }
23805
+
23697
23806
  /* Filters */
23698
23807
  .filters {
23699
23808
  display: flex;
@@ -24858,23 +24967,33 @@ function documentsPage(data) {
24858
24967
  function documentDetailPage(doc) {
24859
24968
  const fm = doc.frontmatter;
24860
24969
  const label = typeLabel(fm.type);
24861
- const skipKeys = /* @__PURE__ */ new Set(["title", "type"]);
24970
+ const skipKeys = /* @__PURE__ */ new Set(["title", "type", "assessmentHistory", "assessmentSummary"]);
24862
24971
  const entries = Object.entries(fm).filter(
24863
- ([key]) => !skipKeys.has(key) && fm[key] != null
24972
+ ([key, value]) => !skipKeys.has(key) && value != null && typeof value !== "object"
24973
+ );
24974
+ const arrayEntries = Object.entries(fm).filter(
24975
+ ([key, value]) => !skipKeys.has(key) && Array.isArray(value) && value.every((v) => typeof v === "string")
24864
24976
  );
24865
- const dtDd = entries.map(([key, value]) => {
24977
+ const allEntries = [
24978
+ ...entries.filter(([, v]) => !Array.isArray(v)),
24979
+ ...arrayEntries
24980
+ ];
24981
+ const dtDd = allEntries.map(([key, value]) => {
24866
24982
  let rendered;
24867
24983
  if (key === "status") {
24868
24984
  rendered = statusBadge(value);
24869
24985
  } else if (key === "tags" && Array.isArray(value)) {
24870
24986
  rendered = value.map((t) => `<span class="badge badge-default">${escapeHtml(t)}</span>`).join(" ");
24871
- } else if (key === "created" || key === "updated") {
24987
+ } else if (key === "created" || key === "updated" || key === "lastAssessedAt" || key === "lastJiraSyncAt") {
24872
24988
  rendered = formatDate(value);
24873
24989
  } else {
24874
- rendered = escapeHtml(String(value));
24990
+ rendered = linkArtifactIds(escapeHtml(String(value)));
24875
24991
  }
24876
24992
  return `<dt>${escapeHtml(key)}</dt><dd>${rendered}</dd>`;
24877
24993
  }).join("\n ");
24994
+ const rawHistory = Array.isArray(fm.assessmentHistory) ? fm.assessmentHistory : fm.assessmentSummary && typeof fm.assessmentSummary === "object" ? [fm.assessmentSummary] : [];
24995
+ const assessmentHistory = rawHistory.filter(isValidAssessmentEntry).sort((a, b) => (b.generatedAt ?? "").localeCompare(a.generatedAt ?? ""));
24996
+ const timelineHtml = assessmentHistory.length > 0 ? renderAssessmentTimeline(assessmentHistory) : "";
24878
24997
  return `
24879
24998
  <div class="breadcrumb">
24880
24999
  <a href="/">Overview</a><span class="sep">/</span>
@@ -24894,8 +25013,73 @@ function documentDetailPage(doc) {
24894
25013
  </div>
24895
25014
 
24896
25015
  ${doc.content.trim() ? `<div class="detail-content">${renderMarkdown(doc.content)}</div>` : ""}
25016
+
25017
+ ${timelineHtml}
24897
25018
  `;
24898
25019
  }
25020
+ function isValidAssessmentEntry(value) {
25021
+ if (typeof value !== "object" || value === null) return false;
25022
+ const obj = value;
25023
+ if (typeof obj.generatedAt !== "string") return false;
25024
+ if (obj.signals !== void 0 && !Array.isArray(obj.signals)) return false;
25025
+ return true;
25026
+ }
25027
+ function normalizeEntry(entry) {
25028
+ return {
25029
+ generatedAt: entry.generatedAt ?? "",
25030
+ commentSummary: typeof entry.commentSummary === "string" ? entry.commentSummary : null,
25031
+ commentAnalysisProgress: typeof entry.commentAnalysisProgress === "number" ? entry.commentAnalysisProgress : null,
25032
+ signals: Array.isArray(entry.signals) ? entry.signals.filter((s) => typeof s === "string") : [],
25033
+ childCount: typeof entry.childCount === "number" ? entry.childCount : 0,
25034
+ childDoneCount: typeof entry.childDoneCount === "number" ? entry.childDoneCount : 0,
25035
+ childRollupProgress: typeof entry.childRollupProgress === "number" ? entry.childRollupProgress : null,
25036
+ linkedIssueCount: typeof entry.linkedIssueCount === "number" ? entry.linkedIssueCount : 0
25037
+ };
25038
+ }
25039
+ function renderAssessmentTimeline(history) {
25040
+ const entries = history.map((raw, i) => {
25041
+ const entry = normalizeEntry(raw);
25042
+ const date5 = entry.generatedAt ? formatDate(entry.generatedAt) : "Unknown date";
25043
+ const time3 = entry.generatedAt?.slice(11, 16) ?? "";
25044
+ const isLatest = i === 0;
25045
+ const parts = [];
25046
+ if (entry.commentSummary) {
25047
+ parts.push(`<div class="assessment-comment">${linkArtifactIds(escapeHtml(entry.commentSummary))}</div>`);
25048
+ }
25049
+ if (entry.commentAnalysisProgress !== null) {
25050
+ parts.push(`<div class="assessment-stat">\u{1F4CA} Comment-derived progress: <strong>${entry.commentAnalysisProgress}%</strong></div>`);
25051
+ }
25052
+ if (entry.childCount > 0) {
25053
+ const bar = progressBarHtml(entry.childRollupProgress ?? 0);
25054
+ parts.push(`<div class="assessment-stat">\u{1F476} Children: ${entry.childDoneCount}/${entry.childCount} done ${bar} ${entry.childRollupProgress ?? 0}%</div>`);
25055
+ }
25056
+ if (entry.linkedIssueCount > 0) {
25057
+ parts.push(`<div class="assessment-stat">\u{1F517} Linked issues: ${entry.linkedIssueCount}</div>`);
25058
+ }
25059
+ if (entry.signals.length > 0) {
25060
+ const signalItems = entry.signals.map((s) => `<li>${linkArtifactIds(escapeHtml(s))}</li>`).join("");
25061
+ parts.push(`<ul class="assessment-signals">${signalItems}</ul>`);
25062
+ }
25063
+ return `
25064
+ <div class="assessment-entry${isLatest ? " assessment-latest" : ""}">
25065
+ <div class="assessment-header">
25066
+ <span class="assessment-date">${escapeHtml(date5)} ${escapeHtml(time3)}</span>
25067
+ ${isLatest ? '<span class="badge badge-default">Latest</span>' : ""}
25068
+ </div>
25069
+ ${parts.join("\n")}
25070
+ </div>`;
25071
+ });
25072
+ return `
25073
+ <div class="assessment-timeline">
25074
+ <h3>Assessment History</h3>
25075
+ ${entries.join("\n")}
25076
+ </div>`;
25077
+ }
25078
+ function progressBarHtml(pct) {
25079
+ const filled = Math.round(Math.max(0, Math.min(100, pct)) / 10);
25080
+ const empty = 10 - filled;
25081
+ return `<span class="progress-bar-inline">${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}</span>`;
25082
+ }
24899
25083
 
24900
25084
  // src/web/persona-views.ts
24901
25085
  var VIEWS = /* @__PURE__ */ new Map();