mrvn-cli 0.5.21 → 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 +64 -14
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +63 -13
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +64 -14
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin-serve.js
CHANGED
|
@@ -19842,6 +19842,7 @@ function generateProposedActions(issues) {
|
|
|
19842
19842
|
// src/skills/builtin/jira/sprint-progress.ts
|
|
19843
19843
|
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
19844
19844
|
var DONE_STATUSES6 = /* @__PURE__ */ new Set(["done", "closed", "resolved", "obsolete", "wont do", "cancelled"]);
|
|
19845
|
+
var PROGRESS_DONE_STATUSES = /* @__PURE__ */ new Set(["done", "closed", "resolved", "obsolete", "wont do"]);
|
|
19845
19846
|
var BATCH_SIZE = 5;
|
|
19846
19847
|
var MAX_LINKED_ISSUES = 50;
|
|
19847
19848
|
var BLOCKED_WEIGHT_RISK_THRESHOLD = 0.3;
|
|
@@ -20731,11 +20732,12 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20731
20732
|
}
|
|
20732
20733
|
}
|
|
20733
20734
|
const primaryHasComments = jiraKey ? (jiraIssues.get(jiraKey)?.comments.length ?? 0) > 0 : false;
|
|
20735
|
+
let commentAnalysisProgress = null;
|
|
20734
20736
|
if (depth < MAX_LLM_DEPTH && jiraKey && primaryHasComments) {
|
|
20735
20737
|
const estimatedChars = estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignals);
|
|
20736
20738
|
if (estimatedChars <= MAX_LLM_COMMENT_CHARS) {
|
|
20737
20739
|
try {
|
|
20738
|
-
const
|
|
20740
|
+
const analysis = await analyzeSingleArtifactComments(
|
|
20739
20741
|
fm.id,
|
|
20740
20742
|
fm.title,
|
|
20741
20743
|
jiraKey,
|
|
@@ -20744,7 +20746,20 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20744
20746
|
linkedJiraIssues,
|
|
20745
20747
|
linkedIssueSignals
|
|
20746
20748
|
);
|
|
20747
|
-
commentSummary = summary;
|
|
20749
|
+
commentSummary = analysis.summary;
|
|
20750
|
+
commentAnalysisProgress = analysis.progressEstimate;
|
|
20751
|
+
if (commentAnalysisProgress !== null) {
|
|
20752
|
+
const hasExplicitProgress = "progress" in fm && typeof fm.progress === "number";
|
|
20753
|
+
if (!hasExplicitProgress && !fm.progressOverride && commentAnalysisProgress !== currentProgress) {
|
|
20754
|
+
proposedUpdates.push({
|
|
20755
|
+
artifactId: fm.id,
|
|
20756
|
+
field: "progress",
|
|
20757
|
+
currentValue: currentProgress,
|
|
20758
|
+
proposedValue: commentAnalysisProgress,
|
|
20759
|
+
reason: `Comment analysis estimates ${commentAnalysisProgress}% progress`
|
|
20760
|
+
});
|
|
20761
|
+
}
|
|
20762
|
+
}
|
|
20748
20763
|
} catch (err) {
|
|
20749
20764
|
errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20750
20765
|
}
|
|
@@ -20768,8 +20783,16 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20768
20783
|
children.push(childReport);
|
|
20769
20784
|
}
|
|
20770
20785
|
if (children.length > 0) {
|
|
20786
|
+
const childProgressValues = children.map((c) => {
|
|
20787
|
+
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
20788
|
+
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
20789
|
+
if (lastStatus && PROGRESS_DONE_STATUSES.has(String(lastStatus.proposedValue))) return 100;
|
|
20790
|
+
const lastProgress = findLast(updates, (u) => u.field === "progress");
|
|
20791
|
+
if (lastProgress) return lastProgress.proposedValue;
|
|
20792
|
+
return c.marvinProgress;
|
|
20793
|
+
});
|
|
20771
20794
|
const rolledUpProgress = Math.round(
|
|
20772
|
-
|
|
20795
|
+
childProgressValues.reduce((s, p) => s + p, 0) / childProgressValues.length
|
|
20773
20796
|
);
|
|
20774
20797
|
if (rolledUpProgress !== currentProgress) {
|
|
20775
20798
|
proposedUpdates.push({
|
|
@@ -20785,7 +20808,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20785
20808
|
const appliedUpdates = [];
|
|
20786
20809
|
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
20787
20810
|
const doneArtifacts = new Set(
|
|
20788
|
-
proposedUpdates.filter((u) => u.field === "status" &&
|
|
20811
|
+
proposedUpdates.filter((u) => u.field === "status" && PROGRESS_DONE_STATUSES.has(String(u.proposedValue))).map((u) => u.artifactId)
|
|
20789
20812
|
);
|
|
20790
20813
|
for (const update of proposedUpdates) {
|
|
20791
20814
|
if (update.field === "review") continue;
|
|
@@ -20834,6 +20857,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20834
20857
|
progressDrift,
|
|
20835
20858
|
commentSignals,
|
|
20836
20859
|
commentSummary,
|
|
20860
|
+
commentAnalysisProgress,
|
|
20837
20861
|
linkedIssues,
|
|
20838
20862
|
linkedIssueSignals,
|
|
20839
20863
|
children,
|
|
@@ -20926,13 +20950,15 @@ function estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignal
|
|
|
20926
20950
|
}
|
|
20927
20951
|
var SINGLE_ARTIFACT_COMMENT_PROMPT = `You are a delivery management assistant analyzing Jira comments for a single work item.
|
|
20928
20952
|
|
|
20929
|
-
|
|
20930
|
-
-
|
|
20931
|
-
-
|
|
20932
|
-
- Any decisions, handoffs, or scheduling mentioned
|
|
20933
|
-
- Relevant context from linked issue comments (if provided)
|
|
20953
|
+
Analyze the comments and produce:
|
|
20954
|
+
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).
|
|
20955
|
+
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.
|
|
20934
20956
|
|
|
20935
|
-
Return
|
|
20957
|
+
Return a JSON object with this exact structure:
|
|
20958
|
+
{"summary": "your 2-3 sentence summary", "progressEstimate": 75}
|
|
20959
|
+
|
|
20960
|
+
Use null for progressEstimate if the comments don't provide enough evidence to estimate.
|
|
20961
|
+
IMPORTANT: Only return the JSON object, no other text.`;
|
|
20936
20962
|
async function analyzeSingleArtifactComments(artifactId, title, jiraKey, jiraStatus, jiraIssues, linkedJiraIssues, linkedIssueSignals) {
|
|
20937
20963
|
const promptParts = [];
|
|
20938
20964
|
const primaryData = jiraIssues.get(jiraKey);
|
|
@@ -20955,7 +20981,7 @@ ${commentTexts}`);
|
|
|
20955
20981
|
promptParts.push(`### Linked: ${signal.sourceKey} (${signal.linkType})
|
|
20956
20982
|
${commentTexts}`);
|
|
20957
20983
|
}
|
|
20958
|
-
if (promptParts.length === 0) return null;
|
|
20984
|
+
if (promptParts.length === 0) return { summary: null, progressEstimate: null };
|
|
20959
20985
|
const prompt = promptParts.join("\n\n");
|
|
20960
20986
|
const result = query2({
|
|
20961
20987
|
prompt,
|
|
@@ -20972,11 +20998,25 @@ ${commentTexts}`);
|
|
|
20972
20998
|
(b) => b.type === "text"
|
|
20973
20999
|
);
|
|
20974
21000
|
if (textBlock) {
|
|
20975
|
-
return textBlock.text.trim();
|
|
21001
|
+
return parseCommentAnalysis(textBlock.text.trim());
|
|
20976
21002
|
}
|
|
20977
21003
|
}
|
|
20978
21004
|
}
|
|
20979
|
-
return null;
|
|
21005
|
+
return { summary: null, progressEstimate: null };
|
|
21006
|
+
}
|
|
21007
|
+
function parseCommentAnalysis(text) {
|
|
21008
|
+
const parsed = parseLlmJson(text);
|
|
21009
|
+
if (parsed && typeof parsed.summary === "string") {
|
|
21010
|
+
const progressEstimate2 = typeof parsed.progressEstimate === "number" && parsed.progressEstimate >= 0 && parsed.progressEstimate <= 100 ? Math.round(parsed.progressEstimate) : null;
|
|
21011
|
+
return { summary: parsed.summary, progressEstimate: progressEstimate2 };
|
|
21012
|
+
}
|
|
21013
|
+
let progressEstimate = null;
|
|
21014
|
+
const pctMatch = text.match(/(\d{1,3})%/);
|
|
21015
|
+
if (pctMatch) {
|
|
21016
|
+
const pct = parseInt(pctMatch[1], 10);
|
|
21017
|
+
if (pct >= 0 && pct <= 100) progressEstimate = pct;
|
|
21018
|
+
}
|
|
21019
|
+
return { summary: text, progressEstimate };
|
|
20980
21020
|
}
|
|
20981
21021
|
function emptyArtifactReport(artifactId, errors) {
|
|
20982
21022
|
return {
|
|
@@ -20996,6 +21036,7 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
20996
21036
|
progressDrift: false,
|
|
20997
21037
|
commentSignals: [],
|
|
20998
21038
|
commentSummary: null,
|
|
21039
|
+
commentAnalysisProgress: null,
|
|
20999
21040
|
linkedIssues: [],
|
|
21000
21041
|
linkedIssueSignals: [],
|
|
21001
21042
|
children: [],
|
|
@@ -21033,6 +21074,9 @@ function formatArtifactReport(report) {
|
|
|
21033
21074
|
if (report.commentSummary) {
|
|
21034
21075
|
parts.push(`## Comments`);
|
|
21035
21076
|
parts.push(report.commentSummary);
|
|
21077
|
+
if (report.commentAnalysisProgress !== null) {
|
|
21078
|
+
parts.push(` \u{1F4CA} Comment-derived progress estimate: ${report.commentAnalysisProgress}%`);
|
|
21079
|
+
}
|
|
21036
21080
|
parts.push("");
|
|
21037
21081
|
}
|
|
21038
21082
|
if (report.children.length > 0) {
|
|
@@ -21113,6 +21157,12 @@ function formatArtifactChild(parts, child, depth) {
|
|
|
21113
21157
|
formatArtifactChild(parts, grandchild, depth + 1);
|
|
21114
21158
|
}
|
|
21115
21159
|
}
|
|
21160
|
+
function findLast(arr, predicate) {
|
|
21161
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
21162
|
+
if (predicate(arr[i])) return arr[i];
|
|
21163
|
+
}
|
|
21164
|
+
return void 0;
|
|
21165
|
+
}
|
|
21116
21166
|
|
|
21117
21167
|
// src/skills/builtin/jira/tools.ts
|
|
21118
21168
|
var JIRA_TYPE = "jira-issue";
|