mrvn-cli 0.2.4 → 0.2.6

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 CHANGED
@@ -438,9 +438,10 @@ var deliveryManager = {
438
438
  "Team coordination",
439
439
  "Process governance",
440
440
  "Status tracking",
441
- "Epic scheduling and tracking"
441
+ "Epic scheduling and tracking",
442
+ "Sprint planning and tracking"
442
443
  ],
443
- documentTypes: ["action", "decision", "meeting", "question", "feature", "epic"],
444
+ documentTypes: ["action", "decision", "meeting", "question", "feature", "epic", "sprint"],
444
445
  contributionTypes: ["risk-finding", "blocker-report", "dependency-update", "status-assessment"]
445
446
  };
446
447
 
@@ -477,9 +478,10 @@ var techLead = {
477
478
  "Technical decisions",
478
479
  "Implementation guidance",
479
480
  "Non-functional requirements",
480
- "Epic creation and scoping"
481
+ "Epic creation and scoping",
482
+ "Sprint scoping and technical execution"
481
483
  ],
482
- documentTypes: ["decision", "action", "question", "epic"],
484
+ documentTypes: ["decision", "action", "question", "epic", "sprint"],
483
485
  contributionTypes: ["action-result", "spike-findings", "technical-assessment", "architecture-review"]
484
486
  };
485
487
 
@@ -528,6 +530,7 @@ You have access to governance tools for managing project artifacts:
528
530
  - **Questions** (Q-xxx): List, get, create, and update questions
529
531
  - **Features** (F-xxx): List, get, create, and update feature definitions
530
532
  - **Epics** (E-xxx): List, get, create, and update implementation epics (must link to approved features)
533
+ - **Sprints** (SP-xxx): List, get, create, and update time-boxed iterations with linked epics and delivery dates
531
534
  - **Documents**: Search and read any project document
532
535
  - **Sources**: List source documents and view their processing status and derived artifacts
533
536
 
@@ -15511,6 +15514,60 @@ function createReportTools(store) {
15511
15514
  },
15512
15515
  { annotations: { readOnly: true } }
15513
15516
  ),
15517
+ tool8(
15518
+ "generate_sprint_progress",
15519
+ "Generate progress report for a sprint or all sprints, showing linked epics and tagged work items",
15520
+ {
15521
+ sprint: external_exports.string().optional().describe("Specific sprint ID (e.g. 'SP-001') or omit for all")
15522
+ },
15523
+ async (args) => {
15524
+ const allDocs = store.list();
15525
+ const sprintDocs = store.list({ type: "sprint" });
15526
+ const sprints = sprintDocs.filter((s) => !args.sprint || s.frontmatter.id === args.sprint).map((sprintDoc) => {
15527
+ const sprintId = sprintDoc.frontmatter.id;
15528
+ const linkedEpicIds = sprintDoc.frontmatter.linkedEpics ?? [];
15529
+ const linkedEpics = linkedEpicIds.map((epicId) => {
15530
+ const epic = store.get(epicId);
15531
+ return epic ? { id: epicId, title: epic.frontmatter.title, status: epic.frontmatter.status } : { id: epicId, title: "(not found)", status: "unknown" };
15532
+ });
15533
+ const workItems = allDocs.filter(
15534
+ (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(`sprint:${sprintId}`)
15535
+ );
15536
+ const byStatus = {};
15537
+ for (const doc of workItems) {
15538
+ byStatus[doc.frontmatter.status] = (byStatus[doc.frontmatter.status] ?? 0) + 1;
15539
+ }
15540
+ const doneCount = (byStatus["done"] ?? 0) + (byStatus["resolved"] ?? 0) + (byStatus["closed"] ?? 0);
15541
+ const total = workItems.length;
15542
+ const completionPct = total > 0 ? Math.round(doneCount / total * 100) : 0;
15543
+ return {
15544
+ id: sprintDoc.frontmatter.id,
15545
+ title: sprintDoc.frontmatter.title,
15546
+ status: sprintDoc.frontmatter.status,
15547
+ goal: sprintDoc.frontmatter.goal,
15548
+ startDate: sprintDoc.frontmatter.startDate,
15549
+ endDate: sprintDoc.frontmatter.endDate,
15550
+ linkedEpics,
15551
+ workItems: {
15552
+ total,
15553
+ done: doneCount,
15554
+ completionPct,
15555
+ byStatus,
15556
+ items: workItems.map((d) => ({
15557
+ id: d.frontmatter.id,
15558
+ title: d.frontmatter.title,
15559
+ type: d.frontmatter.type,
15560
+ status: d.frontmatter.status
15561
+ }))
15562
+ }
15563
+ };
15564
+ });
15565
+ return {
15566
+ content: [{ type: "text", text: JSON.stringify({ sprints }, null, 2) }]
15567
+ };
15568
+ },
15569
+ { annotations: { readOnly: true } }
15570
+ ),
15514
15571
  tool8(
15515
15572
  "generate_feature_progress",
15516
15573
  "Generate progress report for features and their linked epics",
@@ -15557,7 +15614,7 @@ function createReportTools(store) {
15557
15614
  {
15558
15615
  title: external_exports.string().describe("Report title"),
15559
15616
  content: external_exports.string().describe("Full report content in markdown"),
15560
- reportType: external_exports.enum(["status", "risk-register", "gar", "epic-progress", "feature-progress", "custom"]).describe("Type of report"),
15617
+ reportType: external_exports.enum(["status", "risk-register", "gar", "epic-progress", "feature-progress", "sprint-progress", "custom"]).describe("Type of report"),
15561
15618
  tags: external_exports.array(external_exports.string()).optional().describe("Additional tags")
15562
15619
  },
15563
15620
  async (args) => {
@@ -15974,13 +16031,369 @@ function createContributionTools(store) {
15974
16031
  ];
15975
16032
  }
15976
16033
 
16034
+ // src/plugins/builtin/tools/sprints.ts
16035
+ import { tool as tool12 } from "@anthropic-ai/claude-agent-sdk";
16036
+ function createSprintTools(store) {
16037
+ return [
16038
+ tool12(
16039
+ "list_sprints",
16040
+ "List all sprints in the project, optionally filtered by status",
16041
+ {
16042
+ status: external_exports.enum(["planned", "active", "completed", "cancelled"]).optional().describe("Filter by sprint status")
16043
+ },
16044
+ async (args) => {
16045
+ const docs = store.list({ type: "sprint", status: args.status });
16046
+ const summary = docs.map((d) => ({
16047
+ id: d.frontmatter.id,
16048
+ title: d.frontmatter.title,
16049
+ status: d.frontmatter.status,
16050
+ goal: d.frontmatter.goal,
16051
+ startDate: d.frontmatter.startDate,
16052
+ endDate: d.frontmatter.endDate,
16053
+ linkedEpics: d.frontmatter.linkedEpics,
16054
+ tags: d.frontmatter.tags
16055
+ }));
16056
+ return {
16057
+ content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
16058
+ };
16059
+ },
16060
+ { annotations: { readOnly: true } }
16061
+ ),
16062
+ tool12(
16063
+ "get_sprint",
16064
+ "Get the full content of a specific sprint by ID",
16065
+ { id: external_exports.string().describe("Sprint ID (e.g. 'SP-001')") },
16066
+ async (args) => {
16067
+ const doc = store.get(args.id);
16068
+ if (!doc) {
16069
+ return {
16070
+ content: [{ type: "text", text: `Sprint ${args.id} not found` }],
16071
+ isError: true
16072
+ };
16073
+ }
16074
+ return {
16075
+ content: [
16076
+ {
16077
+ type: "text",
16078
+ text: JSON.stringify(
16079
+ { ...doc.frontmatter, content: doc.content },
16080
+ null,
16081
+ 2
16082
+ )
16083
+ }
16084
+ ]
16085
+ };
16086
+ },
16087
+ { annotations: { readOnly: true } }
16088
+ ),
16089
+ tool12(
16090
+ "create_sprint",
16091
+ "Create a new sprint with dates, goal, and optionally linked epics",
16092
+ {
16093
+ title: external_exports.string().describe("Sprint title"),
16094
+ content: external_exports.string().describe("Sprint description and objectives"),
16095
+ goal: external_exports.string().describe("Sprint goal \u2014 what this sprint aims to deliver"),
16096
+ startDate: external_exports.string().describe("Sprint start date (ISO format, e.g. '2026-03-01')"),
16097
+ endDate: external_exports.string().describe("Sprint end date (ISO format, e.g. '2026-03-14')"),
16098
+ status: external_exports.enum(["planned", "active", "completed", "cancelled"]).optional().describe("Sprint status (default: 'planned')"),
16099
+ linkedEpics: external_exports.array(external_exports.string()).optional().describe("Epic IDs to link (e.g. ['E-001', 'E-003']). Soft-validated: warns if not found but still creates."),
16100
+ tags: external_exports.array(external_exports.string()).optional().describe("Additional tags")
16101
+ },
16102
+ async (args) => {
16103
+ const warnings = [];
16104
+ if (args.linkedEpics) {
16105
+ for (const epicId of args.linkedEpics) {
16106
+ const epic = store.get(epicId);
16107
+ if (!epic) {
16108
+ warnings.push(`Epic ${epicId} not found (linked anyway)`);
16109
+ }
16110
+ }
16111
+ }
16112
+ const frontmatter = {
16113
+ title: args.title,
16114
+ status: args.status ?? "planned",
16115
+ goal: args.goal,
16116
+ startDate: args.startDate,
16117
+ endDate: args.endDate,
16118
+ linkedEpics: args.linkedEpics ?? [],
16119
+ tags: [...args.tags ?? []]
16120
+ };
16121
+ const doc = store.create("sprint", frontmatter, args.content);
16122
+ const sprintId = doc.frontmatter.id;
16123
+ if (args.linkedEpics) {
16124
+ for (const epicId of args.linkedEpics) {
16125
+ const epic = store.get(epicId);
16126
+ if (epic) {
16127
+ const existingTags = epic.frontmatter.tags ?? [];
16128
+ const sprintTag = `sprint:${sprintId}`;
16129
+ if (!existingTags.includes(sprintTag)) {
16130
+ store.update(epicId, { tags: [...existingTags, sprintTag] });
16131
+ }
16132
+ }
16133
+ }
16134
+ }
16135
+ const parts = [`Created sprint ${sprintId}: ${doc.frontmatter.title}`];
16136
+ if (warnings.length > 0) {
16137
+ parts.push(`Warnings: ${warnings.join("; ")}`);
16138
+ }
16139
+ return {
16140
+ content: [{ type: "text", text: parts.join("\n") }]
16141
+ };
16142
+ }
16143
+ ),
16144
+ tool12(
16145
+ "update_sprint",
16146
+ "Update an existing sprint. Cannot change id or type.",
16147
+ {
16148
+ id: external_exports.string().describe("Sprint ID to update"),
16149
+ title: external_exports.string().optional().describe("New title"),
16150
+ status: external_exports.enum(["planned", "active", "completed", "cancelled"]).optional().describe("New status"),
16151
+ content: external_exports.string().optional().describe("New content"),
16152
+ goal: external_exports.string().optional().describe("New sprint goal"),
16153
+ startDate: external_exports.string().optional().describe("New start date"),
16154
+ endDate: external_exports.string().optional().describe("New end date"),
16155
+ linkedEpics: external_exports.array(external_exports.string()).optional().describe("New list of linked epic IDs (replaces existing)"),
16156
+ tags: external_exports.array(external_exports.string()).optional().describe("New tags (replaces existing)")
16157
+ },
16158
+ async (args) => {
16159
+ const { id, content, linkedEpics, ...updates } = args;
16160
+ const existing = store.get(id);
16161
+ if (!existing) {
16162
+ return {
16163
+ content: [{ type: "text", text: `Sprint ${id} not found` }],
16164
+ isError: true
16165
+ };
16166
+ }
16167
+ if (linkedEpics !== void 0) {
16168
+ const oldLinked = existing.frontmatter.linkedEpics ?? [];
16169
+ const sprintTag = `sprint:${id}`;
16170
+ const removed = oldLinked.filter((e) => !linkedEpics.includes(e));
16171
+ for (const epicId of removed) {
16172
+ const epic = store.get(epicId);
16173
+ if (epic) {
16174
+ const tags = epic.frontmatter.tags ?? [];
16175
+ const filtered = tags.filter((t) => t !== sprintTag);
16176
+ if (filtered.length !== tags.length) {
16177
+ store.update(epicId, { tags: filtered });
16178
+ }
16179
+ }
16180
+ }
16181
+ const added = linkedEpics.filter((e) => !oldLinked.includes(e));
16182
+ for (const epicId of added) {
16183
+ const epic = store.get(epicId);
16184
+ if (epic) {
16185
+ const tags = epic.frontmatter.tags ?? [];
16186
+ if (!tags.includes(sprintTag)) {
16187
+ store.update(epicId, { tags: [...tags, sprintTag] });
16188
+ }
16189
+ }
16190
+ }
16191
+ updates.linkedEpics = linkedEpics;
16192
+ }
16193
+ const doc = store.update(id, updates, content);
16194
+ return {
16195
+ content: [
16196
+ {
16197
+ type: "text",
16198
+ text: `Updated sprint ${doc.frontmatter.id}: ${doc.frontmatter.title}`
16199
+ }
16200
+ ]
16201
+ };
16202
+ }
16203
+ )
16204
+ ];
16205
+ }
16206
+
16207
+ // src/plugins/builtin/tools/sprint-planning.ts
16208
+ import { tool as tool13 } from "@anthropic-ai/claude-agent-sdk";
16209
+ var PRIORITY_ORDER = {
16210
+ critical: 0,
16211
+ high: 1,
16212
+ medium: 2,
16213
+ low: 3
16214
+ };
16215
+ function priorityRank(p) {
16216
+ return PRIORITY_ORDER[p ?? ""] ?? 99;
16217
+ }
16218
+ function createSprintPlanningTools(store) {
16219
+ return [
16220
+ tool13(
16221
+ "gather_sprint_planning_context",
16222
+ "Aggregate all planning-relevant data for proposing the next sprint: approved features, backlog epics, active sprint, velocity reference, blockers, and summary stats",
16223
+ {
16224
+ focusFeature: external_exports.string().optional().describe("Filter backlog to epics of a specific feature ID (e.g. 'F-001')"),
16225
+ sprintDurationDays: external_exports.number().optional().describe("Expected sprint duration in days \u2014 passed through for capacity reasoning")
16226
+ },
16227
+ async (args) => {
16228
+ const features = store.list({ type: "feature" });
16229
+ const epics = store.list({ type: "epic" });
16230
+ const sprints = store.list({ type: "sprint" });
16231
+ const questions = store.list({ type: "question", status: "open" });
16232
+ const contributions = store.list({ type: "contribution" });
16233
+ const approvedFeatures = features.filter((f) => f.frontmatter.status === "approved").sort((a, b) => priorityRank(a.frontmatter.priority) - priorityRank(b.frontmatter.priority)).map((f) => {
16234
+ const linkedEpics = epics.filter((e) => e.frontmatter.linkedFeature === f.frontmatter.id);
16235
+ const epicsByStatus = {};
16236
+ for (const e of linkedEpics) {
16237
+ epicsByStatus[e.frontmatter.status] = (epicsByStatus[e.frontmatter.status] ?? 0) + 1;
16238
+ }
16239
+ return {
16240
+ id: f.frontmatter.id,
16241
+ title: f.frontmatter.title,
16242
+ priority: f.frontmatter.priority,
16243
+ owner: f.frontmatter.owner,
16244
+ epicCount: linkedEpics.length,
16245
+ epicsByStatus
16246
+ };
16247
+ });
16248
+ const assignedEpicIds = /* @__PURE__ */ new Set();
16249
+ for (const sp of sprints) {
16250
+ const linked = sp.frontmatter.linkedEpics ?? [];
16251
+ for (const id of linked) assignedEpicIds.add(id);
16252
+ }
16253
+ const featureMap = new Map(features.map((f) => [f.frontmatter.id, f]));
16254
+ let backlogEpics = epics.filter(
16255
+ (e) => !assignedEpicIds.has(e.frontmatter.id) && e.frontmatter.status !== "done"
16256
+ );
16257
+ if (args.focusFeature) {
16258
+ backlogEpics = backlogEpics.filter(
16259
+ (e) => e.frontmatter.linkedFeature === args.focusFeature
16260
+ );
16261
+ }
16262
+ const backlog = backlogEpics.sort((a, b) => {
16263
+ const fa = featureMap.get(a.frontmatter.linkedFeature);
16264
+ const fb = featureMap.get(b.frontmatter.linkedFeature);
16265
+ return priorityRank(fa?.frontmatter.priority) - priorityRank(fb?.frontmatter.priority);
16266
+ }).map((e) => {
16267
+ const parent = featureMap.get(e.frontmatter.linkedFeature);
16268
+ return {
16269
+ id: e.frontmatter.id,
16270
+ title: e.frontmatter.title,
16271
+ status: e.frontmatter.status,
16272
+ linkedFeature: e.frontmatter.linkedFeature,
16273
+ featureTitle: parent?.frontmatter.title ?? null,
16274
+ featurePriority: parent?.frontmatter.priority ?? null,
16275
+ estimatedEffort: e.frontmatter.estimatedEffort ?? null,
16276
+ targetDate: e.frontmatter.targetDate ?? null
16277
+ };
16278
+ });
16279
+ const activeSprintDoc = sprints.find((s) => s.frontmatter.status === "active") ?? null;
16280
+ let activeSprint = null;
16281
+ if (activeSprintDoc) {
16282
+ const linkedEpicIds = activeSprintDoc.frontmatter.linkedEpics ?? [];
16283
+ const linkedEpics = linkedEpicIds.map((epicId) => {
16284
+ const epic = store.get(epicId);
16285
+ return epic ? { id: epicId, title: epic.frontmatter.title, status: epic.frontmatter.status } : { id: epicId, title: "(not found)", status: "unknown" };
16286
+ });
16287
+ const allDocs = store.list();
16288
+ const sprintTag = `sprint:${activeSprintDoc.frontmatter.id}`;
16289
+ const workItems = allDocs.filter(
16290
+ (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
16291
+ );
16292
+ const doneCount = workItems.filter(
16293
+ (d) => d.frontmatter.status === "done" || d.frontmatter.status === "resolved" || d.frontmatter.status === "closed"
16294
+ ).length;
16295
+ const completionPct = workItems.length > 0 ? Math.round(doneCount / workItems.length * 100) : 0;
16296
+ activeSprint = {
16297
+ id: activeSprintDoc.frontmatter.id,
16298
+ title: activeSprintDoc.frontmatter.title,
16299
+ goal: activeSprintDoc.frontmatter.goal,
16300
+ startDate: activeSprintDoc.frontmatter.startDate,
16301
+ endDate: activeSprintDoc.frontmatter.endDate,
16302
+ linkedEpics,
16303
+ workItems: { total: workItems.length, done: doneCount, completionPct }
16304
+ };
16305
+ }
16306
+ const completedSprints = sprints.filter((s) => s.frontmatter.status === "completed").sort((a, b) => {
16307
+ const da = a.frontmatter.endDate ?? "";
16308
+ const db = b.frontmatter.endDate ?? "";
16309
+ return da < db ? 1 : da > db ? -1 : 0;
16310
+ }).slice(0, 2);
16311
+ const velocityReference = completedSprints.map((sp) => {
16312
+ const linkedEpicIds = sp.frontmatter.linkedEpics ?? [];
16313
+ const efforts = [];
16314
+ for (const epicId of linkedEpicIds) {
16315
+ const epic = store.get(epicId);
16316
+ if (epic?.frontmatter.estimatedEffort) {
16317
+ efforts.push(String(epic.frontmatter.estimatedEffort));
16318
+ }
16319
+ }
16320
+ const allDocs = store.list();
16321
+ const sprintTag = `sprint:${sp.frontmatter.id}`;
16322
+ const workItems = allDocs.filter(
16323
+ (d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.tags?.includes(sprintTag)
16324
+ );
16325
+ return {
16326
+ id: sp.frontmatter.id,
16327
+ title: sp.frontmatter.title,
16328
+ startDate: sp.frontmatter.startDate,
16329
+ endDate: sp.frontmatter.endDate,
16330
+ epicCount: linkedEpicIds.length,
16331
+ efforts,
16332
+ workItemCount: workItems.length
16333
+ };
16334
+ });
16335
+ const openBlockerContributions = contributions.filter(
16336
+ (c) => c.frontmatter.status === "open" && (c.frontmatter.contributionType === "risk-finding" || c.frontmatter.contributionType === "blocker-report")
16337
+ );
16338
+ const blockers = {
16339
+ openQuestions: questions.map((q) => ({
16340
+ id: q.frontmatter.id,
16341
+ title: q.frontmatter.title
16342
+ })),
16343
+ openRiskAndBlockerContributions: openBlockerContributions.map((c) => ({
16344
+ id: c.frontmatter.id,
16345
+ title: c.frontmatter.title,
16346
+ contributionType: c.frontmatter.contributionType
16347
+ }))
16348
+ };
16349
+ const totalBacklogEfforts = backlog.filter((e) => e.estimatedEffort !== null).map((e) => String(e.estimatedEffort));
16350
+ const approvedFeaturesWithNoEpics = approvedFeatures.filter((f) => f.epicCount === 0).map((f) => ({ id: f.id, title: f.title }));
16351
+ const now = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
16352
+ const epicsAtRisk = epics.filter((e) => {
16353
+ if (e.frontmatter.status === "done") return false;
16354
+ if (e.frontmatter.targetDate && e.frontmatter.targetDate < now) return true;
16355
+ const parent = featureMap.get(e.frontmatter.linkedFeature);
16356
+ if (parent?.frontmatter.status === "deferred") return true;
16357
+ return false;
16358
+ }).map((e) => ({
16359
+ id: e.frontmatter.id,
16360
+ title: e.frontmatter.title,
16361
+ reason: e.frontmatter.targetDate && e.frontmatter.targetDate < now ? "past-target-date" : "deferred-feature"
16362
+ }));
16363
+ const plannedSprintCount = sprints.filter((s) => s.frontmatter.status === "planned").length;
16364
+ const summary = {
16365
+ totalBacklogEpics: backlog.length,
16366
+ totalBacklogEfforts,
16367
+ approvedFeaturesWithNoEpics,
16368
+ epicsAtRisk,
16369
+ plannedSprintCount
16370
+ };
16371
+ const result = {
16372
+ approvedFeatures,
16373
+ backlog,
16374
+ activeSprint,
16375
+ velocityReference,
16376
+ blockers,
16377
+ summary,
16378
+ ...args.sprintDurationDays !== void 0 ? { sprintDurationDays: args.sprintDurationDays } : {}
16379
+ };
16380
+ return {
16381
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
16382
+ };
16383
+ },
16384
+ { annotations: { readOnly: true } }
16385
+ )
16386
+ ];
16387
+ }
16388
+
15977
16389
  // src/plugins/common.ts
15978
16390
  var COMMON_REGISTRATIONS = [
15979
16391
  { type: "meeting", dirName: "meetings", idPrefix: "M" },
15980
16392
  { type: "report", dirName: "reports", idPrefix: "R" },
15981
16393
  { type: "feature", dirName: "features", idPrefix: "F" },
15982
16394
  { type: "epic", dirName: "epics", idPrefix: "E" },
15983
- { type: "contribution", dirName: "contributions", idPrefix: "C" }
16395
+ { type: "contribution", dirName: "contributions", idPrefix: "C" },
16396
+ { type: "sprint", dirName: "sprints", idPrefix: "SP" }
15984
16397
  ];
15985
16398
  function createCommonTools(store) {
15986
16399
  return [
@@ -15988,7 +16401,9 @@ function createCommonTools(store) {
15988
16401
  ...createReportTools(store),
15989
16402
  ...createFeatureTools(store),
15990
16403
  ...createEpicTools(store),
15991
- ...createContributionTools(store)
16404
+ ...createContributionTools(store),
16405
+ ...createSprintTools(store),
16406
+ ...createSprintPlanningTools(store)
15992
16407
  ];
15993
16408
  }
15994
16409
 
@@ -15998,7 +16413,7 @@ var genericAgilePlugin = {
15998
16413
  name: "Generic Agile",
15999
16414
  description: "Default methodology plugin providing standard agile governance patterns for decisions, actions, and questions.",
16000
16415
  version: "0.1.0",
16001
- documentTypes: ["decision", "action", "question", "meeting", "report", "feature", "epic", "contribution"],
16416
+ documentTypes: ["decision", "action", "question", "meeting", "report", "feature", "epic", "contribution", "sprint"],
16002
16417
  documentTypeRegistrations: [...COMMON_REGISTRATIONS],
16003
16418
  tools: (store) => [...createCommonTools(store)],
16004
16419
  promptFragments: {
@@ -16025,7 +16440,10 @@ var genericAgilePlugin = {
16025
16440
  - **list_contributions** / **get_contribution**: Browse and read contribution records.
16026
16441
  - **create_contribution**: Record a contribution with persona, type, and optional related artifact.
16027
16442
  - **update_contribution**: Update a contribution (e.g. append effects).
16028
- - Available contribution types: stakeholder-feedback, acceptance-result, priority-change, market-insight.`,
16443
+ - Available contribution types: stakeholder-feedback, acceptance-result, priority-change, market-insight.
16444
+
16445
+ **Sprint Tools (read-only for awareness):**
16446
+ - **list_sprints** / **get_sprint**: View sprints to understand delivery timelines and iteration scope.`,
16029
16447
  "tech-lead": `You own epics and break approved features into implementation work.
16030
16448
 
16031
16449
  **Epic Tools:**
@@ -16052,7 +16470,18 @@ var genericAgilePlugin = {
16052
16470
  - **list_contributions** / **get_contribution**: Browse and read contribution records.
16053
16471
  - **create_contribution**: Record a contribution with persona, type, and optional related artifact.
16054
16472
  - **update_contribution**: Update a contribution (e.g. append effects).
16055
- - Available contribution types: action-result, spike-findings, technical-assessment, architecture-review.`,
16473
+ - Available contribution types: action-result, spike-findings, technical-assessment, architecture-review.
16474
+
16475
+ **Sprint Tools:**
16476
+ - **list_sprints** / **get_sprint**: View sprints to understand iteration scope and delivery dates.
16477
+ - **update_sprint**: Assign epics to sprints by updating linkedEpics when breaking features into work.
16478
+ - Tag technical actions and decisions with \`sprint:SP-xxx\` to associate them with a sprint.
16479
+ - Use **generate_sprint_progress** to track technical work completion within an iteration.
16480
+
16481
+ **Sprint Planning:**
16482
+ - When asked to plan or propose a sprint, ALWAYS call **gather_sprint_planning_context** first.
16483
+ - Focus on: technical readiness of each epic, open technical questions or spikes, effort balance across the sprint, and feature coverage.
16484
+ - Present a structured sprint proposal with technical rationale for each selected epic, known technical risks, and any prerequisite work that should be completed first.`,
16056
16485
  "delivery-manager": `You track delivery across features and epics, manage schedules, and report on progress.
16057
16486
 
16058
16487
  **Report Tools:**
@@ -16086,14 +16515,35 @@ var genericAgilePlugin = {
16086
16515
  - **list_contributions** / **get_contribution**: Browse and read contribution records.
16087
16516
  - **create_contribution**: Record a contribution with persona, type, and optional related artifact.
16088
16517
  - **update_contribution**: Update a contribution (e.g. append effects).
16089
- - Available contribution types: risk-finding, blocker-report, dependency-update, status-assessment.`,
16090
- "*": `You have access to feature, epic, and meeting tools for project coordination:
16518
+ - Available contribution types: risk-finding, blocker-report, dependency-update, status-assessment.
16519
+
16520
+ **Sprint Tools:**
16521
+ - **list_sprints** / **get_sprint**: Browse and read sprint definitions.
16522
+ - **create_sprint**: Create sprints with dates, goals, and linked epics. Use status "planned" for upcoming sprints or "active"/"completed"/"cancelled" for current/past sprints.
16523
+ - **update_sprint**: Update sprint status, dates, goal, or linked epics. When linkedEpics changes, affected epics are re-tagged automatically.
16524
+ - **generate_sprint_progress**: Progress report for a specific sprint or all sprints \u2014 shows linked epics with statuses, work items tagged \`sprint:SP-xxx\` grouped by status, and done/total completion %.
16525
+ - Use \`save_report\` with reportType "sprint-progress" to persist sprint reports.
16526
+
16527
+ **Sprint Workflow:**
16528
+ - Create sprints with clear goals and date boundaries.
16529
+ - Assign epics to sprints via linkedEpics.
16530
+ - Tag work items (actions, decisions, questions) with \`sprint:SP-xxx\` for sprint scoping.
16531
+ - Track delivery dates and flag at-risk sprints.
16532
+ - Register past/completed sprints for historical tracking.
16533
+
16534
+ **Sprint Planning:**
16535
+ - When asked to plan or propose a sprint, ALWAYS call **gather_sprint_planning_context** first. It aggregates approved features, backlog epics, active sprint status, velocity from recent sprints, blockers, and summary stats in one call.
16536
+ - Reason through: priority (critical/high features first), capacity (compare backlog effort to velocity reference), dependencies and blockers, balance across features, and risk.
16537
+ - Present a structured sprint proposal: title, goal, suggested dates, selected epics with rationale for each, excluded epics with reason, and identified risks.
16538
+ - After user confirmation, use **create_sprint** with the agreed epics to persist the sprint.`,
16539
+ "*": `You have access to feature, epic, sprint, and meeting tools for project coordination:
16091
16540
 
16092
16541
  **Features** (F-xxx): Product capabilities defined by the Product Owner. Features progress through draft \u2192 approved \u2192 done.
16093
16542
  **Epics** (E-xxx): Implementation work packages created by the Tech Lead, linked to approved features. Epics progress through planned \u2192 in-progress \u2192 done.
16543
+ **Sprints** (SP-xxx): Time-boxed iterations that group epics and work items with delivery dates. Sprints progress through planned \u2192 active \u2192 completed (or cancelled).
16094
16544
  **Meetings**: Meeting records with attendees, agendas, and notes.
16095
16545
 
16096
- **Key workflow rule:** Epics must link to approved features \u2014 the system enforces this. The Product Owner defines and approves features, the Tech Lead breaks them into epics, and the Delivery Manager tracks dates and progress.
16546
+ **Key workflow rule:** Epics must link to approved features \u2014 the system enforces this. The Product Owner defines and approves features, the Tech Lead breaks them into epics, the Delivery Manager plans sprints and tracks dates and progress. Work items are associated with sprints via \`sprint:SP-xxx\` tags.
16097
16547
 
16098
16548
  - **list_meetings** / **get_meeting**: Browse and read meeting records.
16099
16549
  - **create_meeting**: Record meetings with attendees, date, and agenda. The meeting date is required \u2014 extract it from the meeting content or ask the user if not found.
@@ -16108,10 +16558,10 @@ var genericAgilePlugin = {
16108
16558
  };
16109
16559
 
16110
16560
  // src/plugins/builtin/tools/use-cases.ts
16111
- import { tool as tool12 } from "@anthropic-ai/claude-agent-sdk";
16561
+ import { tool as tool14 } from "@anthropic-ai/claude-agent-sdk";
16112
16562
  function createUseCaseTools(store) {
16113
16563
  return [
16114
- tool12(
16564
+ tool14(
16115
16565
  "list_use_cases",
16116
16566
  "List all extension use cases, optionally filtered by status or extension type",
16117
16567
  {
@@ -16141,7 +16591,7 @@ function createUseCaseTools(store) {
16141
16591
  },
16142
16592
  { annotations: { readOnly: true } }
16143
16593
  ),
16144
- tool12(
16594
+ tool14(
16145
16595
  "get_use_case",
16146
16596
  "Get the full content of a specific use case by ID",
16147
16597
  { id: external_exports.string().describe("Use case ID (e.g. 'UC-001')") },
@@ -16168,7 +16618,7 @@ function createUseCaseTools(store) {
16168
16618
  },
16169
16619
  { annotations: { readOnly: true } }
16170
16620
  ),
16171
- tool12(
16621
+ tool14(
16172
16622
  "create_use_case",
16173
16623
  "Create a new extension use case definition (Phase 1: Assess Extension Use Case)",
16174
16624
  {
@@ -16202,7 +16652,7 @@ function createUseCaseTools(store) {
16202
16652
  };
16203
16653
  }
16204
16654
  ),
16205
- tool12(
16655
+ tool14(
16206
16656
  "update_use_case",
16207
16657
  "Update an existing extension use case",
16208
16658
  {
@@ -16232,10 +16682,10 @@ function createUseCaseTools(store) {
16232
16682
  }
16233
16683
 
16234
16684
  // src/plugins/builtin/tools/tech-assessments.ts
16235
- import { tool as tool13 } from "@anthropic-ai/claude-agent-sdk";
16685
+ import { tool as tool15 } from "@anthropic-ai/claude-agent-sdk";
16236
16686
  function createTechAssessmentTools(store) {
16237
16687
  return [
16238
- tool13(
16688
+ tool15(
16239
16689
  "list_tech_assessments",
16240
16690
  "List all technology assessments, optionally filtered by status",
16241
16691
  {
@@ -16266,7 +16716,7 @@ function createTechAssessmentTools(store) {
16266
16716
  },
16267
16717
  { annotations: { readOnly: true } }
16268
16718
  ),
16269
- tool13(
16719
+ tool15(
16270
16720
  "get_tech_assessment",
16271
16721
  "Get the full content of a specific technology assessment by ID",
16272
16722
  { id: external_exports.string().describe("Tech assessment ID (e.g. 'TA-001')") },
@@ -16293,7 +16743,7 @@ function createTechAssessmentTools(store) {
16293
16743
  },
16294
16744
  { annotations: { readOnly: true } }
16295
16745
  ),
16296
- tool13(
16746
+ tool15(
16297
16747
  "create_tech_assessment",
16298
16748
  "Create a new technology assessment linked to an assessed/approved use case (Phase 2: Assess Extension Technology)",
16299
16749
  {
@@ -16364,7 +16814,7 @@ function createTechAssessmentTools(store) {
16364
16814
  };
16365
16815
  }
16366
16816
  ),
16367
- tool13(
16817
+ tool15(
16368
16818
  "update_tech_assessment",
16369
16819
  "Update an existing technology assessment. The linked use case cannot be changed.",
16370
16820
  {
@@ -16394,10 +16844,10 @@ function createTechAssessmentTools(store) {
16394
16844
  }
16395
16845
 
16396
16846
  // src/plugins/builtin/tools/extension-designs.ts
16397
- import { tool as tool14 } from "@anthropic-ai/claude-agent-sdk";
16847
+ import { tool as tool16 } from "@anthropic-ai/claude-agent-sdk";
16398
16848
  function createExtensionDesignTools(store) {
16399
16849
  return [
16400
- tool14(
16850
+ tool16(
16401
16851
  "list_extension_designs",
16402
16852
  "List all extension designs, optionally filtered by status",
16403
16853
  {
@@ -16427,7 +16877,7 @@ function createExtensionDesignTools(store) {
16427
16877
  },
16428
16878
  { annotations: { readOnly: true } }
16429
16879
  ),
16430
- tool14(
16880
+ tool16(
16431
16881
  "get_extension_design",
16432
16882
  "Get the full content of a specific extension design by ID",
16433
16883
  { id: external_exports.string().describe("Extension design ID (e.g. 'XD-001')") },
@@ -16454,7 +16904,7 @@ function createExtensionDesignTools(store) {
16454
16904
  },
16455
16905
  { annotations: { readOnly: true } }
16456
16906
  ),
16457
- tool14(
16907
+ tool16(
16458
16908
  "create_extension_design",
16459
16909
  "Create a new extension design linked to a recommended tech assessment (Phase 3: Define Extension Target Solution)",
16460
16910
  {
@@ -16522,7 +16972,7 @@ function createExtensionDesignTools(store) {
16522
16972
  };
16523
16973
  }
16524
16974
  ),
16525
- tool14(
16975
+ tool16(
16526
16976
  "update_extension_design",
16527
16977
  "Update an existing extension design. The linked tech assessment cannot be changed.",
16528
16978
  {
@@ -16551,10 +17001,10 @@ function createExtensionDesignTools(store) {
16551
17001
  }
16552
17002
 
16553
17003
  // src/plugins/builtin/tools/aem-reports.ts
16554
- import { tool as tool15 } from "@anthropic-ai/claude-agent-sdk";
17004
+ import { tool as tool17 } from "@anthropic-ai/claude-agent-sdk";
16555
17005
  function createAemReportTools(store) {
16556
17006
  return [
16557
- tool15(
17007
+ tool17(
16558
17008
  "generate_extension_portfolio",
16559
17009
  "Generate a portfolio view of all use cases with their linked tech assessments and extension designs",
16560
17010
  {},
@@ -16606,7 +17056,7 @@ function createAemReportTools(store) {
16606
17056
  },
16607
17057
  { annotations: { readOnly: true } }
16608
17058
  ),
16609
- tool15(
17059
+ tool17(
16610
17060
  "generate_tech_readiness",
16611
17061
  "Generate a BTP technology readiness report showing service coverage and gaps across assessments",
16612
17062
  {},
@@ -16658,7 +17108,7 @@ function createAemReportTools(store) {
16658
17108
  },
16659
17109
  { annotations: { readOnly: true } }
16660
17110
  ),
16661
- tool15(
17111
+ tool17(
16662
17112
  "generate_phase_status",
16663
17113
  "Generate a phase progress report showing artifact counts and readiness per AEM phase",
16664
17114
  {},
@@ -16720,11 +17170,11 @@ function createAemReportTools(store) {
16720
17170
  import * as fs6 from "fs";
16721
17171
  import * as path6 from "path";
16722
17172
  import * as YAML4 from "yaml";
16723
- import { tool as tool16 } from "@anthropic-ai/claude-agent-sdk";
17173
+ import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
16724
17174
  var PHASES = ["assess-use-case", "assess-technology", "define-solution"];
16725
17175
  function createAemPhaseTools(store, marvinDir) {
16726
17176
  return [
16727
- tool16(
17177
+ tool18(
16728
17178
  "get_current_phase",
16729
17179
  "Get the current AEM phase from project configuration",
16730
17180
  {},
@@ -16745,7 +17195,7 @@ function createAemPhaseTools(store, marvinDir) {
16745
17195
  },
16746
17196
  { annotations: { readOnly: true } }
16747
17197
  ),
16748
- tool16(
17198
+ tool18(
16749
17199
  "advance_phase",
16750
17200
  "Advance to the next AEM phase. Performs soft gate checks and warns if artifacts are incomplete, but does not block.",
16751
17201
  {
@@ -17520,7 +17970,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17520
17970
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17521
17971
 
17522
17972
  // src/skills/action-tools.ts
17523
- import { tool as tool17 } from "@anthropic-ai/claude-agent-sdk";
17973
+ import { tool as tool19 } from "@anthropic-ai/claude-agent-sdk";
17524
17974
 
17525
17975
  // src/skills/action-runner.ts
17526
17976
  import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
@@ -17586,7 +18036,7 @@ function createSkillActionTools(skills, context) {
17586
18036
  if (!skill.actions) continue;
17587
18037
  for (const action of skill.actions) {
17588
18038
  tools.push(
17589
- tool17(
18039
+ tool19(
17590
18040
  `${skill.id}__${action.id}`,
17591
18041
  action.description,
17592
18042
  {
@@ -17678,10 +18128,10 @@ ${lines.join("\n\n")}`;
17678
18128
  }
17679
18129
 
17680
18130
  // src/mcp/persona-tools.ts
17681
- import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
18131
+ import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
17682
18132
  function createPersonaTools(ctx, marvinDir) {
17683
18133
  return [
17684
- tool18(
18134
+ tool20(
17685
18135
  "set_persona",
17686
18136
  "Set the active persona for this session. Returns full guidance for the selected persona including behavioral rules, allowed document types, and scope. Call this before working to ensure persona-appropriate behavior.",
17687
18137
  {
@@ -17711,7 +18161,7 @@ ${summaries}`
17711
18161
  };
17712
18162
  }
17713
18163
  ),
17714
- tool18(
18164
+ tool20(
17715
18165
  "get_persona_guidance",
17716
18166
  "Get guidance for a persona without changing the active persona. If no persona is specified, lists all available personas with summaries.",
17717
18167
  {
@@ -19338,7 +19788,8 @@ function getDirNameForType(store, type) {
19338
19788
  meeting: "meetings",
19339
19789
  report: "reports",
19340
19790
  feature: "features",
19341
- epic: "epics"
19791
+ epic: "epics",
19792
+ sprint: "sprints"
19342
19793
  };
19343
19794
  return typeDir[type] ?? `${type}s`;
19344
19795
  }
@@ -20245,7 +20696,7 @@ function createProgram() {
20245
20696
  const program = new Command();
20246
20697
  program.name("marvin").description(
20247
20698
  "AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
20248
- ).version("0.2.4");
20699
+ ).version("0.2.6");
20249
20700
  program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
20250
20701
  await initCommand();
20251
20702
  });