mrvn-cli 0.5.12 → 0.5.14
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 +492 -28
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +516 -52
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +492 -28
- 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:"));
|
|
@@ -14675,7 +14680,7 @@ function collectSprintSummaryData(store, sprintId) {
|
|
|
14675
14680
|
confluenceTitle: doc.frontmatter.confluenceTitle
|
|
14676
14681
|
};
|
|
14677
14682
|
allItemsById.set(item.id, item);
|
|
14678
|
-
if (about &&
|
|
14683
|
+
if (about && workItemIds.has(about)) {
|
|
14679
14684
|
if (!childrenByParent.has(about)) childrenByParent.set(about, []);
|
|
14680
14685
|
childrenByParent.get(about).push(item);
|
|
14681
14686
|
}
|
|
@@ -18262,7 +18267,7 @@ import * as readline from "readline";
|
|
|
18262
18267
|
import chalk2 from "chalk";
|
|
18263
18268
|
import ora from "ora";
|
|
18264
18269
|
import {
|
|
18265
|
-
query as
|
|
18270
|
+
query as query5
|
|
18266
18271
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
18267
18272
|
|
|
18268
18273
|
// src/personas/prompt-builder.ts
|
|
@@ -18402,9 +18407,9 @@ var DocumentStore = class {
|
|
|
18402
18407
|
}
|
|
18403
18408
|
}
|
|
18404
18409
|
}
|
|
18405
|
-
list(
|
|
18410
|
+
list(query10) {
|
|
18406
18411
|
const results = [];
|
|
18407
|
-
const types =
|
|
18412
|
+
const types = query10?.type ? [query10.type] : Object.keys(this.typeDirs);
|
|
18408
18413
|
for (const type of types) {
|
|
18409
18414
|
const dirName = this.typeDirs[type];
|
|
18410
18415
|
if (!dirName) continue;
|
|
@@ -18415,9 +18420,9 @@ var DocumentStore = class {
|
|
|
18415
18420
|
const filePath = path6.join(dir, file2);
|
|
18416
18421
|
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
18417
18422
|
const doc = parseDocument(raw, filePath);
|
|
18418
|
-
if (
|
|
18419
|
-
if (
|
|
18420
|
-
if (
|
|
18423
|
+
if (query10?.status && doc.frontmatter.status !== query10.status) continue;
|
|
18424
|
+
if (query10?.owner && doc.frontmatter.owner !== query10.owner) continue;
|
|
18425
|
+
if (query10?.tag && (!doc.frontmatter.tags || !doc.frontmatter.tags.includes(query10.tag)))
|
|
18421
18426
|
continue;
|
|
18422
18427
|
results.push(doc);
|
|
18423
18428
|
}
|
|
@@ -21252,9 +21257,9 @@ tr:hover td {
|
|
|
21252
21257
|
.integration-icons {
|
|
21253
21258
|
display: inline-flex;
|
|
21254
21259
|
align-items: center;
|
|
21255
|
-
gap: 0.
|
|
21260
|
+
gap: 0.25rem;
|
|
21256
21261
|
vertical-align: middle;
|
|
21257
|
-
margin-left: 0.
|
|
21262
|
+
margin-left: 0.5rem;
|
|
21258
21263
|
}
|
|
21259
21264
|
.integration-link {
|
|
21260
21265
|
display: inline-flex;
|
|
@@ -22379,7 +22384,7 @@ function poBacklogPage(ctx) {
|
|
|
22379
22384
|
}
|
|
22380
22385
|
}
|
|
22381
22386
|
}
|
|
22382
|
-
const
|
|
22387
|
+
const DONE_STATUSES17 = /* @__PURE__ */ new Set(["done", "closed", "resolved", "cancelled"]);
|
|
22383
22388
|
function featureTaskStats(featureId) {
|
|
22384
22389
|
const fEpics = featureToEpics.get(featureId) ?? [];
|
|
22385
22390
|
let total = 0;
|
|
@@ -22388,7 +22393,7 @@ function poBacklogPage(ctx) {
|
|
|
22388
22393
|
for (const epic of fEpics) {
|
|
22389
22394
|
for (const t of epicToTasks.get(epic.frontmatter.id) ?? []) {
|
|
22390
22395
|
total++;
|
|
22391
|
-
if (
|
|
22396
|
+
if (DONE_STATUSES17.has(t.frontmatter.status)) done++;
|
|
22392
22397
|
progressSum += getEffectiveProgress(t.frontmatter);
|
|
22393
22398
|
}
|
|
22394
22399
|
}
|
|
@@ -25351,6 +25356,11 @@ function mapJiraStatusForTask(status, configMap) {
|
|
|
25351
25356
|
const lookup = buildStatusLookup(configMap, DEFAULT_TASK_STATUS_MAP);
|
|
25352
25357
|
return lookup.get(status.toLowerCase()) ?? "backlog";
|
|
25353
25358
|
}
|
|
25359
|
+
function extractJiraKeyFromTags(tags) {
|
|
25360
|
+
if (!tags) return void 0;
|
|
25361
|
+
const tag = tags.find((t) => /^jira:[A-Z]+-\d+$/i.test(t));
|
|
25362
|
+
return tag ? tag.slice(5) : void 0;
|
|
25363
|
+
}
|
|
25354
25364
|
function computeSubtaskProgress(subtasks) {
|
|
25355
25365
|
if (subtasks.length === 0) return 0;
|
|
25356
25366
|
const done = subtasks.filter(
|
|
@@ -25733,10 +25743,10 @@ async function fetchJiraDaily(store, client, host, projectKey, dateRange, status
|
|
|
25733
25743
|
jiraKeyToArtifacts.set(jk, list);
|
|
25734
25744
|
}
|
|
25735
25745
|
}
|
|
25736
|
-
const
|
|
25746
|
+
const BATCH_SIZE2 = 5;
|
|
25737
25747
|
const issues = searchResult.issues;
|
|
25738
|
-
for (let i = 0; i < issues.length; i +=
|
|
25739
|
-
const batch = issues.slice(i, i +
|
|
25748
|
+
for (let i = 0; i < issues.length; i += BATCH_SIZE2) {
|
|
25749
|
+
const batch = issues.slice(i, i + BATCH_SIZE2);
|
|
25740
25750
|
const results = await Promise.allSettled(
|
|
25741
25751
|
batch.map(
|
|
25742
25752
|
(issue2) => processIssue(issue2, client, host, dateRange, jiraKeyToArtifacts, allDocs, statusMap)
|
|
@@ -25960,6 +25970,420 @@ function generateProposedActions(issues) {
|
|
|
25960
25970
|
return actions;
|
|
25961
25971
|
}
|
|
25962
25972
|
|
|
25973
|
+
// src/skills/builtin/jira/sprint-progress.ts
|
|
25974
|
+
import { query as query3 } from "@anthropic-ai/claude-agent-sdk";
|
|
25975
|
+
var DONE_STATUSES16 = /* @__PURE__ */ new Set(["done", "closed", "resolved", "obsolete", "wont do", "cancelled"]);
|
|
25976
|
+
var BATCH_SIZE = 5;
|
|
25977
|
+
async function assessSprintProgress(store, client, host, options = {}) {
|
|
25978
|
+
const errors = [];
|
|
25979
|
+
const sprintData = collectSprintSummaryData(store, options.sprintId);
|
|
25980
|
+
if (!sprintData) {
|
|
25981
|
+
return {
|
|
25982
|
+
sprintId: options.sprintId ?? "unknown",
|
|
25983
|
+
sprintTitle: "Sprint not found",
|
|
25984
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25985
|
+
timeline: { startDate: null, endDate: null, daysRemaining: 0, totalDays: 0, percentComplete: 0 },
|
|
25986
|
+
overallProgress: 0,
|
|
25987
|
+
itemReports: [],
|
|
25988
|
+
focusAreas: [],
|
|
25989
|
+
driftItems: [],
|
|
25990
|
+
blockers: [],
|
|
25991
|
+
proposedUpdates: [],
|
|
25992
|
+
appliedUpdates: [],
|
|
25993
|
+
errors: [`Sprint ${options.sprintId ?? "(active)"} not found. Create a sprint artifact first.`]
|
|
25994
|
+
};
|
|
25995
|
+
}
|
|
25996
|
+
const sprintTag = `sprint:${sprintData.sprint.id}`;
|
|
25997
|
+
const actions = store.list({ type: "action", tag: sprintTag });
|
|
25998
|
+
const tasks = store.list({ type: "task", tag: sprintTag });
|
|
25999
|
+
const sprintItemIds = new Set([...actions, ...tasks].map((d) => d.frontmatter.id));
|
|
26000
|
+
const allTasks = store.list({ type: "task" });
|
|
26001
|
+
const allActions = store.list({ type: "action" });
|
|
26002
|
+
const nestedTasks = allTasks.filter(
|
|
26003
|
+
(d) => !sprintItemIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintItemIds.has(d.frontmatter.aboutArtifact)
|
|
26004
|
+
);
|
|
26005
|
+
const nestedActions = allActions.filter(
|
|
26006
|
+
(d) => !sprintItemIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintItemIds.has(d.frontmatter.aboutArtifact)
|
|
26007
|
+
);
|
|
26008
|
+
const allItems = [...actions, ...tasks, ...nestedTasks, ...nestedActions];
|
|
26009
|
+
const itemJiraKeys = /* @__PURE__ */ new Map();
|
|
26010
|
+
for (const doc of allItems) {
|
|
26011
|
+
const jiraKey = doc.frontmatter.jiraKey ?? extractJiraKeyFromTags(doc.frontmatter.tags);
|
|
26012
|
+
if (jiraKey) {
|
|
26013
|
+
itemJiraKeys.set(doc.frontmatter.id, jiraKey);
|
|
26014
|
+
}
|
|
26015
|
+
}
|
|
26016
|
+
const jiraKeys = [...new Set(itemJiraKeys.values())];
|
|
26017
|
+
const jiraIssues = /* @__PURE__ */ new Map();
|
|
26018
|
+
for (let i = 0; i < jiraKeys.length; i += BATCH_SIZE) {
|
|
26019
|
+
const batch = jiraKeys.slice(i, i + BATCH_SIZE);
|
|
26020
|
+
const results = await Promise.allSettled(
|
|
26021
|
+
batch.map(async (key) => {
|
|
26022
|
+
const [issue2, comments] = await Promise.all([
|
|
26023
|
+
client.getIssueWithLinks(key),
|
|
26024
|
+
client.getComments(key)
|
|
26025
|
+
]);
|
|
26026
|
+
return { key, issue: issue2, comments };
|
|
26027
|
+
})
|
|
26028
|
+
);
|
|
26029
|
+
for (const result of results) {
|
|
26030
|
+
if (result.status === "fulfilled") {
|
|
26031
|
+
jiraIssues.set(result.value.key, {
|
|
26032
|
+
issue: result.value.issue,
|
|
26033
|
+
comments: result.value.comments
|
|
26034
|
+
});
|
|
26035
|
+
} else {
|
|
26036
|
+
const batchKey = batch[results.indexOf(result)];
|
|
26037
|
+
errors.push(`Failed to fetch ${batchKey}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`);
|
|
26038
|
+
}
|
|
26039
|
+
}
|
|
26040
|
+
}
|
|
26041
|
+
const proposedUpdates = [];
|
|
26042
|
+
const itemReports = [];
|
|
26043
|
+
const childReportsByParent = /* @__PURE__ */ new Map();
|
|
26044
|
+
for (const doc of allItems) {
|
|
26045
|
+
const fm = doc.frontmatter;
|
|
26046
|
+
const jiraKey = itemJiraKeys.get(fm.id) ?? null;
|
|
26047
|
+
const jiraData = jiraKey ? jiraIssues.get(jiraKey) : null;
|
|
26048
|
+
let jiraStatus = null;
|
|
26049
|
+
let proposedMarvinStatus = null;
|
|
26050
|
+
let jiraSubtaskProgress = null;
|
|
26051
|
+
const commentSignals = [];
|
|
26052
|
+
if (jiraData) {
|
|
26053
|
+
jiraStatus = jiraData.issue.fields.status.name;
|
|
26054
|
+
proposedMarvinStatus = fm.type === "task" ? mapJiraStatusForTask(jiraStatus, options.statusMap?.task) : mapJiraStatusForAction(jiraStatus, options.statusMap?.action);
|
|
26055
|
+
const subtasks = jiraData.issue.fields.subtasks ?? [];
|
|
26056
|
+
if (subtasks.length > 0) {
|
|
26057
|
+
jiraSubtaskProgress = computeSubtaskProgress(subtasks);
|
|
26058
|
+
}
|
|
26059
|
+
for (const comment of jiraData.comments) {
|
|
26060
|
+
const text = extractCommentText(comment.body);
|
|
26061
|
+
const signals = detectCommentSignals(text);
|
|
26062
|
+
commentSignals.push(...signals);
|
|
26063
|
+
}
|
|
26064
|
+
}
|
|
26065
|
+
const statusDrift = proposedMarvinStatus !== null && proposedMarvinStatus !== fm.status;
|
|
26066
|
+
const currentProgress = getEffectiveProgress(fm);
|
|
26067
|
+
const progressDrift = jiraSubtaskProgress !== null && !fm.progressOverride && jiraSubtaskProgress !== currentProgress;
|
|
26068
|
+
if (statusDrift && proposedMarvinStatus) {
|
|
26069
|
+
proposedUpdates.push({
|
|
26070
|
+
artifactId: fm.id,
|
|
26071
|
+
field: "status",
|
|
26072
|
+
currentValue: fm.status,
|
|
26073
|
+
proposedValue: proposedMarvinStatus,
|
|
26074
|
+
reason: `Jira ${jiraKey} is "${jiraStatus}" \u2192 maps to "${proposedMarvinStatus}"`
|
|
26075
|
+
});
|
|
26076
|
+
}
|
|
26077
|
+
if (progressDrift && jiraSubtaskProgress !== null) {
|
|
26078
|
+
proposedUpdates.push({
|
|
26079
|
+
artifactId: fm.id,
|
|
26080
|
+
field: "progress",
|
|
26081
|
+
currentValue: currentProgress,
|
|
26082
|
+
proposedValue: jiraSubtaskProgress,
|
|
26083
|
+
reason: `Jira ${jiraKey} subtask progress is ${jiraSubtaskProgress}%`
|
|
26084
|
+
});
|
|
26085
|
+
}
|
|
26086
|
+
const tags = fm.tags ?? [];
|
|
26087
|
+
const focusTag = tags.find((t) => t.startsWith("focus:"));
|
|
26088
|
+
const report = {
|
|
26089
|
+
id: fm.id,
|
|
26090
|
+
title: fm.title,
|
|
26091
|
+
type: fm.type,
|
|
26092
|
+
marvinStatus: fm.status,
|
|
26093
|
+
marvinProgress: currentProgress,
|
|
26094
|
+
jiraKey,
|
|
26095
|
+
jiraStatus,
|
|
26096
|
+
jiraSubtaskProgress,
|
|
26097
|
+
proposedMarvinStatus,
|
|
26098
|
+
statusDrift,
|
|
26099
|
+
progressDrift,
|
|
26100
|
+
commentSignals,
|
|
26101
|
+
commentSummary: null,
|
|
26102
|
+
children: [],
|
|
26103
|
+
owner: fm.owner ?? null,
|
|
26104
|
+
focusArea: focusTag ? focusTag.slice(6) : null
|
|
26105
|
+
};
|
|
26106
|
+
const aboutArtifact = fm.aboutArtifact;
|
|
26107
|
+
if (aboutArtifact && sprintItemIds.has(aboutArtifact)) {
|
|
26108
|
+
if (!childReportsByParent.has(aboutArtifact)) {
|
|
26109
|
+
childReportsByParent.set(aboutArtifact, []);
|
|
26110
|
+
}
|
|
26111
|
+
childReportsByParent.get(aboutArtifact).push(report);
|
|
26112
|
+
}
|
|
26113
|
+
itemReports.push(report);
|
|
26114
|
+
}
|
|
26115
|
+
for (const report of itemReports) {
|
|
26116
|
+
const children = childReportsByParent.get(report.id);
|
|
26117
|
+
if (children) {
|
|
26118
|
+
report.children = children;
|
|
26119
|
+
}
|
|
26120
|
+
}
|
|
26121
|
+
const childIds = /* @__PURE__ */ new Set();
|
|
26122
|
+
for (const children of childReportsByParent.values()) {
|
|
26123
|
+
for (const child of children) childIds.add(child.id);
|
|
26124
|
+
}
|
|
26125
|
+
const rootReports = itemReports.filter((r) => !childIds.has(r.id));
|
|
26126
|
+
const focusAreaMap = /* @__PURE__ */ new Map();
|
|
26127
|
+
for (const report of rootReports) {
|
|
26128
|
+
const area = report.focusArea ?? "Uncategorized";
|
|
26129
|
+
if (!focusAreaMap.has(area)) focusAreaMap.set(area, []);
|
|
26130
|
+
focusAreaMap.get(area).push(report);
|
|
26131
|
+
}
|
|
26132
|
+
const focusAreas = [];
|
|
26133
|
+
for (const [name, items] of focusAreaMap) {
|
|
26134
|
+
const allFlatItems = items.flatMap((i) => [i, ...i.children]);
|
|
26135
|
+
const doneCount = allFlatItems.filter((i) => DONE_STATUSES16.has(i.marvinStatus)).length;
|
|
26136
|
+
const blockedCount = allFlatItems.filter((i) => i.marvinStatus === "blocked").length;
|
|
26137
|
+
const avgProgress = allFlatItems.length > 0 ? Math.round(allFlatItems.reduce((s, i) => s + i.marvinProgress, 0) / allFlatItems.length) : 0;
|
|
26138
|
+
focusAreas.push({
|
|
26139
|
+
name,
|
|
26140
|
+
items,
|
|
26141
|
+
totalCount: allFlatItems.length,
|
|
26142
|
+
doneCount,
|
|
26143
|
+
blockedCount,
|
|
26144
|
+
avgProgress
|
|
26145
|
+
});
|
|
26146
|
+
}
|
|
26147
|
+
focusAreas.sort((a, b) => {
|
|
26148
|
+
if (a.name === "Uncategorized") return 1;
|
|
26149
|
+
if (b.name === "Uncategorized") return -1;
|
|
26150
|
+
return a.name.localeCompare(b.name);
|
|
26151
|
+
});
|
|
26152
|
+
const driftItems = itemReports.filter((r) => r.statusDrift || r.progressDrift);
|
|
26153
|
+
const blockers = itemReports.filter(
|
|
26154
|
+
(r) => r.marvinStatus === "blocked" || r.commentSignals.some((s) => s.type === "blocker")
|
|
26155
|
+
);
|
|
26156
|
+
if (options.analyzeComments) {
|
|
26157
|
+
const itemsWithComments = itemReports.filter((r) => r.commentSignals.length > 0 && r.jiraKey);
|
|
26158
|
+
if (itemsWithComments.length > 0) {
|
|
26159
|
+
try {
|
|
26160
|
+
const summaries = await analyzeCommentsForProgress(
|
|
26161
|
+
itemsWithComments,
|
|
26162
|
+
jiraIssues,
|
|
26163
|
+
itemJiraKeys
|
|
26164
|
+
);
|
|
26165
|
+
for (const [artifactId, summary] of summaries) {
|
|
26166
|
+
const report = itemReports.find((r) => r.id === artifactId);
|
|
26167
|
+
if (report) report.commentSummary = summary;
|
|
26168
|
+
}
|
|
26169
|
+
} catch (err) {
|
|
26170
|
+
errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26171
|
+
}
|
|
26172
|
+
}
|
|
26173
|
+
}
|
|
26174
|
+
const appliedUpdates = [];
|
|
26175
|
+
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
26176
|
+
for (const update of proposedUpdates) {
|
|
26177
|
+
try {
|
|
26178
|
+
store.update(update.artifactId, {
|
|
26179
|
+
[update.field]: update.proposedValue,
|
|
26180
|
+
lastJiraSyncAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26181
|
+
});
|
|
26182
|
+
const doc = store.get(update.artifactId);
|
|
26183
|
+
if (doc) {
|
|
26184
|
+
if (doc.frontmatter.type === "task") {
|
|
26185
|
+
propagateProgressFromTask(store, update.artifactId);
|
|
26186
|
+
} else if (doc.frontmatter.type === "action") {
|
|
26187
|
+
propagateProgressToAction(store, update.artifactId);
|
|
26188
|
+
}
|
|
26189
|
+
}
|
|
26190
|
+
appliedUpdates.push(update);
|
|
26191
|
+
} catch (err) {
|
|
26192
|
+
errors.push(
|
|
26193
|
+
`Failed to apply update to ${update.artifactId}: ${err instanceof Error ? err.message : String(err)}`
|
|
26194
|
+
);
|
|
26195
|
+
}
|
|
26196
|
+
}
|
|
26197
|
+
}
|
|
26198
|
+
return {
|
|
26199
|
+
sprintId: sprintData.sprint.id,
|
|
26200
|
+
sprintTitle: sprintData.sprint.title,
|
|
26201
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26202
|
+
timeline: {
|
|
26203
|
+
startDate: sprintData.sprint.startDate ?? null,
|
|
26204
|
+
endDate: sprintData.sprint.endDate ?? null,
|
|
26205
|
+
daysRemaining: sprintData.timeline.daysRemaining,
|
|
26206
|
+
totalDays: sprintData.timeline.totalDays,
|
|
26207
|
+
percentComplete: sprintData.timeline.percentComplete
|
|
26208
|
+
},
|
|
26209
|
+
overallProgress: sprintData.workItems.completionPct,
|
|
26210
|
+
itemReports: rootReports,
|
|
26211
|
+
focusAreas,
|
|
26212
|
+
driftItems,
|
|
26213
|
+
blockers,
|
|
26214
|
+
proposedUpdates: options.applyUpdates ? [] : proposedUpdates,
|
|
26215
|
+
appliedUpdates,
|
|
26216
|
+
errors
|
|
26217
|
+
};
|
|
26218
|
+
}
|
|
26219
|
+
var COMMENT_ANALYSIS_PROMPT = `You are a delivery management assistant analyzing Jira comments for progress signals.
|
|
26220
|
+
|
|
26221
|
+
For each item below, read the Jira comments and produce a 1-2 sentence progress summary.
|
|
26222
|
+
Focus on: what work was done, what's pending, any blockers or decisions mentioned.
|
|
26223
|
+
|
|
26224
|
+
Return your response as a JSON object mapping artifact IDs to summary strings.
|
|
26225
|
+
Example: {"T-001": "Backend API completed and deployed. Frontend integration pending review.", "A-003": "Blocked on infrastructure team approval."}
|
|
26226
|
+
|
|
26227
|
+
IMPORTANT: Only return the JSON object, no other text.`;
|
|
26228
|
+
async function analyzeCommentsForProgress(items, jiraIssues, itemJiraKeys) {
|
|
26229
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
26230
|
+
const MAX_ITEMS_PER_CALL = 20;
|
|
26231
|
+
const itemsToAnalyze = items.slice(0, MAX_ITEMS_PER_CALL);
|
|
26232
|
+
const promptParts = [];
|
|
26233
|
+
for (const item of itemsToAnalyze) {
|
|
26234
|
+
const jiraKey = itemJiraKeys.get(item.id);
|
|
26235
|
+
if (!jiraKey) continue;
|
|
26236
|
+
const jiraData = jiraIssues.get(jiraKey);
|
|
26237
|
+
if (!jiraData || jiraData.comments.length === 0) continue;
|
|
26238
|
+
const commentTexts = jiraData.comments.map((c) => {
|
|
26239
|
+
const text = extractCommentText(c.body);
|
|
26240
|
+
return ` [${c.author.displayName}, ${c.created.slice(0, 10)}]: ${text.slice(0, 500)}`;
|
|
26241
|
+
}).join("\n");
|
|
26242
|
+
promptParts.push(`## ${item.id} \u2014 ${item.title} (${jiraKey}, Jira status: ${item.jiraStatus})
|
|
26243
|
+
Comments:
|
|
26244
|
+
${commentTexts}`);
|
|
26245
|
+
}
|
|
26246
|
+
if (promptParts.length === 0) return summaries;
|
|
26247
|
+
const prompt = promptParts.join("\n\n");
|
|
26248
|
+
const result = query3({
|
|
26249
|
+
prompt,
|
|
26250
|
+
options: {
|
|
26251
|
+
systemPrompt: COMMENT_ANALYSIS_PROMPT,
|
|
26252
|
+
maxTurns: 1,
|
|
26253
|
+
tools: [],
|
|
26254
|
+
allowedTools: []
|
|
26255
|
+
}
|
|
26256
|
+
});
|
|
26257
|
+
for await (const msg of result) {
|
|
26258
|
+
if (msg.type === "assistant") {
|
|
26259
|
+
const textBlock = msg.message.content.find(
|
|
26260
|
+
(b) => b.type === "text"
|
|
26261
|
+
);
|
|
26262
|
+
if (textBlock) {
|
|
26263
|
+
try {
|
|
26264
|
+
const parsed = JSON.parse(textBlock.text);
|
|
26265
|
+
for (const [id, summary] of Object.entries(parsed)) {
|
|
26266
|
+
if (typeof summary === "string") {
|
|
26267
|
+
summaries.set(id, summary);
|
|
26268
|
+
}
|
|
26269
|
+
}
|
|
26270
|
+
} catch {
|
|
26271
|
+
const match = textBlock.text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
26272
|
+
if (match) {
|
|
26273
|
+
try {
|
|
26274
|
+
const parsed = JSON.parse(match[1]);
|
|
26275
|
+
for (const [id, summary] of Object.entries(parsed)) {
|
|
26276
|
+
if (typeof summary === "string") {
|
|
26277
|
+
summaries.set(id, summary);
|
|
26278
|
+
}
|
|
26279
|
+
}
|
|
26280
|
+
} catch {
|
|
26281
|
+
}
|
|
26282
|
+
}
|
|
26283
|
+
}
|
|
26284
|
+
}
|
|
26285
|
+
}
|
|
26286
|
+
}
|
|
26287
|
+
return summaries;
|
|
26288
|
+
}
|
|
26289
|
+
function formatProgressReport(report) {
|
|
26290
|
+
const parts = [];
|
|
26291
|
+
parts.push(`# Sprint Progress Assessment \u2014 ${report.sprintId}`);
|
|
26292
|
+
parts.push(`${report.sprintTitle}`);
|
|
26293
|
+
parts.push(`Generated: ${report.generatedAt.slice(0, 16)}`);
|
|
26294
|
+
parts.push("");
|
|
26295
|
+
if (report.timeline.startDate && report.timeline.endDate) {
|
|
26296
|
+
parts.push(`## Timeline`);
|
|
26297
|
+
parts.push(`${report.timeline.startDate} \u2192 ${report.timeline.endDate}`);
|
|
26298
|
+
parts.push(`Days remaining: ${report.timeline.daysRemaining} / ${report.timeline.totalDays} (${report.timeline.percentComplete}% elapsed)`);
|
|
26299
|
+
parts.push(`Overall progress: ${report.overallProgress}%`);
|
|
26300
|
+
parts.push("");
|
|
26301
|
+
}
|
|
26302
|
+
if (report.focusAreas.length > 0) {
|
|
26303
|
+
parts.push(`## Focus Areas`);
|
|
26304
|
+
parts.push("");
|
|
26305
|
+
for (const area of report.focusAreas) {
|
|
26306
|
+
const bar = progressBar6(area.avgProgress);
|
|
26307
|
+
parts.push(`### ${area.name} ${bar} ${area.avgProgress}%`);
|
|
26308
|
+
parts.push(`${area.doneCount}/${area.totalCount} done${area.blockedCount > 0 ? ` | ${area.blockedCount} blocked` : ""}`);
|
|
26309
|
+
parts.push("");
|
|
26310
|
+
for (const item of area.items) {
|
|
26311
|
+
formatItemLine(parts, item, 0);
|
|
26312
|
+
}
|
|
26313
|
+
parts.push("");
|
|
26314
|
+
}
|
|
26315
|
+
}
|
|
26316
|
+
if (report.driftItems.length > 0) {
|
|
26317
|
+
parts.push(`## Status Drift (${report.driftItems.length} items)`);
|
|
26318
|
+
for (const item of report.driftItems) {
|
|
26319
|
+
const driftParts = [];
|
|
26320
|
+
if (item.statusDrift) {
|
|
26321
|
+
driftParts.push(`status: ${item.marvinStatus} \u2192 ${item.proposedMarvinStatus}`);
|
|
26322
|
+
}
|
|
26323
|
+
if (item.progressDrift && item.jiraSubtaskProgress !== null) {
|
|
26324
|
+
driftParts.push(`progress: ${item.marvinProgress}% \u2192 ${item.jiraSubtaskProgress}%`);
|
|
26325
|
+
}
|
|
26326
|
+
parts.push(` \u26A0 ${item.id} (${item.jiraKey}) \u2014 ${driftParts.join(", ")}`);
|
|
26327
|
+
}
|
|
26328
|
+
parts.push("");
|
|
26329
|
+
}
|
|
26330
|
+
if (report.blockers.length > 0) {
|
|
26331
|
+
parts.push(`## Blockers (${report.blockers.length})`);
|
|
26332
|
+
for (const item of report.blockers) {
|
|
26333
|
+
const blockerSignals = item.commentSignals.filter((s) => s.type === "blocker");
|
|
26334
|
+
parts.push(` \u{1F6AB} ${item.id} \u2014 ${item.title}${item.jiraKey ? ` (${item.jiraKey})` : ""}`);
|
|
26335
|
+
for (const signal of blockerSignals) {
|
|
26336
|
+
parts.push(` "${signal.snippet}"`);
|
|
26337
|
+
}
|
|
26338
|
+
}
|
|
26339
|
+
parts.push("");
|
|
26340
|
+
}
|
|
26341
|
+
if (report.proposedUpdates.length > 0) {
|
|
26342
|
+
parts.push(`## Proposed Updates (${report.proposedUpdates.length})`);
|
|
26343
|
+
for (const update of report.proposedUpdates) {
|
|
26344
|
+
parts.push(` ${update.artifactId}.${update.field}: ${String(update.currentValue)} \u2192 ${String(update.proposedValue)}`);
|
|
26345
|
+
parts.push(` Reason: ${update.reason}`);
|
|
26346
|
+
}
|
|
26347
|
+
parts.push("");
|
|
26348
|
+
parts.push("Run with applyUpdates=true to apply these changes.");
|
|
26349
|
+
parts.push("");
|
|
26350
|
+
}
|
|
26351
|
+
if (report.appliedUpdates.length > 0) {
|
|
26352
|
+
parts.push(`## Applied Updates (${report.appliedUpdates.length})`);
|
|
26353
|
+
for (const update of report.appliedUpdates) {
|
|
26354
|
+
parts.push(` \u2713 ${update.artifactId}.${update.field}: ${String(update.currentValue)} \u2192 ${String(update.proposedValue)}`);
|
|
26355
|
+
}
|
|
26356
|
+
parts.push("");
|
|
26357
|
+
}
|
|
26358
|
+
if (report.errors.length > 0) {
|
|
26359
|
+
parts.push(`## Errors`);
|
|
26360
|
+
for (const err of report.errors) {
|
|
26361
|
+
parts.push(` ${err}`);
|
|
26362
|
+
}
|
|
26363
|
+
parts.push("");
|
|
26364
|
+
}
|
|
26365
|
+
return parts.join("\n");
|
|
26366
|
+
}
|
|
26367
|
+
function formatItemLine(parts, item, depth) {
|
|
26368
|
+
const indent = " ".repeat(depth + 1);
|
|
26369
|
+
const statusIcon = DONE_STATUSES16.has(item.marvinStatus) ? "\u2713" : item.marvinStatus === "blocked" ? "\u{1F6AB}" : item.marvinStatus === "in-progress" ? "\u25B6" : "\u25CB";
|
|
26370
|
+
const jiraLabel = item.jiraKey ? ` [${item.jiraKey}: ${item.jiraStatus}]` : "";
|
|
26371
|
+
const driftFlag = item.statusDrift ? " \u26A0drift" : "";
|
|
26372
|
+
const progressLabel = item.marvinProgress > 0 ? ` ${item.marvinProgress}%` : "";
|
|
26373
|
+
parts.push(`${indent}${statusIcon} ${item.id} \u2014 ${item.title} [${item.marvinStatus}]${progressLabel}${jiraLabel}${driftFlag}`);
|
|
26374
|
+
if (item.commentSummary) {
|
|
26375
|
+
parts.push(`${indent} \u{1F4AC} ${item.commentSummary}`);
|
|
26376
|
+
}
|
|
26377
|
+
for (const child of item.children) {
|
|
26378
|
+
formatItemLine(parts, child, depth + 1);
|
|
26379
|
+
}
|
|
26380
|
+
}
|
|
26381
|
+
function progressBar6(pct) {
|
|
26382
|
+
const filled = Math.round(pct / 10);
|
|
26383
|
+
const empty = 10 - filled;
|
|
26384
|
+
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}]`;
|
|
26385
|
+
}
|
|
26386
|
+
|
|
25963
26387
|
// src/skills/builtin/jira/tools.ts
|
|
25964
26388
|
var JIRA_TYPE = "jira-issue";
|
|
25965
26389
|
function jiraNotConfiguredError() {
|
|
@@ -26725,6 +27149,36 @@ function createJiraTools(store, projectConfig) {
|
|
|
26725
27149
|
};
|
|
26726
27150
|
},
|
|
26727
27151
|
{ annotations: { readOnlyHint: true } }
|
|
27152
|
+
),
|
|
27153
|
+
// --- Sprint progress assessment ---
|
|
27154
|
+
tool20(
|
|
27155
|
+
"assess_sprint_progress",
|
|
27156
|
+
"Assess sprint progress by fetching live Jira statuses for all sprint-scoped items, detecting drift between Marvin and Jira, grouping by focus area with rollup progress, and extracting comment signals. Optionally applies updates and uses LLM for comment analysis.",
|
|
27157
|
+
{
|
|
27158
|
+
sprintId: external_exports.string().optional().describe("Sprint ID (e.g. 'SP-001'). Defaults to active sprint."),
|
|
27159
|
+
analyzeComments: external_exports.boolean().optional().describe("Use LLM to summarize Jira comments for progress signals (default false)"),
|
|
27160
|
+
applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to Marvin artifacts (default false)")
|
|
27161
|
+
},
|
|
27162
|
+
async (args) => {
|
|
27163
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
27164
|
+
if (!jira) return jiraNotConfiguredError();
|
|
27165
|
+
const report = await assessSprintProgress(
|
|
27166
|
+
store,
|
|
27167
|
+
jira.client,
|
|
27168
|
+
jira.host,
|
|
27169
|
+
{
|
|
27170
|
+
sprintId: args.sprintId,
|
|
27171
|
+
analyzeComments: args.analyzeComments ?? false,
|
|
27172
|
+
applyUpdates: args.applyUpdates ?? false,
|
|
27173
|
+
statusMap
|
|
27174
|
+
}
|
|
27175
|
+
);
|
|
27176
|
+
return {
|
|
27177
|
+
content: [{ type: "text", text: formatProgressReport(report) }],
|
|
27178
|
+
isError: report.errors.length > 0 && report.itemReports.length === 0
|
|
27179
|
+
};
|
|
27180
|
+
},
|
|
27181
|
+
{ annotations: { readOnlyHint: false } }
|
|
26728
27182
|
)
|
|
26729
27183
|
];
|
|
26730
27184
|
}
|
|
@@ -26826,6 +27280,7 @@ var COMMON_TOOLS = `**Available tools:**
|
|
|
26826
27280
|
- \`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.
|
|
26827
27281
|
- \`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.
|
|
26828
27282
|
- \`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).
|
|
27283
|
+
- \`assess_sprint_progress\` \u2014 fetch live Jira statuses for all sprint-scoped items, detect drift, group by focus area with rollup progress, and extract comment signals. Use \`analyzeComments=true\` for LLM summaries, \`applyUpdates=true\` to apply changes.
|
|
26829
27284
|
- \`fetch_jira_statuses\` \u2014 **read-only**: discover all Jira statuses in a project and show their Marvin mappings (mapped vs unmapped).
|
|
26830
27285
|
- \`search_jira\` \u2014 **read-only**: search Jira via JQL and return results with Marvin cross-references. No documents created \u2014 use to preview before importing or find issues for linking.
|
|
26831
27286
|
- \`pull_jira_issue\` / \`pull_jira_issues_jql\` \u2014 import Jira issues as local JI-xxx documents (for Jira-originated items with no existing Marvin artifact).
|
|
@@ -26837,6 +27292,11 @@ var COMMON_WORKFLOW = `**Jira sync workflow:**
|
|
|
26837
27292
|
2. Analyze the proposed changes (status transitions, subtask progress, blockers from linked issues)
|
|
26838
27293
|
3. Use \`update_action\` / \`update_task\` to apply the changes you agree with
|
|
26839
27294
|
|
|
27295
|
+
**Sprint progress workflow:**
|
|
27296
|
+
1. Call \`assess_sprint_progress\` to get a comprehensive view of all sprint items with live Jira data
|
|
27297
|
+
2. Review focus area rollups, status drift, and blockers
|
|
27298
|
+
3. Optionally run with \`applyUpdates=true\` to bulk-sync statuses, or \`analyzeComments=true\` for LLM-powered comment summaries
|
|
27299
|
+
|
|
26840
27300
|
**Daily review workflow:**
|
|
26841
27301
|
1. Call \`fetch_jira_daily\` (optionally with \`from\`/\`to\` date range) to get a summary of all Jira activity
|
|
26842
27302
|
2. Review the proposed actions: status updates, unlinked issues to track, questions that may be answered, Confluence pages to review
|
|
@@ -26860,6 +27320,7 @@ ${COMMON_WORKFLOW}
|
|
|
26860
27320
|
|
|
26861
27321
|
**As Product Owner, use Jira integration to:**
|
|
26862
27322
|
- Use \`fetch_jira_daily\` for daily standups \u2014 review what changed, identify status drift, spot untracked work
|
|
27323
|
+
- Use \`assess_sprint_progress\` for sprint reviews \u2014 see overall progress by focus area, detect drift, and identify blockers
|
|
26863
27324
|
- Pull stakeholder-reported issues for triage and prioritization
|
|
26864
27325
|
- Push approved features as Stories for development tracking
|
|
26865
27326
|
- Link decisions to Jira issues for audit trail and traceability
|
|
@@ -26872,6 +27333,7 @@ ${COMMON_WORKFLOW}
|
|
|
26872
27333
|
|
|
26873
27334
|
**As Tech Lead, use Jira integration to:**
|
|
26874
27335
|
- Use \`fetch_jira_daily\` to review technical progress \u2014 status transitions, new comments, Confluence design docs
|
|
27336
|
+
- Use \`assess_sprint_progress\` for sprint health checks \u2014 focus area rollups, Jira drift detection, blocker tracking
|
|
26875
27337
|
- Pull technical issues and bugs for sprint planning and estimation
|
|
26876
27338
|
- Push epics, tasks, and technical decisions to Jira for cross-team visibility
|
|
26877
27339
|
- Use \`link_to_jira\` to connect Marvin tasks to existing Jira tickets
|
|
@@ -26885,6 +27347,8 @@ This is a third path for progress tracking alongside Contributions and Meetings.
|
|
|
26885
27347
|
|
|
26886
27348
|
**As Delivery Manager, use Jira integration to:**
|
|
26887
27349
|
- Use \`fetch_jira_daily\` for daily progress reports \u2014 track what moved, identify blockers, spot untracked work
|
|
27350
|
+
- Use \`assess_sprint_progress\` for sprint reviews and stakeholder updates \u2014 comprehensive progress by focus area with Jira enrichment
|
|
27351
|
+
- Use \`assess_sprint_progress\` with \`applyUpdates=true\` to bulk-sync Marvin statuses from Jira
|
|
26888
27352
|
- Pull sprint issues for tracking progress and blockers
|
|
26889
27353
|
- Push actions and tasks to Jira for stakeholder visibility
|
|
26890
27354
|
- Use \`fetch_jira_daily\` with a date range for sprint retrospectives (e.g. \`from: "2026-03-10", to: "2026-03-21"\`)
|
|
@@ -28383,11 +28847,11 @@ function createMarvinMcpServer(store, options) {
|
|
|
28383
28847
|
}
|
|
28384
28848
|
|
|
28385
28849
|
// src/agent/session-namer.ts
|
|
28386
|
-
import { query as
|
|
28850
|
+
import { query as query4 } from "@anthropic-ai/claude-agent-sdk";
|
|
28387
28851
|
async function generateSessionName(turns) {
|
|
28388
28852
|
try {
|
|
28389
28853
|
const transcript = turns.slice(-20).map((t) => `${t.role}: ${t.content.slice(0, 200)}`).join("\n");
|
|
28390
|
-
const result =
|
|
28854
|
+
const result = query4({
|
|
28391
28855
|
prompt: `Summarize this conversation in 3-5 words as a kebab-case name suitable for a filename. Output ONLY the name, nothing else.
|
|
28392
28856
|
|
|
28393
28857
|
${transcript}`,
|
|
@@ -28665,7 +29129,7 @@ Marvin \u2014 ${persona.name}
|
|
|
28665
29129
|
if (existingSession) {
|
|
28666
29130
|
queryOptions.resume = existingSession.id;
|
|
28667
29131
|
}
|
|
28668
|
-
const conversation =
|
|
29132
|
+
const conversation = query5({
|
|
28669
29133
|
prompt,
|
|
28670
29134
|
options: queryOptions
|
|
28671
29135
|
});
|
|
@@ -29024,7 +29488,7 @@ import * as fs12 from "fs";
|
|
|
29024
29488
|
import * as path12 from "path";
|
|
29025
29489
|
import chalk7 from "chalk";
|
|
29026
29490
|
import ora2 from "ora";
|
|
29027
|
-
import { query as
|
|
29491
|
+
import { query as query6 } from "@anthropic-ai/claude-agent-sdk";
|
|
29028
29492
|
|
|
29029
29493
|
// src/sources/prompts.ts
|
|
29030
29494
|
function buildIngestSystemPrompt(persona, projectConfig, isDraft) {
|
|
@@ -29157,7 +29621,7 @@ async function ingestFile(options) {
|
|
|
29157
29621
|
const spinner = ora2({ text: `Analyzing ${fileName}...`, color: "cyan" });
|
|
29158
29622
|
spinner.start();
|
|
29159
29623
|
try {
|
|
29160
|
-
const conversation =
|
|
29624
|
+
const conversation = query6({
|
|
29161
29625
|
prompt: userPrompt,
|
|
29162
29626
|
options: {
|
|
29163
29627
|
systemPrompt,
|
|
@@ -29687,7 +30151,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
29687
30151
|
import { tool as tool24 } from "@anthropic-ai/claude-agent-sdk";
|
|
29688
30152
|
|
|
29689
30153
|
// src/skills/action-runner.ts
|
|
29690
|
-
import { query as
|
|
30154
|
+
import { query as query7 } from "@anthropic-ai/claude-agent-sdk";
|
|
29691
30155
|
var GOVERNANCE_TOOL_NAMES2 = [
|
|
29692
30156
|
"mcp__marvin-governance__list_decisions",
|
|
29693
30157
|
"mcp__marvin-governance__get_decision",
|
|
@@ -29709,7 +30173,7 @@ async function runSkillAction(action, userPrompt, context) {
|
|
|
29709
30173
|
try {
|
|
29710
30174
|
const mcpServer = createMarvinMcpServer(context.store);
|
|
29711
30175
|
const allowedTools = action.allowGovernanceTools !== false ? GOVERNANCE_TOOL_NAMES2 : [];
|
|
29712
|
-
const conversation =
|
|
30176
|
+
const conversation = query7({
|
|
29713
30177
|
prompt: userPrompt,
|
|
29714
30178
|
options: {
|
|
29715
30179
|
systemPrompt: action.systemPrompt,
|
|
@@ -30750,7 +31214,7 @@ import chalk13 from "chalk";
|
|
|
30750
31214
|
// src/analysis/analyze.ts
|
|
30751
31215
|
import chalk12 from "chalk";
|
|
30752
31216
|
import ora4 from "ora";
|
|
30753
|
-
import { query as
|
|
31217
|
+
import { query as query8 } from "@anthropic-ai/claude-agent-sdk";
|
|
30754
31218
|
|
|
30755
31219
|
// src/analysis/prompts.ts
|
|
30756
31220
|
function buildAnalyzeSystemPrompt(persona, projectConfig, isDraft) {
|
|
@@ -30880,7 +31344,7 @@ async function analyzeMeeting(options) {
|
|
|
30880
31344
|
const spinner = ora4({ text: `Analyzing meeting ${meetingId}...`, color: "cyan" });
|
|
30881
31345
|
spinner.start();
|
|
30882
31346
|
try {
|
|
30883
|
-
const conversation =
|
|
31347
|
+
const conversation = query8({
|
|
30884
31348
|
prompt: userPrompt,
|
|
30885
31349
|
options: {
|
|
30886
31350
|
systemPrompt,
|
|
@@ -31007,7 +31471,7 @@ import chalk15 from "chalk";
|
|
|
31007
31471
|
// src/contributions/contribute.ts
|
|
31008
31472
|
import chalk14 from "chalk";
|
|
31009
31473
|
import ora5 from "ora";
|
|
31010
|
-
import { query as
|
|
31474
|
+
import { query as query9 } from "@anthropic-ai/claude-agent-sdk";
|
|
31011
31475
|
|
|
31012
31476
|
// src/contributions/prompts.ts
|
|
31013
31477
|
function buildContributeSystemPrompt(persona, contributionType, projectConfig, isDraft) {
|
|
@@ -31261,7 +31725,7 @@ async function contributeFromPersona(options) {
|
|
|
31261
31725
|
"mcp__marvin-governance__get_action",
|
|
31262
31726
|
"mcp__marvin-governance__get_question"
|
|
31263
31727
|
];
|
|
31264
|
-
const conversation =
|
|
31728
|
+
const conversation = query9({
|
|
31265
31729
|
prompt: userPrompt,
|
|
31266
31730
|
options: {
|
|
31267
31731
|
systemPrompt,
|
|
@@ -32100,7 +32564,7 @@ function createProgram() {
|
|
|
32100
32564
|
const program2 = new Command();
|
|
32101
32565
|
program2.name("marvin").description(
|
|
32102
32566
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
32103
|
-
).version("0.5.
|
|
32567
|
+
).version("0.5.14");
|
|
32104
32568
|
program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
32105
32569
|
await initCommand();
|
|
32106
32570
|
});
|