@gethmy/mcp 2.1.0 → 2.1.2

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,5 +1,5 @@
1
- import { existsSync, readFileSync, readdirSync, statSync, } from "node:fs";
2
- import { join } from "node:path";
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, resolve, sep } from "node:path";
3
3
  import * as p from "@clack/prompts";
4
4
  import { colors, symbols } from "./theme.js";
5
5
  // ── Helpers ─────────────────────────────────────────────────────────────────
@@ -141,8 +141,12 @@ export function scanProject(cwd) {
141
141
  let framework = null;
142
142
  if (pkg) {
143
143
  const deps = {
144
- ...(typeof pkg.dependencies === "object" ? pkg.dependencies : {}),
145
- ...(typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}),
144
+ ...(typeof pkg.dependencies === "object"
145
+ ? pkg.dependencies
146
+ : {}),
147
+ ...(typeof pkg.devDependencies === "object"
148
+ ? pkg.devDependencies
149
+ : {}),
146
150
  };
147
151
  if (deps.next) {
148
152
  framework = "next";
@@ -305,7 +309,11 @@ function describeScript(name) {
305
309
  * Generate a scaffold AGENTS.md from project metadata.
306
310
  */
307
311
  export function generateAgentsMd(info, _cwd) {
308
- const lang = info.language === "typescript" ? "TypeScript" : info.language === "javascript" ? "JavaScript" : info.language;
312
+ const lang = info.language === "typescript"
313
+ ? "TypeScript"
314
+ : info.language === "javascript"
315
+ ? "JavaScript"
316
+ : info.language;
309
317
  const frameworkLabel = info.framework ? `${info.framework} ` : "";
310
318
  const monoLabel = info.monorepo ? " (monorepo)" : "";
311
319
  const lines = [];
@@ -404,19 +412,63 @@ export function generateArchitectureMd(info, _cwd) {
404
412
  return lines.join("\n");
405
413
  }
406
414
  // ── Verification ────────────────────────────────────────────────────────────
415
+ /** Vague phrases that provide no actionable guidance to agents. */
416
+ const VAGUE_STANDARDS = [
417
+ "follow best practices",
418
+ "use best practices",
419
+ "keep it clean",
420
+ "write clean code",
421
+ "maintain code quality",
422
+ "ensure quality",
423
+ "use proper naming",
424
+ "follow conventions",
425
+ "be consistent",
426
+ ];
407
427
  /**
408
- * Verify existing docs for broken references, stale commands, and dead paths.
428
+ * Verify existing docs for broken references, stale commands, dead paths,
429
+ * and structural quality issues from the setup-agent-docs quality checks.
409
430
  */
410
431
  export function verifyDocs(cwd) {
411
432
  const issues = [];
412
- // 1. CLAUDE.md — check @-references
413
433
  const claudeMd = readText(join(cwd, "CLAUDE.md"));
434
+ const agentsMd = readText(join(cwd, "AGENTS.md"));
435
+ const pkg = readJson(join(cwd, "package.json"));
436
+ const pkgScripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null
437
+ ? pkg.scripts
438
+ : {};
439
+ // ── CLAUDE.md checks ──────────────────────────────────────────────────
440
+ const projectRoot = resolve(cwd);
414
441
  if (claudeMd) {
442
+ // Check @-references exist on disk (with path traversal protection)
443
+ const importedFiles = [];
415
444
  for (const line of claudeMd.split("\n")) {
416
445
  const match = line.match(/^@(.+)$/);
417
446
  if (match) {
418
447
  const refPath = match[1].trim();
419
- if (!existsSync(join(cwd, refPath))) {
448
+ // Reject absolute paths
449
+ if (isAbsolute(refPath)) {
450
+ issues.push({
451
+ severity: "error",
452
+ file: "CLAUDE.md",
453
+ message: `@ reference uses an absolute path: ${refPath}`,
454
+ fix: "Use a project-relative path under the repository root",
455
+ });
456
+ continue;
457
+ }
458
+ // Resolve and ensure the path stays inside the project root
459
+ const resolvedPath = resolve(projectRoot, refPath);
460
+ if (resolvedPath !== projectRoot &&
461
+ !resolvedPath.startsWith(projectRoot + sep)) {
462
+ issues.push({
463
+ severity: "error",
464
+ file: "CLAUDE.md",
465
+ message: `@ reference escapes project root: ${refPath}`,
466
+ fix: "Remove traversal segments (../) and keep references inside the repo",
467
+ });
468
+ continue;
469
+ }
470
+ importedFiles.push({ ref: refPath, resolved: resolvedPath });
471
+ if (!existsSync(resolvedPath)) {
420
472
  issues.push({
421
473
  severity: "error",
422
474
  file: "CLAUDE.md",
@@ -426,26 +478,96 @@ export function verifyDocs(cwd) {
426
478
  }
427
479
  }
428
480
  }
481
+ // Line count — CLAUDE.md should be under 100 lines (lean, @imports only)
482
+ const claudeLines = claudeMd.split("\n").length;
483
+ if (claudeLines > 100) {
484
+ issues.push({
485
+ severity: "warning",
486
+ file: "CLAUDE.md",
487
+ message: `CLAUDE.md is ${claudeLines} lines (recommended: under 100)`,
488
+ fix: "Move detailed content to AGENTS.md or docs/ files and use @imports",
489
+ });
490
+ }
491
+ // Duplication — check if CLAUDE.md duplicates content from imported files
492
+ if (importedFiles.length > 0) {
493
+ const claudeHeadings = extractHeadings(claudeMd);
494
+ for (const { ref: refPath, resolved: resolvedPath } of importedFiles) {
495
+ const refContent = readText(resolvedPath);
496
+ if (!refContent)
497
+ continue;
498
+ const refHeadings = extractHeadings(refContent);
499
+ // Flag if CLAUDE.md repeats section headings from imported files
500
+ for (const heading of claudeHeadings) {
501
+ if (refHeadings.has(heading)) {
502
+ issues.push({
503
+ severity: "warning",
504
+ file: "CLAUDE.md",
505
+ message: `Section "${heading}" duplicates content from @${refPath}`,
506
+ fix: `Remove the "${heading}" section — it's already included via @import`,
507
+ });
508
+ }
509
+ }
510
+ }
511
+ }
429
512
  }
430
- // 2. AGENTS.md check commands against package.json scripts
431
- const agentsMd = readText(join(cwd, "AGENTS.md"));
432
- const pkg = readJson(join(cwd, "package.json"));
433
- const pkgScripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null
434
- ? pkg.scripts
435
- : {};
513
+ // ── AGENTS.md checks ──────────────────────────────────────────────────
436
514
  if (agentsMd) {
437
- // Extract commands from code blocks
515
+ // Project Context first non-heading, non-blank line should be exactly one line
516
+ const agentsLines = agentsMd.split("\n");
517
+ const contextLines = [];
518
+ let pastFirstHeading = false;
519
+ let hitNextSection = false;
520
+ for (const line of agentsLines) {
521
+ if (!pastFirstHeading) {
522
+ if (line.startsWith("# ")) {
523
+ pastFirstHeading = true;
524
+ }
525
+ continue;
526
+ }
527
+ // Stop at next ## heading
528
+ if (line.startsWith("## ")) {
529
+ hitNextSection = true;
530
+ break;
531
+ }
532
+ const trimmed = line.trim();
533
+ if (trimmed)
534
+ contextLines.push(trimmed);
535
+ }
536
+ if (pastFirstHeading && !hitNextSection && contextLines.length === 0) {
537
+ issues.push({
538
+ severity: "warning",
539
+ file: "AGENTS.md",
540
+ message: "Missing project context line after the title heading",
541
+ fix: "Add a single-line description: stack + what the project does",
542
+ });
543
+ }
544
+ else if (contextLines.length > 1) {
545
+ issues.push({
546
+ severity: "warning",
547
+ file: "AGENTS.md",
548
+ message: `Project context should be exactly 1 line, found ${contextLines.length}`,
549
+ fix: "Condense to a single line: stack + what the project does",
550
+ });
551
+ }
552
+ // Commands — check against package.json scripts
438
553
  const codeBlockRe = /```[\s\S]*?```/g;
439
554
  let blockMatch;
440
555
  while ((blockMatch = codeBlockRe.exec(agentsMd)) !== null) {
441
556
  const block = blockMatch[0];
442
- // Match lines that look like package manager commands
443
557
  const cmdRe = /(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?(\S+)/g;
444
558
  let cmdMatch;
445
559
  while ((cmdMatch = cmdRe.exec(block)) !== null) {
446
560
  const scriptName = cmdMatch[1];
447
- // Skip if the script name is a built-in (install, init, etc.)
448
- const builtins = new Set(["install", "init", "create", "exec", "dlx", "x", "test", "start"]);
561
+ const builtins = new Set([
562
+ "install",
563
+ "init",
564
+ "create",
565
+ "exec",
566
+ "dlx",
567
+ "x",
568
+ "test",
569
+ "start",
570
+ ]);
449
571
  if (builtins.has(scriptName))
450
572
  continue;
451
573
  if (Object.keys(pkgScripts).length > 0 && !(scriptName in pkgScripts)) {
@@ -458,27 +580,91 @@ export function verifyDocs(cwd) {
458
580
  }
459
581
  }
460
582
  }
461
- // 3. Check backtick-quoted paths in AGENTS.md
583
+ // Code Standards flag vague, non-actionable phrases
584
+ const standardsSection = extractSection(agentsMd, "Code Standards");
585
+ if (standardsSection) {
586
+ const lower = standardsSection.toLowerCase();
587
+ for (const phrase of VAGUE_STANDARDS) {
588
+ if (lower.includes(phrase)) {
589
+ issues.push({
590
+ severity: "warning",
591
+ file: "AGENTS.md",
592
+ message: `Code Standards contains vague phrase: "${phrase}"`,
593
+ fix: "Replace with specific, verifiable conventions derived from config files",
594
+ });
595
+ }
596
+ }
597
+ }
598
+ // Missing test command — if no test script exists, AGENTS.md should say so
599
+ if (Object.keys(pkgScripts).length > 0) {
600
+ const hasTestScript = Object.keys(pkgScripts).some((k) => k === "test" || k.startsWith("test:"));
601
+ if (!hasTestScript) {
602
+ const mentionsNoTest = agentsMd.toLowerCase().includes("no test");
603
+ if (!mentionsNoTest) {
604
+ issues.push({
605
+ severity: "warning",
606
+ file: "AGENTS.md",
607
+ message: "No test script in package.json and AGENTS.md doesn't mention it",
608
+ fix: 'Add a note like "No test framework. Verify changes with `bun run build`."',
609
+ });
610
+ }
611
+ }
612
+ }
613
+ // Check backtick-quoted paths
462
614
  checkBacktickPaths(agentsMd, "AGENTS.md", cwd, issues);
463
615
  }
464
- // 3b. Check backtick-quoted paths in docs/architecture.md
616
+ // ── docs/architecture.md checks ───────────────────────────────────────
465
617
  const archMd = readText(join(cwd, "docs", "architecture.md"));
466
618
  if (archMd) {
467
619
  checkBacktickPaths(archMd, "docs/architecture.md", cwd, issues);
468
620
  }
469
621
  return issues;
470
622
  }
623
+ /** Extract ## headings from markdown content. */
624
+ function extractHeadings(content) {
625
+ const headings = new Set();
626
+ for (const line of content.split("\n")) {
627
+ const match = line.match(/^#{2,3}\s+(.+)$/);
628
+ if (match) {
629
+ headings.add(match[1].trim());
630
+ }
631
+ }
632
+ return headings;
633
+ }
634
+ /** Extract content under a specific ## section heading. */
635
+ function extractSection(content, heading) {
636
+ const lines = content.split("\n");
637
+ let capturing = false;
638
+ const result = [];
639
+ for (const line of lines) {
640
+ if (capturing) {
641
+ // Stop at next ## heading
642
+ if (line.match(/^#{1,2}\s/))
643
+ break;
644
+ result.push(line);
645
+ }
646
+ else if (line.match(new RegExp(`^##\\s+${heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "i"))) {
647
+ capturing = true;
648
+ }
649
+ }
650
+ return result.length > 0 ? result.join("\n") : null;
651
+ }
471
652
  /** Scan markdown for backtick-quoted paths and check they exist. */
472
653
  function checkBacktickPaths(content, file, cwd, issues) {
473
654
  const pathRe = /`((?:src\/|packages\/|apps\/|supabase\/|docs\/)[^`]+)`/g;
474
655
  let match;
475
656
  const checked = new Set();
657
+ const root = resolve(cwd);
476
658
  while ((match = pathRe.exec(content)) !== null) {
477
659
  const refPath = match[1].replace(/\/$/, ""); // strip trailing slash
478
660
  if (checked.has(refPath))
479
661
  continue;
480
662
  checked.add(refPath);
481
- if (!existsSync(join(cwd, refPath))) {
663
+ // Skip paths that escape the project root (e.g. src/../../etc/hosts)
664
+ const resolvedRef = resolve(root, refPath);
665
+ if (resolvedRef !== root && !resolvedRef.startsWith(root + sep))
666
+ continue;
667
+ if (!existsSync(resolvedRef)) {
482
668
  issues.push({
483
669
  severity: "warning",
484
670
  file,
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
  import * as p from "@clack/prompts";
5
5
  import { areSkillsInstalled, getConfigPath, getLocalConfigPath, hasProjectContext, isConfigured, loadConfig, saveLocalConfig, } from "../config.js";
6
+ import { buildSkillFile, HARMONY_WORKFLOW_PROMPT } from "../skills.js";
6
7
  import { detectAgents } from "./agents.js";
7
8
  import { runDocsStep } from "./docs.js";
8
9
  import { colors, formatPath, messages } from "./theme.js";
@@ -11,296 +12,6 @@ import { getWriteSummary, writeFilesWithProgress } from "./writer.js";
11
12
  const GLOBAL_SKILLS_DIR = join(homedir(), ".agents", "skills");
12
13
  // API base URL
13
14
  const API_URL = "https://gethmy.com/api";
14
- // Harmony workflow prompt - shared across agents
15
- const HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
16
-
17
- Start work on a Harmony card. Card reference: $ARGUMENTS
18
-
19
- ## 1. Find & Fetch Card
20
-
21
- Parse the reference and fetch the card:
22
- - \`#42\` or \`42\` → \`harmony_get_card_by_short_id\` with \`shortId: 42\`
23
- - UUID → \`harmony_get_card\` with \`cardId\`
24
- - Name/text → \`harmony_search_cards\` with \`query\`
25
-
26
- ## 2. Get Board State
27
-
28
- Call \`harmony_get_board\` to get columns and labels. From the response:
29
- - Find the "In Progress" (or "Progress") column ID
30
- - Find the "agent" label ID
31
-
32
- ## 3. Setup Card for Work
33
-
34
- Execute these in sequence:
35
- 1. \`harmony_move_card\` → Move to "In Progress" column
36
- 2. \`harmony_add_label_to_card\` → Add "agent" label
37
- 3. \`harmony_start_agent_session\`:
38
- - \`cardId\`: Card UUID
39
- - \`agentIdentifier\`: Your agent identifier
40
- - \`agentName\`: Your agent name
41
- - \`currentTask\`: "Analyzing card requirements"
42
-
43
- ## 4. Generate Work Prompt
44
-
45
- Call \`harmony_generate_prompt\` with:
46
- - \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
47
- - \`variant\`: Select based on task:
48
- - \`"execute"\` (default) → Clear tasks, bug fixes, well-defined work
49
- - \`"analysis"\` → Complex features, unclear requirements
50
- - \`"draft"\` → Medium complexity, want feedback first
51
-
52
- The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
53
-
54
- ## 5. Display Card Summary
55
-
56
- Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
57
-
58
- ## 6. Implement Solution
59
-
60
- Work on the card following the generated prompt's guidance. Update progress at milestones:
61
- - \`harmony_update_agent_progress\` with \`progressPercent\` (0-100), \`currentTask\`, \`status\`, \`blockers\`
62
-
63
- **Progress checkpoints:** 20% (exploration), 50% (implementation), 80% (testing), 100% (done)
64
-
65
- ## 7. Complete Work
66
-
67
- When finished:
68
- 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`
69
- 2. \`harmony_move_card\` to "Review" column
70
- 3. Summarize accomplishments
71
-
72
- If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
73
-
74
- ## Key Tools Reference
75
-
76
- **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\`
77
-
78
- **Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
79
-
80
- **Labels:** \`harmony_add_label_to_card\`, \`harmony_remove_label_from_card\`, \`harmony_create_label\`
81
-
82
- **Links:** \`harmony_add_link_to_card\`, \`harmony_remove_link_from_card\`, \`harmony_get_card_links\`
83
-
84
- **Board:** \`harmony_get_board\`, \`harmony_list_projects\`, \`harmony_get_context\`, \`harmony_set_project_context\`
85
-
86
- **Sessions:** \`harmony_start_agent_session\`, \`harmony_update_agent_progress\`, \`harmony_end_agent_session\`, \`harmony_get_agent_session\`
87
-
88
- **AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
89
- `;
90
- // Harmony plan prompt - unified plan creation and execution workflow
91
- const HARMONY_PLAN_PROMPT = `# Harmony Plan Workflow
92
-
93
- Create a new plan or work on an existing one. Argument: $ARGUMENTS
94
-
95
- ## Step 1 — Detect Intent
96
-
97
- Parse \`$ARGUMENTS\` to determine the workflow:
98
-
99
- - **UUID** (contains dashes, 36 chars) → call \`harmony_get_plan\` with \`planId\` directly → **Step 2A**
100
- - **\`#N\`** (short ID) → call \`harmony_get_card_by_short_id\` to get the card, then \`harmony_get_plan\` with \`cardId\` → **Step 2A**
101
- - **Text** (anything else) → call \`harmony_list_plans\` with \`search\` set to the text
102
- - If **one match** → use it → **Step 2A**
103
- - If **multiple matches** → list them with title, status, phase, and updated date. Ask the user to pick one using \`AskUserQuestion\` → **Step 2A**
104
- - If **no matches** → ask user: "No existing plans found for '$ARGUMENTS'. Would you like to create a new plan on this topic?" → **Step 2B**
105
- - **Empty / vague topic** → **Step 2B** (create new plan)
106
-
107
- ---
108
-
109
- ## Step 2A — Work on Existing Plan
110
-
111
- ### 2A.1 — Analyze & Display
112
-
113
- Once you have the plan ID, call \`harmony_get_plan\` to fetch the full plan with tasks. Show a structured summary:
114
-
115
- \\\`\\\`\\\`
116
- ## [Plan Title]
117
- **Status:** draft/active/archived | **Phase:** plan/execute/verify/done
118
- **Tasks:** N total (X pending, Y in_progress, Z completed)
119
- **URL:** https://gethmy.com/plans/{id}
120
- \\\`\\\`\\\`
121
-
122
- If plan is in execute phase and tasks already have linked cards, note which tasks have cards and which don't.
123
-
124
- ### 2A.2 — Recall Context
125
-
126
- Call \`harmony_memory_search\` with the plan title to find related knowledge, patterns, or decisions that may inform execution.
127
-
128
- ### 2A.3 — Present Options
129
-
130
- Use \`AskUserQuestion\` to offer execution choices. Adapt options based on plan state:
131
-
132
- #### Default options (plan in \`plan\` phase):
133
-
134
- **(A) Single card** — Create one card with plan summary + link to plan. Best for simple plans.
135
- **(B) Multiple cards** — Create one card per task via \`harmony_advance_plan\`. Best for complex plans with independent tasks.
136
- **(C) Analyze only** — Review the plan and design an implementation approach. Create cards later.
137
- **(D) Skip** — Do nothing.
138
-
139
- #### If plan has no tasks:
140
- Only offer **(A) Single card**, **(C) Analyze only**, or **(D) Skip**.
141
-
142
- #### If plan is already in \`execute\` phase with existing cards:
143
- **(A) Work on existing cards** — List cards with short IDs, suggest \`/hmy #N\` to start
144
- **(B) Create cards for remaining tasks** — Only create cards for tasks without linked cards
145
- **(C) Analyze progress** — Review what's done vs remaining
146
- **(D) Skip**
147
-
148
- ### 2A.4 — Execute Choice
149
-
150
- #### Option A — Single card
151
- 1. Call \`harmony_create_card\` with:
152
- - \`title\`: Plan title
153
- - \`description\`: Brief 2-3 sentence summary of the plan + \`\\n\\n[View plan](https://gethmy.com/plans/{planId})\`
154
- - \`priority\`: based on plan task priorities (use highest)
155
- 2. Call \`harmony_update_plan\` to set \`status: "active"\`, \`workflowPhase: "execute"\`
156
-
157
- #### Option B — Multiple cards (advance plan)
158
- 1. Call \`harmony_advance_plan\` with:
159
- - \`planId\`: the plan ID
160
- - \`phase\`: \`"execute"\`
161
- - \`summary\`: Brief summary of the plan scope
162
- 2. Display the created cards with their short IDs
163
-
164
- #### Option C — Analyze only
165
- 1. Present a structured implementation analysis:
166
- - Suggested order of tasks
167
- - Dependencies between tasks
168
- - Key technical considerations from memory search
169
- - Estimated complexity
170
- 2. Suggest creating cards when ready
171
-
172
- #### Option D — Skip
173
- Acknowledge and stop.
174
-
175
- ### 2A.5 — Summary
176
-
177
- After execution, show:
178
- - Created card(s) with short IDs
179
- - Current plan phase
180
- - Suggest next step: \`/hmy #N\` to start working on a card
181
-
182
- ---
183
-
184
- ## Step 2B — Create New Plan
185
-
186
- ### 2B.1 — Context Gathering
187
-
188
- Before interviewing, gather existing context:
189
-
190
- 1. Call \`harmony_get_board\` for board state (columns, cards, labels)
191
- 2. Call \`harmony_recall\` with relevant tags to find existing knowledge on the topic
192
- 3. Call \`harmony_memory_search\` with the topic to find related patterns/decisions/lessons
193
-
194
- Note what you learn — reference it during the interview to ask smarter questions.
195
-
196
- ### 2B.2 — Structured Interview (3-5 questions)
197
-
198
- Interview the user with **3-5 focused questions** using AskUserQuestion. Adapt based on complexity.
199
-
200
- #### Core Questions
201
- 1. **Problem & Audience**: What problem are we solving? Who benefits?
202
- 2. **Scope**: What's in v1, what's deferred?
203
- 3. **Technical Constraints**: Any technical preferences, constraints, or existing patterns to follow?
204
-
205
- #### Adaptive Follow-ups (if needed)
206
- - Key user flows or interactions?
207
- - Integration points with existing systems?
208
- - Performance, security, or accessibility requirements?
209
-
210
- #### Interview Rules
211
- - Reference what you found in Step 2B.1 (board state, memories) to ask informed questions
212
- - Skip questions that aren't relevant — simple features need fewer questions
213
- - Tell the user when you have enough information to draft
214
-
215
- ### 2B.3 — Plan Document
216
-
217
- Create a structured markdown document:
218
-
219
- \\\`\\\`\\\`markdown
220
- # [Title]
221
-
222
- ## Problem
223
- [What problem we're solving and why]
224
-
225
- ## Scope
226
-
227
- ### In Scope
228
- - [Feature/capability 1]
229
- - [Feature/capability 2]
230
-
231
- ### Out of Scope
232
- - [Deferred items]
233
-
234
- ## Approach
235
- [Technical design, architecture decisions, key patterns]
236
-
237
- ### Key Decisions
238
- | Decision | Choice | Rationale |
239
- |----------|--------|-----------|
240
- | ... | ... | ... |
241
-
242
- ## Tasks
243
- 1. **[Task title]** — priority: high
244
- [Brief description]
245
-
246
- 2. **[Task title]** — priority: medium
247
- [Brief description]
248
-
249
- [Continue for all tasks...]
250
-
251
- ## Risks & Mitigations
252
- | Risk | Mitigation |
253
- |------|------------|
254
- | ... | ... |
255
-
256
- ## Success Criteria
257
- - [ ] [Measurable criterion]
258
- \\\`\\\`\\\`
259
-
260
- ### 2B.4 — Create Plan
261
-
262
- Call \`harmony_create_plan\` with:
263
- - \`title\`: The plan title
264
- - \`content\`: Full markdown document from Step 2B.3
265
- - \`source\`: \`"agent"\`
266
- - \`workflowPhase\`: \`"plan"\`
267
- - \`tasks\`: Array of tasks from the Tasks section, each with:
268
- - \`content\`: Task title + brief description
269
- - \`priority\`: \`"high"\`, \`"medium"\`, or \`"low"\`
270
- - \`status\`: \`"pending"\`
271
-
272
- ### 2B.5 — User Approval
273
-
274
- Show the user:
275
- - Plan URL: \`https://gethmy.com/plans/{id}\`
276
- - Number of tasks created
277
- - Brief summary
278
-
279
- Then ask: **"Ready to execute? I'll create board cards from these tasks and start the execution phase."**
280
-
281
- Options:
282
- 1. **Yes, advance to Execute** — proceed to Step 2B.6
283
- 2. **Let me review first** — end here, they can advance later from the UI
284
- 3. **Make changes** — iterate on the plan
285
-
286
- ### 2B.6 — Advance to Execute
287
-
288
- Call \`harmony_advance_plan\` with:
289
- - \`planId\`: The plan ID from Step 2B.4
290
- - \`phase\`: \`"execute"\`
291
- - \`summary\`: A 2-3 sentence summary of the key decisions made during planning
292
-
293
- Report the result:
294
- - "Created N cards in 'To Do'. Use \`/hmy #<id>\` to start working on any card."
295
- - List the created cards with their short IDs
296
-
297
- ## Key Tools Reference
298
-
299
- **Discovery:** \`harmony_list_plans\`, \`harmony_get_plan\`, \`harmony_get_card_by_short_id\`
300
- **Context:** \`harmony_get_board\`, \`harmony_recall\`, \`harmony_memory_search\`
301
- **Planning:** \`harmony_create_plan\`, \`harmony_advance_plan\`, \`harmony_update_plan\`
302
- **Execution:** \`harmony_create_card\`, \`harmony_update_card\`
303
- `;
304
15
  /**
305
16
  * Register MCP server using Claude CLI
306
17
  * Returns true if successful, false if CLI unavailable or failed
@@ -432,24 +143,9 @@ function getAgentFiles(agentId, cwd, installMode = "global") {
432
143
  const symlinks = [];
433
144
  switch (agentId) {
434
145
  case "claude": {
435
- // Claude Code skill file
436
- const skillContent = `---
437
- name: hmy
438
- description: Start working on a Harmony card. Use when given a card reference like #42, UUID, or card name to implement.
439
- argument-hint: <card-reference>
440
- ---
441
-
442
- ${HARMONY_WORKFLOW_PROMPT.replace("Your agent identifier", "claude-code").replace("Your agent name", "Claude Code")}
443
- `;
444
- // hmy-plan skill file (unified plan creation + execution)
445
- const planSkillContent = `---
446
- name: hmy-plan
447
- 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.
448
- argument-hint: [plan name, ID, or topic to plan]
449
- ---
450
-
451
- ${HARMONY_PLAN_PROMPT.replace("$ARGUMENTS", "$ARGUMENTS")}
452
- `;
146
+ // Claude Code skill files built from the central skill registry
147
+ const skillContent = buildSkillFile("hmy", "claude");
148
+ const planSkillContent = buildSkillFile("hmy-plan", "claude");
453
149
  if (installMode === "global") {
454
150
  // Global mode: Write skills to ~/.agents/skills/, symlink directories to ~/.claude/skills/
455
151
  files.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/mcp",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -46,7 +46,8 @@
46
46
  "coding-assistant"
47
47
  ],
48
48
  "engines": {
49
- "node": ">=18.0.0"
49
+ "node": ">=20.0.0",
50
+ "bun": ">=1.0.0"
50
51
  },
51
52
  "scripts": {
52
53
  "build": "bun build src/index.ts src/cli.ts --outdir dist --target node && tsc --outDir dist/lib --declaration false --skipLibCheck --noCheck",
@@ -68,7 +69,7 @@
68
69
  "zod": "^4.3.6"
69
70
  },
70
71
  "devDependencies": {
71
- "@types/node": "^25.2.0",
72
- "typescript": "^5.9.3"
72
+ "@types/node": "^25.5.0",
73
+ "typescript": "^6.0.1"
73
74
  }
74
75
  }