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.js
CHANGED
|
@@ -26053,6 +26053,7 @@ function generateProposedActions(issues) {
|
|
|
26053
26053
|
// src/skills/builtin/jira/sprint-progress.ts
|
|
26054
26054
|
import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
|
|
26055
26055
|
var DONE_STATUSES15 = /* @__PURE__ */ new Set(["done", "closed", "resolved", "obsolete", "wont do", "cancelled"]);
|
|
26056
|
+
var PROGRESS_DONE_STATUSES = /* @__PURE__ */ new Set(["done", "closed", "resolved", "obsolete", "wont do"]);
|
|
26056
26057
|
var BATCH_SIZE = 5;
|
|
26057
26058
|
var MAX_LINKED_ISSUES = 50;
|
|
26058
26059
|
var BLOCKED_WEIGHT_RISK_THRESHOLD = 0.3;
|
|
@@ -26942,11 +26943,12 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26942
26943
|
}
|
|
26943
26944
|
}
|
|
26944
26945
|
const primaryHasComments = jiraKey ? (jiraIssues.get(jiraKey)?.comments.length ?? 0) > 0 : false;
|
|
26946
|
+
let commentAnalysisProgress = null;
|
|
26945
26947
|
if (depth < MAX_LLM_DEPTH && jiraKey && primaryHasComments) {
|
|
26946
26948
|
const estimatedChars = estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignals);
|
|
26947
26949
|
if (estimatedChars <= MAX_LLM_COMMENT_CHARS) {
|
|
26948
26950
|
try {
|
|
26949
|
-
const
|
|
26951
|
+
const analysis = await analyzeSingleArtifactComments(
|
|
26950
26952
|
fm.id,
|
|
26951
26953
|
fm.title,
|
|
26952
26954
|
jiraKey,
|
|
@@ -26955,7 +26957,20 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26955
26957
|
linkedJiraIssues,
|
|
26956
26958
|
linkedIssueSignals
|
|
26957
26959
|
);
|
|
26958
|
-
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
|
+
}
|
|
26959
26974
|
} catch (err) {
|
|
26960
26975
|
errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26961
26976
|
}
|
|
@@ -26979,8 +26994,16 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26979
26994
|
children.push(childReport);
|
|
26980
26995
|
}
|
|
26981
26996
|
if (children.length > 0) {
|
|
26997
|
+
const childProgressValues = children.map((c) => {
|
|
26998
|
+
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
26999
|
+
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
27000
|
+
if (lastStatus && PROGRESS_DONE_STATUSES.has(String(lastStatus.proposedValue))) return 100;
|
|
27001
|
+
const lastProgress = findLast(updates, (u) => u.field === "progress");
|
|
27002
|
+
if (lastProgress) return lastProgress.proposedValue;
|
|
27003
|
+
return c.marvinProgress;
|
|
27004
|
+
});
|
|
26982
27005
|
const rolledUpProgress = Math.round(
|
|
26983
|
-
|
|
27006
|
+
childProgressValues.reduce((s, p) => s + p, 0) / childProgressValues.length
|
|
26984
27007
|
);
|
|
26985
27008
|
if (rolledUpProgress !== currentProgress) {
|
|
26986
27009
|
proposedUpdates.push({
|
|
@@ -26996,7 +27019,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
26996
27019
|
const appliedUpdates = [];
|
|
26997
27020
|
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
26998
27021
|
const doneArtifacts = new Set(
|
|
26999
|
-
proposedUpdates.filter((u) => u.field === "status" &&
|
|
27022
|
+
proposedUpdates.filter((u) => u.field === "status" && PROGRESS_DONE_STATUSES.has(String(u.proposedValue))).map((u) => u.artifactId)
|
|
27000
27023
|
);
|
|
27001
27024
|
for (const update of proposedUpdates) {
|
|
27002
27025
|
if (update.field === "review") continue;
|
|
@@ -27045,6 +27068,7 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
27045
27068
|
progressDrift,
|
|
27046
27069
|
commentSignals,
|
|
27047
27070
|
commentSummary,
|
|
27071
|
+
commentAnalysisProgress,
|
|
27048
27072
|
linkedIssues,
|
|
27049
27073
|
linkedIssueSignals,
|
|
27050
27074
|
children,
|
|
@@ -27137,13 +27161,15 @@ function estimateCommentTextSize(jiraIssues, linkedJiraIssues, linkedIssueSignal
|
|
|
27137
27161
|
}
|
|
27138
27162
|
var SINGLE_ARTIFACT_COMMENT_PROMPT = `You are a delivery management assistant analyzing Jira comments for a single work item.
|
|
27139
27163
|
|
|
27140
|
-
|
|
27141
|
-
-
|
|
27142
|
-
-
|
|
27143
|
-
- Any decisions, handoffs, or scheduling mentioned
|
|
27144
|
-
- 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.
|
|
27145
27167
|
|
|
27146
|
-
Return
|
|
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.`;
|
|
27147
27173
|
async function analyzeSingleArtifactComments(artifactId, title, jiraKey, jiraStatus, jiraIssues, linkedJiraIssues, linkedIssueSignals) {
|
|
27148
27174
|
const promptParts = [];
|
|
27149
27175
|
const primaryData = jiraIssues.get(jiraKey);
|
|
@@ -27166,7 +27192,7 @@ ${commentTexts}`);
|
|
|
27166
27192
|
promptParts.push(`### Linked: ${signal.sourceKey} (${signal.linkType})
|
|
27167
27193
|
${commentTexts}`);
|
|
27168
27194
|
}
|
|
27169
|
-
if (promptParts.length === 0) return null;
|
|
27195
|
+
if (promptParts.length === 0) return { summary: null, progressEstimate: null };
|
|
27170
27196
|
const prompt = promptParts.join("\n\n");
|
|
27171
27197
|
const result = query3({
|
|
27172
27198
|
prompt,
|
|
@@ -27183,11 +27209,25 @@ ${commentTexts}`);
|
|
|
27183
27209
|
(b) => b.type === "text"
|
|
27184
27210
|
);
|
|
27185
27211
|
if (textBlock) {
|
|
27186
|
-
return textBlock.text.trim();
|
|
27212
|
+
return parseCommentAnalysis(textBlock.text.trim());
|
|
27187
27213
|
}
|
|
27188
27214
|
}
|
|
27189
27215
|
}
|
|
27190
|
-
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 };
|
|
27191
27231
|
}
|
|
27192
27232
|
function emptyArtifactReport(artifactId, errors) {
|
|
27193
27233
|
return {
|
|
@@ -27207,6 +27247,7 @@ function emptyArtifactReport(artifactId, errors) {
|
|
|
27207
27247
|
progressDrift: false,
|
|
27208
27248
|
commentSignals: [],
|
|
27209
27249
|
commentSummary: null,
|
|
27250
|
+
commentAnalysisProgress: null,
|
|
27210
27251
|
linkedIssues: [],
|
|
27211
27252
|
linkedIssueSignals: [],
|
|
27212
27253
|
children: [],
|
|
@@ -27244,6 +27285,9 @@ function formatArtifactReport(report) {
|
|
|
27244
27285
|
if (report.commentSummary) {
|
|
27245
27286
|
parts.push(`## Comments`);
|
|
27246
27287
|
parts.push(report.commentSummary);
|
|
27288
|
+
if (report.commentAnalysisProgress !== null) {
|
|
27289
|
+
parts.push(` \u{1F4CA} Comment-derived progress estimate: ${report.commentAnalysisProgress}%`);
|
|
27290
|
+
}
|
|
27247
27291
|
parts.push("");
|
|
27248
27292
|
}
|
|
27249
27293
|
if (report.children.length > 0) {
|
|
@@ -27324,6 +27368,12 @@ function formatArtifactChild(parts, child, depth) {
|
|
|
27324
27368
|
formatArtifactChild(parts, grandchild, depth + 1);
|
|
27325
27369
|
}
|
|
27326
27370
|
}
|
|
27371
|
+
function findLast(arr, predicate) {
|
|
27372
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
27373
|
+
if (predicate(arr[i])) return arr[i];
|
|
27374
|
+
}
|
|
27375
|
+
return void 0;
|
|
27376
|
+
}
|
|
27327
27377
|
|
|
27328
27378
|
// src/skills/builtin/jira/tools.ts
|
|
27329
27379
|
var JIRA_TYPE = "jira-issue";
|
|
@@ -33567,7 +33617,7 @@ function createProgram() {
|
|
|
33567
33617
|
const program2 = new Command();
|
|
33568
33618
|
program2.name("marvin").description(
|
|
33569
33619
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
33570
|
-
).version("0.5.
|
|
33620
|
+
).version("0.5.23");
|
|
33571
33621
|
program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
33572
33622
|
await initCommand();
|
|
33573
33623
|
});
|