@gethmy/mcp 2.3.1 → 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.
Files changed (34) hide show
  1. package/dist/lib/api-client.js +2099 -648
  2. package/dist/lib/config.js +217 -201
  3. package/package.json +9 -5
  4. package/src/memory-cleanup.ts +2 -4
  5. package/dist/lib/__tests__/active-learning.test.js +0 -386
  6. package/dist/lib/__tests__/agent-performance-profiles.test.js +0 -325
  7. package/dist/lib/__tests__/auto-session.test.js +0 -661
  8. package/dist/lib/__tests__/context-assembly.test.js +0 -362
  9. package/dist/lib/__tests__/graph-expansion.test.js +0 -150
  10. package/dist/lib/__tests__/integration-memory-crud.test.js +0 -797
  11. package/dist/lib/__tests__/integration-memory-system.test.js +0 -281
  12. package/dist/lib/__tests__/lifecycle-maintenance.test.js +0 -207
  13. package/dist/lib/__tests__/pattern-detection.test.js +0 -295
  14. package/dist/lib/__tests__/prompt-builder.test.js +0 -418
  15. package/dist/lib/active-learning.js +0 -822
  16. package/dist/lib/auto-session.js +0 -214
  17. package/dist/lib/cli.js +0 -138
  18. package/dist/lib/consolidation.js +0 -303
  19. package/dist/lib/context-assembly.js +0 -884
  20. package/dist/lib/graph-expansion.js +0 -163
  21. package/dist/lib/http.js +0 -175
  22. package/dist/lib/index.js +0 -7
  23. package/dist/lib/lifecycle-maintenance.js +0 -88
  24. package/dist/lib/memory-cleanup.js +0 -455
  25. package/dist/lib/onboard.js +0 -36
  26. package/dist/lib/prompt-builder.js +0 -488
  27. package/dist/lib/remote.js +0 -166
  28. package/dist/lib/server.js +0 -3365
  29. package/dist/lib/skills.js +0 -593
  30. package/dist/lib/tui/agents.js +0 -116
  31. package/dist/lib/tui/docs.js +0 -744
  32. package/dist/lib/tui/setup.js +0 -934
  33. package/dist/lib/tui/theme.js +0 -95
  34. package/dist/lib/tui/writer.js +0 -200
@@ -1,95 +0,0 @@
1
- import * as pc from "picocolors";
2
- /**
3
- * Consistent theme for Harmony MCP TUI
4
- * Uses picocolors for lightweight color output
5
- */
6
- // Brand colors and symbols
7
- export const symbols = {
8
- harmony: "\u25B2", // Triangle for Harmony logo
9
- check: "\u2713",
10
- cross: "\u2717",
11
- bullet: "\u2022",
12
- arrow: "\u2192",
13
- arrowRight: "\u25B8",
14
- dot: "\u25CF",
15
- dotEmpty: "\u25CB",
16
- info: "\u2139",
17
- warning: "\u26A0",
18
- pointer: "\u276F",
19
- };
20
- // Color functions
21
- export const colors = {
22
- // Brand
23
- brand: (text) => pc.cyan(text),
24
- brandBold: (text) => pc.bold(pc.cyan(text)),
25
- // Status
26
- success: (text) => pc.green(text),
27
- error: (text) => pc.red(text),
28
- warning: (text) => pc.yellow(text),
29
- info: (text) => pc.blue(text),
30
- // Text
31
- dim: (text) => pc.dim(text),
32
- bold: (text) => pc.bold(text),
33
- muted: (text) => pc.gray(text),
34
- // Highlights
35
- highlight: (text) => pc.cyan(text),
36
- link: (text) => pc.underline(pc.cyan(text)),
37
- };
38
- // Styled messages
39
- export const messages = {
40
- header: () => {
41
- return `
42
- ${colors.brandBold(" HARMONY")}
43
- ${colors.dim(" Project management for AI agents")}
44
- `;
45
- },
46
- done: (message) => {
47
- return `${colors.success(symbols.check)} ${message}`;
48
- },
49
- fail: (message) => {
50
- return `${colors.error(symbols.cross)} ${message}`;
51
- },
52
- skip: (message) => {
53
- return `${colors.dim("-")} ${colors.dim(message)}`;
54
- },
55
- step: (number, total, message) => {
56
- return `${colors.dim(`[${number}/${total}]`)} ${message}`;
57
- },
58
- fileCreated: (path) => {
59
- return ` ${colors.success(symbols.check)} ${colors.dim(path)}`;
60
- },
61
- fileSkipped: (path) => {
62
- return ` ${colors.dim(symbols.bullet)} ${colors.dim(path)} ${colors.dim("(exists)")}`;
63
- },
64
- fileError: (path, error) => {
65
- return ` ${colors.error(symbols.cross)} ${path}: ${colors.error(error)}`;
66
- },
67
- };
68
- // Box drawing for sections
69
- export function box(title, content) {
70
- const lines = content.split("\n");
71
- const maxWidth = Math.max(title.length, ...lines.map((l) => l.length));
72
- const width = maxWidth + 4;
73
- const top = `\u250C${"─".repeat(width)}\u2510`;
74
- const bottom = `\u2514${"─".repeat(width)}\u2518`;
75
- const titleLine = `\u2502 ${colors.bold(title)}${" ".repeat(width - title.length - 1)}\u2502`;
76
- const contentLines = lines
77
- .map((line) => `\u2502 ${line}${" ".repeat(width - line.length - 1)}\u2502`)
78
- .join("\n");
79
- return `${top}\n${titleLine}\n${contentLines}\n${bottom}`;
80
- }
81
- // Format file paths for display (shorten home directory)
82
- export function formatPath(path, homeDir) {
83
- if (path.startsWith(homeDir)) {
84
- return `~${path.slice(homeDir.length)}`;
85
- }
86
- return path;
87
- }
88
- // Indent helper
89
- export function indent(text, spaces = 2) {
90
- const pad = " ".repeat(spaces);
91
- return text
92
- .split("\n")
93
- .map((line) => `${pad}${line}`)
94
- .join("\n");
95
- }
@@ -1,200 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { dirname } from "node:path";
4
- import * as p from "@clack/prompts";
5
- import { colors, formatPath, messages } from "./theme.js";
6
- /**
7
- * Ensure directory exists
8
- */
9
- function ensureDir(dirPath) {
10
- if (!existsSync(dirPath)) {
11
- mkdirSync(dirPath, { recursive: true, mode: 0o755 });
12
- }
13
- }
14
- /**
15
- * Write a file, optionally skipping if exists
16
- */
17
- export function writeFile(filePath, content, options = {}) {
18
- const exists = existsSync(filePath);
19
- if (exists && !options.force) {
20
- return { path: filePath, action: "skip" };
21
- }
22
- try {
23
- ensureDir(dirname(filePath));
24
- // Use restrictive permissions for config files
25
- const mode = filePath.includes(".harmony-mcp") ? 0o600 : 0o644;
26
- writeFileSync(filePath, content, { mode });
27
- return { path: filePath, action: exists ? "update" : "create" };
28
- }
29
- catch (error) {
30
- return {
31
- path: filePath,
32
- action: "skip",
33
- error: error instanceof Error ? error.message : String(error),
34
- };
35
- }
36
- }
37
- /**
38
- * Merge JSON content into existing file
39
- */
40
- export function mergeJsonFile(filePath, updates, options = {}) {
41
- const exists = existsSync(filePath);
42
- if (!exists) {
43
- try {
44
- ensureDir(dirname(filePath));
45
- writeFileSync(filePath, JSON.stringify(updates, null, 2), {
46
- mode: 0o644,
47
- });
48
- return { path: filePath, action: "create" };
49
- }
50
- catch (error) {
51
- return {
52
- path: filePath,
53
- action: "skip",
54
- error: error instanceof Error ? error.message : String(error),
55
- };
56
- }
57
- }
58
- try {
59
- const existing = JSON.parse(readFileSync(filePath, "utf-8"));
60
- // Deep merge mcpServers if present (always update harmony config)
61
- if (updates.mcpServers && existing.mcpServers) {
62
- const existingServers = existing.mcpServers;
63
- const updateServers = updates.mcpServers;
64
- existing.mcpServers = { ...existingServers, ...updateServers };
65
- }
66
- else {
67
- Object.assign(existing, updates);
68
- }
69
- writeFileSync(filePath, JSON.stringify(existing, null, 2), { mode: 0o644 });
70
- return { path: filePath, action: "merge" };
71
- }
72
- catch {
73
- if (options.force) {
74
- try {
75
- writeFileSync(filePath, JSON.stringify(updates, null, 2), {
76
- mode: 0o644,
77
- });
78
- return { path: filePath, action: "update" };
79
- }
80
- catch (error) {
81
- return {
82
- path: filePath,
83
- action: "skip",
84
- error: error instanceof Error ? error.message : String(error),
85
- };
86
- }
87
- }
88
- return {
89
- path: filePath,
90
- action: "skip",
91
- error: "Could not parse existing file",
92
- };
93
- }
94
- }
95
- /**
96
- * Append to TOML file (for Codex config)
97
- */
98
- export function appendToToml(filePath, section, content, options = {}) {
99
- const exists = existsSync(filePath);
100
- if (!exists) {
101
- try {
102
- ensureDir(dirname(filePath));
103
- writeFileSync(filePath, content, { mode: 0o644 });
104
- return { path: filePath, action: "create" };
105
- }
106
- catch (error) {
107
- return {
108
- path: filePath,
109
- action: "skip",
110
- error: error instanceof Error ? error.message : String(error),
111
- };
112
- }
113
- }
114
- try {
115
- const existing = readFileSync(filePath, "utf-8");
116
- if (existing.includes(section)) {
117
- if (options.force) {
118
- // Replace existing section
119
- const updated = existing.replace(new RegExp(`\\[${section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\][\\s\\S]*?(?=\\[|$)`), content.trim() + "\n\n");
120
- writeFileSync(filePath, updated, { mode: 0o644 });
121
- return { path: filePath, action: "update" };
122
- }
123
- return { path: filePath, action: "skip" };
124
- }
125
- // Append new section
126
- writeFileSync(filePath, existing + "\n" + content, { mode: 0o644 });
127
- return { path: filePath, action: "merge" };
128
- }
129
- catch (error) {
130
- return {
131
- path: filePath,
132
- action: "skip",
133
- error: error instanceof Error ? error.message : String(error),
134
- };
135
- }
136
- }
137
- /**
138
- * Write multiple files with progress display
139
- */
140
- export async function writeFilesWithProgress(files, options = {}) {
141
- const results = [];
142
- const home = homedir();
143
- const spinner = p.spinner();
144
- spinner.start("Writing configuration files...");
145
- for (const file of files) {
146
- let result;
147
- if (file.type === "json") {
148
- const jsonContent = JSON.parse(file.content);
149
- result = mergeJsonFile(file.path, jsonContent, options);
150
- }
151
- else if (file.type === "toml" && file.tomlSection) {
152
- result = appendToToml(file.path, file.tomlSection, file.content, options);
153
- }
154
- else {
155
- result = writeFile(file.path, file.content, options);
156
- }
157
- results.push(result);
158
- // Small delay for visual effect
159
- await new Promise((resolve) => setTimeout(resolve, 50));
160
- }
161
- spinner.stop("Files written");
162
- // Display results
163
- for (const result of results) {
164
- const displayPath = formatPath(result.path, home);
165
- if (result.error) {
166
- console.log(messages.fileError(displayPath, result.error));
167
- }
168
- else if (result.action === "skip") {
169
- console.log(messages.fileSkipped(displayPath));
170
- }
171
- else {
172
- const actionLabel = result.action === "merge" ? "updated" : "created";
173
- console.log(` ${colors.success("\u2713")} ${colors.dim(displayPath)} ${colors.dim(`(${actionLabel})`)}`);
174
- }
175
- }
176
- return results;
177
- }
178
- /**
179
- * Get summary of what will be written
180
- */
181
- export function getWriteSummary(files, options = {}) {
182
- const toCreate = [];
183
- const toUpdate = [];
184
- const toSkip = [];
185
- const home = homedir();
186
- for (const file of files) {
187
- const displayPath = formatPath(file.path, home);
188
- const exists = existsSync(file.path);
189
- if (exists && !options.force) {
190
- toSkip.push(displayPath);
191
- }
192
- else if (exists) {
193
- toUpdate.push(displayPath);
194
- }
195
- else {
196
- toCreate.push(displayPath);
197
- }
198
- }
199
- return { toCreate, toUpdate, toSkip };
200
- }