mrvn-cli 0.5.20 → 0.5.22
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 +66 -30
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +65 -29
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +66 -30
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin-serve.js
CHANGED
|
@@ -14369,24 +14369,26 @@ function getEffectiveProgress(frontmatter) {
|
|
|
14369
14369
|
if (typeof raw === "number") return Math.max(0, Math.min(100, Math.round(raw)));
|
|
14370
14370
|
return STATUS_PROGRESS_DEFAULTS[frontmatter.status] ?? 0;
|
|
14371
14371
|
}
|
|
14372
|
-
function propagateProgressFromTask(store, taskId) {
|
|
14372
|
+
function propagateProgressFromTask(store, taskId, options) {
|
|
14373
14373
|
const updated = [];
|
|
14374
14374
|
const task = store.get(taskId);
|
|
14375
14375
|
if (!task) return updated;
|
|
14376
|
-
if (
|
|
14377
|
-
if (task.frontmatter.
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
}
|
|
14381
|
-
} else if (!task.frontmatter.progressOverride) {
|
|
14382
|
-
const children = store.list({ type: "contribution" }).filter((d) => d.frontmatter.aboutArtifact === taskId);
|
|
14383
|
-
if (children.length > 0) {
|
|
14384
|
-
const avg = children.reduce((sum, c) => sum + getEffectiveProgress(c.frontmatter), 0) / children.length;
|
|
14385
|
-
const progress = Math.round(avg);
|
|
14386
|
-
if (task.frontmatter.progress !== progress) {
|
|
14387
|
-
store.update(taskId, { progress });
|
|
14376
|
+
if (!options?.skipSelf) {
|
|
14377
|
+
if (DONE_STATUSES.has(task.frontmatter.status)) {
|
|
14378
|
+
if (task.frontmatter.progress !== 100) {
|
|
14379
|
+
store.update(taskId, { progress: 100 });
|
|
14388
14380
|
updated.push(taskId);
|
|
14389
14381
|
}
|
|
14382
|
+
} else if (!task.frontmatter.progressOverride) {
|
|
14383
|
+
const children = store.list({ type: "contribution" }).filter((d) => d.frontmatter.aboutArtifact === taskId);
|
|
14384
|
+
if (children.length > 0) {
|
|
14385
|
+
const avg = children.reduce((sum, c) => sum + getEffectiveProgress(c.frontmatter), 0) / children.length;
|
|
14386
|
+
const progress = Math.round(avg);
|
|
14387
|
+
if (task.frontmatter.progress !== progress) {
|
|
14388
|
+
store.update(taskId, { progress });
|
|
14389
|
+
updated.push(taskId);
|
|
14390
|
+
}
|
|
14391
|
+
}
|
|
14390
14392
|
}
|
|
14391
14393
|
}
|
|
14392
14394
|
const aboutArtifact = task.frontmatter.aboutArtifact;
|
|
@@ -14398,10 +14400,11 @@ function propagateProgressFromTask(store, taskId) {
|
|
|
14398
14400
|
}
|
|
14399
14401
|
return updated;
|
|
14400
14402
|
}
|
|
14401
|
-
function propagateProgressToAction(store, actionId) {
|
|
14403
|
+
function propagateProgressToAction(store, actionId, options) {
|
|
14402
14404
|
const updated = [];
|
|
14403
14405
|
const action = store.get(actionId);
|
|
14404
14406
|
if (!action) return updated;
|
|
14407
|
+
if (options?.skipSelf) return updated;
|
|
14405
14408
|
if (DONE_STATUSES.has(action.frontmatter.status)) {
|
|
14406
14409
|
if (action.frontmatter.progress !== 100) {
|
|
14407
14410
|
store.update(actionId, { progress: 100 });
|
|
@@ -14586,10 +14589,11 @@ function createActionTools(store) {
|
|
|
14586
14589
|
tags: external_exports.array(external_exports.string()).optional().describe("Replace all tags. When provided with sprints, sprint tags are merged into this array."),
|
|
14587
14590
|
sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001']."),
|
|
14588
14591
|
workFocus: external_exports.string().optional().describe("Work focus name (e.g. 'Budget UX'). Replaces existing focus:<value> tag."),
|
|
14589
|
-
progress: external_exports.number().nullable().optional().describe("Explicit progress percentage (0-100). Pass null to clear the override and revert to auto-calculation from children.")
|
|
14592
|
+
progress: external_exports.number().nullable().optional().describe("Explicit progress percentage (0-100). Pass null to clear the override and revert to auto-calculation from children."),
|
|
14593
|
+
progressOverride: external_exports.boolean().optional().describe("Control auto-calculation lock. true = lock progress to explicit value, false = allow auto-calculation from children. When omitted: setting progress implies true, null progress implies false.")
|
|
14590
14594
|
},
|
|
14591
14595
|
async (args) => {
|
|
14592
|
-
const { id, content, sprints, tags, workFocus, progress, owner, assignee, ...updates } = args;
|
|
14596
|
+
const { id, content, sprints, tags, workFocus, progress, progressOverride, owner, assignee, ...updates } = args;
|
|
14593
14597
|
if (owner !== void 0) updates.owner = normalizeOwner(owner);
|
|
14594
14598
|
if (assignee !== void 0) updates.assignee = assignee;
|
|
14595
14599
|
if (tags !== void 0) {
|
|
@@ -14628,13 +14632,17 @@ function createActionTools(store) {
|
|
|
14628
14632
|
}
|
|
14629
14633
|
if (typeof progress === "number") {
|
|
14630
14634
|
updates.progress = Math.max(0, Math.min(100, Math.round(progress)));
|
|
14631
|
-
updates.progressOverride = true;
|
|
14635
|
+
updates.progressOverride = progressOverride ?? true;
|
|
14632
14636
|
} else if (progress === null) {
|
|
14633
14637
|
updates.progressOverride = false;
|
|
14638
|
+
} else if (progressOverride !== void 0) {
|
|
14639
|
+
updates.progressOverride = progressOverride;
|
|
14634
14640
|
}
|
|
14635
14641
|
const doc = store.update(id, updates, content);
|
|
14636
14642
|
if (args.status !== void 0 || typeof progress === "number") {
|
|
14637
|
-
propagateProgressToAction(store, id
|
|
14643
|
+
propagateProgressToAction(store, id, {
|
|
14644
|
+
skipSelf: typeof progress === "number"
|
|
14645
|
+
});
|
|
14638
14646
|
}
|
|
14639
14647
|
return {
|
|
14640
14648
|
content: [
|
|
@@ -17867,10 +17875,11 @@ function createTaskTools(store) {
|
|
|
17867
17875
|
priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
|
|
17868
17876
|
tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)"),
|
|
17869
17877
|
workFocus: external_exports.string().optional().describe("Work focus name (e.g. 'Budget UX'). Replaces existing focus:<value> tag."),
|
|
17870
|
-
progress: external_exports.number().nullable().optional().describe("Explicit progress percentage (0-100). Overrides auto-calculation from child contributions. Pass null to clear the override and revert to auto-calculation.")
|
|
17878
|
+
progress: external_exports.number().nullable().optional().describe("Explicit progress percentage (0-100). Overrides auto-calculation from child contributions. Pass null to clear the override and revert to auto-calculation."),
|
|
17879
|
+
progressOverride: external_exports.boolean().optional().describe("Control auto-calculation lock. true = lock progress to explicit value, false = allow auto-calculation from children. When omitted: setting progress implies true, null progress implies false.")
|
|
17871
17880
|
},
|
|
17872
17881
|
async (args) => {
|
|
17873
|
-
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workFocus, progress, ...updates } = args;
|
|
17882
|
+
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workFocus, progress, progressOverride, ...updates } = args;
|
|
17874
17883
|
const warnings = [];
|
|
17875
17884
|
if (rawLinkedEpic !== void 0) {
|
|
17876
17885
|
const linkedEpics = normalizeLinkedEpics(rawLinkedEpic);
|
|
@@ -17899,13 +17908,17 @@ function createTaskTools(store) {
|
|
|
17899
17908
|
}
|
|
17900
17909
|
if (typeof progress === "number") {
|
|
17901
17910
|
updates.progress = Math.max(0, Math.min(100, Math.round(progress)));
|
|
17902
|
-
updates.progressOverride = true;
|
|
17911
|
+
updates.progressOverride = progressOverride ?? true;
|
|
17903
17912
|
} else if (progress === null) {
|
|
17904
17913
|
updates.progressOverride = false;
|
|
17914
|
+
} else if (progressOverride !== void 0) {
|
|
17915
|
+
updates.progressOverride = progressOverride;
|
|
17905
17916
|
}
|
|
17906
17917
|
const doc = store.update(id, updates, content);
|
|
17907
17918
|
if (args.status !== void 0 || typeof progress === "number") {
|
|
17908
|
-
propagateProgressFromTask(store, id
|
|
17919
|
+
propagateProgressFromTask(store, id, {
|
|
17920
|
+
skipSelf: typeof progress === "number"
|
|
17921
|
+
});
|
|
17909
17922
|
}
|
|
17910
17923
|
const parts = [`Updated task ${doc.frontmatter.id}: ${doc.frontmatter.title}`];
|
|
17911
17924
|
if (warnings.length > 0) {
|
|
@@ -19829,6 +19842,7 @@ function generateProposedActions(issues) {
|
|
|
19829
19842
|
// src/skills/builtin/jira/sprint-progress.ts
|
|
19830
19843
|
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
19831
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"]);
|
|
19832
19846
|
var BATCH_SIZE = 5;
|
|
19833
19847
|
var MAX_LINKED_ISSUES = 50;
|
|
19834
19848
|
var BLOCKED_WEIGHT_RISK_THRESHOLD = 0.3;
|
|
@@ -20755,8 +20769,16 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20755
20769
|
children.push(childReport);
|
|
20756
20770
|
}
|
|
20757
20771
|
if (children.length > 0) {
|
|
20772
|
+
const childProgressValues = children.map((c) => {
|
|
20773
|
+
const updates = c.appliedUpdates.length > 0 ? c.appliedUpdates : c.proposedUpdates;
|
|
20774
|
+
const lastStatus = findLast(updates, (u) => u.field === "status");
|
|
20775
|
+
if (lastStatus && PROGRESS_DONE_STATUSES.has(String(lastStatus.proposedValue))) return 100;
|
|
20776
|
+
const lastProgress = findLast(updates, (u) => u.field === "progress");
|
|
20777
|
+
if (lastProgress) return lastProgress.proposedValue;
|
|
20778
|
+
return c.marvinProgress;
|
|
20779
|
+
});
|
|
20758
20780
|
const rolledUpProgress = Math.round(
|
|
20759
|
-
|
|
20781
|
+
childProgressValues.reduce((s, p) => s + p, 0) / childProgressValues.length
|
|
20760
20782
|
);
|
|
20761
20783
|
if (rolledUpProgress !== currentProgress) {
|
|
20762
20784
|
proposedUpdates.push({
|
|
@@ -20771,8 +20793,14 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20771
20793
|
const signals = buildSignals(commentSignals, linkedIssues, statusDrift, proposedMarvinStatus);
|
|
20772
20794
|
const appliedUpdates = [];
|
|
20773
20795
|
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
20796
|
+
const doneArtifacts = new Set(
|
|
20797
|
+
proposedUpdates.filter((u) => u.field === "status" && PROGRESS_DONE_STATUSES.has(String(u.proposedValue))).map((u) => u.artifactId)
|
|
20798
|
+
);
|
|
20774
20799
|
for (const update of proposedUpdates) {
|
|
20775
20800
|
if (update.field === "review") continue;
|
|
20801
|
+
if (update.field === "progress" && doneArtifacts.has(update.artifactId)) {
|
|
20802
|
+
if (update.proposedValue !== 100) continue;
|
|
20803
|
+
}
|
|
20776
20804
|
try {
|
|
20777
20805
|
const updatePayload = {
|
|
20778
20806
|
[update.field]: update.proposedValue,
|
|
@@ -20782,12 +20810,14 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20782
20810
|
updatePayload.progressOverride = false;
|
|
20783
20811
|
}
|
|
20784
20812
|
store.update(update.artifactId, updatePayload);
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
if (updatedDoc
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20813
|
+
if (update.field === "status") {
|
|
20814
|
+
const updatedDoc = store.get(update.artifactId);
|
|
20815
|
+
if (updatedDoc) {
|
|
20816
|
+
if (updatedDoc.frontmatter.type === "task") {
|
|
20817
|
+
propagateProgressFromTask(store, update.artifactId);
|
|
20818
|
+
} else if (updatedDoc.frontmatter.type === "action") {
|
|
20819
|
+
propagateProgressToAction(store, update.artifactId);
|
|
20820
|
+
}
|
|
20791
20821
|
}
|
|
20792
20822
|
}
|
|
20793
20823
|
appliedUpdates.push(update);
|
|
@@ -21092,6 +21122,12 @@ function formatArtifactChild(parts, child, depth) {
|
|
|
21092
21122
|
formatArtifactChild(parts, grandchild, depth + 1);
|
|
21093
21123
|
}
|
|
21094
21124
|
}
|
|
21125
|
+
function findLast(arr, predicate) {
|
|
21126
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
21127
|
+
if (predicate(arr[i])) return arr[i];
|
|
21128
|
+
}
|
|
21129
|
+
return void 0;
|
|
21130
|
+
}
|
|
21095
21131
|
|
|
21096
21132
|
// src/skills/builtin/jira/tools.ts
|
|
21097
21133
|
var JIRA_TYPE = "jira-issue";
|