@gethmy/mcp 2.2.1 → 2.2.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/README.md +5 -7
- package/dist/cli.js +405 -143
- package/dist/http.js +6 -4
- package/dist/index.js +164 -85
- package/dist/lib/auto-session.js +1 -1
- package/dist/lib/cli.js +9 -0
- package/dist/lib/onboard.js +36 -0
- package/dist/lib/server.js +129 -73
- package/dist/lib/skills.js +1 -1
- package/dist/lib/tui/setup.js +212 -59
- package/dist/remote.js +7132 -10614
- package/package.json +2 -1
- package/src/auto-session.ts +1 -1
- package/src/cli.ts +9 -0
- package/src/onboard.ts +93 -0
- package/src/server.ts +153 -102
- package/src/skills.ts +1 -1
- package/src/tui/setup.ts +249 -67
package/dist/http.js
CHANGED
|
@@ -26,6 +26,7 @@ var __export = (target, all) => {
|
|
|
26
26
|
set: (newValue) => all[name] = () => newValue
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
30
|
var __require = import.meta.require;
|
|
30
31
|
|
|
31
32
|
// src/http.ts
|
|
@@ -1637,7 +1638,7 @@ var cors = (options) => {
|
|
|
1637
1638
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1638
1639
|
import { homedir } from "os";
|
|
1639
1640
|
import { join } from "path";
|
|
1640
|
-
var DEFAULT_API_URL = "https://gethmy.com/api";
|
|
1641
|
+
var DEFAULT_API_URL = "https://app.gethmy.com/api";
|
|
1641
1642
|
var LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";
|
|
1642
1643
|
function getConfigDir() {
|
|
1643
1644
|
return join(homedir(), ".harmony-mcp");
|
|
@@ -1730,7 +1731,7 @@ function hasLocalConfig(cwd) {
|
|
|
1730
1731
|
function getApiKey() {
|
|
1731
1732
|
const config = loadConfig();
|
|
1732
1733
|
if (!config.apiKey) {
|
|
1733
|
-
throw new Error(`Not configured. Run "
|
|
1734
|
+
throw new Error(`Not configured. Run "npx @gethmy/mcp setup" to set your API key.
|
|
1734
1735
|
` + "You can generate an API key at https://gethmy.com \u2192 Settings \u2192 API Keys.");
|
|
1735
1736
|
}
|
|
1736
1737
|
return config.apiKey;
|
|
@@ -1823,6 +1824,7 @@ var app = new Hono2;
|
|
|
1823
1824
|
app.use("/*", cors({
|
|
1824
1825
|
origin: [
|
|
1825
1826
|
"https://gethmy.com",
|
|
1827
|
+
"https://app.gethmy.com",
|
|
1826
1828
|
"http://localhost:8080",
|
|
1827
1829
|
"http://localhost:3000"
|
|
1828
1830
|
],
|
|
@@ -1841,7 +1843,7 @@ async function forwardToApi(method, path, authHeader, apiKey, body) {
|
|
|
1841
1843
|
if (apiKey) {
|
|
1842
1844
|
headers["X-API-Key"] = apiKey;
|
|
1843
1845
|
} else if (authHeader) {
|
|
1844
|
-
headers
|
|
1846
|
+
headers.Authorization = authHeader;
|
|
1845
1847
|
} else {
|
|
1846
1848
|
throw new Error("Unauthorized: Missing API key or Authorization header");
|
|
1847
1849
|
}
|
|
@@ -1899,7 +1901,7 @@ async function handleRequest(c, method, path) {
|
|
|
1899
1901
|
try {
|
|
1900
1902
|
const authHeader = c.req.header("Authorization");
|
|
1901
1903
|
const apiKey = c.req.header("X-API-Key");
|
|
1902
|
-
let body
|
|
1904
|
+
let body;
|
|
1903
1905
|
if (["POST", "PATCH", "PUT"].includes(method)) {
|
|
1904
1906
|
try {
|
|
1905
1907
|
body = await c.json();
|
package/dist/index.js
CHANGED
|
@@ -29,19 +29,19 @@ var __export = (target, all) => {
|
|
|
29
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
30
30
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
31
31
|
|
|
32
|
-
// ../memory/
|
|
32
|
+
// ../memory/dist/schema.js
|
|
33
33
|
var init_schema = () => {};
|
|
34
34
|
|
|
35
|
-
// ../memory/
|
|
35
|
+
// ../memory/dist/constraints.js
|
|
36
36
|
var init_constraints = __esm(() => {
|
|
37
37
|
init_schema();
|
|
38
38
|
});
|
|
39
|
-
// ../memory/
|
|
39
|
+
// ../memory/dist/client.js
|
|
40
40
|
var init_client = __esm(() => {
|
|
41
41
|
init_constraints();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
// ../memory/
|
|
44
|
+
// ../memory/dist/graph-walk.js
|
|
45
45
|
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
46
46
|
const visited = new Set;
|
|
47
47
|
const collectedEntities = [];
|
|
@@ -122,7 +122,7 @@ async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntitie
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
// ../memory/
|
|
125
|
+
// ../memory/dist/lifecycle.js
|
|
126
126
|
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
127
127
|
const halfLife = DECAY_HALF_LIVES[tier];
|
|
128
128
|
const now = Date.now();
|
|
@@ -207,7 +207,7 @@ var init_lifecycle = __esm(() => {
|
|
|
207
207
|
};
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
-
// ../memory/
|
|
210
|
+
// ../memory/dist/sync-storage.js
|
|
211
211
|
function parseSyncMarkdown(markdown) {
|
|
212
212
|
const trimmed = markdown.trim();
|
|
213
213
|
let frontmatter = {
|
|
@@ -323,16 +323,9 @@ function parseYamlArray(value) {
|
|
|
323
323
|
return match[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
-
// ../memory/
|
|
326
|
+
// ../memory/dist/sync.js
|
|
327
327
|
import { createHash } from "node:crypto";
|
|
328
|
-
import {
|
|
329
|
-
existsSync,
|
|
330
|
-
mkdirSync,
|
|
331
|
-
readdirSync,
|
|
332
|
-
readFileSync,
|
|
333
|
-
rmSync,
|
|
334
|
-
writeFileSync
|
|
335
|
-
} from "node:fs";
|
|
328
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
336
329
|
import { join, relative, sep } from "node:path";
|
|
337
330
|
function computeFileHash(content) {
|
|
338
331
|
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
@@ -597,8 +590,8 @@ async function syncFull(client, config, workspaceId, projectId) {
|
|
|
597
590
|
}
|
|
598
591
|
var init_sync = () => {};
|
|
599
592
|
|
|
600
|
-
// ../memory/
|
|
601
|
-
var
|
|
593
|
+
// ../memory/dist/index.js
|
|
594
|
+
var init_dist = __esm(() => {
|
|
602
595
|
init_client();
|
|
603
596
|
init_constraints();
|
|
604
597
|
init_lifecycle();
|
|
@@ -7562,7 +7555,7 @@ async function recordContextFeedback(client2, cardId, sessionStatus, progressPer
|
|
|
7562
7555
|
}
|
|
7563
7556
|
var DEFAULT_TOKEN_BUDGET = 4000, MAX_TOKENS_PER_ENTITY = 500, MIN_RELEVANCE_THRESHOLD = 0.1, TIER_WEIGHTS, PROCEDURE_BUDGET_FRACTION = 0.15, TIER_BUDGET_ALLOCATION, MIN_REFERENCE_SLOTS = 3, manifestCache, MAX_CACHE_SIZE = 50, sessionAssemblyMap, MAX_SESSION_MAP_SIZE = 100;
|
|
7564
7557
|
var init_context_assembly = __esm(() => {
|
|
7565
|
-
|
|
7558
|
+
init_dist();
|
|
7566
7559
|
TIER_WEIGHTS = {
|
|
7567
7560
|
reference: 1,
|
|
7568
7561
|
episode: 0.7,
|
|
@@ -8017,7 +8010,7 @@ var init_prompt_builder = __esm(() => {
|
|
|
8017
8010
|
});
|
|
8018
8011
|
|
|
8019
8012
|
// src/server.ts
|
|
8020
|
-
|
|
8013
|
+
init_dist();
|
|
8021
8014
|
|
|
8022
8015
|
// ../../node_modules/zod/v4/core/index.js
|
|
8023
8016
|
var exports_core2 = {};
|
|
@@ -25789,7 +25782,7 @@ function deriveClusterTitle(cluster, type) {
|
|
|
25789
25782
|
init_context_assembly();
|
|
25790
25783
|
|
|
25791
25784
|
// src/lifecycle-maintenance.ts
|
|
25792
|
-
|
|
25785
|
+
init_dist();
|
|
25793
25786
|
async function runLifecycleMaintenance(client3, workspaceId, projectId) {
|
|
25794
25787
|
const result = {
|
|
25795
25788
|
archived: 0,
|
|
@@ -25858,6 +25851,47 @@ async function runLifecycleMaintenance(client3, workspaceId, projectId) {
|
|
|
25858
25851
|
return result;
|
|
25859
25852
|
}
|
|
25860
25853
|
|
|
25854
|
+
// src/onboard.ts
|
|
25855
|
+
async function onboardNewUser(params) {
|
|
25856
|
+
const {
|
|
25857
|
+
email: email3,
|
|
25858
|
+
password,
|
|
25859
|
+
fullName,
|
|
25860
|
+
workspaceName = `${fullName}'s Workspace`,
|
|
25861
|
+
projectName = "My First Board",
|
|
25862
|
+
template = "kanban",
|
|
25863
|
+
keyName = "mcp-agent",
|
|
25864
|
+
apiUrl = getApiUrl()
|
|
25865
|
+
} = params;
|
|
25866
|
+
const signupResult = await signupUser(apiUrl, {
|
|
25867
|
+
email: email3,
|
|
25868
|
+
password,
|
|
25869
|
+
full_name: fullName
|
|
25870
|
+
});
|
|
25871
|
+
const token = signupResult.session.access_token;
|
|
25872
|
+
const workspaceResult = await requestWithBearer(apiUrl, token, "POST", "/workspaces", {
|
|
25873
|
+
name: workspaceName
|
|
25874
|
+
});
|
|
25875
|
+
const projectResult = await requestWithBearer(apiUrl, token, "POST", "/projects", {
|
|
25876
|
+
workspaceId: workspaceResult.workspace.id,
|
|
25877
|
+
name: projectName,
|
|
25878
|
+
template
|
|
25879
|
+
});
|
|
25880
|
+
const keyResult = await requestWithBearer(apiUrl, token, "POST", "/api-keys", {
|
|
25881
|
+
name: keyName
|
|
25882
|
+
});
|
|
25883
|
+
return {
|
|
25884
|
+
user: signupResult.user,
|
|
25885
|
+
workspace: workspaceResult.workspace,
|
|
25886
|
+
project: projectResult.project,
|
|
25887
|
+
columns: projectResult.columns,
|
|
25888
|
+
apiKey: {
|
|
25889
|
+
rawKey: keyResult.rawKey,
|
|
25890
|
+
prefix: keyResult.apiKey.prefix
|
|
25891
|
+
}
|
|
25892
|
+
};
|
|
25893
|
+
}
|
|
25894
|
+
|
|
25861
25895
|
// src/server.ts
|
|
25862
25896
|
var memorySessions = new Map;
|
|
25863
25897
|
function initMemorySession(cardId, agentIdentifier, agentName) {
|
|
@@ -25992,18 +26026,22 @@ var TOOLS = {
|
|
|
25992
26026
|
}
|
|
25993
26027
|
},
|
|
25994
26028
|
harmony_move_card: {
|
|
25995
|
-
description: "Move a card to a different column or position",
|
|
26029
|
+
description: "Move a card to a different column or position. Provide either columnId (UUID) or columnName (e.g. 'Review', 'Done').",
|
|
25996
26030
|
inputSchema: {
|
|
25997
26031
|
type: "object",
|
|
25998
26032
|
properties: {
|
|
25999
26033
|
cardId: { type: "string", description: "Card ID to move" },
|
|
26000
|
-
columnId: { type: "string", description: "Target column ID" },
|
|
26034
|
+
columnId: { type: "string", description: "Target column ID (UUID)" },
|
|
26035
|
+
columnName: {
|
|
26036
|
+
type: "string",
|
|
26037
|
+
description: "Target column name (e.g. 'To Do', 'In Progress', 'Review', 'Done'). Used if columnId is not provided."
|
|
26038
|
+
},
|
|
26001
26039
|
position: {
|
|
26002
26040
|
type: "number",
|
|
26003
26041
|
description: "Position in column (0-indexed)"
|
|
26004
26042
|
}
|
|
26005
26043
|
},
|
|
26006
|
-
required: ["cardId"
|
|
26044
|
+
required: ["cardId"]
|
|
26007
26045
|
}
|
|
26008
26046
|
},
|
|
26009
26047
|
harmony_archive_card: {
|
|
@@ -26134,14 +26172,21 @@ var TOOLS = {
|
|
|
26134
26172
|
}
|
|
26135
26173
|
},
|
|
26136
26174
|
harmony_add_label_to_card: {
|
|
26137
|
-
description: "Add a label to a card",
|
|
26175
|
+
description: "Add a label to a card. Provide labelId directly, or labelName to look up (or auto-create) the label by name.",
|
|
26138
26176
|
inputSchema: {
|
|
26139
26177
|
type: "object",
|
|
26140
26178
|
properties: {
|
|
26141
26179
|
cardId: { type: "string" },
|
|
26142
|
-
labelId: {
|
|
26180
|
+
labelId: {
|
|
26181
|
+
type: "string",
|
|
26182
|
+
description: "Label ID (optional if labelName provided)"
|
|
26183
|
+
},
|
|
26184
|
+
labelName: {
|
|
26185
|
+
type: "string",
|
|
26186
|
+
description: "Label name — will look up or create if not found"
|
|
26187
|
+
}
|
|
26143
26188
|
},
|
|
26144
|
-
required: ["cardId"
|
|
26189
|
+
required: ["cardId"]
|
|
26145
26190
|
}
|
|
26146
26191
|
},
|
|
26147
26192
|
harmony_remove_label_from_card: {
|
|
@@ -27458,6 +27503,17 @@ function registerHandlers(server, deps) {
|
|
|
27458
27503
|
throw new Error(`Unknown resource: ${uri}`);
|
|
27459
27504
|
});
|
|
27460
27505
|
}
|
|
27506
|
+
async function resolveColumnByName(client3, projectId, columnName) {
|
|
27507
|
+
const board = await client3.getBoard(projectId, { summary: true });
|
|
27508
|
+
const columns = board.columns;
|
|
27509
|
+
const lower = columnName.toLowerCase();
|
|
27510
|
+
const col = columns.find((c) => c.name.toLowerCase() === lower) || columns.find((c) => c.name.toLowerCase().includes(lower));
|
|
27511
|
+
if (!col) {
|
|
27512
|
+
const available = columns.map((c) => c.name).join(", ");
|
|
27513
|
+
throw new Error(`Column "${columnName}" not found. Available columns: ${available}`);
|
|
27514
|
+
}
|
|
27515
|
+
return col;
|
|
27516
|
+
}
|
|
27461
27517
|
async function handleToolCall(name, args, deps) {
|
|
27462
27518
|
const unauthenticatedTools = ["harmony_signup", "harmony_onboard"];
|
|
27463
27519
|
if (!unauthenticatedTools.includes(name) && !deps.isConfigured()) {
|
|
@@ -27507,16 +27563,29 @@ async function handleToolCall(name, args, deps) {
|
|
|
27507
27563
|
}
|
|
27508
27564
|
case "harmony_move_card": {
|
|
27509
27565
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
27510
|
-
const columnId = exports_external.string().uuid().parse(args.columnId);
|
|
27511
27566
|
const position = args.position !== undefined ? exports_external.number().int().min(0).parse(args.position) : undefined;
|
|
27567
|
+
let columnId;
|
|
27568
|
+
let resolvedProjectId;
|
|
27569
|
+
if (args.columnId) {
|
|
27570
|
+
columnId = exports_external.string().uuid().parse(args.columnId);
|
|
27571
|
+
} else if (args.columnName) {
|
|
27572
|
+
const columnName = exports_external.string().parse(args.columnName);
|
|
27573
|
+
const { card: cardForProject } = await client3.getCard(cardId);
|
|
27574
|
+
resolvedProjectId = cardForProject?.project_id;
|
|
27575
|
+
if (!resolvedProjectId)
|
|
27576
|
+
throw new Error("Card has no project");
|
|
27577
|
+
const col = await resolveColumnByName(client3, resolvedProjectId, columnName);
|
|
27578
|
+
columnId = col.id;
|
|
27579
|
+
} else {
|
|
27580
|
+
throw new Error("Either columnId or columnName is required");
|
|
27581
|
+
}
|
|
27512
27582
|
const result = await client3.moveCard(cardId, columnId, position);
|
|
27513
27583
|
let sessionEnded = false;
|
|
27514
27584
|
try {
|
|
27515
27585
|
const { card } = result;
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
});
|
|
27586
|
+
const projectId = card?.project_id || resolvedProjectId;
|
|
27587
|
+
if (projectId) {
|
|
27588
|
+
const board = await client3.getBoard(projectId, { summary: true });
|
|
27520
27589
|
const columns = board.columns;
|
|
27521
27590
|
const destCol = columns.find((c) => c.id === columnId);
|
|
27522
27591
|
const colName = destCol?.name?.toLowerCase() || "";
|
|
@@ -27603,7 +27672,32 @@ async function handleToolCall(name, args, deps) {
|
|
|
27603
27672
|
}
|
|
27604
27673
|
case "harmony_add_label_to_card": {
|
|
27605
27674
|
const cardId = exports_external.string().uuid().parse(args.cardId);
|
|
27606
|
-
|
|
27675
|
+
let labelId = args.labelId ? exports_external.string().uuid().parse(args.labelId) : undefined;
|
|
27676
|
+
const labelName = args.labelName ? exports_external.string().min(1).max(100).parse(args.labelName) : undefined;
|
|
27677
|
+
if (!labelId && labelName) {
|
|
27678
|
+
const { card } = await client3.getCard(cardId);
|
|
27679
|
+
const projectId = card.project_id;
|
|
27680
|
+
if (!projectId) {
|
|
27681
|
+
throw new Error("Cannot resolve label by name: card has no project_id");
|
|
27682
|
+
}
|
|
27683
|
+
if (projectId) {
|
|
27684
|
+
const board = await client3.getBoard(projectId, { summary: true });
|
|
27685
|
+
const labels = board.labels;
|
|
27686
|
+
const existing = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
27687
|
+
if (existing) {
|
|
27688
|
+
labelId = existing.id;
|
|
27689
|
+
} else {
|
|
27690
|
+
const created = await client3.createLabel(projectId, {
|
|
27691
|
+
name: labelName,
|
|
27692
|
+
color: "#57b8a5"
|
|
27693
|
+
});
|
|
27694
|
+
labelId = created.label.id;
|
|
27695
|
+
}
|
|
27696
|
+
}
|
|
27697
|
+
}
|
|
27698
|
+
if (!labelId) {
|
|
27699
|
+
throw new Error("Either labelId or labelName must be provided");
|
|
27700
|
+
}
|
|
27607
27701
|
await client3.addLabelToCard(cardId, labelId);
|
|
27608
27702
|
return { success: true };
|
|
27609
27703
|
}
|
|
@@ -27733,10 +27827,17 @@ async function handleToolCall(name, args, deps) {
|
|
|
27733
27827
|
}
|
|
27734
27828
|
if (addLabels?.length) {
|
|
27735
27829
|
for (const labelName of addLabels) {
|
|
27736
|
-
|
|
27830
|
+
let label = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
27831
|
+
if (!label && projectId) {
|
|
27832
|
+
const created = await client3.createLabel(projectId, {
|
|
27833
|
+
name: labelName,
|
|
27834
|
+
color: "#57b8a5"
|
|
27835
|
+
});
|
|
27836
|
+
label = created.label;
|
|
27837
|
+
}
|
|
27737
27838
|
if (label) {
|
|
27738
27839
|
await client3.addLabelToCard(cardId, label.id);
|
|
27739
|
-
labelsAdded.push(label.name);
|
|
27840
|
+
labelsAdded.push(label.name ?? labelName);
|
|
27740
27841
|
}
|
|
27741
27842
|
}
|
|
27742
27843
|
}
|
|
@@ -27856,27 +27957,21 @@ async function handleToolCall(name, args, deps) {
|
|
|
27856
27957
|
const endProgressPercent = args.progressPercent !== undefined ? exports_external.number().min(0).max(100).parse(args.progressPercent) : undefined;
|
|
27857
27958
|
await flushMemoryActions(client3, cardId);
|
|
27858
27959
|
cleanupMemorySession(cardId);
|
|
27859
|
-
|
|
27860
|
-
|
|
27861
|
-
|
|
27862
|
-
|
|
27960
|
+
let result = { session: null };
|
|
27961
|
+
let sessionEndError = null;
|
|
27962
|
+
try {
|
|
27963
|
+
result = await client3.endAgentSession(cardId, {
|
|
27964
|
+
status: sessionStatus,
|
|
27965
|
+
progressPercent: endProgressPercent
|
|
27966
|
+
});
|
|
27967
|
+
} catch (err) {
|
|
27968
|
+
sessionEndError = err instanceof Error ? err.message : "Failed to end session";
|
|
27969
|
+
}
|
|
27863
27970
|
untrack(cardId);
|
|
27864
27971
|
let movedTo = null;
|
|
27865
|
-
const _learningsExtracted = 0;
|
|
27866
|
-
let _cardTitle = "";
|
|
27867
|
-
let _cardLabels = [];
|
|
27868
|
-
let _cardDescription = "";
|
|
27869
|
-
let _cardSubtasks = [];
|
|
27870
27972
|
try {
|
|
27871
27973
|
const { card } = await client3.getCard(cardId);
|
|
27872
27974
|
const typedCard = card;
|
|
27873
|
-
_cardTitle = typedCard.title || "";
|
|
27874
|
-
_cardLabels = (typedCard.labels || []).map((l) => l.name);
|
|
27875
|
-
_cardDescription = typedCard.description || "";
|
|
27876
|
-
_cardSubtasks = (typedCard.subtasks || []).map((s) => ({
|
|
27877
|
-
title: s.title,
|
|
27878
|
-
done: s.done
|
|
27879
|
-
}));
|
|
27880
27975
|
const projectId = typedCard.project_id;
|
|
27881
27976
|
if (sessionStatus === "completed" && typedCard.labels?.length) {
|
|
27882
27977
|
const agentLabel = typedCard.labels.find((l) => l.name.toLowerCase() === "agent");
|
|
@@ -27885,21 +27980,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
27885
27980
|
}
|
|
27886
27981
|
}
|
|
27887
27982
|
if (moveToColumn && projectId) {
|
|
27888
|
-
const
|
|
27889
|
-
|
|
27890
|
-
|
|
27891
|
-
const columns = board.columns;
|
|
27892
|
-
const col = columns.find((c) => c.name.toLowerCase().includes(moveToColumn.toLowerCase()));
|
|
27893
|
-
if (col) {
|
|
27894
|
-
await client3.moveCard(cardId, col.id);
|
|
27895
|
-
movedTo = col.name;
|
|
27896
|
-
}
|
|
27983
|
+
const col = await resolveColumnByName(client3, projectId, moveToColumn);
|
|
27984
|
+
await client3.moveCard(cardId, col.id);
|
|
27985
|
+
movedTo = col.name;
|
|
27897
27986
|
}
|
|
27898
27987
|
} catch {}
|
|
27899
27988
|
const sessionObj = result.session;
|
|
27900
27989
|
const pipelineResult = await runEndSessionPipeline(client3, deps, cardId, sessionStatus, endProgressPercent, sessionObj);
|
|
27901
27990
|
return {
|
|
27902
27991
|
success: true,
|
|
27992
|
+
...sessionEndError && { sessionEndError },
|
|
27903
27993
|
movedTo,
|
|
27904
27994
|
learningsExtracted: pipelineResult.learningsExtracted,
|
|
27905
27995
|
feedbackAdjusted: pipelineResult.feedbackAdjusted,
|
|
@@ -28641,38 +28731,27 @@ async function handleToolCall(name, args, deps) {
|
|
|
28641
28731
|
const projectName = args.projectName || "My First Project";
|
|
28642
28732
|
const template = args.template || "kanban";
|
|
28643
28733
|
const keyName = args.keyName || "mcp-agent";
|
|
28644
|
-
const
|
|
28645
|
-
const signupResult = await signupUser(apiUrl, {
|
|
28734
|
+
const result = await onboardNewUser({
|
|
28646
28735
|
email: email3,
|
|
28647
28736
|
password,
|
|
28648
|
-
|
|
28649
|
-
|
|
28650
|
-
|
|
28651
|
-
|
|
28652
|
-
|
|
28737
|
+
fullName,
|
|
28738
|
+
workspaceName,
|
|
28739
|
+
projectName,
|
|
28740
|
+
template,
|
|
28741
|
+
keyName,
|
|
28742
|
+
apiUrl: deps.getApiUrl()
|
|
28653
28743
|
});
|
|
28654
|
-
|
|
28655
|
-
|
|
28656
|
-
|
|
28657
|
-
template
|
|
28658
|
-
});
|
|
28659
|
-
const keyResult = await requestWithBearer(apiUrl, token, "POST", "/api-keys", {
|
|
28660
|
-
name: keyName
|
|
28661
|
-
});
|
|
28662
|
-
deps.saveConfig({ apiKey: keyResult.rawKey });
|
|
28663
|
-
deps.setActiveWorkspace(workspaceResult.workspace.id);
|
|
28664
|
-
deps.setActiveProject(projectResult.project.id);
|
|
28744
|
+
deps.saveConfig({ apiKey: result.apiKey.rawKey });
|
|
28745
|
+
deps.setActiveWorkspace(result.workspace.id);
|
|
28746
|
+
deps.setActiveProject(result.project.id);
|
|
28665
28747
|
deps.resetClient();
|
|
28666
28748
|
return {
|
|
28667
28749
|
success: true,
|
|
28668
|
-
user:
|
|
28669
|
-
workspace:
|
|
28670
|
-
project:
|
|
28671
|
-
columns:
|
|
28672
|
-
apiKey:
|
|
28673
|
-
rawKey: keyResult.rawKey,
|
|
28674
|
-
prefix: keyResult.apiKey.prefix
|
|
28675
|
-
},
|
|
28750
|
+
user: result.user,
|
|
28751
|
+
workspace: result.workspace,
|
|
28752
|
+
project: result.project,
|
|
28753
|
+
columns: result.columns,
|
|
28754
|
+
apiKey: result.apiKey,
|
|
28676
28755
|
message: `Onboarding complete! Account created for ${email3}. Workspace "${workspaceName}" and project "${projectName}" are ready. API key saved to config.`
|
|
28677
28756
|
};
|
|
28678
28757
|
}
|
package/dist/lib/auto-session.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* after 10 minutes of inactivity or when a different card is worked on.
|
|
7
7
|
*
|
|
8
8
|
* Agent identity is resolved from the MCP client's `initialize` handshake
|
|
9
|
-
* (clientInfo.name), so "Claude Code", "Cursor", "
|
|
9
|
+
* (clientInfo.name), so "Claude Code", "Cursor", "Codex", etc. are
|
|
10
10
|
* detected automatically — no hardcoded fallback needed.
|
|
11
11
|
*/
|
|
12
12
|
/** Well-known MCP client names → human-friendly display names */
|
package/dist/lib/cli.js
CHANGED
|
@@ -15,6 +15,11 @@ program
|
|
|
15
15
|
.command("serve")
|
|
16
16
|
.description("Start the MCP server (stdio transport)")
|
|
17
17
|
.action(async () => {
|
|
18
|
+
if (!isConfigured()) {
|
|
19
|
+
console.error("No API key configured.");
|
|
20
|
+
console.error("Run: npx @gethmy/mcp setup");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
18
23
|
await refreshSkills();
|
|
19
24
|
const server = new HarmonyMCPServer();
|
|
20
25
|
await server.run();
|
|
@@ -109,6 +114,8 @@ program
|
|
|
109
114
|
.option("-p, --project <id>", "Set project context")
|
|
110
115
|
.option("--skip-context", "Skip workspace/project selection")
|
|
111
116
|
.option("--skip-docs", "Skip project docs scaffold/verification")
|
|
117
|
+
.option("--new", "Create a new account (skip the choice prompt)")
|
|
118
|
+
.option("-n, --name <name>", "Full name (for account creation)")
|
|
112
119
|
.action(async (options) => {
|
|
113
120
|
await runSetup({
|
|
114
121
|
force: options.force,
|
|
@@ -124,6 +131,8 @@ program
|
|
|
124
131
|
projectId: options.project,
|
|
125
132
|
skipContext: options.skipContext,
|
|
126
133
|
skipDocs: options.skipDocs,
|
|
134
|
+
newAccount: options.new,
|
|
135
|
+
name: options.name,
|
|
127
136
|
});
|
|
128
137
|
});
|
|
129
138
|
program.parse();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { requestWithBearer, signupUser } from "./api-client.js";
|
|
2
|
+
import { getApiUrl } from "./config.js";
|
|
3
|
+
export async function onboardNewUser(params) {
|
|
4
|
+
const { email, password, fullName, workspaceName = `${fullName}'s Workspace`, projectName = "My First Board", template = "kanban", keyName = "mcp-agent", apiUrl = getApiUrl(), } = params;
|
|
5
|
+
// 1. Signup
|
|
6
|
+
const signupResult = await signupUser(apiUrl, {
|
|
7
|
+
email,
|
|
8
|
+
password,
|
|
9
|
+
full_name: fullName,
|
|
10
|
+
});
|
|
11
|
+
const token = signupResult.session.access_token;
|
|
12
|
+
// 2. Create workspace
|
|
13
|
+
const workspaceResult = await requestWithBearer(apiUrl, token, "POST", "/workspaces", {
|
|
14
|
+
name: workspaceName,
|
|
15
|
+
});
|
|
16
|
+
// 3. Create project
|
|
17
|
+
const projectResult = await requestWithBearer(apiUrl, token, "POST", "/projects", {
|
|
18
|
+
workspaceId: workspaceResult.workspace.id,
|
|
19
|
+
name: projectName,
|
|
20
|
+
template,
|
|
21
|
+
});
|
|
22
|
+
// 4. Generate API key
|
|
23
|
+
const keyResult = await requestWithBearer(apiUrl, token, "POST", "/api-keys", {
|
|
24
|
+
name: keyName,
|
|
25
|
+
});
|
|
26
|
+
return {
|
|
27
|
+
user: signupResult.user,
|
|
28
|
+
workspace: workspaceResult.workspace,
|
|
29
|
+
project: projectResult.project,
|
|
30
|
+
columns: projectResult.columns,
|
|
31
|
+
apiKey: {
|
|
32
|
+
rawKey: keyResult.rawKey,
|
|
33
|
+
prefix: keyResult.apiKey.prefix,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|