harmony-mcp 1.1.1 → 1.2.1
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/cli.js +444 -0
- package/dist/index.js +444 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -25384,6 +25384,15 @@ class HarmonyApiClient {
|
|
|
25384
25384
|
async removeLabelFromCard(cardId, labelId) {
|
|
25385
25385
|
return this.request("DELETE", `/cards/${cardId}/labels/${labelId}`);
|
|
25386
25386
|
}
|
|
25387
|
+
async addLinkToCard(sourceCardId, targetCardId, linkType) {
|
|
25388
|
+
return this.request("POST", `/cards/${sourceCardId}/links`, { targetCardId, linkType });
|
|
25389
|
+
}
|
|
25390
|
+
async removeLinkFromCard(linkId) {
|
|
25391
|
+
return this.request("DELETE", `/card-links/${linkId}`);
|
|
25392
|
+
}
|
|
25393
|
+
async getCardLinks(cardId) {
|
|
25394
|
+
return this.request("GET", `/cards/${cardId}/links`);
|
|
25395
|
+
}
|
|
25387
25396
|
async createColumn(projectId, name) {
|
|
25388
25397
|
return this.request("POST", "/columns", { projectId, name });
|
|
25389
25398
|
}
|
|
@@ -25433,6 +25442,312 @@ function getClient() {
|
|
|
25433
25442
|
return client;
|
|
25434
25443
|
}
|
|
25435
25444
|
|
|
25445
|
+
// src/prompt-builder.ts
|
|
25446
|
+
var LABEL_CATEGORY_MAP = {
|
|
25447
|
+
bug: "bug",
|
|
25448
|
+
fix: "bug",
|
|
25449
|
+
hotfix: "bug",
|
|
25450
|
+
defect: "bug",
|
|
25451
|
+
issue: "bug",
|
|
25452
|
+
error: "bug",
|
|
25453
|
+
feature: "feature",
|
|
25454
|
+
enhancement: "feature",
|
|
25455
|
+
improvement: "feature",
|
|
25456
|
+
new: "feature",
|
|
25457
|
+
design: "design",
|
|
25458
|
+
ui: "design",
|
|
25459
|
+
ux: "design",
|
|
25460
|
+
frontend: "design",
|
|
25461
|
+
styling: "design",
|
|
25462
|
+
review: "review",
|
|
25463
|
+
"code review": "review",
|
|
25464
|
+
pr: "review",
|
|
25465
|
+
feedback: "review",
|
|
25466
|
+
onboarding: "onboarding",
|
|
25467
|
+
documentation: "onboarding",
|
|
25468
|
+
docs: "onboarding",
|
|
25469
|
+
guide: "onboarding",
|
|
25470
|
+
tutorial: "onboarding",
|
|
25471
|
+
epic: "epic",
|
|
25472
|
+
initiative: "epic",
|
|
25473
|
+
project: "epic",
|
|
25474
|
+
milestone: "epic"
|
|
25475
|
+
};
|
|
25476
|
+
var DEFAULT_ROLE_FRAMINGS = {
|
|
25477
|
+
bug: {
|
|
25478
|
+
category: "bug",
|
|
25479
|
+
role: "Senior QA Engineer and Software Developer",
|
|
25480
|
+
perspective: "You are investigating and fixing a bug report.",
|
|
25481
|
+
focus: [
|
|
25482
|
+
"Root cause analysis",
|
|
25483
|
+
"Steps to reproduce",
|
|
25484
|
+
"Impact assessment",
|
|
25485
|
+
"Fix implementation",
|
|
25486
|
+
"Regression prevention",
|
|
25487
|
+
"Test cases to prevent recurrence"
|
|
25488
|
+
],
|
|
25489
|
+
outputSuggestions: [
|
|
25490
|
+
"Bug triage summary",
|
|
25491
|
+
"Root cause explanation",
|
|
25492
|
+
"Fix implementation plan",
|
|
25493
|
+
"Test cases"
|
|
25494
|
+
]
|
|
25495
|
+
},
|
|
25496
|
+
feature: {
|
|
25497
|
+
category: "feature",
|
|
25498
|
+
role: "Product Engineer",
|
|
25499
|
+
perspective: "You are implementing a new feature or enhancement.",
|
|
25500
|
+
focus: [
|
|
25501
|
+
"User requirements",
|
|
25502
|
+
"Technical specification",
|
|
25503
|
+
"Implementation approach",
|
|
25504
|
+
"Edge cases",
|
|
25505
|
+
"Acceptance criteria",
|
|
25506
|
+
"Integration points"
|
|
25507
|
+
],
|
|
25508
|
+
outputSuggestions: [
|
|
25509
|
+
"Technical specification",
|
|
25510
|
+
"Implementation tasks",
|
|
25511
|
+
"Acceptance criteria checklist",
|
|
25512
|
+
"API design"
|
|
25513
|
+
]
|
|
25514
|
+
},
|
|
25515
|
+
design: {
|
|
25516
|
+
category: "design",
|
|
25517
|
+
role: "UX Designer and Frontend Developer",
|
|
25518
|
+
perspective: "You are designing and implementing a user interface.",
|
|
25519
|
+
focus: [
|
|
25520
|
+
"User experience flow",
|
|
25521
|
+
"Visual design consistency",
|
|
25522
|
+
"Accessibility (WCAG)",
|
|
25523
|
+
"Responsive behavior",
|
|
25524
|
+
"Component architecture",
|
|
25525
|
+
"Interaction patterns"
|
|
25526
|
+
],
|
|
25527
|
+
outputSuggestions: [
|
|
25528
|
+
"User flow diagram",
|
|
25529
|
+
"Component specifications",
|
|
25530
|
+
"Accessibility checklist",
|
|
25531
|
+
"Responsive breakpoints"
|
|
25532
|
+
]
|
|
25533
|
+
},
|
|
25534
|
+
review: {
|
|
25535
|
+
category: "review",
|
|
25536
|
+
role: "Code Reviewer and Technical Lead",
|
|
25537
|
+
perspective: "You are reviewing code for quality, correctness, and maintainability.",
|
|
25538
|
+
focus: [
|
|
25539
|
+
"Code correctness",
|
|
25540
|
+
"Performance implications",
|
|
25541
|
+
"Security considerations",
|
|
25542
|
+
"Testing coverage",
|
|
25543
|
+
"Documentation",
|
|
25544
|
+
"Best practices adherence"
|
|
25545
|
+
],
|
|
25546
|
+
outputSuggestions: [
|
|
25547
|
+
"Review checklist",
|
|
25548
|
+
"Suggested improvements",
|
|
25549
|
+
"Test scenarios",
|
|
25550
|
+
"Security audit"
|
|
25551
|
+
]
|
|
25552
|
+
},
|
|
25553
|
+
onboarding: {
|
|
25554
|
+
category: "onboarding",
|
|
25555
|
+
role: "Technical Writer and Developer Advocate",
|
|
25556
|
+
perspective: "You are creating documentation or onboarding materials.",
|
|
25557
|
+
focus: [
|
|
25558
|
+
"Clear step-by-step instructions",
|
|
25559
|
+
"Prerequisites and setup",
|
|
25560
|
+
"Common pitfalls",
|
|
25561
|
+
"Examples and use cases",
|
|
25562
|
+
"Troubleshooting guide",
|
|
25563
|
+
"Related resources"
|
|
25564
|
+
],
|
|
25565
|
+
outputSuggestions: [
|
|
25566
|
+
"Getting started guide",
|
|
25567
|
+
"Step-by-step tutorial",
|
|
25568
|
+
"FAQ section",
|
|
25569
|
+
"Troubleshooting guide"
|
|
25570
|
+
]
|
|
25571
|
+
},
|
|
25572
|
+
epic: {
|
|
25573
|
+
category: "epic",
|
|
25574
|
+
role: "Technical Project Manager and Architect",
|
|
25575
|
+
perspective: "You are planning and coordinating a large initiative.",
|
|
25576
|
+
focus: [
|
|
25577
|
+
"Scope definition",
|
|
25578
|
+
"Task breakdown",
|
|
25579
|
+
"Dependencies",
|
|
25580
|
+
"Risk assessment",
|
|
25581
|
+
"Timeline considerations",
|
|
25582
|
+
"Success metrics"
|
|
25583
|
+
],
|
|
25584
|
+
outputSuggestions: [
|
|
25585
|
+
"Epic breakdown into stories",
|
|
25586
|
+
"Dependency graph",
|
|
25587
|
+
"Risk mitigation plan",
|
|
25588
|
+
"Success criteria"
|
|
25589
|
+
]
|
|
25590
|
+
},
|
|
25591
|
+
custom: {
|
|
25592
|
+
category: "custom",
|
|
25593
|
+
role: "Software Engineer",
|
|
25594
|
+
perspective: "You are working on a software task.",
|
|
25595
|
+
focus: [
|
|
25596
|
+
"Understanding requirements",
|
|
25597
|
+
"Implementation approach",
|
|
25598
|
+
"Quality considerations",
|
|
25599
|
+
"Testing strategy"
|
|
25600
|
+
],
|
|
25601
|
+
outputSuggestions: [
|
|
25602
|
+
"Implementation plan",
|
|
25603
|
+
"Technical notes",
|
|
25604
|
+
"Task checklist"
|
|
25605
|
+
]
|
|
25606
|
+
}
|
|
25607
|
+
};
|
|
25608
|
+
var VARIANT_INSTRUCTIONS = {
|
|
25609
|
+
analysis: `ANALYSIS MODE: Analyze this task thoroughly. Identify requirements, constraints, edge cases, and potential challenges. Do NOT implement anything yet - focus on understanding and planning.`,
|
|
25610
|
+
draft: `DRAFT MODE: Create a detailed implementation plan with code structure, key decisions, and approach. Include pseudocode or skeleton code where helpful. This is for review before full implementation.`,
|
|
25611
|
+
execute: `EXECUTE MODE: Implement this task completely. Write production-ready code following best practices. Include necessary tests and documentation.`
|
|
25612
|
+
};
|
|
25613
|
+
function inferCategoryFromLabels(labels) {
|
|
25614
|
+
for (const label of labels) {
|
|
25615
|
+
const normalizedName = label.name.toLowerCase().trim();
|
|
25616
|
+
if (LABEL_CATEGORY_MAP[normalizedName]) {
|
|
25617
|
+
return LABEL_CATEGORY_MAP[normalizedName];
|
|
25618
|
+
}
|
|
25619
|
+
for (const [key, category] of Object.entries(LABEL_CATEGORY_MAP)) {
|
|
25620
|
+
if (normalizedName.includes(key) || key.includes(normalizedName)) {
|
|
25621
|
+
return category;
|
|
25622
|
+
}
|
|
25623
|
+
}
|
|
25624
|
+
}
|
|
25625
|
+
return "custom";
|
|
25626
|
+
}
|
|
25627
|
+
function getRoleFraming(category) {
|
|
25628
|
+
return DEFAULT_ROLE_FRAMINGS[category];
|
|
25629
|
+
}
|
|
25630
|
+
function estimateTokens(text) {
|
|
25631
|
+
return Math.ceil(text.length / 4);
|
|
25632
|
+
}
|
|
25633
|
+
function formatSubtasks(subtasks) {
|
|
25634
|
+
if (subtasks.length === 0)
|
|
25635
|
+
return "";
|
|
25636
|
+
const completed = subtasks.filter((s) => s.completed).length;
|
|
25637
|
+
const lines = subtasks.map((s) => ` ${s.completed ? "[x]" : "[ ]"} ${s.title}`);
|
|
25638
|
+
return `
|
|
25639
|
+
## Subtasks (${completed}/${subtasks.length} completed)
|
|
25640
|
+
${lines.join(`
|
|
25641
|
+
`)}`;
|
|
25642
|
+
}
|
|
25643
|
+
function formatLabels(labels) {
|
|
25644
|
+
if (labels.length === 0)
|
|
25645
|
+
return "";
|
|
25646
|
+
return `
|
|
25647
|
+
**Labels:** ${labels.map((l) => l.name).join(", ")}`;
|
|
25648
|
+
}
|
|
25649
|
+
function formatLinkedCards(links) {
|
|
25650
|
+
if (!links || links.length === 0)
|
|
25651
|
+
return "";
|
|
25652
|
+
const lines = links.map((link) => {
|
|
25653
|
+
const prefix = link.direction === "outgoing" ? "->" : "<-";
|
|
25654
|
+
return ` ${prefix} #${link.target_card.short_id}: ${link.target_card.title} (${link.display_type})`;
|
|
25655
|
+
});
|
|
25656
|
+
return `
|
|
25657
|
+
## Related Cards
|
|
25658
|
+
${lines.join(`
|
|
25659
|
+
`)}`;
|
|
25660
|
+
}
|
|
25661
|
+
function generatePrompt(options) {
|
|
25662
|
+
const { card, column, variant, customConstraints } = options;
|
|
25663
|
+
const contextOpts = {
|
|
25664
|
+
includeTitle: true,
|
|
25665
|
+
includeDescription: true,
|
|
25666
|
+
includeLabels: true,
|
|
25667
|
+
includeSubtasks: true,
|
|
25668
|
+
includeActivity: false,
|
|
25669
|
+
includeAssignee: true,
|
|
25670
|
+
includeDueDate: true,
|
|
25671
|
+
includePriority: true,
|
|
25672
|
+
includeLinks: true,
|
|
25673
|
+
includeColumn: true,
|
|
25674
|
+
...options.contextOptions
|
|
25675
|
+
};
|
|
25676
|
+
const labels = card.labels || [];
|
|
25677
|
+
const subtasks = card.subtasks || [];
|
|
25678
|
+
const links = card.links || [];
|
|
25679
|
+
const category = inferCategoryFromLabels(labels);
|
|
25680
|
+
const roleFraming = getRoleFraming(category);
|
|
25681
|
+
const sections = [];
|
|
25682
|
+
sections.push(`# Role: ${roleFraming.role}
|
|
25683
|
+
`);
|
|
25684
|
+
sections.push(roleFraming.perspective);
|
|
25685
|
+
sections.push("");
|
|
25686
|
+
sections.push(VARIANT_INSTRUCTIONS[variant]);
|
|
25687
|
+
sections.push("");
|
|
25688
|
+
sections.push(`# Task: ${card.title}`);
|
|
25689
|
+
if (contextOpts.includeColumn && column) {
|
|
25690
|
+
sections.push(`**Status:** ${column.name}`);
|
|
25691
|
+
}
|
|
25692
|
+
if (contextOpts.includePriority) {
|
|
25693
|
+
sections.push(`**Priority:** ${card.priority}`);
|
|
25694
|
+
}
|
|
25695
|
+
if (contextOpts.includeDueDate && card.due_date) {
|
|
25696
|
+
sections.push(`**Due:** ${card.due_date}`);
|
|
25697
|
+
}
|
|
25698
|
+
if (contextOpts.includeAssignee && card.assignee) {
|
|
25699
|
+
sections.push(`**Assignee:** ${card.assignee.full_name || card.assignee.email}`);
|
|
25700
|
+
}
|
|
25701
|
+
if (contextOpts.includeLabels && labels.length > 0) {
|
|
25702
|
+
sections.push(formatLabels(labels));
|
|
25703
|
+
}
|
|
25704
|
+
if (contextOpts.includeDescription && card.description) {
|
|
25705
|
+
sections.push(`
|
|
25706
|
+
## Description
|
|
25707
|
+
${card.description}`);
|
|
25708
|
+
}
|
|
25709
|
+
if (contextOpts.includeSubtasks && subtasks.length > 0) {
|
|
25710
|
+
sections.push(formatSubtasks(subtasks));
|
|
25711
|
+
}
|
|
25712
|
+
if (contextOpts.includeLinks && links.length > 0) {
|
|
25713
|
+
sections.push(formatLinkedCards(links));
|
|
25714
|
+
}
|
|
25715
|
+
sections.push(`
|
|
25716
|
+
## Focus Areas`);
|
|
25717
|
+
roleFraming.focus.forEach((f) => {
|
|
25718
|
+
sections.push(`- ${f}`);
|
|
25719
|
+
});
|
|
25720
|
+
sections.push(`
|
|
25721
|
+
## Suggested Outputs`);
|
|
25722
|
+
roleFraming.outputSuggestions.forEach((s) => {
|
|
25723
|
+
sections.push(`- ${s}`);
|
|
25724
|
+
});
|
|
25725
|
+
if (customConstraints) {
|
|
25726
|
+
sections.push(`
|
|
25727
|
+
## Additional Instructions
|
|
25728
|
+
${customConstraints}`);
|
|
25729
|
+
}
|
|
25730
|
+
sections.push(`
|
|
25731
|
+
---
|
|
25732
|
+
*Card #${card.short_id} | Generated for ${variant} mode*`);
|
|
25733
|
+
const prompt = sections.join(`
|
|
25734
|
+
`);
|
|
25735
|
+
return {
|
|
25736
|
+
prompt,
|
|
25737
|
+
variant,
|
|
25738
|
+
category,
|
|
25739
|
+
role: roleFraming.role,
|
|
25740
|
+
contextSummary: {
|
|
25741
|
+
hasDescription: !!card.description,
|
|
25742
|
+
labelCount: labels.length,
|
|
25743
|
+
subtaskCount: subtasks.length,
|
|
25744
|
+
completedSubtasks: subtasks.filter((s) => s.completed).length,
|
|
25745
|
+
linkedCardCount: links.length
|
|
25746
|
+
},
|
|
25747
|
+
tokenEstimate: estimateTokens(prompt)
|
|
25748
|
+
};
|
|
25749
|
+
}
|
|
25750
|
+
|
|
25436
25751
|
// src/server.ts
|
|
25437
25752
|
var TOOLS = {
|
|
25438
25753
|
harmony_create_card: {
|
|
@@ -25596,6 +25911,42 @@ var TOOLS = {
|
|
|
25596
25911
|
required: ["cardId", "labelId"]
|
|
25597
25912
|
}
|
|
25598
25913
|
},
|
|
25914
|
+
harmony_add_link_to_card: {
|
|
25915
|
+
description: "Create a link between two cards. Link types: relates_to, blocks, duplicates, is_part_of",
|
|
25916
|
+
inputSchema: {
|
|
25917
|
+
type: "object",
|
|
25918
|
+
properties: {
|
|
25919
|
+
sourceCardId: { type: "string", description: "The card creating the link from" },
|
|
25920
|
+
targetCardId: { type: "string", description: "The card being linked to" },
|
|
25921
|
+
linkType: {
|
|
25922
|
+
type: "string",
|
|
25923
|
+
enum: ["relates_to", "blocks", "duplicates", "is_part_of"],
|
|
25924
|
+
description: "Type of relationship: relates_to (generic), blocks (source blocks target), duplicates (source duplicates target), is_part_of (source is part of target)"
|
|
25925
|
+
}
|
|
25926
|
+
},
|
|
25927
|
+
required: ["sourceCardId", "targetCardId", "linkType"]
|
|
25928
|
+
}
|
|
25929
|
+
},
|
|
25930
|
+
harmony_remove_link_from_card: {
|
|
25931
|
+
description: "Remove a link between cards",
|
|
25932
|
+
inputSchema: {
|
|
25933
|
+
type: "object",
|
|
25934
|
+
properties: {
|
|
25935
|
+
linkId: { type: "string", description: "The link ID to remove" }
|
|
25936
|
+
},
|
|
25937
|
+
required: ["linkId"]
|
|
25938
|
+
}
|
|
25939
|
+
},
|
|
25940
|
+
harmony_get_card_links: {
|
|
25941
|
+
description: "Get all links for a card",
|
|
25942
|
+
inputSchema: {
|
|
25943
|
+
type: "object",
|
|
25944
|
+
properties: {
|
|
25945
|
+
cardId: { type: "string", description: "Card ID to get links for" }
|
|
25946
|
+
},
|
|
25947
|
+
required: ["cardId"]
|
|
25948
|
+
}
|
|
25949
|
+
},
|
|
25599
25950
|
harmony_create_subtask: {
|
|
25600
25951
|
description: "Create a subtask on a card",
|
|
25601
25952
|
inputSchema: {
|
|
@@ -25759,6 +26110,27 @@ var TOOLS = {
|
|
|
25759
26110
|
},
|
|
25760
26111
|
required: ["cardId"]
|
|
25761
26112
|
}
|
|
26113
|
+
},
|
|
26114
|
+
harmony_generate_prompt: {
|
|
26115
|
+
description: "Generate an AI-ready prompt from a card. Automatically infers role and focus based on labels (bug, feature, design, etc.). Use this to create context-rich prompts for working on cards.",
|
|
26116
|
+
inputSchema: {
|
|
26117
|
+
type: "object",
|
|
26118
|
+
properties: {
|
|
26119
|
+
cardId: { type: "string", description: "Card ID (UUID) to generate prompt from" },
|
|
26120
|
+
shortId: { type: "number", description: "Card short ID (e.g., 42 for #42) - alternative to cardId" },
|
|
26121
|
+
projectId: { type: "string", description: "Project ID (required if using shortId, optional if context set)" },
|
|
26122
|
+
variant: {
|
|
26123
|
+
type: "string",
|
|
26124
|
+
enum: ["analysis", "draft", "execute"],
|
|
26125
|
+
description: "Prompt variant: analysis (understand/plan), draft (design solution), execute (implement fully). Default: execute"
|
|
26126
|
+
},
|
|
26127
|
+
includeSubtasks: { type: "boolean", description: "Include subtasks in prompt (default: true)" },
|
|
26128
|
+
includeLinks: { type: "boolean", description: "Include linked cards in prompt (default: true)" },
|
|
26129
|
+
includeDescription: { type: "boolean", description: "Include description in prompt (default: true)" },
|
|
26130
|
+
customConstraints: { type: "string", description: "Additional instructions to append to the prompt" }
|
|
26131
|
+
},
|
|
26132
|
+
required: []
|
|
26133
|
+
}
|
|
25762
26134
|
}
|
|
25763
26135
|
};
|
|
25764
26136
|
var RESOURCES = [
|
|
@@ -26001,6 +26373,23 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
26001
26373
|
await client2.removeLabelFromCard(cardId, labelId);
|
|
26002
26374
|
return { success: true };
|
|
26003
26375
|
}
|
|
26376
|
+
case "harmony_add_link_to_card": {
|
|
26377
|
+
const sourceCardId = exports_external.string().uuid().parse(args.sourceCardId);
|
|
26378
|
+
const targetCardId = exports_external.string().uuid().parse(args.targetCardId);
|
|
26379
|
+
const linkType = exports_external.enum(["relates_to", "blocks", "duplicates", "is_part_of"]).parse(args.linkType);
|
|
26380
|
+
const result = await client2.addLinkToCard(sourceCardId, targetCardId, linkType);
|
|
26381
|
+
return { success: true, ...result };
|
|
26382
|
+
}
|
|
26383
|
+
case "harmony_remove_link_from_card": {
|
|
26384
|
+
const linkId = exports_external.string().uuid().parse(args.linkId);
|
|
26385
|
+
await client2.removeLinkFromCard(linkId);
|
|
26386
|
+
return { success: true };
|
|
26387
|
+
}
|
|
26388
|
+
case "harmony_get_card_links": {
|
|
26389
|
+
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
26390
|
+
const result = await client2.getCardLinks(cardId);
|
|
26391
|
+
return result;
|
|
26392
|
+
}
|
|
26004
26393
|
case "harmony_create_subtask": {
|
|
26005
26394
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
26006
26395
|
const title = exports_external.string().min(1).parse(args.title);
|
|
@@ -26118,6 +26507,61 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
26118
26507
|
});
|
|
26119
26508
|
return { success: true, ...result };
|
|
26120
26509
|
}
|
|
26510
|
+
case "harmony_generate_prompt": {
|
|
26511
|
+
let cardData;
|
|
26512
|
+
let columnData = null;
|
|
26513
|
+
if (args.cardId) {
|
|
26514
|
+
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
26515
|
+
const cardResult = await client2.getCard(cardId);
|
|
26516
|
+
cardData = cardResult.card;
|
|
26517
|
+
} else if (args.shortId !== undefined) {
|
|
26518
|
+
const shortId = exports_external.number().int().positive().parse(args.shortId);
|
|
26519
|
+
const projectId = args.projectId || getActiveProjectId();
|
|
26520
|
+
if (!projectId) {
|
|
26521
|
+
throw new Error("Project ID required when using shortId. Use harmony_set_project_context or provide projectId.");
|
|
26522
|
+
}
|
|
26523
|
+
const cardResult = await client2.getCardByShortId(projectId, shortId);
|
|
26524
|
+
cardData = cardResult.card;
|
|
26525
|
+
} else {
|
|
26526
|
+
throw new Error("Either cardId or shortId must be provided");
|
|
26527
|
+
}
|
|
26528
|
+
const projectIdForBoard = args.projectId || getActiveProjectId() || cardData.project_id;
|
|
26529
|
+
if (projectIdForBoard) {
|
|
26530
|
+
try {
|
|
26531
|
+
const board = await client2.getBoard(projectIdForBoard, { summary: true });
|
|
26532
|
+
const columnId = cardData.column_id;
|
|
26533
|
+
const column = board.columns.find((col) => col.id === columnId);
|
|
26534
|
+
if (column) {
|
|
26535
|
+
columnData = { name: column.name };
|
|
26536
|
+
}
|
|
26537
|
+
} catch {}
|
|
26538
|
+
}
|
|
26539
|
+
const variant = args.variant || "execute";
|
|
26540
|
+
const contextOptions = {};
|
|
26541
|
+
if (args.includeSubtasks !== undefined) {
|
|
26542
|
+
contextOptions.includeSubtasks = args.includeSubtasks === true || args.includeSubtasks === "true";
|
|
26543
|
+
}
|
|
26544
|
+
if (args.includeLinks !== undefined) {
|
|
26545
|
+
contextOptions.includeLinks = args.includeLinks === true || args.includeLinks === "true";
|
|
26546
|
+
}
|
|
26547
|
+
if (args.includeDescription !== undefined) {
|
|
26548
|
+
contextOptions.includeDescription = args.includeDescription === true || args.includeDescription === "true";
|
|
26549
|
+
}
|
|
26550
|
+
const result = generatePrompt({
|
|
26551
|
+
card: cardData,
|
|
26552
|
+
column: columnData,
|
|
26553
|
+
variant,
|
|
26554
|
+
contextOptions,
|
|
26555
|
+
customConstraints: args.customConstraints
|
|
26556
|
+
});
|
|
26557
|
+
return {
|
|
26558
|
+
success: true,
|
|
26559
|
+
cardId: cardData.id,
|
|
26560
|
+
shortId: cardData.short_id,
|
|
26561
|
+
title: cardData.title,
|
|
26562
|
+
...result
|
|
26563
|
+
};
|
|
26564
|
+
}
|
|
26121
26565
|
default:
|
|
26122
26566
|
throw new Error(`Unknown tool: ${name}`);
|
|
26123
26567
|
}
|
package/dist/index.js
CHANGED
|
@@ -23146,6 +23146,15 @@ class HarmonyApiClient {
|
|
|
23146
23146
|
async removeLabelFromCard(cardId, labelId) {
|
|
23147
23147
|
return this.request("DELETE", `/cards/${cardId}/labels/${labelId}`);
|
|
23148
23148
|
}
|
|
23149
|
+
async addLinkToCard(sourceCardId, targetCardId, linkType) {
|
|
23150
|
+
return this.request("POST", `/cards/${sourceCardId}/links`, { targetCardId, linkType });
|
|
23151
|
+
}
|
|
23152
|
+
async removeLinkFromCard(linkId) {
|
|
23153
|
+
return this.request("DELETE", `/card-links/${linkId}`);
|
|
23154
|
+
}
|
|
23155
|
+
async getCardLinks(cardId) {
|
|
23156
|
+
return this.request("GET", `/cards/${cardId}/links`);
|
|
23157
|
+
}
|
|
23149
23158
|
async createColumn(projectId, name) {
|
|
23150
23159
|
return this.request("POST", "/columns", { projectId, name });
|
|
23151
23160
|
}
|
|
@@ -23195,6 +23204,312 @@ function getClient() {
|
|
|
23195
23204
|
return client;
|
|
23196
23205
|
}
|
|
23197
23206
|
|
|
23207
|
+
// src/prompt-builder.ts
|
|
23208
|
+
var LABEL_CATEGORY_MAP = {
|
|
23209
|
+
bug: "bug",
|
|
23210
|
+
fix: "bug",
|
|
23211
|
+
hotfix: "bug",
|
|
23212
|
+
defect: "bug",
|
|
23213
|
+
issue: "bug",
|
|
23214
|
+
error: "bug",
|
|
23215
|
+
feature: "feature",
|
|
23216
|
+
enhancement: "feature",
|
|
23217
|
+
improvement: "feature",
|
|
23218
|
+
new: "feature",
|
|
23219
|
+
design: "design",
|
|
23220
|
+
ui: "design",
|
|
23221
|
+
ux: "design",
|
|
23222
|
+
frontend: "design",
|
|
23223
|
+
styling: "design",
|
|
23224
|
+
review: "review",
|
|
23225
|
+
"code review": "review",
|
|
23226
|
+
pr: "review",
|
|
23227
|
+
feedback: "review",
|
|
23228
|
+
onboarding: "onboarding",
|
|
23229
|
+
documentation: "onboarding",
|
|
23230
|
+
docs: "onboarding",
|
|
23231
|
+
guide: "onboarding",
|
|
23232
|
+
tutorial: "onboarding",
|
|
23233
|
+
epic: "epic",
|
|
23234
|
+
initiative: "epic",
|
|
23235
|
+
project: "epic",
|
|
23236
|
+
milestone: "epic"
|
|
23237
|
+
};
|
|
23238
|
+
var DEFAULT_ROLE_FRAMINGS = {
|
|
23239
|
+
bug: {
|
|
23240
|
+
category: "bug",
|
|
23241
|
+
role: "Senior QA Engineer and Software Developer",
|
|
23242
|
+
perspective: "You are investigating and fixing a bug report.",
|
|
23243
|
+
focus: [
|
|
23244
|
+
"Root cause analysis",
|
|
23245
|
+
"Steps to reproduce",
|
|
23246
|
+
"Impact assessment",
|
|
23247
|
+
"Fix implementation",
|
|
23248
|
+
"Regression prevention",
|
|
23249
|
+
"Test cases to prevent recurrence"
|
|
23250
|
+
],
|
|
23251
|
+
outputSuggestions: [
|
|
23252
|
+
"Bug triage summary",
|
|
23253
|
+
"Root cause explanation",
|
|
23254
|
+
"Fix implementation plan",
|
|
23255
|
+
"Test cases"
|
|
23256
|
+
]
|
|
23257
|
+
},
|
|
23258
|
+
feature: {
|
|
23259
|
+
category: "feature",
|
|
23260
|
+
role: "Product Engineer",
|
|
23261
|
+
perspective: "You are implementing a new feature or enhancement.",
|
|
23262
|
+
focus: [
|
|
23263
|
+
"User requirements",
|
|
23264
|
+
"Technical specification",
|
|
23265
|
+
"Implementation approach",
|
|
23266
|
+
"Edge cases",
|
|
23267
|
+
"Acceptance criteria",
|
|
23268
|
+
"Integration points"
|
|
23269
|
+
],
|
|
23270
|
+
outputSuggestions: [
|
|
23271
|
+
"Technical specification",
|
|
23272
|
+
"Implementation tasks",
|
|
23273
|
+
"Acceptance criteria checklist",
|
|
23274
|
+
"API design"
|
|
23275
|
+
]
|
|
23276
|
+
},
|
|
23277
|
+
design: {
|
|
23278
|
+
category: "design",
|
|
23279
|
+
role: "UX Designer and Frontend Developer",
|
|
23280
|
+
perspective: "You are designing and implementing a user interface.",
|
|
23281
|
+
focus: [
|
|
23282
|
+
"User experience flow",
|
|
23283
|
+
"Visual design consistency",
|
|
23284
|
+
"Accessibility (WCAG)",
|
|
23285
|
+
"Responsive behavior",
|
|
23286
|
+
"Component architecture",
|
|
23287
|
+
"Interaction patterns"
|
|
23288
|
+
],
|
|
23289
|
+
outputSuggestions: [
|
|
23290
|
+
"User flow diagram",
|
|
23291
|
+
"Component specifications",
|
|
23292
|
+
"Accessibility checklist",
|
|
23293
|
+
"Responsive breakpoints"
|
|
23294
|
+
]
|
|
23295
|
+
},
|
|
23296
|
+
review: {
|
|
23297
|
+
category: "review",
|
|
23298
|
+
role: "Code Reviewer and Technical Lead",
|
|
23299
|
+
perspective: "You are reviewing code for quality, correctness, and maintainability.",
|
|
23300
|
+
focus: [
|
|
23301
|
+
"Code correctness",
|
|
23302
|
+
"Performance implications",
|
|
23303
|
+
"Security considerations",
|
|
23304
|
+
"Testing coverage",
|
|
23305
|
+
"Documentation",
|
|
23306
|
+
"Best practices adherence"
|
|
23307
|
+
],
|
|
23308
|
+
outputSuggestions: [
|
|
23309
|
+
"Review checklist",
|
|
23310
|
+
"Suggested improvements",
|
|
23311
|
+
"Test scenarios",
|
|
23312
|
+
"Security audit"
|
|
23313
|
+
]
|
|
23314
|
+
},
|
|
23315
|
+
onboarding: {
|
|
23316
|
+
category: "onboarding",
|
|
23317
|
+
role: "Technical Writer and Developer Advocate",
|
|
23318
|
+
perspective: "You are creating documentation or onboarding materials.",
|
|
23319
|
+
focus: [
|
|
23320
|
+
"Clear step-by-step instructions",
|
|
23321
|
+
"Prerequisites and setup",
|
|
23322
|
+
"Common pitfalls",
|
|
23323
|
+
"Examples and use cases",
|
|
23324
|
+
"Troubleshooting guide",
|
|
23325
|
+
"Related resources"
|
|
23326
|
+
],
|
|
23327
|
+
outputSuggestions: [
|
|
23328
|
+
"Getting started guide",
|
|
23329
|
+
"Step-by-step tutorial",
|
|
23330
|
+
"FAQ section",
|
|
23331
|
+
"Troubleshooting guide"
|
|
23332
|
+
]
|
|
23333
|
+
},
|
|
23334
|
+
epic: {
|
|
23335
|
+
category: "epic",
|
|
23336
|
+
role: "Technical Project Manager and Architect",
|
|
23337
|
+
perspective: "You are planning and coordinating a large initiative.",
|
|
23338
|
+
focus: [
|
|
23339
|
+
"Scope definition",
|
|
23340
|
+
"Task breakdown",
|
|
23341
|
+
"Dependencies",
|
|
23342
|
+
"Risk assessment",
|
|
23343
|
+
"Timeline considerations",
|
|
23344
|
+
"Success metrics"
|
|
23345
|
+
],
|
|
23346
|
+
outputSuggestions: [
|
|
23347
|
+
"Epic breakdown into stories",
|
|
23348
|
+
"Dependency graph",
|
|
23349
|
+
"Risk mitigation plan",
|
|
23350
|
+
"Success criteria"
|
|
23351
|
+
]
|
|
23352
|
+
},
|
|
23353
|
+
custom: {
|
|
23354
|
+
category: "custom",
|
|
23355
|
+
role: "Software Engineer",
|
|
23356
|
+
perspective: "You are working on a software task.",
|
|
23357
|
+
focus: [
|
|
23358
|
+
"Understanding requirements",
|
|
23359
|
+
"Implementation approach",
|
|
23360
|
+
"Quality considerations",
|
|
23361
|
+
"Testing strategy"
|
|
23362
|
+
],
|
|
23363
|
+
outputSuggestions: [
|
|
23364
|
+
"Implementation plan",
|
|
23365
|
+
"Technical notes",
|
|
23366
|
+
"Task checklist"
|
|
23367
|
+
]
|
|
23368
|
+
}
|
|
23369
|
+
};
|
|
23370
|
+
var VARIANT_INSTRUCTIONS = {
|
|
23371
|
+
analysis: `ANALYSIS MODE: Analyze this task thoroughly. Identify requirements, constraints, edge cases, and potential challenges. Do NOT implement anything yet - focus on understanding and planning.`,
|
|
23372
|
+
draft: `DRAFT MODE: Create a detailed implementation plan with code structure, key decisions, and approach. Include pseudocode or skeleton code where helpful. This is for review before full implementation.`,
|
|
23373
|
+
execute: `EXECUTE MODE: Implement this task completely. Write production-ready code following best practices. Include necessary tests and documentation.`
|
|
23374
|
+
};
|
|
23375
|
+
function inferCategoryFromLabels(labels) {
|
|
23376
|
+
for (const label of labels) {
|
|
23377
|
+
const normalizedName = label.name.toLowerCase().trim();
|
|
23378
|
+
if (LABEL_CATEGORY_MAP[normalizedName]) {
|
|
23379
|
+
return LABEL_CATEGORY_MAP[normalizedName];
|
|
23380
|
+
}
|
|
23381
|
+
for (const [key, category] of Object.entries(LABEL_CATEGORY_MAP)) {
|
|
23382
|
+
if (normalizedName.includes(key) || key.includes(normalizedName)) {
|
|
23383
|
+
return category;
|
|
23384
|
+
}
|
|
23385
|
+
}
|
|
23386
|
+
}
|
|
23387
|
+
return "custom";
|
|
23388
|
+
}
|
|
23389
|
+
function getRoleFraming(category) {
|
|
23390
|
+
return DEFAULT_ROLE_FRAMINGS[category];
|
|
23391
|
+
}
|
|
23392
|
+
function estimateTokens(text) {
|
|
23393
|
+
return Math.ceil(text.length / 4);
|
|
23394
|
+
}
|
|
23395
|
+
function formatSubtasks(subtasks) {
|
|
23396
|
+
if (subtasks.length === 0)
|
|
23397
|
+
return "";
|
|
23398
|
+
const completed = subtasks.filter((s) => s.completed).length;
|
|
23399
|
+
const lines = subtasks.map((s) => ` ${s.completed ? "[x]" : "[ ]"} ${s.title}`);
|
|
23400
|
+
return `
|
|
23401
|
+
## Subtasks (${completed}/${subtasks.length} completed)
|
|
23402
|
+
${lines.join(`
|
|
23403
|
+
`)}`;
|
|
23404
|
+
}
|
|
23405
|
+
function formatLabels(labels) {
|
|
23406
|
+
if (labels.length === 0)
|
|
23407
|
+
return "";
|
|
23408
|
+
return `
|
|
23409
|
+
**Labels:** ${labels.map((l) => l.name).join(", ")}`;
|
|
23410
|
+
}
|
|
23411
|
+
function formatLinkedCards(links) {
|
|
23412
|
+
if (!links || links.length === 0)
|
|
23413
|
+
return "";
|
|
23414
|
+
const lines = links.map((link) => {
|
|
23415
|
+
const prefix = link.direction === "outgoing" ? "->" : "<-";
|
|
23416
|
+
return ` ${prefix} #${link.target_card.short_id}: ${link.target_card.title} (${link.display_type})`;
|
|
23417
|
+
});
|
|
23418
|
+
return `
|
|
23419
|
+
## Related Cards
|
|
23420
|
+
${lines.join(`
|
|
23421
|
+
`)}`;
|
|
23422
|
+
}
|
|
23423
|
+
function generatePrompt(options) {
|
|
23424
|
+
const { card, column, variant, customConstraints } = options;
|
|
23425
|
+
const contextOpts = {
|
|
23426
|
+
includeTitle: true,
|
|
23427
|
+
includeDescription: true,
|
|
23428
|
+
includeLabels: true,
|
|
23429
|
+
includeSubtasks: true,
|
|
23430
|
+
includeActivity: false,
|
|
23431
|
+
includeAssignee: true,
|
|
23432
|
+
includeDueDate: true,
|
|
23433
|
+
includePriority: true,
|
|
23434
|
+
includeLinks: true,
|
|
23435
|
+
includeColumn: true,
|
|
23436
|
+
...options.contextOptions
|
|
23437
|
+
};
|
|
23438
|
+
const labels = card.labels || [];
|
|
23439
|
+
const subtasks = card.subtasks || [];
|
|
23440
|
+
const links = card.links || [];
|
|
23441
|
+
const category = inferCategoryFromLabels(labels);
|
|
23442
|
+
const roleFraming = getRoleFraming(category);
|
|
23443
|
+
const sections = [];
|
|
23444
|
+
sections.push(`# Role: ${roleFraming.role}
|
|
23445
|
+
`);
|
|
23446
|
+
sections.push(roleFraming.perspective);
|
|
23447
|
+
sections.push("");
|
|
23448
|
+
sections.push(VARIANT_INSTRUCTIONS[variant]);
|
|
23449
|
+
sections.push("");
|
|
23450
|
+
sections.push(`# Task: ${card.title}`);
|
|
23451
|
+
if (contextOpts.includeColumn && column) {
|
|
23452
|
+
sections.push(`**Status:** ${column.name}`);
|
|
23453
|
+
}
|
|
23454
|
+
if (contextOpts.includePriority) {
|
|
23455
|
+
sections.push(`**Priority:** ${card.priority}`);
|
|
23456
|
+
}
|
|
23457
|
+
if (contextOpts.includeDueDate && card.due_date) {
|
|
23458
|
+
sections.push(`**Due:** ${card.due_date}`);
|
|
23459
|
+
}
|
|
23460
|
+
if (contextOpts.includeAssignee && card.assignee) {
|
|
23461
|
+
sections.push(`**Assignee:** ${card.assignee.full_name || card.assignee.email}`);
|
|
23462
|
+
}
|
|
23463
|
+
if (contextOpts.includeLabels && labels.length > 0) {
|
|
23464
|
+
sections.push(formatLabels(labels));
|
|
23465
|
+
}
|
|
23466
|
+
if (contextOpts.includeDescription && card.description) {
|
|
23467
|
+
sections.push(`
|
|
23468
|
+
## Description
|
|
23469
|
+
${card.description}`);
|
|
23470
|
+
}
|
|
23471
|
+
if (contextOpts.includeSubtasks && subtasks.length > 0) {
|
|
23472
|
+
sections.push(formatSubtasks(subtasks));
|
|
23473
|
+
}
|
|
23474
|
+
if (contextOpts.includeLinks && links.length > 0) {
|
|
23475
|
+
sections.push(formatLinkedCards(links));
|
|
23476
|
+
}
|
|
23477
|
+
sections.push(`
|
|
23478
|
+
## Focus Areas`);
|
|
23479
|
+
roleFraming.focus.forEach((f) => {
|
|
23480
|
+
sections.push(`- ${f}`);
|
|
23481
|
+
});
|
|
23482
|
+
sections.push(`
|
|
23483
|
+
## Suggested Outputs`);
|
|
23484
|
+
roleFraming.outputSuggestions.forEach((s) => {
|
|
23485
|
+
sections.push(`- ${s}`);
|
|
23486
|
+
});
|
|
23487
|
+
if (customConstraints) {
|
|
23488
|
+
sections.push(`
|
|
23489
|
+
## Additional Instructions
|
|
23490
|
+
${customConstraints}`);
|
|
23491
|
+
}
|
|
23492
|
+
sections.push(`
|
|
23493
|
+
---
|
|
23494
|
+
*Card #${card.short_id} | Generated for ${variant} mode*`);
|
|
23495
|
+
const prompt = sections.join(`
|
|
23496
|
+
`);
|
|
23497
|
+
return {
|
|
23498
|
+
prompt,
|
|
23499
|
+
variant,
|
|
23500
|
+
category,
|
|
23501
|
+
role: roleFraming.role,
|
|
23502
|
+
contextSummary: {
|
|
23503
|
+
hasDescription: !!card.description,
|
|
23504
|
+
labelCount: labels.length,
|
|
23505
|
+
subtaskCount: subtasks.length,
|
|
23506
|
+
completedSubtasks: subtasks.filter((s) => s.completed).length,
|
|
23507
|
+
linkedCardCount: links.length
|
|
23508
|
+
},
|
|
23509
|
+
tokenEstimate: estimateTokens(prompt)
|
|
23510
|
+
};
|
|
23511
|
+
}
|
|
23512
|
+
|
|
23198
23513
|
// src/server.ts
|
|
23199
23514
|
var TOOLS = {
|
|
23200
23515
|
harmony_create_card: {
|
|
@@ -23358,6 +23673,42 @@ var TOOLS = {
|
|
|
23358
23673
|
required: ["cardId", "labelId"]
|
|
23359
23674
|
}
|
|
23360
23675
|
},
|
|
23676
|
+
harmony_add_link_to_card: {
|
|
23677
|
+
description: "Create a link between two cards. Link types: relates_to, blocks, duplicates, is_part_of",
|
|
23678
|
+
inputSchema: {
|
|
23679
|
+
type: "object",
|
|
23680
|
+
properties: {
|
|
23681
|
+
sourceCardId: { type: "string", description: "The card creating the link from" },
|
|
23682
|
+
targetCardId: { type: "string", description: "The card being linked to" },
|
|
23683
|
+
linkType: {
|
|
23684
|
+
type: "string",
|
|
23685
|
+
enum: ["relates_to", "blocks", "duplicates", "is_part_of"],
|
|
23686
|
+
description: "Type of relationship: relates_to (generic), blocks (source blocks target), duplicates (source duplicates target), is_part_of (source is part of target)"
|
|
23687
|
+
}
|
|
23688
|
+
},
|
|
23689
|
+
required: ["sourceCardId", "targetCardId", "linkType"]
|
|
23690
|
+
}
|
|
23691
|
+
},
|
|
23692
|
+
harmony_remove_link_from_card: {
|
|
23693
|
+
description: "Remove a link between cards",
|
|
23694
|
+
inputSchema: {
|
|
23695
|
+
type: "object",
|
|
23696
|
+
properties: {
|
|
23697
|
+
linkId: { type: "string", description: "The link ID to remove" }
|
|
23698
|
+
},
|
|
23699
|
+
required: ["linkId"]
|
|
23700
|
+
}
|
|
23701
|
+
},
|
|
23702
|
+
harmony_get_card_links: {
|
|
23703
|
+
description: "Get all links for a card",
|
|
23704
|
+
inputSchema: {
|
|
23705
|
+
type: "object",
|
|
23706
|
+
properties: {
|
|
23707
|
+
cardId: { type: "string", description: "Card ID to get links for" }
|
|
23708
|
+
},
|
|
23709
|
+
required: ["cardId"]
|
|
23710
|
+
}
|
|
23711
|
+
},
|
|
23361
23712
|
harmony_create_subtask: {
|
|
23362
23713
|
description: "Create a subtask on a card",
|
|
23363
23714
|
inputSchema: {
|
|
@@ -23521,6 +23872,27 @@ var TOOLS = {
|
|
|
23521
23872
|
},
|
|
23522
23873
|
required: ["cardId"]
|
|
23523
23874
|
}
|
|
23875
|
+
},
|
|
23876
|
+
harmony_generate_prompt: {
|
|
23877
|
+
description: "Generate an AI-ready prompt from a card. Automatically infers role and focus based on labels (bug, feature, design, etc.). Use this to create context-rich prompts for working on cards.",
|
|
23878
|
+
inputSchema: {
|
|
23879
|
+
type: "object",
|
|
23880
|
+
properties: {
|
|
23881
|
+
cardId: { type: "string", description: "Card ID (UUID) to generate prompt from" },
|
|
23882
|
+
shortId: { type: "number", description: "Card short ID (e.g., 42 for #42) - alternative to cardId" },
|
|
23883
|
+
projectId: { type: "string", description: "Project ID (required if using shortId, optional if context set)" },
|
|
23884
|
+
variant: {
|
|
23885
|
+
type: "string",
|
|
23886
|
+
enum: ["analysis", "draft", "execute"],
|
|
23887
|
+
description: "Prompt variant: analysis (understand/plan), draft (design solution), execute (implement fully). Default: execute"
|
|
23888
|
+
},
|
|
23889
|
+
includeSubtasks: { type: "boolean", description: "Include subtasks in prompt (default: true)" },
|
|
23890
|
+
includeLinks: { type: "boolean", description: "Include linked cards in prompt (default: true)" },
|
|
23891
|
+
includeDescription: { type: "boolean", description: "Include description in prompt (default: true)" },
|
|
23892
|
+
customConstraints: { type: "string", description: "Additional instructions to append to the prompt" }
|
|
23893
|
+
},
|
|
23894
|
+
required: []
|
|
23895
|
+
}
|
|
23524
23896
|
}
|
|
23525
23897
|
};
|
|
23526
23898
|
var RESOURCES = [
|
|
@@ -23763,6 +24135,23 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
23763
24135
|
await client2.removeLabelFromCard(cardId, labelId);
|
|
23764
24136
|
return { success: true };
|
|
23765
24137
|
}
|
|
24138
|
+
case "harmony_add_link_to_card": {
|
|
24139
|
+
const sourceCardId = exports_external.string().uuid().parse(args.sourceCardId);
|
|
24140
|
+
const targetCardId = exports_external.string().uuid().parse(args.targetCardId);
|
|
24141
|
+
const linkType = exports_external.enum(["relates_to", "blocks", "duplicates", "is_part_of"]).parse(args.linkType);
|
|
24142
|
+
const result = await client2.addLinkToCard(sourceCardId, targetCardId, linkType);
|
|
24143
|
+
return { success: true, ...result };
|
|
24144
|
+
}
|
|
24145
|
+
case "harmony_remove_link_from_card": {
|
|
24146
|
+
const linkId = exports_external.string().uuid().parse(args.linkId);
|
|
24147
|
+
await client2.removeLinkFromCard(linkId);
|
|
24148
|
+
return { success: true };
|
|
24149
|
+
}
|
|
24150
|
+
case "harmony_get_card_links": {
|
|
24151
|
+
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
24152
|
+
const result = await client2.getCardLinks(cardId);
|
|
24153
|
+
return result;
|
|
24154
|
+
}
|
|
23766
24155
|
case "harmony_create_subtask": {
|
|
23767
24156
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
23768
24157
|
const title = exports_external.string().min(1).parse(args.title);
|
|
@@ -23880,6 +24269,61 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
23880
24269
|
});
|
|
23881
24270
|
return { success: true, ...result };
|
|
23882
24271
|
}
|
|
24272
|
+
case "harmony_generate_prompt": {
|
|
24273
|
+
let cardData;
|
|
24274
|
+
let columnData = null;
|
|
24275
|
+
if (args.cardId) {
|
|
24276
|
+
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
24277
|
+
const cardResult = await client2.getCard(cardId);
|
|
24278
|
+
cardData = cardResult.card;
|
|
24279
|
+
} else if (args.shortId !== undefined) {
|
|
24280
|
+
const shortId = exports_external.number().int().positive().parse(args.shortId);
|
|
24281
|
+
const projectId = args.projectId || getActiveProjectId();
|
|
24282
|
+
if (!projectId) {
|
|
24283
|
+
throw new Error("Project ID required when using shortId. Use harmony_set_project_context or provide projectId.");
|
|
24284
|
+
}
|
|
24285
|
+
const cardResult = await client2.getCardByShortId(projectId, shortId);
|
|
24286
|
+
cardData = cardResult.card;
|
|
24287
|
+
} else {
|
|
24288
|
+
throw new Error("Either cardId or shortId must be provided");
|
|
24289
|
+
}
|
|
24290
|
+
const projectIdForBoard = args.projectId || getActiveProjectId() || cardData.project_id;
|
|
24291
|
+
if (projectIdForBoard) {
|
|
24292
|
+
try {
|
|
24293
|
+
const board = await client2.getBoard(projectIdForBoard, { summary: true });
|
|
24294
|
+
const columnId = cardData.column_id;
|
|
24295
|
+
const column = board.columns.find((col) => col.id === columnId);
|
|
24296
|
+
if (column) {
|
|
24297
|
+
columnData = { name: column.name };
|
|
24298
|
+
}
|
|
24299
|
+
} catch {}
|
|
24300
|
+
}
|
|
24301
|
+
const variant = args.variant || "execute";
|
|
24302
|
+
const contextOptions = {};
|
|
24303
|
+
if (args.includeSubtasks !== undefined) {
|
|
24304
|
+
contextOptions.includeSubtasks = args.includeSubtasks === true || args.includeSubtasks === "true";
|
|
24305
|
+
}
|
|
24306
|
+
if (args.includeLinks !== undefined) {
|
|
24307
|
+
contextOptions.includeLinks = args.includeLinks === true || args.includeLinks === "true";
|
|
24308
|
+
}
|
|
24309
|
+
if (args.includeDescription !== undefined) {
|
|
24310
|
+
contextOptions.includeDescription = args.includeDescription === true || args.includeDescription === "true";
|
|
24311
|
+
}
|
|
24312
|
+
const result = generatePrompt({
|
|
24313
|
+
card: cardData,
|
|
24314
|
+
column: columnData,
|
|
24315
|
+
variant,
|
|
24316
|
+
contextOptions,
|
|
24317
|
+
customConstraints: args.customConstraints
|
|
24318
|
+
});
|
|
24319
|
+
return {
|
|
24320
|
+
success: true,
|
|
24321
|
+
cardId: cardData.id,
|
|
24322
|
+
shortId: cardData.short_id,
|
|
24323
|
+
title: cardData.title,
|
|
24324
|
+
...result
|
|
24325
|
+
};
|
|
24326
|
+
}
|
|
23883
24327
|
default:
|
|
23884
24328
|
throw new Error(`Unknown tool: ${name}`);
|
|
23885
24329
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harmony-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/Way/getharmony
|
|
16
|
+
"url": "https://github.com/Way/getharmony"
|
|
17
17
|
},
|
|
18
18
|
"homepage": "https://gethmy.com",
|
|
19
19
|
"bugs": {
|