@gethmy/mcp 2.0.0 → 2.1.0
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 +1 -1
- package/dist/cli.js +547 -58
- package/dist/index.js +3 -3
- package/dist/lib/__tests__/active-learning.test.js +386 -0
- package/dist/lib/__tests__/agent-performance-profiles.test.js +325 -0
- package/dist/lib/__tests__/auto-session.test.js +661 -0
- package/dist/lib/__tests__/context-assembly.test.js +362 -0
- package/dist/lib/__tests__/graph-expansion.test.js +150 -0
- package/dist/lib/__tests__/integration-memory-crud.test.js +797 -0
- package/dist/lib/__tests__/integration-memory-system.test.js +281 -0
- package/dist/lib/__tests__/lifecycle-maintenance.test.js +207 -0
- package/dist/lib/__tests__/pattern-detection.test.js +295 -0
- package/dist/lib/__tests__/prompt-builder.test.js +418 -0
- package/dist/lib/active-learning.js +878 -0
- package/dist/lib/api-client.js +548 -0
- package/dist/lib/auto-session.js +173 -0
- package/dist/lib/cli.js +127 -0
- package/dist/lib/config.js +205 -0
- package/dist/lib/consolidation.js +243 -0
- package/dist/lib/context-assembly.js +606 -0
- package/dist/lib/graph-expansion.js +163 -0
- package/dist/lib/http.js +174 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/lifecycle-maintenance.js +88 -0
- package/dist/lib/prompt-builder.js +483 -0
- package/dist/lib/remote.js +166 -0
- package/dist/lib/server.js +3132 -0
- package/dist/lib/tui/agents.js +116 -0
- package/dist/lib/tui/docs.js +558 -0
- package/dist/lib/tui/setup.js +1068 -0
- package/dist/lib/tui/theme.js +95 -0
- package/dist/lib/tui/writer.js +200 -0
- package/package.json +11 -3
- package/src/__tests__/active-learning.test.ts +483 -0
- package/src/__tests__/agent-performance-profiles.test.ts +468 -0
- package/src/__tests__/auto-session.test.ts +912 -0
- package/src/__tests__/context-assembly.test.ts +506 -0
- package/src/__tests__/graph-expansion.test.ts +285 -0
- package/src/__tests__/integration-memory-crud.test.ts +948 -0
- package/src/__tests__/integration-memory-system.test.ts +321 -0
- package/src/__tests__/lifecycle-maintenance.test.ts +238 -0
- package/src/__tests__/pattern-detection.test.ts +438 -0
- package/src/__tests__/prompt-builder.test.ts +505 -0
- package/src/active-learning.ts +1227 -0
- package/src/api-client.ts +963 -0
- package/src/auto-session.ts +218 -0
- package/src/cli.ts +166 -0
- package/src/config.ts +285 -0
- package/src/consolidation.ts +314 -0
- package/src/context-assembly.ts +842 -0
- package/src/graph-expansion.ts +234 -0
- package/src/http.ts +265 -0
- package/src/index.ts +8 -0
- package/src/lifecycle-maintenance.ts +120 -0
- package/src/prompt-builder.ts +681 -0
- package/src/remote.ts +227 -0
- package/src/server.ts +3858 -0
- package/src/tui/agents.ts +154 -0
- package/src/tui/docs.ts +650 -0
- package/src/tui/setup.ts +1281 -0
- package/src/tui/theme.ts +114 -0
- package/src/tui/writer.ts +260 -0
package/dist/cli.js
CHANGED
|
@@ -8828,7 +8828,7 @@ function hasLocalConfig(cwd) {
|
|
|
8828
8828
|
function getApiKey() {
|
|
8829
8829
|
const config = loadConfig();
|
|
8830
8830
|
if (!config.apiKey) {
|
|
8831
|
-
throw new Error(`Not configured. Run "
|
|
8831
|
+
throw new Error(`Not configured. Run "npx @gethmy/mcp setup" to set your API key.
|
|
8832
8832
|
` + "You can generate an API key at https://gethmy.com → Settings → API Keys.");
|
|
8833
8833
|
}
|
|
8834
8834
|
return config.apiKey;
|
|
@@ -29409,7 +29409,7 @@ function registerHandlers(server, deps) {
|
|
|
29409
29409
|
async function handleToolCall(name, args, deps) {
|
|
29410
29410
|
const unauthenticatedTools = ["harmony_signup", "harmony_onboard"];
|
|
29411
29411
|
if (!unauthenticatedTools.includes(name) && !deps.isConfigured()) {
|
|
29412
|
-
throw new Error(`Not configured. Run "
|
|
29412
|
+
throw new Error(`Not configured. Run "npx @gethmy/mcp setup" to set your API key.
|
|
29413
29413
|
` + `You can generate an API key at https://gethmy.com → Settings → API Keys.
|
|
29414
29414
|
` + 'Or use "harmony_onboard" to create an account and configure automatically.');
|
|
29415
29415
|
}
|
|
@@ -30704,7 +30704,7 @@ function createConfigDeps() {
|
|
|
30704
30704
|
class HarmonyMCPServer {
|
|
30705
30705
|
server;
|
|
30706
30706
|
constructor() {
|
|
30707
|
-
this.server = new Server({ name: "
|
|
30707
|
+
this.server = new Server({ name: "@gethmy/mcp", version: "2.0.0" }, { capabilities: { tools: {}, resources: {} } });
|
|
30708
30708
|
registerHandlers(this.server, createConfigDeps());
|
|
30709
30709
|
}
|
|
30710
30710
|
async run() {
|
|
@@ -30745,14 +30745,14 @@ class HarmonyMCPServer {
|
|
|
30745
30745
|
|
|
30746
30746
|
// src/tui/setup.ts
|
|
30747
30747
|
import {
|
|
30748
|
-
existsSync as
|
|
30748
|
+
existsSync as existsSync6,
|
|
30749
30749
|
lstatSync,
|
|
30750
30750
|
mkdirSync as mkdirSync4,
|
|
30751
30751
|
symlinkSync,
|
|
30752
30752
|
unlinkSync
|
|
30753
30753
|
} from "node:fs";
|
|
30754
30754
|
import { homedir as homedir4 } from "node:os";
|
|
30755
|
-
import { dirname as dirname2, join as
|
|
30755
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
30756
30756
|
|
|
30757
30757
|
// ../../node_modules/@clack/core/dist/index.mjs
|
|
30758
30758
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -31519,6 +31519,15 @@ function detectAgents(cwd = process.cwd()) {
|
|
|
31519
31519
|
});
|
|
31520
31520
|
}
|
|
31521
31521
|
|
|
31522
|
+
// src/tui/docs.ts
|
|
31523
|
+
import {
|
|
31524
|
+
existsSync as existsSync4,
|
|
31525
|
+
readFileSync as readFileSync3,
|
|
31526
|
+
readdirSync as readdirSync2,
|
|
31527
|
+
statSync
|
|
31528
|
+
} from "node:fs";
|
|
31529
|
+
import { join as join4 } from "node:path";
|
|
31530
|
+
|
|
31522
31531
|
// src/tui/theme.ts
|
|
31523
31532
|
var pc = __toESM(require_picocolors(), 1);
|
|
31524
31533
|
var symbols = {
|
|
@@ -31583,17 +31592,488 @@ function formatPath(path, homeDir) {
|
|
|
31583
31592
|
return path;
|
|
31584
31593
|
}
|
|
31585
31594
|
|
|
31595
|
+
// src/tui/docs.ts
|
|
31596
|
+
var IGNORED_DIRS = new Set([
|
|
31597
|
+
"node_modules",
|
|
31598
|
+
".git",
|
|
31599
|
+
"dist",
|
|
31600
|
+
"build",
|
|
31601
|
+
".next",
|
|
31602
|
+
".nuxt",
|
|
31603
|
+
".output",
|
|
31604
|
+
".vercel",
|
|
31605
|
+
".turbo",
|
|
31606
|
+
".cache",
|
|
31607
|
+
"coverage",
|
|
31608
|
+
".harmony-worktrees",
|
|
31609
|
+
"__pycache__",
|
|
31610
|
+
"target",
|
|
31611
|
+
"vendor"
|
|
31612
|
+
]);
|
|
31613
|
+
function readJson(filePath) {
|
|
31614
|
+
try {
|
|
31615
|
+
return JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
31616
|
+
} catch {
|
|
31617
|
+
return null;
|
|
31618
|
+
}
|
|
31619
|
+
}
|
|
31620
|
+
function readText(filePath) {
|
|
31621
|
+
try {
|
|
31622
|
+
return readFileSync3(filePath, "utf-8");
|
|
31623
|
+
} catch {
|
|
31624
|
+
return null;
|
|
31625
|
+
}
|
|
31626
|
+
}
|
|
31627
|
+
function listDirs(dirPath) {
|
|
31628
|
+
try {
|
|
31629
|
+
return readdirSync2(dirPath).filter((entry) => {
|
|
31630
|
+
if (IGNORED_DIRS.has(entry) || entry.startsWith("."))
|
|
31631
|
+
return false;
|
|
31632
|
+
try {
|
|
31633
|
+
return statSync(join4(dirPath, entry)).isDirectory();
|
|
31634
|
+
} catch {
|
|
31635
|
+
return false;
|
|
31636
|
+
}
|
|
31637
|
+
});
|
|
31638
|
+
} catch {
|
|
31639
|
+
return [];
|
|
31640
|
+
}
|
|
31641
|
+
}
|
|
31642
|
+
var DIR_DESCRIPTIONS = {
|
|
31643
|
+
components: "UI components",
|
|
31644
|
+
pages: "Route-level pages",
|
|
31645
|
+
routes: "Route-level pages",
|
|
31646
|
+
views: "Route-level pages",
|
|
31647
|
+
hooks: "Custom hooks",
|
|
31648
|
+
lib: "Utilities",
|
|
31649
|
+
utils: "Utilities",
|
|
31650
|
+
api: "API / server code",
|
|
31651
|
+
server: "API / server code",
|
|
31652
|
+
contexts: "State management",
|
|
31653
|
+
store: "State management",
|
|
31654
|
+
stores: "State management",
|
|
31655
|
+
types: "Type definitions",
|
|
31656
|
+
styles: "Stylesheets",
|
|
31657
|
+
public: "Static assets",
|
|
31658
|
+
static: "Static assets",
|
|
31659
|
+
assets: "Static assets",
|
|
31660
|
+
supabase: "Supabase backend",
|
|
31661
|
+
functions: "Edge functions",
|
|
31662
|
+
packages: "Monorepo packages",
|
|
31663
|
+
apps: "Monorepo applications",
|
|
31664
|
+
src: "Source code",
|
|
31665
|
+
test: "Tests",
|
|
31666
|
+
tests: "Tests",
|
|
31667
|
+
__tests__: "Tests",
|
|
31668
|
+
scripts: "Build / utility scripts",
|
|
31669
|
+
config: "Configuration",
|
|
31670
|
+
docs: "Documentation",
|
|
31671
|
+
migrations: "Database migrations",
|
|
31672
|
+
prisma: "Prisma schema & migrations",
|
|
31673
|
+
e2e: "End-to-end tests",
|
|
31674
|
+
cypress: "Cypress tests"
|
|
31675
|
+
};
|
|
31676
|
+
function describeDir(name) {
|
|
31677
|
+
return DIR_DESCRIPTIONS[name.toLowerCase()] ?? name;
|
|
31678
|
+
}
|
|
31679
|
+
function scanProject(cwd) {
|
|
31680
|
+
let packageManager = null;
|
|
31681
|
+
if (existsSync4(join4(cwd, "bun.lock")) || existsSync4(join4(cwd, "bun.lockb"))) {
|
|
31682
|
+
packageManager = "bun";
|
|
31683
|
+
} else if (existsSync4(join4(cwd, "pnpm-lock.yaml"))) {
|
|
31684
|
+
packageManager = "pnpm";
|
|
31685
|
+
} else if (existsSync4(join4(cwd, "yarn.lock"))) {
|
|
31686
|
+
packageManager = "yarn";
|
|
31687
|
+
} else if (existsSync4(join4(cwd, "package.json"))) {
|
|
31688
|
+
packageManager = "npm";
|
|
31689
|
+
}
|
|
31690
|
+
const pkg = readJson(join4(cwd, "package.json"));
|
|
31691
|
+
const scripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
|
|
31692
|
+
let language = "unknown";
|
|
31693
|
+
if (existsSync4(join4(cwd, "tsconfig.json"))) {
|
|
31694
|
+
language = "typescript";
|
|
31695
|
+
} else if (existsSync4(join4(cwd, "go.mod"))) {
|
|
31696
|
+
language = "go";
|
|
31697
|
+
} else if (existsSync4(join4(cwd, "Cargo.toml"))) {
|
|
31698
|
+
language = "rust";
|
|
31699
|
+
} else if (existsSync4(join4(cwd, "setup.py")) || existsSync4(join4(cwd, "pyproject.toml"))) {
|
|
31700
|
+
language = "python";
|
|
31701
|
+
} else if (pkg) {
|
|
31702
|
+
language = "javascript";
|
|
31703
|
+
}
|
|
31704
|
+
let framework = null;
|
|
31705
|
+
if (pkg) {
|
|
31706
|
+
const deps = {
|
|
31707
|
+
...typeof pkg.dependencies === "object" ? pkg.dependencies : {},
|
|
31708
|
+
...typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}
|
|
31709
|
+
};
|
|
31710
|
+
if (deps.next) {
|
|
31711
|
+
framework = "next";
|
|
31712
|
+
} else if (deps.react && deps.vite) {
|
|
31713
|
+
framework = "react+vite";
|
|
31714
|
+
} else if (deps.react) {
|
|
31715
|
+
framework = "react";
|
|
31716
|
+
} else if (deps.vue && deps.vite) {
|
|
31717
|
+
framework = "vue+vite";
|
|
31718
|
+
} else if (deps.vue && deps.nuxt) {
|
|
31719
|
+
framework = "nuxt";
|
|
31720
|
+
} else if (deps.vue) {
|
|
31721
|
+
framework = "vue";
|
|
31722
|
+
} else if (deps.astro) {
|
|
31723
|
+
framework = "astro";
|
|
31724
|
+
} else if (deps.svelte) {
|
|
31725
|
+
framework = "svelte";
|
|
31726
|
+
} else if (deps.express) {
|
|
31727
|
+
framework = "express";
|
|
31728
|
+
} else if (deps.fastify) {
|
|
31729
|
+
framework = "fastify";
|
|
31730
|
+
} else if (deps.hono) {
|
|
31731
|
+
framework = "hono";
|
|
31732
|
+
}
|
|
31733
|
+
}
|
|
31734
|
+
let linter = null;
|
|
31735
|
+
if (existsSync4(join4(cwd, "biome.json")) || existsSync4(join4(cwd, "biome.jsonc"))) {
|
|
31736
|
+
linter = "biome";
|
|
31737
|
+
} else {
|
|
31738
|
+
const eslintFiles = [
|
|
31739
|
+
".eslintrc",
|
|
31740
|
+
".eslintrc.js",
|
|
31741
|
+
".eslintrc.cjs",
|
|
31742
|
+
".eslintrc.json",
|
|
31743
|
+
".eslintrc.yml",
|
|
31744
|
+
".eslintrc.yaml",
|
|
31745
|
+
"eslint.config.js",
|
|
31746
|
+
"eslint.config.mjs",
|
|
31747
|
+
"eslint.config.cjs",
|
|
31748
|
+
"eslint.config.ts"
|
|
31749
|
+
];
|
|
31750
|
+
if (eslintFiles.some((f) => existsSync4(join4(cwd, f)))) {
|
|
31751
|
+
linter = "eslint";
|
|
31752
|
+
} else {
|
|
31753
|
+
const prettierFiles = [
|
|
31754
|
+
".prettierrc",
|
|
31755
|
+
".prettierrc.js",
|
|
31756
|
+
".prettierrc.json",
|
|
31757
|
+
".prettierrc.yml",
|
|
31758
|
+
".prettierrc.yaml",
|
|
31759
|
+
"prettier.config.js",
|
|
31760
|
+
"prettier.config.mjs"
|
|
31761
|
+
];
|
|
31762
|
+
if (prettierFiles.some((f) => existsSync4(join4(cwd, f)))) {
|
|
31763
|
+
linter = "prettier";
|
|
31764
|
+
}
|
|
31765
|
+
}
|
|
31766
|
+
}
|
|
31767
|
+
let indentStyle = null;
|
|
31768
|
+
const biome = readJson(join4(cwd, "biome.json")) ?? readJson(join4(cwd, "biome.jsonc"));
|
|
31769
|
+
if (biome) {
|
|
31770
|
+
const formatter = biome.formatter;
|
|
31771
|
+
if (formatter) {
|
|
31772
|
+
const type = formatter.indentStyle === "tab" ? "tab" : "space";
|
|
31773
|
+
const width = typeof formatter.indentWidth === "number" ? formatter.indentWidth : 2;
|
|
31774
|
+
indentStyle = { type, width };
|
|
31775
|
+
}
|
|
31776
|
+
}
|
|
31777
|
+
if (!indentStyle) {
|
|
31778
|
+
const editorConfig = readText(join4(cwd, ".editorconfig"));
|
|
31779
|
+
if (editorConfig) {
|
|
31780
|
+
const styleMatch = editorConfig.match(/indent_style\s*=\s*(space|tab)/);
|
|
31781
|
+
const sizeMatch = editorConfig.match(/indent_size\s*=\s*(\d+)/);
|
|
31782
|
+
if (styleMatch) {
|
|
31783
|
+
indentStyle = {
|
|
31784
|
+
type: styleMatch[1],
|
|
31785
|
+
width: sizeMatch ? Number.parseInt(sizeMatch[1], 10) : 2
|
|
31786
|
+
};
|
|
31787
|
+
}
|
|
31788
|
+
}
|
|
31789
|
+
}
|
|
31790
|
+
const dirs = listDirs(cwd);
|
|
31791
|
+
const srcDirs = existsSync4(join4(cwd, "src")) ? listDirs(join4(cwd, "src")) : [];
|
|
31792
|
+
const monorepo = existsSync4(join4(cwd, "packages")) || existsSync4(join4(cwd, "apps"));
|
|
31793
|
+
const existingDocs = {
|
|
31794
|
+
agentsMd: existsSync4(join4(cwd, "AGENTS.md")),
|
|
31795
|
+
claudeMd: existsSync4(join4(cwd, "CLAUDE.md")),
|
|
31796
|
+
docsDir: existsSync4(join4(cwd, "docs")),
|
|
31797
|
+
architectureMd: existsSync4(join4(cwd, "docs", "architecture.md"))
|
|
31798
|
+
};
|
|
31799
|
+
return {
|
|
31800
|
+
packageManager,
|
|
31801
|
+
scripts,
|
|
31802
|
+
language,
|
|
31803
|
+
framework,
|
|
31804
|
+
linter,
|
|
31805
|
+
indentStyle,
|
|
31806
|
+
dirs,
|
|
31807
|
+
srcDirs,
|
|
31808
|
+
monorepo,
|
|
31809
|
+
existingDocs
|
|
31810
|
+
};
|
|
31811
|
+
}
|
|
31812
|
+
function runCmd(pm) {
|
|
31813
|
+
if (pm === "bun")
|
|
31814
|
+
return "bun run";
|
|
31815
|
+
if (pm === "pnpm")
|
|
31816
|
+
return "pnpm run";
|
|
31817
|
+
if (pm === "yarn")
|
|
31818
|
+
return "yarn";
|
|
31819
|
+
return "npm run";
|
|
31820
|
+
}
|
|
31821
|
+
function describeScript(name) {
|
|
31822
|
+
const map3 = {
|
|
31823
|
+
dev: "Dev server",
|
|
31824
|
+
start: "Start server",
|
|
31825
|
+
build: "Production build",
|
|
31826
|
+
lint: "Lint",
|
|
31827
|
+
"lint:fix": "Lint + autofix",
|
|
31828
|
+
format: "Format code",
|
|
31829
|
+
test: "Run tests",
|
|
31830
|
+
"test:watch": "Run tests (watch)",
|
|
31831
|
+
"test:e2e": "End-to-end tests",
|
|
31832
|
+
typecheck: "Type-check",
|
|
31833
|
+
"type-check": "Type-check",
|
|
31834
|
+
preview: "Preview production build",
|
|
31835
|
+
deploy: "Deploy",
|
|
31836
|
+
generate: "Code generation",
|
|
31837
|
+
migrate: "Run migrations",
|
|
31838
|
+
seed: "Seed database",
|
|
31839
|
+
clean: "Clean build artifacts",
|
|
31840
|
+
prepare: "Prepare (husky, etc.)"
|
|
31841
|
+
};
|
|
31842
|
+
return map3[name] ?? "";
|
|
31843
|
+
}
|
|
31844
|
+
function generateAgentsMd(info, _cwd) {
|
|
31845
|
+
const lang = info.language === "typescript" ? "TypeScript" : info.language === "javascript" ? "JavaScript" : info.language;
|
|
31846
|
+
const frameworkLabel = info.framework ? `${info.framework} ` : "";
|
|
31847
|
+
const monoLabel = info.monorepo ? " (monorepo)" : "";
|
|
31848
|
+
const lines = [];
|
|
31849
|
+
lines.push("# AGENTS.md");
|
|
31850
|
+
lines.push("");
|
|
31851
|
+
lines.push(`${frameworkLabel}${lang} project${monoLabel}.`);
|
|
31852
|
+
lines.push("");
|
|
31853
|
+
const scriptEntries = Object.entries(info.scripts);
|
|
31854
|
+
if (scriptEntries.length > 0 && info.packageManager) {
|
|
31855
|
+
const prefix = runCmd(info.packageManager);
|
|
31856
|
+
lines.push("## Commands");
|
|
31857
|
+
lines.push("");
|
|
31858
|
+
lines.push("```bash");
|
|
31859
|
+
const commands = scriptEntries.map(([name]) => `${prefix} ${name}`);
|
|
31860
|
+
const maxLen = Math.max(...commands.map((c) => c.length));
|
|
31861
|
+
for (let i = 0;i < scriptEntries.length; i++) {
|
|
31862
|
+
const [name] = scriptEntries[i];
|
|
31863
|
+
const cmd = commands[i];
|
|
31864
|
+
const desc = describeScript(name);
|
|
31865
|
+
if (desc) {
|
|
31866
|
+
lines.push(`${cmd}${" ".repeat(maxLen - cmd.length + 4)}# ${desc}`);
|
|
31867
|
+
} else {
|
|
31868
|
+
lines.push(cmd);
|
|
31869
|
+
}
|
|
31870
|
+
}
|
|
31871
|
+
lines.push("```");
|
|
31872
|
+
lines.push("");
|
|
31873
|
+
}
|
|
31874
|
+
lines.push("## Code Standards");
|
|
31875
|
+
lines.push("");
|
|
31876
|
+
const langLabel = info.language === "typescript" ? "TypeScript" : "JavaScript";
|
|
31877
|
+
if (info.language === "typescript" || info.language === "javascript") {
|
|
31878
|
+
lines.push(`- ${langLabel} with ES modules`);
|
|
31879
|
+
}
|
|
31880
|
+
if (info.indentStyle) {
|
|
31881
|
+
const unit = info.indentStyle.type === "tab" ? "tab" : "space";
|
|
31882
|
+
lines.push(`- ${info.indentStyle.width}-${unit} indentation`);
|
|
31883
|
+
}
|
|
31884
|
+
if (info.linter) {
|
|
31885
|
+
lines.push(`- Linted with ${info.linter}`);
|
|
31886
|
+
}
|
|
31887
|
+
lines.push("");
|
|
31888
|
+
lines.push("## Architecture");
|
|
31889
|
+
lines.push("");
|
|
31890
|
+
for (const dir of info.dirs) {
|
|
31891
|
+
lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
|
|
31892
|
+
}
|
|
31893
|
+
if (info.srcDirs.length > 0) {
|
|
31894
|
+
for (const sub of info.srcDirs) {
|
|
31895
|
+
lines.push(` - \`src/${sub}/\` — ${describeDir(sub)}`);
|
|
31896
|
+
}
|
|
31897
|
+
}
|
|
31898
|
+
lines.push("");
|
|
31899
|
+
return lines.join(`
|
|
31900
|
+
`);
|
|
31901
|
+
}
|
|
31902
|
+
function generateClaudeMd(info) {
|
|
31903
|
+
const lines = [];
|
|
31904
|
+
lines.push("# CLAUDE.md");
|
|
31905
|
+
lines.push("");
|
|
31906
|
+
lines.push("@AGENTS.md");
|
|
31907
|
+
if (info.existingDocs.architectureMd || info.dirs.includes("docs")) {
|
|
31908
|
+
lines.push("@docs/architecture.md");
|
|
31909
|
+
}
|
|
31910
|
+
lines.push("");
|
|
31911
|
+
return lines.join(`
|
|
31912
|
+
`);
|
|
31913
|
+
}
|
|
31914
|
+
function generateArchitectureMd(info, _cwd) {
|
|
31915
|
+
const lines = [];
|
|
31916
|
+
lines.push("# Architecture");
|
|
31917
|
+
lines.push("");
|
|
31918
|
+
lines.push("## Directory Structure");
|
|
31919
|
+
lines.push("");
|
|
31920
|
+
for (const dir of info.dirs) {
|
|
31921
|
+
lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
|
|
31922
|
+
}
|
|
31923
|
+
if (info.srcDirs.length > 0) {
|
|
31924
|
+
lines.push("");
|
|
31925
|
+
lines.push("### `src/`");
|
|
31926
|
+
lines.push("");
|
|
31927
|
+
for (const sub of info.srcDirs) {
|
|
31928
|
+
lines.push(`- \`src/${sub}/\` — ${describeDir(sub)}`);
|
|
31929
|
+
}
|
|
31930
|
+
}
|
|
31931
|
+
lines.push("");
|
|
31932
|
+
return lines.join(`
|
|
31933
|
+
`);
|
|
31934
|
+
}
|
|
31935
|
+
function verifyDocs(cwd) {
|
|
31936
|
+
const issues = [];
|
|
31937
|
+
const claudeMd = readText(join4(cwd, "CLAUDE.md"));
|
|
31938
|
+
if (claudeMd) {
|
|
31939
|
+
for (const line of claudeMd.split(`
|
|
31940
|
+
`)) {
|
|
31941
|
+
const match = line.match(/^@(.+)$/);
|
|
31942
|
+
if (match) {
|
|
31943
|
+
const refPath = match[1].trim();
|
|
31944
|
+
if (!existsSync4(join4(cwd, refPath))) {
|
|
31945
|
+
issues.push({
|
|
31946
|
+
severity: "error",
|
|
31947
|
+
file: "CLAUDE.md",
|
|
31948
|
+
message: `Referenced file does not exist: ${refPath}`,
|
|
31949
|
+
fix: `Remove the @${refPath} line or create the file`
|
|
31950
|
+
});
|
|
31951
|
+
}
|
|
31952
|
+
}
|
|
31953
|
+
}
|
|
31954
|
+
}
|
|
31955
|
+
const agentsMd = readText(join4(cwd, "AGENTS.md"));
|
|
31956
|
+
const pkg = readJson(join4(cwd, "package.json"));
|
|
31957
|
+
const pkgScripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
|
|
31958
|
+
if (agentsMd) {
|
|
31959
|
+
const codeBlockRe = /```[\s\S]*?```/g;
|
|
31960
|
+
let blockMatch;
|
|
31961
|
+
while ((blockMatch = codeBlockRe.exec(agentsMd)) !== null) {
|
|
31962
|
+
const block = blockMatch[0];
|
|
31963
|
+
const cmdRe = /(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?(\S+)/g;
|
|
31964
|
+
let cmdMatch;
|
|
31965
|
+
while ((cmdMatch = cmdRe.exec(block)) !== null) {
|
|
31966
|
+
const scriptName = cmdMatch[1];
|
|
31967
|
+
const builtins = new Set(["install", "init", "create", "exec", "dlx", "x", "test", "start"]);
|
|
31968
|
+
if (builtins.has(scriptName))
|
|
31969
|
+
continue;
|
|
31970
|
+
if (Object.keys(pkgScripts).length > 0 && !(scriptName in pkgScripts)) {
|
|
31971
|
+
issues.push({
|
|
31972
|
+
severity: "warning",
|
|
31973
|
+
file: "AGENTS.md",
|
|
31974
|
+
message: `Command references script "${scriptName}" which is not in package.json`,
|
|
31975
|
+
fix: `Update the command or add "${scriptName}" to package.json scripts`
|
|
31976
|
+
});
|
|
31977
|
+
}
|
|
31978
|
+
}
|
|
31979
|
+
}
|
|
31980
|
+
checkBacktickPaths(agentsMd, "AGENTS.md", cwd, issues);
|
|
31981
|
+
}
|
|
31982
|
+
const archMd = readText(join4(cwd, "docs", "architecture.md"));
|
|
31983
|
+
if (archMd) {
|
|
31984
|
+
checkBacktickPaths(archMd, "docs/architecture.md", cwd, issues);
|
|
31985
|
+
}
|
|
31986
|
+
return issues;
|
|
31987
|
+
}
|
|
31988
|
+
function checkBacktickPaths(content, file2, cwd, issues) {
|
|
31989
|
+
const pathRe = /`((?:src\/|packages\/|apps\/|supabase\/|docs\/)[^`]+)`/g;
|
|
31990
|
+
let match;
|
|
31991
|
+
const checked = new Set;
|
|
31992
|
+
while ((match = pathRe.exec(content)) !== null) {
|
|
31993
|
+
const refPath = match[1].replace(/\/$/, "");
|
|
31994
|
+
if (checked.has(refPath))
|
|
31995
|
+
continue;
|
|
31996
|
+
checked.add(refPath);
|
|
31997
|
+
if (!existsSync4(join4(cwd, refPath))) {
|
|
31998
|
+
issues.push({
|
|
31999
|
+
severity: "warning",
|
|
32000
|
+
file: file2,
|
|
32001
|
+
message: `Referenced path does not exist: ${refPath}`,
|
|
32002
|
+
fix: `Update or remove the \`${refPath}\` reference`
|
|
32003
|
+
});
|
|
32004
|
+
}
|
|
32005
|
+
}
|
|
32006
|
+
}
|
|
32007
|
+
async function runDocsStep(cwd) {
|
|
32008
|
+
const info = scanProject(cwd);
|
|
32009
|
+
const hasDocs = info.existingDocs.agentsMd || info.existingDocs.claudeMd;
|
|
32010
|
+
if (!hasDocs) {
|
|
32011
|
+
const shouldGenerate = await ye({
|
|
32012
|
+
message: "No project docs found. Generate AGENTS.md and CLAUDE.md?",
|
|
32013
|
+
initialValue: true
|
|
32014
|
+
});
|
|
32015
|
+
if (pD(shouldGenerate) || !shouldGenerate) {
|
|
32016
|
+
return { files: [], issues: [], skipped: true };
|
|
32017
|
+
}
|
|
32018
|
+
const files = [];
|
|
32019
|
+
files.push({
|
|
32020
|
+
path: join4(cwd, "AGENTS.md"),
|
|
32021
|
+
content: generateAgentsMd(info, cwd),
|
|
32022
|
+
type: "text"
|
|
32023
|
+
});
|
|
32024
|
+
files.push({
|
|
32025
|
+
path: join4(cwd, "CLAUDE.md"),
|
|
32026
|
+
content: generateClaudeMd(info),
|
|
32027
|
+
type: "text"
|
|
32028
|
+
});
|
|
32029
|
+
if (info.dirs.includes("docs") || info.srcDirs.length > 0) {
|
|
32030
|
+
files.push({
|
|
32031
|
+
path: join4(cwd, "docs", "architecture.md"),
|
|
32032
|
+
content: generateArchitectureMd(info, cwd),
|
|
32033
|
+
type: "text"
|
|
32034
|
+
});
|
|
32035
|
+
}
|
|
32036
|
+
M2.success(`Generated ${files.length} doc file(s): ${files.map((f) => f.path.replace(cwd + "/", "")).join(", ")}`);
|
|
32037
|
+
return { files, issues: [], skipped: false };
|
|
32038
|
+
}
|
|
32039
|
+
const shouldVerify = await ye({
|
|
32040
|
+
message: "Project docs found. Verify for issues?",
|
|
32041
|
+
initialValue: false
|
|
32042
|
+
});
|
|
32043
|
+
if (pD(shouldVerify) || !shouldVerify) {
|
|
32044
|
+
return { files: [], issues: [], skipped: true };
|
|
32045
|
+
}
|
|
32046
|
+
const issues = verifyDocs(cwd);
|
|
32047
|
+
if (issues.length === 0) {
|
|
32048
|
+
M2.success("No issues found in project docs.");
|
|
32049
|
+
} else {
|
|
32050
|
+
for (const issue2 of issues) {
|
|
32051
|
+
const prefix = `${colors.bold(issue2.file)}:`;
|
|
32052
|
+
if (issue2.severity === "error") {
|
|
32053
|
+
M2.error(`${prefix} ${issue2.message}`);
|
|
32054
|
+
} else {
|
|
32055
|
+
M2.warning(`${prefix} ${issue2.message}`);
|
|
32056
|
+
}
|
|
32057
|
+
if (issue2.fix) {
|
|
32058
|
+
M2.message(` ${symbols.arrow} ${colors.dim(issue2.fix)}`);
|
|
32059
|
+
}
|
|
32060
|
+
}
|
|
32061
|
+
M2.info(`Found ${issues.length} issue(s) (${issues.filter((i) => i.severity === "error").length} errors, ${issues.filter((i) => i.severity === "warning").length} warnings)`);
|
|
32062
|
+
}
|
|
32063
|
+
return { files: [], issues, skipped: false };
|
|
32064
|
+
}
|
|
32065
|
+
|
|
31586
32066
|
// src/tui/writer.ts
|
|
31587
|
-
import { existsSync as
|
|
32067
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
31588
32068
|
import { homedir as homedir3 } from "node:os";
|
|
31589
32069
|
import { dirname } from "node:path";
|
|
31590
32070
|
function ensureDir(dirPath) {
|
|
31591
|
-
if (!
|
|
32071
|
+
if (!existsSync5(dirPath)) {
|
|
31592
32072
|
mkdirSync3(dirPath, { recursive: true, mode: 493 });
|
|
31593
32073
|
}
|
|
31594
32074
|
}
|
|
31595
32075
|
function writeFile(filePath, content, options = {}) {
|
|
31596
|
-
const exists =
|
|
32076
|
+
const exists = existsSync5(filePath);
|
|
31597
32077
|
if (exists && !options.force) {
|
|
31598
32078
|
return { path: filePath, action: "skip" };
|
|
31599
32079
|
}
|
|
@@ -31611,7 +32091,7 @@ function writeFile(filePath, content, options = {}) {
|
|
|
31611
32091
|
}
|
|
31612
32092
|
}
|
|
31613
32093
|
function mergeJsonFile(filePath, updates, options = {}) {
|
|
31614
|
-
const exists =
|
|
32094
|
+
const exists = existsSync5(filePath);
|
|
31615
32095
|
if (!exists) {
|
|
31616
32096
|
try {
|
|
31617
32097
|
ensureDir(dirname(filePath));
|
|
@@ -31628,7 +32108,7 @@ function mergeJsonFile(filePath, updates, options = {}) {
|
|
|
31628
32108
|
}
|
|
31629
32109
|
}
|
|
31630
32110
|
try {
|
|
31631
|
-
const existing = JSON.parse(
|
|
32111
|
+
const existing = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
31632
32112
|
if (updates.mcpServers && existing.mcpServers) {
|
|
31633
32113
|
const existingServers = existing.mcpServers;
|
|
31634
32114
|
const updateServers = updates.mcpServers;
|
|
@@ -31661,7 +32141,7 @@ function mergeJsonFile(filePath, updates, options = {}) {
|
|
|
31661
32141
|
}
|
|
31662
32142
|
}
|
|
31663
32143
|
function appendToToml(filePath, section, content, options = {}) {
|
|
31664
|
-
const exists =
|
|
32144
|
+
const exists = existsSync5(filePath);
|
|
31665
32145
|
if (!exists) {
|
|
31666
32146
|
try {
|
|
31667
32147
|
ensureDir(dirname(filePath));
|
|
@@ -31676,7 +32156,7 @@ function appendToToml(filePath, section, content, options = {}) {
|
|
|
31676
32156
|
}
|
|
31677
32157
|
}
|
|
31678
32158
|
try {
|
|
31679
|
-
const existing =
|
|
32159
|
+
const existing = readFileSync4(filePath, "utf-8");
|
|
31680
32160
|
if (existing.includes(section)) {
|
|
31681
32161
|
if (options.force) {
|
|
31682
32162
|
const updated = existing.replace(new RegExp(`\\[${section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\][\\s\\S]*?(?=\\[|$)`), content.trim() + `
|
|
@@ -31737,7 +32217,7 @@ function getWriteSummary(files, options = {}) {
|
|
|
31737
32217
|
const home = homedir3();
|
|
31738
32218
|
for (const file2 of files) {
|
|
31739
32219
|
const displayPath = formatPath(file2.path, home);
|
|
31740
|
-
const exists =
|
|
32220
|
+
const exists = existsSync5(file2.path);
|
|
31741
32221
|
if (exists && !options.force) {
|
|
31742
32222
|
toSkip.push(displayPath);
|
|
31743
32223
|
} else if (exists) {
|
|
@@ -31750,7 +32230,7 @@ function getWriteSummary(files, options = {}) {
|
|
|
31750
32230
|
}
|
|
31751
32231
|
|
|
31752
32232
|
// src/tui/setup.ts
|
|
31753
|
-
var GLOBAL_SKILLS_DIR =
|
|
32233
|
+
var GLOBAL_SKILLS_DIR = join5(homedir4(), ".agents", "skills");
|
|
31754
32234
|
var API_URL = "https://gethmy.com/api";
|
|
31755
32235
|
var HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
|
|
31756
32236
|
|
|
@@ -32043,7 +32523,7 @@ Report the result:
|
|
|
32043
32523
|
async function registerMcpServer() {
|
|
32044
32524
|
try {
|
|
32045
32525
|
const { execSync } = await import("node:child_process");
|
|
32046
|
-
execSync("claude mcp add --transport stdio harmony -- npx -y
|
|
32526
|
+
execSync("claude mcp add --transport stdio harmony -- npx -y @gethmy/mcp@latest serve", {
|
|
32047
32527
|
stdio: "pipe"
|
|
32048
32528
|
});
|
|
32049
32529
|
return true;
|
|
@@ -32052,22 +32532,22 @@ async function registerMcpServer() {
|
|
|
32052
32532
|
}
|
|
32053
32533
|
}
|
|
32054
32534
|
async function writeMcpConfigFallback(home) {
|
|
32055
|
-
const { readFileSync:
|
|
32056
|
-
const settingsPath =
|
|
32535
|
+
const { readFileSync: readFileSync5, writeFileSync: writeFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync7 } = await import("node:fs");
|
|
32536
|
+
const settingsPath = join5(home, ".claude", "settings.json");
|
|
32057
32537
|
const settingsDir = dirname2(settingsPath);
|
|
32058
|
-
if (!
|
|
32538
|
+
if (!existsSync7(settingsDir)) {
|
|
32059
32539
|
mkdirSync5(settingsDir, { recursive: true });
|
|
32060
32540
|
}
|
|
32061
32541
|
let settings = {};
|
|
32062
|
-
if (
|
|
32542
|
+
if (existsSync7(settingsPath)) {
|
|
32063
32543
|
try {
|
|
32064
|
-
settings = JSON.parse(
|
|
32544
|
+
settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
|
|
32065
32545
|
} catch {}
|
|
32066
32546
|
}
|
|
32067
32547
|
const mcpServers = settings.mcpServers || {};
|
|
32068
32548
|
mcpServers.harmony = {
|
|
32069
32549
|
command: "npx",
|
|
32070
|
-
args: ["-y", "
|
|
32550
|
+
args: ["-y", "@gethmy/mcp@latest", "serve"]
|
|
32071
32551
|
};
|
|
32072
32552
|
settings.mcpServers = mcpServers;
|
|
32073
32553
|
writeFileSync4(settingsPath, JSON.stringify(settings, null, 2));
|
|
@@ -32159,31 +32639,31 @@ ${HARMONY_PLAN_PROMPT.replace("$ARGUMENTS", "$ARGUMENTS")}
|
|
|
32159
32639
|
`;
|
|
32160
32640
|
if (installMode === "global") {
|
|
32161
32641
|
files.push({
|
|
32162
|
-
path:
|
|
32642
|
+
path: join5(GLOBAL_SKILLS_DIR, "hmy", "SKILL.md"),
|
|
32163
32643
|
content: skillContent,
|
|
32164
32644
|
type: "text"
|
|
32165
32645
|
});
|
|
32166
32646
|
symlinks.push({
|
|
32167
|
-
target:
|
|
32168
|
-
link:
|
|
32647
|
+
target: join5(GLOBAL_SKILLS_DIR, "hmy"),
|
|
32648
|
+
link: join5(home, ".claude", "skills", "hmy")
|
|
32169
32649
|
});
|
|
32170
32650
|
files.push({
|
|
32171
|
-
path:
|
|
32651
|
+
path: join5(GLOBAL_SKILLS_DIR, "hmy-plan", "SKILL.md"),
|
|
32172
32652
|
content: planSkillContent,
|
|
32173
32653
|
type: "text"
|
|
32174
32654
|
});
|
|
32175
32655
|
symlinks.push({
|
|
32176
|
-
target:
|
|
32177
|
-
link:
|
|
32656
|
+
target: join5(GLOBAL_SKILLS_DIR, "hmy-plan"),
|
|
32657
|
+
link: join5(home, ".claude", "skills", "hmy-plan")
|
|
32178
32658
|
});
|
|
32179
32659
|
} else {
|
|
32180
32660
|
files.push({
|
|
32181
|
-
path:
|
|
32661
|
+
path: join5(cwd, ".claude", "skills", "hmy", "SKILL.md"),
|
|
32182
32662
|
content: skillContent,
|
|
32183
32663
|
type: "text"
|
|
32184
32664
|
});
|
|
32185
32665
|
files.push({
|
|
32186
|
-
path:
|
|
32666
|
+
path: join5(cwd, ".claude", "skills", "hmy-plan", "SKILL.md"),
|
|
32187
32667
|
content: planSkillContent,
|
|
32188
32668
|
type: "text"
|
|
32189
32669
|
});
|
|
@@ -32218,7 +32698,7 @@ When given a card reference (e.g., #42 or a card name), follow this workflow:
|
|
|
32218
32698
|
- \`harmony_generate_prompt\` - Get role-based guidance and focus areas for the card
|
|
32219
32699
|
`;
|
|
32220
32700
|
files.push({
|
|
32221
|
-
path:
|
|
32701
|
+
path: join5(cwd, "AGENTS.md"),
|
|
32222
32702
|
content: agentsContent,
|
|
32223
32703
|
type: "text"
|
|
32224
32704
|
});
|
|
@@ -32235,17 +32715,17 @@ ${HARMONY_WORKFLOW_PROMPT.replace("$ARGUMENTS", "{{card}}").replace("Your agent
|
|
|
32235
32715
|
`;
|
|
32236
32716
|
if (installMode === "global") {
|
|
32237
32717
|
files.push({
|
|
32238
|
-
path:
|
|
32718
|
+
path: join5(GLOBAL_SKILLS_DIR, "codex", "hmy.md"),
|
|
32239
32719
|
content: promptContent,
|
|
32240
32720
|
type: "text"
|
|
32241
32721
|
});
|
|
32242
32722
|
symlinks.push({
|
|
32243
|
-
target:
|
|
32244
|
-
link:
|
|
32723
|
+
target: join5(GLOBAL_SKILLS_DIR, "codex", "hmy.md"),
|
|
32724
|
+
link: join5(home, ".codex", "prompts", "hmy.md")
|
|
32245
32725
|
});
|
|
32246
32726
|
} else {
|
|
32247
32727
|
files.push({
|
|
32248
|
-
path:
|
|
32728
|
+
path: join5(home, ".codex", "prompts", "hmy.md"),
|
|
32249
32729
|
content: promptContent,
|
|
32250
32730
|
type: "text"
|
|
32251
32731
|
});
|
|
@@ -32254,10 +32734,10 @@ ${HARMONY_WORKFLOW_PROMPT.replace("$ARGUMENTS", "{{card}}").replace("Your agent
|
|
|
32254
32734
|
# Harmony MCP Server
|
|
32255
32735
|
[mcp_servers.harmony]
|
|
32256
32736
|
command = "npx"
|
|
32257
|
-
args = ["-y", "
|
|
32737
|
+
args = ["-y", "@gethmy/mcp@latest", "serve"]
|
|
32258
32738
|
`;
|
|
32259
32739
|
files.push({
|
|
32260
|
-
path:
|
|
32740
|
+
path: join5(home, ".codex", "config.toml"),
|
|
32261
32741
|
content: tomlContent,
|
|
32262
32742
|
type: "toml",
|
|
32263
32743
|
tomlSection: "mcp_servers.harmony"
|
|
@@ -32266,12 +32746,12 @@ args = ["-y", "harmony-mcp@latest", "serve"]
|
|
|
32266
32746
|
}
|
|
32267
32747
|
case "cursor": {
|
|
32268
32748
|
files.push({
|
|
32269
|
-
path:
|
|
32749
|
+
path: join5(cwd, ".cursor", "mcp.json"),
|
|
32270
32750
|
content: JSON.stringify({
|
|
32271
32751
|
mcpServers: {
|
|
32272
32752
|
harmony: {
|
|
32273
32753
|
command: "npx",
|
|
32274
|
-
args: ["-y", "
|
|
32754
|
+
args: ["-y", "@gethmy/mcp@latest", "serve"]
|
|
32275
32755
|
}
|
|
32276
32756
|
}
|
|
32277
32757
|
}, null, 2),
|
|
@@ -32292,17 +32772,17 @@ ${HARMONY_WORKFLOW_PROMPT.replace("$ARGUMENTS", "the card reference").replace("Y
|
|
|
32292
32772
|
`;
|
|
32293
32773
|
if (installMode === "global") {
|
|
32294
32774
|
files.push({
|
|
32295
|
-
path:
|
|
32775
|
+
path: join5(GLOBAL_SKILLS_DIR, "cursor", "harmony.mdc"),
|
|
32296
32776
|
content: ruleContent,
|
|
32297
32777
|
type: "text"
|
|
32298
32778
|
});
|
|
32299
32779
|
symlinks.push({
|
|
32300
|
-
target:
|
|
32301
|
-
link:
|
|
32780
|
+
target: join5(GLOBAL_SKILLS_DIR, "cursor", "harmony.mdc"),
|
|
32781
|
+
link: join5(home, ".cursor", "rules", "harmony.mdc")
|
|
32302
32782
|
});
|
|
32303
32783
|
} else {
|
|
32304
32784
|
files.push({
|
|
32305
|
-
path:
|
|
32785
|
+
path: join5(cwd, ".cursor", "rules", "harmony.mdc"),
|
|
32306
32786
|
content: ruleContent,
|
|
32307
32787
|
type: "text"
|
|
32308
32788
|
});
|
|
@@ -32311,12 +32791,12 @@ ${HARMONY_WORKFLOW_PROMPT.replace("$ARGUMENTS", "the card reference").replace("Y
|
|
|
32311
32791
|
}
|
|
32312
32792
|
case "windsurf": {
|
|
32313
32793
|
files.push({
|
|
32314
|
-
path:
|
|
32794
|
+
path: join5(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
32315
32795
|
content: JSON.stringify({
|
|
32316
32796
|
mcpServers: {
|
|
32317
32797
|
harmony: {
|
|
32318
32798
|
command: "npx",
|
|
32319
|
-
args: ["-y", "
|
|
32799
|
+
args: ["-y", "@gethmy/mcp@latest", "serve"],
|
|
32320
32800
|
disabled: false,
|
|
32321
32801
|
alwaysAllow: []
|
|
32322
32802
|
}
|
|
@@ -32337,17 +32817,17 @@ ${HARMONY_WORKFLOW_PROMPT.replace("$ARGUMENTS", "the card reference").replace("Y
|
|
|
32337
32817
|
`;
|
|
32338
32818
|
if (installMode === "global") {
|
|
32339
32819
|
files.push({
|
|
32340
|
-
path:
|
|
32820
|
+
path: join5(GLOBAL_SKILLS_DIR, "windsurf", "harmony.md"),
|
|
32341
32821
|
content: ruleContent,
|
|
32342
32822
|
type: "text"
|
|
32343
32823
|
});
|
|
32344
32824
|
symlinks.push({
|
|
32345
|
-
target:
|
|
32346
|
-
link:
|
|
32825
|
+
target: join5(GLOBAL_SKILLS_DIR, "windsurf", "harmony.md"),
|
|
32826
|
+
link: join5(home, ".codeium", "windsurf", "rules", "harmony.md")
|
|
32347
32827
|
});
|
|
32348
32828
|
} else {
|
|
32349
32829
|
files.push({
|
|
32350
|
-
path:
|
|
32830
|
+
path: join5(cwd, ".windsurf", "rules", "harmony.md"),
|
|
32351
32831
|
content: ruleContent,
|
|
32352
32832
|
type: "text"
|
|
32353
32833
|
});
|
|
@@ -32548,6 +33028,14 @@ async function runSetup(options = {}) {
|
|
|
32548
33028
|
type: "text"
|
|
32549
33029
|
});
|
|
32550
33030
|
}
|
|
33031
|
+
if (!options.skipDocs) {
|
|
33032
|
+
const docsResult = await runDocsStep(cwd);
|
|
33033
|
+
if (!docsResult.skipped) {
|
|
33034
|
+
for (const file2 of docsResult.files) {
|
|
33035
|
+
allFiles.push(file2);
|
|
33036
|
+
}
|
|
33037
|
+
}
|
|
33038
|
+
}
|
|
32551
33039
|
if (needsSkills && selectedAgents.length > 0) {
|
|
32552
33040
|
for (const agentId of selectedAgents) {
|
|
32553
33041
|
const { files, symlinks } = getAgentFiles(agentId, cwd, installMode);
|
|
@@ -32623,7 +33111,7 @@ async function runSetup(options = {}) {
|
|
|
32623
33111
|
for (const symlink of allSymlinks) {
|
|
32624
33112
|
try {
|
|
32625
33113
|
const linkDir = dirname2(symlink.link);
|
|
32626
|
-
if (!
|
|
33114
|
+
if (!existsSync6(linkDir)) {
|
|
32627
33115
|
mkdirSync4(linkDir, { recursive: true });
|
|
32628
33116
|
}
|
|
32629
33117
|
let linkExists = false;
|
|
@@ -32652,9 +33140,9 @@ async function runSetup(options = {}) {
|
|
|
32652
33140
|
} else {
|
|
32653
33141
|
try {
|
|
32654
33142
|
await writeMcpConfigFallback(home);
|
|
32655
|
-
console.log(` ${colors.success("✓")} ${colors.dim(formatPath(
|
|
33143
|
+
console.log(` ${colors.success("✓")} ${colors.dim(formatPath(join5(home, ".claude", "settings.json"), home))} ${colors.dim("(updated)")}`);
|
|
32656
33144
|
} catch {
|
|
32657
|
-
M2.warning("Could not register MCP server. Run manually: claude mcp add --transport stdio harmony -- npx -y
|
|
33145
|
+
M2.warning("Could not register MCP server. Run manually: claude mcp add --transport stdio harmony -- npx -y @gethmy/mcp@latest serve");
|
|
32658
33146
|
}
|
|
32659
33147
|
}
|
|
32660
33148
|
}
|
|
@@ -32690,7 +33178,7 @@ async function runSetup(options = {}) {
|
|
|
32690
33178
|
console.log(` ${colors.brand("Cursor/Windsurf:")} MCP tools available automatically`);
|
|
32691
33179
|
}
|
|
32692
33180
|
console.log("");
|
|
32693
|
-
console.log(` ${colors.dim("Add to new project: npx
|
|
33181
|
+
console.log(` ${colors.dim("Add to new project: npx @gethmy/mcp setup")}`);
|
|
32694
33182
|
console.log(` ${colors.dim("Need help? Visit https://gethmy.com/docs/mcp")}`);
|
|
32695
33183
|
console.log("");
|
|
32696
33184
|
}
|
|
@@ -32698,7 +33186,7 @@ async function runSetup(options = {}) {
|
|
|
32698
33186
|
// src/cli.ts
|
|
32699
33187
|
var require2 = createRequire2(import.meta.url);
|
|
32700
33188
|
var { version: version2 } = require2("../package.json");
|
|
32701
|
-
program.name("
|
|
33189
|
+
program.name("@gethmy/mcp").description("MCP server for Harmony Kanban board").version(version2);
|
|
32702
33190
|
program.command("serve").description("Start the MCP server (stdio transport)").action(async () => {
|
|
32703
33191
|
const server = new HarmonyMCPServer;
|
|
32704
33192
|
await server.run();
|
|
@@ -32730,7 +33218,7 @@ Skills:`);
|
|
|
32730
33218
|
}
|
|
32731
33219
|
} else {
|
|
32732
33220
|
console.log(" Installed: No");
|
|
32733
|
-
console.log(" Run: npx
|
|
33221
|
+
console.log(" Run: npx @gethmy/mcp setup");
|
|
32734
33222
|
}
|
|
32735
33223
|
console.log(`
|
|
32736
33224
|
Context:`);
|
|
@@ -32753,7 +33241,7 @@ Context:`);
|
|
|
32753
33241
|
} else {
|
|
32754
33242
|
console.log(`Status: Not configured
|
|
32755
33243
|
`);
|
|
32756
|
-
console.log("Run: npx
|
|
33244
|
+
console.log("Run: npx @gethmy/mcp setup");
|
|
32757
33245
|
console.log("Get an API key at: https://gethmy.com/user/keys");
|
|
32758
33246
|
}
|
|
32759
33247
|
});
|
|
@@ -32766,9 +33254,9 @@ program.command("reset").description("Remove stored configuration").action(() =>
|
|
|
32766
33254
|
});
|
|
32767
33255
|
console.log("Configuration reset successfully");
|
|
32768
33256
|
console.log(`
|
|
32769
|
-
To reconfigure, run: npx
|
|
33257
|
+
To reconfigure, run: npx @gethmy/mcp setup`);
|
|
32770
33258
|
});
|
|
32771
|
-
program.command("setup").description("Smart setup wizard for Harmony MCP (recommended)").option("-f, --force", "Overwrite existing configuration files").option("-k, --api-key <key>", "API key (skips prompt)").option("-e, --email <email>", "Your email for auto-assignment").option("-a, --agents <agents...>", "Agents to configure: claude, codex, cursor, windsurf").option("-l, --local", "Install skills locally in project directory").option("-g, --global", "Install skills globally (recommended)").option("-w, --workspace <id>", "Set workspace context").option("-p, --project <id>", "Set project context").option("--skip-context", "Skip workspace/project selection").action(async (options) => {
|
|
33259
|
+
program.command("setup").description("Smart setup wizard for Harmony MCP (recommended)").option("-f, --force", "Overwrite existing configuration files").option("-k, --api-key <key>", "API key (skips prompt)").option("-e, --email <email>", "Your email for auto-assignment").option("-a, --agents <agents...>", "Agents to configure: claude, codex, cursor, windsurf").option("-l, --local", "Install skills locally in project directory").option("-g, --global", "Install skills globally (recommended)").option("-w, --workspace <id>", "Set workspace context").option("-p, --project <id>", "Set project context").option("--skip-context", "Skip workspace/project selection").option("--skip-docs", "Skip project docs scaffold/verification").action(async (options) => {
|
|
32772
33260
|
await runSetup({
|
|
32773
33261
|
force: options.force,
|
|
32774
33262
|
apiKey: options.apiKey,
|
|
@@ -32777,7 +33265,8 @@ program.command("setup").description("Smart setup wizard for Harmony MCP (recomm
|
|
|
32777
33265
|
installMode: options.global ? "global" : options.local ? "local" : undefined,
|
|
32778
33266
|
workspaceId: options.workspace,
|
|
32779
33267
|
projectId: options.project,
|
|
32780
|
-
skipContext: options.skipContext
|
|
33268
|
+
skipContext: options.skipContext,
|
|
33269
|
+
skipDocs: options.skipDocs
|
|
32781
33270
|
});
|
|
32782
33271
|
});
|
|
32783
33272
|
program.parse();
|