mrvn-cli 0.5.26 → 0.5.27

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
@@ -22430,7 +22430,10 @@ function normalizeEntry(entry) {
22430
22430
  childCount: typeof entry.childCount === "number" ? entry.childCount : 0,
22431
22431
  childDoneCount: typeof entry.childDoneCount === "number" ? entry.childDoneCount : 0,
22432
22432
  childRollupProgress: typeof entry.childRollupProgress === "number" ? entry.childRollupProgress : null,
22433
- linkedIssueCount: typeof entry.linkedIssueCount === "number" ? entry.linkedIssueCount : 0
22433
+ linkedIssueCount: typeof entry.linkedIssueCount === "number" ? entry.linkedIssueCount : 0,
22434
+ blockerProgress: typeof entry.blockerProgress === "number" ? entry.blockerProgress : null,
22435
+ totalBlockers: typeof entry.totalBlockers === "number" ? entry.totalBlockers : 0,
22436
+ resolvedBlockers: typeof entry.resolvedBlockers === "number" ? entry.resolvedBlockers : 0
22434
22437
  };
22435
22438
  }
22436
22439
  function renderAssessmentTimeline(history) {
@@ -22450,6 +22453,10 @@ function renderAssessmentTimeline(history) {
22450
22453
  const bar = progressBarHtml(entry.childRollupProgress ?? 0);
22451
22454
  parts.push(`<div class="assessment-stat">\u{1F476} Children: ${entry.childDoneCount}/${entry.childCount} done ${bar} ${entry.childRollupProgress ?? 0}%</div>`);
22452
22455
  }
22456
+ if (entry.totalBlockers > 0) {
22457
+ const bar = progressBarHtml(entry.blockerProgress ?? 0);
22458
+ parts.push(`<div class="assessment-stat">\u{1F6A7} Blockers: ${entry.resolvedBlockers}/${entry.totalBlockers} resolved ${bar} ${entry.blockerProgress ?? 0}%</div>`);
22459
+ }
22453
22460
  if (entry.linkedIssueCount > 0) {
22454
22461
  parts.push(`<div class="assessment-stat">\u{1F517} Linked issues: ${entry.linkedIssueCount}</div>`);
22455
22462
  }
@@ -27272,6 +27279,15 @@ function analyzeLinkedIssueSignals(linkedIssues, frontmatter, jiraKey, proposedU
27272
27279
  });
27273
27280
  }
27274
27281
  }
27282
+ function computeBlockerProgress(linkedIssues, prerequisiteWeight) {
27283
+ const blockerLinks = linkedIssues.filter(
27284
+ (l) => BLOCKER_LINK_PATTERNS.some((p) => l.relationship.toLowerCase().includes(p.split(" ")[0]))
27285
+ );
27286
+ if (blockerLinks.length === 0) return null;
27287
+ const resolved = blockerLinks.filter((l) => l.isDone).length;
27288
+ const blockerProgress = Math.round(resolved / blockerLinks.length * prerequisiteWeight * 100);
27289
+ return { blockerProgress, totalBlockers: blockerLinks.length, resolvedBlockers: resolved };
27290
+ }
27275
27291
  var LINKED_COMMENT_ANALYSIS_PROMPT = `You are a delivery management assistant analyzing Jira comments from linked issues for progress signals.
27276
27292
 
27277
27293
  For each linked issue below, read the comments and produce a 1-sentence summary focused on: impact on the parent issue, blockers, or decisions.
@@ -27685,6 +27701,39 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
27685
27701
  });
27686
27702
  }
27687
27703
  }
27704
+ const prerequisiteWeight = options.prerequisiteWeight ?? 0.3;
27705
+ const blockerResult = computeBlockerProgress(linkedIssues, prerequisiteWeight);
27706
+ let blockerProgressValue = null;
27707
+ let totalBlockersCount = 0;
27708
+ let resolvedBlockersCount = 0;
27709
+ if (blockerResult && !fm.progressOverride && !DONE_STATUSES15.has(fm.status)) {
27710
+ blockerProgressValue = blockerResult.blockerProgress;
27711
+ totalBlockersCount = blockerResult.totalBlockers;
27712
+ resolvedBlockersCount = blockerResult.resolvedBlockers;
27713
+ const lastProgressUpdate = findLast(proposedUpdates, (u) => u.artifactId === fm.id && u.field === "progress");
27714
+ const implementationProgress = lastProgressUpdate ? lastProgressUpdate.proposedValue : currentProgress;
27715
+ const combinedProgress = Math.round(
27716
+ blockerResult.blockerProgress + implementationProgress * (1 - prerequisiteWeight)
27717
+ );
27718
+ const estimatedProgress = Math.max(currentProgress, combinedProgress);
27719
+ if (estimatedProgress !== currentProgress && estimatedProgress !== implementationProgress) {
27720
+ for (let i = proposedUpdates.length - 1; i >= 0; i--) {
27721
+ if (proposedUpdates[i].artifactId === fm.id && proposedUpdates[i].field === "progress") {
27722
+ proposedUpdates.splice(i, 1);
27723
+ }
27724
+ }
27725
+ proposedUpdates.push({
27726
+ artifactId: fm.id,
27727
+ field: "progress",
27728
+ currentValue: currentProgress,
27729
+ proposedValue: estimatedProgress,
27730
+ reason: `Blocker resolution (${resolvedBlockersCount}/${totalBlockersCount}) + implementation \u2192 dependency-weighted progress ${estimatedProgress}%`
27731
+ });
27732
+ }
27733
+ } else if (blockerResult) {
27734
+ totalBlockersCount = blockerResult.totalBlockers;
27735
+ resolvedBlockersCount = blockerResult.resolvedBlockers;
27736
+ }
27688
27737
  const signals = buildSignals(commentSignals, linkedIssues, statusDrift, proposedMarvinStatus);
27689
27738
  const appliedUpdates = [];
27690
27739
  if (options.applyUpdates && proposedUpdates.length > 0) {
@@ -27727,7 +27776,10 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
27727
27776
  commentAnalysisProgress,
27728
27777
  signals,
27729
27778
  children,
27730
- linkedIssues
27779
+ linkedIssues,
27780
+ blockerProgressValue,
27781
+ totalBlockersCount,
27782
+ resolvedBlockersCount
27731
27783
  );
27732
27784
  const existingHistory = Array.isArray(fm.assessmentHistory) ? fm.assessmentHistory : [];
27733
27785
  const legacySummary = fm.assessmentSummary;
@@ -27776,6 +27828,9 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
27776
27828
  commentAnalysisProgress,
27777
27829
  linkedIssues,
27778
27830
  linkedIssueSignals,
27831
+ blockerProgress: blockerProgressValue,
27832
+ totalBlockers: totalBlockersCount,
27833
+ resolvedBlockers: resolvedBlockersCount,
27779
27834
  children,
27780
27835
  proposedUpdates: options.applyUpdates ? [] : proposedUpdates,
27781
27836
  appliedUpdates,
@@ -27955,6 +28010,9 @@ function emptyArtifactReport(artifactId, errors) {
27955
28010
  commentAnalysisProgress: null,
27956
28011
  linkedIssues: [],
27957
28012
  linkedIssueSignals: [],
28013
+ blockerProgress: null,
28014
+ totalBlockers: 0,
28015
+ resolvedBlockers: 0,
27958
28016
  children: [],
27959
28017
  proposedUpdates: [],
27960
28018
  appliedUpdates: [],
@@ -27962,7 +28020,7 @@ function emptyArtifactReport(artifactId, errors) {
27962
28020
  errors
27963
28021
  };
27964
28022
  }
27965
- function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals, children, linkedIssues) {
28023
+ function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals, children, linkedIssues, blockerProgress = null, totalBlockers = 0, resolvedBlockers = 0) {
27966
28024
  const childProgressValues = children.map((c) => {
27967
28025
  const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
27968
28026
  const lastStatus = findLast(updates, (u) => u.field === "status");
@@ -27986,7 +28044,10 @@ function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals
27986
28044
  childCount: children.length,
27987
28045
  childDoneCount,
27988
28046
  childRollupProgress,
27989
- linkedIssueCount: linkedIssues.length
28047
+ linkedIssueCount: linkedIssues.length,
28048
+ blockerProgress,
28049
+ totalBlockers,
28050
+ resolvedBlockers
27990
28051
  };
27991
28052
  }
27992
28053
  function formatArtifactReport(report) {
@@ -28022,6 +28083,12 @@ function formatArtifactReport(report) {
28022
28083
  }
28023
28084
  parts.push("");
28024
28085
  }
28086
+ if (report.totalBlockers > 0) {
28087
+ parts.push(`## Blocker Resolution`);
28088
+ const bpLabel = report.blockerProgress !== null ? `${report.blockerProgress}%` : "n/a (skipped)";
28089
+ parts.push(` ${report.resolvedBlockers}/${report.totalBlockers} blockers resolved \u2192 ${bpLabel} prerequisite progress`);
28090
+ parts.push("");
28091
+ }
28025
28092
  if (report.children.length > 0) {
28026
28093
  const doneCount = report.children.filter((c) => DONE_STATUSES15.has(c.marvinStatus)).length;
28027
28094
  const childProgress = Math.round(
@@ -28920,10 +28987,11 @@ function createJiraTools(store, projectConfig) {
28920
28987
  // --- Single-artifact assessment ---
28921
28988
  tool20(
28922
28989
  "assess_artifact",
28923
- "Deep assessment of a single Marvin artifact (task, action, or epic). Fetches live Jira status, analyzes comments with LLM, traverses all linked issues, detects drift, rolls up child progress, and extracts contextual signals (blockers, unblocks, handoffs, superseded work).",
28990
+ "Deep assessment of a single Marvin artifact (task, action, or epic). Fetches live Jira status, analyzes comments with LLM, traverses all linked issues, detects drift, rolls up child progress, computes dependency-weighted progress from blocker resolution, and extracts contextual signals (blockers, unblocks, handoffs, superseded work).",
28924
28991
  {
28925
28992
  artifactId: external_exports.string().describe("Marvin artifact ID (e.g. 'T-063', 'A-151', 'E-003')"),
28926
- applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to the artifact (default false)")
28993
+ applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to the artifact (default false)"),
28994
+ prerequisiteWeight: external_exports.number().min(0).max(1).optional().describe("Weight for blocker-resolution progress signal (0-1, default 0.3). Portion of effort attributed to dependency readiness.")
28927
28995
  },
28928
28996
  async (args) => {
28929
28997
  const jira = createJiraClient(jiraUserConfig);
@@ -28935,6 +29003,7 @@ function createJiraTools(store, projectConfig) {
28935
29003
  {
28936
29004
  artifactId: args.artifactId,
28937
29005
  applyUpdates: args.applyUpdates ?? false,
29006
+ prerequisiteWeight: args.prerequisiteWeight,
28938
29007
  statusMap
28939
29008
  }
28940
29009
  );
@@ -34349,7 +34418,7 @@ function createProgram() {
34349
34418
  const program2 = new Command();
34350
34419
  program2.name("marvin").description(
34351
34420
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
34352
- ).version("0.5.26");
34421
+ ).version("0.5.27");
34353
34422
  program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
34354
34423
  await initCommand();
34355
34424
  });