mrvn-cli 0.1.0 → 0.1.2
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 +339 -7
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +73 -2
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +339 -7
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -218,9 +218,9 @@ var DocumentStore = class {
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
-
list(
|
|
221
|
+
list(query6) {
|
|
222
222
|
const results = [];
|
|
223
|
-
const types =
|
|
223
|
+
const types = query6?.type ? [query6.type] : Object.keys(this.typeDirs);
|
|
224
224
|
for (const type of types) {
|
|
225
225
|
const dirName = this.typeDirs[type];
|
|
226
226
|
if (!dirName) continue;
|
|
@@ -231,9 +231,9 @@ var DocumentStore = class {
|
|
|
231
231
|
const filePath = path3.join(dir, file2);
|
|
232
232
|
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
233
233
|
const doc = parseDocument(raw, filePath);
|
|
234
|
-
if (
|
|
235
|
-
if (
|
|
236
|
-
if (
|
|
234
|
+
if (query6?.status && doc.frontmatter.status !== query6.status) continue;
|
|
235
|
+
if (query6?.owner && doc.frontmatter.owner !== query6.owner) continue;
|
|
236
|
+
if (query6?.tag && (!doc.frontmatter.tags || !doc.frontmatter.tags.includes(query6.tag)))
|
|
237
237
|
continue;
|
|
238
238
|
results.push(doc);
|
|
239
239
|
}
|
|
@@ -15224,6 +15224,72 @@ function createMeetingTools(store) {
|
|
|
15224
15224
|
]
|
|
15225
15225
|
};
|
|
15226
15226
|
}
|
|
15227
|
+
),
|
|
15228
|
+
tool7(
|
|
15229
|
+
"analyze_meeting",
|
|
15230
|
+
"Analyze a meeting to identify decisions, actions, and questions. Returns the meeting content with existing project context so you can extract and create artifacts using the create_decision, create_action, and create_question tools.",
|
|
15231
|
+
{
|
|
15232
|
+
id: external_exports.string().describe("Meeting ID to analyze (e.g. 'M-001')"),
|
|
15233
|
+
include_context: external_exports.boolean().optional().describe("Include existing artifacts for dedup awareness (default: true)")
|
|
15234
|
+
},
|
|
15235
|
+
async (args) => {
|
|
15236
|
+
const doc = store.get(args.id);
|
|
15237
|
+
if (!doc) {
|
|
15238
|
+
return {
|
|
15239
|
+
content: [{ type: "text", text: `Meeting ${args.id} not found` }],
|
|
15240
|
+
isError: true
|
|
15241
|
+
};
|
|
15242
|
+
}
|
|
15243
|
+
if (doc.frontmatter.type !== "meeting") {
|
|
15244
|
+
return {
|
|
15245
|
+
content: [{ type: "text", text: `Document ${args.id} is not a meeting (type: ${doc.frontmatter.type})` }],
|
|
15246
|
+
isError: true
|
|
15247
|
+
};
|
|
15248
|
+
}
|
|
15249
|
+
const includeContext = args.include_context !== false;
|
|
15250
|
+
const sections = [];
|
|
15251
|
+
sections.push(`# Meeting: ${doc.frontmatter.title} (${args.id})`);
|
|
15252
|
+
sections.push(`**Status:** ${doc.frontmatter.status}`);
|
|
15253
|
+
sections.push(`**Date:** ${doc.frontmatter.date ?? doc.frontmatter.created}`);
|
|
15254
|
+
if (doc.frontmatter.attendees) {
|
|
15255
|
+
sections.push(`**Attendees:** ${doc.frontmatter.attendees.join(", ")}`);
|
|
15256
|
+
}
|
|
15257
|
+
sections.push("");
|
|
15258
|
+
sections.push(doc.content);
|
|
15259
|
+
if (includeContext) {
|
|
15260
|
+
const decisions = store.list({ type: "decision" });
|
|
15261
|
+
const actions = store.list({ type: "action" });
|
|
15262
|
+
const questions = store.list({ type: "question" });
|
|
15263
|
+
sections.push("\n---\n# Existing Artifacts (for dedup awareness)");
|
|
15264
|
+
if (decisions.length > 0) {
|
|
15265
|
+
sections.push("\n## Existing Decisions");
|
|
15266
|
+
for (const d of decisions) {
|
|
15267
|
+
sections.push(`- ${d.frontmatter.id}: ${d.frontmatter.title} [${d.frontmatter.status}]`);
|
|
15268
|
+
}
|
|
15269
|
+
}
|
|
15270
|
+
if (actions.length > 0) {
|
|
15271
|
+
sections.push("\n## Existing Actions");
|
|
15272
|
+
for (const a of actions) {
|
|
15273
|
+
sections.push(`- ${a.frontmatter.id}: ${a.frontmatter.title} [${a.frontmatter.status}]`);
|
|
15274
|
+
}
|
|
15275
|
+
}
|
|
15276
|
+
if (questions.length > 0) {
|
|
15277
|
+
sections.push("\n## Existing Questions");
|
|
15278
|
+
for (const q of questions) {
|
|
15279
|
+
sections.push(`- ${q.frontmatter.id}: ${q.frontmatter.title} [${q.frontmatter.status}]`);
|
|
15280
|
+
}
|
|
15281
|
+
}
|
|
15282
|
+
}
|
|
15283
|
+
sections.push("\n---\n# Instructions");
|
|
15284
|
+
sections.push(`Analyze this meeting and create artifacts using create_decision, create_action, and create_question tools.`);
|
|
15285
|
+
sections.push(`For each artifact, include the tag "source:${args.id}" for traceability.`);
|
|
15286
|
+
sections.push(`After creating artifacts, update the meeting using update_meeting to append an Outcomes section listing the created artifact IDs.`);
|
|
15287
|
+
sections.push(`Avoid creating duplicates of existing artifacts listed above.`);
|
|
15288
|
+
return {
|
|
15289
|
+
content: [{ type: "text", text: sections.join("\n") }]
|
|
15290
|
+
};
|
|
15291
|
+
},
|
|
15292
|
+
{ annotations: { readOnly: true } }
|
|
15227
15293
|
)
|
|
15228
15294
|
];
|
|
15229
15295
|
}
|
|
@@ -15822,6 +15888,7 @@ var genericAgilePlugin = {
|
|
|
15822
15888
|
- **list_meetings** / **get_meeting**: Browse and read meeting records.
|
|
15823
15889
|
- **create_meeting**: Record new meetings with attendees, date, and agenda.
|
|
15824
15890
|
- **update_meeting**: Update meeting status or notes after completion.
|
|
15891
|
+
- **analyze_meeting**: Analyze a meeting to review its outcomes and extract artifacts.
|
|
15825
15892
|
|
|
15826
15893
|
**Key Workflow Rules:**
|
|
15827
15894
|
- Create features as "draft" and approve them when requirements are clear and prioritized.
|
|
@@ -15842,6 +15909,7 @@ var genericAgilePlugin = {
|
|
|
15842
15909
|
- **list_meetings** / **get_meeting**: Browse and read meeting records.
|
|
15843
15910
|
- **create_meeting**: Record new meetings with attendees, date, and agenda.
|
|
15844
15911
|
- **update_meeting**: Update meeting status or notes after completion.
|
|
15912
|
+
- **analyze_meeting**: Analyze a meeting to review its outcomes and extract artifacts.
|
|
15845
15913
|
|
|
15846
15914
|
**Key Workflow Rules:**
|
|
15847
15915
|
- Only create epics against approved features \u2014 create_epic enforces this.
|
|
@@ -15869,11 +15937,13 @@ var genericAgilePlugin = {
|
|
|
15869
15937
|
- **list_meetings** / **get_meeting**: Browse and read meeting records.
|
|
15870
15938
|
- **create_meeting**: Record new meetings with attendees, date, and agenda.
|
|
15871
15939
|
- **update_meeting**: Update meeting status or notes after completion.
|
|
15940
|
+
- **analyze_meeting**: Analyze a completed meeting to extract decisions, actions, and questions. Use this to ensure meeting outcomes are properly tracked as governance artifacts.
|
|
15872
15941
|
|
|
15873
15942
|
**Key Workflow Rules:**
|
|
15874
15943
|
- After generating any report, offer to save it with save_report for audit trail.
|
|
15875
15944
|
- Proactively flag risks: unowned actions, overdue items, epics linked to deferred features.
|
|
15876
|
-
- Use feature progress reports for stakeholder updates and epic progress for sprint-level tracking
|
|
15945
|
+
- Use feature progress reports for stakeholder updates and epic progress for sprint-level tracking.
|
|
15946
|
+
- Use analyze_meeting after meetings to extract outcomes into governance artifacts.`,
|
|
15877
15947
|
"*": `You have access to feature, epic, and meeting tools for project coordination:
|
|
15878
15948
|
|
|
15879
15949
|
**Features** (F-xxx): Product capabilities defined by the Product Owner. Features progress through draft \u2192 approved \u2192 done.
|
|
@@ -15884,7 +15954,8 @@ var genericAgilePlugin = {
|
|
|
15884
15954
|
|
|
15885
15955
|
- **list_meetings** / **get_meeting**: Browse and read meeting records.
|
|
15886
15956
|
- **create_meeting**: Record meetings with attendees, date, and agenda.
|
|
15887
|
-
- **update_meeting**: Update meeting status or notes
|
|
15957
|
+
- **update_meeting**: Update meeting status or notes.
|
|
15958
|
+
- **analyze_meeting**: Analyze a meeting to extract decisions, actions, and questions as governance artifacts.`
|
|
15888
15959
|
}
|
|
15889
15960
|
};
|
|
15890
15961
|
|
|
@@ -17119,6 +17190,7 @@ Marvin \u2014 ${persona.name}
|
|
|
17119
17190
|
"mcp__marvin-governance__get_source_info",
|
|
17120
17191
|
"mcp__marvin-governance__list_sessions",
|
|
17121
17192
|
"mcp__marvin-governance__get_session",
|
|
17193
|
+
"mcp__marvin-governance__analyze_meeting",
|
|
17122
17194
|
...pluginTools.map((t) => `mcp__marvin-governance__${t.name}`),
|
|
17123
17195
|
...codeSkillTools.map((t) => `mcp__marvin-governance__${t.name}`),
|
|
17124
17196
|
...actionTools.map((t) => `mcp__marvin-governance__${t.name}`)
|
|
@@ -18928,6 +19000,263 @@ async function importCommand(inputPath, options) {
|
|
|
18928
19000
|
}
|
|
18929
19001
|
}
|
|
18930
19002
|
|
|
19003
|
+
// src/cli/commands/analyze.ts
|
|
19004
|
+
import chalk13 from "chalk";
|
|
19005
|
+
|
|
19006
|
+
// src/analysis/analyze.ts
|
|
19007
|
+
import chalk12 from "chalk";
|
|
19008
|
+
import ora4 from "ora";
|
|
19009
|
+
import { query as query5 } from "@anthropic-ai/claude-agent-sdk";
|
|
19010
|
+
|
|
19011
|
+
// src/analysis/prompts.ts
|
|
19012
|
+
function buildAnalyzeSystemPrompt(persona, projectConfig, isDraft) {
|
|
19013
|
+
const parts = [];
|
|
19014
|
+
parts.push(persona.systemPrompt);
|
|
19015
|
+
parts.push(`
|
|
19016
|
+
## Project Context
|
|
19017
|
+
- **Project Name:** ${projectConfig.name}
|
|
19018
|
+
- **Methodology:** ${projectConfig.methodology ?? "Generic Agile"}
|
|
19019
|
+
`);
|
|
19020
|
+
parts.push(`
|
|
19021
|
+
## Meeting Analysis Task
|
|
19022
|
+
You are analyzing a meeting record to extract governance artifacts for the project.
|
|
19023
|
+
Review the meeting content thoroughly and identify:
|
|
19024
|
+
|
|
19025
|
+
1. **Decisions** (D-xxx): Any decisions made during the meeting \u2014 architectural choices, process agreements, technology selections, or resolved discussion points.
|
|
19026
|
+
2. **Actions** (A-xxx): Tasks assigned, follow-ups agreed upon, work items to be done, or commitments made during the meeting.
|
|
19027
|
+
3. **Questions** (Q-xxx): Open questions raised, unresolved discussion points, items needing further investigation, or clarifications needed.
|
|
19028
|
+
|
|
19029
|
+
For each artifact, provide:
|
|
19030
|
+
- A clear, concise title
|
|
19031
|
+
- Detailed content with rationale or context from the meeting discussion
|
|
19032
|
+
- Appropriate status (decisions: "decided" or "open"; actions: "open"; questions: "open")
|
|
19033
|
+
- Relevant tags for categorization
|
|
19034
|
+
`);
|
|
19035
|
+
if (isDraft) {
|
|
19036
|
+
parts.push(`
|
|
19037
|
+
## Mode: Draft Proposal
|
|
19038
|
+
Present your findings as a structured proposal. Do NOT create any artifacts.
|
|
19039
|
+
Format your response as:
|
|
19040
|
+
|
|
19041
|
+
### Proposed Decisions
|
|
19042
|
+
For each decision:
|
|
19043
|
+
- **Title:** [title]
|
|
19044
|
+
- **Status:** [decided/open]
|
|
19045
|
+
- **Content:** [description and rationale from the meeting]
|
|
19046
|
+
- **Tags:** [comma-separated tags]
|
|
19047
|
+
|
|
19048
|
+
### Proposed Actions
|
|
19049
|
+
For each action:
|
|
19050
|
+
- **Title:** [title]
|
|
19051
|
+
- **Assignee:** [who was assigned, if mentioned]
|
|
19052
|
+
- **Content:** [what needs to be done]
|
|
19053
|
+
- **Tags:** [comma-separated tags]
|
|
19054
|
+
|
|
19055
|
+
### Proposed Questions
|
|
19056
|
+
For each question:
|
|
19057
|
+
- **Title:** [title]
|
|
19058
|
+
- **Content:** [what needs clarification and why]
|
|
19059
|
+
- **Tags:** [comma-separated tags]
|
|
19060
|
+
|
|
19061
|
+
### Summary
|
|
19062
|
+
Provide a brief summary of the meeting outcomes and any recommendations.
|
|
19063
|
+
`);
|
|
19064
|
+
} else {
|
|
19065
|
+
parts.push(`
|
|
19066
|
+
## Mode: Direct Creation
|
|
19067
|
+
Use the MCP tools to create artifacts directly:
|
|
19068
|
+
- Use \`create_decision\` for decisions
|
|
19069
|
+
- Use \`create_action\` for action items
|
|
19070
|
+
- Use \`create_question\` for questions
|
|
19071
|
+
|
|
19072
|
+
Before creating artifacts, check existing ones using the list tools to avoid duplicates.
|
|
19073
|
+
|
|
19074
|
+
For EVERY artifact you create, include:
|
|
19075
|
+
- A \`source:<meeting-id>\` tag in the tags array (the meeting ID is provided in the user prompt)
|
|
19076
|
+
- Clear title and detailed content with context from the meeting
|
|
19077
|
+
|
|
19078
|
+
After creating all artifacts, provide a summary of what was created.
|
|
19079
|
+
`);
|
|
19080
|
+
}
|
|
19081
|
+
return parts.join("\n");
|
|
19082
|
+
}
|
|
19083
|
+
function buildAnalyzeUserPrompt(meetingId, meetingContent, meetingTitle, isDraft) {
|
|
19084
|
+
const mode = isDraft ? "propose" : "create";
|
|
19085
|
+
return `Please analyze the following meeting record and ${mode} governance artifacts (decisions, actions, questions) based on its content.
|
|
19086
|
+
|
|
19087
|
+
**Meeting ID:** ${meetingId}
|
|
19088
|
+
**Meeting Title:** ${meetingTitle}
|
|
19089
|
+
|
|
19090
|
+
---
|
|
19091
|
+
${meetingContent}
|
|
19092
|
+
---
|
|
19093
|
+
|
|
19094
|
+
Analyze this meeting thoroughly and ${mode} all relevant governance artifacts. Tag each artifact with "source:${meetingId}" for traceability back to this meeting.`;
|
|
19095
|
+
}
|
|
19096
|
+
|
|
19097
|
+
// src/analysis/analyze.ts
|
|
19098
|
+
async function analyzeMeeting(options) {
|
|
19099
|
+
const { marvinDir, meetingId, draft, persona: personaInput } = options;
|
|
19100
|
+
const config2 = getConfig(marvinDir);
|
|
19101
|
+
const personaId = resolvePersonaId(personaInput);
|
|
19102
|
+
const persona = getPersona(personaId);
|
|
19103
|
+
const plugin = resolvePlugin(config2.project.methodology);
|
|
19104
|
+
const registrations = plugin?.documentTypeRegistrations ?? [];
|
|
19105
|
+
const store = new DocumentStore(marvinDir, registrations);
|
|
19106
|
+
const meetingDoc = store.get(meetingId);
|
|
19107
|
+
if (!meetingDoc) {
|
|
19108
|
+
throw new Error(`Meeting ${meetingId} not found`);
|
|
19109
|
+
}
|
|
19110
|
+
if (meetingDoc.frontmatter.type !== "meeting") {
|
|
19111
|
+
throw new Error(`Document ${meetingId} is not a meeting (type: ${meetingDoc.frontmatter.type})`);
|
|
19112
|
+
}
|
|
19113
|
+
const createdArtifacts = [];
|
|
19114
|
+
if (!draft) {
|
|
19115
|
+
const originalCreate = store.create.bind(store);
|
|
19116
|
+
store.create = (type, frontmatter, content) => {
|
|
19117
|
+
const tags = frontmatter.tags ?? [];
|
|
19118
|
+
const sourceTag = `source:${meetingId}`;
|
|
19119
|
+
if (!tags.includes(sourceTag)) {
|
|
19120
|
+
tags.push(sourceTag);
|
|
19121
|
+
}
|
|
19122
|
+
const doc = originalCreate(type, { ...frontmatter, source: meetingId, tags }, content);
|
|
19123
|
+
createdArtifacts.push(doc.frontmatter.id);
|
|
19124
|
+
return doc;
|
|
19125
|
+
};
|
|
19126
|
+
}
|
|
19127
|
+
const pluginTools = plugin ? getPluginTools(plugin, store, marvinDir) : [];
|
|
19128
|
+
const mcpServer = createMarvinMcpServer(store, { pluginTools });
|
|
19129
|
+
const systemPrompt = buildAnalyzeSystemPrompt(persona, config2.project, draft);
|
|
19130
|
+
const userPrompt = buildAnalyzeUserPrompt(
|
|
19131
|
+
meetingId,
|
|
19132
|
+
meetingDoc.content,
|
|
19133
|
+
meetingDoc.frontmatter.title,
|
|
19134
|
+
draft
|
|
19135
|
+
);
|
|
19136
|
+
const spinner = ora4({ text: `Analyzing meeting ${meetingId}...`, color: "cyan" });
|
|
19137
|
+
spinner.start();
|
|
19138
|
+
try {
|
|
19139
|
+
const conversation = query5({
|
|
19140
|
+
prompt: userPrompt,
|
|
19141
|
+
options: {
|
|
19142
|
+
systemPrompt,
|
|
19143
|
+
mcpServers: { "marvin-governance": mcpServer },
|
|
19144
|
+
permissionMode: "acceptEdits",
|
|
19145
|
+
maxTurns: 10,
|
|
19146
|
+
tools: [],
|
|
19147
|
+
allowedTools: [
|
|
19148
|
+
"mcp__marvin-governance__create_decision",
|
|
19149
|
+
"mcp__marvin-governance__create_action",
|
|
19150
|
+
"mcp__marvin-governance__create_question",
|
|
19151
|
+
"mcp__marvin-governance__list_decisions",
|
|
19152
|
+
"mcp__marvin-governance__list_actions",
|
|
19153
|
+
"mcp__marvin-governance__list_questions"
|
|
19154
|
+
]
|
|
19155
|
+
}
|
|
19156
|
+
});
|
|
19157
|
+
for await (const message of conversation) {
|
|
19158
|
+
handleAnalyzeMessage(message, spinner);
|
|
19159
|
+
}
|
|
19160
|
+
if (!draft && createdArtifacts.length > 0) {
|
|
19161
|
+
appendOutcomesToMeeting(store, meetingDoc.frontmatter.id, meetingDoc.content, createdArtifacts, store);
|
|
19162
|
+
}
|
|
19163
|
+
spinner.stop();
|
|
19164
|
+
if (draft) {
|
|
19165
|
+
console.log(chalk12.dim(`
|
|
19166
|
+
Draft proposal complete. No artifacts were created.`));
|
|
19167
|
+
console.log(chalk12.dim(`Use "marvin analyze ${meetingId} --no-draft" to create artifacts.`));
|
|
19168
|
+
} else {
|
|
19169
|
+
console.log(chalk12.green(`
|
|
19170
|
+
Created ${createdArtifacts.length} artifact${createdArtifacts.length === 1 ? "" : "s"} from meeting ${meetingId}`));
|
|
19171
|
+
if (createdArtifacts.length > 0) {
|
|
19172
|
+
console.log(chalk12.dim(` ${createdArtifacts.join(", ")}`));
|
|
19173
|
+
}
|
|
19174
|
+
}
|
|
19175
|
+
return { meetingId, artifacts: createdArtifacts, draft };
|
|
19176
|
+
} catch (err) {
|
|
19177
|
+
spinner.stop();
|
|
19178
|
+
throw err;
|
|
19179
|
+
}
|
|
19180
|
+
}
|
|
19181
|
+
function appendOutcomesToMeeting(store, meetingId, existingContent, artifacts, storeInstance) {
|
|
19182
|
+
const outcomeLines = artifacts.map((id) => {
|
|
19183
|
+
const doc = storeInstance.get(id);
|
|
19184
|
+
const title = doc ? doc.frontmatter.title : id;
|
|
19185
|
+
return `- ${id}: ${title}`;
|
|
19186
|
+
});
|
|
19187
|
+
const outcomesSection = `
|
|
19188
|
+
|
|
19189
|
+
## Outcomes
|
|
19190
|
+
${outcomeLines.join("\n")}`;
|
|
19191
|
+
const updatedContent = existingContent + outcomesSection;
|
|
19192
|
+
store.update(meetingId, {}, updatedContent);
|
|
19193
|
+
}
|
|
19194
|
+
function handleAnalyzeMessage(message, spinner) {
|
|
19195
|
+
switch (message.type) {
|
|
19196
|
+
case "assistant": {
|
|
19197
|
+
spinner.stop();
|
|
19198
|
+
const textBlocks = message.message.content.filter(
|
|
19199
|
+
(b) => b.type === "text"
|
|
19200
|
+
);
|
|
19201
|
+
if (textBlocks.length > 0) {
|
|
19202
|
+
console.log(
|
|
19203
|
+
chalk12.cyan("\nMarvin: ") + textBlocks.map((b) => b.text).join("\n")
|
|
19204
|
+
);
|
|
19205
|
+
}
|
|
19206
|
+
break;
|
|
19207
|
+
}
|
|
19208
|
+
case "system": {
|
|
19209
|
+
if (message.subtype === "init") {
|
|
19210
|
+
spinner.start("Analyzing...");
|
|
19211
|
+
}
|
|
19212
|
+
break;
|
|
19213
|
+
}
|
|
19214
|
+
case "result": {
|
|
19215
|
+
spinner.stop();
|
|
19216
|
+
if (message.subtype !== "success") {
|
|
19217
|
+
console.log(
|
|
19218
|
+
chalk12.red(`
|
|
19219
|
+
Analysis ended with error: ${message.subtype}`)
|
|
19220
|
+
);
|
|
19221
|
+
}
|
|
19222
|
+
break;
|
|
19223
|
+
}
|
|
19224
|
+
}
|
|
19225
|
+
}
|
|
19226
|
+
|
|
19227
|
+
// src/cli/commands/analyze.ts
|
|
19228
|
+
async function analyzeCommand(meetingId, options) {
|
|
19229
|
+
const project = loadProject();
|
|
19230
|
+
const marvinDir = project.marvinDir;
|
|
19231
|
+
const config2 = getConfig(marvinDir);
|
|
19232
|
+
const plugin = resolvePlugin(config2.project.methodology);
|
|
19233
|
+
const registrations = plugin?.documentTypeRegistrations ?? [];
|
|
19234
|
+
const store = new DocumentStore(marvinDir, registrations);
|
|
19235
|
+
const meetingDoc = store.get(meetingId);
|
|
19236
|
+
if (!meetingDoc) {
|
|
19237
|
+
console.log(chalk13.red(`Meeting ${meetingId} not found.`));
|
|
19238
|
+
console.log(chalk13.dim(`Use "marvin chat --as dm" to create meetings, or check the ID.`));
|
|
19239
|
+
return;
|
|
19240
|
+
}
|
|
19241
|
+
if (meetingDoc.frontmatter.type !== "meeting") {
|
|
19242
|
+
console.log(chalk13.red(`Document ${meetingId} is not a meeting (type: ${meetingDoc.frontmatter.type}).`));
|
|
19243
|
+
return;
|
|
19244
|
+
}
|
|
19245
|
+
const isDraft = options.draft !== false;
|
|
19246
|
+
const persona = options.as ?? "delivery-manager";
|
|
19247
|
+
console.log(chalk13.bold(`
|
|
19248
|
+
Analyzing meeting: ${meetingDoc.frontmatter.title}`));
|
|
19249
|
+
console.log(chalk13.dim(`Mode: ${isDraft ? "draft (propose only)" : "direct (create artifacts)"}`));
|
|
19250
|
+
console.log(chalk13.dim(`Persona: ${persona}
|
|
19251
|
+
`));
|
|
19252
|
+
await analyzeMeeting({
|
|
19253
|
+
marvinDir,
|
|
19254
|
+
meetingId,
|
|
19255
|
+
draft: isDraft,
|
|
19256
|
+
persona
|
|
19257
|
+
});
|
|
19258
|
+
}
|
|
19259
|
+
|
|
18931
19260
|
// src/cli/program.ts
|
|
18932
19261
|
function createProgram() {
|
|
18933
19262
|
const program = new Command();
|
|
@@ -18973,6 +19302,9 @@ function createProgram() {
|
|
|
18973
19302
|
program.command("clone <url> [directory]").description("Clone governance data from a remote repository").action(async (url2, directory) => {
|
|
18974
19303
|
await cloneCommand(url2, directory);
|
|
18975
19304
|
});
|
|
19305
|
+
program.command("analyze <meeting-id>").description("Analyze a meeting to extract decisions, actions, and questions").option("--draft", "Propose artifacts without creating them (default)").option("--no-draft", "Create artifacts directly via MCP tools").option("--as <persona>", "Persona for analysis (default: delivery-manager)").action(async (meetingId, options) => {
|
|
19306
|
+
await analyzeCommand(meetingId, options);
|
|
19307
|
+
});
|
|
18976
19308
|
program.command("import <path>").description("Import documents or sources from external paths").option("--dry-run", "Preview without writing files").option(
|
|
18977
19309
|
"--conflict <strategy>",
|
|
18978
19310
|
"ID conflict strategy: renumber, skip, overwrite (default: renumber)"
|