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/marvin.js CHANGED
@@ -26943,11 +26943,12 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
26943
26943
  }
26944
26944
  }
26945
26945
  const primaryHasComments = jiraKey ? (jiraIssues.get(jiraKey)?.comments.length ?? 0) > 0 : false;
26946
+ let commentAnalysisProgress = null;
26946
26947
  if (depth < MAX_LLM_DEPTH && jiraKey && primaryHasComments) {
26947
26948
  const estimatedChars = estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignals);
26948
26949
  if (estimatedChars <= MAX_LLM_COMMENT_CHARS) {
26949
26950
  try {
26950
- const summary = await analyzeSingleArtifactComments(
26951
+ const analysis = await analyzeSingleArtifactComments(
26951
26952
  fm.id,
26952
26953
  fm.title,
26953
26954
  jiraKey,
@@ -26956,7 +26957,20 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
26956
26957
  linkedJiraIssues,
26957
26958
  linkedIssueSignals
26958
26959
  );
26959
- commentSummary = summary;
26960
+ commentSummary = analysis.summary;
26961
+ commentAnalysisProgress = analysis.progressEstimate;
26962
+ if (commentAnalysisProgress !== null) {
26963
+ const hasExplicitProgress = "progress" in fm && typeof fm.progress === "number";
26964
+ if (!hasExplicitProgress && !fm.progressOverride && commentAnalysisProgress !== currentProgress) {
26965
+ proposedUpdates.push({
26966
+ artifactId: fm.id,
26967
+ field: "progress",
26968
+ currentValue: currentProgress,
26969
+ proposedValue: commentAnalysisProgress,
26970
+ reason: `Comment analysis estimates ${commentAnalysisProgress}% progress`
26971
+ });
26972
+ }
26973
+ }
26960
26974
  } catch (err) {
26961
26975
  errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
26962
26976
  }
@@ -27054,6 +27068,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
27054
27068
  progressDrift,
27055
27069
  commentSignals,
27056
27070
  commentSummary,
27071
+ commentAnalysisProgress,
27057
27072
  linkedIssues,
27058
27073
  linkedIssueSignals,
27059
27074
  children,
@@ -27146,13 +27161,15 @@ function estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignal
27146
27161
  }
27147
27162
  var SINGLE_ARTIFACT_COMMENT_PROMPT = `You are a delivery management assistant analyzing Jira comments for a single work item.
27148
27163
 
27149
- Produce a 2-3 sentence progress summary covering:
27150
- - What work has been completed
27151
- - What is pending or blocked
27152
- - Any decisions, handoffs, or scheduling mentioned
27153
- - Relevant context from linked issue comments (if provided)
27164
+ Analyze the comments and produce:
27165
+ 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).
27166
+ 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.
27154
27167
 
27155
- Return ONLY the summary text, no JSON or formatting.`;
27168
+ Return a JSON object with this exact structure:
27169
+ {"summary": "your 2-3 sentence summary", "progressEstimate": 75}
27170
+
27171
+ Use null for progressEstimate if the comments don't provide enough evidence to estimate.
27172
+ IMPORTANT: Only return the JSON object, no other text.`;
27156
27173
  async function analyzeSingleArtifactComments(artifactId, title, jiraKey, jiraStatus, jiraIssues, linkedJiraIssues, linkedIssueSignals) {
27157
27174
  const promptParts = [];
27158
27175
  const primaryData = jiraIssues.get(jiraKey);
@@ -27175,7 +27192,7 @@ ${commentTexts}`);
27175
27192
  promptParts.push(`### Linked: ${signal.sourceKey} (${signal.linkType})
27176
27193
  ${commentTexts}`);
27177
27194
  }
27178
- if (promptParts.length === 0) return null;
27195
+ if (promptParts.length === 0) return { summary: null, progressEstimate: null };
27179
27196
  const prompt = promptParts.join("\n\n");
27180
27197
  const result = query3({
27181
27198
  prompt,
@@ -27192,11 +27209,25 @@ ${commentTexts}`);
27192
27209
  (b) => b.type === "text"
27193
27210
  );
27194
27211
  if (textBlock) {
27195
- return textBlock.text.trim();
27212
+ return parseCommentAnalysis(textBlock.text.trim());
27196
27213
  }
27197
27214
  }
27198
27215
  }
27199
- return null;
27216
+ return { summary: null, progressEstimate: null };
27217
+ }
27218
+ function parseCommentAnalysis(text) {
27219
+ const parsed = parseLlmJson(text);
27220
+ if (parsed && typeof parsed.summary === "string") {
27221
+ const progressEstimate2 = typeof parsed.progressEstimate === "number" && parsed.progressEstimate >= 0 && parsed.progressEstimate <= 100 ? Math.round(parsed.progressEstimate) : null;
27222
+ return { summary: parsed.summary, progressEstimate: progressEstimate2 };
27223
+ }
27224
+ let progressEstimate = null;
27225
+ const pctMatch = text.match(/(\d{1,3})%/);
27226
+ if (pctMatch) {
27227
+ const pct = parseInt(pctMatch[1], 10);
27228
+ if (pct >= 0 && pct <= 100) progressEstimate = pct;
27229
+ }
27230
+ return { summary: text, progressEstimate };
27200
27231
  }
27201
27232
  function emptyArtifactReport(artifactId, errors) {
27202
27233
  return {
@@ -27216,6 +27247,7 @@ function emptyArtifactReport(artifactId, errors) {
27216
27247
  progressDrift: false,
27217
27248
  commentSignals: [],
27218
27249
  commentSummary: null,
27250
+ commentAnalysisProgress: null,
27219
27251
  linkedIssues: [],
27220
27252
  linkedIssueSignals: [],
27221
27253
  children: [],
@@ -27253,6 +27285,9 @@ function formatArtifactReport(report) {
27253
27285
  if (report.commentSummary) {
27254
27286
  parts.push(`## Comments`);
27255
27287
  parts.push(report.commentSummary);
27288
+ if (report.commentAnalysisProgress !== null) {
27289
+ parts.push(` \u{1F4CA} Comment-derived progress estimate: ${report.commentAnalysisProgress}%`);
27290
+ }
27256
27291
  parts.push("");
27257
27292
  }
27258
27293
  if (report.children.length > 0) {
@@ -33582,7 +33617,7 @@ function createProgram() {
33582
33617
  const program2 = new Command();
33583
33618
  program2.name("marvin").description(
33584
33619
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
33585
- ).version("0.5.22");
33620
+ ).version("0.5.23");
33586
33621
  program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
33587
33622
  await initCommand();
33588
33623
  });