mrvn-cli 0.4.7 → 0.4.9
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/README.md +7 -1
- package/dist/index.js +155 -43
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +154 -42
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +155 -43
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin-serve.js
CHANGED
|
@@ -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
|
-
|
|
14464
|
-
|
|
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
|
-
|
|
14473
|
-
|
|
14474
|
-
|
|
14475
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -15560,13 +15582,14 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15560
15582
|
const workItemDocs = allDocs.filter(
|
|
15561
15583
|
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
|
|
15562
15584
|
);
|
|
15585
|
+
const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
|
|
15563
15586
|
const byStatus = {};
|
|
15564
15587
|
const byType = {};
|
|
15565
15588
|
let doneCount = 0;
|
|
15566
15589
|
let inProgressCount = 0;
|
|
15567
15590
|
let openCount = 0;
|
|
15568
15591
|
let blockedCount = 0;
|
|
15569
|
-
for (const doc of
|
|
15592
|
+
for (const doc of primaryDocs) {
|
|
15570
15593
|
const s = doc.frontmatter.status;
|
|
15571
15594
|
byStatus[s] = (byStatus[s] ?? 0) + 1;
|
|
15572
15595
|
byType[doc.frontmatter.type] = (byType[doc.frontmatter.type] ?? 0) + 1;
|
|
@@ -15575,21 +15598,61 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15575
15598
|
else if (s === "blocked") blockedCount++;
|
|
15576
15599
|
else openCount++;
|
|
15577
15600
|
}
|
|
15601
|
+
const allItemsById = /* @__PURE__ */ new Map();
|
|
15602
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
15603
|
+
const sprintItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
|
|
15604
|
+
for (const doc of workItemDocs) {
|
|
15605
|
+
const about = doc.frontmatter.aboutArtifact;
|
|
15606
|
+
const streamTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("stream:"));
|
|
15607
|
+
const item = {
|
|
15608
|
+
id: doc.frontmatter.id,
|
|
15609
|
+
title: doc.frontmatter.title,
|
|
15610
|
+
type: doc.frontmatter.type,
|
|
15611
|
+
status: doc.frontmatter.status,
|
|
15612
|
+
workStream: streamTag ? streamTag.slice(7) : void 0,
|
|
15613
|
+
aboutArtifact: about
|
|
15614
|
+
};
|
|
15615
|
+
allItemsById.set(item.id, item);
|
|
15616
|
+
if (about && sprintItemIds.has(about)) {
|
|
15617
|
+
if (!childrenByParent.has(about)) childrenByParent.set(about, []);
|
|
15618
|
+
childrenByParent.get(about).push(item);
|
|
15619
|
+
}
|
|
15620
|
+
}
|
|
15621
|
+
const itemsWithChildren = /* @__PURE__ */ new Set();
|
|
15622
|
+
for (const [parentId, children] of childrenByParent) {
|
|
15623
|
+
const parent = allItemsById.get(parentId);
|
|
15624
|
+
if (parent) {
|
|
15625
|
+
parent.children = children;
|
|
15626
|
+
for (const child of children) itemsWithChildren.add(child.id);
|
|
15627
|
+
}
|
|
15628
|
+
}
|
|
15629
|
+
for (const item of allItemsById.values()) {
|
|
15630
|
+
if (item.children) {
|
|
15631
|
+
for (const child of item.children) {
|
|
15632
|
+
const grandchildren = childrenByParent.get(child.id);
|
|
15633
|
+
if (grandchildren) {
|
|
15634
|
+
child.children = grandchildren;
|
|
15635
|
+
for (const gc of grandchildren) itemsWithChildren.add(gc.id);
|
|
15636
|
+
}
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15639
|
+
}
|
|
15640
|
+
const items = [];
|
|
15641
|
+
for (const doc of workItemDocs) {
|
|
15642
|
+
if (!itemsWithChildren.has(doc.frontmatter.id)) {
|
|
15643
|
+
items.push(allItemsById.get(doc.frontmatter.id));
|
|
15644
|
+
}
|
|
15645
|
+
}
|
|
15578
15646
|
const workItems = {
|
|
15579
|
-
total:
|
|
15647
|
+
total: primaryDocs.length,
|
|
15580
15648
|
done: doneCount,
|
|
15581
15649
|
inProgress: inProgressCount,
|
|
15582
15650
|
open: openCount,
|
|
15583
15651
|
blocked: blockedCount,
|
|
15584
|
-
completionPct:
|
|
15652
|
+
completionPct: primaryDocs.length > 0 ? Math.round(doneCount / primaryDocs.length * 100) : 0,
|
|
15585
15653
|
byStatus,
|
|
15586
15654
|
byType,
|
|
15587
|
-
items
|
|
15588
|
-
id: d.frontmatter.id,
|
|
15589
|
-
title: d.frontmatter.title,
|
|
15590
|
-
type: d.frontmatter.type,
|
|
15591
|
-
status: d.frontmatter.status
|
|
15592
|
-
}))
|
|
15655
|
+
items
|
|
15593
15656
|
};
|
|
15594
15657
|
const meetings = [];
|
|
15595
15658
|
if (startDate && endDate) {
|
|
@@ -15671,7 +15734,7 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15671
15734
|
const prev = completedSprints[0];
|
|
15672
15735
|
const prevTag = `sprint:${prev.frontmatter.id}`;
|
|
15673
15736
|
const prevWorkItems = allDocs.filter(
|
|
15674
|
-
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(prevTag)
|
|
15737
|
+
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.type !== "contribution" && d.frontmatter.tags?.includes(prevTag)
|
|
15675
15738
|
);
|
|
15676
15739
|
const prevDone = prevWorkItems.filter((d) => DONE_STATUSES.has(d.frontmatter.status)).length;
|
|
15677
15740
|
const prevRate = prevWorkItems.length > 0 ? Math.round(prevDone / prevWorkItems.length * 100) : 0;
|
|
@@ -16564,19 +16627,22 @@ function createContributionTools(store) {
|
|
|
16564
16627
|
content: external_exports.string().describe("Contribution content \u2014 the input from the persona"),
|
|
16565
16628
|
persona: external_exports.string().describe("Persona making the contribution (e.g. 'tech-lead')"),
|
|
16566
16629
|
contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
|
|
16567
|
-
aboutArtifact: external_exports.string().
|
|
16568
|
-
status: external_exports.string().optional().describe("Status (default: '
|
|
16569
|
-
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
|
|
16630
|
+
aboutArtifact: external_exports.string().describe("Artifact ID this contribution relates to (e.g. 'A-001', 'T-003')"),
|
|
16631
|
+
status: external_exports.string().optional().describe("Status (default: 'done')"),
|
|
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.")
|
|
16570
16634
|
},
|
|
16571
16635
|
async (args) => {
|
|
16572
16636
|
const frontmatter = {
|
|
16573
16637
|
title: args.title,
|
|
16574
|
-
status: args.status ?? "
|
|
16638
|
+
status: args.status ?? "done",
|
|
16575
16639
|
persona: args.persona,
|
|
16576
16640
|
contributionType: args.contributionType
|
|
16577
16641
|
};
|
|
16578
|
-
|
|
16579
|
-
|
|
16642
|
+
frontmatter.aboutArtifact = args.aboutArtifact;
|
|
16643
|
+
const tags = [...args.tags ?? []];
|
|
16644
|
+
if (args.workStream) tags.push(`stream:${args.workStream}`);
|
|
16645
|
+
if (tags.length > 0) frontmatter.tags = tags;
|
|
16580
16646
|
const doc = store.create("contribution", frontmatter, args.content);
|
|
16581
16647
|
return {
|
|
16582
16648
|
content: [
|
|
@@ -16595,10 +16661,18 @@ function createContributionTools(store) {
|
|
|
16595
16661
|
id: external_exports.string().describe("Contribution ID to update"),
|
|
16596
16662
|
title: external_exports.string().optional().describe("New title"),
|
|
16597
16663
|
status: external_exports.string().optional().describe("New status"),
|
|
16598
|
-
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.")
|
|
16599
16666
|
},
|
|
16600
16667
|
async (args) => {
|
|
16601
|
-
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
|
+
}
|
|
16602
16676
|
const doc = store.update(id, updates, content);
|
|
16603
16677
|
return {
|
|
16604
16678
|
content: [
|
|
@@ -17059,13 +17133,15 @@ function createTaskTools(store) {
|
|
|
17059
17133
|
title: external_exports.string().describe("Task title"),
|
|
17060
17134
|
content: external_exports.string().describe("Task description and implementation details"),
|
|
17061
17135
|
linkedEpic: linkedEpicArray.describe("Epic ID(s) to link this task to (e.g. ['E-001'] or ['E-001', 'E-002'])"),
|
|
17136
|
+
aboutArtifact: external_exports.string().optional().describe("Parent artifact this task derives from (e.g. 'A-001')"),
|
|
17062
17137
|
status: external_exports.enum(["backlog", "ready", "in-progress", "review", "done"]).optional().describe("Task status (default: 'backlog')"),
|
|
17063
17138
|
acceptanceCriteria: external_exports.string().optional().describe("Acceptance criteria for the task"),
|
|
17064
17139
|
technicalNotes: external_exports.string().optional().describe("Technical implementation notes"),
|
|
17065
17140
|
estimatedPoints: external_exports.number().optional().describe("Story point estimate"),
|
|
17066
17141
|
complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("Task complexity"),
|
|
17067
17142
|
priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("Task priority"),
|
|
17068
|
-
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.")
|
|
17069
17145
|
},
|
|
17070
17146
|
async (args) => {
|
|
17071
17147
|
const linkedEpics = normalizeLinkedEpics(args.linkedEpic);
|
|
@@ -17078,12 +17154,15 @@ function createTaskTools(store) {
|
|
|
17078
17154
|
warnings.push(`Warning: ${epicId} is a ${epic.frontmatter.type}, not an epic`);
|
|
17079
17155
|
}
|
|
17080
17156
|
}
|
|
17157
|
+
const baseTags = [...generateEpicTags(linkedEpics), ...args.tags ?? []];
|
|
17158
|
+
if (args.workStream) baseTags.push(`stream:${args.workStream}`);
|
|
17081
17159
|
const frontmatter = {
|
|
17082
17160
|
title: args.title,
|
|
17083
17161
|
status: args.status ?? "backlog",
|
|
17084
17162
|
linkedEpic: linkedEpics,
|
|
17085
|
-
tags:
|
|
17163
|
+
tags: baseTags
|
|
17086
17164
|
};
|
|
17165
|
+
if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
|
|
17087
17166
|
if (args.acceptanceCriteria) frontmatter.acceptanceCriteria = args.acceptanceCriteria;
|
|
17088
17167
|
if (args.technicalNotes) frontmatter.technicalNotes = args.technicalNotes;
|
|
17089
17168
|
if (args.estimatedPoints !== void 0) frontmatter.estimatedPoints = args.estimatedPoints;
|
|
@@ -17107,6 +17186,7 @@ function createTaskTools(store) {
|
|
|
17107
17186
|
{
|
|
17108
17187
|
id: external_exports.string().describe("Task ID to update"),
|
|
17109
17188
|
title: external_exports.string().optional().describe("New title"),
|
|
17189
|
+
aboutArtifact: external_exports.string().optional().describe("Parent artifact this task derives from (e.g. 'A-001')"),
|
|
17110
17190
|
status: external_exports.enum(["backlog", "ready", "in-progress", "review", "done"]).optional().describe("New status"),
|
|
17111
17191
|
content: external_exports.string().optional().describe("New content"),
|
|
17112
17192
|
linkedEpic: linkedEpicArray.optional().describe("New linked epic ID(s)"),
|
|
@@ -17115,10 +17195,11 @@ function createTaskTools(store) {
|
|
|
17115
17195
|
estimatedPoints: external_exports.number().optional().describe("New story point estimate"),
|
|
17116
17196
|
complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("New complexity"),
|
|
17117
17197
|
priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
|
|
17118
|
-
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.")
|
|
17119
17200
|
},
|
|
17120
17201
|
async (args) => {
|
|
17121
|
-
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, ...updates } = args;
|
|
17202
|
+
const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workStream, ...updates } = args;
|
|
17122
17203
|
const warnings = [];
|
|
17123
17204
|
if (rawLinkedEpic !== void 0) {
|
|
17124
17205
|
const linkedEpics = normalizeLinkedEpics(rawLinkedEpic);
|
|
@@ -17139,6 +17220,12 @@ function createTaskTools(store) {
|
|
|
17139
17220
|
} else if (userTags !== void 0) {
|
|
17140
17221
|
updates.tags = userTags;
|
|
17141
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
|
+
}
|
|
17142
17229
|
const doc = store.update(id, updates, content);
|
|
17143
17230
|
const parts = [`Updated task ${doc.frontmatter.id}: ${doc.frontmatter.title}`];
|
|
17144
17231
|
if (warnings.length > 0) {
|
|
@@ -20207,6 +20294,17 @@ tr:hover td {
|
|
|
20207
20294
|
background: var(--bg-hover);
|
|
20208
20295
|
}
|
|
20209
20296
|
|
|
20297
|
+
/* Hierarchical work-item sub-rows */
|
|
20298
|
+
.child-row td {
|
|
20299
|
+
font-size: 0.8125rem;
|
|
20300
|
+
border-bottom-style: dashed;
|
|
20301
|
+
}
|
|
20302
|
+
.contribution-row td {
|
|
20303
|
+
font-size: 0.8125rem;
|
|
20304
|
+
color: var(--text-dim);
|
|
20305
|
+
border-bottom-style: dashed;
|
|
20306
|
+
}
|
|
20307
|
+
|
|
20210
20308
|
/* GAR */
|
|
20211
20309
|
.gar-overall {
|
|
20212
20310
|
text-align: center;
|
|
@@ -21894,22 +21992,36 @@ function sprintSummaryPage(data, cached2) {
|
|
|
21894
21992
|
</div>`,
|
|
21895
21993
|
{ titleTag: "h3" }
|
|
21896
21994
|
) : "";
|
|
21897
|
-
|
|
21995
|
+
function renderItemRows(items, depth = 0) {
|
|
21996
|
+
return items.flatMap((w) => {
|
|
21997
|
+
const isChild = depth > 0;
|
|
21998
|
+
const isContribution = w.type === "contribution";
|
|
21999
|
+
const rowClass = isContribution ? ' class="contribution-row"' : isChild ? ' class="child-row"' : "";
|
|
22000
|
+
const indent = depth > 0 ? ` style="padding-left: ${0.75 + depth * 1}rem"` : "";
|
|
22001
|
+
const streamCell = w.workStream ? `<span class="badge badge-subtle">${escapeHtml(w.workStream)}</span>` : "";
|
|
22002
|
+
const row = `
|
|
22003
|
+
<tr${rowClass}>
|
|
22004
|
+
<td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
|
|
22005
|
+
<td>${escapeHtml(w.title)}</td>
|
|
22006
|
+
<td>${streamCell}</td>
|
|
22007
|
+
<td>${escapeHtml(typeLabel(w.type))}</td>
|
|
22008
|
+
<td>${statusBadge(w.status)}</td>
|
|
22009
|
+
</tr>`;
|
|
22010
|
+
const childRows = w.children ? renderItemRows(w.children, depth + 1) : [];
|
|
22011
|
+
return [row, ...childRows];
|
|
22012
|
+
});
|
|
22013
|
+
}
|
|
22014
|
+
const workItemRows = renderItemRows(data.workItems.items);
|
|
22015
|
+
const workItemsSection = workItemRows.length > 0 ? collapsibleSection(
|
|
21898
22016
|
"ss-work-items",
|
|
21899
22017
|
"Work Items",
|
|
21900
22018
|
`<div class="table-wrap">
|
|
21901
22019
|
<table>
|
|
21902
22020
|
<thead>
|
|
21903
|
-
<tr><th>ID</th><th>Title</th><th>Type</th><th>Status</th></tr>
|
|
22021
|
+
<tr><th>ID</th><th>Title</th><th>Stream</th><th>Type</th><th>Status</th></tr>
|
|
21904
22022
|
</thead>
|
|
21905
22023
|
<tbody>
|
|
21906
|
-
${
|
|
21907
|
-
<tr>
|
|
21908
|
-
<td><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
|
|
21909
|
-
<td>${escapeHtml(w.title)}</td>
|
|
21910
|
-
<td>${escapeHtml(typeLabel(w.type))}</td>
|
|
21911
|
-
<td>${statusBadge(w.status)}</td>
|
|
21912
|
-
</tr>`).join("")}
|
|
22024
|
+
${workItemRows.join("")}
|
|
21913
22025
|
</tbody>
|
|
21914
22026
|
</table>
|
|
21915
22027
|
</div>`,
|