mrvn-cli 0.2.2 → 0.2.4
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.d.ts +1 -0
- package/dist/index.js +599 -43
- package/dist/index.js.map +1 -1
- package/dist/marvin-serve.js +185 -37
- package/dist/marvin-serve.js.map +1 -1
- package/dist/marvin.js +624 -68
- package/dist/marvin.js.map +1 -1
- package/package.json +1 -1
package/dist/marvin.js
CHANGED
|
@@ -14656,19 +14656,141 @@ function createEpicTools(store) {
|
|
|
14656
14656
|
];
|
|
14657
14657
|
}
|
|
14658
14658
|
|
|
14659
|
+
// src/plugins/builtin/tools/contributions.ts
|
|
14660
|
+
import { tool as tool5 } from "@anthropic-ai/claude-agent-sdk";
|
|
14661
|
+
function createContributionTools(store) {
|
|
14662
|
+
return [
|
|
14663
|
+
tool5(
|
|
14664
|
+
"list_contributions",
|
|
14665
|
+
"List all contributions in the project, optionally filtered by persona, contribution type, or status",
|
|
14666
|
+
{
|
|
14667
|
+
persona: external_exports.string().optional().describe("Filter by persona (e.g. 'tech-lead', 'product-owner')"),
|
|
14668
|
+
contributionType: external_exports.string().optional().describe("Filter by contribution type (e.g. 'action-result', 'risk-finding')"),
|
|
14669
|
+
status: external_exports.string().optional().describe("Filter by status")
|
|
14670
|
+
},
|
|
14671
|
+
async (args) => {
|
|
14672
|
+
let docs = store.list({ type: "contribution", status: args.status });
|
|
14673
|
+
if (args.persona) {
|
|
14674
|
+
docs = docs.filter((d) => d.frontmatter.persona === args.persona);
|
|
14675
|
+
}
|
|
14676
|
+
if (args.contributionType) {
|
|
14677
|
+
docs = docs.filter((d) => d.frontmatter.contributionType === args.contributionType);
|
|
14678
|
+
}
|
|
14679
|
+
const summary = docs.map((d) => ({
|
|
14680
|
+
id: d.frontmatter.id,
|
|
14681
|
+
title: d.frontmatter.title,
|
|
14682
|
+
status: d.frontmatter.status,
|
|
14683
|
+
persona: d.frontmatter.persona,
|
|
14684
|
+
contributionType: d.frontmatter.contributionType,
|
|
14685
|
+
aboutArtifact: d.frontmatter.aboutArtifact,
|
|
14686
|
+
created: d.frontmatter.created,
|
|
14687
|
+
tags: d.frontmatter.tags
|
|
14688
|
+
}));
|
|
14689
|
+
return {
|
|
14690
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
|
|
14691
|
+
};
|
|
14692
|
+
},
|
|
14693
|
+
{ annotations: { readOnly: true } }
|
|
14694
|
+
),
|
|
14695
|
+
tool5(
|
|
14696
|
+
"get_contribution",
|
|
14697
|
+
"Get the full content of a specific contribution by ID",
|
|
14698
|
+
{ id: external_exports.string().describe("Contribution ID (e.g. 'C-001')") },
|
|
14699
|
+
async (args) => {
|
|
14700
|
+
const doc = store.get(args.id);
|
|
14701
|
+
if (!doc) {
|
|
14702
|
+
return {
|
|
14703
|
+
content: [{ type: "text", text: `Contribution ${args.id} not found` }],
|
|
14704
|
+
isError: true
|
|
14705
|
+
};
|
|
14706
|
+
}
|
|
14707
|
+
return {
|
|
14708
|
+
content: [
|
|
14709
|
+
{
|
|
14710
|
+
type: "text",
|
|
14711
|
+
text: JSON.stringify(
|
|
14712
|
+
{ ...doc.frontmatter, content: doc.content },
|
|
14713
|
+
null,
|
|
14714
|
+
2
|
|
14715
|
+
)
|
|
14716
|
+
}
|
|
14717
|
+
]
|
|
14718
|
+
};
|
|
14719
|
+
},
|
|
14720
|
+
{ annotations: { readOnly: true } }
|
|
14721
|
+
),
|
|
14722
|
+
tool5(
|
|
14723
|
+
"create_contribution",
|
|
14724
|
+
"Create a new contribution record from a persona",
|
|
14725
|
+
{
|
|
14726
|
+
title: external_exports.string().describe("Title of the contribution"),
|
|
14727
|
+
content: external_exports.string().describe("Contribution content \u2014 the input from the persona"),
|
|
14728
|
+
persona: external_exports.string().describe("Persona making the contribution (e.g. 'tech-lead')"),
|
|
14729
|
+
contributionType: external_exports.string().describe("Type of contribution (e.g. 'action-result', 'risk-finding')"),
|
|
14730
|
+
aboutArtifact: external_exports.string().optional().describe("Artifact ID this contribution relates to (e.g. 'A-001')"),
|
|
14731
|
+
status: external_exports.string().optional().describe("Status (default: 'open')"),
|
|
14732
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization")
|
|
14733
|
+
},
|
|
14734
|
+
async (args) => {
|
|
14735
|
+
const frontmatter = {
|
|
14736
|
+
title: args.title,
|
|
14737
|
+
status: args.status ?? "open",
|
|
14738
|
+
persona: args.persona,
|
|
14739
|
+
contributionType: args.contributionType
|
|
14740
|
+
};
|
|
14741
|
+
if (args.aboutArtifact) frontmatter.aboutArtifact = args.aboutArtifact;
|
|
14742
|
+
if (args.tags) frontmatter.tags = args.tags;
|
|
14743
|
+
const doc = store.create("contribution", frontmatter, args.content);
|
|
14744
|
+
return {
|
|
14745
|
+
content: [
|
|
14746
|
+
{
|
|
14747
|
+
type: "text",
|
|
14748
|
+
text: `Created contribution ${doc.frontmatter.id}: ${doc.frontmatter.title}`
|
|
14749
|
+
}
|
|
14750
|
+
]
|
|
14751
|
+
};
|
|
14752
|
+
}
|
|
14753
|
+
),
|
|
14754
|
+
tool5(
|
|
14755
|
+
"update_contribution",
|
|
14756
|
+
"Update an existing contribution (e.g. to append an Effects section)",
|
|
14757
|
+
{
|
|
14758
|
+
id: external_exports.string().describe("Contribution ID to update"),
|
|
14759
|
+
title: external_exports.string().optional().describe("New title"),
|
|
14760
|
+
status: external_exports.string().optional().describe("New status"),
|
|
14761
|
+
content: external_exports.string().optional().describe("New content")
|
|
14762
|
+
},
|
|
14763
|
+
async (args) => {
|
|
14764
|
+
const { id, content, ...updates } = args;
|
|
14765
|
+
const doc = store.update(id, updates, content);
|
|
14766
|
+
return {
|
|
14767
|
+
content: [
|
|
14768
|
+
{
|
|
14769
|
+
type: "text",
|
|
14770
|
+
text: `Updated contribution ${doc.frontmatter.id}: ${doc.frontmatter.title}`
|
|
14771
|
+
}
|
|
14772
|
+
]
|
|
14773
|
+
};
|
|
14774
|
+
}
|
|
14775
|
+
)
|
|
14776
|
+
];
|
|
14777
|
+
}
|
|
14778
|
+
|
|
14659
14779
|
// src/plugins/common.ts
|
|
14660
14780
|
var COMMON_REGISTRATIONS = [
|
|
14661
14781
|
{ type: "meeting", dirName: "meetings", idPrefix: "M" },
|
|
14662
14782
|
{ type: "report", dirName: "reports", idPrefix: "R" },
|
|
14663
14783
|
{ type: "feature", dirName: "features", idPrefix: "F" },
|
|
14664
|
-
{ type: "epic", dirName: "epics", idPrefix: "E" }
|
|
14784
|
+
{ type: "epic", dirName: "epics", idPrefix: "E" },
|
|
14785
|
+
{ type: "contribution", dirName: "contributions", idPrefix: "C" }
|
|
14665
14786
|
];
|
|
14666
14787
|
function createCommonTools(store) {
|
|
14667
14788
|
return [
|
|
14668
14789
|
...createMeetingTools(store),
|
|
14669
14790
|
...createReportTools(store),
|
|
14670
14791
|
...createFeatureTools(store),
|
|
14671
|
-
...createEpicTools(store)
|
|
14792
|
+
...createEpicTools(store),
|
|
14793
|
+
...createContributionTools(store)
|
|
14672
14794
|
];
|
|
14673
14795
|
}
|
|
14674
14796
|
|
|
@@ -14678,7 +14800,7 @@ var genericAgilePlugin = {
|
|
|
14678
14800
|
name: "Generic Agile",
|
|
14679
14801
|
description: "Default methodology plugin providing standard agile governance patterns for decisions, actions, and questions.",
|
|
14680
14802
|
version: "0.1.0",
|
|
14681
|
-
documentTypes: ["decision", "action", "question", "meeting", "report", "feature", "epic"],
|
|
14803
|
+
documentTypes: ["decision", "action", "question", "meeting", "report", "feature", "epic", "contribution"],
|
|
14682
14804
|
documentTypeRegistrations: [...COMMON_REGISTRATIONS],
|
|
14683
14805
|
tools: (store) => [...createCommonTools(store)],
|
|
14684
14806
|
promptFragments: {
|
|
@@ -14699,7 +14821,13 @@ var genericAgilePlugin = {
|
|
|
14699
14821
|
- Create features as "draft" and approve them when requirements are clear and prioritized.
|
|
14700
14822
|
- Do NOT create epics \u2014 that is the Tech Lead's responsibility. You can view epics to track progress.
|
|
14701
14823
|
- Use priority levels (critical, high, medium, low) to communicate business value.
|
|
14702
|
-
- Tag features for categorization and cross-referencing
|
|
14824
|
+
- Tag features for categorization and cross-referencing.
|
|
14825
|
+
|
|
14826
|
+
**Contribution Tools:**
|
|
14827
|
+
- **list_contributions** / **get_contribution**: Browse and read contribution records.
|
|
14828
|
+
- **create_contribution**: Record a contribution with persona, type, and optional related artifact.
|
|
14829
|
+
- **update_contribution**: Update a contribution (e.g. append effects).
|
|
14830
|
+
- Available contribution types: stakeholder-feedback, acceptance-result, priority-change, market-insight.`,
|
|
14703
14831
|
"tech-lead": `You own epics and break approved features into implementation work.
|
|
14704
14832
|
|
|
14705
14833
|
**Epic Tools:**
|
|
@@ -14720,7 +14848,13 @@ var genericAgilePlugin = {
|
|
|
14720
14848
|
- Only create epics against approved features \u2014 create_epic enforces this.
|
|
14721
14849
|
- Tag work items (actions, decisions, questions) with \`epic:E-xxx\` to group them under an epic.
|
|
14722
14850
|
- Collaborate with the Delivery Manager on target dates and effort estimates.
|
|
14723
|
-
- Each epic should have a clear scope and definition of done
|
|
14851
|
+
- Each epic should have a clear scope and definition of done.
|
|
14852
|
+
|
|
14853
|
+
**Contribution Tools:**
|
|
14854
|
+
- **list_contributions** / **get_contribution**: Browse and read contribution records.
|
|
14855
|
+
- **create_contribution**: Record a contribution with persona, type, and optional related artifact.
|
|
14856
|
+
- **update_contribution**: Update a contribution (e.g. append effects).
|
|
14857
|
+
- Available contribution types: action-result, spike-findings, technical-assessment, architecture-review.`,
|
|
14724
14858
|
"delivery-manager": `You track delivery across features and epics, manage schedules, and report on progress.
|
|
14725
14859
|
|
|
14726
14860
|
**Report Tools:**
|
|
@@ -14748,7 +14882,13 @@ var genericAgilePlugin = {
|
|
|
14748
14882
|
- After generating any report, offer to save it with save_report for audit trail.
|
|
14749
14883
|
- Proactively flag risks: unowned actions, overdue items, epics linked to deferred features.
|
|
14750
14884
|
- Use feature progress reports for stakeholder updates and epic progress for sprint-level tracking.
|
|
14751
|
-
- Use analyze_meeting after meetings to extract outcomes into governance artifacts
|
|
14885
|
+
- Use analyze_meeting after meetings to extract outcomes into governance artifacts.
|
|
14886
|
+
|
|
14887
|
+
**Contribution Tools:**
|
|
14888
|
+
- **list_contributions** / **get_contribution**: Browse and read contribution records.
|
|
14889
|
+
- **create_contribution**: Record a contribution with persona, type, and optional related artifact.
|
|
14890
|
+
- **update_contribution**: Update a contribution (e.g. append effects).
|
|
14891
|
+
- Available contribution types: risk-finding, blocker-report, dependency-update, status-assessment.`,
|
|
14752
14892
|
"*": `You have access to feature, epic, and meeting tools for project coordination:
|
|
14753
14893
|
|
|
14754
14894
|
**Features** (F-xxx): Product capabilities defined by the Product Owner. Features progress through draft \u2192 approved \u2192 done.
|
|
@@ -14760,15 +14900,20 @@ var genericAgilePlugin = {
|
|
|
14760
14900
|
- **list_meetings** / **get_meeting**: Browse and read meeting records.
|
|
14761
14901
|
- **create_meeting**: Record meetings with attendees, date, and agenda. The meeting date is required \u2014 extract it from the meeting content or ask the user if not found.
|
|
14762
14902
|
- **update_meeting**: Update meeting status or notes.
|
|
14763
|
-
- **analyze_meeting**: Analyze a meeting to extract decisions, actions, and questions as governance artifacts
|
|
14903
|
+
- **analyze_meeting**: Analyze a meeting to extract decisions, actions, and questions as governance artifacts.
|
|
14904
|
+
|
|
14905
|
+
**Contributions** (C-xxx): Structured inputs from personas outside of meetings (e.g. action results, risk findings, stakeholder feedback). Contributions are analyzed to produce governance effects.
|
|
14906
|
+
- **list_contributions** / **get_contribution**: Browse and read contribution records.
|
|
14907
|
+
- **create_contribution**: Record a contribution with persona, type, and optional related artifact.
|
|
14908
|
+
- **update_contribution**: Update a contribution (e.g. append effects).`
|
|
14764
14909
|
}
|
|
14765
14910
|
};
|
|
14766
14911
|
|
|
14767
14912
|
// src/plugins/builtin/tools/use-cases.ts
|
|
14768
|
-
import { tool as
|
|
14913
|
+
import { tool as tool6 } from "@anthropic-ai/claude-agent-sdk";
|
|
14769
14914
|
function createUseCaseTools(store) {
|
|
14770
14915
|
return [
|
|
14771
|
-
|
|
14916
|
+
tool6(
|
|
14772
14917
|
"list_use_cases",
|
|
14773
14918
|
"List all extension use cases, optionally filtered by status or extension type",
|
|
14774
14919
|
{
|
|
@@ -14798,7 +14943,7 @@ function createUseCaseTools(store) {
|
|
|
14798
14943
|
},
|
|
14799
14944
|
{ annotations: { readOnly: true } }
|
|
14800
14945
|
),
|
|
14801
|
-
|
|
14946
|
+
tool6(
|
|
14802
14947
|
"get_use_case",
|
|
14803
14948
|
"Get the full content of a specific use case by ID",
|
|
14804
14949
|
{ id: external_exports.string().describe("Use case ID (e.g. 'UC-001')") },
|
|
@@ -14825,7 +14970,7 @@ function createUseCaseTools(store) {
|
|
|
14825
14970
|
},
|
|
14826
14971
|
{ annotations: { readOnly: true } }
|
|
14827
14972
|
),
|
|
14828
|
-
|
|
14973
|
+
tool6(
|
|
14829
14974
|
"create_use_case",
|
|
14830
14975
|
"Create a new extension use case definition (Phase 1: Assess Extension Use Case)",
|
|
14831
14976
|
{
|
|
@@ -14859,7 +15004,7 @@ function createUseCaseTools(store) {
|
|
|
14859
15004
|
};
|
|
14860
15005
|
}
|
|
14861
15006
|
),
|
|
14862
|
-
|
|
15007
|
+
tool6(
|
|
14863
15008
|
"update_use_case",
|
|
14864
15009
|
"Update an existing extension use case",
|
|
14865
15010
|
{
|
|
@@ -14889,10 +15034,10 @@ function createUseCaseTools(store) {
|
|
|
14889
15034
|
}
|
|
14890
15035
|
|
|
14891
15036
|
// src/plugins/builtin/tools/tech-assessments.ts
|
|
14892
|
-
import { tool as
|
|
15037
|
+
import { tool as tool7 } from "@anthropic-ai/claude-agent-sdk";
|
|
14893
15038
|
function createTechAssessmentTools(store) {
|
|
14894
15039
|
return [
|
|
14895
|
-
|
|
15040
|
+
tool7(
|
|
14896
15041
|
"list_tech_assessments",
|
|
14897
15042
|
"List all technology assessments, optionally filtered by status",
|
|
14898
15043
|
{
|
|
@@ -14923,7 +15068,7 @@ function createTechAssessmentTools(store) {
|
|
|
14923
15068
|
},
|
|
14924
15069
|
{ annotations: { readOnly: true } }
|
|
14925
15070
|
),
|
|
14926
|
-
|
|
15071
|
+
tool7(
|
|
14927
15072
|
"get_tech_assessment",
|
|
14928
15073
|
"Get the full content of a specific technology assessment by ID",
|
|
14929
15074
|
{ id: external_exports.string().describe("Tech assessment ID (e.g. 'TA-001')") },
|
|
@@ -14950,7 +15095,7 @@ function createTechAssessmentTools(store) {
|
|
|
14950
15095
|
},
|
|
14951
15096
|
{ annotations: { readOnly: true } }
|
|
14952
15097
|
),
|
|
14953
|
-
|
|
15098
|
+
tool7(
|
|
14954
15099
|
"create_tech_assessment",
|
|
14955
15100
|
"Create a new technology assessment linked to an assessed/approved use case (Phase 2: Assess Extension Technology)",
|
|
14956
15101
|
{
|
|
@@ -15021,7 +15166,7 @@ function createTechAssessmentTools(store) {
|
|
|
15021
15166
|
};
|
|
15022
15167
|
}
|
|
15023
15168
|
),
|
|
15024
|
-
|
|
15169
|
+
tool7(
|
|
15025
15170
|
"update_tech_assessment",
|
|
15026
15171
|
"Update an existing technology assessment. The linked use case cannot be changed.",
|
|
15027
15172
|
{
|
|
@@ -15051,10 +15196,10 @@ function createTechAssessmentTools(store) {
|
|
|
15051
15196
|
}
|
|
15052
15197
|
|
|
15053
15198
|
// src/plugins/builtin/tools/extension-designs.ts
|
|
15054
|
-
import { tool as
|
|
15199
|
+
import { tool as tool8 } from "@anthropic-ai/claude-agent-sdk";
|
|
15055
15200
|
function createExtensionDesignTools(store) {
|
|
15056
15201
|
return [
|
|
15057
|
-
|
|
15202
|
+
tool8(
|
|
15058
15203
|
"list_extension_designs",
|
|
15059
15204
|
"List all extension designs, optionally filtered by status",
|
|
15060
15205
|
{
|
|
@@ -15084,7 +15229,7 @@ function createExtensionDesignTools(store) {
|
|
|
15084
15229
|
},
|
|
15085
15230
|
{ annotations: { readOnly: true } }
|
|
15086
15231
|
),
|
|
15087
|
-
|
|
15232
|
+
tool8(
|
|
15088
15233
|
"get_extension_design",
|
|
15089
15234
|
"Get the full content of a specific extension design by ID",
|
|
15090
15235
|
{ id: external_exports.string().describe("Extension design ID (e.g. 'XD-001')") },
|
|
@@ -15111,7 +15256,7 @@ function createExtensionDesignTools(store) {
|
|
|
15111
15256
|
},
|
|
15112
15257
|
{ annotations: { readOnly: true } }
|
|
15113
15258
|
),
|
|
15114
|
-
|
|
15259
|
+
tool8(
|
|
15115
15260
|
"create_extension_design",
|
|
15116
15261
|
"Create a new extension design linked to a recommended tech assessment (Phase 3: Define Extension Target Solution)",
|
|
15117
15262
|
{
|
|
@@ -15179,7 +15324,7 @@ function createExtensionDesignTools(store) {
|
|
|
15179
15324
|
};
|
|
15180
15325
|
}
|
|
15181
15326
|
),
|
|
15182
|
-
|
|
15327
|
+
tool8(
|
|
15183
15328
|
"update_extension_design",
|
|
15184
15329
|
"Update an existing extension design. The linked tech assessment cannot be changed.",
|
|
15185
15330
|
{
|
|
@@ -15208,10 +15353,10 @@ function createExtensionDesignTools(store) {
|
|
|
15208
15353
|
}
|
|
15209
15354
|
|
|
15210
15355
|
// src/plugins/builtin/tools/aem-reports.ts
|
|
15211
|
-
import { tool as
|
|
15356
|
+
import { tool as tool9 } from "@anthropic-ai/claude-agent-sdk";
|
|
15212
15357
|
function createAemReportTools(store) {
|
|
15213
15358
|
return [
|
|
15214
|
-
|
|
15359
|
+
tool9(
|
|
15215
15360
|
"generate_extension_portfolio",
|
|
15216
15361
|
"Generate a portfolio view of all use cases with their linked tech assessments and extension designs",
|
|
15217
15362
|
{},
|
|
@@ -15263,7 +15408,7 @@ function createAemReportTools(store) {
|
|
|
15263
15408
|
},
|
|
15264
15409
|
{ annotations: { readOnly: true } }
|
|
15265
15410
|
),
|
|
15266
|
-
|
|
15411
|
+
tool9(
|
|
15267
15412
|
"generate_tech_readiness",
|
|
15268
15413
|
"Generate a BTP technology readiness report showing service coverage and gaps across assessments",
|
|
15269
15414
|
{},
|
|
@@ -15315,7 +15460,7 @@ function createAemReportTools(store) {
|
|
|
15315
15460
|
},
|
|
15316
15461
|
{ annotations: { readOnly: true } }
|
|
15317
15462
|
),
|
|
15318
|
-
|
|
15463
|
+
tool9(
|
|
15319
15464
|
"generate_phase_status",
|
|
15320
15465
|
"Generate a phase progress report showing artifact counts and readiness per AEM phase",
|
|
15321
15466
|
{},
|
|
@@ -15377,11 +15522,11 @@ function createAemReportTools(store) {
|
|
|
15377
15522
|
import * as fs3 from "fs";
|
|
15378
15523
|
import * as path3 from "path";
|
|
15379
15524
|
import * as YAML2 from "yaml";
|
|
15380
|
-
import { tool as
|
|
15525
|
+
import { tool as tool10 } from "@anthropic-ai/claude-agent-sdk";
|
|
15381
15526
|
var PHASES = ["assess-use-case", "assess-technology", "define-solution"];
|
|
15382
15527
|
function createAemPhaseTools(store, marvinDir) {
|
|
15383
15528
|
return [
|
|
15384
|
-
|
|
15529
|
+
tool10(
|
|
15385
15530
|
"get_current_phase",
|
|
15386
15531
|
"Get the current AEM phase from project configuration",
|
|
15387
15532
|
{},
|
|
@@ -15402,7 +15547,7 @@ function createAemPhaseTools(store, marvinDir) {
|
|
|
15402
15547
|
},
|
|
15403
15548
|
{ annotations: { readOnly: true } }
|
|
15404
15549
|
),
|
|
15405
|
-
|
|
15550
|
+
tool10(
|
|
15406
15551
|
"advance_phase",
|
|
15407
15552
|
"Advance to the next AEM phase. Performs soft gate checks and warns if artifacts are incomplete, but does not block.",
|
|
15408
15553
|
{
|
|
@@ -15813,7 +15958,8 @@ var productOwner = {
|
|
|
15813
15958
|
"Acceptance criteria",
|
|
15814
15959
|
"Feature definition and prioritization"
|
|
15815
15960
|
],
|
|
15816
|
-
documentTypes: ["decision", "question", "action", "feature"]
|
|
15961
|
+
documentTypes: ["decision", "question", "action", "feature"],
|
|
15962
|
+
contributionTypes: ["stakeholder-feedback", "acceptance-result", "priority-change", "market-insight"]
|
|
15817
15963
|
};
|
|
15818
15964
|
|
|
15819
15965
|
// src/personas/builtin/delivery-manager.ts
|
|
@@ -15851,7 +15997,8 @@ var deliveryManager = {
|
|
|
15851
15997
|
"Status tracking",
|
|
15852
15998
|
"Epic scheduling and tracking"
|
|
15853
15999
|
],
|
|
15854
|
-
documentTypes: ["action", "decision", "meeting", "question", "feature", "epic"]
|
|
16000
|
+
documentTypes: ["action", "decision", "meeting", "question", "feature", "epic"],
|
|
16001
|
+
contributionTypes: ["risk-finding", "blocker-report", "dependency-update", "status-assessment"]
|
|
15855
16002
|
};
|
|
15856
16003
|
|
|
15857
16004
|
// src/personas/builtin/tech-lead.ts
|
|
@@ -15889,7 +16036,8 @@ var techLead = {
|
|
|
15889
16036
|
"Non-functional requirements",
|
|
15890
16037
|
"Epic creation and scoping"
|
|
15891
16038
|
],
|
|
15892
|
-
documentTypes: ["decision", "action", "question", "epic"]
|
|
16039
|
+
documentTypes: ["decision", "action", "question", "epic"],
|
|
16040
|
+
contributionTypes: ["action-result", "spike-findings", "technical-assessment", "architecture-review"]
|
|
15893
16041
|
};
|
|
15894
16042
|
|
|
15895
16043
|
// src/personas/registry.ts
|
|
@@ -16046,9 +16194,9 @@ var DocumentStore = class {
|
|
|
16046
16194
|
}
|
|
16047
16195
|
}
|
|
16048
16196
|
}
|
|
16049
|
-
list(
|
|
16197
|
+
list(query7) {
|
|
16050
16198
|
const results = [];
|
|
16051
|
-
const types =
|
|
16199
|
+
const types = query7?.type ? [query7.type] : Object.keys(this.typeDirs);
|
|
16052
16200
|
for (const type of types) {
|
|
16053
16201
|
const dirName = this.typeDirs[type];
|
|
16054
16202
|
if (!dirName) continue;
|
|
@@ -16059,9 +16207,9 @@ var DocumentStore = class {
|
|
|
16059
16207
|
const filePath = path5.join(dir, file2);
|
|
16060
16208
|
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
16061
16209
|
const doc = parseDocument(raw, filePath);
|
|
16062
|
-
if (
|
|
16063
|
-
if (
|
|
16064
|
-
if (
|
|
16210
|
+
if (query7?.status && doc.frontmatter.status !== query7.status) continue;
|
|
16211
|
+
if (query7?.owner && doc.frontmatter.owner !== query7.owner) continue;
|
|
16212
|
+
if (query7?.tag && (!doc.frontmatter.tags || !doc.frontmatter.tags.includes(query7.tag)))
|
|
16065
16213
|
continue;
|
|
16066
16214
|
results.push(doc);
|
|
16067
16215
|
}
|
|
@@ -16264,10 +16412,10 @@ import {
|
|
|
16264
16412
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
16265
16413
|
|
|
16266
16414
|
// src/agent/tools/decisions.ts
|
|
16267
|
-
import { tool as
|
|
16415
|
+
import { tool as tool11 } from "@anthropic-ai/claude-agent-sdk";
|
|
16268
16416
|
function createDecisionTools(store) {
|
|
16269
16417
|
return [
|
|
16270
|
-
|
|
16418
|
+
tool11(
|
|
16271
16419
|
"list_decisions",
|
|
16272
16420
|
"List all decisions in the project, optionally filtered by status",
|
|
16273
16421
|
{ status: external_exports.string().optional().describe("Filter by status (e.g. 'open', 'decided', 'superseded')") },
|
|
@@ -16285,7 +16433,7 @@ function createDecisionTools(store) {
|
|
|
16285
16433
|
},
|
|
16286
16434
|
{ annotations: { readOnly: true } }
|
|
16287
16435
|
),
|
|
16288
|
-
|
|
16436
|
+
tool11(
|
|
16289
16437
|
"get_decision",
|
|
16290
16438
|
"Get the full content of a specific decision by ID",
|
|
16291
16439
|
{ id: external_exports.string().describe("Decision ID (e.g. 'D-001')") },
|
|
@@ -16312,7 +16460,7 @@ function createDecisionTools(store) {
|
|
|
16312
16460
|
},
|
|
16313
16461
|
{ annotations: { readOnly: true } }
|
|
16314
16462
|
),
|
|
16315
|
-
|
|
16463
|
+
tool11(
|
|
16316
16464
|
"create_decision",
|
|
16317
16465
|
"Create a new decision record",
|
|
16318
16466
|
{
|
|
@@ -16343,7 +16491,7 @@ function createDecisionTools(store) {
|
|
|
16343
16491
|
};
|
|
16344
16492
|
}
|
|
16345
16493
|
),
|
|
16346
|
-
|
|
16494
|
+
tool11(
|
|
16347
16495
|
"update_decision",
|
|
16348
16496
|
"Update an existing decision",
|
|
16349
16497
|
{
|
|
@@ -16370,10 +16518,10 @@ function createDecisionTools(store) {
|
|
|
16370
16518
|
}
|
|
16371
16519
|
|
|
16372
16520
|
// src/agent/tools/actions.ts
|
|
16373
|
-
import { tool as
|
|
16521
|
+
import { tool as tool12 } from "@anthropic-ai/claude-agent-sdk";
|
|
16374
16522
|
function createActionTools(store) {
|
|
16375
16523
|
return [
|
|
16376
|
-
|
|
16524
|
+
tool12(
|
|
16377
16525
|
"list_actions",
|
|
16378
16526
|
"List all action items in the project, optionally filtered by status or owner",
|
|
16379
16527
|
{
|
|
@@ -16400,7 +16548,7 @@ function createActionTools(store) {
|
|
|
16400
16548
|
},
|
|
16401
16549
|
{ annotations: { readOnly: true } }
|
|
16402
16550
|
),
|
|
16403
|
-
|
|
16551
|
+
tool12(
|
|
16404
16552
|
"get_action",
|
|
16405
16553
|
"Get the full content of a specific action item by ID",
|
|
16406
16554
|
{ id: external_exports.string().describe("Action ID (e.g. 'A-001')") },
|
|
@@ -16427,7 +16575,7 @@ function createActionTools(store) {
|
|
|
16427
16575
|
},
|
|
16428
16576
|
{ annotations: { readOnly: true } }
|
|
16429
16577
|
),
|
|
16430
|
-
|
|
16578
|
+
tool12(
|
|
16431
16579
|
"create_action",
|
|
16432
16580
|
"Create a new action item",
|
|
16433
16581
|
{
|
|
@@ -16460,7 +16608,7 @@ function createActionTools(store) {
|
|
|
16460
16608
|
};
|
|
16461
16609
|
}
|
|
16462
16610
|
),
|
|
16463
|
-
|
|
16611
|
+
tool12(
|
|
16464
16612
|
"update_action",
|
|
16465
16613
|
"Update an existing action item",
|
|
16466
16614
|
{
|
|
@@ -16488,10 +16636,10 @@ function createActionTools(store) {
|
|
|
16488
16636
|
}
|
|
16489
16637
|
|
|
16490
16638
|
// src/agent/tools/questions.ts
|
|
16491
|
-
import { tool as
|
|
16639
|
+
import { tool as tool13 } from "@anthropic-ai/claude-agent-sdk";
|
|
16492
16640
|
function createQuestionTools(store) {
|
|
16493
16641
|
return [
|
|
16494
|
-
|
|
16642
|
+
tool13(
|
|
16495
16643
|
"list_questions",
|
|
16496
16644
|
"List all questions in the project, optionally filtered by status",
|
|
16497
16645
|
{
|
|
@@ -16512,7 +16660,7 @@ function createQuestionTools(store) {
|
|
|
16512
16660
|
},
|
|
16513
16661
|
{ annotations: { readOnly: true } }
|
|
16514
16662
|
),
|
|
16515
|
-
|
|
16663
|
+
tool13(
|
|
16516
16664
|
"get_question",
|
|
16517
16665
|
"Get the full content of a specific question by ID",
|
|
16518
16666
|
{ id: external_exports.string().describe("Question ID (e.g. 'Q-001')") },
|
|
@@ -16539,7 +16687,7 @@ function createQuestionTools(store) {
|
|
|
16539
16687
|
},
|
|
16540
16688
|
{ annotations: { readOnly: true } }
|
|
16541
16689
|
),
|
|
16542
|
-
|
|
16690
|
+
tool13(
|
|
16543
16691
|
"create_question",
|
|
16544
16692
|
"Create a new question that needs to be answered",
|
|
16545
16693
|
{
|
|
@@ -16570,7 +16718,7 @@ function createQuestionTools(store) {
|
|
|
16570
16718
|
};
|
|
16571
16719
|
}
|
|
16572
16720
|
),
|
|
16573
|
-
|
|
16721
|
+
tool13(
|
|
16574
16722
|
"update_question",
|
|
16575
16723
|
"Update an existing question",
|
|
16576
16724
|
{
|
|
@@ -16597,10 +16745,10 @@ function createQuestionTools(store) {
|
|
|
16597
16745
|
}
|
|
16598
16746
|
|
|
16599
16747
|
// src/agent/tools/documents.ts
|
|
16600
|
-
import { tool as
|
|
16748
|
+
import { tool as tool14 } from "@anthropic-ai/claude-agent-sdk";
|
|
16601
16749
|
function createDocumentTools(store) {
|
|
16602
16750
|
return [
|
|
16603
|
-
|
|
16751
|
+
tool14(
|
|
16604
16752
|
"search_documents",
|
|
16605
16753
|
"Search all project documents, optionally filtered by type, status, or tag",
|
|
16606
16754
|
{
|
|
@@ -16632,7 +16780,7 @@ function createDocumentTools(store) {
|
|
|
16632
16780
|
},
|
|
16633
16781
|
{ annotations: { readOnly: true } }
|
|
16634
16782
|
),
|
|
16635
|
-
|
|
16783
|
+
tool14(
|
|
16636
16784
|
"read_document",
|
|
16637
16785
|
"Read the full content of any project document by ID",
|
|
16638
16786
|
{ id: external_exports.string().describe("Document ID (e.g. 'D-001', 'A-003', 'Q-002')") },
|
|
@@ -16659,7 +16807,7 @@ function createDocumentTools(store) {
|
|
|
16659
16807
|
},
|
|
16660
16808
|
{ annotations: { readOnly: true } }
|
|
16661
16809
|
),
|
|
16662
|
-
|
|
16810
|
+
tool14(
|
|
16663
16811
|
"project_summary",
|
|
16664
16812
|
"Get a summary of all project documents and their counts",
|
|
16665
16813
|
{},
|
|
@@ -16691,10 +16839,10 @@ function createDocumentTools(store) {
|
|
|
16691
16839
|
}
|
|
16692
16840
|
|
|
16693
16841
|
// src/agent/tools/sources.ts
|
|
16694
|
-
import { tool as
|
|
16842
|
+
import { tool as tool15 } from "@anthropic-ai/claude-agent-sdk";
|
|
16695
16843
|
function createSourceTools(manifest) {
|
|
16696
16844
|
return [
|
|
16697
|
-
|
|
16845
|
+
tool15(
|
|
16698
16846
|
"list_sources",
|
|
16699
16847
|
"List all source documents and their processing status",
|
|
16700
16848
|
{
|
|
@@ -16724,7 +16872,7 @@ function createSourceTools(manifest) {
|
|
|
16724
16872
|
},
|
|
16725
16873
|
{ annotations: { readOnly: true } }
|
|
16726
16874
|
),
|
|
16727
|
-
|
|
16875
|
+
tool15(
|
|
16728
16876
|
"get_source_info",
|
|
16729
16877
|
"Get detailed information about a specific source document",
|
|
16730
16878
|
{
|
|
@@ -16762,10 +16910,10 @@ function createSourceTools(manifest) {
|
|
|
16762
16910
|
}
|
|
16763
16911
|
|
|
16764
16912
|
// src/agent/tools/sessions.ts
|
|
16765
|
-
import { tool as
|
|
16913
|
+
import { tool as tool16 } from "@anthropic-ai/claude-agent-sdk";
|
|
16766
16914
|
function createSessionTools(store) {
|
|
16767
16915
|
return [
|
|
16768
|
-
|
|
16916
|
+
tool16(
|
|
16769
16917
|
"list_sessions",
|
|
16770
16918
|
"List all saved chat sessions, sorted by most recently used",
|
|
16771
16919
|
{
|
|
@@ -16789,7 +16937,7 @@ function createSessionTools(store) {
|
|
|
16789
16937
|
},
|
|
16790
16938
|
{ annotations: { readOnly: true } }
|
|
16791
16939
|
),
|
|
16792
|
-
|
|
16940
|
+
tool16(
|
|
16793
16941
|
"get_session",
|
|
16794
16942
|
"Get details of a specific saved session by name",
|
|
16795
16943
|
{ name: external_exports.string().describe("Session name (e.g. 'jwt-auth-decision')") },
|
|
@@ -18378,7 +18526,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
18378
18526
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18379
18527
|
|
|
18380
18528
|
// src/skills/action-tools.ts
|
|
18381
|
-
import { tool as
|
|
18529
|
+
import { tool as tool17 } from "@anthropic-ai/claude-agent-sdk";
|
|
18382
18530
|
|
|
18383
18531
|
// src/skills/action-runner.ts
|
|
18384
18532
|
import { query as query4 } from "@anthropic-ai/claude-agent-sdk";
|
|
@@ -18444,7 +18592,7 @@ function createSkillActionTools(skills, context) {
|
|
|
18444
18592
|
if (!skill.actions) continue;
|
|
18445
18593
|
for (const action of skill.actions) {
|
|
18446
18594
|
tools.push(
|
|
18447
|
-
|
|
18595
|
+
tool17(
|
|
18448
18596
|
`${skill.id}__${action.id}`,
|
|
18449
18597
|
action.description,
|
|
18450
18598
|
{
|
|
@@ -18536,10 +18684,10 @@ ${lines.join("\n\n")}`;
|
|
|
18536
18684
|
}
|
|
18537
18685
|
|
|
18538
18686
|
// src/mcp/persona-tools.ts
|
|
18539
|
-
import { tool as
|
|
18687
|
+
import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
|
|
18540
18688
|
function createPersonaTools(ctx, marvinDir) {
|
|
18541
18689
|
return [
|
|
18542
|
-
|
|
18690
|
+
tool18(
|
|
18543
18691
|
"set_persona",
|
|
18544
18692
|
"Set the active persona for this session. Returns full guidance for the selected persona including behavioral rules, allowed document types, and scope. Call this before working to ensure persona-appropriate behavior.",
|
|
18545
18693
|
{
|
|
@@ -18569,7 +18717,7 @@ ${summaries}`
|
|
|
18569
18717
|
};
|
|
18570
18718
|
}
|
|
18571
18719
|
),
|
|
18572
|
-
|
|
18720
|
+
tool18(
|
|
18573
18721
|
"get_persona_guidance",
|
|
18574
18722
|
"Get guidance for a persona without changing the active persona. If no persona is specified, lists all available personas with summaries.",
|
|
18575
18723
|
{
|
|
@@ -19681,12 +19829,417 @@ Analyzing meeting: ${meetingDoc.frontmatter.title}`));
|
|
|
19681
19829
|
});
|
|
19682
19830
|
}
|
|
19683
19831
|
|
|
19832
|
+
// src/cli/commands/contribute.ts
|
|
19833
|
+
import chalk15 from "chalk";
|
|
19834
|
+
|
|
19835
|
+
// src/contributions/contribute.ts
|
|
19836
|
+
import chalk14 from "chalk";
|
|
19837
|
+
import ora5 from "ora";
|
|
19838
|
+
import { query as query6 } from "@anthropic-ai/claude-agent-sdk";
|
|
19839
|
+
|
|
19840
|
+
// src/contributions/prompts.ts
|
|
19841
|
+
function buildContributeSystemPrompt(persona, contributionType, projectConfig, isDraft) {
|
|
19842
|
+
const parts = [];
|
|
19843
|
+
parts.push(persona.systemPrompt);
|
|
19844
|
+
parts.push(`
|
|
19845
|
+
## Project Context
|
|
19846
|
+
- **Project Name:** ${projectConfig.name}
|
|
19847
|
+
- **Methodology:** ${projectConfig.methodology ?? "Generic Agile"}
|
|
19848
|
+
`);
|
|
19849
|
+
parts.push(`
|
|
19850
|
+
## Contribution Analysis Task
|
|
19851
|
+
You are processing a **${contributionType}** contribution from the **${persona.name}**.
|
|
19852
|
+
Review the contribution content and determine what governance effects should follow.
|
|
19853
|
+
|
|
19854
|
+
Possible effects include:
|
|
19855
|
+
1. **Create** new artifacts \u2014 decisions (D-xxx), actions (A-xxx), questions (Q-xxx)
|
|
19856
|
+
2. **Update** existing artifacts \u2014 change status, add information, close items
|
|
19857
|
+
`);
|
|
19858
|
+
parts.push(buildContributionTypeInstructions(contributionType));
|
|
19859
|
+
if (isDraft) {
|
|
19860
|
+
parts.push(`
|
|
19861
|
+
## Mode: Draft Proposal
|
|
19862
|
+
Present your findings as a structured proposal. Do NOT create or update any artifacts.
|
|
19863
|
+
Format your response as:
|
|
19864
|
+
|
|
19865
|
+
### Proposed Effects
|
|
19866
|
+
For each effect:
|
|
19867
|
+
- **Action:** [create/update]
|
|
19868
|
+
- **Target:** [new artifact type or existing artifact ID]
|
|
19869
|
+
- **Details:** [what would be created or changed]
|
|
19870
|
+
- **Rationale:** [why this effect follows from the contribution]
|
|
19871
|
+
|
|
19872
|
+
### Summary
|
|
19873
|
+
Provide a brief summary of the contribution analysis and recommendations.
|
|
19874
|
+
`);
|
|
19875
|
+
} else {
|
|
19876
|
+
parts.push(`
|
|
19877
|
+
## Mode: Direct Execution
|
|
19878
|
+
Use the MCP tools to create and update artifacts directly:
|
|
19879
|
+
- Use \`create_decision\` / \`create_action\` / \`create_question\` for new artifacts
|
|
19880
|
+
- Use \`update_decision\` / \`update_action\` / \`update_question\` to modify existing ones
|
|
19881
|
+
- Use \`list_decisions\` / \`list_actions\` / \`list_questions\` to check existing artifacts before creating or updating
|
|
19882
|
+
|
|
19883
|
+
Before creating artifacts, check existing ones using the list tools to avoid duplicates.
|
|
19884
|
+
|
|
19885
|
+
For EVERY artifact you create or update, include:
|
|
19886
|
+
- A \`source:<contribution-id>\` tag in the tags array (the contribution ID is provided in the user prompt)
|
|
19887
|
+
- Clear title and detailed content with context from the contribution
|
|
19888
|
+
|
|
19889
|
+
After processing all effects, provide a summary of what was created and updated.
|
|
19890
|
+
`);
|
|
19891
|
+
}
|
|
19892
|
+
return parts.join("\n");
|
|
19893
|
+
}
|
|
19894
|
+
function buildContributionTypeInstructions(contributionType) {
|
|
19895
|
+
const instructions = {
|
|
19896
|
+
"action-result": `
|
|
19897
|
+
### Type-Specific Guidance: Action Result
|
|
19898
|
+
The contributor is reporting results of a completed action.
|
|
19899
|
+
- Update the referenced action's status to "done" if results are conclusive
|
|
19900
|
+
- Check if the results answer any open questions \u2014 if so, update those questions
|
|
19901
|
+
- Check if results challenge any existing decisions \u2014 if so, create a new question or update the decision
|
|
19902
|
+
- If results reveal new work, create new actions`,
|
|
19903
|
+
"spike-findings": `
|
|
19904
|
+
### Type-Specific Guidance: Spike Findings
|
|
19905
|
+
The contributor is sharing findings from a technical investigation (spike).
|
|
19906
|
+
- Create decisions for any architectural or technical choices made
|
|
19907
|
+
- Update or close the original spike action if referenced
|
|
19908
|
+
- Create new actions for follow-up implementation work
|
|
19909
|
+
- Create questions for areas needing further investigation`,
|
|
19910
|
+
"technical-assessment": `
|
|
19911
|
+
### Type-Specific Guidance: Technical Assessment
|
|
19912
|
+
The contributor is providing a technical evaluation.
|
|
19913
|
+
- Create decisions for technical recommendations
|
|
19914
|
+
- Create actions for remediation or improvement tasks
|
|
19915
|
+
- Create questions for areas needing more investigation
|
|
19916
|
+
- Flag any risks by tagging artifacts with "risk"`,
|
|
19917
|
+
"architecture-review": `
|
|
19918
|
+
### Type-Specific Guidance: Architecture Review
|
|
19919
|
+
The contributor is documenting an architecture review.
|
|
19920
|
+
- Create decisions for architectural choices and trade-offs
|
|
19921
|
+
- Create actions for any architectural changes needed
|
|
19922
|
+
- Create questions for design concerns or alternatives to evaluate
|
|
19923
|
+
- Update existing decisions if the review validates or challenges them`,
|
|
19924
|
+
"stakeholder-feedback": `
|
|
19925
|
+
### Type-Specific Guidance: Stakeholder Feedback
|
|
19926
|
+
The contributor is relaying feedback from stakeholders.
|
|
19927
|
+
- Create or update decisions based on stakeholder direction
|
|
19928
|
+
- Create actions for requested changes or follow-ups
|
|
19929
|
+
- Create questions for items needing clarification
|
|
19930
|
+
- Update priorities on existing artifacts if feedback changes priorities`,
|
|
19931
|
+
"acceptance-result": `
|
|
19932
|
+
### Type-Specific Guidance: Acceptance Result
|
|
19933
|
+
The contributor is reporting results of acceptance testing.
|
|
19934
|
+
- Update the referenced action/feature status based on pass/fail
|
|
19935
|
+
- Create new actions for any rework needed
|
|
19936
|
+
- Create questions for ambiguous acceptance criteria
|
|
19937
|
+
- If accepted, mark related actions as "done"`,
|
|
19938
|
+
"priority-change": `
|
|
19939
|
+
### Type-Specific Guidance: Priority Change
|
|
19940
|
+
The contributor is communicating a change in priorities.
|
|
19941
|
+
- Update priority fields on affected artifacts
|
|
19942
|
+
- Create decisions documenting the priority change rationale
|
|
19943
|
+
- Create actions for any re-planning needed
|
|
19944
|
+
- Flag any blocked or impacted items`,
|
|
19945
|
+
"market-insight": `
|
|
19946
|
+
### Type-Specific Guidance: Market Insight
|
|
19947
|
+
The contributor is sharing market intelligence or competitive information.
|
|
19948
|
+
- Create decisions if the insight drives product direction changes
|
|
19949
|
+
- Create questions for areas needing further market research
|
|
19950
|
+
- Create actions for competitive response tasks
|
|
19951
|
+
- Update existing features or priorities if affected`,
|
|
19952
|
+
"risk-finding": `
|
|
19953
|
+
### Type-Specific Guidance: Risk Finding
|
|
19954
|
+
The contributor is identifying a project risk.
|
|
19955
|
+
- Create actions for risk mitigation tasks
|
|
19956
|
+
- Create decisions for risk response strategies
|
|
19957
|
+
- Create questions for risks needing further assessment
|
|
19958
|
+
- Tag all related artifacts with "risk" for tracking`,
|
|
19959
|
+
"blocker-report": `
|
|
19960
|
+
### Type-Specific Guidance: Blocker Report
|
|
19961
|
+
The contributor is reporting a blocker.
|
|
19962
|
+
- Create actions to resolve the blocker
|
|
19963
|
+
- Update blocked artifacts' status or add blocking context
|
|
19964
|
+
- Create questions for blockers needing external input
|
|
19965
|
+
- Escalate by creating high-priority actions if critical`,
|
|
19966
|
+
"dependency-update": `
|
|
19967
|
+
### Type-Specific Guidance: Dependency Update
|
|
19968
|
+
The contributor is reporting on external or internal dependencies.
|
|
19969
|
+
- Update affected actions with dependency information
|
|
19970
|
+
- Create new actions for dependency-related tasks
|
|
19971
|
+
- Create questions for uncertain dependencies
|
|
19972
|
+
- Update timelines or flag schedule risks`,
|
|
19973
|
+
"status-assessment": `
|
|
19974
|
+
### Type-Specific Guidance: Status Assessment
|
|
19975
|
+
The contributor is providing a delivery status assessment.
|
|
19976
|
+
- Update action statuses based on assessment
|
|
19977
|
+
- Create actions for corrective measures
|
|
19978
|
+
- Create questions for items needing investigation
|
|
19979
|
+
- Create decisions for any process changes needed`
|
|
19980
|
+
};
|
|
19981
|
+
return instructions[contributionType] ?? `
|
|
19982
|
+
### Type-Specific Guidance
|
|
19983
|
+
Analyze the contribution and determine appropriate governance effects based on the content.`;
|
|
19984
|
+
}
|
|
19985
|
+
function buildContributeUserPrompt(contributionId, contributionType, content, aboutArtifact, isDraft) {
|
|
19986
|
+
const mode = isDraft ? "propose" : "execute";
|
|
19987
|
+
const aboutLine = aboutArtifact ? `
|
|
19988
|
+
**Related Artifact:** ${aboutArtifact}` : "";
|
|
19989
|
+
return `Please analyze the following contribution and ${mode} governance effects.
|
|
19990
|
+
|
|
19991
|
+
**Contribution ID:** ${contributionId}
|
|
19992
|
+
**Contribution Type:** ${contributionType}${aboutLine}
|
|
19993
|
+
|
|
19994
|
+
---
|
|
19995
|
+
${content}
|
|
19996
|
+
---
|
|
19997
|
+
|
|
19998
|
+
Analyze this contribution thoroughly and ${mode} all relevant governance effects (create new artifacts, update existing ones). Tag each created or updated artifact with "source:${contributionId}" for traceability.`;
|
|
19999
|
+
}
|
|
20000
|
+
|
|
20001
|
+
// src/contributions/contribute.ts
|
|
20002
|
+
async function contributeFromPersona(options) {
|
|
20003
|
+
const { marvinDir, prompt, aboutArtifact, draft } = options;
|
|
20004
|
+
const config2 = getConfig(marvinDir);
|
|
20005
|
+
const personaId = resolvePersonaId(options.persona);
|
|
20006
|
+
const persona = getPersona(personaId);
|
|
20007
|
+
const allowedTypes = persona.contributionTypes ?? [];
|
|
20008
|
+
if (allowedTypes.length > 0 && !allowedTypes.includes(options.contributionType)) {
|
|
20009
|
+
throw new Error(
|
|
20010
|
+
`Contribution type "${options.contributionType}" is not valid for persona "${persona.name}". Allowed types: ${allowedTypes.join(", ")}`
|
|
20011
|
+
);
|
|
20012
|
+
}
|
|
20013
|
+
const plugin = resolvePlugin(config2.project.methodology);
|
|
20014
|
+
const registrations = plugin?.documentTypeRegistrations ?? [];
|
|
20015
|
+
const store = new DocumentStore(marvinDir, registrations);
|
|
20016
|
+
const contributionFrontmatter = {
|
|
20017
|
+
title: `${options.contributionType}: ${prompt.slice(0, 60)}${prompt.length > 60 ? "..." : ""}`,
|
|
20018
|
+
status: "open",
|
|
20019
|
+
persona: personaId,
|
|
20020
|
+
contributionType: options.contributionType
|
|
20021
|
+
};
|
|
20022
|
+
if (aboutArtifact) contributionFrontmatter.aboutArtifact = aboutArtifact;
|
|
20023
|
+
const contributionDoc = store.create("contribution", contributionFrontmatter, prompt);
|
|
20024
|
+
const contributionId = contributionDoc.frontmatter.id;
|
|
20025
|
+
const createdArtifacts = [];
|
|
20026
|
+
const updatedArtifacts = [];
|
|
20027
|
+
if (!draft) {
|
|
20028
|
+
const originalCreate = store.create.bind(store);
|
|
20029
|
+
store.create = (type, frontmatter, content) => {
|
|
20030
|
+
const tags = frontmatter.tags ?? [];
|
|
20031
|
+
const sourceTag = `source:${contributionId}`;
|
|
20032
|
+
if (!tags.includes(sourceTag)) {
|
|
20033
|
+
tags.push(sourceTag);
|
|
20034
|
+
}
|
|
20035
|
+
const doc = originalCreate(type, { ...frontmatter, source: contributionId, tags }, content);
|
|
20036
|
+
createdArtifacts.push(doc.frontmatter.id);
|
|
20037
|
+
return doc;
|
|
20038
|
+
};
|
|
20039
|
+
const originalUpdate = store.update.bind(store);
|
|
20040
|
+
store.update = (id, updates, content) => {
|
|
20041
|
+
if (id === contributionId) {
|
|
20042
|
+
return originalUpdate(id, updates, content);
|
|
20043
|
+
}
|
|
20044
|
+
const existing = store.get(id);
|
|
20045
|
+
const existingTags = existing?.frontmatter.tags ?? [];
|
|
20046
|
+
const sourceTag = `source:${contributionId}`;
|
|
20047
|
+
if (!existingTags.includes(sourceTag)) {
|
|
20048
|
+
existingTags.push(sourceTag);
|
|
20049
|
+
}
|
|
20050
|
+
const doc = originalUpdate(id, { ...updates, tags: existingTags }, content);
|
|
20051
|
+
if (!updatedArtifacts.includes(id)) {
|
|
20052
|
+
updatedArtifacts.push(id);
|
|
20053
|
+
}
|
|
20054
|
+
return doc;
|
|
20055
|
+
};
|
|
20056
|
+
}
|
|
20057
|
+
const pluginTools = plugin ? getPluginTools(plugin, store, marvinDir) : [];
|
|
20058
|
+
const mcpServer = createMarvinMcpServer(store, { pluginTools });
|
|
20059
|
+
const systemPrompt = buildContributeSystemPrompt(persona, options.contributionType, config2.project, draft);
|
|
20060
|
+
const userPrompt = buildContributeUserPrompt(
|
|
20061
|
+
contributionId,
|
|
20062
|
+
options.contributionType,
|
|
20063
|
+
prompt,
|
|
20064
|
+
aboutArtifact,
|
|
20065
|
+
draft
|
|
20066
|
+
);
|
|
20067
|
+
const spinner = ora5({ text: `Processing contribution ${contributionId}...`, color: "cyan" });
|
|
20068
|
+
spinner.start();
|
|
20069
|
+
try {
|
|
20070
|
+
const allowedTools = draft ? [
|
|
20071
|
+
"mcp__marvin-governance__list_decisions",
|
|
20072
|
+
"mcp__marvin-governance__list_actions",
|
|
20073
|
+
"mcp__marvin-governance__list_questions",
|
|
20074
|
+
"mcp__marvin-governance__get_decision",
|
|
20075
|
+
"mcp__marvin-governance__get_action",
|
|
20076
|
+
"mcp__marvin-governance__get_question"
|
|
20077
|
+
] : [
|
|
20078
|
+
"mcp__marvin-governance__create_decision",
|
|
20079
|
+
"mcp__marvin-governance__create_action",
|
|
20080
|
+
"mcp__marvin-governance__create_question",
|
|
20081
|
+
"mcp__marvin-governance__update_decision",
|
|
20082
|
+
"mcp__marvin-governance__update_action",
|
|
20083
|
+
"mcp__marvin-governance__update_question",
|
|
20084
|
+
"mcp__marvin-governance__list_decisions",
|
|
20085
|
+
"mcp__marvin-governance__list_actions",
|
|
20086
|
+
"mcp__marvin-governance__list_questions",
|
|
20087
|
+
"mcp__marvin-governance__get_decision",
|
|
20088
|
+
"mcp__marvin-governance__get_action",
|
|
20089
|
+
"mcp__marvin-governance__get_question"
|
|
20090
|
+
];
|
|
20091
|
+
const conversation = query6({
|
|
20092
|
+
prompt: userPrompt,
|
|
20093
|
+
options: {
|
|
20094
|
+
systemPrompt,
|
|
20095
|
+
mcpServers: { "marvin-governance": mcpServer },
|
|
20096
|
+
permissionMode: "acceptEdits",
|
|
20097
|
+
maxTurns: 10,
|
|
20098
|
+
tools: [],
|
|
20099
|
+
allowedTools
|
|
20100
|
+
}
|
|
20101
|
+
});
|
|
20102
|
+
for await (const message of conversation) {
|
|
20103
|
+
handleContributeMessage(message, spinner);
|
|
20104
|
+
}
|
|
20105
|
+
const effects = [...createdArtifacts, ...updatedArtifacts];
|
|
20106
|
+
if (!draft && effects.length > 0) {
|
|
20107
|
+
appendEffectsToContribution(store, contributionId, contributionDoc.content, createdArtifacts, updatedArtifacts, store);
|
|
20108
|
+
}
|
|
20109
|
+
spinner.stop();
|
|
20110
|
+
if (draft) {
|
|
20111
|
+
console.log(chalk14.dim(`
|
|
20112
|
+
Draft proposal complete. No artifacts were created or updated.`));
|
|
20113
|
+
console.log(chalk14.dim(`Use --no-draft to execute effects directly.`));
|
|
20114
|
+
} else {
|
|
20115
|
+
const totalEffects = createdArtifacts.length + updatedArtifacts.length;
|
|
20116
|
+
console.log(chalk14.green(`
|
|
20117
|
+
Contribution ${contributionId} processed: ${totalEffects} effect${totalEffects === 1 ? "" : "s"}`));
|
|
20118
|
+
if (createdArtifacts.length > 0) {
|
|
20119
|
+
console.log(chalk14.dim(` Created: ${createdArtifacts.join(", ")}`));
|
|
20120
|
+
}
|
|
20121
|
+
if (updatedArtifacts.length > 0) {
|
|
20122
|
+
console.log(chalk14.dim(` Updated: ${updatedArtifacts.join(", ")}`));
|
|
20123
|
+
}
|
|
20124
|
+
}
|
|
20125
|
+
return { contributionId, effects, draft };
|
|
20126
|
+
} catch (err) {
|
|
20127
|
+
spinner.stop();
|
|
20128
|
+
throw err;
|
|
20129
|
+
}
|
|
20130
|
+
}
|
|
20131
|
+
function appendEffectsToContribution(store, contributionId, existingContent, created, updated, storeInstance) {
|
|
20132
|
+
const lines = [];
|
|
20133
|
+
if (created.length > 0) {
|
|
20134
|
+
lines.push("### Created");
|
|
20135
|
+
for (const id of created) {
|
|
20136
|
+
const doc = storeInstance.get(id);
|
|
20137
|
+
const title = doc ? doc.frontmatter.title : id;
|
|
20138
|
+
lines.push(`- ${id}: ${title}`);
|
|
20139
|
+
}
|
|
20140
|
+
}
|
|
20141
|
+
if (updated.length > 0) {
|
|
20142
|
+
lines.push("### Updated");
|
|
20143
|
+
for (const id of updated) {
|
|
20144
|
+
const doc = storeInstance.get(id);
|
|
20145
|
+
const title = doc ? doc.frontmatter.title : id;
|
|
20146
|
+
lines.push(`- ${id}: ${title}`);
|
|
20147
|
+
}
|
|
20148
|
+
}
|
|
20149
|
+
const effectsSection = `
|
|
20150
|
+
|
|
20151
|
+
## Effects
|
|
20152
|
+
${lines.join("\n")}`;
|
|
20153
|
+
const updatedContent = existingContent + effectsSection;
|
|
20154
|
+
store.update(contributionId, { status: "processed" }, updatedContent);
|
|
20155
|
+
}
|
|
20156
|
+
function handleContributeMessage(message, spinner) {
|
|
20157
|
+
switch (message.type) {
|
|
20158
|
+
case "assistant": {
|
|
20159
|
+
spinner.stop();
|
|
20160
|
+
const textBlocks = message.message.content.filter(
|
|
20161
|
+
(b) => b.type === "text"
|
|
20162
|
+
);
|
|
20163
|
+
if (textBlocks.length > 0) {
|
|
20164
|
+
console.log(
|
|
20165
|
+
chalk14.cyan("\nMarvin: ") + textBlocks.map((b) => b.text).join("\n")
|
|
20166
|
+
);
|
|
20167
|
+
}
|
|
20168
|
+
break;
|
|
20169
|
+
}
|
|
20170
|
+
case "system": {
|
|
20171
|
+
if (message.subtype === "init") {
|
|
20172
|
+
spinner.start("Analyzing contribution...");
|
|
20173
|
+
}
|
|
20174
|
+
break;
|
|
20175
|
+
}
|
|
20176
|
+
case "result": {
|
|
20177
|
+
spinner.stop();
|
|
20178
|
+
if (message.subtype !== "success") {
|
|
20179
|
+
console.log(
|
|
20180
|
+
chalk14.red(`
|
|
20181
|
+
Contribution analysis ended with error: ${message.subtype}`)
|
|
20182
|
+
);
|
|
20183
|
+
}
|
|
20184
|
+
break;
|
|
20185
|
+
}
|
|
20186
|
+
}
|
|
20187
|
+
}
|
|
20188
|
+
|
|
20189
|
+
// src/cli/commands/contribute.ts
|
|
20190
|
+
async function contributeCommand(options) {
|
|
20191
|
+
const project = loadProject();
|
|
20192
|
+
const marvinDir = project.marvinDir;
|
|
20193
|
+
if (!options.as) {
|
|
20194
|
+
console.log(chalk15.red("Missing required option: --as <persona>"));
|
|
20195
|
+
console.log(chalk15.dim('Example: marvin contribute --as tl --type action-result --prompt "..."'));
|
|
20196
|
+
return;
|
|
20197
|
+
}
|
|
20198
|
+
if (!options.type) {
|
|
20199
|
+
console.log(chalk15.red("Missing required option: --type <contribution-type>"));
|
|
20200
|
+
const personaId2 = resolvePersonaId(options.as);
|
|
20201
|
+
const persona2 = getPersona(personaId2);
|
|
20202
|
+
if (persona2?.contributionTypes?.length) {
|
|
20203
|
+
console.log(chalk15.dim(`Available types for ${persona2.name}: ${persona2.contributionTypes.join(", ")}`));
|
|
20204
|
+
}
|
|
20205
|
+
return;
|
|
20206
|
+
}
|
|
20207
|
+
if (!options.prompt) {
|
|
20208
|
+
console.log(chalk15.red("Missing required option: --prompt <text>"));
|
|
20209
|
+
console.log(chalk15.dim("Provide the contribution content via --prompt."));
|
|
20210
|
+
return;
|
|
20211
|
+
}
|
|
20212
|
+
const personaId = resolvePersonaId(options.as);
|
|
20213
|
+
const persona = getPersona(personaId);
|
|
20214
|
+
if (!persona) {
|
|
20215
|
+
console.log(chalk15.red(`Unknown persona: ${options.as}`));
|
|
20216
|
+
return;
|
|
20217
|
+
}
|
|
20218
|
+
const isDraft = options.draft !== false;
|
|
20219
|
+
console.log(chalk15.bold(`
|
|
20220
|
+
Contribution: ${options.type}`));
|
|
20221
|
+
console.log(chalk15.dim(`Persona: ${persona.name}`));
|
|
20222
|
+
console.log(chalk15.dim(`Mode: ${isDraft ? "draft (propose only)" : "direct (execute effects)"}`));
|
|
20223
|
+
if (options.about) {
|
|
20224
|
+
console.log(chalk15.dim(`About: ${options.about}`));
|
|
20225
|
+
}
|
|
20226
|
+
console.log();
|
|
20227
|
+
await contributeFromPersona({
|
|
20228
|
+
marvinDir,
|
|
20229
|
+
persona: options.as,
|
|
20230
|
+
contributionType: options.type,
|
|
20231
|
+
prompt: options.prompt,
|
|
20232
|
+
aboutArtifact: options.about,
|
|
20233
|
+
draft: isDraft
|
|
20234
|
+
});
|
|
20235
|
+
}
|
|
20236
|
+
|
|
19684
20237
|
// src/cli/program.ts
|
|
19685
20238
|
function createProgram() {
|
|
19686
20239
|
const program2 = new Command();
|
|
19687
20240
|
program2.name("marvin").description(
|
|
19688
20241
|
"AI-powered product development assistant with Product Owner, Delivery Manager, and Technical Lead personas"
|
|
19689
|
-
).version("0.2.
|
|
20242
|
+
).version("0.2.4");
|
|
19690
20243
|
program2.command("init").description("Initialize a new Marvin project in the current directory").action(async () => {
|
|
19691
20244
|
await initCommand();
|
|
19692
20245
|
});
|
|
@@ -19729,6 +20282,9 @@ function createProgram() {
|
|
|
19729
20282
|
program2.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) => {
|
|
19730
20283
|
await analyzeCommand(meetingId, options);
|
|
19731
20284
|
});
|
|
20285
|
+
program2.command("contribute").description("Submit a structured contribution from a persona to generate governance effects").requiredOption("--as <persona>", "Persona making the contribution (po, dm, tl)").requiredOption("--type <type>", "Contribution type (e.g. action-result, risk-finding)").requiredOption("--prompt <text>", "Contribution content").option("--about <artifact-id>", "Related artifact ID (e.g. A-001)").option("--draft", "Propose effects without executing (default)").option("--no-draft", "Execute effects directly").action(async (options) => {
|
|
20286
|
+
await contributeCommand(options);
|
|
20287
|
+
});
|
|
19732
20288
|
program2.command("import <path>").description("Import documents or sources from external paths").option("--dry-run", "Preview without writing files").option(
|
|
19733
20289
|
"--conflict <strategy>",
|
|
19734
20290
|
"ID conflict strategy: renumber, skip, overwrite (default: renumber)"
|