mrvn-cli 0.4.8 → 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/dist/marvin.js CHANGED
@@ -14594,11 +14594,13 @@ function collectSprintSummaryData(store, sprintId) {
14594
14594
  const sprintItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
14595
14595
  for (const doc of workItemDocs) {
14596
14596
  const about = doc.frontmatter.aboutArtifact;
14597
+ const streamTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("stream:"));
14597
14598
  const item = {
14598
14599
  id: doc.frontmatter.id,
14599
14600
  title: doc.frontmatter.title,
14600
14601
  type: doc.frontmatter.type,
14601
14602
  status: doc.frontmatter.status,
14603
+ workStream: streamTag ? streamTag.slice(7) : void 0,
14602
14604
  aboutArtifact: about
14603
14605
  };
14604
14606
  allItemsById.set(item.id, item);
@@ -15618,7 +15620,8 @@ function createContributionTools(store) {
15618
15620
  contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
15619
15621
  aboutArtifact: external_exports.string().describe("Artifact ID this contribution relates to (e.g. 'A-001', 'T-003')"),
15620
15622
  status: external_exports.string().optional().describe("Status (default: 'done')"),
15621
- tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
15623
+ tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
15624
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
15622
15625
  },
15623
15626
  async (args) => {
15624
15627
  const frontmatter = {
@@ -15628,7 +15631,9 @@ function createContributionTools(store) {
15628
15631
  contributionType: args.contributionType
15629
15632
  };
15630
15633
  frontmatter.aboutArtifact = args.aboutArtifact;
15631
- if (args.tags) frontmatter.tags = args.tags;
15634
+ const tags = [...args.tags ?? []];
15635
+ if (args.workStream) tags.push(`stream:${args.workStream}`);
15636
+ if (tags.length > 0) frontmatter.tags = tags;
15632
15637
  const doc = store.create("contribution", frontmatter, args.content);
15633
15638
  return {
15634
15639
  content: [
@@ -15647,10 +15652,18 @@ function createContributionTools(store) {
15647
15652
  id: external_exports.string().describe("Contribution ID to update"),
15648
15653
  title: external_exports.string().optional().describe("New title"),
15649
15654
  status: external_exports.string().optional().describe("New status"),
15650
- content: external_exports.string().optional().describe("New content")
15655
+ content: external_exports.string().optional().describe("New content"),
15656
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
15651
15657
  },
15652
15658
  async (args) => {
15653
- const { id, content, ...updates } = args;
15659
+ const { id, content, workStream, ...updates } = args;
15660
+ if (workStream !== void 0) {
15661
+ const existing = store.get(id);
15662
+ const existingTags = existing?.frontmatter.tags ?? [];
15663
+ const filtered = existingTags.filter((t) => !t.startsWith("stream:"));
15664
+ filtered.push(`stream:${workStream}`);
15665
+ updates.tags = filtered;
15666
+ }
15654
15667
  const doc = store.update(id, updates, content);
15655
15668
  return {
15656
15669
  content: [
@@ -16118,7 +16131,8 @@ function createTaskTools(store) {
16118
16131
  estimatedPoints: external_exports.number().optional().describe("Story point estimate"),
16119
16132
  complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("Task complexity"),
16120
16133
  priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("Task priority"),
16121
- tags: external_exports.array(external_exports.string()).optional().describe("Additional tags")
16134
+ tags: external_exports.array(external_exports.string()).optional().describe("Additional tags"),
16135
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
16122
16136
  },
16123
16137
  async (args) => {
16124
16138
  const linkedEpics = normalizeLinkedEpics(args.linkedEpic);
@@ -16131,11 +16145,13 @@ function createTaskTools(store) {
16131
16145
  warnings.push(`Warning: ${epicId} is a ${epic.frontmatter.type}, not an epic`);
16132
16146
  }
16133
16147
  }
16148
+ const baseTags = [...generateEpicTags(linkedEpics), ...args.tags ?? []];
16149
+ if (args.workStream) baseTags.push(`stream:${args.workStream}`);
16134
16150
  const frontmatter = {
16135
16151
  title: args.title,
16136
16152
  status: args.status ?? "backlog",
16137
16153
  linkedEpic: linkedEpics,
16138
- tags: [...generateEpicTags(linkedEpics), ...args.tags ?? []]
16154
+ tags: baseTags
16139
16155
  };
16140
16156
  if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
16141
16157
  if (args.acceptanceCriteria) frontmatter.acceptanceCriteria = args.acceptanceCriteria;
@@ -16170,10 +16186,11 @@ function createTaskTools(store) {
16170
16186
  estimatedPoints: external_exports.number().optional().describe("New story point estimate"),
16171
16187
  complexity: external_exports.enum(["trivial", "simple", "moderate", "complex", "very-complex"]).optional().describe("New complexity"),
16172
16188
  priority: external_exports.enum(["critical", "high", "medium", "low"]).optional().describe("New priority"),
16173
- tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)")
16189
+ tags: external_exports.array(external_exports.string()).optional().describe("Replace tags (e.g. remove old tags, add new ones)"),
16190
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
16174
16191
  },
16175
16192
  async (args) => {
16176
- const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, ...updates } = args;
16193
+ const { id, content, linkedEpic: rawLinkedEpic, tags: userTags, workStream, ...updates } = args;
16177
16194
  const warnings = [];
16178
16195
  if (rawLinkedEpic !== void 0) {
16179
16196
  const linkedEpics = normalizeLinkedEpics(rawLinkedEpic);
@@ -16194,6 +16211,12 @@ function createTaskTools(store) {
16194
16211
  } else if (userTags !== void 0) {
16195
16212
  updates.tags = userTags;
16196
16213
  }
16214
+ if (workStream !== void 0) {
16215
+ const currentTags = updates.tags ?? store.get(id)?.frontmatter.tags ?? [];
16216
+ const filtered = currentTags.filter((t) => !t.startsWith("stream:"));
16217
+ filtered.push(`stream:${workStream}`);
16218
+ updates.tags = filtered;
16219
+ }
16197
16220
  const doc = store.update(id, updates, content);
16198
16221
  const parts = [`Updated task ${doc.frontmatter.id}: ${doc.frontmatter.title}`];
16199
16222
  if (warnings.length > 0) {
@@ -18180,7 +18203,8 @@ function createActionTools(store) {
18180
18203
  priority: external_exports.string().optional().describe("Priority (high, medium, low)"),
18181
18204
  tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
18182
18205
  dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
18183
- sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags.")
18206
+ sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (e.g. ['SP-001']). Adds sprint:SP-xxx tags."),
18207
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Adds a stream:<value> tag.")
18184
18208
  },
18185
18209
  async (args) => {
18186
18210
  const tags = [...args.tags ?? []];
@@ -18190,6 +18214,9 @@ function createActionTools(store) {
18190
18214
  if (!tags.includes(tag)) tags.push(tag);
18191
18215
  }
18192
18216
  }
18217
+ if (args.workStream) {
18218
+ tags.push(`stream:${args.workStream}`);
18219
+ }
18193
18220
  const doc = store.create(
18194
18221
  "action",
18195
18222
  {
@@ -18227,10 +18254,11 @@ function createActionTools(store) {
18227
18254
  priority: external_exports.string().optional().describe("New priority"),
18228
18255
  dueDate: external_exports.string().optional().describe("Due date in ISO format (e.g. '2026-03-15')"),
18229
18256
  tags: external_exports.array(external_exports.string()).optional().describe("Replace all tags. When provided with sprints, sprint tags are merged into this array."),
18230
- sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001'].")
18257
+ sprints: external_exports.array(external_exports.string()).optional().describe("Sprint IDs to assign (replaces existing sprint tags). E.g. ['SP-001']."),
18258
+ workStream: external_exports.string().optional().describe("Work stream name (e.g. 'Budget UX'). Replaces existing stream:<value> tag.")
18231
18259
  },
18232
18260
  async (args) => {
18233
- const { id, content, sprints, tags, ...updates } = args;
18261
+ const { id, content, sprints, tags, workStream, ...updates } = args;
18234
18262
  if (tags !== void 0) {
18235
18263
  const merged = [...tags];
18236
18264
  if (sprints) {
@@ -18239,8 +18267,14 @@ function createActionTools(store) {
18239
18267
  if (!merged.includes(tag)) merged.push(tag);
18240
18268
  }
18241
18269
  }
18242
- updates.tags = merged;
18243
- } else if (sprints !== void 0) {
18270
+ if (workStream !== void 0) {
18271
+ const filtered = merged.filter((t) => !t.startsWith("stream:"));
18272
+ filtered.push(`stream:${workStream}`);
18273
+ updates.tags = filtered;
18274
+ } else {
18275
+ updates.tags = merged;
18276
+ }
18277
+ } else if (sprints !== void 0 || workStream !== void 0) {
18244
18278
  const existing = store.get(id);
18245
18279
  if (!existing) {
18246
18280
  return {
@@ -18248,10 +18282,16 @@ function createActionTools(store) {
18248
18282
  isError: true
18249
18283
  };
18250
18284
  }
18251
- const existingTags = existing.frontmatter.tags ?? [];
18252
- const nonSprintTags = existingTags.filter((t) => !t.startsWith("sprint:"));
18253
- const newSprintTags = sprints.map((s) => `sprint:${s}`);
18254
- updates.tags = [...nonSprintTags, ...newSprintTags];
18285
+ let existingTags = existing.frontmatter.tags ?? [];
18286
+ if (sprints !== void 0) {
18287
+ existingTags = existingTags.filter((t) => !t.startsWith("sprint:"));
18288
+ existingTags.push(...sprints.map((s) => `sprint:${s}`));
18289
+ }
18290
+ if (workStream !== void 0) {
18291
+ existingTags = existingTags.filter((t) => !t.startsWith("stream:"));
18292
+ existingTags.push(`stream:${workStream}`);
18293
+ }
18294
+ updates.tags = existingTags;
18255
18295
  }
18256
18296
  const doc = store.update(id, updates, content);
18257
18297
  return {
@@ -18416,14 +18456,19 @@ function createDocumentTools(store) {
18416
18456
  {
18417
18457
  type: external_exports.string().optional().describe(`Filter by document type (registered types: ${store.registeredTypes.join(", ")})`),
18418
18458
  status: external_exports.string().optional().describe("Filter by status"),
18419
- tag: external_exports.string().optional().describe("Filter by tag")
18459
+ tag: external_exports.string().optional().describe("Filter by tag"),
18460
+ workStream: external_exports.string().optional().describe("Filter by work stream name (matches stream:<value> tag)")
18420
18461
  },
18421
18462
  async (args) => {
18422
- const docs = store.list({
18463
+ let docs = store.list({
18423
18464
  type: args.type,
18424
18465
  status: args.status,
18425
18466
  tag: args.tag
18426
18467
  });
18468
+ if (args.workStream) {
18469
+ const streamTag = `stream:${args.workStream}`;
18470
+ docs = docs.filter((d) => d.frontmatter.tags?.includes(streamTag));
18471
+ }
18427
18472
  const summary = docs.map((d) => ({
18428
18473
  id: d.frontmatter.id,
18429
18474
  title: d.frontmatter.title,
@@ -21165,10 +21210,12 @@ function sprintSummaryPage(data, cached2) {
21165
21210
  const isContribution = w.type === "contribution";
21166
21211
  const rowClass = isContribution ? ' class="contribution-row"' : isChild ? ' class="child-row"' : "";
21167
21212
  const indent = depth > 0 ? ` style="padding-left: ${0.75 + depth * 1}rem"` : "";
21213
+ const streamCell = w.workStream ? `<span class="badge badge-subtle">${escapeHtml(w.workStream)}</span>` : "";
21168
21214
  const row = `
21169
21215
  <tr${rowClass}>
21170
21216
  <td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
21171
21217
  <td>${escapeHtml(w.title)}</td>
21218
+ <td>${streamCell}</td>
21172
21219
  <td>${escapeHtml(typeLabel(w.type))}</td>
21173
21220
  <td>${statusBadge(w.status)}</td>
21174
21221
  </tr>`;
@@ -21183,7 +21230,7 @@ function sprintSummaryPage(data, cached2) {
21183
21230
  `<div class="table-wrap">
21184
21231
  <table>
21185
21232
  <thead>
21186
- <tr><th>ID</th><th>Title</th><th>Type</th><th>Status</th></tr>
21233
+ <tr><th>ID</th><th>Title</th><th>Stream</th><th>Type</th><th>Status</th></tr>
21187
21234
  </thead>
21188
21235
  <tbody>
21189
21236
  ${workItemRows.join("")}
@@ -26224,7 +26271,7 @@ function createProgram() {
26224
26271
  const program2 = new Command();
26225
26272
  program2.name("marvin").description(
26226
26273
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
26227
- ).version("0.4.8");
26274
+ ).version("0.4.9");
26228
26275
  program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
26229
26276
  await initCommand();
26230
26277
  });