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.
@@ -14401,7 +14401,8 @@ function createActionTools(store) {
14401
14401
  priority: external_exports.string().optional().describe("Priority (high, medium, low)"),
14402
14402
  tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
14403
14403
  dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
14404
- sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags.")
14404
+ sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags."),
14405
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
14405
14406
  },
14406
14407
  async (args) => {
14407
14408
  const tags = [...args.tags ?? []];
@@ -14411,6 +14412,9 @@ function createActionTools(store) {
14411
14412
  if (!tags.includes(tag)) tags.push(tag);
14412
14413
  }
14413
14414
  }
14415
+ if (args.workStream) {
14416
+ tags.push(`stream:${args.workStream}`);
14417
+ }
14414
14418
  const doc = store.create(
14415
14419
  "action",
14416
14420
  {
@@ -14448,10 +14452,11 @@ function createActionTools(store) {
14448
14452
  priority: external_exports.string().optional().describe("New priority"),
14449
14453
  dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
14450
14454
  tags: external_exports.array(external_exports.string()).optional().describe("Replace all tags. When provided with sprints, sprint tags are merged into this array."),
14451
- sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001'].")
14455
+ sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001']."),
14456
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
14452
14457
  },
14453
14458
  async (args) => {
14454
- const { id, content, sprints, tags, ...updates } = args;
14459
+ const { id, content, sprints, tags, workStream, ...updates } = args;
14455
14460
  if (tags !== void 0) {
14456
14461
  const merged = [...tags];
14457
14462
  if (sprints) {
@@ -14460,8 +14465,14 @@ function createActionTools(store) {
14460
14465
  if (!merged.includes(tag)) merged.push(tag);
14461
14466
  }
14462
14467
  }
14463
- updates.tags = merged;
14464
- } else if (sprints !== void 0) {
14468
+ if (workStream !== void 0) {
14469
+ const filtered = merged.filter((t) => !t.startsWith("stream:"));
14470
+ filtered.push(`stream:${workStream}`);
14471
+ updates.tags = filtered;
14472
+ } else {
14473
+ updates.tags = merged;
14474
+ }
14475
+ } else if (sprints !== void 0 || workStream !== void 0) {
14465
14476
  const existing = store.get(id);
14466
14477
  if (!existing) {
14467
14478
  return {
@@ -14469,10 +14480,16 @@ function createActionTools(store) {
14469
14480
  isError: true
14470
14481
  };
14471
14482
  }
14472
- const existingTags = existing.frontmatter.tags ?? [];
14473
- const nonSprintTags = existingTags.filter((t) => !t.startsWith("sprint:"));
14474
- const newSprintTags = sprints.map((s) => `sprint:${s}`);
14475
- updates.tags = [...nonSprintTags, ...newSprintTags];
14483
+ let existingTags = existing.frontmatter.tags ?? [];
14484
+ if (sprints !== void 0) {
14485
+ existingTags = existingTags.filter((t) => !t.startsWith("sprint:"));
14486
+ existingTags.push(...sprints.map((s) => `sprint:${s}`));
14487
+ }
14488
+ if (workStream !== void 0) {
14489
+ existingTags = existingTags.filter((t) => !t.startsWith("stream:"));
14490
+ existingTags.push(`stream:${workStream}`);
14491
+ }
14492
+ updates.tags = existingTags;
14476
14493
  }
14477
14494
  const doc = store.update(id, updates, content);
14478
14495
  return {
@@ -14637,14 +14654,19 @@ function createDocumentTools(store) {
14637
14654
  {
14638
14655
  type: external_exports.string().optional().describe(`Filter by document type (registered types: ${store.registeredTypes.join(", ")})`),
14639
14656
  status: external_exports.string().optional().describe("Filter by status"),
14640
- tag: external_exports.string().optional().describe("Filter by tag")
14657
+ tag: external_exports.string().optional().describe("Filter by tag"),
14658
+ workStream: external_exports.string().optional().describe("Filter by work stream name (matches stream:<value> tag)")
14641
14659
  },
14642
14660
  async (args) => {
14643
- const docs = store.list({
14661
+ let docs = store.list({
14644
14662
  type: args.type,
14645
14663
  status: args.status,
14646
14664
  tag: args.tag
14647
14665
  });
14666
+ if (args.workStream) {
14667
+ const streamTag = `stream:${args.workStream}`;
14668
+ docs = docs.filter((d) => d.frontmatter.tags?.includes(streamTag));
14669
+ }
14648
14670
  const summary = docs.map((d) => ({
14649
14671
  id: d.frontmatter.id,
14650
14672
  title: d.frontmatter.title,
@@ -15558,7 +15580,7 @@ function collectSprintSummaryData(store, sprintId) {
15558
15580
  });
15559
15581
  const sprintTag = `sprint:${fm.id}`;
15560
15582
  const workItemDocs = allDocs.filter(
15561
- (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
15583
+ (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.type !== "meeting" && d.frontmatter.tags?.includes(sprintTag)
15562
15584
  );
15563
15585
  const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
15564
15586
  const byStatus = {};
@@ -15581,11 +15603,13 @@ function collectSprintSummaryData(store, sprintId) {
15581
15603
  const sprintItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
15582
15604
  for (const doc of workItemDocs) {
15583
15605
  const about = doc.frontmatter.aboutArtifact;
15606
+ const streamTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("stream:"));
15584
15607
  const item = {
15585
15608
  id: doc.frontmatter.id,
15586
15609
  title: doc.frontmatter.title,
15587
15610
  type: doc.frontmatter.type,
15588
15611
  status: doc.frontmatter.status,
15612
+ workStream: streamTag ? streamTag.slice(7) : void 0,
15589
15613
  aboutArtifact: about
15590
15614
  };
15591
15615
  allItemsById.set(item.id, item);
@@ -16605,7 +16629,8 @@ function createContributionTools(store) {
16605
16629
  contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
16606
16630
  aboutArtifact: external_exports.string().describe("Artifact ID this contribution relates to (e.g. 'A-001', 'T-003')"),
16607
16631
  status: external_exports.string().optional().describe("Status (default: 'done')"),
16608
- tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
16632
+ tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
16633
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
16609
16634
  },
16610
16635
  async (args) => {
16611
16636
  const frontmatter = {
@@ -16615,7 +16640,9 @@ function createContributionTools(store) {
16615
16640
  contributionType: args.contributionType
16616
16641
  };
16617
16642
  frontmatter.aboutArtifact = args.aboutArtifact;
16618
- if (args.tags) frontmatter.tags = args.tags;
16643
+ const tags = [...args.tags ?? []];
16644
+ if (args.workStream) tags.push(`stream:${args.workStream}`);
16645
+ if (tags.length > 0) frontmatter.tags = tags;
16619
16646
  const doc = store.create("contribution", frontmatter, args.content);
16620
16647
  return {
16621
16648
  content: [
@@ -16634,10 +16661,18 @@ function createContributionTools(store) {
16634
16661
  id: external_exports.string().describe("Contribution ID to update"),
16635
16662
  title: external_exports.string().optional().describe("New title"),
16636
16663
  status: external_exports.string().optional().describe("New status"),
16637
- content: external_exports.string().optional().describe("New content")
16664
+ content: external_exports.string().optional().describe("New content"),
16665
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
16638
16666
  },
16639
16667
  async (args) => {
16640
- const { id, content, ...updates } = args;
16668
+ const { id, content, workStream, ...updates } = args;
16669
+ if (workStream !== void 0) {
16670
+ const existing = store.get(id);
16671
+ const existingTags = existing?.frontmatter.tags ?? [];
16672
+ const filtered = existingTags.filter((t) => !t.startsWith("stream:"));
16673
+ filtered.push(`stream:${workStream}`);
16674
+ updates.tags = filtered;
16675
+ }
16641
16676
  const doc = store.update(id, updates, content);
16642
16677
  return {
16643
16678
  content: [
@@ -17105,7 +17140,8 @@ function createTaskTools(store) {
17105
17140
  estimatedPoints: external_exports.number().optional().describe("Story point estimate"),
17106
17141
  complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("Task complexity"),
17107
17142
  priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("Task priority"),
17108
- tags: external_exports.array(external_exports.string()).optional().describe("Additional tags")
17143
+ tags: external_exports.array(external_exports.string()).optional().describe("Additional tags"),
17144
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
17109
17145
  },
17110
17146
  async (args) => {
17111
17147
  const linkedEpics = normalizeLinkedEpics(args.linkedEpic);
@@ -17118,11 +17154,13 @@ function createTaskTools(store) {
17118
17154
  warnings.push(`Warning: ${epicId} is a ${epic.frontmatter.type}, not an epic`);
17119
17155
  }
17120
17156
  }
17157
+ const baseTags = [...generateEpicTags(linkedEpics), ...args.tags ?? []];
17158
+ if (args.workStream) baseTags.push(`stream:${args.workStream}`);
17121
17159
  const frontmatter = {
17122
17160
  title: args.title,
17123
17161
  status: args.status ?? "backlog",
17124
17162
  linkedEpic: linkedEpics,
17125
- tags: [...generateEpicTags(linkedEpics), ...args.tags ?? []]
17163
+ tags: baseTags
17126
17164
  };
17127
17165
  if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
17128
17166
  if (args.acceptanceCriteria) frontmatter.acceptanceCriteria = args.acceptanceCriteria;
@@ -17157,10 +17195,11 @@ function createTaskTools(store) {
17157
17195
  estimatedPoints: external_exports.number().optional().describe("New story point estimate"),
17158
17196
  complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("New complexity"),
17159
17197
  priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
17160
- tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)")
17198
+ tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)"),
17199
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
17161
17200
  },
17162
17201
  async (args) => {
17163
- const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, ...updates } = args;
17202
+ const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workStream, ...updates } = args;
17164
17203
  const warnings = [];
17165
17204
  if (rawLinkedEpic !== void 0) {
17166
17205
  const linkedEpics = normalizeLinkedEpics(rawLinkedEpic);
@@ -17181,6 +17220,12 @@ function createTaskTools(store) {
17181
17220
  } else if (userTags !== void 0) {
17182
17221
  updates.tags = userTags;
17183
17222
  }
17223
+ if (workStream !== void 0) {
17224
+ const currentTags = updates.tags ?? store.get(id)?.frontmatter.tags ?? [];
17225
+ const filtered = currentTags.filter((t) => !t.startsWith("stream:"));
17226
+ filtered.push(`stream:${workStream}`);
17227
+ updates.tags = filtered;
17228
+ }
17184
17229
  const doc = store.update(id, updates, content);
17185
17230
  const parts = [`Updated task ${doc.frontmatter.id}: ${doc.frontmatter.title}`];
17186
17231
  if (warnings.length > 0) {
@@ -20210,6 +20255,12 @@ a:hover { text-decoration: underline; }
20210
20255
  .badge-closed, .badge-resolved { background: rgba(52, 211, 153, 0.15); color: var(--green); }
20211
20256
  .badge-blocked { background: rgba(248, 113, 113, 0.15); color: var(--red); }
20212
20257
  .badge-default { background: rgba(139, 143, 164, 0.1); color: var(--text-dim); }
20258
+ .badge-subtle {
20259
+ background: rgba(139, 143, 164, 0.12);
20260
+ color: var(--text-dim);
20261
+ text-transform: none;
20262
+ font-weight: 500;
20263
+ }
20213
20264
 
20214
20265
  /* Table */
20215
20266
  .table-wrap {
@@ -21026,6 +21077,22 @@ tr:hover td {
21026
21077
  max-height: 0;
21027
21078
  opacity: 0;
21028
21079
  }
21080
+
21081
+ /* Sortable table headers */
21082
+ .sortable-th {
21083
+ cursor: pointer;
21084
+ user-select: none;
21085
+ }
21086
+ .sortable-th:hover {
21087
+ text-decoration: underline;
21088
+ color: var(--text);
21089
+ }
21090
+ .sort-arrow {
21091
+ display: inline-block;
21092
+ margin-left: 0.3rem;
21093
+ font-size: 0.65rem;
21094
+ opacity: 0.7;
21095
+ }
21029
21096
  `;
21030
21097
  }
21031
21098
 
@@ -21947,16 +22014,56 @@ function sprintSummaryPage(data, cached2) {
21947
22014
  </div>`,
21948
22015
  { titleTag: "h3" }
21949
22016
  ) : "";
22017
+ const STREAM_PALETTE = [
22018
+ "hsla(220, 30%, 22%, 0.45)",
22019
+ "hsla(160, 30%, 20%, 0.45)",
22020
+ "hsla(280, 25%, 22%, 0.45)",
22021
+ "hsla(30, 35%, 22%, 0.45)",
22022
+ "hsla(340, 25%, 22%, 0.45)",
22023
+ "hsla(190, 30%, 20%, 0.45)",
22024
+ "hsla(60, 25%, 20%, 0.45)",
22025
+ "hsla(120, 20%, 20%, 0.45)"
22026
+ ];
22027
+ function hashString(s) {
22028
+ let h = 0;
22029
+ for (let i = 0; i < s.length; i++) {
22030
+ h = (h << 5) - h + s.charCodeAt(i) | 0;
22031
+ }
22032
+ return Math.abs(h);
22033
+ }
22034
+ function collectStreams(items) {
22035
+ const streams = /* @__PURE__ */ new Set();
22036
+ for (const w of items) {
22037
+ if (w.workStream) streams.add(w.workStream);
22038
+ if (w.children) {
22039
+ for (const s of collectStreams(w.children)) streams.add(s);
22040
+ }
22041
+ }
22042
+ return streams;
22043
+ }
22044
+ const uniqueStreams = collectStreams(data.workItems.items);
22045
+ const streamColorMap = /* @__PURE__ */ new Map();
22046
+ for (const name of uniqueStreams) {
22047
+ streamColorMap.set(name, STREAM_PALETTE[hashString(name) % STREAM_PALETTE.length]);
22048
+ }
22049
+ const streamStyleRules = [...streamColorMap.entries()].map(([name, color]) => `tr[data-stream="${escapeHtml(name)}"] td { background: ${color}; }`).join("\n");
22050
+ const streamStyleBlock = streamStyleRules ? `<style>${streamStyleRules}</style>` : "";
21950
22051
  function renderItemRows(items, depth = 0) {
21951
22052
  return items.flatMap((w) => {
21952
22053
  const isChild = depth > 0;
21953
22054
  const isContribution = w.type === "contribution";
21954
- const rowClass = isContribution ? ' class="contribution-row"' : isChild ? ' class="child-row"' : "";
22055
+ const classes = [];
22056
+ if (isContribution) classes.push("contribution-row");
22057
+ else if (isChild) classes.push("child-row");
22058
+ const dataStream = w.workStream ? ` data-stream="${escapeHtml(w.workStream)}"` : "";
22059
+ const rowAttrs = classes.length > 0 ? ` class="${classes.join(" ")}"` : "";
21955
22060
  const indent = depth > 0 ? ` style="padding-left: ${0.75 + depth * 1}rem"` : "";
22061
+ const streamCell = w.workStream ? `<span class="badge badge-subtle">${escapeHtml(w.workStream)}</span>` : "";
21956
22062
  const row = `
21957
- <tr${rowClass}>
22063
+ <tr${rowAttrs}${dataStream}>
21958
22064
  <td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
21959
22065
  <td>${escapeHtml(w.title)}</td>
22066
+ <td>${streamCell}</td>
21960
22067
  <td>${escapeHtml(typeLabel(w.type))}</td>
21961
22068
  <td>${statusBadge(w.status)}</td>
21962
22069
  </tr>`;
@@ -21965,13 +22072,21 @@ function sprintSummaryPage(data, cached2) {
21965
22072
  });
21966
22073
  }
21967
22074
  const workItemRows = renderItemRows(data.workItems.items);
22075
+ const sortableHeaders = `<tr>
22076
+ <th class="sortable-th" onclick="sortWorkItems(0)">ID<span class="sort-arrow" id="sort-arrow-0"></span></th>
22077
+ <th class="sortable-th" onclick="sortWorkItems(1)">Title<span class="sort-arrow" id="sort-arrow-1"></span></th>
22078
+ <th class="sortable-th" onclick="sortWorkItems(2)">Stream<span class="sort-arrow" id="sort-arrow-2"></span></th>
22079
+ <th class="sortable-th" onclick="sortWorkItems(3)">Type<span class="sort-arrow" id="sort-arrow-3"></span></th>
22080
+ <th class="sortable-th" onclick="sortWorkItems(4)">Status<span class="sort-arrow" id="sort-arrow-4"></span></th>
22081
+ </tr>`;
21968
22082
  const workItemsSection = workItemRows.length > 0 ? collapsibleSection(
21969
22083
  "ss-work-items",
21970
22084
  "Work Items",
21971
- `<div class="table-wrap">
21972
- <table>
22085
+ `${streamStyleBlock}
22086
+ <div class="table-wrap">
22087
+ <table id="work-items-table">
21973
22088
  <thead>
21974
- <tr><th>ID</th><th>Title</th><th>Type</th><th>Status</th></tr>
22089
+ ${sortableHeaders}
21975
22090
  </thead>
21976
22091
  <tbody>
21977
22092
  ${workItemRows.join("")}
@@ -22050,6 +22165,61 @@ function sprintSummaryPage(data, cached2) {
22050
22165
  </div>
22051
22166
 
22052
22167
  <script>
22168
+ var _sortCol = -1;
22169
+ var _sortAsc = true;
22170
+
22171
+ function sortWorkItems(col) {
22172
+ var table = document.getElementById('work-items-table');
22173
+ if (!table) return;
22174
+ var tbody = table.querySelector('tbody');
22175
+ var allRows = Array.from(tbody.querySelectorAll('tr'));
22176
+
22177
+ // Toggle direction if clicking the same column
22178
+ if (_sortCol === col) {
22179
+ _sortAsc = !_sortAsc;
22180
+ } else {
22181
+ _sortCol = col;
22182
+ _sortAsc = true;
22183
+ }
22184
+
22185
+ // Update sort arrows
22186
+ for (var i = 0; i < 5; i++) {
22187
+ var arrow = document.getElementById('sort-arrow-' + i);
22188
+ if (arrow) arrow.textContent = i === col ? (_sortAsc ? ' \\u25B2' : ' \\u25BC') : '';
22189
+ }
22190
+
22191
+ // Group rows: root rows + their child/contribution rows
22192
+ var groups = [];
22193
+ var current = null;
22194
+ for (var r = 0; r < allRows.length; r++) {
22195
+ var row = allRows[r];
22196
+ var isChild = row.classList.contains('child-row') || row.classList.contains('contribution-row');
22197
+ if (!isChild) {
22198
+ current = { root: row, children: [] };
22199
+ groups.push(current);
22200
+ } else if (current) {
22201
+ current.children.push(row);
22202
+ }
22203
+ }
22204
+
22205
+ // Sort groups by root row text content of target column
22206
+ groups.sort(function(a, b) {
22207
+ var aText = (a.root.children[col] ? a.root.children[col].textContent : '').trim().toLowerCase();
22208
+ var bText = (b.root.children[col] ? b.root.children[col].textContent : '').trim().toLowerCase();
22209
+ if (aText < bText) return _sortAsc ? -1 : 1;
22210
+ if (aText > bText) return _sortAsc ? 1 : -1;
22211
+ return 0;
22212
+ });
22213
+
22214
+ // Re-append rows in sorted order
22215
+ for (var g = 0; g < groups.length; g++) {
22216
+ tbody.appendChild(groups[g].root);
22217
+ for (var c = 0; c < groups[g].children.length; c++) {
22218
+ tbody.appendChild(groups[g].children[c]);
22219
+ }
22220
+ }
22221
+ }
22222
+
22053
22223
  async function generateSummary() {
22054
22224
  var btn = document.getElementById('generate-btn');
22055
22225
  var loading = document.getElementById('summary-loading');