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/index.js +76 -7
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +75 -6
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +76 -7
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21118,7 +21118,10 @@ function normalizeEntry(entry) {
|
|
|
21118
21118
|
childCount: typeof entry.childCount === "number" ? entry.childCount : 0,
|
|
21119
21119
|
childDoneCount: typeof entry.childDoneCount === "number" ? entry.childDoneCount : 0,
|
|
21120
21120
|
childRollupProgress: typeof entry.childRollupProgress === "number" ? entry.childRollupProgress : null,
|
|
21121
|
-
linkedIssueCount: typeof entry.linkedIssueCount === "number" ? entry.linkedIssueCount : 0
|
|
21121
|
+
linkedIssueCount: typeof entry.linkedIssueCount === "number" ? entry.linkedIssueCount : 0,
|
|
21122
|
+
blockerProgress: typeof entry.blockerProgress === "number" ? entry.blockerProgress : null,
|
|
21123
|
+
totalBlockers: typeof entry.totalBlockers === "number" ? entry.totalBlockers : 0,
|
|
21124
|
+
resolvedBlockers: typeof entry.resolvedBlockers === "number" ? entry.resolvedBlockers : 0
|
|
21122
21125
|
};
|
|
21123
21126
|
}
|
|
21124
21127
|
function renderAssessmentTimeline(history) {
|
|
@@ -21138,6 +21141,10 @@ function renderAssessmentTimeline(history) {
|
|
|
21138
21141
|
const bar = progressBarHtml(entry.childRollupProgress ?? 0);
|
|
21139
21142
|
parts.push(`<div class="assessment-stat">\u{1F476} Children: ${entry.childDoneCount}/${entry.childCount} done ${bar} ${entry.childRollupProgress ?? 0}%</div>`);
|
|
21140
21143
|
}
|
|
21144
|
+
if (entry.totalBlockers > 0) {
|
|
21145
|
+
const bar = progressBarHtml(entry.blockerProgress ?? 0);
|
|
21146
|
+
parts.push(`<div class="assessment-stat">\u{1F6A7} Blockers: ${entry.resolvedBlockers}/${entry.totalBlockers} resolved ${bar} ${entry.blockerProgress ?? 0}%</div>`);
|
|
21147
|
+
}
|
|
21141
21148
|
if (entry.linkedIssueCount > 0) {
|
|
21142
21149
|
parts.push(`<div class="assessment-stat">\u{1F517} Linked issues: ${entry.linkedIssueCount}</div>`);
|
|
21143
21150
|
}
|
|
@@ -27028,6 +27035,15 @@ function analyzeLinkedIssueSignals(linkedIssues, frontmatter, jiraKey, proposedU
|
|
|
27028
27035
|
});
|
|
27029
27036
|
}
|
|
27030
27037
|
}
|
|
27038
|
+
function computeBlockerProgress(linkedIssues, prerequisiteWeight) {
|
|
27039
|
+
const blockerLinks = linkedIssues.filter(
|
|
27040
|
+
(l) => BLOCKER_LINK_PATTERNS.some((p) => l.relationship.toLowerCase().includes(p.split(" ")[0]))
|
|
27041
|
+
);
|
|
27042
|
+
if (blockerLinks.length === 0) return null;
|
|
27043
|
+
const resolved = blockerLinks.filter((l) => l.isDone).length;
|
|
27044
|
+
const blockerProgress = Math.round(resolved / blockerLinks.length * prerequisiteWeight * 100);
|
|
27045
|
+
return { blockerProgress, totalBlockers: blockerLinks.length, resolvedBlockers: resolved };
|
|
27046
|
+
}
|
|
27031
27047
|
var LINKED_COMMENT_ANALYSIS_PROMPT = `You are a delivery management assistant analyzing Jira comments from linked issues for progress signals.
|
|
27032
27048
|
|
|
27033
27049
|
For each linked issue below, read the comments and produce a 1-sentence summary focused on: impact on the parent issue, blockers, or decisions.
|
|
@@ -27441,6 +27457,39 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
27441
27457
|
});
|
|
27442
27458
|
}
|
|
27443
27459
|
}
|
|
27460
|
+
const prerequisiteWeight = options.prerequisiteWeight ?? 0.3;
|
|
27461
|
+
const blockerResult = computeBlockerProgress(linkedIssues, prerequisiteWeight);
|
|
27462
|
+
let blockerProgressValue = null;
|
|
27463
|
+
let totalBlockersCount = 0;
|
|
27464
|
+
let resolvedBlockersCount = 0;
|
|
27465
|
+
if (blockerResult && !fm.progressOverride && !DONE_STATUSES15.has(fm.status)) {
|
|
27466
|
+
blockerProgressValue = blockerResult.blockerProgress;
|
|
27467
|
+
totalBlockersCount = blockerResult.totalBlockers;
|
|
27468
|
+
resolvedBlockersCount = blockerResult.resolvedBlockers;
|
|
27469
|
+
const lastProgressUpdate = findLast(proposedUpdates, (u) => u.artifactId === fm.id && u.field === "progress");
|
|
27470
|
+
const implementationProgress = lastProgressUpdate ? lastProgressUpdate.proposedValue : currentProgress;
|
|
27471
|
+
const combinedProgress = Math.round(
|
|
27472
|
+
blockerResult.blockerProgress + implementationProgress * (1 - prerequisiteWeight)
|
|
27473
|
+
);
|
|
27474
|
+
const estimatedProgress = Math.max(currentProgress, combinedProgress);
|
|
27475
|
+
if (estimatedProgress !== currentProgress && estimatedProgress !== implementationProgress) {
|
|
27476
|
+
for (let i = proposedUpdates.length - 1; i >= 0; i--) {
|
|
27477
|
+
if (proposedUpdates[i].artifactId === fm.id && proposedUpdates[i].field === "progress") {
|
|
27478
|
+
proposedUpdates.splice(i, 1);
|
|
27479
|
+
}
|
|
27480
|
+
}
|
|
27481
|
+
proposedUpdates.push({
|
|
27482
|
+
artifactId: fm.id,
|
|
27483
|
+
field: "progress",
|
|
27484
|
+
currentValue: currentProgress,
|
|
27485
|
+
proposedValue: estimatedProgress,
|
|
27486
|
+
reason: `Blocker resolution (${resolvedBlockersCount}/${totalBlockersCount}) + implementation \u2192 dependency-weighted progress ${estimatedProgress}%`
|
|
27487
|
+
});
|
|
27488
|
+
}
|
|
27489
|
+
} else if (blockerResult) {
|
|
27490
|
+
totalBlockersCount = blockerResult.totalBlockers;
|
|
27491
|
+
resolvedBlockersCount = blockerResult.resolvedBlockers;
|
|
27492
|
+
}
|
|
27444
27493
|
const signals = buildSignals(commentSignals, linkedIssues, statusDrift, proposedMarvinStatus);
|
|
27445
27494
|
const appliedUpdates = [];
|
|
27446
27495
|
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
@@ -27483,7 +27532,10 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
27483
27532
|
commentAnalysisProgress,
|
|
27484
27533
|
signals,
|
|
27485
27534
|
children,
|
|
27486
|
-
linkedIssues
|
|
27535
|
+
linkedIssues,
|
|
27536
|
+
blockerProgressValue,
|
|
27537
|
+
totalBlockersCount,
|
|
27538
|
+
resolvedBlockersCount
|
|
27487
27539
|
);
|
|
27488
27540
|
const existingHistory = Array.isArray(fm.assessmentHistory) ? fm.assessmentHistory : [];
|
|
27489
27541
|
const legacySummary = fm.assessmentSummary;
|
|
@@ -27532,6 +27584,9 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
27532
27584
|
commentAnalysisProgress,
|
|
27533
27585
|
linkedIssues,
|
|
27534
27586
|
linkedIssueSignals,
|
|
27587
|
+
blockerProgress: blockerProgressValue,
|
|
27588
|
+
totalBlockers: totalBlockersCount,
|
|
27589
|
+
resolvedBlockers: resolvedBlockersCount,
|
|
27535
27590
|
children,
|
|
27536
27591
|
proposedUpdates: options.applyUpdates ? [] : proposedUpdates,
|
|
27537
27592
|
appliedUpdates,
|
|
@@ -27711,6 +27766,9 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
27711
27766
|
commentAnalysisProgress: null,
|
|
27712
27767
|
linkedIssues: [],
|
|
27713
27768
|
linkedIssueSignals: [],
|
|
27769
|
+
blockerProgress: null,
|
|
27770
|
+
totalBlockers: 0,
|
|
27771
|
+
resolvedBlockers: 0,
|
|
27714
27772
|
children: [],
|
|
27715
27773
|
proposedUpdates: [],
|
|
27716
27774
|
appliedUpdates: [],
|
|
@@ -27718,7 +27776,7 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
27718
27776
|
errors
|
|
27719
27777
|
};
|
|
27720
27778
|
}
|
|
27721
|
-
function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals, children, linkedIssues) {
|
|
27779
|
+
function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals, children, linkedIssues, blockerProgress = null, totalBlockers = 0, resolvedBlockers = 0) {
|
|
27722
27780
|
const childProgressValues = children.map((c) => {
|
|
27723
27781
|
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
27724
27782
|
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
@@ -27742,7 +27800,10 @@ function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals
|
|
|
27742
27800
|
childCount: children.length,
|
|
27743
27801
|
childDoneCount,
|
|
27744
27802
|
childRollupProgress,
|
|
27745
|
-
linkedIssueCount: linkedIssues.length
|
|
27803
|
+
linkedIssueCount: linkedIssues.length,
|
|
27804
|
+
blockerProgress,
|
|
27805
|
+
totalBlockers,
|
|
27806
|
+
resolvedBlockers
|
|
27746
27807
|
};
|
|
27747
27808
|
}
|
|
27748
27809
|
function formatArtifactReport(report) {
|
|
@@ -27778,6 +27839,12 @@ function formatArtifactReport(report) {
|
|
|
27778
27839
|
}
|
|
27779
27840
|
parts.push("");
|
|
27780
27841
|
}
|
|
27842
|
+
if (report.totalBlockers > 0) {
|
|
27843
|
+
parts.push(`## Blocker Resolution`);
|
|
27844
|
+
const bpLabel = report.blockerProgress !== null ? `${report.blockerProgress}%` : "n/a (skipped)";
|
|
27845
|
+
parts.push(` ${report.resolvedBlockers}/${report.totalBlockers} blockers resolved \u2192 ${bpLabel} prerequisite progress`);
|
|
27846
|
+
parts.push("");
|
|
27847
|
+
}
|
|
27781
27848
|
if (report.children.length > 0) {
|
|
27782
27849
|
const doneCount = report.children.filter((c) => DONE_STATUSES15.has(c.marvinStatus)).length;
|
|
27783
27850
|
const childProgress = Math.round(
|
|
@@ -28676,10 +28743,11 @@ function createJiraTools(store, projectConfig) {
|
|
|
28676
28743
|
// --- Single-artifact assessment ---
|
|
28677
28744
|
tool20(
|
|
28678
28745
|
"assess_artifact",
|
|
28679
|
-
"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).",
|
|
28746
|
+
"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).",
|
|
28680
28747
|
{
|
|
28681
28748
|
artifactId: external_exports.string().describe("Marvin artifact ID (e.g. 'T-063', 'A-151', 'E-003')"),
|
|
28682
|
-
applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to the artifact (default false)")
|
|
28749
|
+
applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to the artifact (default false)"),
|
|
28750
|
+
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.")
|
|
28683
28751
|
},
|
|
28684
28752
|
async (args) => {
|
|
28685
28753
|
const jira = createJiraClient(jiraUserConfig);
|
|
@@ -28691,6 +28759,7 @@ function createJiraTools(store, projectConfig) {
|
|
|
28691
28759
|
{
|
|
28692
28760
|
artifactId: args.artifactId,
|
|
28693
28761
|
applyUpdates: args.applyUpdates ?? false,
|
|
28762
|
+
prerequisiteWeight: args.prerequisiteWeight,
|
|
28694
28763
|
statusMap
|
|
28695
28764
|
}
|
|
28696
28765
|
);
|
|
@@ -34359,7 +34428,7 @@ function createProgram() {
|
|
|
34359
34428
|
const program = new Command();
|
|
34360
34429
|
program.name("marvin").description(
|
|
34361
34430
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
34362
|
-
).version("0.5.
|
|
34431
|
+
).version("0.5.27");
|
|
34363
34432
|
program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
34364
34433
|
await initCommand();
|
|
34365
34434
|
});
|