mrvn-cli 0.5.11 → 0.5.13
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 +183 -18
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +182 -17
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +183 -18
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin.js
CHANGED
|
@@ -14635,9 +14635,14 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
14635
14635
|
};
|
|
14636
14636
|
});
|
|
14637
14637
|
const sprintTag = `sprint:${fm.id}`;
|
|
14638
|
-
const
|
|
14638
|
+
const sprintTaggedDocs = allDocs.filter(
|
|
14639
14639
|
(d) => d.frontmatter.type !== "sprint" && d.frontmatter.type !== "epic" && d.frontmatter.type !== "meeting" && d.frontmatter.type !== "decision" && d.frontmatter.type !== "question" && d.frontmatter.tags?.includes(sprintTag)
|
|
14640
14640
|
);
|
|
14641
|
+
const sprintTaggedIds = new Set(sprintTaggedDocs.map((d) => d.frontmatter.id));
|
|
14642
|
+
const orphanContributions = allDocs.filter(
|
|
14643
|
+
(d) => d.frontmatter.type === "contribution" && !sprintTaggedIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintTaggedIds.has(d.frontmatter.aboutArtifact)
|
|
14644
|
+
);
|
|
14645
|
+
const workItemDocs = [...sprintTaggedDocs, ...orphanContributions];
|
|
14641
14646
|
const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
|
|
14642
14647
|
const byStatus = {};
|
|
14643
14648
|
const byType = {};
|
|
@@ -14656,7 +14661,7 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
14656
14661
|
}
|
|
14657
14662
|
const allItemsById = /* @__PURE__ */ new Map();
|
|
14658
14663
|
const childrenByParent = /* @__PURE__ */ new Map();
|
|
14659
|
-
const
|
|
14664
|
+
const workItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
|
|
14660
14665
|
for (const doc of workItemDocs) {
|
|
14661
14666
|
const about = doc.frontmatter.aboutArtifact;
|
|
14662
14667
|
const focusTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("focus:"));
|
|
@@ -14670,10 +14675,12 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
14670
14675
|
workFocus: focusTag ? focusTag.slice(6) : void 0,
|
|
14671
14676
|
aboutArtifact: about,
|
|
14672
14677
|
jiraKey: doc.frontmatter.jiraKey,
|
|
14673
|
-
jiraUrl: doc.frontmatter.jiraUrl
|
|
14678
|
+
jiraUrl: doc.frontmatter.jiraUrl,
|
|
14679
|
+
confluenceUrl: doc.frontmatter.confluenceUrl,
|
|
14680
|
+
confluenceTitle: doc.frontmatter.confluenceTitle
|
|
14674
14681
|
};
|
|
14675
14682
|
allItemsById.set(item.id, item);
|
|
14676
|
-
if (about &&
|
|
14683
|
+
if (about && workItemIds.has(about)) {
|
|
14677
14684
|
if (!childrenByParent.has(about)) childrenByParent.set(about, []);
|
|
14678
14685
|
childrenByParent.get(about).push(item);
|
|
14679
14686
|
}
|
|
@@ -19356,11 +19363,30 @@ function formatDate(iso) {
|
|
|
19356
19363
|
function typeLabel(type) {
|
|
19357
19364
|
return type.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
19358
19365
|
}
|
|
19366
|
+
var JIRA_SVG = `<svg class="integration-icon" viewBox="0 0 256 256" width="14" height="14" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="jg1" x1="98.03%" y1="0.16%" x2="58.89%" y2="40.87%"><stop offset="18%" stop-color="#0052CC"/><stop offset="100%" stop-color="#2684FF"/></linearGradient><linearGradient id="jg2" x1="100.17%" y1="0.05%" x2="55.76%" y2="45.19%"><stop offset="18%" stop-color="#0052CC"/><stop offset="100%" stop-color="#2684FF"/></linearGradient></defs><path d="M244.658 0H121.707a55.502 55.502 0 0 0 55.502 55.502h22.649V77.37c.02 30.625 24.841 55.447 55.466 55.502V10.666C255.324 4.777 250.55 0 244.658 0z" fill="#2684FF"/><path d="M183.822 61.262H60.872c.019 30.625 24.84 55.447 55.466 55.502h22.649v21.868c.02 30.597 24.798 55.408 55.395 55.502V71.928c0-5.891-4.776-10.666-10.56-10.666z" fill="url(#jg1)"/><path d="M122.951 122.489H0c0 30.653 24.85 55.502 55.502 55.502h22.72v21.868c.02 30.597 24.798 55.408 55.396 55.502V133.155c0-5.891-4.776-10.666-10.667-10.666z" fill="url(#jg2)"/></svg>`;
|
|
19367
|
+
var CONFLUENCE_SVG = `<svg class="integration-icon" viewBox="0 0 256 246" width="14" height="14" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="cg1" x1="99.14%" y1="113.9%" x2="33.86%" y2="37.96%"><stop offset="18%" stop-color="#0052CC"/><stop offset="100%" stop-color="#2684FF"/></linearGradient><linearGradient id="cg2" x1="0.86%" y1="-13.9%" x2="66.14%" y2="62.04%"><stop offset="18%" stop-color="#0052CC"/><stop offset="100%" stop-color="#2684FF"/></linearGradient></defs><path d="M9.26 187.28c-3.14 5.06-6.71 10.98-9.26 15.53a7.84 7.84 0 0 0 2.83 10.72l67.58 40.48a7.85 7.85 0 0 0 10.72-2.63c2.14-3.54 5.01-8.25 8.15-13.41 22.18-36.47 44.67-32.02 85.83-13.41l68.59 31.05a7.85 7.85 0 0 0 10.42-3.94l29.24-66.24a7.85 7.85 0 0 0-3.84-10.32c-20.53-9.27-61.49-27.75-87.33-39.45-72.2-32.73-133.87-30.05-182.93 51.62z" fill="url(#cg1)"/><path d="M246.11 58.24c3.14-5.06 6.71-10.98 9.26-15.53a7.84 7.84 0 0 0-2.83-10.72L184.96 0a7.85 7.85 0 0 0-10.72 2.63c-2.14 3.54-5.01 8.25-8.15 13.41-22.18 36.47-44.67 32.02-85.83 13.41L12.37 -1.6a7.85 7.85 0 0 0-10.42 3.94L-27.29 68.58a7.85 7.85 0 0 0 3.84 10.32c20.53 9.27 61.49 27.75 87.33 39.45 72.2 32.73 133.87 30.05 182.23-60.11z" fill="url(#cg2)"/></svg>`;
|
|
19359
19368
|
function jiraIcon(jiraKey, jiraUrl) {
|
|
19360
19369
|
if (!jiraKey) return "";
|
|
19361
19370
|
const href = jiraUrl ?? "#";
|
|
19362
19371
|
const title = escapeHtml(jiraKey);
|
|
19363
|
-
return `<a href="${escapeHtml(href)}" target="_blank" rel="noopener" title="Jira: ${title}" class="
|
|
19372
|
+
return `<a href="${escapeHtml(href)}" target="_blank" rel="noopener" title="Jira: ${title}" class="integration-link jira-link">${JIRA_SVG}</a>`;
|
|
19373
|
+
}
|
|
19374
|
+
function confluenceIcon(confluenceUrl, confluenceTitle) {
|
|
19375
|
+
if (!confluenceUrl) return "";
|
|
19376
|
+
const title = confluenceTitle ? escapeHtml(confluenceTitle) : "Confluence";
|
|
19377
|
+
return `<a href="${escapeHtml(confluenceUrl)}" target="_blank" rel="noopener" title="${title}" class="integration-link confluence-link">${CONFLUENCE_SVG}</a>`;
|
|
19378
|
+
}
|
|
19379
|
+
function integrationIcons(frontmatter) {
|
|
19380
|
+
const jira = jiraIcon(
|
|
19381
|
+
frontmatter.jiraKey,
|
|
19382
|
+
frontmatter.jiraUrl
|
|
19383
|
+
);
|
|
19384
|
+
const confluence = confluenceIcon(
|
|
19385
|
+
frontmatter.confluenceUrl,
|
|
19386
|
+
frontmatter.confluenceTitle
|
|
19387
|
+
);
|
|
19388
|
+
if (!jira && !confluence) return "";
|
|
19389
|
+
return `<span class="integration-icons">${jira}${confluence}</span>`;
|
|
19364
19390
|
}
|
|
19365
19391
|
function renderMarkdown(md) {
|
|
19366
19392
|
const lines = md.split("\n");
|
|
@@ -21227,17 +21253,22 @@ tr:hover td {
|
|
|
21227
21253
|
.owner-badge-dm { background: rgba(52, 211, 153, 0.18); color: #34d399; }
|
|
21228
21254
|
.owner-badge-other { background: rgba(139, 143, 164, 0.12); color: var(--text-dim); }
|
|
21229
21255
|
|
|
21230
|
-
/* Jira
|
|
21231
|
-
.
|
|
21256
|
+
/* Integration icons (Jira, Confluence) */
|
|
21257
|
+
.integration-icons {
|
|
21232
21258
|
display: inline-flex;
|
|
21233
21259
|
align-items: center;
|
|
21260
|
+
gap: 0.25rem;
|
|
21234
21261
|
vertical-align: middle;
|
|
21235
|
-
margin-left: 0.
|
|
21262
|
+
margin-left: 0.5rem;
|
|
21263
|
+
}
|
|
21264
|
+
.integration-link {
|
|
21265
|
+
display: inline-flex;
|
|
21266
|
+
align-items: center;
|
|
21236
21267
|
opacity: 0.7;
|
|
21237
21268
|
transition: opacity 0.15s;
|
|
21238
21269
|
}
|
|
21239
|
-
.
|
|
21240
|
-
.
|
|
21270
|
+
.integration-link:hover { opacity: 1; }
|
|
21271
|
+
.integration-icon { vertical-align: middle; }
|
|
21241
21272
|
|
|
21242
21273
|
/* Group header rows (PO dashboard decisions/deps) */
|
|
21243
21274
|
.group-header-row td {
|
|
@@ -21263,7 +21294,7 @@ function documentsPage(data) {
|
|
|
21263
21294
|
(doc) => `
|
|
21264
21295
|
<tr>
|
|
21265
21296
|
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.id)}</a></td>
|
|
21266
|
-
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.title)}</a>${
|
|
21297
|
+
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.title)}</a>${integrationIcons(doc.frontmatter)}</td>
|
|
21267
21298
|
<td>${statusBadge(doc.frontmatter.status)}</td>
|
|
21268
21299
|
<td>${escapeHtml(doc.frontmatter.owner ?? "\u2014")}</td>
|
|
21269
21300
|
<td>${doc.frontmatter.priority ? `<span class="priority-${doc.frontmatter.priority.toLowerCase()}">${escapeHtml(doc.frontmatter.priority)}</span>` : "\u2014"}</td>
|
|
@@ -21352,7 +21383,7 @@ function documentDetailPage(doc) {
|
|
|
21352
21383
|
</div>
|
|
21353
21384
|
|
|
21354
21385
|
<div class="page-header">
|
|
21355
|
-
<h2>${escapeHtml(fm.title)}${
|
|
21386
|
+
<h2>${escapeHtml(fm.title)}${integrationIcons(fm)}</h2>
|
|
21356
21387
|
<div class="subtitle">${escapeHtml(fm.id)} · ${escapeHtml(label)}</div>
|
|
21357
21388
|
</div>
|
|
21358
21389
|
|
|
@@ -22645,7 +22676,7 @@ function renderItemRows(items, borderColor, showOwner, depth = 0) {
|
|
|
22645
22676
|
const row = `
|
|
22646
22677
|
<tr class="${classes.join(" ")}" style="--focus-color: ${borderColor}">
|
|
22647
22678
|
<td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
|
|
22648
|
-
<td>${escapeHtml(w.title)}${jiraIcon(w.jiraKey, w.jiraUrl)}</td>
|
|
22679
|
+
<td>${escapeHtml(w.title)}${jiraIcon(w.jiraKey, w.jiraUrl)}${confluenceIcon(w.confluenceUrl, w.confluenceTitle)}</td>
|
|
22649
22680
|
${ownerCell}
|
|
22650
22681
|
<td>${statusBadge(w.status)}</td>
|
|
22651
22682
|
<td>${progressCell}</td>
|
|
@@ -24270,7 +24301,7 @@ function boardPage(data, basePath = "/board") {
|
|
|
24270
24301
|
<div class="board-card">
|
|
24271
24302
|
<a href="/docs/${doc.frontmatter.type}/${doc.frontmatter.id}">
|
|
24272
24303
|
<div class="bc-id">${escapeHtml(doc.frontmatter.id)}</div>
|
|
24273
|
-
<div class="bc-title">${escapeHtml(doc.frontmatter.title)}${
|
|
24304
|
+
<div class="bc-title">${escapeHtml(doc.frontmatter.title)}${integrationIcons(doc.frontmatter)}</div>
|
|
24274
24305
|
${doc.frontmatter.owner ? `<div class="bc-owner">${escapeHtml(doc.frontmatter.owner)}</div>` : ""}
|
|
24275
24306
|
</a>
|
|
24276
24307
|
</div>`
|
|
@@ -25162,11 +25193,14 @@ import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
25162
25193
|
var JiraClient = class {
|
|
25163
25194
|
baseUrl;
|
|
25164
25195
|
baseUrlV3;
|
|
25196
|
+
confluenceBaseUrl;
|
|
25165
25197
|
authHeader;
|
|
25198
|
+
host;
|
|
25166
25199
|
constructor(config2) {
|
|
25167
|
-
|
|
25168
|
-
this.baseUrl = `https://${host}/rest/api/2`;
|
|
25169
|
-
this.baseUrlV3 = `https://${host}/rest/api/3`;
|
|
25200
|
+
this.host = config2.host.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
25201
|
+
this.baseUrl = `https://${this.host}/rest/api/2`;
|
|
25202
|
+
this.baseUrlV3 = `https://${this.host}/rest/api/3`;
|
|
25203
|
+
this.confluenceBaseUrl = `https://${this.host}/wiki/api/v2`;
|
|
25170
25204
|
this.authHeader = "Basic " + Buffer.from(`${config2.email}:${config2.apiToken}`).toString("base64");
|
|
25171
25205
|
}
|
|
25172
25206
|
async request(path21, method = "GET", body) {
|
|
@@ -25254,6 +25288,30 @@ var JiraClient = class {
|
|
|
25254
25288
|
{ body }
|
|
25255
25289
|
);
|
|
25256
25290
|
}
|
|
25291
|
+
// --- Confluence methods ---
|
|
25292
|
+
async getConfluencePage(pageId) {
|
|
25293
|
+
return this.doRequest(
|
|
25294
|
+
`${this.confluenceBaseUrl}/pages/${encodeURIComponent(pageId)}?body-format=atlas_doc_format`,
|
|
25295
|
+
"GET"
|
|
25296
|
+
);
|
|
25297
|
+
}
|
|
25298
|
+
/**
|
|
25299
|
+
* Extract a Confluence page ID from various URL formats.
|
|
25300
|
+
* Returns null if the URL doesn't match any known pattern.
|
|
25301
|
+
*/
|
|
25302
|
+
static extractPageId(url2) {
|
|
25303
|
+
const pagesMatch = url2.match(/\/pages\/(\d+)/);
|
|
25304
|
+
if (pagesMatch) return pagesMatch[1];
|
|
25305
|
+
const paramMatch = url2.match(/[?&]pageId=(\d+)/);
|
|
25306
|
+
if (paramMatch) return paramMatch[1];
|
|
25307
|
+
return null;
|
|
25308
|
+
}
|
|
25309
|
+
/**
|
|
25310
|
+
* Build a web URL for a Confluence page.
|
|
25311
|
+
*/
|
|
25312
|
+
getConfluencePageUrl(pageId) {
|
|
25313
|
+
return `https://${this.host}/wiki/pages/viewpage.action?pageId=${pageId}`;
|
|
25314
|
+
}
|
|
25257
25315
|
};
|
|
25258
25316
|
function createJiraClient(jiraUserConfig) {
|
|
25259
25317
|
const host = jiraUserConfig?.host ?? process.env.JIRA_HOST;
|
|
@@ -26354,6 +26412,111 @@ function createJiraTools(store, projectConfig) {
|
|
|
26354
26412
|
};
|
|
26355
26413
|
}
|
|
26356
26414
|
),
|
|
26415
|
+
// --- Confluence tools ---
|
|
26416
|
+
tool20(
|
|
26417
|
+
"link_to_confluence",
|
|
26418
|
+
"Link a Confluence page to any Marvin artifact. Validates the page exists and fetches its title.",
|
|
26419
|
+
{
|
|
26420
|
+
artifactId: external_exports.string().describe("Marvin artifact ID (e.g. 'D-001', 'A-003', 'T-002')"),
|
|
26421
|
+
confluenceUrl: external_exports.string().describe("Confluence page URL")
|
|
26422
|
+
},
|
|
26423
|
+
async (args) => {
|
|
26424
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
26425
|
+
if (!jira) return jiraNotConfiguredError();
|
|
26426
|
+
const artifact = store.get(args.artifactId);
|
|
26427
|
+
if (!artifact) {
|
|
26428
|
+
return {
|
|
26429
|
+
content: [
|
|
26430
|
+
{ type: "text", text: `Artifact ${args.artifactId} not found` }
|
|
26431
|
+
],
|
|
26432
|
+
isError: true
|
|
26433
|
+
};
|
|
26434
|
+
}
|
|
26435
|
+
const pageId = JiraClient.extractPageId(args.confluenceUrl);
|
|
26436
|
+
if (!pageId) {
|
|
26437
|
+
return {
|
|
26438
|
+
content: [
|
|
26439
|
+
{ type: "text", text: `Could not extract page ID from URL: ${args.confluenceUrl}` }
|
|
26440
|
+
],
|
|
26441
|
+
isError: true
|
|
26442
|
+
};
|
|
26443
|
+
}
|
|
26444
|
+
const page = await jira.client.getConfluencePage(pageId);
|
|
26445
|
+
const existingTags = artifact.frontmatter.tags ?? [];
|
|
26446
|
+
store.update(args.artifactId, {
|
|
26447
|
+
confluenceUrl: args.confluenceUrl,
|
|
26448
|
+
confluencePageId: pageId,
|
|
26449
|
+
confluenceTitle: page.title,
|
|
26450
|
+
tags: [...existingTags.filter((t) => !t.startsWith("confluence:")), `confluence:${page.title}`]
|
|
26451
|
+
});
|
|
26452
|
+
return {
|
|
26453
|
+
content: [
|
|
26454
|
+
{
|
|
26455
|
+
type: "text",
|
|
26456
|
+
text: `Linked ${args.artifactId} to Confluence page "${page.title}" (ID: ${pageId}).`
|
|
26457
|
+
}
|
|
26458
|
+
]
|
|
26459
|
+
};
|
|
26460
|
+
}
|
|
26461
|
+
),
|
|
26462
|
+
tool20(
|
|
26463
|
+
"read_confluence_page",
|
|
26464
|
+
"Read the content of a Confluence page by URL or page ID. Returns the page title, metadata, and body as plain text.",
|
|
26465
|
+
{
|
|
26466
|
+
pageUrl: external_exports.string().optional().describe("Confluence page URL"),
|
|
26467
|
+
pageId: external_exports.string().optional().describe("Confluence page ID (alternative to URL)")
|
|
26468
|
+
},
|
|
26469
|
+
async (args) => {
|
|
26470
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
26471
|
+
if (!jira) return jiraNotConfiguredError();
|
|
26472
|
+
const resolvedId = args.pageId ?? (args.pageUrl ? JiraClient.extractPageId(args.pageUrl) : null);
|
|
26473
|
+
if (!resolvedId) {
|
|
26474
|
+
return {
|
|
26475
|
+
content: [
|
|
26476
|
+
{
|
|
26477
|
+
type: "text",
|
|
26478
|
+
text: "Provide either pageUrl or pageId. Could not extract page ID from the given URL."
|
|
26479
|
+
}
|
|
26480
|
+
],
|
|
26481
|
+
isError: true
|
|
26482
|
+
};
|
|
26483
|
+
}
|
|
26484
|
+
const page = await jira.client.getConfluencePage(resolvedId);
|
|
26485
|
+
let bodyText = "";
|
|
26486
|
+
if (page.body?.atlas_doc_format?.value) {
|
|
26487
|
+
try {
|
|
26488
|
+
const adf = JSON.parse(page.body.atlas_doc_format.value);
|
|
26489
|
+
bodyText = extractCommentText(adf);
|
|
26490
|
+
} catch {
|
|
26491
|
+
bodyText = page.body.atlas_doc_format.value;
|
|
26492
|
+
}
|
|
26493
|
+
}
|
|
26494
|
+
const parts = [
|
|
26495
|
+
`# ${page.title}`,
|
|
26496
|
+
"",
|
|
26497
|
+
`Page ID: ${page.id}`,
|
|
26498
|
+
`Status: ${page.status}`,
|
|
26499
|
+
`Version: ${page.version.number} (${page.version.createdAt.slice(0, 10)})`,
|
|
26500
|
+
"",
|
|
26501
|
+
"---",
|
|
26502
|
+
"",
|
|
26503
|
+
bodyText || "(empty page)"
|
|
26504
|
+
];
|
|
26505
|
+
const allDocs = store.registeredTypes.flatMap((t) => store.list({ type: t }));
|
|
26506
|
+
const linkedArtifacts = allDocs.filter(
|
|
26507
|
+
(d) => d.frontmatter.confluencePageId === resolvedId || d.frontmatter.confluenceUrl === args.pageUrl
|
|
26508
|
+
);
|
|
26509
|
+
if (linkedArtifacts.length > 0) {
|
|
26510
|
+
parts.push("");
|
|
26511
|
+
parts.push("---");
|
|
26512
|
+
parts.push(`Linked Marvin artifacts: ${linkedArtifacts.map((d) => d.frontmatter.id).join(", ")}`);
|
|
26513
|
+
}
|
|
26514
|
+
return {
|
|
26515
|
+
content: [{ type: "text", text: parts.join("\n") }]
|
|
26516
|
+
};
|
|
26517
|
+
},
|
|
26518
|
+
{ annotations: { readOnlyHint: true } }
|
|
26519
|
+
),
|
|
26357
26520
|
// --- Jira status fetch (read-only) ---
|
|
26358
26521
|
tool20(
|
|
26359
26522
|
"fetch_jira_status",
|
|
@@ -26664,6 +26827,8 @@ function formatIssueEntry(issue2) {
|
|
|
26664
26827
|
var COMMON_TOOLS = `**Available tools:**
|
|
26665
26828
|
- \`push_artifact_to_jira\` \u2014 create a Jira issue from any Marvin artifact and link it directly via \`jiraKey\` on the artifact.
|
|
26666
26829
|
- \`link_to_jira\` \u2014 link an existing Jira issue to any Marvin artifact (sets \`jiraKey\` directly on the artifact).
|
|
26830
|
+
- \`link_to_confluence\` \u2014 link a Confluence page to any Marvin artifact. Validates the page exists and fetches its title.
|
|
26831
|
+
- \`read_confluence_page\` \u2014 **read-only**: fetch and return the content of a Confluence page by URL or page ID. Use this to review Confluence content for updating tasks, generating contributions, or answering questions.
|
|
26667
26832
|
- \`fetch_jira_status\` \u2014 **read-only**: fetch current Jira status, subtask progress, and linked issues for Jira-linked actions/tasks. Returns proposed changes without applying them.
|
|
26668
26833
|
- \`fetch_jira_daily\` \u2014 **read-only**: fetch a daily/range summary of all Jira changes \u2014 status transitions, comments, linked Confluence pages, and cross-references with Marvin artifacts. Returns proposed actions (status updates, unlinked issues, question candidates, Confluence pages to review).
|
|
26669
26834
|
- \`fetch_jira_statuses\` \u2014 **read-only**: discover all Jira statuses in a project and show their Marvin mappings (mapped vs unmapped).
|
|
@@ -31940,7 +32105,7 @@ function createProgram() {
|
|
|
31940
32105
|
const program2 = new Command();
|
|
31941
32106
|
program2.name("marvin").description(
|
|
31942
32107
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
31943
|
-
).version("0.5.
|
|
32108
|
+
).version("0.5.13");
|
|
31944
32109
|
program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
31945
32110
|
await initCommand();
|
|
31946
32111
|
});
|