@gethmy/mcp 2.3.2 → 2.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.
@@ -1,776 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __create = Object.create;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __toESM = (mod, isNodeMode, target) => {
8
- target = mod != null ? __create(__getProtoOf(mod)) : {};
9
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
- for (let key of __getOwnPropNames(mod))
11
- if (!__hasOwnProp.call(to, key))
12
- __defProp(to, key, {
13
- get: () => mod[key],
14
- enumerable: true
15
- });
16
- return to;
17
- };
18
- var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
19
- var __export = (target, all) => {
20
- for (var name in all)
21
- __defProp(target, name, {
22
- get: all[name],
23
- enumerable: true,
24
- configurable: true,
25
- set: (newValue) => all[name] = () => newValue
26
- });
27
- };
28
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
-
31
- // src/config.ts
32
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
33
- import { homedir } from "node:os";
34
- import { join } from "node:path";
35
- var DEFAULT_API_URL = "https://app.gethmy.com/api";
36
- var LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";
37
- function getConfigDir() {
38
- return join(homedir(), ".harmony-mcp");
39
- }
40
- function getConfigPath() {
41
- return join(getConfigDir(), "config.json");
42
- }
43
- function getLocalConfigPath(cwd) {
44
- return join(cwd || process.cwd(), LOCAL_CONFIG_FILENAME);
45
- }
46
- function loadConfig() {
47
- const configPath = getConfigPath();
48
- if (!existsSync(configPath)) {
49
- return {
50
- apiKey: null,
51
- apiUrl: DEFAULT_API_URL,
52
- activeWorkspaceId: null,
53
- activeProjectId: null,
54
- userEmail: null,
55
- memoryDir: null
56
- };
57
- }
58
- try {
59
- const data = readFileSync(configPath, "utf-8");
60
- const config = JSON.parse(data);
61
- return {
62
- apiKey: config.apiKey || null,
63
- apiUrl: config.apiUrl || DEFAULT_API_URL,
64
- activeWorkspaceId: config.activeWorkspaceId || null,
65
- activeProjectId: config.activeProjectId || null,
66
- userEmail: config.userEmail || null,
67
- memoryDir: config.memoryDir || null
68
- };
69
- } catch {
70
- return {
71
- apiKey: null,
72
- apiUrl: DEFAULT_API_URL,
73
- activeWorkspaceId: null,
74
- activeProjectId: null,
75
- userEmail: null,
76
- memoryDir: null
77
- };
78
- }
79
- }
80
- function saveConfig(config) {
81
- const configDir = getConfigDir();
82
- const configPath = getConfigPath();
83
- if (!existsSync(configDir)) {
84
- mkdirSync(configDir, { recursive: true, mode: 448 });
85
- }
86
- const existingConfig = loadConfig();
87
- const newConfig = { ...existingConfig, ...config };
88
- writeFileSync(configPath, JSON.stringify(newConfig, null, 2), {
89
- mode: 384
90
- });
91
- }
92
- function loadLocalConfig(cwd) {
93
- const localConfigPath = getLocalConfigPath(cwd);
94
- if (!existsSync(localConfigPath)) {
95
- return null;
96
- }
97
- try {
98
- const data = readFileSync(localConfigPath, "utf-8");
99
- const config = JSON.parse(data);
100
- return {
101
- workspaceId: config.workspaceId || null,
102
- projectId: config.projectId || null
103
- };
104
- } catch {
105
- return null;
106
- }
107
- }
108
- function saveLocalConfig(config, cwd) {
109
- const localConfigPath = getLocalConfigPath(cwd);
110
- const existingConfig = loadLocalConfig(cwd) || {
111
- workspaceId: null,
112
- projectId: null
113
- };
114
- const newConfig = { ...existingConfig, ...config };
115
- const cleanConfig = {};
116
- if (newConfig.workspaceId)
117
- cleanConfig.workspaceId = newConfig.workspaceId;
118
- if (newConfig.projectId)
119
- cleanConfig.projectId = newConfig.projectId;
120
- writeFileSync(localConfigPath, JSON.stringify(cleanConfig, null, 2));
121
- }
122
- function hasLocalConfig(cwd) {
123
- return existsSync(getLocalConfigPath(cwd));
124
- }
125
- function getApiKey() {
126
- const config = loadConfig();
127
- if (!config.apiKey) {
128
- throw new Error(`Not configured. Run "npx @gethmy/mcp setup" to set your API key.
129
- ` + "You can generate an API key at https://gethmy.com → Settings → API Keys.");
130
- }
131
- return config.apiKey;
132
- }
133
- function getApiUrl() {
134
- const config = loadConfig();
135
- return config.apiUrl;
136
- }
137
- function getUserEmail() {
138
- const config = loadConfig();
139
- return config.userEmail;
140
- }
141
- function setUserEmail(email) {
142
- saveConfig({ userEmail: email });
143
- }
144
- function setActiveWorkspace(workspaceId, options) {
145
- if (options?.local) {
146
- saveLocalConfig({ workspaceId }, options.cwd);
147
- } else {
148
- saveConfig({ activeWorkspaceId: workspaceId });
149
- }
150
- }
151
- function setActiveProject(projectId, options) {
152
- if (options?.local) {
153
- saveLocalConfig({ projectId }, options.cwd);
154
- } else {
155
- saveConfig({ activeProjectId: projectId });
156
- }
157
- }
158
- function getActiveWorkspaceId(cwd) {
159
- const localConfig = loadLocalConfig(cwd);
160
- if (localConfig?.workspaceId) {
161
- return localConfig.workspaceId;
162
- }
163
- return loadConfig().activeWorkspaceId;
164
- }
165
- function getActiveProjectId(cwd) {
166
- const localConfig = loadLocalConfig(cwd);
167
- if (localConfig?.projectId) {
168
- return localConfig.projectId;
169
- }
170
- return loadConfig().activeProjectId;
171
- }
172
- function isConfigured() {
173
- const config = loadConfig();
174
- return !!config.apiKey;
175
- }
176
- function areSkillsInstalled(cwd) {
177
- const home = homedir();
178
- const workingDir = cwd || process.cwd();
179
- const foundPaths = [];
180
- const globalSkillsDir = join(home, ".agents", "skills");
181
- const globalSkillPath = join(globalSkillsDir, "hmy", "SKILL.md");
182
- if (existsSync(globalSkillPath)) {
183
- foundPaths.push(globalSkillPath);
184
- return { installed: true, location: "global", paths: foundPaths };
185
- }
186
- const claudeGlobalSkill = join(home, ".claude", "skills", "hmy.md");
187
- if (existsSync(claudeGlobalSkill)) {
188
- foundPaths.push(claudeGlobalSkill);
189
- return { installed: true, location: "global", paths: foundPaths };
190
- }
191
- const claudeGlobalSkillAlt = join(home, ".claude", "skills", "hmy", "SKILL.md");
192
- if (existsSync(claudeGlobalSkillAlt)) {
193
- foundPaths.push(claudeGlobalSkillAlt);
194
- return { installed: true, location: "global", paths: foundPaths };
195
- }
196
- const localSkillPath = join(workingDir, ".claude", "skills", "hmy.md");
197
- if (existsSync(localSkillPath)) {
198
- foundPaths.push(localSkillPath);
199
- return { installed: true, location: "local", paths: foundPaths };
200
- }
201
- const localSkillPathAlt = join(workingDir, ".claude", "skills", "hmy", "SKILL.md");
202
- if (existsSync(localSkillPathAlt)) {
203
- foundPaths.push(localSkillPathAlt);
204
- return { installed: true, location: "local", paths: foundPaths };
205
- }
206
- return { installed: false, location: null, paths: [] };
207
- }
208
- function hasProjectContext(cwd) {
209
- const localConfig = loadLocalConfig(cwd);
210
- return !!(localConfig?.workspaceId || localConfig?.projectId);
211
- }
212
- function getMemoryDir() {
213
- const config = loadConfig();
214
- if (config.memoryDir)
215
- return config.memoryDir;
216
- return join(homedir(), ".harmony", "memory");
217
- }
218
-
219
- // src/skills.ts
220
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
221
- import { dirname } from "node:path";
222
- var SKILLS_VERSION = "4";
223
- var VERSION_MARKER_PREFIX = "<!-- skills-version:";
224
- var HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
225
-
226
- Start work on a Harmony card. Card reference: $ARGUMENTS
227
-
228
- ## 1. Find & Fetch Card
229
-
230
- Parse the reference and fetch the card:
231
- - \`#42\` or \`42\` → \`harmony_get_card_by_short_id\` with \`shortId: 42\`
232
- - UUID → \`harmony_get_card\` with \`cardId\`
233
- - Name/text → \`harmony_search_cards\` with \`query\`
234
-
235
- ## 2. Get Board State
236
-
237
- Call \`harmony_get_board\` to get columns and labels. From the response:
238
- - Find the "In Progress" (or "Progress") column ID
239
- - Find the "agent" label ID
240
-
241
- ## 3. Setup Card for Work
242
-
243
- Execute these in sequence:
244
- 1. \`harmony_move_card\` → Move to "In Progress" column
245
- 2. \`harmony_add_label_to_card\` → Add "agent" label
246
- 3. \`harmony_start_agent_session\`:
247
- - \`cardId\`: Card UUID
248
- - \`agentIdentifier\`: Your agent identifier
249
- - \`agentName\`: Your agent name
250
- - \`currentTask\`: "Analyzing card requirements"
251
-
252
- ## 4. Generate Work Prompt
253
-
254
- Call \`harmony_generate_prompt\` with:
255
- - \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
256
- - \`variant\`: Select based on task:
257
- - \`"execute"\` (default) → Clear tasks, bug fixes, well-defined work
258
- - \`"analysis"\` → Complex features, unclear requirements
259
- - \`"draft"\` → Medium complexity, want feedback first
260
-
261
- The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
262
-
263
- ## 5. Display Card Summary
264
-
265
- Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
266
-
267
- ## 6. Implement Solution
268
-
269
- Work on the card following the generated prompt's guidance. Update progress at milestones:
270
- - \`harmony_update_agent_progress\` with \`progressPercent\` (0-100), \`currentTask\`, \`status\`, \`blockers\`
271
-
272
- **Progress checkpoints:** 20% (exploration), 50% (implementation), 80% (testing), 100% (done)
273
-
274
- ## 7. Complete Work
275
-
276
- When finished:
277
- 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`
278
- 2. \`harmony_move_card\` to "Review" column
279
- 3. Summarize accomplishments
280
-
281
- If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
282
-
283
- ## Key Tools Reference
284
-
285
- **Cards:** \`harmony_get_card\`, \`harmony_get_card_by_short_id\`, \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
286
-
287
- **Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
288
-
289
- **Labels:** \`harmony_add_label_to_card\`, \`harmony_remove_label_from_card\`, \`harmony_create_label\`
290
-
291
- **Links:** \`harmony_add_link_to_card\`, \`harmony_remove_link_from_card\`, \`harmony_get_card_links\`
292
-
293
- **Board:** \`harmony_get_board\`, \`harmony_list_projects\`, \`harmony_get_context\`, \`harmony_set_project_context\`
294
-
295
- **Sessions:** \`harmony_start_agent_session\`, \`harmony_update_agent_progress\`, \`harmony_end_agent_session\`, \`harmony_get_agent_session\`
296
-
297
- **AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
298
- `;
299
- var HMY_SKILL_CONTENT = `# Harmony Card Workflow
300
-
301
- User input: $ARGUMENTS
302
-
303
- ## 0. Detect Intent
304
-
305
- Parse \`$ARGUMENTS\` to determine what the user wants:
306
-
307
- | Pattern | Intent | Go to |
308
- |---|---|---|
309
- | \`create ...\` or \`new ...\` | **Create** a new card | Step A |
310
- | \`#42\`, \`42\`, UUID, or card name (no action verb) | **Work on** an existing card | Step B |
311
- | \`move #42 to Done\`, \`update #42 ...\`, \`assign #42 ...\` | **Quick action** on a card | Step C |
312
- | \`show #42\`, \`view #42\`, \`status #42\` | **View** card details | Step D |
313
-
314
- If ambiguous, ask the user what they'd like to do.
315
-
316
- ---
317
-
318
- ## Step A: Create Card
319
-
320
- Create a card without starting work on it.
321
-
322
- 1. Parse the title and any details from the arguments (e.g., \`create Add dark mode toggle\` → title: "Add dark mode toggle")
323
- 2. Call \`harmony_create_card\` with:
324
- - \`title\`: extracted title
325
- - \`description\`: if the user provided details beyond the title
326
- - \`priority\`, \`columnId\`, \`assigneeId\`: only if explicitly specified
327
- 3. Show the created card: title, short ID, column, and a link if available.
328
- 4. **Stop here.** Do not start an agent session or begin implementation.
329
-
330
- ---
331
-
332
- ## Step B: Work on Existing Card
333
-
334
- Start work on a Harmony card.
335
-
336
- ### B1. Find & Fetch Card
337
-
338
- Parse the reference and fetch the card:
339
- - \`#42\` or \`42\` → \`harmony_get_card_by_short_id\` with \`shortId: 42\`
340
- - UUID → \`harmony_get_card\` with \`cardId\`
341
- - Name/text → \`harmony_search_cards\` with \`query\`
342
-
343
- ### B2. Start Agent Session
344
-
345
- Call \`harmony_start_agent_session\` with:
346
- - \`cardId\`: Card UUID
347
- - \`agentIdentifier\`: Your agent identifier
348
- - \`agentName\`: Your agent name
349
- - \`currentTask\`: A specific description of the first thing you'll do (e.g., "Exploring codebase to understand auth flow"), NOT a generic phrase like "Analyzing card requirements"
350
- - \`moveToColumn\`: "In Progress"
351
- - \`addLabels\`: ["agent"]
352
-
353
- This single call moves the card, adds the label, auto-assigns, and starts the session.
354
-
355
- ### B3. Generate Work Prompt
356
-
357
- Call \`harmony_generate_prompt\` with:
358
- - \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
359
- - \`variant\`: Select based on task:
360
- - \`"execute"\` (default) → Clear tasks, bug fixes, well-defined work
361
- - \`"analysis"\` → Complex features, unclear requirements
362
- - \`"draft"\` → Medium complexity, want feedback first
363
-
364
- The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
365
-
366
- ### B4. Display Card Summary
367
-
368
- Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
369
-
370
- ### B5. Implement Solution
371
-
372
- Work on the card following the generated prompt's guidance.
373
-
374
- **REQUIRED: Update progress at each milestone** by calling \`harmony_update_agent_progress\`. This is not optional — the card's live status badge depends on these updates.
375
-
376
- | Milestone | \`progressPercent\` | Example \`currentTask\` |
377
- |---|---|---|
378
- | After exploring codebase & understanding requirements | 20 | "Reading auth middleware and identifying affected routes" |
379
- | When starting implementation | 50 | "Refactoring token validation in auth.ts" |
380
- | When moving to testing/verification | 80 | "Running build and verifying changes compile" |
381
- | When done, before ending session | 100 | "All changes complete, ready for review" |
382
-
383
- Always set \`currentTask\` to a specific description of what you're actually doing — never leave it as "Analyzing card requirements" or other generic text.
384
-
385
- ### B6. Complete Work
386
-
387
- When finished:
388
- 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`, \`moveToColumn: "Review"\`
389
- 2. Summarize accomplishments
390
-
391
- If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
392
-
393
- ---
394
-
395
- ## Step C: Quick Action
396
-
397
- Fetch the card first (same as B1), then perform the requested action:
398
- - **Move:** \`harmony_move_card\` with target column
399
- - **Update:** \`harmony_update_card\` with changed fields
400
- - **Assign:** \`harmony_assign_card\`
401
- - **Label:** \`harmony_add_label_to_card\` / \`harmony_remove_label_from_card\`
402
- - **Archive:** \`harmony_archive_card\`
403
-
404
- Show confirmation and stop. Do not start an agent session.
405
-
406
- ---
407
-
408
- ## Step D: View Card
409
-
410
- Fetch the card (same as B1) and display: title, short ID, column, priority, labels, assignee, due date, description, subtasks, and links.
411
-
412
- Do not start an agent session.
413
-
414
- ---
415
-
416
- ## Step E: Auto-Detect Card for Implementation Tasks
417
-
418
- **IMPORTANT:** This step applies when you are about to implement a plan, feature, or fix
419
- that was NOT started via /hmy. Before writing any code, check if the work maps to an
420
- existing Harmony card.
421
-
422
- ### When to run this check
423
- - User says "implement this plan", "build this feature", "fix this bug" (without /hmy)
424
- - You are about to execute a plan file
425
- - Skip if: the user already started with /hmy, or no Harmony MCP tools are available
426
-
427
- ### Detection steps
428
- 1. Call \`harmony_search_cards\` with keywords from the plan title or task description
429
- 2. If a card matches (same feature/fix described), tell the user:
430
- "This maps to card #N — starting a session to track progress."
431
- 3. Call \`harmony_start_agent_session\` with \`moveToColumn: "In Progress"\`, \`addLabels: ["agent"]\`
432
- 4. Track progress with \`harmony_update_agent_progress\` at milestones
433
- 5. When done, call \`harmony_end_agent_session\` with \`status: "completed"\`, \`moveToColumn: "Review"\`
434
-
435
- ### If no match
436
- Proceed normally without a session. No action needed.
437
-
438
- ---
439
-
440
- ## Key Tools Reference
441
-
442
- **Cards:** \`harmony_get_card\`, \`harmony_get_card_by_short_id\`, \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
443
-
444
- **Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
445
-
446
- **Labels:** \`harmony_add_label_to_card\`, \`harmony_remove_label_from_card\`, \`harmony_create_label\`
447
-
448
- **Links:** \`harmony_add_link_to_card\`, \`harmony_remove_link_from_card\`, \`harmony_get_card_links\`
449
-
450
- **Board:** \`harmony_get_board\`, \`harmony_list_projects\`, \`harmony_get_context\`, \`harmony_set_project_context\`
451
-
452
- **Sessions:** \`harmony_start_agent_session\`, \`harmony_update_agent_progress\`, \`harmony_end_agent_session\`, \`harmony_get_agent_session\`
453
-
454
- **AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
455
- `;
456
- var HMY_PLAN_CONTENT = `# Harmony Plan Workflow
457
-
458
- Create a new plan or work on an existing one. Argument: $ARGUMENTS
459
-
460
- ## Step 1 — Detect Intent
461
-
462
- Parse \`$ARGUMENTS\` to determine the workflow:
463
-
464
- - **UUID** (contains dashes, 36 chars) → call \`harmony_get_plan\` with \`planId\` directly → **Step 2A**
465
- - **\`#N\`** (short ID) → call \`harmony_get_card_by_short_id\` to get the card, then \`harmony_get_plan\` with \`cardId\` → **Step 2A**
466
- - **Text** (anything else) → call \`harmony_list_plans\` with \`search\` set to the text
467
- - If **one match** → use it → **Step 2A**
468
- - If **multiple matches** → list them with title, status, phase, and updated date. Ask the user to pick one using \`AskUserQuestion\` → **Step 2A**
469
- - If **no matches** → ask user: "No existing plans found for '$ARGUMENTS'. Would you like to create a new plan on this topic?" → **Step 2B**
470
- - **Empty / vague topic** → **Step 2B** (create new plan)
471
-
472
- ---
473
-
474
- ## Step 2A — Work on Existing Plan
475
-
476
- ### 2A.1 — Analyze & Display
477
-
478
- Once you have the plan ID, call \`harmony_get_plan\` to fetch the full plan with tasks. Show a structured summary:
479
-
480
- \\\`\\\`\\\`
481
- ## [Plan Title]
482
- **Status:** draft/active/archived | **Phase:** plan/execute/verify/done
483
- **Tasks:** N total (X pending, Y in_progress, Z completed)
484
- **URL:** https://app.gethmy.com/plans/{id}
485
- \\\`\\\`\\\`
486
-
487
- If plan is in execute phase and tasks already have linked cards, note which tasks have cards and which don't.
488
-
489
- ### 2A.2 — Recall Context
490
-
491
- Call \`harmony_memory_search\` with the plan title to find related knowledge, patterns, or decisions that may inform execution.
492
-
493
- ### 2A.3 — Present Options
494
-
495
- Use \`AskUserQuestion\` to offer execution choices. Adapt options based on plan state:
496
-
497
- #### Default options (plan in \`plan\` phase):
498
-
499
- **(A) Single card** — Create one card with plan summary + link to plan. Best for simple plans.
500
- **(B) Multiple cards** — Create one card per task via \`harmony_advance_plan\`. Best for complex plans with independent tasks.
501
- **(C) Analyze only** — Review the plan and design an implementation approach. Create cards later.
502
- **(D) Skip** — Do nothing.
503
-
504
- #### If plan has no tasks:
505
- Only offer **(A) Single card**, **(C) Analyze only**, or **(D) Skip**.
506
-
507
- #### If plan is already in \`execute\` phase with existing cards:
508
- **(A) Work on existing cards** — List cards with short IDs, suggest \`/hmy #N\` to start
509
- **(B) Create cards for remaining tasks** — Only create cards for tasks without linked cards
510
- **(C) Analyze progress** — Review what's done vs remaining
511
- **(D) Skip**
512
-
513
- ### 2A.4 — Execute Choice
514
-
515
- #### Option A — Single card
516
- 1. Call \`harmony_create_card\` with:
517
- - \`title\`: Plan title
518
- - \`description\`: Brief 2-3 sentence summary of the plan + \`\\n\\n[View plan](https://app.gethmy.com/plans/{planId})\`
519
- - \`priority\`: based on plan task priorities (use highest)
520
- 2. Call \`harmony_update_plan\` to set \`status: "active"\`, \`workflowPhase: "execute"\`
521
-
522
- #### Option B — Multiple cards (advance plan)
523
- 1. Call \`harmony_advance_plan\` with:
524
- - \`planId\`: the plan ID
525
- - \`phase\`: \`"execute"\`
526
- - \`summary\`: Brief summary of the plan scope
527
- 2. Display the created cards with their short IDs
528
-
529
- #### Option C — Analyze only
530
- 1. Present a structured implementation analysis:
531
- - Suggested order of tasks
532
- - Dependencies between tasks
533
- - Key technical considerations from memory search
534
- - Estimated complexity
535
- 2. Suggest creating cards when ready
536
-
537
- #### Option D — Skip
538
- Acknowledge and stop.
539
-
540
- ### 2A.5 — Summary
541
-
542
- After execution, show:
543
- - Created card(s) with short IDs
544
- - Current plan phase
545
- - Suggest next step: \`/hmy #N\` to start working on a card
546
-
547
- ---
548
-
549
- ## Step 2B — Create New Plan
550
-
551
- ### 2B.1 — Context Gathering
552
-
553
- Before interviewing, gather existing context:
554
-
555
- 1. Call \`harmony_get_board\` for board state (columns, cards, labels)
556
- 2. Call \`harmony_recall\` with relevant tags to find existing knowledge on the topic
557
- 3. Call \`harmony_memory_search\` with the topic to find related patterns/decisions/lessons
558
-
559
- Note what you learn — reference it during the interview to ask smarter questions.
560
-
561
- ### 2B.2 — Structured Interview (3-5 questions)
562
-
563
- Interview the user with **3-5 focused questions** using AskUserQuestion. Adapt based on complexity.
564
-
565
- #### Core Questions
566
- 1. **Problem & Audience**: What problem are we solving? Who benefits?
567
- 2. **Scope**: What's in v1, what's deferred?
568
- 3. **Technical Constraints**: Any technical preferences, constraints, or existing patterns to follow?
569
-
570
- #### Adaptive Follow-ups (if needed)
571
- - Key user flows or interactions?
572
- - Integration points with existing systems?
573
- - Performance, security, or accessibility requirements?
574
-
575
- #### Interview Rules
576
- - Reference what you found in Step 2B.1 (board state, memories) to ask informed questions
577
- - Skip questions that aren't relevant — simple features need fewer questions
578
- - Tell the user when you have enough information to draft
579
-
580
- ### 2B.3 — Plan Document
581
-
582
- Create a structured markdown document:
583
-
584
- \\\`\\\`\\\`markdown
585
- # [Title]
586
-
587
- ## Problem
588
- [What problem we're solving and why]
589
-
590
- ## Scope
591
-
592
- ### In Scope
593
- - [Feature/capability 1]
594
- - [Feature/capability 2]
595
-
596
- ### Out of Scope
597
- - [Deferred items]
598
-
599
- ## Approach
600
- [Technical design, architecture decisions, key patterns]
601
-
602
- ### Key Decisions
603
- | Decision | Choice | Rationale |
604
- |----------|--------|-----------|
605
- | ... | ... | ... |
606
-
607
- ## Tasks
608
- 1. **[Task title]** — priority: high
609
- [Brief description]
610
-
611
- 2. **[Task title]** — priority: medium
612
- [Brief description]
613
-
614
- [Continue for all tasks...]
615
-
616
- ## Risks & Mitigations
617
- | Risk | Mitigation |
618
- |------|------------|
619
- | ... | ... |
620
-
621
- ## Success Criteria
622
- - [ ] [Measurable criterion]
623
- \\\`\\\`\\\`
624
-
625
- ### 2B.4 — Create Plan
626
-
627
- Call \`harmony_create_plan\` with:
628
- - \`title\`: The plan title
629
- - \`content\`: Full markdown document from Step 2B.3
630
- - \`source\`: \`"agent"\`
631
- - \`workflowPhase\`: \`"plan"\`
632
- - \`tasks\`: Array of tasks from the Tasks section, each with:
633
- - \`content\`: Task title + brief description
634
- - \`priority\`: \`"high"\`, \`"medium"\`, or \`"low"\`
635
- - \`status\`: \`"pending"\`
636
-
637
- ### 2B.5 — User Approval
638
-
639
- Show the user:
640
- - Plan URL: \`https://app.gethmy.com/plans/{id}\`
641
- - Number of tasks created
642
- - Brief summary
643
-
644
- Then ask: **"Ready to execute? I'll create board cards from these tasks and start the execution phase."**
645
-
646
- Options:
647
- 1. **Yes, advance to Execute** — proceed to Step 2B.6
648
- 2. **Let me review first** — end here, they can advance later from the UI
649
- 3. **Make changes** — iterate on the plan
650
-
651
- ### 2B.6 — Advance to Execute
652
-
653
- Call \`harmony_advance_plan\` with:
654
- - \`planId\`: The plan ID from Step 2B.4
655
- - \`phase\`: \`"execute"\`
656
- - \`summary\`: A 2-3 sentence summary of the key decisions made during planning
657
-
658
- Report the result:
659
- - "Created N cards in 'To Do'. Use \`/hmy #<id>\` to start working on any card."
660
- - List the created cards with their short IDs
661
-
662
- ## Key Tools Reference
663
-
664
- **Discovery:** \`harmony_list_plans\`, \`harmony_get_plan\`, \`harmony_get_card_by_short_id\`
665
- **Context:** \`harmony_get_board\`, \`harmony_recall\`, \`harmony_memory_search\`
666
- **Planning:** \`harmony_create_plan\`, \`harmony_advance_plan\`, \`harmony_update_plan\`
667
- **Execution:** \`harmony_create_card\`, \`harmony_update_card\`
668
- `;
669
- var SKILL_DEFINITIONS = {
670
- hmy: {
671
- name: "hmy",
672
- description: "Work with Harmony cards — create, view, update, or start working on them. Use when given a card reference like #42, or commands like create, move, update.",
673
- argumentHint: "<command or card-reference>",
674
- content: HMY_SKILL_CONTENT
675
- },
676
- "hmy-plan": {
677
- name: "hmy-plan",
678
- description: "Create a new plan or work on an existing one. Use when asked to plan a feature, execute a plan, review a plan, or given a plan reference.",
679
- argumentHint: "[plan name, ID, or topic to plan]",
680
- content: HMY_PLAN_CONTENT
681
- }
682
- };
683
- function buildSkillFile(skillId, agentId) {
684
- const skill = SKILL_DEFINITIONS[skillId];
685
- if (!skill) {
686
- throw new Error(`Unknown skill: ${skillId}`);
687
- }
688
- let content = skill.content;
689
- if (agentId === "claude") {
690
- content = content.replace("Your agent identifier", "claude-code").replace("Your agent name", "Claude Code");
691
- }
692
- const frontmatter = `---
693
- name: ${skill.name}
694
- description: ${skill.description}
695
- argument-hint: ${skill.argumentHint}
696
- ---`;
697
- return `${frontmatter}
698
-
699
- ${content}
700
- ${VERSION_MARKER_PREFIX}${SKILLS_VERSION} -->`;
701
- }
702
- function parseSkillVersion(content) {
703
- const match = content.match(/<!-- skills-version:(\d+) -->/);
704
- return match ? match[1] : null;
705
- }
706
- function findSkillFiles(paths) {
707
- const results = [];
708
- for (const filePath of paths) {
709
- if (!existsSync2(filePath))
710
- continue;
711
- for (const skillId of Object.keys(SKILL_DEFINITIONS)) {
712
- if (filePath.includes(`/${skillId}/`) || filePath.includes(`/${skillId}.md`)) {
713
- results.push({ skillId, filePath });
714
- break;
715
- }
716
- }
717
- }
718
- return results;
719
- }
720
- async function refreshSkills() {
721
- try {
722
- const status = areSkillsInstalled();
723
- if (!status.installed) {
724
- return;
725
- }
726
- const skillFiles = findSkillFiles(status.paths);
727
- if (skillFiles.length > 0) {
728
- const samplePath = skillFiles[0].filePath;
729
- for (const skillId of Object.keys(SKILL_DEFINITIONS)) {
730
- const alreadyFound = skillFiles.some((sf) => sf.skillId === skillId);
731
- if (alreadyFound)
732
- continue;
733
- let siblingPath;
734
- if (samplePath.endsWith("SKILL.md")) {
735
- const parentDir = dirname(dirname(samplePath));
736
- siblingPath = `${parentDir}/${skillId}/SKILL.md`;
737
- } else {
738
- const parentDir = dirname(samplePath);
739
- siblingPath = `${parentDir}/${skillId}.md`;
740
- }
741
- if (existsSync2(siblingPath)) {
742
- skillFiles.push({ skillId, filePath: siblingPath });
743
- }
744
- }
745
- }
746
- if (skillFiles.length === 0) {
747
- return;
748
- }
749
- let updated = false;
750
- for (const { skillId, filePath } of skillFiles) {
751
- try {
752
- const currentContent = readFileSync2(filePath, "utf-8");
753
- const currentVersion = parseSkillVersion(currentContent);
754
- if (currentVersion === null || Number(currentVersion) < Number(SKILLS_VERSION)) {
755
- const newContent = buildSkillFile(skillId, "claude");
756
- const dir = dirname(filePath);
757
- if (!existsSync2(dir)) {
758
- mkdirSync2(dir, { recursive: true });
759
- }
760
- writeFileSync2(filePath, newContent);
761
- updated = true;
762
- }
763
- } catch {}
764
- }
765
- if (updated) {
766
- console.error(`Harmony: Updated skills to v${SKILLS_VERSION}`);
767
- }
768
- } catch {}
769
- }
770
- export {
771
- refreshSkills,
772
- buildSkillFile,
773
- SKILL_DEFINITIONS,
774
- SKILLS_VERSION,
775
- HARMONY_WORKFLOW_PROMPT
776
- };