@gethmy/mcp 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -7
- package/dist/cli.js +2515 -2134
- package/dist/http.js +6 -4
- package/dist/index.js +8088 -7890
- package/dist/lib/__tests__/auto-session.test.js +33 -33
- package/dist/lib/api-client.js +116 -0
- package/dist/lib/auto-session.js +41 -5
- package/dist/lib/cli.js +9 -0
- package/dist/lib/onboard.js +36 -0
- package/dist/lib/server.js +150 -169
- 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/__tests__/auto-session.test.ts +33 -33
- package/src/api-client.ts +205 -0
- package/src/auto-session.ts +54 -4
- package/src/cli.ts +9 -0
- package/src/onboard.ts +93 -0
- package/src/remote.ts +2 -1
- package/src/server.ts +178 -221
- package/src/skills.ts +1 -1
- package/src/tui/setup.ts +249 -67
package/dist/lib/server.js
CHANGED
|
@@ -4,14 +4,14 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { detectContradictions, extractLearnings, extractMidSessionLearnings, } from "./active-learning.js";
|
|
7
|
-
import { getClient,
|
|
7
|
+
import { getClient, resetClient, signupUser, } from "./api-client.js";
|
|
8
8
|
import { AUTO_START_TRIGGERS, destroyAutoSession, initAutoSession, markExplicit, shutdownAllSessions, trackActivity, untrack, } from "./auto-session.js";
|
|
9
9
|
import { getActiveProjectId, getActiveWorkspaceId, getApiUrl, getMemoryDir, getUserEmail, isConfigured, saveConfig, setActiveProject, setActiveWorkspace, } from "./config.js";
|
|
10
10
|
import { consolidateMemories } from "./consolidation.js";
|
|
11
11
|
import { assembleContext, cacheManifest, computeRelevanceScore, getCachedManifest, mapToContextEntity, recordContextFeedback, trackSessionAssembly, } from "./context-assembly.js";
|
|
12
12
|
import { autoExpandGraph } from "./graph-expansion.js";
|
|
13
13
|
import { runLifecycleMaintenance } from "./lifecycle-maintenance.js";
|
|
14
|
-
import {
|
|
14
|
+
import { onboardNewUser } from "./onboard.js";
|
|
15
15
|
const memorySessions = new Map();
|
|
16
16
|
function initMemorySession(cardId, agentIdentifier, agentName) {
|
|
17
17
|
memorySessions.set(cardId, {
|
|
@@ -169,18 +169,22 @@ const TOOLS = {
|
|
|
169
169
|
},
|
|
170
170
|
},
|
|
171
171
|
harmony_move_card: {
|
|
172
|
-
description: "Move a card to a different column or position",
|
|
172
|
+
description: "Move a card to a different column or position. Provide either columnId (UUID) or columnName (e.g. 'Review', 'Done').",
|
|
173
173
|
inputSchema: {
|
|
174
174
|
type: "object",
|
|
175
175
|
properties: {
|
|
176
176
|
cardId: { type: "string", description: "Card ID to move" },
|
|
177
|
-
columnId: { type: "string", description: "Target column ID" },
|
|
177
|
+
columnId: { type: "string", description: "Target column ID (UUID)" },
|
|
178
|
+
columnName: {
|
|
179
|
+
type: "string",
|
|
180
|
+
description: "Target column name (e.g. 'To Do', 'In Progress', 'Review', 'Done'). Used if columnId is not provided.",
|
|
181
|
+
},
|
|
178
182
|
position: {
|
|
179
183
|
type: "number",
|
|
180
184
|
description: "Position in column (0-indexed)",
|
|
181
185
|
},
|
|
182
186
|
},
|
|
183
|
-
required: ["cardId"
|
|
187
|
+
required: ["cardId"],
|
|
184
188
|
},
|
|
185
189
|
},
|
|
186
190
|
harmony_archive_card: {
|
|
@@ -313,14 +317,21 @@ const TOOLS = {
|
|
|
313
317
|
},
|
|
314
318
|
},
|
|
315
319
|
harmony_add_label_to_card: {
|
|
316
|
-
description: "Add a label to a card",
|
|
320
|
+
description: "Add a label to a card. Provide labelId directly, or labelName to look up (or auto-create) the label by name.",
|
|
317
321
|
inputSchema: {
|
|
318
322
|
type: "object",
|
|
319
323
|
properties: {
|
|
320
324
|
cardId: { type: "string" },
|
|
321
|
-
labelId: {
|
|
325
|
+
labelId: {
|
|
326
|
+
type: "string",
|
|
327
|
+
description: "Label ID (optional if labelName provided)",
|
|
328
|
+
},
|
|
329
|
+
labelName: {
|
|
330
|
+
type: "string",
|
|
331
|
+
description: "Label name — will look up or create if not found",
|
|
332
|
+
},
|
|
322
333
|
},
|
|
323
|
-
required: ["cardId"
|
|
334
|
+
required: ["cardId"],
|
|
324
335
|
},
|
|
325
336
|
},
|
|
326
337
|
harmony_remove_label_from_card: {
|
|
@@ -1704,6 +1715,19 @@ export function registerHandlers(server, deps) {
|
|
|
1704
1715
|
throw new Error(`Unknown resource: ${uri}`);
|
|
1705
1716
|
});
|
|
1706
1717
|
}
|
|
1718
|
+
/** Resolve a column name to its ID. Prefers exact match, falls back to substring. */
|
|
1719
|
+
async function resolveColumnByName(client, projectId, columnName) {
|
|
1720
|
+
const board = await client.getBoard(projectId, { summary: true });
|
|
1721
|
+
const columns = board.columns;
|
|
1722
|
+
const lower = columnName.toLowerCase();
|
|
1723
|
+
const col = columns.find((c) => c.name.toLowerCase() === lower) ||
|
|
1724
|
+
columns.find((c) => c.name.toLowerCase().includes(lower));
|
|
1725
|
+
if (!col) {
|
|
1726
|
+
const available = columns.map((c) => c.name).join(", ");
|
|
1727
|
+
throw new Error(`Column "${columnName}" not found. Available columns: ${available}`);
|
|
1728
|
+
}
|
|
1729
|
+
return col;
|
|
1730
|
+
}
|
|
1707
1731
|
async function handleToolCall(name, args, deps) {
|
|
1708
1732
|
// Unauthenticated tools that don't require an API key
|
|
1709
1733
|
const unauthenticatedTools = ["harmony_signup", "harmony_onboard"];
|
|
@@ -1758,19 +1782,36 @@ async function handleToolCall(name, args, deps) {
|
|
|
1758
1782
|
}
|
|
1759
1783
|
case "harmony_move_card": {
|
|
1760
1784
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
1761
|
-
const columnId = z.string().uuid().parse(args.columnId);
|
|
1762
1785
|
const position = args.position !== undefined
|
|
1763
1786
|
? z.number().int().min(0).parse(args.position)
|
|
1764
1787
|
: undefined;
|
|
1788
|
+
// Resolve columnId — accept UUID directly or resolve from columnName
|
|
1789
|
+
let columnId;
|
|
1790
|
+
let resolvedProjectId;
|
|
1791
|
+
if (args.columnId) {
|
|
1792
|
+
columnId = z.string().uuid().parse(args.columnId);
|
|
1793
|
+
}
|
|
1794
|
+
else if (args.columnName) {
|
|
1795
|
+
const columnName = z.string().parse(args.columnName);
|
|
1796
|
+
const { card: cardForProject } = await client.getCard(cardId);
|
|
1797
|
+
resolvedProjectId = cardForProject
|
|
1798
|
+
?.project_id;
|
|
1799
|
+
if (!resolvedProjectId)
|
|
1800
|
+
throw new Error("Card has no project");
|
|
1801
|
+
const col = await resolveColumnByName(client, resolvedProjectId, columnName);
|
|
1802
|
+
columnId = col.id;
|
|
1803
|
+
}
|
|
1804
|
+
else {
|
|
1805
|
+
throw new Error("Either columnId or columnName is required");
|
|
1806
|
+
}
|
|
1765
1807
|
const result = await client.moveCard(cardId, columnId, position);
|
|
1766
1808
|
// Auto-end active agent session when moving to Review or Done
|
|
1767
1809
|
let sessionEnded = false;
|
|
1768
1810
|
try {
|
|
1769
1811
|
const { card } = result;
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
});
|
|
1812
|
+
const projectId = card?.project_id || resolvedProjectId;
|
|
1813
|
+
if (projectId) {
|
|
1814
|
+
const board = await client.getBoard(projectId, { summary: true });
|
|
1774
1815
|
const columns = board.columns;
|
|
1775
1816
|
const destCol = columns.find((c) => c.id === columnId);
|
|
1776
1817
|
const colName = destCol?.name?.toLowerCase() || "";
|
|
@@ -1871,7 +1912,38 @@ async function handleToolCall(name, args, deps) {
|
|
|
1871
1912
|
}
|
|
1872
1913
|
case "harmony_add_label_to_card": {
|
|
1873
1914
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
1874
|
-
|
|
1915
|
+
let labelId = args.labelId
|
|
1916
|
+
? z.string().uuid().parse(args.labelId)
|
|
1917
|
+
: undefined;
|
|
1918
|
+
const labelName = args.labelName
|
|
1919
|
+
? z.string().min(1).max(100).parse(args.labelName)
|
|
1920
|
+
: undefined;
|
|
1921
|
+
// If labelName provided without labelId, look up or create the label
|
|
1922
|
+
if (!labelId && labelName) {
|
|
1923
|
+
const { card } = await client.getCard(cardId);
|
|
1924
|
+
const projectId = card.project_id;
|
|
1925
|
+
if (!projectId) {
|
|
1926
|
+
throw new Error("Cannot resolve label by name: card has no project_id");
|
|
1927
|
+
}
|
|
1928
|
+
if (projectId) {
|
|
1929
|
+
const board = await client.getBoard(projectId, { summary: true });
|
|
1930
|
+
const labels = board.labels;
|
|
1931
|
+
const existing = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
1932
|
+
if (existing) {
|
|
1933
|
+
labelId = existing.id;
|
|
1934
|
+
}
|
|
1935
|
+
else {
|
|
1936
|
+
const created = await client.createLabel(projectId, {
|
|
1937
|
+
name: labelName,
|
|
1938
|
+
color: "#57b8a5",
|
|
1939
|
+
});
|
|
1940
|
+
labelId = created.label.id;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
if (!labelId) {
|
|
1945
|
+
throw new Error("Either labelId or labelName must be provided");
|
|
1946
|
+
}
|
|
1875
1947
|
await client.addLabelToCard(cardId, labelId);
|
|
1876
1948
|
return { success: true };
|
|
1877
1949
|
}
|
|
@@ -2016,10 +2088,18 @@ async function handleToolCall(name, args, deps) {
|
|
|
2016
2088
|
}
|
|
2017
2089
|
if (addLabels?.length) {
|
|
2018
2090
|
for (const labelName of addLabels) {
|
|
2019
|
-
|
|
2091
|
+
let label = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
|
|
2092
|
+
if (!label && projectId) {
|
|
2093
|
+
const created = await client.createLabel(projectId, {
|
|
2094
|
+
name: labelName,
|
|
2095
|
+
color: "#57b8a5",
|
|
2096
|
+
});
|
|
2097
|
+
label = created
|
|
2098
|
+
.label;
|
|
2099
|
+
}
|
|
2020
2100
|
if (label) {
|
|
2021
2101
|
await client.addLabelToCard(cardId, label.id);
|
|
2022
|
-
labelsAdded.push(label.name);
|
|
2102
|
+
labelsAdded.push(label.name ?? labelName);
|
|
2023
2103
|
}
|
|
2024
2104
|
}
|
|
2025
2105
|
}
|
|
@@ -2177,29 +2257,25 @@ async function handleToolCall(name, args, deps) {
|
|
|
2177
2257
|
// Final flush of any pending memory actions before ending the session
|
|
2178
2258
|
await flushMemoryActions(client, cardId);
|
|
2179
2259
|
cleanupMemorySession(cardId);
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2260
|
+
// End the session — tolerate failure (e.g., session already ended or not found)
|
|
2261
|
+
let result = { session: null };
|
|
2262
|
+
let sessionEndError = null;
|
|
2263
|
+
try {
|
|
2264
|
+
result = await client.endAgentSession(cardId, {
|
|
2265
|
+
status: sessionStatus,
|
|
2266
|
+
progressPercent: endProgressPercent,
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
catch (err) {
|
|
2270
|
+
sessionEndError =
|
|
2271
|
+
err instanceof Error ? err.message : "Failed to end session";
|
|
2272
|
+
}
|
|
2273
|
+
// Remove from auto-session tracking regardless
|
|
2185
2274
|
untrack(cardId);
|
|
2186
2275
|
let movedTo = null;
|
|
2187
|
-
const _learningsExtracted = 0;
|
|
2188
|
-
// Get card info for move and learning extraction
|
|
2189
|
-
let _cardTitle = "";
|
|
2190
|
-
let _cardLabels = [];
|
|
2191
|
-
let _cardDescription = "";
|
|
2192
|
-
let _cardSubtasks = [];
|
|
2193
2276
|
try {
|
|
2194
2277
|
const { card } = await client.getCard(cardId);
|
|
2195
2278
|
const typedCard = card;
|
|
2196
|
-
_cardTitle = typedCard.title || "";
|
|
2197
|
-
_cardLabels = (typedCard.labels || []).map((l) => l.name);
|
|
2198
|
-
_cardDescription = typedCard.description || "";
|
|
2199
|
-
_cardSubtasks = (typedCard.subtasks || []).map((s) => ({
|
|
2200
|
-
title: s.title,
|
|
2201
|
-
done: s.done,
|
|
2202
|
-
}));
|
|
2203
2279
|
const projectId = typedCard.project_id;
|
|
2204
2280
|
// Remove "agent" label when session is completed (not paused)
|
|
2205
2281
|
if (sessionStatus === "completed" && typedCard.labels?.length) {
|
|
@@ -2209,15 +2285,9 @@ async function handleToolCall(name, args, deps) {
|
|
|
2209
2285
|
}
|
|
2210
2286
|
}
|
|
2211
2287
|
if (moveToColumn && projectId) {
|
|
2212
|
-
const
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
const columns = board.columns;
|
|
2216
|
-
const col = columns.find((c) => c.name.toLowerCase().includes(moveToColumn.toLowerCase()));
|
|
2217
|
-
if (col) {
|
|
2218
|
-
await client.moveCard(cardId, col.id);
|
|
2219
|
-
movedTo = col.name;
|
|
2220
|
-
}
|
|
2288
|
+
const col = await resolveColumnByName(client, projectId, moveToColumn);
|
|
2289
|
+
await client.moveCard(cardId, col.id);
|
|
2290
|
+
movedTo = col.name;
|
|
2221
2291
|
}
|
|
2222
2292
|
}
|
|
2223
2293
|
catch {
|
|
@@ -2228,6 +2298,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
2228
2298
|
const pipelineResult = await runEndSessionPipeline(client, deps, cardId, sessionStatus, endProgressPercent, sessionObj);
|
|
2229
2299
|
return {
|
|
2230
2300
|
success: true,
|
|
2301
|
+
...(sessionEndError && { sessionEndError }),
|
|
2231
2302
|
movedTo,
|
|
2232
2303
|
learningsExtracted: pipelineResult.learningsExtracted,
|
|
2233
2304
|
feedbackAdjusted: pipelineResult.feedbackAdjusted,
|
|
@@ -2261,13 +2332,10 @@ async function handleToolCall(name, args, deps) {
|
|
|
2261
2332
|
}
|
|
2262
2333
|
// Prompt generation
|
|
2263
2334
|
case "harmony_generate_prompt": {
|
|
2264
|
-
//
|
|
2265
|
-
let
|
|
2266
|
-
let columnData = null;
|
|
2335
|
+
// Resolve card ID — either directly or via short ID
|
|
2336
|
+
let cardId;
|
|
2267
2337
|
if (args.cardId) {
|
|
2268
|
-
|
|
2269
|
-
const cardResult = await client.getCard(cardId);
|
|
2270
|
-
cardData = cardResult.card;
|
|
2338
|
+
cardId = z.string().uuid().parse(args.cardId);
|
|
2271
2339
|
}
|
|
2272
2340
|
else if (args.shortId !== undefined) {
|
|
2273
2341
|
const shortId = z.number().int().positive().parse(args.shortId);
|
|
@@ -2276,32 +2344,12 @@ async function handleToolCall(name, args, deps) {
|
|
|
2276
2344
|
throw new Error("Project ID required when using shortId. Use harmony_set_project_context or provide projectId.");
|
|
2277
2345
|
}
|
|
2278
2346
|
const cardResult = await client.getCardByShortId(projectId, shortId);
|
|
2279
|
-
|
|
2347
|
+
cardId = cardResult.card.id;
|
|
2280
2348
|
}
|
|
2281
2349
|
else {
|
|
2282
2350
|
throw new Error("Either cardId or shortId must be provided");
|
|
2283
2351
|
}
|
|
2284
|
-
//
|
|
2285
|
-
const projectIdForBoard = args.projectId ||
|
|
2286
|
-
getActiveProjectId() ||
|
|
2287
|
-
cardData.project_id;
|
|
2288
|
-
if (projectIdForBoard) {
|
|
2289
|
-
try {
|
|
2290
|
-
const board = await client.getBoard(projectIdForBoard, {
|
|
2291
|
-
summary: true,
|
|
2292
|
-
});
|
|
2293
|
-
const columnId = cardData
|
|
2294
|
-
.column_id;
|
|
2295
|
-
const column = board.columns.find((col) => col.id === columnId);
|
|
2296
|
-
if (column) {
|
|
2297
|
-
columnData = { name: column.name };
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
catch {
|
|
2301
|
-
// Column info not available, continue without it
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
const variant = args.variant || "execute";
|
|
2352
|
+
// Parse MCP-specific context options
|
|
2305
2353
|
const contextOptions = {};
|
|
2306
2354
|
if (args.includeSubtasks !== undefined) {
|
|
2307
2355
|
contextOptions.includeSubtasks =
|
|
@@ -2316,75 +2364,21 @@ async function handleToolCall(name, args, deps) {
|
|
|
2316
2364
|
args.includeDescription === true ||
|
|
2317
2365
|
args.includeDescription === "true";
|
|
2318
2366
|
}
|
|
2319
|
-
//
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
if (workspaceId && cardData.title) {
|
|
2326
|
-
const cardLabels = (cardData.labels || []).map((l) => l.name);
|
|
2327
|
-
const taskContext = [cardData.title, cardData.description || ""]
|
|
2328
|
-
.filter(Boolean)
|
|
2329
|
-
.join(" ");
|
|
2330
|
-
const assembled = await assembleContext({
|
|
2331
|
-
workspaceId,
|
|
2332
|
-
projectId: getActiveProjectId() || undefined,
|
|
2333
|
-
taskContext,
|
|
2334
|
-
cardLabels,
|
|
2335
|
-
cardId: cardData.id,
|
|
2336
|
-
client,
|
|
2337
|
-
});
|
|
2338
|
-
if (assembled.context) {
|
|
2339
|
-
assembledContextStr = assembled.context;
|
|
2340
|
-
assemblyId = assembled.manifest.assemblyId;
|
|
2341
|
-
cacheManifest(assembled.manifest);
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
catch {
|
|
2346
|
-
// Context assembly failed, try legacy fallback
|
|
2347
|
-
try {
|
|
2348
|
-
const workspaceId = deps.getActiveWorkspaceId();
|
|
2349
|
-
if (workspaceId && cardData.title) {
|
|
2350
|
-
const memoryResult = await client.searchMemoryEntities(workspaceId, cardData.title, {
|
|
2351
|
-
project_id: getActiveProjectId() || undefined,
|
|
2352
|
-
limit: 5,
|
|
2353
|
-
});
|
|
2354
|
-
if (memoryResult.entities?.length > 0) {
|
|
2355
|
-
memories = memoryResult.entities.map((e) => {
|
|
2356
|
-
const entity = e;
|
|
2357
|
-
return {
|
|
2358
|
-
id: entity.id,
|
|
2359
|
-
type: entity.type,
|
|
2360
|
-
title: entity.title,
|
|
2361
|
-
content: entity.content,
|
|
2362
|
-
confidence: entity.confidence,
|
|
2363
|
-
tags: entity.tags || [],
|
|
2364
|
-
};
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
catch {
|
|
2370
|
-
// Memory fetch also failed, continue without memories
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
const result = generatePrompt({
|
|
2374
|
-
card: cardData,
|
|
2375
|
-
column: columnData,
|
|
2376
|
-
variant,
|
|
2377
|
-
contextOptions,
|
|
2367
|
+
// Delegate to the shared prompt generation pipeline
|
|
2368
|
+
const result = await client.generateCardPrompt({
|
|
2369
|
+
cardId,
|
|
2370
|
+
workspaceId: deps.getActiveWorkspaceId() || "",
|
|
2371
|
+
projectId: args.projectId || getActiveProjectId() || undefined,
|
|
2372
|
+
variant: args.variant || "execute",
|
|
2378
2373
|
customConstraints: args.customConstraints,
|
|
2379
|
-
|
|
2380
|
-
assembledContext: assembledContextStr,
|
|
2381
|
-
assemblyId,
|
|
2374
|
+
contextOptions,
|
|
2382
2375
|
});
|
|
2376
|
+
// MCP-specific: cache the assembly manifest for the feedback loop
|
|
2377
|
+
if (result.assemblyId) {
|
|
2378
|
+
trackSessionAssembly(cardId, result.assemblyId);
|
|
2379
|
+
}
|
|
2383
2380
|
return {
|
|
2384
2381
|
success: true,
|
|
2385
|
-
cardId: cardData.id,
|
|
2386
|
-
shortId: cardData.short_id,
|
|
2387
|
-
title: cardData.title,
|
|
2388
2382
|
...result,
|
|
2389
2383
|
};
|
|
2390
2384
|
}
|
|
@@ -3150,44 +3144,28 @@ async function handleToolCall(name, args, deps) {
|
|
|
3150
3144
|
const projectName = args.projectName || "My First Project";
|
|
3151
3145
|
const template = args.template || "kanban";
|
|
3152
3146
|
const keyName = args.keyName || "mcp-agent";
|
|
3153
|
-
const
|
|
3154
|
-
// 1. Signup
|
|
3155
|
-
const signupResult = await signupUser(apiUrl, {
|
|
3147
|
+
const result = await onboardNewUser({
|
|
3156
3148
|
email,
|
|
3157
3149
|
password,
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
// 2. Create workspace
|
|
3162
|
-
const workspaceResult = await requestWithBearer(apiUrl, token, "POST", "/workspaces", {
|
|
3163
|
-
name: workspaceName,
|
|
3164
|
-
});
|
|
3165
|
-
// 3. Create project
|
|
3166
|
-
const projectResult = await requestWithBearer(apiUrl, token, "POST", "/projects", {
|
|
3167
|
-
workspaceId: workspaceResult.workspace.id,
|
|
3168
|
-
name: projectName,
|
|
3150
|
+
fullName,
|
|
3151
|
+
workspaceName,
|
|
3152
|
+
projectName,
|
|
3169
3153
|
template,
|
|
3154
|
+
keyName,
|
|
3155
|
+
apiUrl: deps.getApiUrl(),
|
|
3170
3156
|
});
|
|
3171
|
-
//
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
// 5. Save config
|
|
3176
|
-
deps.saveConfig({ apiKey: keyResult.rawKey });
|
|
3177
|
-
deps.setActiveWorkspace(workspaceResult.workspace.id);
|
|
3178
|
-
deps.setActiveProject(projectResult.project.id);
|
|
3179
|
-
// 6. Reset client so singleton picks up new key
|
|
3157
|
+
// Save config and reset client
|
|
3158
|
+
deps.saveConfig({ apiKey: result.apiKey.rawKey });
|
|
3159
|
+
deps.setActiveWorkspace(result.workspace.id);
|
|
3160
|
+
deps.setActiveProject(result.project.id);
|
|
3180
3161
|
deps.resetClient();
|
|
3181
3162
|
return {
|
|
3182
3163
|
success: true,
|
|
3183
|
-
user:
|
|
3184
|
-
workspace:
|
|
3185
|
-
project:
|
|
3186
|
-
columns:
|
|
3187
|
-
apiKey:
|
|
3188
|
-
rawKey: keyResult.rawKey,
|
|
3189
|
-
prefix: keyResult.apiKey.prefix,
|
|
3190
|
-
},
|
|
3164
|
+
user: result.user,
|
|
3165
|
+
workspace: result.workspace,
|
|
3166
|
+
project: result.project,
|
|
3167
|
+
columns: result.columns,
|
|
3168
|
+
apiKey: result.apiKey,
|
|
3191
3169
|
message: `Onboarding complete! Account created for ${email}. Workspace "${workspaceName}" and project "${projectName}" are ready. API key saved to config.`,
|
|
3192
3170
|
};
|
|
3193
3171
|
}
|
|
@@ -3267,11 +3245,14 @@ export class HarmonyMCPServer {
|
|
|
3267
3245
|
const transport = new StdioServerTransport();
|
|
3268
3246
|
await this.server.connect(transport);
|
|
3269
3247
|
console.error("Harmony MCP server running on stdio");
|
|
3270
|
-
// Initialize auto-session tracking
|
|
3248
|
+
// Initialize auto-session tracking with MCP client identity detection
|
|
3271
3249
|
const configDeps = createConfigDeps();
|
|
3272
3250
|
initAutoSession(async (client, cardId, status) => {
|
|
3273
3251
|
await runEndSessionPipeline(client, configDeps, cardId, status);
|
|
3274
|
-
}, () => getClient())
|
|
3252
|
+
}, () => getClient(), () => {
|
|
3253
|
+
const cv = this.server.getClientVersion();
|
|
3254
|
+
return cv ? { name: cv.name, version: cv.version } : null;
|
|
3255
|
+
});
|
|
3275
3256
|
// Graceful shutdown: end all auto-sessions
|
|
3276
3257
|
const handleShutdown = async () => {
|
|
3277
3258
|
try {
|
package/dist/lib/skills.js
CHANGED
|
@@ -4,7 +4,7 @@ import { areSkillsInstalled } from "./config.js";
|
|
|
4
4
|
export const SKILLS_VERSION = "3";
|
|
5
5
|
const VERSION_MARKER_PREFIX = "<!-- skills-version:";
|
|
6
6
|
/**
|
|
7
|
-
* Legacy workflow prompt used by Codex, Cursor
|
|
7
|
+
* Legacy workflow prompt used by Codex, Cursor agents.
|
|
8
8
|
* Claude Code skills use the newer SKILL_DEFINITIONS content instead.
|
|
9
9
|
*/
|
|
10
10
|
export const HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
|