@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.
- package/dist/lib/api-client.js +2099 -648
- package/dist/lib/config.js +217 -201
- package/package.json +9 -5
- package/src/memory-cleanup.ts +2 -4
- package/dist/lib/__tests__/active-learning.test.js +0 -386
- package/dist/lib/__tests__/agent-performance-profiles.test.js +0 -325
- package/dist/lib/__tests__/auto-session.test.js +0 -661
- package/dist/lib/__tests__/context-assembly.test.js +0 -362
- package/dist/lib/__tests__/graph-expansion.test.js +0 -150
- package/dist/lib/__tests__/integration-memory-crud.test.js +0 -797
- package/dist/lib/__tests__/integration-memory-system.test.js +0 -281
- package/dist/lib/__tests__/lifecycle-maintenance.test.js +0 -207
- package/dist/lib/__tests__/pattern-detection.test.js +0 -295
- package/dist/lib/__tests__/prompt-builder.test.js +0 -418
- package/dist/lib/active-learning.js +0 -822
- package/dist/lib/auto-session.js +0 -214
- package/dist/lib/cli.js +0 -138
- package/dist/lib/consolidation.js +0 -303
- package/dist/lib/context-assembly.js +0 -884
- package/dist/lib/graph-expansion.js +0 -163
- package/dist/lib/http.js +0 -175
- package/dist/lib/index.js +0 -7
- package/dist/lib/lifecycle-maintenance.js +0 -88
- package/dist/lib/memory-cleanup.js +0 -455
- package/dist/lib/onboard.js +0 -36
- package/dist/lib/prompt-builder.js +0 -488
- package/dist/lib/remote.js +0 -166
- package/dist/lib/server.js +0 -3365
- package/dist/lib/skills.js +0 -593
- package/dist/lib/tui/agents.js +0 -116
- package/dist/lib/tui/docs.js +0 -744
- package/dist/lib/tui/setup.js +0 -934
- package/dist/lib/tui/theme.js +0 -95
- package/dist/lib/tui/writer.js +0 -200
package/dist/lib/config.js
CHANGED
|
@@ -1,205 +1,221 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
12
|
+
|
|
13
|
+
// src/config.ts
|
|
1
14
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
15
|
import { homedir } from "node:os";
|
|
3
16
|
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
const data = readFileSync(configPath, "utf-8");
|
|
29
|
-
const config = JSON.parse(data);
|
|
30
|
-
return {
|
|
31
|
-
apiKey: config.apiKey || null,
|
|
32
|
-
apiUrl: config.apiUrl || DEFAULT_API_URL,
|
|
33
|
-
activeWorkspaceId: config.activeWorkspaceId || null,
|
|
34
|
-
activeProjectId: config.activeProjectId || null,
|
|
35
|
-
userEmail: config.userEmail || null,
|
|
36
|
-
memoryDir: config.memoryDir || null,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return {
|
|
41
|
-
apiKey: null,
|
|
42
|
-
apiUrl: DEFAULT_API_URL,
|
|
43
|
-
activeWorkspaceId: null,
|
|
44
|
-
activeProjectId: null,
|
|
45
|
-
userEmail: null,
|
|
46
|
-
memoryDir: null,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
export function saveConfig(config) {
|
|
51
|
-
const configDir = getConfigDir();
|
|
52
|
-
const configPath = getConfigPath();
|
|
53
|
-
if (!existsSync(configDir)) {
|
|
54
|
-
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
55
|
-
}
|
|
56
|
-
const existingConfig = loadConfig();
|
|
57
|
-
const newConfig = { ...existingConfig, ...config };
|
|
58
|
-
writeFileSync(configPath, JSON.stringify(newConfig, null, 2), {
|
|
59
|
-
mode: 0o600,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export function loadLocalConfig(cwd) {
|
|
63
|
-
const localConfigPath = getLocalConfigPath(cwd);
|
|
64
|
-
if (!existsSync(localConfigPath)) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const data = readFileSync(localConfigPath, "utf-8");
|
|
69
|
-
const config = JSON.parse(data);
|
|
70
|
-
return {
|
|
71
|
-
workspaceId: config.workspaceId || null,
|
|
72
|
-
projectId: config.projectId || null,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
export function saveLocalConfig(config, cwd) {
|
|
80
|
-
const localConfigPath = getLocalConfigPath(cwd);
|
|
81
|
-
const existingConfig = loadLocalConfig(cwd) || {
|
|
82
|
-
workspaceId: null,
|
|
83
|
-
projectId: null,
|
|
17
|
+
var DEFAULT_API_URL = "https://app.gethmy.com/api";
|
|
18
|
+
var LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";
|
|
19
|
+
function getConfigDir() {
|
|
20
|
+
return join(homedir(), ".harmony-mcp");
|
|
21
|
+
}
|
|
22
|
+
function getConfigPath() {
|
|
23
|
+
return join(getConfigDir(), "config.json");
|
|
24
|
+
}
|
|
25
|
+
function getLocalConfigPath(cwd) {
|
|
26
|
+
return join(cwd || process.cwd(), LOCAL_CONFIG_FILENAME);
|
|
27
|
+
}
|
|
28
|
+
function loadConfig() {
|
|
29
|
+
const configPath = getConfigPath();
|
|
30
|
+
if (!existsSync(configPath)) {
|
|
31
|
+
return {
|
|
32
|
+
apiKey: null,
|
|
33
|
+
apiUrl: DEFAULT_API_URL,
|
|
34
|
+
activeWorkspaceId: null,
|
|
35
|
+
activeProjectId: null,
|
|
36
|
+
userEmail: null,
|
|
37
|
+
memoryDir: null
|
|
84
38
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const data = readFileSync(configPath, "utf-8");
|
|
42
|
+
const config = JSON.parse(data);
|
|
43
|
+
return {
|
|
44
|
+
apiKey: config.apiKey || null,
|
|
45
|
+
apiUrl: config.apiUrl || DEFAULT_API_URL,
|
|
46
|
+
activeWorkspaceId: config.activeWorkspaceId || null,
|
|
47
|
+
activeProjectId: config.activeProjectId || null,
|
|
48
|
+
userEmail: config.userEmail || null,
|
|
49
|
+
memoryDir: config.memoryDir || null
|
|
50
|
+
};
|
|
51
|
+
} catch {
|
|
52
|
+
return {
|
|
53
|
+
apiKey: null,
|
|
54
|
+
apiUrl: DEFAULT_API_URL,
|
|
55
|
+
activeWorkspaceId: null,
|
|
56
|
+
activeProjectId: null,
|
|
57
|
+
userEmail: null,
|
|
58
|
+
memoryDir: null
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function saveConfig(config) {
|
|
63
|
+
const configDir = getConfigDir();
|
|
64
|
+
const configPath = getConfigPath();
|
|
65
|
+
if (!existsSync(configDir)) {
|
|
66
|
+
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
67
|
+
}
|
|
68
|
+
const existingConfig = loadConfig();
|
|
69
|
+
const newConfig = { ...existingConfig, ...config };
|
|
70
|
+
writeFileSync(configPath, JSON.stringify(newConfig, null, 2), {
|
|
71
|
+
mode: 384
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function loadLocalConfig(cwd) {
|
|
75
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
76
|
+
if (!existsSync(localConfigPath)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const data = readFileSync(localConfigPath, "utf-8");
|
|
81
|
+
const config = JSON.parse(data);
|
|
82
|
+
return {
|
|
83
|
+
workspaceId: config.workspaceId || null,
|
|
84
|
+
projectId: config.projectId || null
|
|
85
|
+
};
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function saveLocalConfig(config, cwd) {
|
|
91
|
+
const localConfigPath = getLocalConfigPath(cwd);
|
|
92
|
+
const existingConfig = loadLocalConfig(cwd) || {
|
|
93
|
+
workspaceId: null,
|
|
94
|
+
projectId: null
|
|
95
|
+
};
|
|
96
|
+
const newConfig = { ...existingConfig, ...config };
|
|
97
|
+
const cleanConfig = {};
|
|
98
|
+
if (newConfig.workspaceId)
|
|
99
|
+
cleanConfig.workspaceId = newConfig.workspaceId;
|
|
100
|
+
if (newConfig.projectId)
|
|
101
|
+
cleanConfig.projectId = newConfig.projectId;
|
|
102
|
+
writeFileSync(localConfigPath, JSON.stringify(cleanConfig, null, 2));
|
|
103
|
+
}
|
|
104
|
+
function hasLocalConfig(cwd) {
|
|
105
|
+
return existsSync(getLocalConfigPath(cwd));
|
|
106
|
+
}
|
|
107
|
+
function getApiKey() {
|
|
108
|
+
const config = loadConfig();
|
|
109
|
+
if (!config.apiKey) {
|
|
110
|
+
throw new Error(`Not configured. Run "npx @gethmy/mcp setup" to set your API key.
|
|
111
|
+
` + "You can generate an API key at https://gethmy.com → Settings → API Keys.");
|
|
112
|
+
}
|
|
113
|
+
return config.apiKey;
|
|
114
|
+
}
|
|
115
|
+
function getApiUrl() {
|
|
116
|
+
const config = loadConfig();
|
|
117
|
+
return config.apiUrl;
|
|
118
|
+
}
|
|
119
|
+
function getUserEmail() {
|
|
120
|
+
const config = loadConfig();
|
|
121
|
+
return config.userEmail;
|
|
122
|
+
}
|
|
123
|
+
function setUserEmail(email) {
|
|
124
|
+
saveConfig({ userEmail: email });
|
|
125
|
+
}
|
|
126
|
+
function setActiveWorkspace(workspaceId, options) {
|
|
127
|
+
if (options?.local) {
|
|
128
|
+
saveLocalConfig({ workspaceId }, options.cwd);
|
|
129
|
+
} else {
|
|
130
|
+
saveConfig({ activeWorkspaceId: workspaceId });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function setActiveProject(projectId, options) {
|
|
134
|
+
if (options?.local) {
|
|
135
|
+
saveLocalConfig({ projectId }, options.cwd);
|
|
136
|
+
} else {
|
|
137
|
+
saveConfig({ activeProjectId: projectId });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function getActiveWorkspaceId(cwd) {
|
|
141
|
+
const localConfig = loadLocalConfig(cwd);
|
|
142
|
+
if (localConfig?.workspaceId) {
|
|
143
|
+
return localConfig.workspaceId;
|
|
144
|
+
}
|
|
145
|
+
return loadConfig().activeWorkspaceId;
|
|
146
|
+
}
|
|
147
|
+
function getActiveProjectId(cwd) {
|
|
148
|
+
const localConfig = loadLocalConfig(cwd);
|
|
149
|
+
if (localConfig?.projectId) {
|
|
150
|
+
return localConfig.projectId;
|
|
151
|
+
}
|
|
152
|
+
return loadConfig().activeProjectId;
|
|
153
|
+
}
|
|
154
|
+
function isConfigured() {
|
|
155
|
+
const config = loadConfig();
|
|
156
|
+
return !!config.apiKey;
|
|
157
|
+
}
|
|
158
|
+
function areSkillsInstalled(cwd) {
|
|
159
|
+
const home = homedir();
|
|
160
|
+
const workingDir = cwd || process.cwd();
|
|
161
|
+
const foundPaths = [];
|
|
162
|
+
const globalSkillsDir = join(home, ".agents", "skills");
|
|
163
|
+
const globalSkillPath = join(globalSkillsDir, "hmy", "SKILL.md");
|
|
164
|
+
if (existsSync(globalSkillPath)) {
|
|
165
|
+
foundPaths.push(globalSkillPath);
|
|
166
|
+
return { installed: true, location: "global", paths: foundPaths };
|
|
167
|
+
}
|
|
168
|
+
const claudeGlobalSkill = join(home, ".claude", "skills", "hmy.md");
|
|
169
|
+
if (existsSync(claudeGlobalSkill)) {
|
|
170
|
+
foundPaths.push(claudeGlobalSkill);
|
|
171
|
+
return { installed: true, location: "global", paths: foundPaths };
|
|
172
|
+
}
|
|
173
|
+
const claudeGlobalSkillAlt = join(home, ".claude", "skills", "hmy", "SKILL.md");
|
|
174
|
+
if (existsSync(claudeGlobalSkillAlt)) {
|
|
175
|
+
foundPaths.push(claudeGlobalSkillAlt);
|
|
176
|
+
return { installed: true, location: "global", paths: foundPaths };
|
|
177
|
+
}
|
|
178
|
+
const localSkillPath = join(workingDir, ".claude", "skills", "hmy.md");
|
|
179
|
+
if (existsSync(localSkillPath)) {
|
|
180
|
+
foundPaths.push(localSkillPath);
|
|
181
|
+
return { installed: true, location: "local", paths: foundPaths };
|
|
182
|
+
}
|
|
183
|
+
const localSkillPathAlt = join(workingDir, ".claude", "skills", "hmy", "SKILL.md");
|
|
184
|
+
if (existsSync(localSkillPathAlt)) {
|
|
185
|
+
foundPaths.push(localSkillPathAlt);
|
|
186
|
+
return { installed: true, location: "local", paths: foundPaths };
|
|
187
|
+
}
|
|
188
|
+
return { installed: false, location: null, paths: [] };
|
|
189
|
+
}
|
|
190
|
+
function hasProjectContext(cwd) {
|
|
191
|
+
const localConfig = loadLocalConfig(cwd);
|
|
192
|
+
return !!(localConfig?.workspaceId || localConfig?.projectId);
|
|
193
|
+
}
|
|
194
|
+
function getMemoryDir() {
|
|
195
|
+
const config = loadConfig();
|
|
196
|
+
if (config.memoryDir)
|
|
197
|
+
return config.memoryDir;
|
|
198
|
+
return join(homedir(), ".harmony", "memory");
|
|
199
|
+
}
|
|
200
|
+
export {
|
|
201
|
+
setUserEmail,
|
|
202
|
+
setActiveWorkspace,
|
|
203
|
+
setActiveProject,
|
|
204
|
+
saveLocalConfig,
|
|
205
|
+
saveConfig,
|
|
206
|
+
loadLocalConfig,
|
|
207
|
+
loadConfig,
|
|
208
|
+
isConfigured,
|
|
209
|
+
hasProjectContext,
|
|
210
|
+
hasLocalConfig,
|
|
211
|
+
getUserEmail,
|
|
212
|
+
getMemoryDir,
|
|
213
|
+
getLocalConfigPath,
|
|
214
|
+
getConfigPath,
|
|
215
|
+
getConfigDir,
|
|
216
|
+
getApiUrl,
|
|
217
|
+
getApiKey,
|
|
218
|
+
getActiveWorkspaceId,
|
|
219
|
+
getActiveProjectId,
|
|
220
|
+
areSkillsInstalled
|
|
221
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gethmy/mcp",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./dist/index.js",
|
|
12
|
-
"./src
|
|
13
|
-
"types": "./src
|
|
14
|
-
"default": "./dist/lib
|
|
12
|
+
"./src/api-client.js": {
|
|
13
|
+
"types": "./src/api-client.ts",
|
|
14
|
+
"default": "./dist/lib/api-client.js"
|
|
15
|
+
},
|
|
16
|
+
"./src/config.js": {
|
|
17
|
+
"types": "./src/config.ts",
|
|
18
|
+
"default": "./dist/lib/config.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"bin": {
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
"bun": ">=1.0.0"
|
|
51
55
|
},
|
|
52
56
|
"scripts": {
|
|
53
|
-
"build": "bun build src/index.ts src/cli.ts --outdir dist --target node &&
|
|
57
|
+
"build": "bun build src/index.ts src/cli.ts --outdir dist --target node && bun build src/api-client.ts src/config.ts --outdir dist/lib --root src --target node",
|
|
54
58
|
"build:bun": "bun build src/index.ts src/http.ts src/remote.ts src/cli.ts --outdir dist --target bun",
|
|
55
59
|
"serve:remote": "bun src/remote.ts",
|
|
56
60
|
"dev": "bun --watch src/index.ts",
|
package/src/memory-cleanup.ts
CHANGED
|
@@ -339,8 +339,7 @@ function runPruneStep(
|
|
|
339
339
|
const stale: PruneStepResult["items"] = [];
|
|
340
340
|
|
|
341
341
|
for (const entity of drafts) {
|
|
342
|
-
const ageDays =
|
|
343
|
-
(now - new Date(entity.created_at).getTime()) / MS_PER_DAY;
|
|
342
|
+
const ageDays = (now - new Date(entity.created_at).getTime()) / MS_PER_DAY;
|
|
344
343
|
if (ageDays < maxAgeDays) continue;
|
|
345
344
|
|
|
346
345
|
const lifecycle = evaluateLifecycle(entity);
|
|
@@ -367,8 +366,7 @@ async function runOrphanStep(
|
|
|
367
366
|
const candidates = entities.filter((e) => {
|
|
368
367
|
if (e.memory_tier === "reference") return false;
|
|
369
368
|
if (e.access_count >= 2) return false;
|
|
370
|
-
const ageDays =
|
|
371
|
-
(now - new Date(e.created_at).getTime()) / MS_PER_DAY;
|
|
369
|
+
const ageDays = (now - new Date(e.created_at).getTime()) / MS_PER_DAY;
|
|
372
370
|
return ageDays >= orphanAgeDays;
|
|
373
371
|
});
|
|
374
372
|
|