mrvn-cli 0.5.22 → 0.5.23

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.js CHANGED
@@ -26697,11 +26697,12 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
26697
26697
  }
26698
26698
  }
26699
26699
  const primaryHasComments = jiraKey ? (jiraIssues.get(jiraKey)?.comments.length ?? 0) > 0 : false;
26700
+ let commentAnalysisProgress = null;
26700
26701
  if (depth < MAX_LLM_DEPTH && jiraKey && primaryHasComments) {
26701
26702
  const estimatedChars = estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignals);
26702
26703
  if (estimatedChars <= MAX_LLM_COMMENT_CHARS) {
26703
26704
  try {
26704
- const summary = await analyzeSingleArtifactComments(
26705
+ const analysis = await analyzeSingleArtifactComments(
26705
26706
  fm.id,
26706
26707
  fm.title,
26707
26708
  jiraKey,
@@ -26710,7 +26711,20 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
26710
26711
  linkedJiraIssues,
26711
26712
  linkedIssueSignals
26712
26713
  );
26713
- commentSummary = summary;
26714
+ commentSummary = analysis.summary;
26715
+ commentAnalysisProgress = analysis.progressEstimate;
26716
+ if (commentAnalysisProgress !== null) {
26717
+ const hasExplicitProgress = "progress" in fm && typeof fm.progress === "number";
26718
+ if (!hasExplicitProgress && !fm.progressOverride && commentAnalysisProgress !== currentProgress) {
26719
+ proposedUpdates.push({
26720
+ artifactId: fm.id,
26721
+ field: "progress",
26722
+ currentValue: currentProgress,
26723
+ proposedValue: commentAnalysisProgress,
26724
+ reason: `Comment analysis estimates ${commentAnalysisProgress}% progress`
26725
+ });
26726
+ }
26727
+ }
26714
26728
  } catch (err) {
26715
26729
  errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
26716
26730
  }
@@ -26808,6 +26822,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
26808
26822
  progressDrift,
26809
26823
  commentSignals,
26810
26824
  commentSummary,
26825
+ commentAnalysisProgress,
26811
26826
  linkedIssues,
26812
26827
  linkedIssueSignals,
26813
26828
  children,
@@ -26900,13 +26915,15 @@ function estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignal
26900
26915
  }
26901
26916
  var SINGLE_ARTIFACT_COMMENT_PROMPT = `You are a delivery management assistant analyzing Jira comments for a single work item.
26902
26917
 
26903
- Produce a 2-3 sentence progress summary covering:
26904
- - What work has been completed
26905
- - What is pending or blocked
26906
- - Any decisions, handoffs, or scheduling mentioned
26907
- - Relevant context from linked issue comments (if provided)
26918
+ Analyze the comments and produce:
26919
+ 1. A 2-3 sentence progress summary covering: what work has been completed, what is pending or blocked, any decisions/handoffs/scheduling mentioned, and relevant context from linked issue comments (if provided).
26920
+ 2. A progress estimate (0-100%) based on evidence in the comments \u2014 e.g., if comments indicate all items have been triaged into tasks, or implementation is complete pending review, estimate accordingly. If you cannot determine progress from the comments, set progressEstimate to null.
26908
26921
 
26909
- Return ONLY the summary text, no JSON or formatting.`;
26922
+ Return a JSON object with this exact structure:
26923
+ {"summary": "your 2-3 sentence summary", "progressEstimate": 75}
26924
+
26925
+ Use null for progressEstimate if the comments don't provide enough evidence to estimate.
26926
+ IMPORTANT: Only return the JSON object, no other text.`;
26910
26927
  async function analyzeSingleArtifactComments(artifactId, title, jiraKey, jiraStatus, jiraIssues, linkedJiraIssues, linkedIssueSignals) {
26911
26928
  const promptParts = [];
26912
26929
  const primaryData = jiraIssues.get(jiraKey);
@@ -26929,7 +26946,7 @@ ${commentTexts}`);
26929
26946
  promptParts.push(`### Linked: ${signal.sourceKey} (${signal.linkType})
26930
26947
  ${commentTexts}`);
26931
26948
  }
26932
- if (promptParts.length === 0) return null;
26949
+ if (promptParts.length === 0) return { summary: null, progressEstimate: null };
26933
26950
  const prompt = promptParts.join("\n\n");
26934
26951
  const result = query3({
26935
26952
  prompt,
@@ -26946,11 +26963,25 @@ ${commentTexts}`);
26946
26963
  (b) => b.type === "text"
26947
26964
  );
26948
26965
  if (textBlock) {
26949
- return textBlock.text.trim();
26966
+ return parseCommentAnalysis(textBlock.text.trim());
26950
26967
  }
26951
26968
  }
26952
26969
  }
26953
- return null;
26970
+ return { summary: null, progressEstimate: null };
26971
+ }
26972
+ function parseCommentAnalysis(text) {
26973
+ const parsed = parseLlmJson(text);
26974
+ if (parsed && typeof parsed.summary === "string") {
26975
+ const progressEstimate2 = typeof parsed.progressEstimate === "number" && parsed.progressEstimate >= 0 && parsed.progressEstimate <= 100 ? Math.round(parsed.progressEstimate) : null;
26976
+ return { summary: parsed.summary, progressEstimate: progressEstimate2 };
26977
+ }
26978
+ let progressEstimate = null;
26979
+ const pctMatch = text.match(/(\d{1,3})%/);
26980
+ if (pctMatch) {
26981
+ const pct = parseInt(pctMatch[1], 10);
26982
+ if (pct >= 0 && pct <= 100) progressEstimate = pct;
26983
+ }
26984
+ return { summary: text, progressEstimate };
26954
26985
  }
26955
26986
  function emptyArtifactReport(artifactId, errors) {
26956
26987
  return {
@@ -26970,6 +27001,7 @@ function emptyArtifactReport(artifactId, errors) {
26970
27001
  progressDrift: false,
26971
27002
  commentSignals: [],
26972
27003
  commentSummary: null,
27004
+ commentAnalysisProgress: null,
26973
27005
  linkedIssues: [],
26974
27006
  linkedIssueSignals: [],
26975
27007
  children: [],
@@ -27007,6 +27039,9 @@ function formatArtifactReport(report) {
27007
27039
  if (report.commentSummary) {
27008
27040
  parts.push(`## Comments`);
27009
27041
  parts.push(report.commentSummary);
27042
+ if (report.commentAnalysisProgress !== null) {
27043
+ parts.push(` \u{1F4CA} Comment-derived progress estimate: ${report.commentAnalysisProgress}%`);
27044
+ }
27010
27045
  parts.push("");
27011
27046
  }
27012
27047
  if (report.children.length > 0) {
@@ -33590,7 +33625,7 @@ function createProgram() {
33590
33625
  const program = new Command();
33591
33626
  program.name("marvin").description(
33592
33627
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
33593
- ).version("0.5.22");
33628
+ ).version("0.5.23");
33594
33629
  program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
33595
33630
  await initCommand();
33596
33631
  });