mrvn-cli 0.4.8 → 0.4.10
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 +196 -26
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +195 -25
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +196 -26
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14557,7 +14557,8 @@ function createActionTools(store) {
|
|
|
14557
14557
|
priority: external_exports.string().optional().describe("Priority (high, medium, low)"),
|
|
14558
14558
|
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
14559
14559
|
dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
|
|
14560
|
-
sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags.")
|
|
14560
|
+
sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags."),
|
|
14561
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
|
|
14561
14562
|
},
|
|
14562
14563
|
async (args) => {
|
|
14563
14564
|
const tags = [...args.tags ?? []];
|
|
@@ -14567,6 +14568,9 @@ function createActionTools(store) {
|
|
|
14567
14568
|
if (!tags.includes(tag)) tags.push(tag);
|
|
14568
14569
|
}
|
|
14569
14570
|
}
|
|
14571
|
+
if (args.workStream) {
|
|
14572
|
+
tags.push(`stream:${args.workStream}`);
|
|
14573
|
+
}
|
|
14570
14574
|
const doc = store.create(
|
|
14571
14575
|
"action",
|
|
14572
14576
|
{
|
|
@@ -14604,10 +14608,11 @@ function createActionTools(store) {
|
|
|
14604
14608
|
priority: external_exports.string().optional().describe("New priority"),
|
|
14605
14609
|
dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
|
|
14606
14610
|
tags: external_exports.array(external_exports.string()).optional().describe("Replace all tags. When provided with sprints, sprint tags are merged into this array."),
|
|
14607
|
-
sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001'].")
|
|
14611
|
+
sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001']."),
|
|
14612
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
|
|
14608
14613
|
},
|
|
14609
14614
|
async (args) => {
|
|
14610
|
-
const { id, content, sprints, tags, ...updates } = args;
|
|
14615
|
+
const { id, content, sprints, tags, workStream, ...updates } = args;
|
|
14611
14616
|
if (tags !== void 0) {
|
|
14612
14617
|
const merged = [...tags];
|
|
14613
14618
|
if (sprints) {
|
|
@@ -14616,8 +14621,14 @@ function createActionTools(store) {
|
|
|
14616
14621
|
if (!merged.includes(tag)) merged.push(tag);
|
|
14617
14622
|
}
|
|
14618
14623
|
}
|
|
14619
|
-
|
|
14620
|
-
|
|
14624
|
+
if (workStream !== void 0) {
|
|
14625
|
+
const filtered = merged.filter((t) => !t.startsWith("stream:"));
|
|
14626
|
+
filtered.push(`stream:${workStream}`);
|
|
14627
|
+
updates.tags = filtered;
|
|
14628
|
+
} else {
|
|
14629
|
+
updates.tags = merged;
|
|
14630
|
+
}
|
|
14631
|
+
} else if (sprints !== void 0 || workStream !== void 0) {
|
|
14621
14632
|
const existing = store.get(id);
|
|
14622
14633
|
if (!existing) {
|
|
14623
14634
|
return {
|
|
@@ -14625,10 +14636,16 @@ function createActionTools(store) {
|
|
|
14625
14636
|
isError: true
|
|
14626
14637
|
};
|
|
14627
14638
|
}
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14639
|
+
let existingTags = existing.frontmatter.tags ?? [];
|
|
14640
|
+
if (sprints !== void 0) {
|
|
14641
|
+
existingTags = existingTags.filter((t) => !t.startsWith("sprint:"));
|
|
14642
|
+
existingTags.push(...sprints.map((s) => `sprint:${s}`));
|
|
14643
|
+
}
|
|
14644
|
+
if (workStream !== void 0) {
|
|
14645
|
+
existingTags = existingTags.filter((t) => !t.startsWith("stream:"));
|
|
14646
|
+
existingTags.push(`stream:${workStream}`);
|
|
14647
|
+
}
|
|
14648
|
+
updates.tags = existingTags;
|
|
14632
14649
|
}
|
|
14633
14650
|
const doc = store.update(id, updates, content);
|
|
14634
14651
|
return {
|
|
@@ -14793,14 +14810,19 @@ function createDocumentTools(store) {
|
|
|
14793
14810
|
{
|
|
14794
14811
|
type: external_exports.string().optional().describe(`Filter by document type (registered types: ${store.registeredTypes.join(", ")})`),
|
|
14795
14812
|
status: external_exports.string().optional().describe("Filter by status"),
|
|
14796
|
-
tag: external_exports.string().optional().describe("Filter by tag")
|
|
14813
|
+
tag: external_exports.string().optional().describe("Filter by tag"),
|
|
14814
|
+
workStream: external_exports.string().optional().describe("Filter by work stream name (matches stream:<value> tag)")
|
|
14797
14815
|
},
|
|
14798
14816
|
async (args) => {
|
|
14799
|
-
|
|
14817
|
+
let docs = store.list({
|
|
14800
14818
|
type: args.type,
|
|
14801
14819
|
status: args.status,
|
|
14802
14820
|
tag: args.tag
|
|
14803
14821
|
});
|
|
14822
|
+
if (args.workStream) {
|
|
14823
|
+
const streamTag = `stream:${args.workStream}`;
|
|
14824
|
+
docs = docs.filter((d) => d.frontmatter.tags?.includes(streamTag));
|
|
14825
|
+
}
|
|
14804
14826
|
const summary = docs.map((d) => ({
|
|
14805
14827
|
id: d.frontmatter.id,
|
|
14806
14828
|
title: d.frontmatter.title,
|
|
@@ -15470,7 +15492,7 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15470
15492
|
});
|
|
15471
15493
|
const sprintTag = `sprint:${fm.id}`;
|
|
15472
15494
|
const workItemDocs = allDocs.filter(
|
|
15473
|
-
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
|
|
15495
|
+
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.type !== "meeting" && d.frontmatter.tags?.includes(sprintTag)
|
|
15474
15496
|
);
|
|
15475
15497
|
const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
|
|
15476
15498
|
const byStatus = {};
|
|
@@ -15493,11 +15515,13 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15493
15515
|
const sprintItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
|
|
15494
15516
|
for (const doc of workItemDocs) {
|
|
15495
15517
|
const about = doc.frontmatter.aboutArtifact;
|
|
15518
|
+
const streamTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("stream:"));
|
|
15496
15519
|
const item = {
|
|
15497
15520
|
id: doc.frontmatter.id,
|
|
15498
15521
|
title: doc.frontmatter.title,
|
|
15499
15522
|
type: doc.frontmatter.type,
|
|
15500
15523
|
status: doc.frontmatter.status,
|
|
15524
|
+
workStream: streamTag ? streamTag.slice(7) : void 0,
|
|
15501
15525
|
aboutArtifact: about
|
|
15502
15526
|
};
|
|
15503
15527
|
allItemsById.set(item.id, item);
|
|
@@ -16453,6 +16477,12 @@ a:hover { text-decoration: underline; }
|
|
|
16453
16477
|
.badge-closed, .badge-resolved { background: rgba(52, 211, 153, 0.15); color: var(--green); }
|
|
16454
16478
|
.badge-blocked { background: rgba(248, 113, 113, 0.15); color: var(--red); }
|
|
16455
16479
|
.badge-default { background: rgba(139, 143, 164, 0.1); color: var(--text-dim); }
|
|
16480
|
+
.badge-subtle {
|
|
16481
|
+
background: rgba(139, 143, 164, 0.12);
|
|
16482
|
+
color: var(--text-dim);
|
|
16483
|
+
text-transform: none;
|
|
16484
|
+
font-weight: 500;
|
|
16485
|
+
}
|
|
16456
16486
|
|
|
16457
16487
|
/* Table */
|
|
16458
16488
|
.table-wrap {
|
|
@@ -17269,6 +17299,22 @@ tr:hover td {
|
|
|
17269
17299
|
max-height: 0;
|
|
17270
17300
|
opacity: 0;
|
|
17271
17301
|
}
|
|
17302
|
+
|
|
17303
|
+
/* Sortable table headers */
|
|
17304
|
+
.sortable-th {
|
|
17305
|
+
cursor: pointer;
|
|
17306
|
+
user-select: none;
|
|
17307
|
+
}
|
|
17308
|
+
.sortable-th:hover {
|
|
17309
|
+
text-decoration: underline;
|
|
17310
|
+
color: var(--text);
|
|
17311
|
+
}
|
|
17312
|
+
.sort-arrow {
|
|
17313
|
+
display: inline-block;
|
|
17314
|
+
margin-left: 0.3rem;
|
|
17315
|
+
font-size: 0.65rem;
|
|
17316
|
+
opacity: 0.7;
|
|
17317
|
+
}
|
|
17272
17318
|
`;
|
|
17273
17319
|
}
|
|
17274
17320
|
|
|
@@ -18190,16 +18236,56 @@ function sprintSummaryPage(data, cached2) {
|
|
|
18190
18236
|
</div>`,
|
|
18191
18237
|
{ titleTag: "h3" }
|
|
18192
18238
|
) : "";
|
|
18239
|
+
const STREAM_PALETTE = [
|
|
18240
|
+
"hsla(220, 30%, 22%, 0.45)",
|
|
18241
|
+
"hsla(160, 30%, 20%, 0.45)",
|
|
18242
|
+
"hsla(280, 25%, 22%, 0.45)",
|
|
18243
|
+
"hsla(30, 35%, 22%, 0.45)",
|
|
18244
|
+
"hsla(340, 25%, 22%, 0.45)",
|
|
18245
|
+
"hsla(190, 30%, 20%, 0.45)",
|
|
18246
|
+
"hsla(60, 25%, 20%, 0.45)",
|
|
18247
|
+
"hsla(120, 20%, 20%, 0.45)"
|
|
18248
|
+
];
|
|
18249
|
+
function hashString(s) {
|
|
18250
|
+
let h = 0;
|
|
18251
|
+
for (let i = 0; i < s.length; i++) {
|
|
18252
|
+
h = (h << 5) - h + s.charCodeAt(i) | 0;
|
|
18253
|
+
}
|
|
18254
|
+
return Math.abs(h);
|
|
18255
|
+
}
|
|
18256
|
+
function collectStreams(items) {
|
|
18257
|
+
const streams = /* @__PURE__ */ new Set();
|
|
18258
|
+
for (const w of items) {
|
|
18259
|
+
if (w.workStream) streams.add(w.workStream);
|
|
18260
|
+
if (w.children) {
|
|
18261
|
+
for (const s of collectStreams(w.children)) streams.add(s);
|
|
18262
|
+
}
|
|
18263
|
+
}
|
|
18264
|
+
return streams;
|
|
18265
|
+
}
|
|
18266
|
+
const uniqueStreams = collectStreams(data.workItems.items);
|
|
18267
|
+
const streamColorMap = /* @__PURE__ */ new Map();
|
|
18268
|
+
for (const name of uniqueStreams) {
|
|
18269
|
+
streamColorMap.set(name, STREAM_PALETTE[hashString(name) % STREAM_PALETTE.length]);
|
|
18270
|
+
}
|
|
18271
|
+
const streamStyleRules = [...streamColorMap.entries()].map(([name, color]) => `tr[data-stream="${escapeHtml(name)}"] td { background: ${color}; }`).join("\n");
|
|
18272
|
+
const streamStyleBlock = streamStyleRules ? `<style>${streamStyleRules}</style>` : "";
|
|
18193
18273
|
function renderItemRows(items, depth = 0) {
|
|
18194
18274
|
return items.flatMap((w) => {
|
|
18195
18275
|
const isChild = depth > 0;
|
|
18196
18276
|
const isContribution = w.type === "contribution";
|
|
18197
|
-
const
|
|
18277
|
+
const classes = [];
|
|
18278
|
+
if (isContribution) classes.push("contribution-row");
|
|
18279
|
+
else if (isChild) classes.push("child-row");
|
|
18280
|
+
const dataStream = w.workStream ? ` data-stream="${escapeHtml(w.workStream)}"` : "";
|
|
18281
|
+
const rowAttrs = classes.length > 0 ? ` class="${classes.join(" ")}"` : "";
|
|
18198
18282
|
const indent = depth > 0 ? ` style="padding-left: ${0.75 + depth * 1}rem"` : "";
|
|
18283
|
+
const streamCell = w.workStream ? `<span class="badge badge-subtle">${escapeHtml(w.workStream)}</span>` : "";
|
|
18199
18284
|
const row = `
|
|
18200
|
-
<tr${
|
|
18285
|
+
<tr${rowAttrs}${dataStream}>
|
|
18201
18286
|
<td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
|
|
18202
18287
|
<td>${escapeHtml(w.title)}</td>
|
|
18288
|
+
<td>${streamCell}</td>
|
|
18203
18289
|
<td>${escapeHtml(typeLabel(w.type))}</td>
|
|
18204
18290
|
<td>${statusBadge(w.status)}</td>
|
|
18205
18291
|
</tr>`;
|
|
@@ -18208,13 +18294,21 @@ function sprintSummaryPage(data, cached2) {
|
|
|
18208
18294
|
});
|
|
18209
18295
|
}
|
|
18210
18296
|
const workItemRows = renderItemRows(data.workItems.items);
|
|
18297
|
+
const sortableHeaders = `<tr>
|
|
18298
|
+
<th class="sortable-th" onclick="sortWorkItems(0)">ID<span class="sort-arrow" id="sort-arrow-0"></span></th>
|
|
18299
|
+
<th class="sortable-th" onclick="sortWorkItems(1)">Title<span class="sort-arrow" id="sort-arrow-1"></span></th>
|
|
18300
|
+
<th class="sortable-th" onclick="sortWorkItems(2)">Stream<span class="sort-arrow" id="sort-arrow-2"></span></th>
|
|
18301
|
+
<th class="sortable-th" onclick="sortWorkItems(3)">Type<span class="sort-arrow" id="sort-arrow-3"></span></th>
|
|
18302
|
+
<th class="sortable-th" onclick="sortWorkItems(4)">Status<span class="sort-arrow" id="sort-arrow-4"></span></th>
|
|
18303
|
+
</tr>`;
|
|
18211
18304
|
const workItemsSection = workItemRows.length > 0 ? collapsibleSection(
|
|
18212
18305
|
"ss-work-items",
|
|
18213
18306
|
"Work Items",
|
|
18214
|
-
|
|
18215
|
-
|
|
18307
|
+
`${streamStyleBlock}
|
|
18308
|
+
<div class="table-wrap">
|
|
18309
|
+
<table id="work-items-table">
|
|
18216
18310
|
<thead>
|
|
18217
|
-
|
|
18311
|
+
${sortableHeaders}
|
|
18218
18312
|
</thead>
|
|
18219
18313
|
<tbody>
|
|
18220
18314
|
${workItemRows.join("")}
|
|
@@ -18293,6 +18387,61 @@ function sprintSummaryPage(data, cached2) {
|
|
|
18293
18387
|
</div>
|
|
18294
18388
|
|
|
18295
18389
|
<script>
|
|
18390
|
+
var _sortCol = -1;
|
|
18391
|
+
var _sortAsc = true;
|
|
18392
|
+
|
|
18393
|
+
function sortWorkItems(col) {
|
|
18394
|
+
var table = document.getElementById('work-items-table');
|
|
18395
|
+
if (!table) return;
|
|
18396
|
+
var tbody = table.querySelector('tbody');
|
|
18397
|
+
var allRows = Array.from(tbody.querySelectorAll('tr'));
|
|
18398
|
+
|
|
18399
|
+
// Toggle direction if clicking the same column
|
|
18400
|
+
if (_sortCol === col) {
|
|
18401
|
+
_sortAsc = !_sortAsc;
|
|
18402
|
+
} else {
|
|
18403
|
+
_sortCol = col;
|
|
18404
|
+
_sortAsc = true;
|
|
18405
|
+
}
|
|
18406
|
+
|
|
18407
|
+
// Update sort arrows
|
|
18408
|
+
for (var i = 0; i < 5; i++) {
|
|
18409
|
+
var arrow = document.getElementById('sort-arrow-' + i);
|
|
18410
|
+
if (arrow) arrow.textContent = i === col ? (_sortAsc ? ' \\u25B2' : ' \\u25BC') : '';
|
|
18411
|
+
}
|
|
18412
|
+
|
|
18413
|
+
// Group rows: root rows + their child/contribution rows
|
|
18414
|
+
var groups = [];
|
|
18415
|
+
var current = null;
|
|
18416
|
+
for (var r = 0; r < allRows.length; r++) {
|
|
18417
|
+
var row = allRows[r];
|
|
18418
|
+
var isChild = row.classList.contains('child-row') || row.classList.contains('contribution-row');
|
|
18419
|
+
if (!isChild) {
|
|
18420
|
+
current = { root: row, children: [] };
|
|
18421
|
+
groups.push(current);
|
|
18422
|
+
} else if (current) {
|
|
18423
|
+
current.children.push(row);
|
|
18424
|
+
}
|
|
18425
|
+
}
|
|
18426
|
+
|
|
18427
|
+
// Sort groups by root row text content of target column
|
|
18428
|
+
groups.sort(function(a, b) {
|
|
18429
|
+
var aText = (a.root.children[col] ? a.root.children[col].textContent : '').trim().toLowerCase();
|
|
18430
|
+
var bText = (b.root.children[col] ? b.root.children[col].textContent : '').trim().toLowerCase();
|
|
18431
|
+
if (aText < bText) return _sortAsc ? -1 : 1;
|
|
18432
|
+
if (aText > bText) return _sortAsc ? 1 : -1;
|
|
18433
|
+
return 0;
|
|
18434
|
+
});
|
|
18435
|
+
|
|
18436
|
+
// Re-append rows in sorted order
|
|
18437
|
+
for (var g = 0; g < groups.length; g++) {
|
|
18438
|
+
tbody.appendChild(groups[g].root);
|
|
18439
|
+
for (var c = 0; c < groups[g].children.length; c++) {
|
|
18440
|
+
tbody.appendChild(groups[g].children[c]);
|
|
18441
|
+
}
|
|
18442
|
+
}
|
|
18443
|
+
}
|
|
18444
|
+
|
|
18296
18445
|
async function generateSummary() {
|
|
18297
18446
|
var btn = document.getElementById('generate-btn');
|
|
18298
18447
|
var loading = document.getElementById('summary-loading');
|
|
@@ -19513,7 +19662,8 @@ function createContributionTools(store) {
|
|
|
19513
19662
|
contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
|
|
19514
19663
|
aboutArtifact: external_exports.string().describe("Artifact ID this contribution relates to (e.g. 'A-001', 'T-003')"),
|
|
19515
19664
|
status: external_exports.string().optional().describe("Status (default: 'done')"),
|
|
19516
|
-
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
|
|
19665
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
19666
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
|
|
19517
19667
|
},
|
|
19518
19668
|
async (args) => {
|
|
19519
19669
|
const frontmatter = {
|
|
@@ -19523,7 +19673,9 @@ function createContributionTools(store) {
|
|
|
19523
19673
|
contributionType: args.contributionType
|
|
19524
19674
|
};
|
|
19525
19675
|
frontmatter.aboutArtifact = args.aboutArtifact;
|
|
19526
|
-
|
|
19676
|
+
const tags = [...args.tags ?? []];
|
|
19677
|
+
if (args.workStream) tags.push(`stream:${args.workStream}`);
|
|
19678
|
+
if (tags.length > 0) frontmatter.tags = tags;
|
|
19527
19679
|
const doc = store.create("contribution", frontmatter, args.content);
|
|
19528
19680
|
return {
|
|
19529
19681
|
content: [
|
|
@@ -19542,10 +19694,18 @@ function createContributionTools(store) {
|
|
|
19542
19694
|
id: external_exports.string().describe("Contribution ID to update"),
|
|
19543
19695
|
title: external_exports.string().optional().describe("New title"),
|
|
19544
19696
|
status: external_exports.string().optional().describe("New status"),
|
|
19545
|
-
content: external_exports.string().optional().describe("New content")
|
|
19697
|
+
content: external_exports.string().optional().describe("New content"),
|
|
19698
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
|
|
19546
19699
|
},
|
|
19547
19700
|
async (args) => {
|
|
19548
|
-
const { id, content, ...updates } = args;
|
|
19701
|
+
const { id, content, workStream, ...updates } = args;
|
|
19702
|
+
if (workStream !== void 0) {
|
|
19703
|
+
const existing = store.get(id);
|
|
19704
|
+
const existingTags = existing?.frontmatter.tags ?? [];
|
|
19705
|
+
const filtered = existingTags.filter((t) => !t.startsWith("stream:"));
|
|
19706
|
+
filtered.push(`stream:${workStream}`);
|
|
19707
|
+
updates.tags = filtered;
|
|
19708
|
+
}
|
|
19549
19709
|
const doc = store.update(id, updates, content);
|
|
19550
19710
|
return {
|
|
19551
19711
|
content: [
|
|
@@ -20013,7 +20173,8 @@ function createTaskTools(store) {
|
|
|
20013
20173
|
estimatedPoints: external_exports.number().optional().describe("Story point estimate"),
|
|
20014
20174
|
complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("Task complexity"),
|
|
20015
20175
|
priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("Task priority"),
|
|
20016
|
-
tags: external_exports.array(external_exports.string()).optional().describe("Additional tags")
|
|
20176
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Additional tags"),
|
|
20177
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
|
|
20017
20178
|
},
|
|
20018
20179
|
async (args) => {
|
|
20019
20180
|
const linkedEpics = normalizeLinkedEpics(args.linkedEpic);
|
|
@@ -20026,11 +20187,13 @@ function createTaskTools(store) {
|
|
|
20026
20187
|
warnings.push(`Warning: ${epicId} is a ${epic.frontmatter.type}, not an epic`);
|
|
20027
20188
|
}
|
|
20028
20189
|
}
|
|
20190
|
+
const baseTags = [...generateEpicTags(linkedEpics), ...args.tags ?? []];
|
|
20191
|
+
if (args.workStream) baseTags.push(`stream:${args.workStream}`);
|
|
20029
20192
|
const frontmatter = {
|
|
20030
20193
|
title: args.title,
|
|
20031
20194
|
status: args.status ?? "backlog",
|
|
20032
20195
|
linkedEpic: linkedEpics,
|
|
20033
|
-
tags:
|
|
20196
|
+
tags: baseTags
|
|
20034
20197
|
};
|
|
20035
20198
|
if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
|
|
20036
20199
|
if (args.acceptanceCriteria) frontmatter.acceptanceCriteria = args.acceptanceCriteria;
|
|
@@ -20065,10 +20228,11 @@ function createTaskTools(store) {
|
|
|
20065
20228
|
estimatedPoints: external_exports.number().optional().describe("New story point estimate"),
|
|
20066
20229
|
complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("New complexity"),
|
|
20067
20230
|
priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
|
|
20068
|
-
tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)")
|
|
20231
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)"),
|
|
20232
|
+
workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
|
|
20069
20233
|
},
|
|
20070
20234
|
async (args) => {
|
|
20071
|
-
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, ...updates } = args;
|
|
20235
|
+
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workStream, ...updates } = args;
|
|
20072
20236
|
const warnings = [];
|
|
20073
20237
|
if (rawLinkedEpic !== void 0) {
|
|
20074
20238
|
const linkedEpics = normalizeLinkedEpics(rawLinkedEpic);
|
|
@@ -20089,6 +20253,12 @@ function createTaskTools(store) {
|
|
|
20089
20253
|
} else if (userTags !== void 0) {
|
|
20090
20254
|
updates.tags = userTags;
|
|
20091
20255
|
}
|
|
20256
|
+
if (workStream !== void 0) {
|
|
20257
|
+
const currentTags = updates.tags ?? store.get(id)?.frontmatter.tags ?? [];
|
|
20258
|
+
const filtered = currentTags.filter((t) => !t.startsWith("stream:"));
|
|
20259
|
+
filtered.push(`stream:${workStream}`);
|
|
20260
|
+
updates.tags = filtered;
|
|
20261
|
+
}
|
|
20092
20262
|
const doc = store.update(id, updates, content);
|
|
20093
20263
|
const parts = [`Updated task ${doc.frontmatter.id}: ${doc.frontmatter.title}`];
|
|
20094
20264
|
if (warnings.length > 0) {
|
|
@@ -26230,7 +26400,7 @@ function createProgram() {
|
|
|
26230
26400
|
const program = new Command();
|
|
26231
26401
|
program.name("marvin").description(
|
|
26232
26402
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
26233
|
-
).version("0.4.
|
|
26403
|
+
).version("0.4.10");
|
|
26234
26404
|
program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
26235
26405
|
await initCommand();
|
|
26236
26406
|
});
|