mrvn-cli 0.5.19 → 0.5.21
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 +56 -40
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +55 -39
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +56 -40
- 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) {
|
|
@@ -20755,11 +20768,8 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20755
20768
|
children.push(childReport);
|
|
20756
20769
|
}
|
|
20757
20770
|
if (children.length > 0) {
|
|
20758
|
-
const rolledUpProgress =
|
|
20759
|
-
children.
|
|
20760
|
-
weight: resolveWeight(void 0).weight,
|
|
20761
|
-
progress: c.marvinProgress
|
|
20762
|
-
}))
|
|
20771
|
+
const rolledUpProgress = Math.round(
|
|
20772
|
+
children.reduce((s, c) => s + c.marvinProgress, 0) / children.length
|
|
20763
20773
|
);
|
|
20764
20774
|
if (rolledUpProgress !== currentProgress) {
|
|
20765
20775
|
proposedUpdates.push({
|
|
@@ -20767,15 +20777,21 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20767
20777
|
field: "progress",
|
|
20768
20778
|
currentValue: currentProgress,
|
|
20769
20779
|
proposedValue: rolledUpProgress,
|
|
20770
|
-
reason: `Rolled up from ${children.length} children (
|
|
20780
|
+
reason: `Rolled up from ${children.length} children (average ${rolledUpProgress}%)`
|
|
20771
20781
|
});
|
|
20772
20782
|
}
|
|
20773
20783
|
}
|
|
20774
20784
|
const signals = buildSignals(commentSignals, linkedIssues, statusDrift, proposedMarvinStatus);
|
|
20775
20785
|
const appliedUpdates = [];
|
|
20776
20786
|
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
20787
|
+
const doneArtifacts = new Set(
|
|
20788
|
+
proposedUpdates.filter((u) => u.field === "status" && DONE_STATUSES6.has(String(u.proposedValue))).map((u) => u.artifactId)
|
|
20789
|
+
);
|
|
20777
20790
|
for (const update of proposedUpdates) {
|
|
20778
20791
|
if (update.field === "review") continue;
|
|
20792
|
+
if (update.field === "progress" && doneArtifacts.has(update.artifactId)) {
|
|
20793
|
+
if (update.proposedValue !== 100) continue;
|
|
20794
|
+
}
|
|
20779
20795
|
try {
|
|
20780
20796
|
const updatePayload = {
|
|
20781
20797
|
[update.field]: update.proposedValue,
|
|
@@ -20785,12 +20801,14 @@ async function _assessArtifactRecursive(store, client, host, options, visited, d
|
|
|
20785
20801
|
updatePayload.progressOverride = false;
|
|
20786
20802
|
}
|
|
20787
20803
|
store.update(update.artifactId, updatePayload);
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
if (updatedDoc
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20804
|
+
if (update.field === "status") {
|
|
20805
|
+
const updatedDoc = store.get(update.artifactId);
|
|
20806
|
+
if (updatedDoc) {
|
|
20807
|
+
if (updatedDoc.frontmatter.type === "task") {
|
|
20808
|
+
propagateProgressFromTask(store, update.artifactId);
|
|
20809
|
+
} else if (updatedDoc.frontmatter.type === "action") {
|
|
20810
|
+
propagateProgressToAction(store, update.artifactId);
|
|
20811
|
+
}
|
|
20794
20812
|
}
|
|
20795
20813
|
}
|
|
20796
20814
|
appliedUpdates.push(update);
|
|
@@ -21019,11 +21037,9 @@ function formatArtifactReport(report) {
|
|
|
21019
21037
|
}
|
|
21020
21038
|
if (report.children.length > 0) {
|
|
21021
21039
|
const doneCount = report.children.filter((c) => DONE_STATUSES6.has(c.marvinStatus)).length;
|
|
21022
|
-
const
|
|
21023
|
-
|
|
21024
|
-
|
|
21025
|
-
});
|
|
21026
|
-
const childProgress = childWeights.length > 0 ? Math.round(childWeights.reduce((s, c) => s + c.weight * c.progress, 0) / childWeights.reduce((s, c) => s + c.weight, 0)) : 0;
|
|
21040
|
+
const childProgress = Math.round(
|
|
21041
|
+
report.children.reduce((s, c) => s + c.marvinProgress, 0) / report.children.length
|
|
21042
|
+
);
|
|
21027
21043
|
const bar = progressBar(childProgress);
|
|
21028
21044
|
parts.push(`## Children (${doneCount}/${report.children.length} done) ${bar} ${childProgress}%`);
|
|
21029
21045
|
for (const child of report.children) {
|