harmony-mcp 1.3.1 → 1.3.3
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/README.md +64 -39
- package/dist/cli.js +1663 -78
- package/dist/index.js +30 -69
- package/dist/init.js +112 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -23013,7 +23013,8 @@ function loadConfig() {
|
|
|
23013
23013
|
apiKey: null,
|
|
23014
23014
|
apiUrl: DEFAULT_API_URL,
|
|
23015
23015
|
activeWorkspaceId: null,
|
|
23016
|
-
activeProjectId: null
|
|
23016
|
+
activeProjectId: null,
|
|
23017
|
+
userEmail: null
|
|
23017
23018
|
};
|
|
23018
23019
|
}
|
|
23019
23020
|
try {
|
|
@@ -23023,14 +23024,16 @@ function loadConfig() {
|
|
|
23023
23024
|
apiKey: config2.apiKey || null,
|
|
23024
23025
|
apiUrl: config2.apiUrl || DEFAULT_API_URL,
|
|
23025
23026
|
activeWorkspaceId: config2.activeWorkspaceId || null,
|
|
23026
|
-
activeProjectId: config2.activeProjectId || null
|
|
23027
|
+
activeProjectId: config2.activeProjectId || null,
|
|
23028
|
+
userEmail: config2.userEmail || null
|
|
23027
23029
|
};
|
|
23028
23030
|
} catch {
|
|
23029
23031
|
return {
|
|
23030
23032
|
apiKey: null,
|
|
23031
23033
|
apiUrl: DEFAULT_API_URL,
|
|
23032
23034
|
activeWorkspaceId: null,
|
|
23033
|
-
activeProjectId: null
|
|
23035
|
+
activeProjectId: null,
|
|
23036
|
+
userEmail: null
|
|
23034
23037
|
};
|
|
23035
23038
|
}
|
|
23036
23039
|
}
|
|
@@ -23089,6 +23092,13 @@ function getApiUrl() {
|
|
|
23089
23092
|
const config2 = loadConfig();
|
|
23090
23093
|
return config2.apiUrl;
|
|
23091
23094
|
}
|
|
23095
|
+
function getUserEmail() {
|
|
23096
|
+
const config2 = loadConfig();
|
|
23097
|
+
return config2.userEmail;
|
|
23098
|
+
}
|
|
23099
|
+
function setUserEmail(email2) {
|
|
23100
|
+
saveConfig({ userEmail: email2 });
|
|
23101
|
+
}
|
|
23092
23102
|
function setActiveWorkspace(workspaceId, options) {
|
|
23093
23103
|
if (options?.local) {
|
|
23094
23104
|
saveLocalConfig({ workspaceId }, options.cwd);
|
|
@@ -23956,23 +23966,11 @@ var RESOURCES = [
|
|
|
23956
23966
|
mimeType: "application/json"
|
|
23957
23967
|
}
|
|
23958
23968
|
];
|
|
23959
|
-
var PROMPTS = {
|
|
23960
|
-
harmony_daily_standup: {
|
|
23961
|
-
name: "Daily Standup Summary",
|
|
23962
|
-
description: "Generate a summary of recent activity and current work items",
|
|
23963
|
-
arguments: [{ name: "projectId", description: "Project to summarize", required: false }]
|
|
23964
|
-
},
|
|
23965
|
-
harmony_board_cleanup: {
|
|
23966
|
-
name: "Board Cleanup Suggestions",
|
|
23967
|
-
description: "Identify stale cards and suggest cleanup actions",
|
|
23968
|
-
arguments: []
|
|
23969
|
-
}
|
|
23970
|
-
};
|
|
23971
23969
|
|
|
23972
23970
|
class HarmonyMCPServer {
|
|
23973
23971
|
server;
|
|
23974
23972
|
constructor() {
|
|
23975
|
-
this.server = new Server({ name: "harmony-mcp", version: "1.0.0" }, { capabilities: { tools: {}, resources: {}
|
|
23973
|
+
this.server = new Server({ name: "harmony-mcp", version: "1.0.0" }, { capabilities: { tools: {}, resources: {} } });
|
|
23976
23974
|
this.setupHandlers();
|
|
23977
23975
|
}
|
|
23978
23976
|
setupHandlers() {
|
|
@@ -24020,58 +24018,6 @@ class HarmonyMCPServer {
|
|
|
24020
24018
|
}
|
|
24021
24019
|
throw new Error(`Unknown resource: ${uri}`);
|
|
24022
24020
|
});
|
|
24023
|
-
this.server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
24024
|
-
prompts: Object.entries(PROMPTS).map(([name, prompt]) => ({
|
|
24025
|
-
name,
|
|
24026
|
-
description: prompt.description,
|
|
24027
|
-
arguments: prompt.arguments
|
|
24028
|
-
}))
|
|
24029
|
-
}));
|
|
24030
|
-
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
24031
|
-
const { name, arguments: args } = request.params;
|
|
24032
|
-
if (name === "harmony_daily_standup") {
|
|
24033
|
-
const projectId = args?.projectId || getActiveProjectId();
|
|
24034
|
-
if (!projectId) {
|
|
24035
|
-
return {
|
|
24036
|
-
messages: [
|
|
24037
|
-
{
|
|
24038
|
-
role: "user",
|
|
24039
|
-
content: { type: "text", text: "No project context. Please set a project first using harmony_set_project_context." }
|
|
24040
|
-
}
|
|
24041
|
-
]
|
|
24042
|
-
};
|
|
24043
|
-
}
|
|
24044
|
-
try {
|
|
24045
|
-
const client2 = getClient();
|
|
24046
|
-
const board = await client2.getBoard(projectId);
|
|
24047
|
-
return {
|
|
24048
|
-
messages: [
|
|
24049
|
-
{
|
|
24050
|
-
role: "user",
|
|
24051
|
-
content: {
|
|
24052
|
-
type: "text",
|
|
24053
|
-
text: `Generate a daily standup summary for this Harmony project board:
|
|
24054
|
-
|
|
24055
|
-
${JSON.stringify(board, null, 2)}
|
|
24056
|
-
|
|
24057
|
-
Include: cards moved recently, current in-progress items, blocked or high-priority items, and upcoming due dates.`
|
|
24058
|
-
}
|
|
24059
|
-
}
|
|
24060
|
-
]
|
|
24061
|
-
};
|
|
24062
|
-
} catch (error2) {
|
|
24063
|
-
return {
|
|
24064
|
-
messages: [
|
|
24065
|
-
{
|
|
24066
|
-
role: "user",
|
|
24067
|
-
content: { type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }
|
|
24068
|
-
}
|
|
24069
|
-
]
|
|
24070
|
-
};
|
|
24071
|
-
}
|
|
24072
|
-
}
|
|
24073
|
-
throw new Error(`Unknown prompt: ${name}`);
|
|
24074
|
-
});
|
|
24075
24021
|
}
|
|
24076
24022
|
async handleToolCall(name, args) {
|
|
24077
24023
|
if (!isConfigured()) {
|
|
@@ -24283,6 +24229,21 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
24283
24229
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
24284
24230
|
const agentIdentifier = exports_external.string().min(1).parse(args.agentIdentifier);
|
|
24285
24231
|
const agentName = exports_external.string().min(1).parse(args.agentName);
|
|
24232
|
+
let assignedTo = null;
|
|
24233
|
+
const userEmail = getUserEmail();
|
|
24234
|
+
if (userEmail) {
|
|
24235
|
+
try {
|
|
24236
|
+
const workspaceId = getActiveWorkspaceId();
|
|
24237
|
+
if (workspaceId) {
|
|
24238
|
+
const { members } = await client2.getWorkspaceMembers(workspaceId);
|
|
24239
|
+
const user = members.find((m) => m.email === userEmail);
|
|
24240
|
+
if (user) {
|
|
24241
|
+
await client2.updateCard(cardId, { assigneeId: user.id });
|
|
24242
|
+
assignedTo = user.email;
|
|
24243
|
+
}
|
|
24244
|
+
}
|
|
24245
|
+
} catch {}
|
|
24246
|
+
}
|
|
24286
24247
|
const result = await client2.startAgentSession(cardId, {
|
|
24287
24248
|
agentIdentifier,
|
|
24288
24249
|
agentName,
|
|
@@ -24290,7 +24251,7 @@ Include: cards moved recently, current in-progress items, blocked or high-priori
|
|
|
24290
24251
|
currentTask: args.currentTask,
|
|
24291
24252
|
estimatedMinutesRemaining: args.estimatedMinutesRemaining
|
|
24292
24253
|
});
|
|
24293
|
-
return { success: true, ...result };
|
|
24254
|
+
return { success: true, assignedTo, ...result };
|
|
24294
24255
|
}
|
|
24295
24256
|
case "harmony_update_agent_progress": {
|
|
24296
24257
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
package/dist/init.js
CHANGED
|
@@ -106,6 +106,94 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
|
106
106
|
|
|
107
107
|
**AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
|
|
108
108
|
`;
|
|
109
|
+
var HARMONY_STANDUP_PROMPT = `# Harmony Daily Standup
|
|
110
|
+
|
|
111
|
+
Generate a daily standup summary for the current project.
|
|
112
|
+
|
|
113
|
+
## 1. Get Board State
|
|
114
|
+
|
|
115
|
+
Call \`harmony_get_board\` to get the full board state including:
|
|
116
|
+
- All columns and their cards
|
|
117
|
+
- Card priorities, assignees, and due dates
|
|
118
|
+
- Active agent sessions
|
|
119
|
+
|
|
120
|
+
## 2. Analyze Board
|
|
121
|
+
|
|
122
|
+
Organize the information into standup categories:
|
|
123
|
+
|
|
124
|
+
### What was completed recently
|
|
125
|
+
- Cards in "Done" or "Review" columns
|
|
126
|
+
- Cards with recent activity (moved, updated)
|
|
127
|
+
|
|
128
|
+
### What's in progress
|
|
129
|
+
- Cards in "In Progress" column
|
|
130
|
+
- Cards with active agent sessions (show progress %)
|
|
131
|
+
- Who's working on what
|
|
132
|
+
|
|
133
|
+
### What's blocked or at risk
|
|
134
|
+
- High-priority cards not in progress
|
|
135
|
+
- Overdue cards
|
|
136
|
+
- Cards with blockers
|
|
137
|
+
|
|
138
|
+
### What's coming up
|
|
139
|
+
- Cards in "To Do" column
|
|
140
|
+
- Upcoming due dates
|
|
141
|
+
|
|
142
|
+
## 3. Present Summary
|
|
143
|
+
|
|
144
|
+
Format the summary as a clean, readable standup report:
|
|
145
|
+
- Use bullet points for easy scanning
|
|
146
|
+
- Highlight priorities and blockers
|
|
147
|
+
- Include card short IDs for easy reference (e.g., #42)
|
|
148
|
+
- Note any agent work in progress
|
|
149
|
+
`;
|
|
150
|
+
var HARMONY_CLEANUP_PROMPT = `# Harmony Board Cleanup
|
|
151
|
+
|
|
152
|
+
Analyze the board and suggest cleanup actions.
|
|
153
|
+
|
|
154
|
+
## 1. Get Board State
|
|
155
|
+
|
|
156
|
+
Call \`harmony_get_board\` to get the full board state.
|
|
157
|
+
|
|
158
|
+
## 2. Identify Issues
|
|
159
|
+
|
|
160
|
+
Look for:
|
|
161
|
+
|
|
162
|
+
### Stale cards
|
|
163
|
+
- Cards in "In Progress" for too long without updates
|
|
164
|
+
- Cards with past due dates
|
|
165
|
+
- Cards with no recent activity
|
|
166
|
+
|
|
167
|
+
### Organizational issues
|
|
168
|
+
- Cards missing priorities
|
|
169
|
+
- Cards missing assignees in active columns
|
|
170
|
+
- Empty descriptions on complex cards
|
|
171
|
+
|
|
172
|
+
### Potential duplicates
|
|
173
|
+
- Cards with similar titles
|
|
174
|
+
- Use \`harmony_search_cards\` if needed to find related cards
|
|
175
|
+
|
|
176
|
+
## 3. Suggest Actions
|
|
177
|
+
|
|
178
|
+
For each issue found, suggest a specific action:
|
|
179
|
+
- Move stale cards back to backlog
|
|
180
|
+
- Archive completed cards
|
|
181
|
+
- Update missing information
|
|
182
|
+
- Merge or link duplicates
|
|
183
|
+
|
|
184
|
+
Present suggestions as a prioritized list with:
|
|
185
|
+
- Card reference (#ID)
|
|
186
|
+
- Current state
|
|
187
|
+
- Suggested action
|
|
188
|
+
- Why it matters
|
|
189
|
+
|
|
190
|
+
## 4. Optional: Execute Cleanup
|
|
191
|
+
|
|
192
|
+
If the user approves, execute the suggested actions:
|
|
193
|
+
- Use \`harmony_move_card\` to reorganize
|
|
194
|
+
- Use \`harmony_update_card\` to add missing info
|
|
195
|
+
- Use \`harmony_add_link_to_card\` to link related cards
|
|
196
|
+
`;
|
|
109
197
|
function ensureDir(dirPath) {
|
|
110
198
|
if (!existsSync(dirPath)) {
|
|
111
199
|
mkdirSync(dirPath, { recursive: true });
|
|
@@ -164,6 +252,30 @@ ${HARMONY_WORKFLOW_PROMPT.replace("Your agent identifier", "claude-code").replac
|
|
|
164
252
|
result.filesCreated.push(commandPath);
|
|
165
253
|
if (skipped)
|
|
166
254
|
result.filesSkipped.push(commandPath);
|
|
255
|
+
const standupContent = `---
|
|
256
|
+
description: Generate a daily standup summary for the current Harmony project
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
${HARMONY_STANDUP_PROMPT}
|
|
260
|
+
`;
|
|
261
|
+
const standupPath = join(cwd, ".claude", "commands", "hmy-standup.md");
|
|
262
|
+
const standupResult = writeFileIfNotExists(standupPath, standupContent, force);
|
|
263
|
+
if (standupResult.created)
|
|
264
|
+
result.filesCreated.push(standupPath);
|
|
265
|
+
if (standupResult.skipped)
|
|
266
|
+
result.filesSkipped.push(standupPath);
|
|
267
|
+
const cleanupContent = `---
|
|
268
|
+
description: Analyze the Harmony board and suggest cleanup actions for stale cards
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
${HARMONY_CLEANUP_PROMPT}
|
|
272
|
+
`;
|
|
273
|
+
const cleanupPath = join(cwd, ".claude", "commands", "hmy-cleanup.md");
|
|
274
|
+
const cleanupResult = writeFileIfNotExists(cleanupPath, cleanupContent, force);
|
|
275
|
+
if (cleanupResult.created)
|
|
276
|
+
result.filesCreated.push(cleanupPath);
|
|
277
|
+
if (cleanupResult.skipped)
|
|
278
|
+
result.filesSkipped.push(cleanupPath);
|
|
167
279
|
const globalConfigPath = join(homedir(), ".claude", "settings.json");
|
|
168
280
|
const mcpConfig = {
|
|
169
281
|
mcpServers: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harmony-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
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",
|
|
@@ -44,9 +44,11 @@
|
|
|
44
44
|
"prepublishOnly": "bun run build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"@clack/prompts": "^0.9.1",
|
|
47
48
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
48
49
|
"commander": "^12.0.0",
|
|
49
50
|
"hono": "^4.0.0",
|
|
51
|
+
"picocolors": "^1.1.1",
|
|
50
52
|
"zod": "^3.23.0"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|