mrvn-cli 0.5.13 → 0.5.15
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 +572 -23
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +596 -47
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +572 -23
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin.js
CHANGED
|
@@ -18267,7 +18267,7 @@ import * as readline from "readline";
|
|
|
18267
18267
|
import chalk2 from "chalk";
|
|
18268
18268
|
import ora from "ora";
|
|
18269
18269
|
import {
|
|
18270
|
-
query as
|
|
18270
|
+
query as query5
|
|
18271
18271
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
18272
18272
|
|
|
18273
18273
|
// src/personas/prompt-builder.ts
|
|
@@ -18407,9 +18407,9 @@ var DocumentStore = class {
|
|
|
18407
18407
|
}
|
|
18408
18408
|
}
|
|
18409
18409
|
}
|
|
18410
|
-
list(
|
|
18410
|
+
list(query10) {
|
|
18411
18411
|
const results = [];
|
|
18412
|
-
const types =
|
|
18412
|
+
const types = query10?.type ? [query10.type] : Object.keys(this.typeDirs);
|
|
18413
18413
|
for (const type of types) {
|
|
18414
18414
|
const dirName = this.typeDirs[type];
|
|
18415
18415
|
if (!dirName) continue;
|
|
@@ -18420,9 +18420,9 @@ var DocumentStore = class {
|
|
|
18420
18420
|
const filePath = path6.join(dir, file2);
|
|
18421
18421
|
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
18422
18422
|
const doc = parseDocument(raw, filePath);
|
|
18423
|
-
if (
|
|
18424
|
-
if (
|
|
18425
|
-
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)))
|
|
18426
18426
|
continue;
|
|
18427
18427
|
results.push(doc);
|
|
18428
18428
|
}
|
|
@@ -22384,7 +22384,7 @@ function poBacklogPage(ctx) {
|
|
|
22384
22384
|
}
|
|
22385
22385
|
}
|
|
22386
22386
|
}
|
|
22387
|
-
const
|
|
22387
|
+
const DONE_STATUSES17 = /* @__PURE__ */ new Set(["done", "closed", "resolved", "cancelled"]);
|
|
22388
22388
|
function featureTaskStats(featureId) {
|
|
22389
22389
|
const fEpics = featureToEpics.get(featureId) ?? [];
|
|
22390
22390
|
let total = 0;
|
|
@@ -22393,7 +22393,7 @@ function poBacklogPage(ctx) {
|
|
|
22393
22393
|
for (const epic of fEpics) {
|
|
22394
22394
|
for (const t of epicToTasks.get(epic.frontmatter.id) ?? []) {
|
|
22395
22395
|
total++;
|
|
22396
|
-
if (
|
|
22396
|
+
if (DONE_STATUSES17.has(t.frontmatter.status)) done++;
|
|
22397
22397
|
progressSum += getEffectiveProgress(t.frontmatter);
|
|
22398
22398
|
}
|
|
22399
22399
|
}
|
|
@@ -25356,6 +25356,11 @@ function mapJiraStatusForTask(status, configMap) {
|
|
|
25356
25356
|
const lookup = buildStatusLookup(configMap, DEFAULT_TASK_STATUS_MAP);
|
|
25357
25357
|
return lookup.get(status.toLowerCase()) ?? "backlog";
|
|
25358
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
|
+
}
|
|
25359
25364
|
function computeSubtaskProgress(subtasks) {
|
|
25360
25365
|
if (subtasks.length === 0) return 0;
|
|
25361
25366
|
const done = subtasks.filter(
|
|
@@ -25738,10 +25743,10 @@ async function fetchJiraDaily(store, client, host, projectKey, dateRange, status
|
|
|
25738
25743
|
jiraKeyToArtifacts.set(jk, list);
|
|
25739
25744
|
}
|
|
25740
25745
|
}
|
|
25741
|
-
const
|
|
25746
|
+
const BATCH_SIZE2 = 5;
|
|
25742
25747
|
const issues = searchResult.issues;
|
|
25743
|
-
for (let i = 0; i < issues.length; i +=
|
|
25744
|
-
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);
|
|
25745
25750
|
const results = await Promise.allSettled(
|
|
25746
25751
|
batch.map(
|
|
25747
25752
|
(issue2) => processIssue(issue2, client, host, dateRange, jiraKeyToArtifacts, allDocs, statusMap)
|
|
@@ -25965,6 +25970,510 @@ function generateProposedActions(issues) {
|
|
|
25965
25970
|
return actions;
|
|
25966
25971
|
}
|
|
25967
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
|
+
var BLOCKED_WEIGHT_RISK_THRESHOLD = 0.3;
|
|
25978
|
+
var COMPLEXITY_WEIGHTS = {
|
|
25979
|
+
trivial: 1,
|
|
25980
|
+
simple: 2,
|
|
25981
|
+
moderate: 3,
|
|
25982
|
+
complex: 5,
|
|
25983
|
+
"very-complex": 8
|
|
25984
|
+
};
|
|
25985
|
+
var DEFAULT_WEIGHT = 3;
|
|
25986
|
+
var STATUS_PROGRESS_DEFAULTS = {
|
|
25987
|
+
done: 100,
|
|
25988
|
+
closed: 100,
|
|
25989
|
+
resolved: 100,
|
|
25990
|
+
obsolete: 100,
|
|
25991
|
+
"wont do": 100,
|
|
25992
|
+
cancelled: 100,
|
|
25993
|
+
review: 80,
|
|
25994
|
+
"in-progress": 40,
|
|
25995
|
+
ready: 5,
|
|
25996
|
+
backlog: 0,
|
|
25997
|
+
open: 0
|
|
25998
|
+
};
|
|
25999
|
+
var BLOCKED_DEFAULT_PROGRESS = 10;
|
|
26000
|
+
function resolveWeight(complexity) {
|
|
26001
|
+
if (complexity && complexity in COMPLEXITY_WEIGHTS) {
|
|
26002
|
+
return { weight: COMPLEXITY_WEIGHTS[complexity], weightSource: "complexity" };
|
|
26003
|
+
}
|
|
26004
|
+
return { weight: DEFAULT_WEIGHT, weightSource: "default" };
|
|
26005
|
+
}
|
|
26006
|
+
function resolveProgress(frontmatter, commentAnalysisProgress) {
|
|
26007
|
+
const hasExplicitProgress = "progress" in frontmatter && typeof frontmatter.progress === "number";
|
|
26008
|
+
if (hasExplicitProgress) {
|
|
26009
|
+
return { progress: Math.max(0, Math.min(100, Math.round(frontmatter.progress))), progressSource: "explicit" };
|
|
26010
|
+
}
|
|
26011
|
+
if (commentAnalysisProgress !== null) {
|
|
26012
|
+
return { progress: Math.max(0, Math.min(100, Math.round(commentAnalysisProgress))), progressSource: "comment-analysis" };
|
|
26013
|
+
}
|
|
26014
|
+
const status = frontmatter.status;
|
|
26015
|
+
if (status === "blocked") {
|
|
26016
|
+
return { progress: BLOCKED_DEFAULT_PROGRESS, progressSource: "status-default" };
|
|
26017
|
+
}
|
|
26018
|
+
const defaultProgress = STATUS_PROGRESS_DEFAULTS[status] ?? 0;
|
|
26019
|
+
return { progress: defaultProgress, progressSource: "status-default" };
|
|
26020
|
+
}
|
|
26021
|
+
function computeWeightedProgress(items) {
|
|
26022
|
+
if (items.length === 0) return 0;
|
|
26023
|
+
let totalWeight = 0;
|
|
26024
|
+
let weightedSum = 0;
|
|
26025
|
+
for (const item of items) {
|
|
26026
|
+
totalWeight += item.weight;
|
|
26027
|
+
weightedSum += item.weight * item.progress;
|
|
26028
|
+
}
|
|
26029
|
+
if (totalWeight === 0) return 0;
|
|
26030
|
+
return Math.round(weightedSum / totalWeight);
|
|
26031
|
+
}
|
|
26032
|
+
async function assessSprintProgress(store, client, host, options = {}) {
|
|
26033
|
+
const errors = [];
|
|
26034
|
+
const sprintData = collectSprintSummaryData(store, options.sprintId);
|
|
26035
|
+
if (!sprintData) {
|
|
26036
|
+
return {
|
|
26037
|
+
sprintId: options.sprintId ?? "unknown",
|
|
26038
|
+
sprintTitle: "Sprint not found",
|
|
26039
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26040
|
+
timeline: { startDate: null, endDate: null, daysRemaining: 0, totalDays: 0, percentComplete: 0 },
|
|
26041
|
+
overallProgress: 0,
|
|
26042
|
+
itemReports: [],
|
|
26043
|
+
focusAreas: [],
|
|
26044
|
+
driftItems: [],
|
|
26045
|
+
blockers: [],
|
|
26046
|
+
proposedUpdates: [],
|
|
26047
|
+
appliedUpdates: [],
|
|
26048
|
+
errors: [`Sprint ${options.sprintId ?? "(active)"} not found. Create a sprint artifact first.`]
|
|
26049
|
+
};
|
|
26050
|
+
}
|
|
26051
|
+
const sprintTag = `sprint:${sprintData.sprint.id}`;
|
|
26052
|
+
const actions = store.list({ type: "action", tag: sprintTag });
|
|
26053
|
+
const tasks = store.list({ type: "task", tag: sprintTag });
|
|
26054
|
+
const sprintItemIds = new Set([...actions, ...tasks].map((d) => d.frontmatter.id));
|
|
26055
|
+
const allTasks = store.list({ type: "task" });
|
|
26056
|
+
const allActions = store.list({ type: "action" });
|
|
26057
|
+
const nestedTasks = allTasks.filter(
|
|
26058
|
+
(d) => !sprintItemIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintItemIds.has(d.frontmatter.aboutArtifact)
|
|
26059
|
+
);
|
|
26060
|
+
const nestedActions = allActions.filter(
|
|
26061
|
+
(d) => !sprintItemIds.has(d.frontmatter.id) && d.frontmatter.aboutArtifact && sprintItemIds.has(d.frontmatter.aboutArtifact)
|
|
26062
|
+
);
|
|
26063
|
+
const allItems = [...actions, ...tasks, ...nestedTasks, ...nestedActions];
|
|
26064
|
+
const itemJiraKeys = /* @__PURE__ */ new Map();
|
|
26065
|
+
for (const doc of allItems) {
|
|
26066
|
+
const jiraKey = doc.frontmatter.jiraKey ?? extractJiraKeyFromTags(doc.frontmatter.tags);
|
|
26067
|
+
if (jiraKey) {
|
|
26068
|
+
itemJiraKeys.set(doc.frontmatter.id, jiraKey);
|
|
26069
|
+
}
|
|
26070
|
+
}
|
|
26071
|
+
const jiraKeys = [...new Set(itemJiraKeys.values())];
|
|
26072
|
+
const jiraIssues = /* @__PURE__ */ new Map();
|
|
26073
|
+
for (let i = 0; i < jiraKeys.length; i += BATCH_SIZE) {
|
|
26074
|
+
const batch = jiraKeys.slice(i, i + BATCH_SIZE);
|
|
26075
|
+
const results = await Promise.allSettled(
|
|
26076
|
+
batch.map(async (key) => {
|
|
26077
|
+
const [issue2, comments] = await Promise.all([
|
|
26078
|
+
client.getIssueWithLinks(key),
|
|
26079
|
+
client.getComments(key)
|
|
26080
|
+
]);
|
|
26081
|
+
return { key, issue: issue2, comments };
|
|
26082
|
+
})
|
|
26083
|
+
);
|
|
26084
|
+
for (const result of results) {
|
|
26085
|
+
if (result.status === "fulfilled") {
|
|
26086
|
+
jiraIssues.set(result.value.key, {
|
|
26087
|
+
issue: result.value.issue,
|
|
26088
|
+
comments: result.value.comments
|
|
26089
|
+
});
|
|
26090
|
+
} else {
|
|
26091
|
+
const batchKey = batch[results.indexOf(result)];
|
|
26092
|
+
errors.push(`Failed to fetch ${batchKey}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`);
|
|
26093
|
+
}
|
|
26094
|
+
}
|
|
26095
|
+
}
|
|
26096
|
+
const proposedUpdates = [];
|
|
26097
|
+
const itemReports = [];
|
|
26098
|
+
const childReportsByParent = /* @__PURE__ */ new Map();
|
|
26099
|
+
for (const doc of allItems) {
|
|
26100
|
+
const fm = doc.frontmatter;
|
|
26101
|
+
const jiraKey = itemJiraKeys.get(fm.id) ?? null;
|
|
26102
|
+
const jiraData = jiraKey ? jiraIssues.get(jiraKey) : null;
|
|
26103
|
+
let jiraStatus = null;
|
|
26104
|
+
let proposedMarvinStatus = null;
|
|
26105
|
+
let jiraSubtaskProgress = null;
|
|
26106
|
+
const commentSignals = [];
|
|
26107
|
+
if (jiraData) {
|
|
26108
|
+
jiraStatus = jiraData.issue.fields.status.name;
|
|
26109
|
+
proposedMarvinStatus = fm.type === "task" ? mapJiraStatusForTask(jiraStatus, options.statusMap?.task) : mapJiraStatusForAction(jiraStatus, options.statusMap?.action);
|
|
26110
|
+
const subtasks = jiraData.issue.fields.subtasks ?? [];
|
|
26111
|
+
if (subtasks.length > 0) {
|
|
26112
|
+
jiraSubtaskProgress = computeSubtaskProgress(subtasks);
|
|
26113
|
+
}
|
|
26114
|
+
for (const comment of jiraData.comments) {
|
|
26115
|
+
const text = extractCommentText(comment.body);
|
|
26116
|
+
const signals = detectCommentSignals(text);
|
|
26117
|
+
commentSignals.push(...signals);
|
|
26118
|
+
}
|
|
26119
|
+
}
|
|
26120
|
+
const statusDrift = proposedMarvinStatus !== null && proposedMarvinStatus !== fm.status;
|
|
26121
|
+
const currentProgress = getEffectiveProgress(fm);
|
|
26122
|
+
const progressDrift = jiraSubtaskProgress !== null && !fm.progressOverride && jiraSubtaskProgress !== currentProgress;
|
|
26123
|
+
if (statusDrift && proposedMarvinStatus) {
|
|
26124
|
+
proposedUpdates.push({
|
|
26125
|
+
artifactId: fm.id,
|
|
26126
|
+
field: "status",
|
|
26127
|
+
currentValue: fm.status,
|
|
26128
|
+
proposedValue: proposedMarvinStatus,
|
|
26129
|
+
reason: `Jira ${jiraKey} is "${jiraStatus}" \u2192 maps to "${proposedMarvinStatus}"`
|
|
26130
|
+
});
|
|
26131
|
+
}
|
|
26132
|
+
if (progressDrift && jiraSubtaskProgress !== null) {
|
|
26133
|
+
proposedUpdates.push({
|
|
26134
|
+
artifactId: fm.id,
|
|
26135
|
+
field: "progress",
|
|
26136
|
+
currentValue: currentProgress,
|
|
26137
|
+
proposedValue: jiraSubtaskProgress,
|
|
26138
|
+
reason: `Jira ${jiraKey} subtask progress is ${jiraSubtaskProgress}%`
|
|
26139
|
+
});
|
|
26140
|
+
}
|
|
26141
|
+
const tags = fm.tags ?? [];
|
|
26142
|
+
const focusTag = tags.find((t) => t.startsWith("focus:"));
|
|
26143
|
+
const { weight, weightSource } = resolveWeight(fm.complexity);
|
|
26144
|
+
const { progress: resolvedProgress, progressSource } = resolveProgress(fm, null);
|
|
26145
|
+
const report = {
|
|
26146
|
+
id: fm.id,
|
|
26147
|
+
title: fm.title,
|
|
26148
|
+
type: fm.type,
|
|
26149
|
+
marvinStatus: fm.status,
|
|
26150
|
+
marvinProgress: currentProgress,
|
|
26151
|
+
progress: resolvedProgress,
|
|
26152
|
+
progressSource,
|
|
26153
|
+
weight,
|
|
26154
|
+
weightSource,
|
|
26155
|
+
jiraKey,
|
|
26156
|
+
jiraStatus,
|
|
26157
|
+
jiraSubtaskProgress,
|
|
26158
|
+
proposedMarvinStatus,
|
|
26159
|
+
statusDrift,
|
|
26160
|
+
progressDrift,
|
|
26161
|
+
commentSignals,
|
|
26162
|
+
commentSummary: null,
|
|
26163
|
+
children: [],
|
|
26164
|
+
owner: fm.owner ?? null,
|
|
26165
|
+
focusArea: focusTag ? focusTag.slice(6) : null
|
|
26166
|
+
};
|
|
26167
|
+
const aboutArtifact = fm.aboutArtifact;
|
|
26168
|
+
if (aboutArtifact && sprintItemIds.has(aboutArtifact)) {
|
|
26169
|
+
if (!childReportsByParent.has(aboutArtifact)) {
|
|
26170
|
+
childReportsByParent.set(aboutArtifact, []);
|
|
26171
|
+
}
|
|
26172
|
+
childReportsByParent.get(aboutArtifact).push(report);
|
|
26173
|
+
}
|
|
26174
|
+
itemReports.push(report);
|
|
26175
|
+
}
|
|
26176
|
+
for (const report of itemReports) {
|
|
26177
|
+
const children = childReportsByParent.get(report.id);
|
|
26178
|
+
if (children) {
|
|
26179
|
+
report.children = children;
|
|
26180
|
+
}
|
|
26181
|
+
}
|
|
26182
|
+
const childIds = /* @__PURE__ */ new Set();
|
|
26183
|
+
for (const children of childReportsByParent.values()) {
|
|
26184
|
+
for (const child of children) childIds.add(child.id);
|
|
26185
|
+
}
|
|
26186
|
+
const rootReports = itemReports.filter((r) => !childIds.has(r.id));
|
|
26187
|
+
for (const report of rootReports) {
|
|
26188
|
+
if (report.children.length > 0) {
|
|
26189
|
+
const doc = store.get(report.id);
|
|
26190
|
+
const hasExplicitOverride = doc?.frontmatter.progressOverride;
|
|
26191
|
+
if (!hasExplicitOverride) {
|
|
26192
|
+
report.progress = computeWeightedProgress(report.children);
|
|
26193
|
+
report.progressSource = "status-default";
|
|
26194
|
+
}
|
|
26195
|
+
}
|
|
26196
|
+
}
|
|
26197
|
+
const focusAreaMap = /* @__PURE__ */ new Map();
|
|
26198
|
+
for (const report of rootReports) {
|
|
26199
|
+
if (!report.focusArea) continue;
|
|
26200
|
+
if (!focusAreaMap.has(report.focusArea)) focusAreaMap.set(report.focusArea, []);
|
|
26201
|
+
focusAreaMap.get(report.focusArea).push(report);
|
|
26202
|
+
}
|
|
26203
|
+
const focusAreas = [];
|
|
26204
|
+
for (const [name, items] of focusAreaMap) {
|
|
26205
|
+
const allFlatItems = items.flatMap((i) => [i, ...i.children]);
|
|
26206
|
+
const doneCount = allFlatItems.filter((i) => DONE_STATUSES16.has(i.marvinStatus)).length;
|
|
26207
|
+
const blockedCount = allFlatItems.filter((i) => i.marvinStatus === "blocked").length;
|
|
26208
|
+
const progress = computeWeightedProgress(items);
|
|
26209
|
+
const totalWeight = items.reduce((s, i) => s + i.weight, 0);
|
|
26210
|
+
const blockedWeight = items.filter((i) => i.marvinStatus === "blocked").reduce((s, i) => s + i.weight, 0);
|
|
26211
|
+
const blockedWeightPct = totalWeight > 0 ? Math.round(blockedWeight / totalWeight * 100) : 0;
|
|
26212
|
+
const riskWarning = blockedWeightPct > BLOCKED_WEIGHT_RISK_THRESHOLD * 100 ? `${blockedWeightPct}% of scope is blocked` : null;
|
|
26213
|
+
focusAreas.push({
|
|
26214
|
+
name,
|
|
26215
|
+
progress,
|
|
26216
|
+
taskCount: allFlatItems.length,
|
|
26217
|
+
doneCount,
|
|
26218
|
+
blockedCount,
|
|
26219
|
+
blockedWeightPct,
|
|
26220
|
+
riskWarning,
|
|
26221
|
+
items
|
|
26222
|
+
});
|
|
26223
|
+
}
|
|
26224
|
+
focusAreas.sort((a, b) => a.name.localeCompare(b.name));
|
|
26225
|
+
const driftItems = itemReports.filter((r) => r.statusDrift || r.progressDrift);
|
|
26226
|
+
const blockers = itemReports.filter(
|
|
26227
|
+
(r) => r.marvinStatus === "blocked" || r.commentSignals.some((s) => s.type === "blocker")
|
|
26228
|
+
);
|
|
26229
|
+
if (options.analyzeComments) {
|
|
26230
|
+
const itemsWithComments = itemReports.filter((r) => r.commentSignals.length > 0 && r.jiraKey);
|
|
26231
|
+
if (itemsWithComments.length > 0) {
|
|
26232
|
+
try {
|
|
26233
|
+
const summaries = await analyzeCommentsForProgress(
|
|
26234
|
+
itemsWithComments,
|
|
26235
|
+
jiraIssues,
|
|
26236
|
+
itemJiraKeys
|
|
26237
|
+
);
|
|
26238
|
+
for (const [artifactId, summary] of summaries) {
|
|
26239
|
+
const report = itemReports.find((r) => r.id === artifactId);
|
|
26240
|
+
if (report) {
|
|
26241
|
+
report.commentSummary = summary;
|
|
26242
|
+
if (report.progressSource === "status-default") {
|
|
26243
|
+
const pctMatch = summary.match(/(\d{1,3})%/);
|
|
26244
|
+
if (pctMatch) {
|
|
26245
|
+
const pct = parseInt(pctMatch[1], 10);
|
|
26246
|
+
if (pct >= 0 && pct <= 100) {
|
|
26247
|
+
report.progress = pct;
|
|
26248
|
+
report.progressSource = "comment-analysis";
|
|
26249
|
+
}
|
|
26250
|
+
}
|
|
26251
|
+
}
|
|
26252
|
+
}
|
|
26253
|
+
}
|
|
26254
|
+
} catch (err) {
|
|
26255
|
+
errors.push(`Comment analysis failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
26256
|
+
}
|
|
26257
|
+
}
|
|
26258
|
+
}
|
|
26259
|
+
const appliedUpdates = [];
|
|
26260
|
+
if (options.applyUpdates && proposedUpdates.length > 0) {
|
|
26261
|
+
for (const update of proposedUpdates) {
|
|
26262
|
+
try {
|
|
26263
|
+
store.update(update.artifactId, {
|
|
26264
|
+
[update.field]: update.proposedValue,
|
|
26265
|
+
lastJiraSyncAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26266
|
+
});
|
|
26267
|
+
const doc = store.get(update.artifactId);
|
|
26268
|
+
if (doc) {
|
|
26269
|
+
if (doc.frontmatter.type === "task") {
|
|
26270
|
+
propagateProgressFromTask(store, update.artifactId);
|
|
26271
|
+
} else if (doc.frontmatter.type === "action") {
|
|
26272
|
+
propagateProgressToAction(store, update.artifactId);
|
|
26273
|
+
}
|
|
26274
|
+
}
|
|
26275
|
+
appliedUpdates.push(update);
|
|
26276
|
+
} catch (err) {
|
|
26277
|
+
errors.push(
|
|
26278
|
+
`Failed to apply update to ${update.artifactId}: ${err instanceof Error ? err.message : String(err)}`
|
|
26279
|
+
);
|
|
26280
|
+
}
|
|
26281
|
+
}
|
|
26282
|
+
}
|
|
26283
|
+
return {
|
|
26284
|
+
sprintId: sprintData.sprint.id,
|
|
26285
|
+
sprintTitle: sprintData.sprint.title,
|
|
26286
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26287
|
+
timeline: {
|
|
26288
|
+
startDate: sprintData.sprint.startDate ?? null,
|
|
26289
|
+
endDate: sprintData.sprint.endDate ?? null,
|
|
26290
|
+
daysRemaining: sprintData.timeline.daysRemaining,
|
|
26291
|
+
totalDays: sprintData.timeline.totalDays,
|
|
26292
|
+
percentComplete: sprintData.timeline.percentComplete
|
|
26293
|
+
},
|
|
26294
|
+
overallProgress: rootReports.length > 0 ? computeWeightedProgress(rootReports) : sprintData.workItems.completionPct,
|
|
26295
|
+
itemReports: rootReports,
|
|
26296
|
+
focusAreas,
|
|
26297
|
+
driftItems,
|
|
26298
|
+
blockers,
|
|
26299
|
+
proposedUpdates: options.applyUpdates ? [] : proposedUpdates,
|
|
26300
|
+
appliedUpdates,
|
|
26301
|
+
errors
|
|
26302
|
+
};
|
|
26303
|
+
}
|
|
26304
|
+
var COMMENT_ANALYSIS_PROMPT = `You are a delivery management assistant analyzing Jira comments for progress signals.
|
|
26305
|
+
|
|
26306
|
+
For each item below, read the Jira comments and produce a 1-2 sentence progress summary.
|
|
26307
|
+
Focus on: what work was done, what's pending, any blockers or decisions mentioned.
|
|
26308
|
+
|
|
26309
|
+
Return your response as a JSON object mapping artifact IDs to summary strings.
|
|
26310
|
+
Example: {"T-001": "Backend API completed and deployed. Frontend integration pending review.", "A-003": "Blocked on infrastructure team approval."}
|
|
26311
|
+
|
|
26312
|
+
IMPORTANT: Only return the JSON object, no other text.`;
|
|
26313
|
+
async function analyzeCommentsForProgress(items, jiraIssues, itemJiraKeys) {
|
|
26314
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
26315
|
+
const MAX_ITEMS_PER_CALL = 20;
|
|
26316
|
+
const itemsToAnalyze = items.slice(0, MAX_ITEMS_PER_CALL);
|
|
26317
|
+
const promptParts = [];
|
|
26318
|
+
for (const item of itemsToAnalyze) {
|
|
26319
|
+
const jiraKey = itemJiraKeys.get(item.id);
|
|
26320
|
+
if (!jiraKey) continue;
|
|
26321
|
+
const jiraData = jiraIssues.get(jiraKey);
|
|
26322
|
+
if (!jiraData || jiraData.comments.length === 0) continue;
|
|
26323
|
+
const commentTexts = jiraData.comments.map((c) => {
|
|
26324
|
+
const text = extractCommentText(c.body);
|
|
26325
|
+
return ` [${c.author.displayName}, ${c.created.slice(0, 10)}]: ${text.slice(0, 500)}`;
|
|
26326
|
+
}).join("\n");
|
|
26327
|
+
promptParts.push(`## ${item.id} \u2014 ${item.title} (${jiraKey}, Jira status: ${item.jiraStatus})
|
|
26328
|
+
Comments:
|
|
26329
|
+
${commentTexts}`);
|
|
26330
|
+
}
|
|
26331
|
+
if (promptParts.length === 0) return summaries;
|
|
26332
|
+
const prompt = promptParts.join("\n\n");
|
|
26333
|
+
const result = query3({
|
|
26334
|
+
prompt,
|
|
26335
|
+
options: {
|
|
26336
|
+
systemPrompt: COMMENT_ANALYSIS_PROMPT,
|
|
26337
|
+
maxTurns: 1,
|
|
26338
|
+
tools: [],
|
|
26339
|
+
allowedTools: []
|
|
26340
|
+
}
|
|
26341
|
+
});
|
|
26342
|
+
for await (const msg of result) {
|
|
26343
|
+
if (msg.type === "assistant") {
|
|
26344
|
+
const textBlock = msg.message.content.find(
|
|
26345
|
+
(b) => b.type === "text"
|
|
26346
|
+
);
|
|
26347
|
+
if (textBlock) {
|
|
26348
|
+
try {
|
|
26349
|
+
const parsed = JSON.parse(textBlock.text);
|
|
26350
|
+
for (const [id, summary] of Object.entries(parsed)) {
|
|
26351
|
+
if (typeof summary === "string") {
|
|
26352
|
+
summaries.set(id, summary);
|
|
26353
|
+
}
|
|
26354
|
+
}
|
|
26355
|
+
} catch {
|
|
26356
|
+
const match = textBlock.text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
26357
|
+
if (match) {
|
|
26358
|
+
try {
|
|
26359
|
+
const parsed = JSON.parse(match[1]);
|
|
26360
|
+
for (const [id, summary] of Object.entries(parsed)) {
|
|
26361
|
+
if (typeof summary === "string") {
|
|
26362
|
+
summaries.set(id, summary);
|
|
26363
|
+
}
|
|
26364
|
+
}
|
|
26365
|
+
} catch {
|
|
26366
|
+
}
|
|
26367
|
+
}
|
|
26368
|
+
}
|
|
26369
|
+
}
|
|
26370
|
+
}
|
|
26371
|
+
}
|
|
26372
|
+
return summaries;
|
|
26373
|
+
}
|
|
26374
|
+
function formatProgressReport(report) {
|
|
26375
|
+
const parts = [];
|
|
26376
|
+
parts.push(`# Sprint Progress Assessment \u2014 ${report.sprintId}`);
|
|
26377
|
+
parts.push(`${report.sprintTitle}`);
|
|
26378
|
+
parts.push(`Generated: ${report.generatedAt.slice(0, 16)}`);
|
|
26379
|
+
parts.push("");
|
|
26380
|
+
if (report.timeline.startDate && report.timeline.endDate) {
|
|
26381
|
+
parts.push(`## Timeline`);
|
|
26382
|
+
parts.push(`${report.timeline.startDate} \u2192 ${report.timeline.endDate}`);
|
|
26383
|
+
parts.push(`Days remaining: ${report.timeline.daysRemaining} / ${report.timeline.totalDays} (${report.timeline.percentComplete}% elapsed)`);
|
|
26384
|
+
parts.push(`Overall progress: ${report.overallProgress}%`);
|
|
26385
|
+
parts.push("");
|
|
26386
|
+
}
|
|
26387
|
+
if (report.focusAreas.length > 0) {
|
|
26388
|
+
parts.push(`## Focus Areas`);
|
|
26389
|
+
parts.push("");
|
|
26390
|
+
for (const area of report.focusAreas) {
|
|
26391
|
+
const bar = progressBar6(area.progress);
|
|
26392
|
+
parts.push(`### ${area.name} ${bar} ${area.progress}%`);
|
|
26393
|
+
parts.push(`${area.doneCount}/${area.taskCount} done${area.blockedCount > 0 ? ` | ${area.blockedCount} blocked` : ""}`);
|
|
26394
|
+
if (area.riskWarning) {
|
|
26395
|
+
parts.push(` \u26A0 ${area.riskWarning}`);
|
|
26396
|
+
}
|
|
26397
|
+
parts.push("");
|
|
26398
|
+
for (const item of area.items) {
|
|
26399
|
+
formatItemLine(parts, item, 0);
|
|
26400
|
+
}
|
|
26401
|
+
parts.push("");
|
|
26402
|
+
}
|
|
26403
|
+
}
|
|
26404
|
+
if (report.driftItems.length > 0) {
|
|
26405
|
+
parts.push(`## Status Drift (${report.driftItems.length} items)`);
|
|
26406
|
+
for (const item of report.driftItems) {
|
|
26407
|
+
const driftParts = [];
|
|
26408
|
+
if (item.statusDrift) {
|
|
26409
|
+
driftParts.push(`status: ${item.marvinStatus} \u2192 ${item.proposedMarvinStatus}`);
|
|
26410
|
+
}
|
|
26411
|
+
if (item.progressDrift && item.jiraSubtaskProgress !== null) {
|
|
26412
|
+
driftParts.push(`progress: ${item.marvinProgress}% \u2192 ${item.jiraSubtaskProgress}%`);
|
|
26413
|
+
}
|
|
26414
|
+
parts.push(` \u26A0 ${item.id} (${item.jiraKey}) \u2014 ${driftParts.join(", ")}`);
|
|
26415
|
+
}
|
|
26416
|
+
parts.push("");
|
|
26417
|
+
}
|
|
26418
|
+
if (report.blockers.length > 0) {
|
|
26419
|
+
parts.push(`## Blockers (${report.blockers.length})`);
|
|
26420
|
+
for (const item of report.blockers) {
|
|
26421
|
+
const blockerSignals = item.commentSignals.filter((s) => s.type === "blocker");
|
|
26422
|
+
parts.push(` \u{1F6AB} ${item.id} \u2014 ${item.title}${item.jiraKey ? ` (${item.jiraKey})` : ""}`);
|
|
26423
|
+
for (const signal of blockerSignals) {
|
|
26424
|
+
parts.push(` "${signal.snippet}"`);
|
|
26425
|
+
}
|
|
26426
|
+
}
|
|
26427
|
+
parts.push("");
|
|
26428
|
+
}
|
|
26429
|
+
if (report.proposedUpdates.length > 0) {
|
|
26430
|
+
parts.push(`## Proposed Updates (${report.proposedUpdates.length})`);
|
|
26431
|
+
for (const update of report.proposedUpdates) {
|
|
26432
|
+
parts.push(` ${update.artifactId}.${update.field}: ${String(update.currentValue)} \u2192 ${String(update.proposedValue)}`);
|
|
26433
|
+
parts.push(` Reason: ${update.reason}`);
|
|
26434
|
+
}
|
|
26435
|
+
parts.push("");
|
|
26436
|
+
parts.push("Run with applyUpdates=true to apply these changes.");
|
|
26437
|
+
parts.push("");
|
|
26438
|
+
}
|
|
26439
|
+
if (report.appliedUpdates.length > 0) {
|
|
26440
|
+
parts.push(`## Applied Updates (${report.appliedUpdates.length})`);
|
|
26441
|
+
for (const update of report.appliedUpdates) {
|
|
26442
|
+
parts.push(` \u2713 ${update.artifactId}.${update.field}: ${String(update.currentValue)} \u2192 ${String(update.proposedValue)}`);
|
|
26443
|
+
}
|
|
26444
|
+
parts.push("");
|
|
26445
|
+
}
|
|
26446
|
+
if (report.errors.length > 0) {
|
|
26447
|
+
parts.push(`## Errors`);
|
|
26448
|
+
for (const err of report.errors) {
|
|
26449
|
+
parts.push(` ${err}`);
|
|
26450
|
+
}
|
|
26451
|
+
parts.push("");
|
|
26452
|
+
}
|
|
26453
|
+
return parts.join("\n");
|
|
26454
|
+
}
|
|
26455
|
+
function formatItemLine(parts, item, depth) {
|
|
26456
|
+
const indent = " ".repeat(depth + 1);
|
|
26457
|
+
const statusIcon = DONE_STATUSES16.has(item.marvinStatus) ? "\u2713" : item.marvinStatus === "blocked" ? "\u{1F6AB}" : item.marvinStatus === "in-progress" ? "\u25B6" : "\u25CB";
|
|
26458
|
+
const jiraLabel = item.jiraKey ? ` [${item.jiraKey}: ${item.jiraStatus}]` : "";
|
|
26459
|
+
const driftFlag = item.statusDrift ? " \u26A0drift" : "";
|
|
26460
|
+
const progressLabel = ` ${item.progress}%`;
|
|
26461
|
+
const weightLabel = `w${item.weight}`;
|
|
26462
|
+
const sourceLabel = item.progressSource === "explicit" ? "" : item.progressSource === "comment-analysis" ? " (llm)" : " (est)";
|
|
26463
|
+
parts.push(`${indent}${statusIcon} ${item.id} \u2014 ${item.title} [${item.marvinStatus}]${progressLabel}${sourceLabel} (${weightLabel})${jiraLabel}${driftFlag}`);
|
|
26464
|
+
if (item.commentSummary) {
|
|
26465
|
+
parts.push(`${indent} \u{1F4AC} ${item.commentSummary}`);
|
|
26466
|
+
}
|
|
26467
|
+
for (const child of item.children) {
|
|
26468
|
+
formatItemLine(parts, child, depth + 1);
|
|
26469
|
+
}
|
|
26470
|
+
}
|
|
26471
|
+
function progressBar6(pct) {
|
|
26472
|
+
const filled = Math.round(pct / 10);
|
|
26473
|
+
const empty = 10 - filled;
|
|
26474
|
+
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}]`;
|
|
26475
|
+
}
|
|
26476
|
+
|
|
25968
26477
|
// src/skills/builtin/jira/tools.ts
|
|
25969
26478
|
var JIRA_TYPE = "jira-issue";
|
|
25970
26479
|
function jiraNotConfiguredError() {
|
|
@@ -26730,6 +27239,36 @@ function createJiraTools(store, projectConfig) {
|
|
|
26730
27239
|
};
|
|
26731
27240
|
},
|
|
26732
27241
|
{ annotations: { readOnlyHint: true } }
|
|
27242
|
+
),
|
|
27243
|
+
// --- Sprint progress assessment ---
|
|
27244
|
+
tool20(
|
|
27245
|
+
"assess_sprint_progress",
|
|
27246
|
+
"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.",
|
|
27247
|
+
{
|
|
27248
|
+
sprintId: external_exports.string().optional().describe("Sprint ID (e.g. 'SP-001'). Defaults to active sprint."),
|
|
27249
|
+
analyzeComments: external_exports.boolean().optional().describe("Use LLM to summarize Jira comments for progress signals (default false)"),
|
|
27250
|
+
applyUpdates: external_exports.boolean().optional().describe("Apply proposed status/progress updates to Marvin artifacts (default false)")
|
|
27251
|
+
},
|
|
27252
|
+
async (args) => {
|
|
27253
|
+
const jira = createJiraClient(jiraUserConfig);
|
|
27254
|
+
if (!jira) return jiraNotConfiguredError();
|
|
27255
|
+
const report = await assessSprintProgress(
|
|
27256
|
+
store,
|
|
27257
|
+
jira.client,
|
|
27258
|
+
jira.host,
|
|
27259
|
+
{
|
|
27260
|
+
sprintId: args.sprintId,
|
|
27261
|
+
analyzeComments: args.analyzeComments ?? false,
|
|
27262
|
+
applyUpdates: args.applyUpdates ?? false,
|
|
27263
|
+
statusMap
|
|
27264
|
+
}
|
|
27265
|
+
);
|
|
27266
|
+
return {
|
|
27267
|
+
content: [{ type: "text", text: formatProgressReport(report) }],
|
|
27268
|
+
isError: report.errors.length > 0 && report.itemReports.length === 0
|
|
27269
|
+
};
|
|
27270
|
+
},
|
|
27271
|
+
{ annotations: { readOnlyHint: false } }
|
|
26733
27272
|
)
|
|
26734
27273
|
];
|
|
26735
27274
|
}
|
|
@@ -26831,6 +27370,7 @@ var COMMON_TOOLS = `**Available tools:**
|
|
|
26831
27370
|
- \`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.
|
|
26832
27371
|
- \`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.
|
|
26833
27372
|
- \`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).
|
|
27373
|
+
- \`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.
|
|
26834
27374
|
- \`fetch_jira_statuses\` \u2014 **read-only**: discover all Jira statuses in a project and show their Marvin mappings (mapped vs unmapped).
|
|
26835
27375
|
- \`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.
|
|
26836
27376
|
- \`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).
|
|
@@ -26842,6 +27382,11 @@ var COMMON_WORKFLOW = `**Jira sync workflow:**
|
|
|
26842
27382
|
2. Analyze the proposed changes (status transitions, subtask progress, blockers from linked issues)
|
|
26843
27383
|
3. Use \`update_action\` / \`update_task\` to apply the changes you agree with
|
|
26844
27384
|
|
|
27385
|
+
**Sprint progress workflow:**
|
|
27386
|
+
1. Call \`assess_sprint_progress\` to get a comprehensive view of all sprint items with live Jira data
|
|
27387
|
+
2. Review focus area rollups, status drift, and blockers
|
|
27388
|
+
3. Optionally run with \`applyUpdates=true\` to bulk-sync statuses, or \`analyzeComments=true\` for LLM-powered comment summaries
|
|
27389
|
+
|
|
26845
27390
|
**Daily review workflow:**
|
|
26846
27391
|
1. Call \`fetch_jira_daily\` (optionally with \`from\`/\`to\` date range) to get a summary of all Jira activity
|
|
26847
27392
|
2. Review the proposed actions: status updates, unlinked issues to track, questions that may be answered, Confluence pages to review
|
|
@@ -26865,6 +27410,7 @@ ${COMMON_WORKFLOW}
|
|
|
26865
27410
|
|
|
26866
27411
|
**As Product Owner, use Jira integration to:**
|
|
26867
27412
|
- Use \`fetch_jira_daily\` for daily standups \u2014 review what changed, identify status drift, spot untracked work
|
|
27413
|
+
- Use \`assess_sprint_progress\` for sprint reviews \u2014 see overall progress by focus area, detect drift, and identify blockers
|
|
26868
27414
|
- Pull stakeholder-reported issues for triage and prioritization
|
|
26869
27415
|
- Push approved features as Stories for development tracking
|
|
26870
27416
|
- Link decisions to Jira issues for audit trail and traceability
|
|
@@ -26877,6 +27423,7 @@ ${COMMON_WORKFLOW}
|
|
|
26877
27423
|
|
|
26878
27424
|
**As Tech Lead, use Jira integration to:**
|
|
26879
27425
|
- Use \`fetch_jira_daily\` to review technical progress \u2014 status transitions, new comments, Confluence design docs
|
|
27426
|
+
- Use \`assess_sprint_progress\` for sprint health checks \u2014 focus area rollups, Jira drift detection, blocker tracking
|
|
26880
27427
|
- Pull technical issues and bugs for sprint planning and estimation
|
|
26881
27428
|
- Push epics, tasks, and technical decisions to Jira for cross-team visibility
|
|
26882
27429
|
- Use \`link_to_jira\` to connect Marvin tasks to existing Jira tickets
|
|
@@ -26890,6 +27437,8 @@ This is a third path for progress tracking alongside Contributions and Meetings.
|
|
|
26890
27437
|
|
|
26891
27438
|
**As Delivery Manager, use Jira integration to:**
|
|
26892
27439
|
- Use \`fetch_jira_daily\` for daily progress reports \u2014 track what moved, identify blockers, spot untracked work
|
|
27440
|
+
- Use \`assess_sprint_progress\` for sprint reviews and stakeholder updates \u2014 comprehensive progress by focus area with Jira enrichment
|
|
27441
|
+
- Use \`assess_sprint_progress\` with \`applyUpdates=true\` to bulk-sync Marvin statuses from Jira
|
|
26893
27442
|
- Pull sprint issues for tracking progress and blockers
|
|
26894
27443
|
- Push actions and tasks to Jira for stakeholder visibility
|
|
26895
27444
|
- Use \`fetch_jira_daily\` with a date range for sprint retrospectives (e.g. \`from: "2026-03-10", to: "2026-03-21"\`)
|
|
@@ -28388,11 +28937,11 @@ function createMarvinMcpServer(store, options) {
|
|
|
28388
28937
|
}
|
|
28389
28938
|
|
|
28390
28939
|
// src/agent/session-namer.ts
|
|
28391
|
-
import { query as
|
|
28940
|
+
import { query as query4 } from "@anthropic-ai/claude-agent-sdk";
|
|
28392
28941
|
async function generateSessionName(turns) {
|
|
28393
28942
|
try {
|
|
28394
28943
|
const transcript = turns.slice(-20).map((t) => `${t.role}: ${t.content.slice(0, 200)}`).join("\n");
|
|
28395
|
-
const result =
|
|
28944
|
+
const result = query4({
|
|
28396
28945
|
prompt: `Summarize this conversation in 3-5 words as a kebab-case name suitable for a filename. Output ONLY the name, nothing else.
|
|
28397
28946
|
|
|
28398
28947
|
${transcript}`,
|
|
@@ -28670,7 +29219,7 @@ Marvin \u2014 ${persona.name}
|
|
|
28670
29219
|
if (existingSession) {
|
|
28671
29220
|
queryOptions.resume = existingSession.id;
|
|
28672
29221
|
}
|
|
28673
|
-
const conversation =
|
|
29222
|
+
const conversation = query5({
|
|
28674
29223
|
prompt,
|
|
28675
29224
|
options: queryOptions
|
|
28676
29225
|
});
|
|
@@ -29029,7 +29578,7 @@ import * as fs12 from "fs";
|
|
|
29029
29578
|
import * as path12 from "path";
|
|
29030
29579
|
import chalk7 from "chalk";
|
|
29031
29580
|
import ora2 from "ora";
|
|
29032
|
-
import { query as
|
|
29581
|
+
import { query as query6 } from "@anthropic-ai/claude-agent-sdk";
|
|
29033
29582
|
|
|
29034
29583
|
// src/sources/prompts.ts
|
|
29035
29584
|
function buildIngestSystemPrompt(persona, projectConfig, isDraft) {
|
|
@@ -29162,7 +29711,7 @@ async function ingestFile(options) {
|
|
|
29162
29711
|
const spinner = ora2({ text: `Analyzing ${fileName}...`, color: "cyan" });
|
|
29163
29712
|
spinner.start();
|
|
29164
29713
|
try {
|
|
29165
|
-
const conversation =
|
|
29714
|
+
const conversation = query6({
|
|
29166
29715
|
prompt: userPrompt,
|
|
29167
29716
|
options: {
|
|
29168
29717
|
systemPrompt,
|
|
@@ -29692,7 +30241,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
29692
30241
|
import { tool as tool24 } from "@anthropic-ai/claude-agent-sdk";
|
|
29693
30242
|
|
|
29694
30243
|
// src/skills/action-runner.ts
|
|
29695
|
-
import { query as
|
|
30244
|
+
import { query as query7 } from "@anthropic-ai/claude-agent-sdk";
|
|
29696
30245
|
var GOVERNANCE_TOOL_NAMES2 = [
|
|
29697
30246
|
"mcp__marvin-governance__list_decisions",
|
|
29698
30247
|
"mcp__marvin-governance__get_decision",
|
|
@@ -29714,7 +30263,7 @@ async function runSkillAction(action, userPrompt, context) {
|
|
|
29714
30263
|
try {
|
|
29715
30264
|
const mcpServer = createMarvinMcpServer(context.store);
|
|
29716
30265
|
const allowedTools = action.allowGovernanceTools !== false ? GOVERNANCE_TOOL_NAMES2 : [];
|
|
29717
|
-
const conversation =
|
|
30266
|
+
const conversation = query7({
|
|
29718
30267
|
prompt: userPrompt,
|
|
29719
30268
|
options: {
|
|
29720
30269
|
systemPrompt: action.systemPrompt,
|
|
@@ -30755,7 +31304,7 @@ import chalk13 from "chalk";
|
|
|
30755
31304
|
// src/analysis/analyze.ts
|
|
30756
31305
|
import chalk12 from "chalk";
|
|
30757
31306
|
import ora4 from "ora";
|
|
30758
|
-
import { query as
|
|
31307
|
+
import { query as query8 } from "@anthropic-ai/claude-agent-sdk";
|
|
30759
31308
|
|
|
30760
31309
|
// src/analysis/prompts.ts
|
|
30761
31310
|
function buildAnalyzeSystemPrompt(persona, projectConfig, isDraft) {
|
|
@@ -30885,7 +31434,7 @@ async function analyzeMeeting(options) {
|
|
|
30885
31434
|
const spinner = ora4({ text: `Analyzing meeting ${meetingId}...`, color: "cyan" });
|
|
30886
31435
|
spinner.start();
|
|
30887
31436
|
try {
|
|
30888
|
-
const conversation =
|
|
31437
|
+
const conversation = query8({
|
|
30889
31438
|
prompt: userPrompt,
|
|
30890
31439
|
options: {
|
|
30891
31440
|
systemPrompt,
|
|
@@ -31012,7 +31561,7 @@ import chalk15 from "chalk";
|
|
|
31012
31561
|
// src/contributions/contribute.ts
|
|
31013
31562
|
import chalk14 from "chalk";
|
|
31014
31563
|
import ora5 from "ora";
|
|
31015
|
-
import { query as
|
|
31564
|
+
import { query as query9 } from "@anthropic-ai/claude-agent-sdk";
|
|
31016
31565
|
|
|
31017
31566
|
// src/contributions/prompts.ts
|
|
31018
31567
|
function buildContributeSystemPrompt(persona, contributionType, projectConfig, isDraft) {
|
|
@@ -31266,7 +31815,7 @@ async function contributeFromPersona(options) {
|
|
|
31266
31815
|
"mcp__marvin-governance__get_action",
|
|
31267
31816
|
"mcp__marvin-governance__get_question"
|
|
31268
31817
|
];
|
|
31269
|
-
const conversation =
|
|
31818
|
+
const conversation = query9({
|
|
31270
31819
|
prompt: userPrompt,
|
|
31271
31820
|
options: {
|
|
31272
31821
|
systemPrompt,
|
|
@@ -32105,7 +32654,7 @@ function createProgram() {
|
|
|
32105
32654
|
const program2 = new Command();
|
|
32106
32655
|
program2.name("marvin").description(
|
|
32107
32656
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
32108
|
-
).version("0.5.
|
|
32657
|
+
).version("0.5.15");
|
|
32109
32658
|
program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
32110
32659
|
await initCommand();
|
|
32111
32660
|
});
|