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/index.js
CHANGED
|
@@ -15740,9 +15740,14 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15740
15740
|
};
|
|
15741
15741
|
});
|
|
15742
15742
|
const sprintTag = `sprint:${fm.id}`;
|
|
15743
|
-
const
|
|
15743
|
+
const sprintTaggedDocs = allDocs.filter(
|
|
15744
15744
|
(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)
|
|
15745
15745
|
);
|
|
15746
|
+
const sprintTaggedIds = new Set(sprintTaggedDocs.map((d) => d.frontmatter.id));
|
|
15747
|
+
const orphanContributions = allDocs.filter(
|
|
15748
|
+
(d) => d.frontmatter.type === "contribution" && !sprintTaggedIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintTaggedIds.has(d.frontmatter.aboutArtifact)
|
|
15749
|
+
);
|
|
15750
|
+
const workItemDocs = [...sprintTaggedDocs, ...orphanContributions];
|
|
15746
15751
|
const primaryDocs = workItemDocs.filter((d) => d.frontmatter.type !== "contribution");
|
|
15747
15752
|
const byStatus = {};
|
|
15748
15753
|
const byType = {};
|
|
@@ -15761,7 +15766,7 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15761
15766
|
}
|
|
15762
15767
|
const allItemsById = /* @__PURE__ */ new Map();
|
|
15763
15768
|
const childrenByParent = /* @__PURE__ */ new Map();
|
|
15764
|
-
const
|
|
15769
|
+
const workItemIds = new Set(workItemDocs.map((d) => d.frontmatter.id));
|
|
15765
15770
|
for (const doc of workItemDocs) {
|
|
15766
15771
|
const about = doc.frontmatter.aboutArtifact;
|
|
15767
15772
|
const focusTag = (doc.frontmatter.tags ?? []).find((t) => t.startsWith("focus:"));
|
|
@@ -15775,10 +15780,12 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
15775
15780
|
workFocus: focusTag ? focusTag.slice(6) : void 0,
|
|
15776
15781
|
aboutArtifact: about,
|
|
15777
15782
|
jiraKey: doc.frontmatter.jiraKey,
|
|
15778
|
-
jiraUrl: doc.frontmatter.jiraUrl
|
|
15783
|
+
jiraUrl: doc.frontmatter.jiraUrl,
|
|
15784
|
+
confluenceUrl: doc.frontmatter.confluenceUrl,
|
|
15785
|
+
confluenceTitle: doc.frontmatter.confluenceTitle
|
|
15779
15786
|
};
|
|
15780
15787
|
allItemsById.set(item.id, item);
|
|
15781
|
-
if (about &&
|
|
15788
|
+
if (about && workItemIds.has(about)) {
|
|
15782
15789
|
if (!childrenByParent.has(about)) childrenByParent.set(about, []);
|
|
15783
15790
|
childrenByParent.get(about).push(item);
|
|
15784
15791
|
}
|
|
@@ -16286,11 +16293,30 @@ function formatDate(iso) {
|
|
|
16286
16293
|
function typeLabel(type) {
|
|
16287
16294
|
return type.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
16288
16295
|
}
|
|
16296
|
+
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>`;
|
|
16297
|
+
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>`;
|
|
16289
16298
|
function jiraIcon(jiraKey, jiraUrl) {
|
|
16290
16299
|
if (!jiraKey) return "";
|
|
16291
16300
|
const href = jiraUrl ?? "#";
|
|
16292
16301
|
const title = escapeHtml(jiraKey);
|
|
16293
|
-
return `<a href="${escapeHtml(href)}" target="_blank" rel="noopener" title="Jira: ${title}" class="
|
|
16302
|
+
return `<a href="${escapeHtml(href)}" target="_blank" rel="noopener" title="Jira: ${title}" class="integration-link jira-link">${JIRA_SVG}</a>`;
|
|
16303
|
+
}
|
|
16304
|
+
function confluenceIcon(confluenceUrl, confluenceTitle) {
|
|
16305
|
+
if (!confluenceUrl) return "";
|
|
16306
|
+
const title = confluenceTitle ? escapeHtml(confluenceTitle) : "Confluence";
|
|
16307
|
+
return `<a href="${escapeHtml(confluenceUrl)}" target="_blank" rel="noopener" title="${title}" class="integration-link confluence-link">${CONFLUENCE_SVG}</a>`;
|
|
16308
|
+
}
|
|
16309
|
+
function integrationIcons(frontmatter) {
|
|
16310
|
+
const jira = jiraIcon(
|
|
16311
|
+
frontmatter.jiraKey,
|
|
16312
|
+
frontmatter.jiraUrl
|
|
16313
|
+
);
|
|
16314
|
+
const confluence = confluenceIcon(
|
|
16315
|
+
frontmatter.confluenceUrl,
|
|
16316
|
+
frontmatter.confluenceTitle
|
|
16317
|
+
);
|
|
16318
|
+
if (!jira && !confluence) return "";
|
|
16319
|
+
return `<span class="integration-icons">${jira}${confluence}</span>`;
|
|
16294
16320
|
}
|
|
16295
16321
|
function renderMarkdown(md) {
|
|
16296
16322
|
const lines = md.split("\n");
|
|
@@ -18157,17 +18183,22 @@ tr:hover td {
|
|
|
18157
18183
|
.owner-badge-dm { background: rgba(52, 211, 153, 0.18); color: #34d399; }
|
|
18158
18184
|
.owner-badge-other { background: rgba(139, 143, 164, 0.12); color: var(--text-dim); }
|
|
18159
18185
|
|
|
18160
|
-
/* Jira
|
|
18161
|
-
.
|
|
18186
|
+
/* Integration icons (Jira, Confluence) */
|
|
18187
|
+
.integration-icons {
|
|
18162
18188
|
display: inline-flex;
|
|
18163
18189
|
align-items: center;
|
|
18190
|
+
gap: 0.25rem;
|
|
18164
18191
|
vertical-align: middle;
|
|
18165
|
-
margin-left: 0.
|
|
18192
|
+
margin-left: 0.5rem;
|
|
18193
|
+
}
|
|
18194
|
+
.integration-link {
|
|
18195
|
+
display: inline-flex;
|
|
18196
|
+
align-items: center;
|
|
18166
18197
|
opacity: 0.7;
|
|
18167
18198
|
transition: opacity 0.15s;
|
|
18168
18199
|
}
|
|
18169
|
-
.
|
|
18170
|
-
.
|
|
18200
|
+
.integration-link:hover { opacity: 1; }
|
|
18201
|
+
.integration-icon { vertical-align: middle; }
|
|
18171
18202
|
|
|
18172
18203
|
/* Group header rows (PO dashboard decisions/deps) */
|
|
18173
18204
|
.group-header-row td {
|
|
@@ -18193,7 +18224,7 @@ function documentsPage(data) {
|
|
|
18193
18224
|
(doc) => `
|
|
18194
18225
|
<tr>
|
|
18195
18226
|
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.id)}</a></td>
|
|
18196
|
-
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.title)}</a>${
|
|
18227
|
+
<td><a href="/docs/${data.type}/${doc.frontmatter.id}">${escapeHtml(doc.frontmatter.title)}</a>${integrationIcons(doc.frontmatter)}</td>
|
|
18197
18228
|
<td>${statusBadge(doc.frontmatter.status)}</td>
|
|
18198
18229
|
<td>${escapeHtml(doc.frontmatter.owner ?? "\u2014")}</td>
|
|
18199
18230
|
<td>${doc.frontmatter.priority ? `<span class="priority-${doc.frontmatter.priority.toLowerCase()}">${escapeHtml(doc.frontmatter.priority)}</span>` : "\u2014"}</td>
|
|
@@ -18282,7 +18313,7 @@ function documentDetailPage(doc) {
|
|
|
18282
18313
|
</div>
|
|
18283
18314
|
|
|
18284
18315
|
<div class="page-header">
|
|
18285
|
-
<h2>${escapeHtml(fm.title)}${
|
|
18316
|
+
<h2>${escapeHtml(fm.title)}${integrationIcons(fm)}</h2>
|
|
18286
18317
|
<div class="subtitle">${escapeHtml(fm.id)} · ${escapeHtml(label)}</div>
|
|
18287
18318
|
</div>
|
|
18288
18319
|
|
|
@@ -19704,7 +19735,7 @@ function renderItemRows(items, borderColor, showOwner, depth = 0) {
|
|
|
19704
19735
|
const row = `
|
|
19705
19736
|
<tr class="${classes.join(" ")}" style="--focus-color: ${borderColor}">
|
|
19706
19737
|
<td${indent}><a href="/docs/${escapeHtml(w.type)}/${escapeHtml(w.id)}">${escapeHtml(w.id)}</a></td>
|
|
19707
|
-
<td>${escapeHtml(w.title)}${jiraIcon(w.jiraKey, w.jiraUrl)}</td>
|
|
19738
|
+
<td>${escapeHtml(w.title)}${jiraIcon(w.jiraKey, w.jiraUrl)}${confluenceIcon(w.confluenceUrl, w.confluenceTitle)}</td>
|
|
19708
19739
|
${ownerCell}
|
|
19709
19740
|
<td>${statusBadge(w.status)}</td>
|
|
19710
19741
|
<td>${progressCell}</td>
|
|
@@ -21329,7 +21360,7 @@ function boardPage(data, basePath = "/board") {
|
|
|
21329
21360
|
<div class="board-card">
|
|
21330
21361
|
<a href="/docs/${doc.frontmatter.type}/${doc.frontmatter.id}">
|
|
21331
21362
|
<div class="bc-id">${escapeHtml(doc.frontmatter.id)}</div>
|
|
21332
|
-
<div class="bc-title">${escapeHtml(doc.frontmatter.title)}${
|
|
21363
|
+
<div class="bc-title">${escapeHtml(doc.frontmatter.title)}${integrationIcons(doc.frontmatter)}</div>
|
|
21333
21364
|
${doc.frontmatter.owner ? `<div class="bc-owner">${escapeHtml(doc.frontmatter.owner)}</div>` : ""}
|
|
21334
21365
|
</a>
|
|
21335
21366
|
</div>`
|
|
@@ -24916,11 +24947,14 @@ import { tool as tool20 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
24916
24947
|
var JiraClient = class {
|
|
24917
24948
|
baseUrl;
|
|
24918
24949
|
baseUrlV3;
|
|
24950
|
+
confluenceBaseUrl;
|
|
24919
24951
|
authHeader;
|
|
24952
|
+
host;
|
|
24920
24953
|
constructor(config2) {
|
|
24921
|
-
|
|
24922
|
-
this.baseUrl = `https://${host}/rest/api/2`;
|
|
24923
|
-
this.baseUrlV3 = `https://${host}/rest/api/3`;
|
|
24954
|
+
this.host = config2.host.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
24955
|
+
this.baseUrl = `https://${this.host}/rest/api/2`;
|
|
24956
|
+
this.baseUrlV3 = `https://${this.host}/rest/api/3`;
|
|
24957
|
+
this.confluenceBaseUrl = `https://${this.host}/wiki/api/v2`;
|
|
24924
24958
|
this.authHeader = "Basic " + Buffer.from(`${config2.email}:${config2.apiToken}`).toString("base64");
|
|
24925
24959
|
}
|
|
24926
24960
|
async request(path21, method = "GET", body) {
|
|
@@ -25008,6 +25042,30 @@ var JiraClient = class {
|
|
|
25008
25042
|
{ body }
|
|
25009
25043
|
);
|
|
25010
25044
|
}
|
|
25045
|
+
// --- Confluence methods ---
|
|
25046
|
+
async getConfluencePage(pageId) {
|
|
25047
|
+
return this.doRequest(
|
|
25048
|
+
`${this.confluenceBaseUrl}/pages/${encodeURIComponent(pageId)}?body-format=atlas_doc_format`,
|
|
25049
|
+
"GET"
|
|
25050
|
+
);
|
|
25051
|
+
}
|
|
25052
|
+
/**
|
|
25053
|
+
* Extract a Confluence page ID from various URL formats.
|
|
25054
|
+
* Returns null if the URL doesn't match any known pattern.
|
|
25055
|
+
*/
|
|
25056
|
+
static extractPageId(url2) {
|
|
25057
|
+
const pagesMatch = url2.match(/\/pages\/(\d+)/);
|
|
25058
|
+
if (pagesMatch) return pagesMatch[1];
|
|
25059
|
+
const paramMatch = url2.match(/[?&]pageId=(\d+)/);
|
|
25060
|
+
if (paramMatch) return paramMatch[1];
|
|
25061
|
+
return null;
|
|
25062
|
+
}
|
|
25063
|
+
/**
|
|
25064
|
+
* Build a web URL for a Confluence page.
|
|
25065
|
+
*/
|
|
25066
|
+
getConfluencePageUrl(pageId) {
|
|
25067
|
+
return `https://${this.host}/wiki/pages/viewpage.action?pageId=${pageId}`;
|
|
25068
|
+
}
|
|
25011
25069
|
};
|
|
25012
25070
|
function createJiraClient(jiraUserConfig) {
|
|
25013
25071
|
const host = jiraUserConfig?.host ?? process.env.JIRA_HOST;
|
|
@@ -26108,6 +26166,111 @@ function createJiraTools(store, projectConfig) {
|
|
|
26108
26166
|
};
|
|
26109
26167
|
}
|
|
26110
26168
|
),
|
|
26169
|
+
// --- Confluence tools ---
|
|
26170
|
+
tool20(
|
|
26171
|
+
"link_to_confluence",
|
|
26172
|
+
"Link a Confluence page to any Marvin artifact. Validates the page exists and fetches its title.",
|
|
26173
|
+
{
|
|
26174
|
+
artifactId: external_exports.string().describe("Marvin artifact ID (e.g. 'D-001', 'A-003', 'T-002')"),
|
|
26175
|
+
confluenceUrl: external_exports.string().describe("Confluence page URL")
|
|
26176
|
+
},
|
|
26177
|
+
async (args) => {
|
|
26178
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
26179
|
+
if (!jira) return jiraNotConfiguredError();
|
|
26180
|
+
const artifact = store.get(args.artifactId);
|
|
26181
|
+
if (!artifact) {
|
|
26182
|
+
return {
|
|
26183
|
+
content: [
|
|
26184
|
+
{ type: "text", text: `Artifact ${args.artifactId} not found` }
|
|
26185
|
+
],
|
|
26186
|
+
isError: true
|
|
26187
|
+
};
|
|
26188
|
+
}
|
|
26189
|
+
const pageId = JiraClient.extractPageId(args.confluenceUrl);
|
|
26190
|
+
if (!pageId) {
|
|
26191
|
+
return {
|
|
26192
|
+
content: [
|
|
26193
|
+
{ type: "text", text: `Could not extract page ID from URL: ${args.confluenceUrl}` }
|
|
26194
|
+
],
|
|
26195
|
+
isError: true
|
|
26196
|
+
};
|
|
26197
|
+
}
|
|
26198
|
+
const page = await jira.client.getConfluencePage(pageId);
|
|
26199
|
+
const existingTags = artifact.frontmatter.tags ?? [];
|
|
26200
|
+
store.update(args.artifactId, {
|
|
26201
|
+
confluenceUrl: args.confluenceUrl,
|
|
26202
|
+
confluencePageId: pageId,
|
|
26203
|
+
confluenceTitle: page.title,
|
|
26204
|
+
tags: [...existingTags.filter((t) => !t.startsWith("confluence:")), `confluence:${page.title}`]
|
|
26205
|
+
});
|
|
26206
|
+
return {
|
|
26207
|
+
content: [
|
|
26208
|
+
{
|
|
26209
|
+
type: "text",
|
|
26210
|
+
text: `Linked ${args.artifactId} to Confluence page "${page.title}" (ID: ${pageId}).`
|
|
26211
|
+
}
|
|
26212
|
+
]
|
|
26213
|
+
};
|
|
26214
|
+
}
|
|
26215
|
+
),
|
|
26216
|
+
tool20(
|
|
26217
|
+
"read_confluence_page",
|
|
26218
|
+
"Read the content of a Confluence page by URL or page ID. Returns the page title, metadata, and body as plain text.",
|
|
26219
|
+
{
|
|
26220
|
+
pageUrl: external_exports.string().optional().describe("Confluence page URL"),
|
|
26221
|
+
pageId: external_exports.string().optional().describe("Confluence page ID (alternative to URL)")
|
|
26222
|
+
},
|
|
26223
|
+
async (args) => {
|
|
26224
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
26225
|
+
if (!jira) return jiraNotConfiguredError();
|
|
26226
|
+
const resolvedId = args.pageId ?? (args.pageUrl ? JiraClient.extractPageId(args.pageUrl) : null);
|
|
26227
|
+
if (!resolvedId) {
|
|
26228
|
+
return {
|
|
26229
|
+
content: [
|
|
26230
|
+
{
|
|
26231
|
+
type: "text",
|
|
26232
|
+
text: "Provide either pageUrl or pageId. Could not extract page ID from the given URL."
|
|
26233
|
+
}
|
|
26234
|
+
],
|
|
26235
|
+
isError: true
|
|
26236
|
+
};
|
|
26237
|
+
}
|
|
26238
|
+
const page = await jira.client.getConfluencePage(resolvedId);
|
|
26239
|
+
let bodyText = "";
|
|
26240
|
+
if (page.body?.atlas_doc_format?.value) {
|
|
26241
|
+
try {
|
|
26242
|
+
const adf = JSON.parse(page.body.atlas_doc_format.value);
|
|
26243
|
+
bodyText = extractCommentText(adf);
|
|
26244
|
+
} catch {
|
|
26245
|
+
bodyText = page.body.atlas_doc_format.value;
|
|
26246
|
+
}
|
|
26247
|
+
}
|
|
26248
|
+
const parts = [
|
|
26249
|
+
`# ${page.title}`,
|
|
26250
|
+
"",
|
|
26251
|
+
`Page ID: ${page.id}`,
|
|
26252
|
+
`Status: ${page.status}`,
|
|
26253
|
+
`Version: ${page.version.number} (${page.version.createdAt.slice(0, 10)})`,
|
|
26254
|
+
"",
|
|
26255
|
+
"---",
|
|
26256
|
+
"",
|
|
26257
|
+
bodyText || "(empty page)"
|
|
26258
|
+
];
|
|
26259
|
+
const allDocs = store.registeredTypes.flatMap((t) => store.list({ type: t }));
|
|
26260
|
+
const linkedArtifacts = allDocs.filter(
|
|
26261
|
+
(d) => d.frontmatter.confluencePageId === resolvedId || d.frontmatter.confluenceUrl === args.pageUrl
|
|
26262
|
+
);
|
|
26263
|
+
if (linkedArtifacts.length > 0) {
|
|
26264
|
+
parts.push("");
|
|
26265
|
+
parts.push("---");
|
|
26266
|
+
parts.push(`Linked Marvin artifacts: ${linkedArtifacts.map((d) => d.frontmatter.id).join(", ")}`);
|
|
26267
|
+
}
|
|
26268
|
+
return {
|
|
26269
|
+
content: [{ type: "text", text: parts.join("\n") }]
|
|
26270
|
+
};
|
|
26271
|
+
},
|
|
26272
|
+
{ annotations: { readOnlyHint: true } }
|
|
26273
|
+
),
|
|
26111
26274
|
// --- Jira status fetch (read-only) ---
|
|
26112
26275
|
tool20(
|
|
26113
26276
|
"fetch_jira_status",
|
|
@@ -26418,6 +26581,8 @@ function formatIssueEntry(issue2) {
|
|
|
26418
26581
|
var COMMON_TOOLS = `**Available tools:**
|
|
26419
26582
|
- \`push_artifact_to_jira\` \u2014 create a Jira issue from any Marvin artifact and link it directly via \`jiraKey\` on the artifact.
|
|
26420
26583
|
- \`link_to_jira\` \u2014 link an existing Jira issue to any Marvin artifact (sets \`jiraKey\` directly on the artifact).
|
|
26584
|
+
- \`link_to_confluence\` \u2014 link a Confluence page to any Marvin artifact. Validates the page exists and fetches its title.
|
|
26585
|
+
- \`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.
|
|
26421
26586
|
- \`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.
|
|
26422
26587
|
- \`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).
|
|
26423
26588
|
- \`fetch_jira_statuses\` \u2014 **read-only**: discover all Jira statuses in a project and show their Marvin mappings (mapped vs unmapped).
|
|
@@ -31948,7 +32113,7 @@ function createProgram() {
|
|
|
31948
32113
|
const program = new Command();
|
|
31949
32114
|
program.name("marvin").description(
|
|
31950
32115
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
31951
|
-
).version("0.5.
|
|
32116
|
+
).version("0.5.13");
|
|
31952
32117
|
program.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
31953
32118
|
await initCommand();
|
|
31954
32119
|
});
|