mrvn-cli 0.5.22 → 0.5.24
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 +91 -12
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +90 -11
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +91 -12
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
}
|
|
@@ -26791,6 +26805,23 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26791
26805
|
}
|
|
26792
26806
|
}
|
|
26793
26807
|
}
|
|
26808
|
+
if (options.applyUpdates) {
|
|
26809
|
+
const assessmentSummary = buildAssessmentSummary(
|
|
26810
|
+
commentSummary,
|
|
26811
|
+
commentAnalysisProgress,
|
|
26812
|
+
signals,
|
|
26813
|
+
children,
|
|
26814
|
+
linkedIssues
|
|
26815
|
+
);
|
|
26816
|
+
try {
|
|
26817
|
+
store.update(fm.id, {
|
|
26818
|
+
assessmentSummary,
|
|
26819
|
+
lastAssessedAt: assessmentSummary.generatedAt
|
|
26820
|
+
});
|
|
26821
|
+
} catch (err) {
|
|
26822
|
+
errors.push(`Failed to persist assessment summary: ${err instanceof Error ? err.message : String(err)}`);
|
|
26823
|
+
}
|
|
26824
|
+
}
|
|
26794
26825
|
return {
|
|
26795
26826
|
artifactId: fm.id,
|
|
26796
26827
|
title: fm.title,
|
|
@@ -26808,6 +26839,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26808
26839
|
progressDrift,
|
|
26809
26840
|
commentSignals,
|
|
26810
26841
|
commentSummary,
|
|
26842
|
+
commentAnalysisProgress,
|
|
26811
26843
|
linkedIssues,
|
|
26812
26844
|
linkedIssueSignals,
|
|
26813
26845
|
children,
|
|
@@ -26900,13 +26932,15 @@ function estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignal
|
|
|
26900
26932
|
}
|
|
26901
26933
|
var SINGLE_ARTIFACT_COMMENT_PROMPT = `You are a delivery management assistant analyzing Jira comments for a single work item.
|
|
26902
26934
|
|
|
26903
|
-
|
|
26904
|
-
-
|
|
26905
|
-
-
|
|
26906
|
-
- Any decisions, handoffs, or scheduling mentioned
|
|
26907
|
-
- Relevant context from linked issue comments (if provided)
|
|
26935
|
+
Analyze the comments and produce:
|
|
26936
|
+
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).
|
|
26937
|
+
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
26938
|
|
|
26909
|
-
Return
|
|
26939
|
+
Return a JSON object with this exact structure:
|
|
26940
|
+
{"summary": "your 2-3 sentence summary", "progressEstimate": 75}
|
|
26941
|
+
|
|
26942
|
+
Use null for progressEstimate if the comments don't provide enough evidence to estimate.
|
|
26943
|
+
IMPORTANT: Only return the JSON object, no other text.`;
|
|
26910
26944
|
async function analyzeSingleArtifactComments(artifactId, title, jiraKey, jiraStatus, jiraIssues, linkedJiraIssues, linkedIssueSignals) {
|
|
26911
26945
|
const promptParts = [];
|
|
26912
26946
|
const primaryData = jiraIssues.get(jiraKey);
|
|
@@ -26929,7 +26963,7 @@ ${commentTexts}`);
|
|
|
26929
26963
|
promptParts.push(`### Linked: ${signal.sourceKey} (${signal.linkType})
|
|
26930
26964
|
${commentTexts}`);
|
|
26931
26965
|
}
|
|
26932
|
-
if (promptParts.length === 0) return null;
|
|
26966
|
+
if (promptParts.length === 0) return { summary: null, progressEstimate: null };
|
|
26933
26967
|
const prompt = promptParts.join("\n\n");
|
|
26934
26968
|
const result = query3({
|
|
26935
26969
|
prompt,
|
|
@@ -26946,11 +26980,25 @@ ${commentTexts}`);
|
|
|
26946
26980
|
(b) => b.type === "text"
|
|
26947
26981
|
);
|
|
26948
26982
|
if (textBlock) {
|
|
26949
|
-
return textBlock.text.trim();
|
|
26983
|
+
return parseCommentAnalysis(textBlock.text.trim());
|
|
26950
26984
|
}
|
|
26951
26985
|
}
|
|
26952
26986
|
}
|
|
26953
|
-
return null;
|
|
26987
|
+
return { summary: null, progressEstimate: null };
|
|
26988
|
+
}
|
|
26989
|
+
function parseCommentAnalysis(text) {
|
|
26990
|
+
const parsed = parseLlmJson(text);
|
|
26991
|
+
if (parsed && typeof parsed.summary === "string") {
|
|
26992
|
+
const progressEstimate2 = typeof parsed.progressEstimate === "number" && parsed.progressEstimate >= 0 && parsed.progressEstimate <= 100 ? Math.round(parsed.progressEstimate) : null;
|
|
26993
|
+
return { summary: parsed.summary, progressEstimate: progressEstimate2 };
|
|
26994
|
+
}
|
|
26995
|
+
let progressEstimate = null;
|
|
26996
|
+
const pctMatch = text.match(/(\d{1,3})%/);
|
|
26997
|
+
if (pctMatch) {
|
|
26998
|
+
const pct = parseInt(pctMatch[1], 10);
|
|
26999
|
+
if (pct >= 0 && pct <= 100) progressEstimate = pct;
|
|
27000
|
+
}
|
|
27001
|
+
return { summary: text, progressEstimate };
|
|
26954
27002
|
}
|
|
26955
27003
|
function emptyArtifactReport(artifactId, errors) {
|
|
26956
27004
|
return {
|
|
@@ -26970,6 +27018,7 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
26970
27018
|
progressDrift: false,
|
|
26971
27019
|
commentSignals: [],
|
|
26972
27020
|
commentSummary: null,
|
|
27021
|
+
commentAnalysisProgress: null,
|
|
26973
27022
|
linkedIssues: [],
|
|
26974
27023
|
linkedIssueSignals: [],
|
|
26975
27024
|
children: [],
|
|
@@ -26979,6 +27028,33 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
26979
27028
|
errors
|
|
26980
27029
|
};
|
|
26981
27030
|
}
|
|
27031
|
+
function buildAssessmentSummary(commentSummary, commentAnalysisProgress, signals, children, linkedIssues) {
|
|
27032
|
+
const childProgressValues = children.map((c) => {
|
|
27033
|
+
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
27034
|
+
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
27035
|
+
if (lastStatus && PROGRESS_DONE_STATUSES.has(String(lastStatus.proposedValue))) return 100;
|
|
27036
|
+
const lastProgress = findLast(updates, (u) => u.field === "progress");
|
|
27037
|
+
if (lastProgress) return lastProgress.proposedValue;
|
|
27038
|
+
return c.marvinProgress;
|
|
27039
|
+
});
|
|
27040
|
+
const childDoneCount = children.filter((c, i) => {
|
|
27041
|
+
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
27042
|
+
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
27043
|
+
const effectiveStatus = lastStatus ? String(lastStatus.proposedValue) : c.marvinStatus;
|
|
27044
|
+
return DONE_STATUSES15.has(effectiveStatus);
|
|
27045
|
+
}).length;
|
|
27046
|
+
const childRollupProgress = children.length > 0 ? Math.round(childProgressValues.reduce((s, p) => s + p, 0) / childProgressValues.length) : null;
|
|
27047
|
+
return {
|
|
27048
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27049
|
+
commentSummary,
|
|
27050
|
+
commentAnalysisProgress,
|
|
27051
|
+
signals,
|
|
27052
|
+
childCount: children.length,
|
|
27053
|
+
childDoneCount,
|
|
27054
|
+
childRollupProgress,
|
|
27055
|
+
linkedIssueCount: linkedIssues.length
|
|
27056
|
+
};
|
|
27057
|
+
}
|
|
26982
27058
|
function formatArtifactReport(report) {
|
|
26983
27059
|
const parts = [];
|
|
26984
27060
|
parts.push(`# Artifact Assessment \u2014 ${report.artifactId}`);
|
|
@@ -27007,6 +27083,9 @@ function formatArtifactReport(report) {
|
|
|
27007
27083
|
if (report.commentSummary) {
|
|
27008
27084
|
parts.push(`## Comments`);
|
|
27009
27085
|
parts.push(report.commentSummary);
|
|
27086
|
+
if (report.commentAnalysisProgress !== null) {
|
|
27087
|
+
parts.push(` \u{1F4CA} Comment-derived progress estimate: ${report.commentAnalysisProgress}%`);
|
|
27088
|
+
}
|
|
27010
27089
|
parts.push("");
|
|
27011
27090
|
}
|
|
27012
27091
|
if (report.children.length > 0) {
|
|
@@ -33590,7 +33669,7 @@ function createProgram() {
|
|
|
33590
33669
|
const program = new Command();
|
|
33591
33670
|
program.name("marvin").description(
|
|
33592
33671
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
33593
|
-
).version("0.5.
|
|
33672
|
+
).version("0.5.24");
|
|
33594
33673
|
program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
33595
33674
|
await initCommand();
|
|
33596
33675
|
});
|