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/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 tool5 } from "@anthropic-ai/claude-agent-sdk";
14913
+ import { tool as tool6 } from "@anthropic-ai/claude-agent-sdk";
14769
14914
  function createUseCaseTools(store) {
14770
14915
  return [
14771
- tool5(
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
- tool5(
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
- tool5(
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
- tool5(
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 tool6 } from "@anthropic-ai/claude-agent-sdk";
15037
+ import { tool as tool7 } from "@anthropic-ai/claude-agent-sdk";
14893
15038
  function createTechAssessmentTools(store) {
14894
15039
  return [
14895
- tool6(
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
- tool6(
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
- tool6(
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
- tool6(
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 tool7 } from "@anthropic-ai/claude-agent-sdk";
15199
+ import { tool as tool8 } from "@anthropic-ai/claude-agent-sdk";
15055
15200
  function createExtensionDesignTools(store) {
15056
15201
  return [
15057
- tool7(
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
- tool7(
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
- tool7(
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
- tool7(
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 tool8 } from "@anthropic-ai/claude-agent-sdk";
15356
+ import { tool as tool9 } from "@anthropic-ai/claude-agent-sdk";
15212
15357
  function createAemReportTools(store) {
15213
15358
  return [
15214
- tool8(
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
- tool8(
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
- tool8(
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 tool9 } from "@anthropic-ai/claude-agent-sdk";
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
- tool9(
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
- tool9(
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(query6) {
16197
+ list(query7) {
16050
16198
  const results = [];
16051
- const types = query6?.type ? [query6.type] : Object.keys(this.typeDirs);
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 (query6?.status && doc.frontmatter.status !== query6.status) continue;
16063
- if (query6?.owner && doc.frontmatter.owner !== query6.owner) continue;
16064
- if (query6?.tag && (!doc.frontmatter.tags || !doc.frontmatter.tags.includes(query6.tag)))
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 tool10 } from "@anthropic-ai/claude-agent-sdk";
16415
+ import { tool as tool11 } from "@anthropic-ai/claude-agent-sdk";
16268
16416
  function createDecisionTools(store) {
16269
16417
  return [
16270
- tool10(
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
- tool10(
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
- tool10(
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
- tool10(
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 tool11 } from "@anthropic-ai/claude-agent-sdk";
16521
+ import { tool as tool12 } from "@anthropic-ai/claude-agent-sdk";
16374
16522
  function createActionTools(store) {
16375
16523
  return [
16376
- tool11(
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
- tool11(
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
- tool11(
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
- tool11(
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 tool12 } from "@anthropic-ai/claude-agent-sdk";
16639
+ import { tool as tool13 } from "@anthropic-ai/claude-agent-sdk";
16492
16640
  function createQuestionTools(store) {
16493
16641
  return [
16494
- tool12(
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
- tool12(
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
- tool12(
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
- tool12(
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 tool13 } from "@anthropic-ai/claude-agent-sdk";
16748
+ import { tool as tool14 } from "@anthropic-ai/claude-agent-sdk";
16601
16749
  function createDocumentTools(store) {
16602
16750
  return [
16603
- tool13(
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
- tool13(
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
- tool13(
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 tool14 } from "@anthropic-ai/claude-agent-sdk";
16842
+ import { tool as tool15 } from "@anthropic-ai/claude-agent-sdk";
16695
16843
  function createSourceTools(manifest) {
16696
16844
  return [
16697
- tool14(
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
- tool14(
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 tool15 } from "@anthropic-ai/claude-agent-sdk";
16913
+ import { tool as tool16 } from "@anthropic-ai/claude-agent-sdk";
16766
16914
  function createSessionTools(store) {
16767
16915
  return [
16768
- tool15(
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
- tool15(
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 tool16 } from "@anthropic-ai/claude-agent-sdk";
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
- tool16(
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 tool17 } from "@anthropic-ai/claude-agent-sdk";
18687
+ import { tool as tool18 } from "@anthropic-ai/claude-agent-sdk";
18540
18688
  function createPersonaTools(ctx, marvinDir) {
18541
18689
  return [
18542
- tool17(
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
- tool17(
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.1");
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)"