mrvn-cli 0.4.7 → 0.4.8

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/marvin.js CHANGED
@@ -14573,13 +14573,14 @@ function collectSprintSummaryData(store, sprintId) {
14573
14573
  const workItemDocs = allDocs.filter(
14574
14574
  (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
14575
14575
  );
14576
+ const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
14576
14577
  const byStatus = {};
14577
14578
  const byType = {};
14578
14579
  let doneCount = 0;
14579
14580
  let inProgressCount = 0;
14580
14581
  let openCount = 0;
14581
14582
  let blockedCount = 0;
14582
- for (const doc of workItemDocs) {
14583
+ for (const doc of primaryDocs) {
14583
14584
  const s = doc.frontmatter.status;
14584
14585
  byStatus[s] = (byStatus[s] ?? 0) + 1;
14585
14586
  byType[doc.frontmatter.type] = (byType[doc.frontmatter.type] ?? 0) + 1;
@@ -14588,21 +14589,59 @@ function collectSprintSummaryData(store, sprintId) {
14588
14589
  else if (s === "blocked") blockedCount++;
14589
14590
  else openCount++;
14590
14591
  }
14592
+ const allItemsById = /* @__PURE__ */ new Map();
14593
+ const childrenByParent = /* @__PURE__ */ new Map();
14594
+ const sprintItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
14595
+ for (const doc of workItemDocs) {
14596
+ const about = doc.frontmatter.aboutArtifact;
14597
+ const item = {
14598
+ id: doc.frontmatter.id,
14599
+ title: doc.frontmatter.title,
14600
+ type: doc.frontmatter.type,
14601
+ status: doc.frontmatter.status,
14602
+ aboutArtifact: about
14603
+ };
14604
+ allItemsById.set(item.id, item);
14605
+ if (about && sprintItemIds.has(about)) {
14606
+ if (!childrenByParent.has(about)) childrenByParent.set(about, []);
14607
+ childrenByParent.get(about).push(item);
14608
+ }
14609
+ }
14610
+ const itemsWithChildren = /* @__PURE__ */ new Set();
14611
+ for (const [parentId, children] of childrenByParent) {
14612
+ const parent = allItemsById.get(parentId);
14613
+ if (parent) {
14614
+ parent.children = children;
14615
+ for (const child of children) itemsWithChildren.add(child.id);
14616
+ }
14617
+ }
14618
+ for (const item of allItemsById.values()) {
14619
+ if (item.children) {
14620
+ for (const child of item.children) {
14621
+ const grandchildren = childrenByParent.get(child.id);
14622
+ if (grandchildren) {
14623
+ child.children = grandchildren;
14624
+ for (const gc of grandchildren) itemsWithChildren.add(gc.id);
14625
+ }
14626
+ }
14627
+ }
14628
+ }
14629
+ const items = [];
14630
+ for (const doc of workItemDocs) {
14631
+ if (!itemsWithChildren.has(doc.frontmatter.id)) {
14632
+ items.push(allItemsById.get(doc.frontmatter.id));
14633
+ }
14634
+ }
14591
14635
  const workItems = {
14592
- total: workItemDocs.length,
14636
+ total: primaryDocs.length,
14593
14637
  done: doneCount,
14594
14638
  inProgress: inProgressCount,
14595
14639
  open: openCount,
14596
14640
  blocked: blockedCount,
14597
- completionPct: workItemDocs.length > 0 ? Math.round(doneCount / workItemDocs.length * 100) : 0,
14641
+ completionPct: primaryDocs.length > 0 ? Math.round(doneCount / primaryDocs.length * 100) : 0,
14598
14642
  byStatus,
14599
14643
  byType,
14600
- items: workItemDocs.map((d) => ({
14601
- id: d.frontmatter.id,
14602
- title: d.frontmatter.title,
14603
- type: d.frontmatter.type,
14604
- status: d.frontmatter.status
14605
- }))
14644
+ items
14606
14645
  };
14607
14646
  const meetings = [];
14608
14647
  if (startDate && endDate) {
@@ -14684,7 +14723,7 @@ function collectSprintSummaryData(store, sprintId) {
14684
14723
  const prev = completedSprints[0];
14685
14724
  const prevTag = `sprint:${prev.frontmatter.id}`;
14686
14725
  const prevWorkItems = allDocs.filter(
14687
- (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(prevTag)
14726
+ (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.type !== "contribution" && d.frontmatter.tags?.includes(prevTag)
14688
14727
  );
14689
14728
  const prevDone = prevWorkItems.filter((d) => DONE_STATUSES.has(d.frontmatter.status)).length;
14690
14729
  const prevRate = prevWorkItems.length > 0 ? Math.round(prevDone / prevWorkItems.length * 100) : 0;
@@ -15577,18 +15616,18 @@ function createContributionTools(store) {
15577
15616
  content: external_exports.string().describe("Contribution content \u2014 the input from the persona"),
15578
15617
  persona: external_exports.string().describe("Persona making the contribution (e.g. 'tech-lead')"),
15579
15618
  contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
15580
- aboutArtifact: external_exports.string().optional().describe("Artifact ID this contribution relates to (e.g. 'A-001')"),
15581
- status: external_exports.string().optional().describe("Status (default: 'open')"),
15619
+ aboutArtifact: external_exports.string().describe("Artifact ID this contribution relates to (e.g. 'A-001', 'T-003')"),
15620
+ status: external_exports.string().optional().describe("Status (default: 'done')"),
15582
15621
  tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
15583
15622
  },
15584
15623
  async (args) => {
15585
15624
  const frontmatter = {
15586
15625
  title: args.title,
15587
- status: args.status ?? "open",
15626
+ status: args.status ?? "done",
15588
15627
  persona: args.persona,
15589
15628
  contributionType: args.contributionType
15590
15629
  };
15591
- if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
15630
+ frontmatter.aboutArtifact = args.aboutArtifact;
15592
15631
  if (args.tags) frontmatter.tags = args.tags;
15593
15632
  const doc = store.create("contribution", frontmatter, args.content);
15594
15633
  return {
@@ -16072,6 +16111,7 @@ function createTaskTools(store) {
16072
16111
  title: external_exports.string().describe("Task title"),
16073
16112
  content: external_exports.string().describe("Task description and implementation details"),
16074
16113
  linkedEpic: linkedEpicArray.describe("Epic ID(s) to link this task to (e.g. ['E-001'] or ['E-001', 'E-002'])"),
16114
+ aboutArtifact: external_exports.string().optional().describe("Parent artifact this task derives from (e.g. 'A-001')"),
16075
16115
  status: external_exports.enum(["backlog", "ready", "in-progress", "review", "done"]).optional().describe("Task status (default: 'backlog')"),
16076
16116
  acceptanceCriteria: external_exports.string().optional().describe("Acceptance criteria for the task"),
16077
16117
  technicalNotes: external_exports.string().optional().describe("Technical implementation notes"),
@@ -16097,6 +16137,7 @@ function createTaskTools(store) {
16097
16137
  linkedEpic: linkedEpics,
16098
16138
  tags: [...generateEpicTags(linkedEpics), ...args.tags ?? []]
16099
16139
  };
16140
+ if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
16100
16141
  if (args.acceptanceCriteria) frontmatter.acceptanceCriteria = args.acceptanceCriteria;
16101
16142
  if (args.technicalNotes) frontmatter.technicalNotes = args.technicalNotes;
16102
16143
  if (args.estimatedPoints !== void 0) frontmatter.estimatedPoints = args.estimatedPoints;
@@ -16120,6 +16161,7 @@ function createTaskTools(store) {
16120
16161
  {
16121
16162
  id: external_exports.string().describe("Task ID to update"),
16122
16163
  title: external_exports.string().optional().describe("New title"),
16164
+ aboutArtifact: external_exports.string().optional().describe("Parent artifact this task derives from (e.g. 'A-001')"),
16123
16165
  status: external_exports.enum(["backlog", "ready", "in-progress", "review", "done"]).optional().describe("New status"),
16124
16166
  content: external_exports.string().optional().describe("New content"),
16125
16167
  linkedEpic: linkedEpicArray.optional().describe("New linked epic ID(s)"),
@@ -19419,6 +19461,17 @@ tr:hover td {
19419
19461
  background: var(--bg-hover);
19420
19462
  }
19421
19463
 
19464
+ /* Hierarchical work-item sub-rows */
19465
+ .child-row td {
19466
+ font-size: 0.8125rem;
19467
+ border-bottom-style: dashed;
19468
+ }
19469
+ .contribution-row td {
19470
+ font-size: 0.8125rem;
19471
+ color: var(--text-dim);
19472
+ border-bottom-style: dashed;
19473
+ }
19474
+
19422
19475
  /* GAR */
19423
19476
  .gar-overall {
19424
19477
  text-align: center;
@@ -21106,7 +21159,25 @@ function sprintSummaryPage(data, cached2) {
21106
21159
  </div>`,
21107
21160
  { titleTag: "h3" }
21108
21161
  ) : "";
21109
- const workItemsSection = data.workItems.total > 0 ? collapsibleSection(
21162
+ function renderItemRows(items, depth = 0) {
21163
+ return items.flatMap((w) => {
21164
+ const isChild = depth > 0;
21165
+ const isContribution = w.type === "contribution";
21166
+ const rowClass = isContribution ? ' class="contribution-row"' : isChild ? ' class="child-row"' : "";
21167
+ const indent = depth > 0 ? ` style="padding-left: ${0.75 + depth * 1}rem"` : "";
21168
+ const row = `
21169
+ <tr${rowClass}>
21170
+ <td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
21171
+ <td>${escapeHtml(w.title)}</td>
21172
+ <td>${escapeHtml(typeLabel(w.type))}</td>
21173
+ <td>${statusBadge(w.status)}</td>
21174
+ </tr>`;
21175
+ const childRows = w.children ? renderItemRows(w.children, depth + 1) : [];
21176
+ return [row, ...childRows];
21177
+ });
21178
+ }
21179
+ const workItemRows = renderItemRows(data.workItems.items);
21180
+ const workItemsSection = workItemRows.length > 0 ? collapsibleSection(
21110
21181
  "ss-work-items",
21111
21182
  "Work Items",
21112
21183
  `<div class="table-wrap">
@@ -21115,13 +21186,7 @@ function sprintSummaryPage(data, cached2) {
21115
21186
  <tr><th>ID</th><th>Title</th><th>Type</th><th>Status</th></tr>
21116
21187
  </thead>
21117
21188
  <tbody>
21118
- ${data.workItems.items.map((w) => `
21119
- <tr>
21120
- <td><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
21121
- <td>${escapeHtml(w.title)}</td>
21122
- <td>${escapeHtml(typeLabel(w.type))}</td>
21123
- <td>${statusBadge(w.status)}</td>
21124
- </tr>`).join("")}
21189
+ ${workItemRows.join("")}
21125
21190
  </tbody>
21126
21191
  </table>
21127
21192
  </div>`,
@@ -26159,7 +26224,7 @@ function createProgram() {
26159
26224
  const program2 = new Command();
26160
26225
  program2.name("marvin").description(
26161
26226
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
26162
- ).version("0.4.7");
26227
+ ).version("0.4.8");
26163
26228
  program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
26164
26229
  await initCommand();
26165
26230
  });