@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/dist/cli.js CHANGED
@@ -2122,19 +2122,19 @@ var require_commander = __commonJS((exports) => {
2122
2122
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2123
2123
  });
2124
2124
 
2125
- // ../memory/src/schema.ts
2125
+ // ../memory/dist/schema.js
2126
2126
  var init_schema = () => {};
2127
2127
 
2128
- // ../memory/src/constraints.ts
2128
+ // ../memory/dist/constraints.js
2129
2129
  var init_constraints = __esm(() => {
2130
2130
  init_schema();
2131
2131
  });
2132
- // ../memory/src/client.ts
2132
+ // ../memory/dist/client.js
2133
2133
  var init_client = __esm(() => {
2134
2134
  init_constraints();
2135
2135
  });
2136
2136
 
2137
- // ../memory/src/graph-walk.ts
2137
+ // ../memory/dist/graph-walk.js
2138
2138
  async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
2139
2139
  const visited = new Set;
2140
2140
  const collectedEntities = [];
@@ -2215,7 +2215,7 @@ async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntitie
2215
2215
  };
2216
2216
  }
2217
2217
 
2218
- // ../memory/src/lifecycle.ts
2218
+ // ../memory/dist/lifecycle.js
2219
2219
  function computeDecayScore(tier, lastAccessedAt, accessCount) {
2220
2220
  const halfLife = DECAY_HALF_LIVES[tier];
2221
2221
  const now = Date.now();
@@ -2300,7 +2300,7 @@ var init_lifecycle = __esm(() => {
2300
2300
  };
2301
2301
  });
2302
2302
 
2303
- // ../memory/src/sync-storage.ts
2303
+ // ../memory/dist/sync-storage.js
2304
2304
  function parseSyncMarkdown(markdown) {
2305
2305
  const trimmed = markdown.trim();
2306
2306
  let frontmatter = {
@@ -2416,16 +2416,9 @@ function parseYamlArray(value) {
2416
2416
  return match[1].split(",").map((s) => s.trim()).filter(Boolean);
2417
2417
  }
2418
2418
 
2419
- // ../memory/src/sync.ts
2419
+ // ../memory/dist/sync.js
2420
2420
  import { createHash } from "node:crypto";
2421
- import {
2422
- existsSync as existsSync2,
2423
- mkdirSync as mkdirSync2,
2424
- readdirSync,
2425
- readFileSync as readFileSync2,
2426
- rmSync,
2427
- writeFileSync as writeFileSync2
2428
- } from "node:fs";
2421
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
2429
2422
  import { join as join2, relative, sep } from "node:path";
2430
2423
  function computeFileHash(content) {
2431
2424
  return `sha256:${createHash("sha256").update(content).digest("hex")}`;
@@ -2690,8 +2683,8 @@ async function syncFull(client, config, workspaceId, projectId) {
2690
2683
  }
2691
2684
  var init_sync = () => {};
2692
2685
 
2693
- // ../memory/src/index.ts
2694
- var init_src = __esm(() => {
2686
+ // ../memory/dist/index.js
2687
+ var init_dist = __esm(() => {
2695
2688
  init_client();
2696
2689
  init_constraints();
2697
2690
  init_lifecycle();
@@ -9655,7 +9648,7 @@ async function recordContextFeedback(client2, cardId, sessionStatus, progressPer
9655
9648
  }
9656
9649
  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;
9657
9650
  var init_context_assembly = __esm(() => {
9658
- init_src();
9651
+ init_dist();
9659
9652
  TIER_WEIGHTS = {
9660
9653
  reference: 1,
9661
9654
  episode: 0.7,
@@ -10442,7 +10435,7 @@ function getMemoryDir() {
10442
10435
  }
10443
10436
 
10444
10437
  // src/server.ts
10445
- init_src();
10438
+ init_dist();
10446
10439
 
10447
10440
  // ../../node_modules/zod/v4/core/index.js
10448
10441
  var exports_core2 = {};
@@ -28029,7 +28022,7 @@ function deriveClusterTitle(cluster, type) {
28029
28022
  init_context_assembly();
28030
28023
 
28031
28024
  // src/lifecycle-maintenance.ts
28032
- init_src();
28025
+ init_dist();
28033
28026
  async function runLifecycleMaintenance(client3, workspaceId, projectId) {
28034
28027
  const result = {
28035
28028
  archived: 0,
@@ -28098,6 +28091,47 @@ async function runLifecycleMaintenance(client3, workspaceId, projectId) {
28098
28091
  return result;
28099
28092
  }
28100
28093
 
28094
+ // src/onboard.ts
28095
+ async function onboardNewUser(params) {
28096
+ const {
28097
+ email: email3,
28098
+ password,
28099
+ fullName,
28100
+ workspaceName = `${fullName}'s Workspace`,
28101
+ projectName = "My First Board",
28102
+ template = "kanban",
28103
+ keyName = "mcp-agent",
28104
+ apiUrl = getApiUrl()
28105
+ } = params;
28106
+ const signupResult = await signupUser(apiUrl, {
28107
+ email: email3,
28108
+ password,
28109
+ full_name: fullName
28110
+ });
28111
+ const token = signupResult.session.access_token;
28112
+ const workspaceResult = await requestWithBearer(apiUrl, token, "POST", "/workspaces", {
28113
+ name: workspaceName
28114
+ });
28115
+ const projectResult = await requestWithBearer(apiUrl, token, "POST", "/projects", {
28116
+ workspaceId: workspaceResult.workspace.id,
28117
+ name: projectName,
28118
+ template
28119
+ });
28120
+ const keyResult = await requestWithBearer(apiUrl, token, "POST", "/api-keys", {
28121
+ name: keyName
28122
+ });
28123
+ return {
28124
+ user: signupResult.user,
28125
+ workspace: workspaceResult.workspace,
28126
+ project: projectResult.project,
28127
+ columns: projectResult.columns,
28128
+ apiKey: {
28129
+ rawKey: keyResult.rawKey,
28130
+ prefix: keyResult.apiKey.prefix
28131
+ }
28132
+ };
28133
+ }
28134
+
28101
28135
  // src/server.ts
28102
28136
  var memorySessions = new Map;
28103
28137
  function initMemorySession(cardId, agentIdentifier, agentName) {
@@ -28232,18 +28266,22 @@ var TOOLS = {
28232
28266
  }
28233
28267
  },
28234
28268
  harmony_move_card: {
28235
- description: "Move a card to a different column or position",
28269
+ description: "Move a card to a different column or position. Provide either columnId (UUID) or columnName (e.g. 'Review', 'Done').",
28236
28270
  inputSchema: {
28237
28271
  type: "object",
28238
28272
  properties: {
28239
28273
  cardId: { type: "string", description: "Card ID to move" },
28240
- columnId: { type: "string", description: "Target column ID" },
28274
+ columnId: { type: "string", description: "Target column ID (UUID)" },
28275
+ columnName: {
28276
+ type: "string",
28277
+ description: "Target column name (e.g. 'To Do', 'In Progress', 'Review', 'Done'). Used if columnId is not provided."
28278
+ },
28241
28279
  position: {
28242
28280
  type: "number",
28243
28281
  description: "Position in column (0-indexed)"
28244
28282
  }
28245
28283
  },
28246
- required: ["cardId", "columnId"]
28284
+ required: ["cardId"]
28247
28285
  }
28248
28286
  },
28249
28287
  harmony_archive_card: {
@@ -28374,14 +28412,21 @@ var TOOLS = {
28374
28412
  }
28375
28413
  },
28376
28414
  harmony_add_label_to_card: {
28377
- description: "Add a label to a card",
28415
+ description: "Add a label to a card. Provide labelId directly, or labelName to look up (or auto-create) the label by name.",
28378
28416
  inputSchema: {
28379
28417
  type: "object",
28380
28418
  properties: {
28381
28419
  cardId: { type: "string" },
28382
- labelId: { type: "string" }
28420
+ labelId: {
28421
+ type: "string",
28422
+ description: "Label ID (optional if labelName provided)"
28423
+ },
28424
+ labelName: {
28425
+ type: "string",
28426
+ description: "Label name — will look up or create if not found"
28427
+ }
28383
28428
  },
28384
- required: ["cardId", "labelId"]
28429
+ required: ["cardId"]
28385
28430
  }
28386
28431
  },
28387
28432
  harmony_remove_label_from_card: {
@@ -29698,6 +29743,17 @@ function registerHandlers(server, deps) {
29698
29743
  throw new Error(`Unknown resource: ${uri}`);
29699
29744
  });
29700
29745
  }
29746
+ async function resolveColumnByName(client3, projectId, columnName) {
29747
+ const board = await client3.getBoard(projectId, { summary: true });
29748
+ const columns = board.columns;
29749
+ const lower = columnName.toLowerCase();
29750
+ const col = columns.find((c) => c.name.toLowerCase() === lower) || columns.find((c) => c.name.toLowerCase().includes(lower));
29751
+ if (!col) {
29752
+ const available = columns.map((c) => c.name).join(", ");
29753
+ throw new Error(`Column "${columnName}" not found. Available columns: ${available}`);
29754
+ }
29755
+ return col;
29756
+ }
29701
29757
  async function handleToolCall(name, args, deps) {
29702
29758
  const unauthenticatedTools = ["harmony_signup", "harmony_onboard"];
29703
29759
  if (!unauthenticatedTools.includes(name) && !deps.isConfigured()) {
@@ -29747,16 +29803,29 @@ async function handleToolCall(name, args, deps) {
29747
29803
  }
29748
29804
  case "harmony_move_card": {
29749
29805
  const cardId = exports_external.string().uuid().parse(args.cardId);
29750
- const columnId = exports_external.string().uuid().parse(args.columnId);
29751
29806
  const position = args.position !== undefined ? exports_external.number().int().min(0).parse(args.position) : undefined;
29807
+ let columnId;
29808
+ let resolvedProjectId;
29809
+ if (args.columnId) {
29810
+ columnId = exports_external.string().uuid().parse(args.columnId);
29811
+ } else if (args.columnName) {
29812
+ const columnName = exports_external.string().parse(args.columnName);
29813
+ const { card: cardForProject } = await client3.getCard(cardId);
29814
+ resolvedProjectId = cardForProject?.project_id;
29815
+ if (!resolvedProjectId)
29816
+ throw new Error("Card has no project");
29817
+ const col = await resolveColumnByName(client3, resolvedProjectId, columnName);
29818
+ columnId = col.id;
29819
+ } else {
29820
+ throw new Error("Either columnId or columnName is required");
29821
+ }
29752
29822
  const result = await client3.moveCard(cardId, columnId, position);
29753
29823
  let sessionEnded = false;
29754
29824
  try {
29755
29825
  const { card } = result;
29756
- if (card?.project_id) {
29757
- const board = await client3.getBoard(card.project_id, {
29758
- summary: true
29759
- });
29826
+ const projectId = card?.project_id || resolvedProjectId;
29827
+ if (projectId) {
29828
+ const board = await client3.getBoard(projectId, { summary: true });
29760
29829
  const columns = board.columns;
29761
29830
  const destCol = columns.find((c) => c.id === columnId);
29762
29831
  const colName = destCol?.name?.toLowerCase() || "";
@@ -29843,7 +29912,32 @@ async function handleToolCall(name, args, deps) {
29843
29912
  }
29844
29913
  case "harmony_add_label_to_card": {
29845
29914
  const cardId = exports_external.string().uuid().parse(args.cardId);
29846
- const labelId = exports_external.string().uuid().parse(args.labelId);
29915
+ let labelId = args.labelId ? exports_external.string().uuid().parse(args.labelId) : undefined;
29916
+ const labelName = args.labelName ? exports_external.string().min(1).max(100).parse(args.labelName) : undefined;
29917
+ if (!labelId && labelName) {
29918
+ const { card } = await client3.getCard(cardId);
29919
+ const projectId = card.project_id;
29920
+ if (!projectId) {
29921
+ throw new Error("Cannot resolve label by name: card has no project_id");
29922
+ }
29923
+ if (projectId) {
29924
+ const board = await client3.getBoard(projectId, { summary: true });
29925
+ const labels = board.labels;
29926
+ const existing = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
29927
+ if (existing) {
29928
+ labelId = existing.id;
29929
+ } else {
29930
+ const created = await client3.createLabel(projectId, {
29931
+ name: labelName,
29932
+ color: "#57b8a5"
29933
+ });
29934
+ labelId = created.label.id;
29935
+ }
29936
+ }
29937
+ }
29938
+ if (!labelId) {
29939
+ throw new Error("Either labelId or labelName must be provided");
29940
+ }
29847
29941
  await client3.addLabelToCard(cardId, labelId);
29848
29942
  return { success: true };
29849
29943
  }
@@ -29973,10 +30067,17 @@ async function handleToolCall(name, args, deps) {
29973
30067
  }
29974
30068
  if (addLabels?.length) {
29975
30069
  for (const labelName of addLabels) {
29976
- const label = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
30070
+ let label = labels.find((l) => l.name.toLowerCase() === labelName.toLowerCase());
30071
+ if (!label && projectId) {
30072
+ const created = await client3.createLabel(projectId, {
30073
+ name: labelName,
30074
+ color: "#57b8a5"
30075
+ });
30076
+ label = created.label;
30077
+ }
29977
30078
  if (label) {
29978
30079
  await client3.addLabelToCard(cardId, label.id);
29979
- labelsAdded.push(label.name);
30080
+ labelsAdded.push(label.name ?? labelName);
29980
30081
  }
29981
30082
  }
29982
30083
  }
@@ -30096,27 +30197,21 @@ async function handleToolCall(name, args, deps) {
30096
30197
  const endProgressPercent = args.progressPercent !== undefined ? exports_external.number().min(0).max(100).parse(args.progressPercent) : undefined;
30097
30198
  await flushMemoryActions(client3, cardId);
30098
30199
  cleanupMemorySession(cardId);
30099
- const result = await client3.endAgentSession(cardId, {
30100
- status: sessionStatus,
30101
- progressPercent: endProgressPercent
30102
- });
30200
+ let result = { session: null };
30201
+ let sessionEndError = null;
30202
+ try {
30203
+ result = await client3.endAgentSession(cardId, {
30204
+ status: sessionStatus,
30205
+ progressPercent: endProgressPercent
30206
+ });
30207
+ } catch (err) {
30208
+ sessionEndError = err instanceof Error ? err.message : "Failed to end session";
30209
+ }
30103
30210
  untrack(cardId);
30104
30211
  let movedTo = null;
30105
- const _learningsExtracted = 0;
30106
- let _cardTitle = "";
30107
- let _cardLabels = [];
30108
- let _cardDescription = "";
30109
- let _cardSubtasks = [];
30110
30212
  try {
30111
30213
  const { card } = await client3.getCard(cardId);
30112
30214
  const typedCard = card;
30113
- _cardTitle = typedCard.title || "";
30114
- _cardLabels = (typedCard.labels || []).map((l) => l.name);
30115
- _cardDescription = typedCard.description || "";
30116
- _cardSubtasks = (typedCard.subtasks || []).map((s) => ({
30117
- title: s.title,
30118
- done: s.done
30119
- }));
30120
30215
  const projectId = typedCard.project_id;
30121
30216
  if (sessionStatus === "completed" && typedCard.labels?.length) {
30122
30217
  const agentLabel = typedCard.labels.find((l) => l.name.toLowerCase() === "agent");
@@ -30125,21 +30220,16 @@ async function handleToolCall(name, args, deps) {
30125
30220
  }
30126
30221
  }
30127
30222
  if (moveToColumn && projectId) {
30128
- const board = await client3.getBoard(projectId, {
30129
- summary: true
30130
- });
30131
- const columns = board.columns;
30132
- const col = columns.find((c) => c.name.toLowerCase().includes(moveToColumn.toLowerCase()));
30133
- if (col) {
30134
- await client3.moveCard(cardId, col.id);
30135
- movedTo = col.name;
30136
- }
30223
+ const col = await resolveColumnByName(client3, projectId, moveToColumn);
30224
+ await client3.moveCard(cardId, col.id);
30225
+ movedTo = col.name;
30137
30226
  }
30138
30227
  } catch {}
30139
30228
  const sessionObj = result.session;
30140
30229
  const pipelineResult = await runEndSessionPipeline(client3, deps, cardId, sessionStatus, endProgressPercent, sessionObj);
30141
30230
  return {
30142
30231
  success: true,
30232
+ ...sessionEndError && { sessionEndError },
30143
30233
  movedTo,
30144
30234
  learningsExtracted: pipelineResult.learningsExtracted,
30145
30235
  feedbackAdjusted: pipelineResult.feedbackAdjusted,
@@ -30881,38 +30971,27 @@ async function handleToolCall(name, args, deps) {
30881
30971
  const projectName = args.projectName || "My First Project";
30882
30972
  const template = args.template || "kanban";
30883
30973
  const keyName = args.keyName || "mcp-agent";
30884
- const apiUrl = deps.getApiUrl();
30885
- const signupResult = await signupUser(apiUrl, {
30974
+ const result = await onboardNewUser({
30886
30975
  email: email3,
30887
30976
  password,
30888
- full_name: fullName
30889
- });
30890
- const token = signupResult.session.access_token;
30891
- const workspaceResult = await requestWithBearer(apiUrl, token, "POST", "/workspaces", {
30892
- name: workspaceName
30977
+ fullName,
30978
+ workspaceName,
30979
+ projectName,
30980
+ template,
30981
+ keyName,
30982
+ apiUrl: deps.getApiUrl()
30893
30983
  });
30894
- const projectResult = await requestWithBearer(apiUrl, token, "POST", "/projects", {
30895
- workspaceId: workspaceResult.workspace.id,
30896
- name: projectName,
30897
- template
30898
- });
30899
- const keyResult = await requestWithBearer(apiUrl, token, "POST", "/api-keys", {
30900
- name: keyName
30901
- });
30902
- deps.saveConfig({ apiKey: keyResult.rawKey });
30903
- deps.setActiveWorkspace(workspaceResult.workspace.id);
30904
- deps.setActiveProject(projectResult.project.id);
30984
+ deps.saveConfig({ apiKey: result.apiKey.rawKey });
30985
+ deps.setActiveWorkspace(result.workspace.id);
30986
+ deps.setActiveProject(result.project.id);
30905
30987
  deps.resetClient();
30906
30988
  return {
30907
30989
  success: true,
30908
- user: signupResult.user,
30909
- workspace: workspaceResult.workspace,
30910
- project: projectResult.project,
30911
- columns: projectResult.columns,
30912
- apiKey: {
30913
- rawKey: keyResult.rawKey,
30914
- prefix: keyResult.apiKey.prefix
30915
- },
30990
+ user: result.user,
30991
+ workspace: result.workspace,
30992
+ project: result.project,
30993
+ columns: result.columns,
30994
+ apiKey: result.apiKey,
30916
30995
  message: `Onboarding complete! Account created for ${email3}. Workspace "${workspaceName}" and project "${projectName}" are ready. API key saved to config.`
30917
30996
  };
30918
30997
  }
@@ -31972,6 +32051,30 @@ var SD = class extends x {
31972
32051
  this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
31973
32052
  }
31974
32053
  };
32054
+ var TD = Object.defineProperty;
32055
+ var jD = (e, u, t) => (u in e) ? TD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
32056
+ var U = (e, u, t) => (jD(e, typeof u != "symbol" ? u + "" : u, t), t);
32057
+
32058
+ class MD extends x {
32059
+ constructor({ mask: u, ...t }) {
32060
+ super(t), U(this, "valueWithCursor", ""), U(this, "_mask", "•"), this._mask = u ?? "•", this.on("finalize", () => {
32061
+ this.valueWithCursor = this.masked;
32062
+ }), this.on("value", () => {
32063
+ if (this.cursor >= this.value.length)
32064
+ this.valueWithCursor = `${this.masked}${import_picocolors.default.inverse(import_picocolors.default.hidden("_"))}`;
32065
+ else {
32066
+ const F = this.masked.slice(0, this.cursor), s = this.masked.slice(this.cursor);
32067
+ this.valueWithCursor = `${F}${import_picocolors.default.inverse(s[0])}${s.slice(1)}`;
32068
+ }
32069
+ });
32070
+ }
32071
+ get cursor() {
32072
+ return this._cursor;
32073
+ }
32074
+ get masked() {
32075
+ return this.value.replaceAll(/./g, this._mask);
32076
+ }
32077
+ }
31975
32078
  var OD = Object.defineProperty;
31976
32079
  var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31977
32080
  var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
@@ -32046,7 +32149,7 @@ var de = u("├", "+");
32046
32149
  var pe = u("╯", "+");
32047
32150
  var q = u("●", "•");
32048
32151
  var D = u("◆", "*");
32049
- var U = u("▲", "!");
32152
+ var U2 = u("▲", "!");
32050
32153
  var K2 = u("■", "x");
32051
32154
  var b2 = (t) => {
32052
32155
  switch (t) {
@@ -32092,6 +32195,27 @@ ${import_picocolors2.default.cyan(d2)}
32092
32195
  `;
32093
32196
  }
32094
32197
  } }).prompt();
32198
+ var ge = (t) => new MD({ validate: t.validate, mask: t.mask ?? $e, render() {
32199
+ const n = `${import_picocolors2.default.gray(o)}
32200
+ ${b2(this.state)} ${t.message}
32201
+ `, r2 = this.valueWithCursor, i = this.masked;
32202
+ switch (this.state) {
32203
+ case "error":
32204
+ return `${n.trim()}
32205
+ ${import_picocolors2.default.yellow(o)} ${i}
32206
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
32207
+ `;
32208
+ case "submit":
32209
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(i)}`;
32210
+ case "cancel":
32211
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(i ?? ""))}${i ? `
32212
+ ${import_picocolors2.default.gray(o)}` : ""}`;
32213
+ default:
32214
+ return `${n}${import_picocolors2.default.cyan(o)} ${r2}
32215
+ ${import_picocolors2.default.cyan(d2)}
32216
+ `;
32217
+ }
32218
+ } }).prompt();
32095
32219
  var ye = (t) => {
32096
32220
  const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
32097
32221
  return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
@@ -32212,7 +32336,7 @@ var M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) }
32212
32336
  }, step: (t) => {
32213
32337
  M2.message(t, { symbol: import_picocolors2.default.green(C) });
32214
32338
  }, warn: (t) => {
32215
- M2.message(t, { symbol: import_picocolors2.default.yellow(U) });
32339
+ M2.message(t, { symbol: import_picocolors2.default.yellow(U2) });
32216
32340
  }, warning: (t) => {
32217
32341
  M2.warn(t);
32218
32342
  }, error: (t) => {
@@ -33519,42 +33643,156 @@ async function runSetup(options = {}) {
33519
33643
  }
33520
33644
  let apiKey = options.apiKey || existingConfig.apiKey;
33521
33645
  let userEmail = options.userEmail || existingConfig.userEmail || undefined;
33646
+ let selectedWorkspaceIdFromSignup;
33647
+ let selectedProjectIdFromSignup;
33648
+ let selectedWorkspaceNameFromSignup;
33649
+ let selectedProjectNameFromSignup;
33650
+ let createdNewAccount = false;
33522
33651
  if (needsApiKey || !apiKey || !apiKey.startsWith("hmy_")) {
33523
- const keyInput = await he({
33524
- message: "Enter your Harmony API key",
33525
- placeholder: "hmy_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
33526
- validate: (value) => {
33527
- if (!value)
33528
- return "API key is required";
33529
- if (!value.startsWith("hmy_"))
33530
- return 'API key must start with "hmy_"';
33531
- if (value.length < 20)
33532
- return "API key is too short";
33533
- return;
33652
+ let useNewAccount = options.newAccount === true;
33653
+ if (!useNewAccount && options.apiKey) {
33654
+ useNewAccount = false;
33655
+ } else if (!useNewAccount && !options.apiKey) {
33656
+ const getStarted = await ve({
33657
+ message: "How would you like to get started?",
33658
+ options: [
33659
+ {
33660
+ value: "create",
33661
+ label: "Create a free account",
33662
+ hint: "recommended for new users"
33663
+ },
33664
+ {
33665
+ value: "apikey",
33666
+ label: "I already have an API key"
33667
+ }
33668
+ ]
33669
+ });
33670
+ if (pD(getStarted)) {
33671
+ xe("Setup cancelled");
33672
+ process.exit(0);
33534
33673
  }
33535
- });
33536
- if (pD(keyInput)) {
33537
- xe("Setup cancelled");
33538
- process.exit(0);
33674
+ useNewAccount = getStarted === "create";
33675
+ }
33676
+ if (useNewAccount) {
33677
+ const fullName = options.name || await he({
33678
+ message: "Full name",
33679
+ placeholder: "Jane Smith",
33680
+ validate: (v2) => {
33681
+ if (!v2 || v2.trim().length === 0)
33682
+ return "Name is required";
33683
+ if (v2.length > 100)
33684
+ return "Name must be 100 characters or less";
33685
+ return;
33686
+ }
33687
+ });
33688
+ if (pD(fullName)) {
33689
+ xe("Setup cancelled");
33690
+ process.exit(0);
33691
+ }
33692
+ const email3 = options.userEmail || await he({
33693
+ message: "Email",
33694
+ placeholder: "you@example.com",
33695
+ validate: (v2) => {
33696
+ if (!v2)
33697
+ return "Email is required";
33698
+ if (v2.length > 254)
33699
+ return "Email is too long";
33700
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v2))
33701
+ return "Invalid email format";
33702
+ return;
33703
+ }
33704
+ });
33705
+ if (pD(email3)) {
33706
+ xe("Setup cancelled");
33707
+ process.exit(0);
33708
+ }
33709
+ const password = await ge({
33710
+ message: "Password",
33711
+ validate: (v2) => {
33712
+ if (!v2)
33713
+ return "Password is required";
33714
+ if (v2.length < 8)
33715
+ return "Password must be at least 8 characters";
33716
+ if (v2.length > 128)
33717
+ return "Password must be 128 characters or less";
33718
+ return;
33719
+ }
33720
+ });
33721
+ if (pD(password)) {
33722
+ xe("Setup cancelled");
33723
+ process.exit(0);
33724
+ }
33725
+ const spinner2 = Y2();
33726
+ spinner2.start("Creating your account...");
33727
+ try {
33728
+ const result = await onboardNewUser({
33729
+ email: email3,
33730
+ password,
33731
+ fullName
33732
+ });
33733
+ spinner2.stop(colors.success(`Account created for ${result.user.email}`));
33734
+ apiKey = result.apiKey.rawKey;
33735
+ userEmail = result.user.email;
33736
+ selectedWorkspaceIdFromSignup = result.workspace.id;
33737
+ selectedProjectIdFromSignup = result.project.id;
33738
+ selectedWorkspaceNameFromSignup = result.workspace.name;
33739
+ selectedProjectNameFromSignup = result.project.name;
33740
+ createdNewAccount = true;
33741
+ needsApiKey = true;
33742
+ saveConfig({ apiKey, userEmail, apiUrl: API_URL });
33743
+ setActiveWorkspace(selectedWorkspaceIdFromSignup);
33744
+ setActiveProject(selectedProjectIdFromSignup);
33745
+ M2.success("Workspace and board created");
33746
+ } catch (error48) {
33747
+ spinner2.stop(colors.error("Account creation failed"));
33748
+ const msg = error48 instanceof Error ? error48.message : "Unknown error";
33749
+ if (msg.includes("already") || msg.includes("409")) {
33750
+ M2.error("Account already exists. Sign in at app.gethmy.com to get your API key, or re-run setup and choose 'I already have an API key'.");
33751
+ } else {
33752
+ M2.error(msg);
33753
+ M2.info("Please try again or visit https://app.gethmy.com");
33754
+ }
33755
+ process.exit(1);
33756
+ }
33757
+ } else {
33758
+ const keyInput = await he({
33759
+ message: "Enter your Harmony API key",
33760
+ placeholder: "hmy_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
33761
+ validate: (value) => {
33762
+ if (!value)
33763
+ return "API key is required";
33764
+ if (!value.startsWith("hmy_"))
33765
+ return 'API key must start with "hmy_"';
33766
+ if (value.length < 20)
33767
+ return "API key is too short";
33768
+ return;
33769
+ }
33770
+ });
33771
+ if (pD(keyInput)) {
33772
+ xe("Setup cancelled");
33773
+ process.exit(0);
33774
+ }
33775
+ apiKey = keyInput;
33776
+ needsApiKey = true;
33539
33777
  }
33540
- apiKey = keyInput;
33541
- needsApiKey = true;
33542
33778
  } else {
33543
33779
  M2.success(`Using existing API key: ${apiKey.slice(0, 8)}...`);
33544
33780
  }
33545
33781
  const spinner = Y2();
33546
- spinner.start("Validating API key...");
33547
- const validation = await validateApiKey(apiKey);
33548
- if (!validation.valid) {
33549
- spinner.stop(colors.error("API key validation failed"));
33550
- M2.error(validation.error || "Could not connect to Harmony API");
33551
- M2.info("Get an API key at: https://app.gethmy.com/user/keys");
33552
- process.exit(1);
33553
- }
33554
- if (!userEmail) {
33555
- userEmail = validation.email;
33782
+ if (!createdNewAccount) {
33783
+ spinner.start("Validating API key...");
33784
+ const validation = await validateApiKey(apiKey);
33785
+ if (!validation.valid) {
33786
+ spinner.stop(colors.error("API key validation failed"));
33787
+ M2.error(validation.error || "Could not connect to Harmony API");
33788
+ M2.info("Get an API key at: https://app.gethmy.com/user/keys");
33789
+ process.exit(1);
33790
+ }
33791
+ if (!userEmail) {
33792
+ userEmail = validation.email;
33793
+ }
33794
+ spinner.stop(colors.success(userEmail ? `Connected as ${userEmail}` : "API key validated"));
33556
33795
  }
33557
- spinner.stop(colors.success(userEmail ? `Connected as ${userEmail}` : "API key validated"));
33558
33796
  let selectedAgents = [];
33559
33797
  let installMode = options.installMode || "global";
33560
33798
  if (skillsStatus.installed && !options.force) {
@@ -33618,10 +33856,13 @@ async function runSetup(options = {}) {
33618
33856
  installMode = modeSelection;
33619
33857
  }
33620
33858
  }
33621
- let selectedWorkspaceId = options.workspaceId;
33622
- let selectedProjectId = options.projectId;
33623
- let selectedWorkspaceName;
33624
- let selectedProjectName;
33859
+ let selectedWorkspaceId = selectedWorkspaceIdFromSignup || options.workspaceId;
33860
+ let selectedProjectId = selectedProjectIdFromSignup || options.projectId;
33861
+ let selectedWorkspaceName = selectedWorkspaceNameFromSignup;
33862
+ let selectedProjectName = selectedProjectNameFromSignup;
33863
+ if (createdNewAccount) {
33864
+ needsContext = false;
33865
+ }
33625
33866
  if (needsContext && !options.skipContext) {
33626
33867
  spinner.start("Fetching workspaces...");
33627
33868
  let workspaces = [];
@@ -33826,30 +34067,44 @@ async function runSetup(options = {}) {
33826
34067
  }
33827
34068
  console.log("");
33828
34069
  Se(colors.success("Setup complete!"));
33829
- console.log("");
33830
- console.log(` ${colors.bold("Configuration:")}`);
33831
- console.log(` API key: ${formatPath(getConfigPath(), home)}`);
33832
- if (needsSkills && selectedAgents.length > 0) {
33833
- console.log(` Skills: ${installMode === "global" ? "~/.agents/skills/ (global)" : ".claude/skills/ (local)"}`);
33834
- }
33835
- if (selectedWorkspaceId || selectedProjectId) {
33836
- console.log(` Context: ${formatPath(getLocalConfigPath(cwd), home)}`);
33837
- }
33838
- console.log("");
33839
- console.log(` ${colors.bold("Usage:")}`);
33840
- if (!needsSkills || selectedAgents.includes("claude")) {
33841
- console.log(` ${colors.brand("Claude Code:")} ${colors.highlight("/hmy #42")} or ${colors.highlight("/hmy-plan")} ${colors.dim("(create or execute plans)")}`);
33842
- }
33843
- if (selectedAgents.includes("codex")) {
33844
- console.log(` ${colors.brand("Codex:")} ${colors.highlight("/prompts:hmy #42")}`);
33845
- }
33846
- if (selectedAgents.includes("cursor") || selectedAgents.includes("windsurf")) {
33847
- console.log(` ${colors.brand("Cursor/Windsurf:")} MCP tools available automatically`);
34070
+ if (createdNewAccount && selectedWorkspaceNameFromSignup) {
34071
+ const wsSlug = selectedWorkspaceNameFromSignup.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
34072
+ const projSlug = (selectedProjectNameFromSignup || "my-first-board").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
34073
+ console.log("");
34074
+ console.log(` ${colors.bold("Your board:")} ${colors.highlight(`https://app.gethmy.com/${wsSlug}/${projSlug}`)}`);
34075
+ console.log("");
34076
+ console.log(` ${colors.bold("Next steps:")}`);
34077
+ console.log(` 1. Open Claude Code and say: ${colors.highlight('"Show me my board"')}`);
34078
+ console.log(` 2. Create a card: ${colors.highlight('"Create a card called Auth token refresh"')}`);
34079
+ console.log(` 3. Start the daemon: ${colors.highlight("npx @gethmy/agent")}`);
34080
+ console.log("");
34081
+ console.log(` ${colors.dim("Happy shipping!")}`);
34082
+ } else {
34083
+ console.log("");
34084
+ console.log(` ${colors.bold("Configuration:")}`);
34085
+ console.log(` API key: ${formatPath(getConfigPath(), home)}`);
34086
+ if (needsSkills && selectedAgents.length > 0) {
34087
+ console.log(` Skills: ${installMode === "global" ? "~/.agents/skills/ (global)" : ".claude/skills/ (local)"}`);
34088
+ }
34089
+ if (selectedWorkspaceId || selectedProjectId) {
34090
+ console.log(` Context: ${formatPath(getLocalConfigPath(cwd), home)}`);
34091
+ }
34092
+ console.log("");
34093
+ console.log(` ${colors.bold("Usage:")}`);
34094
+ if (!needsSkills || selectedAgents.includes("claude")) {
34095
+ console.log(` ${colors.brand("Claude Code:")} ${colors.highlight("/hmy #42")} or ${colors.highlight("/hmy-plan")} ${colors.dim("(create or execute plans)")}`);
34096
+ }
34097
+ if (selectedAgents.includes("codex")) {
34098
+ console.log(` ${colors.brand("Codex:")} ${colors.highlight("/prompts:hmy #42")}`);
34099
+ }
34100
+ if (selectedAgents.includes("cursor") || selectedAgents.includes("windsurf")) {
34101
+ console.log(` ${colors.brand("Cursor:")} MCP tools available automatically`);
34102
+ }
34103
+ console.log("");
34104
+ console.log(` ${colors.dim("Add to new project: npx @gethmy/mcp setup")}`);
34105
+ console.log(` ${colors.dim("Need help? Visit https://app.gethmy.com/docs/mcp")}`);
33848
34106
  }
33849
34107
  console.log("");
33850
- console.log(` ${colors.dim("Add to new project: npx @gethmy/mcp setup")}`);
33851
- console.log(` ${colors.dim("Need help? Visit https://app.gethmy.com/docs/mcp")}`);
33852
- console.log("");
33853
34108
  }
33854
34109
 
33855
34110
  // src/cli.ts
@@ -33857,6 +34112,11 @@ var require2 = createRequire2(import.meta.url);
33857
34112
  var { version: version2 } = require2("../package.json");
33858
34113
  program.name("@gethmy/mcp").description("MCP server for Harmony Kanban board").version(version2);
33859
34114
  program.command("serve").description("Start the MCP server (stdio transport)").action(async () => {
34115
+ if (!isConfigured()) {
34116
+ console.error("No API key configured.");
34117
+ console.error("Run: npx @gethmy/mcp setup");
34118
+ process.exit(1);
34119
+ }
33860
34120
  await refreshSkills();
33861
34121
  const server = new HarmonyMCPServer;
33862
34122
  await server.run();
@@ -33926,7 +34186,7 @@ program.command("reset").description("Remove stored configuration").action(() =>
33926
34186
  console.log(`
33927
34187
  To reconfigure, run: npx @gethmy/mcp setup`);
33928
34188
  });
33929
- 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) => {
34189
+ 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").option("--new", "Create a new account (skip the choice prompt)").option("-n, --name <name>", "Full name (for account creation)").action(async (options) => {
33930
34190
  await runSetup({
33931
34191
  force: options.force,
33932
34192
  apiKey: options.apiKey,
@@ -33936,7 +34196,9 @@ program.command("setup").description("Smart setup wizard for Harmony MCP (recomm
33936
34196
  workspaceId: options.workspace,
33937
34197
  projectId: options.project,
33938
34198
  skipContext: options.skipContext,
33939
- skipDocs: options.skipDocs
34199
+ skipDocs: options.skipDocs,
34200
+ newAccount: options.new,
34201
+ name: options.name
33940
34202
  });
33941
34203
  });
33942
34204
  program.parse();