@gethmy/mcp 2.13.4 → 2.15.0
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 -2
- package/dist/cli.js +333 -276
- package/dist/index.js +333 -276
- package/dist/lib/api-client.js +170 -140
- package/dist/lib/oauth-refresh.js +350 -0
- package/package.json +7 -3
- package/src/api-client.ts +77 -12
- package/src/auto-session.ts +91 -1
- package/src/server.ts +403 -326
- package/src/skills.ts +2 -2
package/dist/cli.js
CHANGED
|
@@ -1457,6 +1457,8 @@ function serializeCommentThread(comments, options = {}) {
|
|
|
1457
1457
|
const tags = [];
|
|
1458
1458
|
if (c.edited_at)
|
|
1459
1459
|
tags.push("edited");
|
|
1460
|
+
if (c.reply_to_id)
|
|
1461
|
+
tags.push(`reply to ${ref(c.reply_to_id)}`);
|
|
1460
1462
|
if (c.supersedes_id)
|
|
1461
1463
|
tags.push(`supersedes ${ref(c.supersedes_id)}`);
|
|
1462
1464
|
if (c.confirms_id)
|
|
@@ -1791,6 +1793,33 @@ class HarmonyApiClient {
|
|
|
1791
1793
|
const query = params.toString() ? `?${params.toString()}` : "";
|
|
1792
1794
|
return this.request("GET", `/board/${projectId}${query}`);
|
|
1793
1795
|
}
|
|
1796
|
+
async getFullBoard(projectId, options) {
|
|
1797
|
+
const { pageSize = 200, ...boardOpts } = options ?? {};
|
|
1798
|
+
const cards = [];
|
|
1799
|
+
let offset = 0;
|
|
1800
|
+
let last = null;
|
|
1801
|
+
for (;; ) {
|
|
1802
|
+
const page = await this.getBoard(projectId, {
|
|
1803
|
+
...boardOpts,
|
|
1804
|
+
limit: pageSize,
|
|
1805
|
+
offset
|
|
1806
|
+
});
|
|
1807
|
+
last = page;
|
|
1808
|
+
const pageCards = page.cards ?? [];
|
|
1809
|
+
cards.push(...pageCards);
|
|
1810
|
+
const hasMore = page.pagination?.hasMore ?? false;
|
|
1811
|
+
if (!hasMore || pageCards.length === 0)
|
|
1812
|
+
break;
|
|
1813
|
+
offset += pageSize;
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
project: last?.project,
|
|
1817
|
+
columns: last?.columns ?? [],
|
|
1818
|
+
cards,
|
|
1819
|
+
labels: last?.labels ?? [],
|
|
1820
|
+
totalCards: last?.pagination?.totalCards ?? cards.length
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1794
1823
|
async createCard(projectId, data) {
|
|
1795
1824
|
return this.request("POST", "/cards", { projectId, ...data });
|
|
1796
1825
|
}
|
|
@@ -1868,6 +1897,12 @@ class HarmonyApiClient {
|
|
|
1868
1897
|
async getCardExternalLinks(cardId) {
|
|
1869
1898
|
return this.request("GET", `/cards/${cardId}/external-links`);
|
|
1870
1899
|
}
|
|
1900
|
+
async addExternalLink(cardId, url, title) {
|
|
1901
|
+
return this.request("POST", `/cards/${cardId}/external-links`, {
|
|
1902
|
+
url,
|
|
1903
|
+
title
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1871
1906
|
async uploadArtifact(data) {
|
|
1872
1907
|
return this.request("POST", "/artifacts", data);
|
|
1873
1908
|
}
|
|
@@ -1919,6 +1954,7 @@ class HarmonyApiClient {
|
|
|
1919
1954
|
commentType: opts?.commentType,
|
|
1920
1955
|
supersedesId: opts?.supersedesId,
|
|
1921
1956
|
confirmsId: opts?.confirmsId,
|
|
1957
|
+
replyToId: opts?.replyToId,
|
|
1922
1958
|
agentSessionId: opts?.agentSessionId
|
|
1923
1959
|
});
|
|
1924
1960
|
}
|
|
@@ -2371,12 +2407,6 @@ ${planContent.trim()}`;
|
|
|
2371
2407
|
async updatePlaybook(playbookId, updates) {
|
|
2372
2408
|
return this.request("PATCH", `/playbooks/${playbookId}`, updates);
|
|
2373
2409
|
}
|
|
2374
|
-
async runPlaybook(playbookId) {
|
|
2375
|
-
return this.request("POST", `/playbooks/${playbookId}/run`);
|
|
2376
|
-
}
|
|
2377
|
-
async savePlaybookFromCard(data) {
|
|
2378
|
-
return this.request("POST", "/playbooks/from-card", data);
|
|
2379
|
-
}
|
|
2380
2410
|
}
|
|
2381
2411
|
var _promptModules = null;
|
|
2382
2412
|
async function loadPromptModules() {
|
|
@@ -2457,7 +2487,7 @@ function initAutoSession(callback, getClient2, getClientInfo, scopeId = DEFAULT_
|
|
|
2457
2487
|
scope.clientGetter = getClient2;
|
|
2458
2488
|
scope.clientInfoGetter = getClientInfo ?? null;
|
|
2459
2489
|
if (!inactivityTimer) {
|
|
2460
|
-
inactivityTimer = setInterval(
|
|
2490
|
+
inactivityTimer = setInterval(sweepTick, CHECK_INTERVAL_MS);
|
|
2461
2491
|
}
|
|
2462
2492
|
}
|
|
2463
2493
|
async function trackActivity(cardId, options) {
|
|
@@ -2499,7 +2529,8 @@ async function trackActivity(cardId, options) {
|
|
|
2499
2529
|
lastActivityAt: now,
|
|
2500
2530
|
isExplicit: false,
|
|
2501
2531
|
agentIdentifier,
|
|
2502
|
-
agentName
|
|
2532
|
+
agentName,
|
|
2533
|
+
status: "working"
|
|
2503
2534
|
});
|
|
2504
2535
|
}
|
|
2505
2536
|
function markExplicit(cardId, options) {
|
|
@@ -2518,7 +2549,8 @@ function markExplicit(cardId, options) {
|
|
|
2518
2549
|
lastActivityAt: Date.now(),
|
|
2519
2550
|
isExplicit: true,
|
|
2520
2551
|
agentIdentifier: options?.agentIdentifier ?? "explicit",
|
|
2521
|
-
agentName: options?.agentName ?? "Explicit Agent"
|
|
2552
|
+
agentName: options?.agentName ?? "Explicit Agent",
|
|
2553
|
+
status: "working"
|
|
2522
2554
|
});
|
|
2523
2555
|
}
|
|
2524
2556
|
}
|
|
@@ -2564,6 +2596,31 @@ function checkInactivity() {
|
|
|
2564
2596
|
}
|
|
2565
2597
|
}
|
|
2566
2598
|
}
|
|
2599
|
+
function noteSessionStatus(cardId, status, scopeId = DEFAULT_SCOPE) {
|
|
2600
|
+
const session = scopes.get(scopeId)?.sessions.get(cardId);
|
|
2601
|
+
if (session)
|
|
2602
|
+
session.status = status;
|
|
2603
|
+
}
|
|
2604
|
+
function heartbeatActiveSessions() {
|
|
2605
|
+
for (const scope of scopes.values()) {
|
|
2606
|
+
const client3 = scope.clientGetter?.();
|
|
2607
|
+
if (!client3)
|
|
2608
|
+
continue;
|
|
2609
|
+
for (const session of scope.sessions.values()) {
|
|
2610
|
+
if ((session.status ?? "working") !== "working")
|
|
2611
|
+
continue;
|
|
2612
|
+
client3.updateAgentProgress(session.cardId, {
|
|
2613
|
+
agentIdentifier: session.agentIdentifier,
|
|
2614
|
+
agentName: session.agentName,
|
|
2615
|
+
status: "working"
|
|
2616
|
+
}).catch(() => {});
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
function sweepTick() {
|
|
2621
|
+
checkInactivity();
|
|
2622
|
+
heartbeatActiveSessions();
|
|
2623
|
+
}
|
|
2567
2624
|
async function autoEndSession(scope, client3, cardId, status) {
|
|
2568
2625
|
if (!scope.sessions.delete(cardId))
|
|
2569
2626
|
return;
|
|
@@ -3240,7 +3297,7 @@ Start work on a Harmony card. Card reference: $ARGUMENTS
|
|
|
3240
3297
|
## 1. Find & Fetch Card
|
|
3241
3298
|
|
|
3242
3299
|
Parse the reference and fetch the card:
|
|
3243
|
-
- \`#42\` or \`42\` → \`
|
|
3300
|
+
- \`#42\` or \`42\` → \`harmony_get_card\` with \`shortId: 42\`
|
|
3244
3301
|
- UUID → \`harmony_get_card\` with \`cardId\`
|
|
3245
3302
|
- Name/text → \`harmony_search_cards\` with \`query\`
|
|
3246
3303
|
|
|
@@ -3294,7 +3351,7 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
|
3294
3351
|
|
|
3295
3352
|
## Key Tools Reference
|
|
3296
3353
|
|
|
3297
|
-
**Cards:** \`harmony_get_card\`, \`
|
|
3354
|
+
**Cards:** \`harmony_get_card\` (by \`cardId\`, \`shortId\`, or \`shortIds\`), \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
|
|
3298
3355
|
|
|
3299
3356
|
**Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
|
|
3300
3357
|
|
|
@@ -3488,6 +3545,37 @@ function requireExactlyOneScope(scope) {
|
|
|
3488
3545
|
throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
|
|
3489
3546
|
}
|
|
3490
3547
|
}
|
|
3548
|
+
var DEPRECATED_TOOL_ALIASES = {
|
|
3549
|
+
harmony_get_card_by_short_id: "harmony_get_card",
|
|
3550
|
+
harmony_bulk_get_cards: "harmony_get_card",
|
|
3551
|
+
harmony_upload_artifact: "harmony_upload",
|
|
3552
|
+
harmony_upload_card_attachment: "harmony_upload",
|
|
3553
|
+
harmony_request_artifact_upload_url: "harmony_request_upload_url",
|
|
3554
|
+
harmony_request_card_attachment_upload_url: "harmony_request_upload_url",
|
|
3555
|
+
harmony_finalize_artifact: "harmony_finalize_upload",
|
|
3556
|
+
harmony_finalize_card_attachment: "harmony_finalize_upload"
|
|
3557
|
+
};
|
|
3558
|
+
var _warnedDeprecatedTools = new Set;
|
|
3559
|
+
function warnDeprecatedTool(oldName) {
|
|
3560
|
+
if (_warnedDeprecatedTools.has(oldName))
|
|
3561
|
+
return;
|
|
3562
|
+
_warnedDeprecatedTools.add(oldName);
|
|
3563
|
+
const replacement = DEPRECATED_TOOL_ALIASES[oldName];
|
|
3564
|
+
console.error(`[harmony-mcp] Tool "${oldName}" is deprecated (still accepted) — ` + `use "${replacement}" instead. The old name is no longer advertised and ` + `will be removed in a future major version.`);
|
|
3565
|
+
}
|
|
3566
|
+
var DEPRECATED_REMOVED_TOOLS = {
|
|
3567
|
+
harmony_run_playbook: "Playbooks are stage models run by the board and agent daemon as a card moves through their stages — there is no server-side macro to trigger. This tool no longer runs anything.",
|
|
3568
|
+
harmony_save_card_as_playbook: "The steps_version=1 automation macro was removed. Build a stage playbook with harmony_create_playbook instead."
|
|
3569
|
+
};
|
|
3570
|
+
var _warnedRemovedTools = new Set;
|
|
3571
|
+
function deprecatedRemovedToolResult(name) {
|
|
3572
|
+
const message = DEPRECATED_REMOVED_TOOLS[name];
|
|
3573
|
+
if (!_warnedRemovedTools.has(name)) {
|
|
3574
|
+
_warnedRemovedTools.add(name);
|
|
3575
|
+
console.error(`[harmony-mcp] Tool "${name}" is deprecated and no longer functional — ${message}`);
|
|
3576
|
+
}
|
|
3577
|
+
return { success: false, deprecated: true, message };
|
|
3578
|
+
}
|
|
3491
3579
|
var SIGNED_UPLOAD_TIMEOUT_MS = 30000;
|
|
3492
3580
|
async function putToSignedUrl(uploadUrl, bytes, contentType) {
|
|
3493
3581
|
let res;
|
|
@@ -3815,44 +3903,29 @@ var TOOLS = {
|
|
|
3815
3903
|
}
|
|
3816
3904
|
},
|
|
3817
3905
|
harmony_get_card: {
|
|
3818
|
-
description: "
|
|
3819
|
-
inputSchema: {
|
|
3820
|
-
type: "object",
|
|
3821
|
-
properties: {
|
|
3822
|
-
cardId: { type: "string", description: "Card UUID" }
|
|
3823
|
-
},
|
|
3824
|
-
required: ["cardId"]
|
|
3825
|
-
}
|
|
3826
|
-
},
|
|
3827
|
-
harmony_get_card_by_short_id: {
|
|
3828
|
-
description: "Get a card by its short ID (e.g., #42) within a project",
|
|
3906
|
+
description: "Fetch one or many cards. Provide exactly one of: `cardId` (UUID, full detail), " + "`shortId` (e.g. 42, full detail), or `shortIds` (array, max 100 — compact " + "summaries: id, shortId, title, column, priority, assignee, labels, archived, " + "plus any short ids not found). `shortId`/`shortIds` need project context. " + "Prefer one `shortIds` call over repeated single fetches for multiple cards.",
|
|
3829
3907
|
inputSchema: {
|
|
3830
3908
|
type: "object",
|
|
3831
3909
|
properties: {
|
|
3832
|
-
|
|
3910
|
+
cardId: {
|
|
3833
3911
|
type: "string",
|
|
3834
|
-
description: "
|
|
3912
|
+
description: "Card UUID — full detail for one card."
|
|
3835
3913
|
},
|
|
3836
3914
|
shortId: {
|
|
3837
3915
|
type: "number",
|
|
3838
|
-
description: "Short ID
|
|
3839
|
-
}
|
|
3840
|
-
},
|
|
3841
|
-
required: ["shortId"]
|
|
3842
|
-
}
|
|
3843
|
-
},
|
|
3844
|
-
harmony_bulk_get_cards: {
|
|
3845
|
-
description: "Fetch multiple cards by short id in one call. Returns compact summaries " + "(id, shortId, title, column, priority, assignee, labels, archived) plus " + "any short ids not found. Requires project context. Prefer this over " + "repeated harmony_get_card_by_short_id when referencing multiple cards.",
|
|
3846
|
-
inputSchema: {
|
|
3847
|
-
type: "object",
|
|
3848
|
-
properties: {
|
|
3916
|
+
description: "Short ID (e.g. 42 for card #42) — full detail, project-scoped."
|
|
3917
|
+
},
|
|
3849
3918
|
shortIds: {
|
|
3850
3919
|
type: "array",
|
|
3851
3920
|
items: { type: "number" },
|
|
3852
|
-
description: "
|
|
3921
|
+
description: "Short IDs, e.g. [400, 401, 402] — compact summaries in one call. Max 100."
|
|
3922
|
+
},
|
|
3923
|
+
projectId: {
|
|
3924
|
+
type: "string",
|
|
3925
|
+
description: "Project ID for shortId/shortIds (optional if context set)."
|
|
3853
3926
|
}
|
|
3854
3927
|
},
|
|
3855
|
-
required: [
|
|
3928
|
+
required: []
|
|
3856
3929
|
}
|
|
3857
3930
|
},
|
|
3858
3931
|
harmony_bulk_archive_cards: {
|
|
@@ -4007,174 +4080,144 @@ var TOOLS = {
|
|
|
4007
4080
|
required: ["cardId"]
|
|
4008
4081
|
}
|
|
4009
4082
|
},
|
|
4010
|
-
|
|
4011
|
-
description:
|
|
4083
|
+
harmony_upload: {
|
|
4084
|
+
description: 'Upload a file in one call. `target: "card_attachment"` attaches a file to a card ' + "(max 5MB; PNG/JPEG/GIF/WebP/HEIC/HEIF/PDF/DOC(X)/XLS(X)/TXT/CSV) — requires cardId. " + '`target: "artifact"` hosts a self-contained HTML doc (text/html, max 2MB) linked to ' + "exactly one of cardId/planId/workspaceId, rendered in-app in a sandboxed iframe. Provide " + "the bytes as `filePath` (local, direct-to-storage) or `base64Data` (small-file fallback). " + "Returns the attachment/artifact + a signed URL (artifact: use harmony_share_artifact for a " + "public link). Large files on the hosted MCP server: use harmony_request_upload_url + " + "harmony_finalize_upload instead.",
|
|
4012
4085
|
inputSchema: {
|
|
4013
4086
|
type: "object",
|
|
4014
4087
|
properties: {
|
|
4015
|
-
|
|
4088
|
+
target: {
|
|
4089
|
+
type: "string",
|
|
4090
|
+
enum: ["card_attachment", "artifact"],
|
|
4091
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4092
|
+
},
|
|
4093
|
+
cardId: {
|
|
4094
|
+
type: "string",
|
|
4095
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4096
|
+
},
|
|
4097
|
+
planId: {
|
|
4098
|
+
type: "string",
|
|
4099
|
+
description: "Plan UUID (artifact only — link the artifact to a plan)."
|
|
4100
|
+
},
|
|
4101
|
+
workspaceId: {
|
|
4102
|
+
type: "string",
|
|
4103
|
+
description: "Workspace UUID (artifact only — standalone artifact)."
|
|
4104
|
+
},
|
|
4016
4105
|
filePath: {
|
|
4017
4106
|
type: "string",
|
|
4018
|
-
description: "Absolute path to a local file the
|
|
4107
|
+
description: "Absolute path to a local file the server can read. Mutually exclusive with base64Data."
|
|
4019
4108
|
},
|
|
4020
4109
|
base64Data: {
|
|
4021
4110
|
type: "string",
|
|
4022
|
-
description: "Base64-encoded
|
|
4111
|
+
description: "Base64-encoded bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
|
|
4023
4112
|
},
|
|
4024
4113
|
fileName: {
|
|
4025
4114
|
type: "string",
|
|
4026
|
-
description: "File name including extension (
|
|
4115
|
+
description: "File name including extension (card_attachment: required with base64Data, else defaults to the filePath basename)."
|
|
4116
|
+
},
|
|
4117
|
+
title: {
|
|
4118
|
+
type: "string",
|
|
4119
|
+
description: "Artifact display title (defaults to the file basename)."
|
|
4027
4120
|
},
|
|
4028
4121
|
contentType: {
|
|
4029
4122
|
type: "string",
|
|
4030
|
-
description: "Optional MIME type (
|
|
4123
|
+
description: "Optional MIME type (card_attachment; inferred from the extension when omitted)."
|
|
4031
4124
|
}
|
|
4032
4125
|
},
|
|
4033
|
-
required: ["
|
|
4126
|
+
required: ["target"]
|
|
4034
4127
|
}
|
|
4035
4128
|
},
|
|
4036
|
-
|
|
4037
|
-
description: "Step 1 of the large-file / hosted-MCP upload handshake (use when the server can't read local disk). Mints a one-shot signed Storage upload URL
|
|
4129
|
+
harmony_request_upload_url: {
|
|
4130
|
+
description: "Step 1 of the large-file / hosted-MCP upload handshake (use when the server can't read " + 'local disk). Mints a one-shot signed Storage upload URL. `target: "card_attachment"` ' + '(requires cardId, fileName, size; max 5MB) or `target: "artifact"` (one of ' + "cardId/planId/workspaceId; text/html, max 2MB). Returns { uploadUrl, token, storagePath, " + "[fileType] }. Then PUT the raw bytes to uploadUrl (no bytes through the model context) and " + "call harmony_finalize_upload with the storagePath.",
|
|
4038
4131
|
inputSchema: {
|
|
4039
4132
|
type: "object",
|
|
4040
4133
|
properties: {
|
|
4041
|
-
|
|
4042
|
-
fileName: {
|
|
4134
|
+
target: {
|
|
4043
4135
|
type: "string",
|
|
4044
|
-
|
|
4136
|
+
enum: ["card_attachment", "artifact"],
|
|
4137
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4045
4138
|
},
|
|
4046
|
-
|
|
4139
|
+
cardId: {
|
|
4047
4140
|
type: "string",
|
|
4048
|
-
description: "
|
|
4141
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4049
4142
|
},
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
description: "File size in bytes (rejected early if over 5MB)."
|
|
4053
|
-
}
|
|
4054
|
-
},
|
|
4055
|
-
required: ["cardId", "fileName", "size"]
|
|
4056
|
-
}
|
|
4057
|
-
},
|
|
4058
|
-
harmony_finalize_card_attachment: {
|
|
4059
|
-
description: "Step 2 of the upload handshake. After PUTting the bytes to the signed uploadUrl, call this with storagePath to validate and register the attachment. The server re-downloads the object and enforces size + an allowlisted content-type (magic-byte sniff, never the declared type) + an optional sha256 integrity check, deleting and failing on any mismatch. Returns the attachment + a signed URL.",
|
|
4060
|
-
inputSchema: {
|
|
4061
|
-
type: "object",
|
|
4062
|
-
properties: {
|
|
4063
|
-
cardId: { type: "string", description: "Card UUID" },
|
|
4064
|
-
storagePath: {
|
|
4143
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4144
|
+
workspaceId: {
|
|
4065
4145
|
type: "string",
|
|
4066
|
-
description: "
|
|
4146
|
+
description: "Workspace UUID (artifact only)."
|
|
4067
4147
|
},
|
|
4068
4148
|
fileName: {
|
|
4069
4149
|
type: "string",
|
|
4070
|
-
description: "File name including extension (
|
|
4150
|
+
description: "File name including extension (required for card_attachment)."
|
|
4071
4151
|
},
|
|
4152
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4072
4153
|
fileType: {
|
|
4073
4154
|
type: "string",
|
|
4074
|
-
description: "
|
|
4155
|
+
description: "card_attachment MIME type (inferred from the extension when omitted)."
|
|
4075
4156
|
},
|
|
4076
|
-
|
|
4157
|
+
contentType: {
|
|
4077
4158
|
type: "string",
|
|
4078
|
-
description: "
|
|
4159
|
+
description: "artifact MIME type; only 'text/html' is accepted (the default)."
|
|
4079
4160
|
},
|
|
4080
4161
|
size: {
|
|
4081
4162
|
type: "number",
|
|
4082
|
-
description: "
|
|
4163
|
+
description: "File size in bytes (rejected early if over the target's limit)."
|
|
4083
4164
|
}
|
|
4084
4165
|
},
|
|
4085
|
-
required: ["
|
|
4166
|
+
required: ["target"]
|
|
4086
4167
|
}
|
|
4087
4168
|
},
|
|
4088
|
-
|
|
4089
|
-
description: "
|
|
4169
|
+
harmony_finalize_upload: {
|
|
4170
|
+
description: "Step 2 of the upload handshake. After PUTting the bytes to the signed uploadUrl, call this " + "with the storagePath to validate and register. The server re-downloads the object and " + "enforces size + content-type (magic-byte sniff, never the declared type) + an optional " + 'sha256 integrity check, deleting and failing on any mismatch. `target: "card_attachment"` ' + '(cardId, storagePath, fileName) or `target: "artifact"` (storagePath + the same one of ' + "cardId/planId/workspaceId used for the upload URL). Returns the attachment/artifact + a signed URL.",
|
|
4090
4171
|
inputSchema: {
|
|
4091
4172
|
type: "object",
|
|
4092
4173
|
properties: {
|
|
4093
|
-
|
|
4094
|
-
},
|
|
4095
|
-
required: ["cardId"]
|
|
4096
|
-
}
|
|
4097
|
-
},
|
|
4098
|
-
harmony_upload_artifact: {
|
|
4099
|
-
description: "Host a self-contained HTML document (design draft, diagram) and link it to a card, plan, or workspace; rendered in-app in a sandboxed iframe. Provide exactly one of cardId/planId/workspaceId, and the HTML as `filePath` (local, direct-to-storage) or `base64Data` (small-file fallback). text/html only, max 2MB. Returns the artifact + a signed URL; use harmony_share_artifact for a public link. Large files on the hosted MCP server: use harmony_request_artifact_upload_url + harmony_finalize_artifact instead.",
|
|
4100
|
-
inputSchema: {
|
|
4101
|
-
type: "object",
|
|
4102
|
-
properties: {
|
|
4103
|
-
title: {
|
|
4174
|
+
target: {
|
|
4104
4175
|
type: "string",
|
|
4105
|
-
|
|
4176
|
+
enum: ["card_attachment", "artifact"],
|
|
4177
|
+
description: "What to finalize: a card file attachment or a hosted HTML artifact."
|
|
4106
4178
|
},
|
|
4107
|
-
|
|
4108
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4109
|
-
workspaceId: {
|
|
4179
|
+
storagePath: {
|
|
4110
4180
|
type: "string",
|
|
4111
|
-
description: "
|
|
4181
|
+
description: "The storagePath returned by harmony_request_upload_url."
|
|
4112
4182
|
},
|
|
4113
|
-
|
|
4183
|
+
cardId: {
|
|
4114
4184
|
type: "string",
|
|
4115
|
-
description: "
|
|
4185
|
+
description: "Card UUID. Required for card_attachment; scope for artifact."
|
|
4116
4186
|
},
|
|
4117
|
-
|
|
4187
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4188
|
+
workspaceId: {
|
|
4118
4189
|
type: "string",
|
|
4119
|
-
description: "
|
|
4120
|
-
}
|
|
4121
|
-
|
|
4122
|
-
required: []
|
|
4123
|
-
}
|
|
4124
|
-
},
|
|
4125
|
-
harmony_request_artifact_upload_url: {
|
|
4126
|
-
description: "Step 1 of the large-file / hosted-MCP artifact upload handshake (use when the server can't read local disk). Mints a one-shot signed Storage upload URL. Provide exactly one of cardId/planId/workspaceId. Returns { uploadUrl, token, storagePath }. Then PUT the HTML bytes to uploadUrl and call harmony_finalize_artifact with storagePath. text/html only, max 2MB.",
|
|
4127
|
-
inputSchema: {
|
|
4128
|
-
type: "object",
|
|
4129
|
-
properties: {
|
|
4130
|
-
title: {
|
|
4190
|
+
description: "Workspace UUID (artifact only)."
|
|
4191
|
+
},
|
|
4192
|
+
fileName: {
|
|
4131
4193
|
type: "string",
|
|
4132
|
-
description: "
|
|
4194
|
+
description: "File name including extension (required for card_attachment)."
|
|
4133
4195
|
},
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
workspaceId: {
|
|
4196
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4197
|
+
fileType: {
|
|
4137
4198
|
type: "string",
|
|
4138
|
-
description: "
|
|
4199
|
+
description: "card_attachment MIME type; inferred from the extension when omitted."
|
|
4139
4200
|
},
|
|
4140
|
-
|
|
4201
|
+
sha256: {
|
|
4141
4202
|
type: "string",
|
|
4142
|
-
description: "
|
|
4203
|
+
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4143
4204
|
},
|
|
4144
4205
|
size: {
|
|
4145
4206
|
type: "number",
|
|
4146
|
-
description: "
|
|
4207
|
+
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4147
4208
|
}
|
|
4148
4209
|
},
|
|
4149
|
-
required: []
|
|
4210
|
+
required: ["target", "storagePath"]
|
|
4150
4211
|
}
|
|
4151
4212
|
},
|
|
4152
|
-
|
|
4153
|
-
description: "
|
|
4213
|
+
harmony_classify_card: {
|
|
4214
|
+
description: "Classify a card with the LLM classifier: sets `intent` (plan/think/implement/review), `complexity_score` (0-10), `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the type label (feature/bug/idea). Call right after creating a card to classify it in-flow. Idempotent; never touches the user-owned `model_override`.",
|
|
4154
4215
|
inputSchema: {
|
|
4155
4216
|
type: "object",
|
|
4156
4217
|
properties: {
|
|
4157
|
-
|
|
4158
|
-
type: "string",
|
|
4159
|
-
description: "The storagePath returned by harmony_request_artifact_upload_url."
|
|
4160
|
-
},
|
|
4161
|
-
title: { type: "string", description: "Display title." },
|
|
4162
|
-
cardId: { type: "string", description: "Link to this card (UUID)." },
|
|
4163
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4164
|
-
workspaceId: {
|
|
4165
|
-
type: "string",
|
|
4166
|
-
description: "Attach to this workspace as a standalone artifact (UUID)."
|
|
4167
|
-
},
|
|
4168
|
-
sha256: {
|
|
4169
|
-
type: "string",
|
|
4170
|
-
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4171
|
-
},
|
|
4172
|
-
size: {
|
|
4173
|
-
type: "number",
|
|
4174
|
-
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4175
|
-
}
|
|
4218
|
+
cardId: { type: "string", description: "Card UUID" }
|
|
4176
4219
|
},
|
|
4177
|
-
required: ["
|
|
4220
|
+
required: ["cardId"]
|
|
4178
4221
|
}
|
|
4179
4222
|
},
|
|
4180
4223
|
harmony_share_artifact: {
|
|
@@ -4204,6 +4247,27 @@ var TOOLS = {
|
|
|
4204
4247
|
required: ["cardId"]
|
|
4205
4248
|
}
|
|
4206
4249
|
},
|
|
4250
|
+
harmony_add_external_link: {
|
|
4251
|
+
description: "Attach an external reference URL (e.g. a PR/MR link, doc, or dashboard) to a card. Durable — survives description edits. Use this in addition to writing the PR link into the description.",
|
|
4252
|
+
inputSchema: {
|
|
4253
|
+
type: "object",
|
|
4254
|
+
properties: {
|
|
4255
|
+
cardId: {
|
|
4256
|
+
type: "string",
|
|
4257
|
+
description: "Card UUID"
|
|
4258
|
+
},
|
|
4259
|
+
url: {
|
|
4260
|
+
type: "string",
|
|
4261
|
+
description: "The URL to attach"
|
|
4262
|
+
},
|
|
4263
|
+
title: {
|
|
4264
|
+
type: "string",
|
|
4265
|
+
description: "Optional human-readable title for the link"
|
|
4266
|
+
}
|
|
4267
|
+
},
|
|
4268
|
+
required: ["cardId", "url"]
|
|
4269
|
+
}
|
|
4270
|
+
},
|
|
4207
4271
|
harmony_create_subtask: {
|
|
4208
4272
|
description: "Create a subtask on a card",
|
|
4209
4273
|
inputSchema: {
|
|
@@ -4255,7 +4319,7 @@ var TOOLS = {
|
|
|
4255
4319
|
}
|
|
4256
4320
|
},
|
|
4257
4321
|
harmony_add_comment: {
|
|
4258
|
-
description: "Post a comment on a card as the agent — converse with the human in the open: report progress, ask a question, record a decision, or note a finding, instead of editing the card description. Set supersedesId to correct an earlier comment, confirmsId to reaffirm one.",
|
|
4322
|
+
description: "Post a comment on a card as the agent — converse with the human in the open: report progress, ask a question, record a decision, or note a finding, instead of editing the card description. Set supersedesId to correct an earlier comment, confirmsId to reaffirm one. To answer an open question, reply to it with replyToId.",
|
|
4259
4323
|
inputSchema: {
|
|
4260
4324
|
type: "object",
|
|
4261
4325
|
properties: {
|
|
@@ -4281,6 +4345,10 @@ var TOOLS = {
|
|
|
4281
4345
|
confirmsId: {
|
|
4282
4346
|
type: "string",
|
|
4283
4347
|
description: "Comment id this comment reaffirms"
|
|
4348
|
+
},
|
|
4349
|
+
replyToId: {
|
|
4350
|
+
type: "string",
|
|
4351
|
+
description: "Comment id this is a one-level reply to. To answer an open question, reply to it. If you also set supersedesId/confirmsId, it must equal replyToId."
|
|
4284
4352
|
}
|
|
4285
4353
|
},
|
|
4286
4354
|
required: ["cardId", "body"]
|
|
@@ -5151,7 +5219,7 @@ var TOOLS = {
|
|
|
5151
5219
|
}
|
|
5152
5220
|
},
|
|
5153
5221
|
harmony_list_playbook: {
|
|
5154
|
-
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version,
|
|
5222
|
+
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, and state. Read-only.",
|
|
5155
5223
|
inputSchema: {
|
|
5156
5224
|
type: "object",
|
|
5157
5225
|
properties: {
|
|
@@ -5173,21 +5241,8 @@ var TOOLS = {
|
|
|
5173
5241
|
required: ["playbookId"]
|
|
5174
5242
|
}
|
|
5175
5243
|
},
|
|
5176
|
-
harmony_run_playbook: {
|
|
5177
|
-
description: "Run a playbook server-side and return the finalized run. Only legacy automation playbooks (steps_version 1) are runnable; stage playbooks (steps_version 2) are rejected. The server drives every step to completion.",
|
|
5178
|
-
inputSchema: {
|
|
5179
|
-
type: "object",
|
|
5180
|
-
properties: {
|
|
5181
|
-
playbookId: {
|
|
5182
|
-
type: "string",
|
|
5183
|
-
description: "Playbook ID to run (UUID)"
|
|
5184
|
-
}
|
|
5185
|
-
},
|
|
5186
|
-
required: ["playbookId"]
|
|
5187
|
-
}
|
|
5188
|
-
},
|
|
5189
5244
|
harmony_create_playbook: {
|
|
5190
|
-
description: "Create a new playbook in a workspace.
|
|
5245
|
+
description: "Create a new playbook (a reusable process definition) in a workspace. A playbook is an ordered set of stages bound to board columns, run by people and the agent daemon as a card moves through them.",
|
|
5191
5246
|
inputSchema: {
|
|
5192
5247
|
type: "object",
|
|
5193
5248
|
properties: {
|
|
@@ -5197,14 +5252,9 @@ var TOOLS = {
|
|
|
5197
5252
|
},
|
|
5198
5253
|
name: { type: "string", description: "Playbook name" },
|
|
5199
5254
|
description: { type: "string", description: "Playbook description" },
|
|
5200
|
-
stepsVersion: {
|
|
5201
|
-
type: "number",
|
|
5202
|
-
enum: [1, 2],
|
|
5203
|
-
description: "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1."
|
|
5204
|
-
},
|
|
5205
5255
|
steps: {
|
|
5206
5256
|
type: "array",
|
|
5207
|
-
description: "
|
|
5257
|
+
description: "The playbook's ordered stage objects.",
|
|
5208
5258
|
items: { type: "object" }
|
|
5209
5259
|
}
|
|
5210
5260
|
},
|
|
@@ -5224,7 +5274,7 @@ var TOOLS = {
|
|
|
5224
5274
|
description: { type: "string", description: "New description" },
|
|
5225
5275
|
steps: {
|
|
5226
5276
|
type: "array",
|
|
5227
|
-
description: "New
|
|
5277
|
+
description: "New ordered stage objects.",
|
|
5228
5278
|
items: { type: "object" }
|
|
5229
5279
|
},
|
|
5230
5280
|
enabled: {
|
|
@@ -5240,20 +5290,6 @@ var TOOLS = {
|
|
|
5240
5290
|
required: ["playbookId"]
|
|
5241
5291
|
}
|
|
5242
5292
|
},
|
|
5243
|
-
harmony_save_card_as_playbook: {
|
|
5244
|
-
description: "Save an existing card as a new steps_version 1 (automation) playbook, seeding one create-card step from the card. Returns the created playbook.",
|
|
5245
|
-
inputSchema: {
|
|
5246
|
-
type: "object",
|
|
5247
|
-
properties: {
|
|
5248
|
-
cardId: { type: "string", description: "Card ID to template (UUID)" },
|
|
5249
|
-
name: {
|
|
5250
|
-
type: "string",
|
|
5251
|
-
description: "Name for the new playbook (defaults to the card title)"
|
|
5252
|
-
}
|
|
5253
|
-
},
|
|
5254
|
-
required: ["cardId"]
|
|
5255
|
-
}
|
|
5256
|
-
},
|
|
5257
5293
|
harmony_signup: {
|
|
5258
5294
|
description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
|
|
5259
5295
|
inputSchema: {
|
|
@@ -5653,23 +5689,33 @@ async function handleToolCall(name, args, deps) {
|
|
|
5653
5689
|
});
|
|
5654
5690
|
return { success: true, ...result, count: result.cards.length };
|
|
5655
5691
|
}
|
|
5692
|
+
case "harmony_get_card_by_short_id":
|
|
5693
|
+
case "harmony_bulk_get_cards":
|
|
5656
5694
|
case "harmony_get_card": {
|
|
5695
|
+
if (name !== "harmony_get_card")
|
|
5696
|
+
warnDeprecatedTool(name);
|
|
5697
|
+
const hasShortIds = args.shortIds != null;
|
|
5698
|
+
const hasShortId = args.shortId != null;
|
|
5699
|
+
const hasCardId = args.cardId != null;
|
|
5700
|
+
if ([hasShortIds, hasShortId, hasCardId].filter(Boolean).length !== 1) {
|
|
5701
|
+
throw new Error("Provide exactly one of: cardId (UUID), shortId (number), or shortIds (number[]).");
|
|
5702
|
+
}
|
|
5703
|
+
if (hasShortIds) {
|
|
5704
|
+
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5705
|
+
const projectId = getProjectId();
|
|
5706
|
+
const result2 = await client3.bulkGetCards(projectId, shortIds);
|
|
5707
|
+
return { success: true, ...result2 };
|
|
5708
|
+
}
|
|
5709
|
+
if (hasShortId) {
|
|
5710
|
+
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5711
|
+
const projectId = args.projectId || getProjectId();
|
|
5712
|
+
const result2 = await client3.getCardByShortId(projectId, shortId);
|
|
5713
|
+
return { success: true, ...result2 };
|
|
5714
|
+
}
|
|
5657
5715
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5658
5716
|
const result = await client3.getCard(cardId);
|
|
5659
5717
|
return { success: true, ...result };
|
|
5660
5718
|
}
|
|
5661
|
-
case "harmony_get_card_by_short_id": {
|
|
5662
|
-
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5663
|
-
const projectId = args.projectId || getProjectId();
|
|
5664
|
-
const result = await client3.getCardByShortId(projectId, shortId);
|
|
5665
|
-
return { success: true, ...result };
|
|
5666
|
-
}
|
|
5667
|
-
case "harmony_bulk_get_cards": {
|
|
5668
|
-
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5669
|
-
const projectId = getProjectId();
|
|
5670
|
-
const result = await client3.bulkGetCards(projectId, shortIds);
|
|
5671
|
-
return { success: true, ...result };
|
|
5672
|
-
}
|
|
5673
5719
|
case "harmony_bulk_archive_cards": {
|
|
5674
5720
|
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5675
5721
|
const projectId = getProjectId();
|
|
@@ -5769,58 +5815,58 @@ async function handleToolCall(name, args, deps) {
|
|
|
5769
5815
|
const result = await client3.getCardAttachments(cardId);
|
|
5770
5816
|
return result;
|
|
5771
5817
|
}
|
|
5772
|
-
case "harmony_upload_card_attachment":
|
|
5773
|
-
|
|
5818
|
+
case "harmony_upload_card_attachment":
|
|
5819
|
+
case "harmony_upload_artifact":
|
|
5820
|
+
case "harmony_upload": {
|
|
5821
|
+
if (name !== "harmony_upload")
|
|
5822
|
+
warnDeprecatedTool(name);
|
|
5823
|
+
const target = name === "harmony_upload_card_attachment" ? "card_attachment" : name === "harmony_upload_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5774
5824
|
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5775
5825
|
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5776
|
-
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5777
|
-
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5778
5826
|
if (filePath && base64Data) {
|
|
5779
5827
|
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5780
5828
|
}
|
|
5781
|
-
if (
|
|
5782
|
-
const
|
|
5783
|
-
const
|
|
5784
|
-
const
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5829
|
+
if (target === "card_attachment") {
|
|
5830
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5831
|
+
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5832
|
+
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5833
|
+
if (filePath) {
|
|
5834
|
+
const bytes = await readFileForUpload(filePath, MAX_ATTACHMENT_SIZE, "attachment");
|
|
5835
|
+
const resolvedName = fileName || basename(filePath);
|
|
5836
|
+
const signed = await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5837
|
+
fileName: resolvedName,
|
|
5838
|
+
fileType: contentType,
|
|
5839
|
+
size: bytes.byteLength
|
|
5840
|
+
});
|
|
5841
|
+
await putToSignedUrl(signed.uploadUrl, bytes, contentType || signed.fileType || "application/octet-stream");
|
|
5842
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5843
|
+
storagePath: signed.storagePath,
|
|
5844
|
+
fileName: resolvedName,
|
|
5845
|
+
fileType: contentType || signed.fileType,
|
|
5846
|
+
sha256: sha256Hex(bytes),
|
|
5847
|
+
size: bytes.byteLength
|
|
5848
|
+
});
|
|
5801
5849
|
}
|
|
5802
|
-
if (
|
|
5803
|
-
|
|
5850
|
+
if (base64Data) {
|
|
5851
|
+
if (!fileName) {
|
|
5852
|
+
throw new Error("fileName is required when using base64Data.");
|
|
5853
|
+
}
|
|
5854
|
+
if (base64ByteLength(base64Data) > MAX_ATTACHMENT_SIZE) {
|
|
5855
|
+
throw new Error(`File is over the 5MB attachment limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5856
|
+
}
|
|
5857
|
+
return await client3.uploadCardAttachment(cardId2, {
|
|
5858
|
+
fileName,
|
|
5859
|
+
data: base64Data,
|
|
5860
|
+
fileType: contentType
|
|
5861
|
+
});
|
|
5804
5862
|
}
|
|
5805
|
-
|
|
5806
|
-
fileName,
|
|
5807
|
-
data: base64Data,
|
|
5808
|
-
fileType: contentType
|
|
5809
|
-
});
|
|
5863
|
+
throw new Error("Provide either filePath or base64Data.");
|
|
5810
5864
|
}
|
|
5811
|
-
throw new Error("Provide either filePath or base64Data.");
|
|
5812
|
-
}
|
|
5813
|
-
case "harmony_upload_artifact": {
|
|
5814
5865
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5815
5866
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5816
5867
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
5817
5868
|
const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
|
|
5818
5869
|
requireExactlyOneScope({ cardId, planId, workspaceId });
|
|
5819
|
-
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5820
|
-
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5821
|
-
if (filePath && base64Data) {
|
|
5822
|
-
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5823
|
-
}
|
|
5824
5870
|
if (filePath) {
|
|
5825
5871
|
const bytes = await readFileForUpload(filePath, MAX_ARTIFACT_SIZE, "artifact");
|
|
5826
5872
|
const resolvedTitle = title || basename(filePath);
|
|
@@ -5845,7 +5891,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
5845
5891
|
}
|
|
5846
5892
|
if (base64Data) {
|
|
5847
5893
|
if (base64ByteLength(base64Data) > MAX_ARTIFACT_SIZE) {
|
|
5848
|
-
throw new Error(`Artifact is over the 2MB limit. Use the
|
|
5894
|
+
throw new Error(`Artifact is over the 2MB limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5849
5895
|
}
|
|
5850
5896
|
return await client3.uploadArtifact({
|
|
5851
5897
|
title,
|
|
@@ -5857,7 +5903,26 @@ async function handleToolCall(name, args, deps) {
|
|
|
5857
5903
|
}
|
|
5858
5904
|
throw new Error("Provide either filePath or base64Data.");
|
|
5859
5905
|
}
|
|
5860
|
-
case "harmony_request_artifact_upload_url":
|
|
5906
|
+
case "harmony_request_artifact_upload_url":
|
|
5907
|
+
case "harmony_request_card_attachment_upload_url":
|
|
5908
|
+
case "harmony_request_upload_url": {
|
|
5909
|
+
if (name !== "harmony_request_upload_url")
|
|
5910
|
+
warnDeprecatedTool(name);
|
|
5911
|
+
const target = name === "harmony_request_card_attachment_upload_url" ? "card_attachment" : name === "harmony_request_artifact_upload_url" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5912
|
+
if (target === "card_attachment") {
|
|
5913
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5914
|
+
const fileName = z.string().parse(args.fileName);
|
|
5915
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5916
|
+
const size2 = z.number().positive().parse(args.size);
|
|
5917
|
+
if (size2 > MAX_ATTACHMENT_SIZE) {
|
|
5918
|
+
throw new Error(`Declared size ${size2} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5919
|
+
}
|
|
5920
|
+
return await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5921
|
+
fileName,
|
|
5922
|
+
fileType,
|
|
5923
|
+
size: size2
|
|
5924
|
+
});
|
|
5925
|
+
}
|
|
5861
5926
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5862
5927
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5863
5928
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5877,8 +5942,27 @@ async function handleToolCall(name, args, deps) {
|
|
|
5877
5942
|
size
|
|
5878
5943
|
});
|
|
5879
5944
|
}
|
|
5880
|
-
case "harmony_finalize_artifact":
|
|
5945
|
+
case "harmony_finalize_artifact":
|
|
5946
|
+
case "harmony_finalize_card_attachment":
|
|
5947
|
+
case "harmony_finalize_upload": {
|
|
5948
|
+
if (name !== "harmony_finalize_upload")
|
|
5949
|
+
warnDeprecatedTool(name);
|
|
5950
|
+
const target = name === "harmony_finalize_card_attachment" ? "card_attachment" : name === "harmony_finalize_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5881
5951
|
const storagePath = z.string().parse(args.storagePath);
|
|
5952
|
+
if (target === "card_attachment") {
|
|
5953
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5954
|
+
const fileName = z.string().parse(args.fileName);
|
|
5955
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5956
|
+
const sha2562 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5957
|
+
const size2 = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5958
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5959
|
+
storagePath,
|
|
5960
|
+
fileName,
|
|
5961
|
+
fileType,
|
|
5962
|
+
sha256: sha2562,
|
|
5963
|
+
size: size2
|
|
5964
|
+
});
|
|
5965
|
+
}
|
|
5882
5966
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5883
5967
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5884
5968
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5896,35 +5980,6 @@ async function handleToolCall(name, args, deps) {
|
|
|
5896
5980
|
workspaceId
|
|
5897
5981
|
});
|
|
5898
5982
|
}
|
|
5899
|
-
case "harmony_request_card_attachment_upload_url": {
|
|
5900
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5901
|
-
const fileName = z.string().parse(args.fileName);
|
|
5902
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5903
|
-
const size = z.number().positive().parse(args.size);
|
|
5904
|
-
if (size > MAX_ATTACHMENT_SIZE) {
|
|
5905
|
-
throw new Error(`Declared size ${size} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5906
|
-
}
|
|
5907
|
-
return await client3.requestCardAttachmentUploadUrl(cardId, {
|
|
5908
|
-
fileName,
|
|
5909
|
-
fileType,
|
|
5910
|
-
size
|
|
5911
|
-
});
|
|
5912
|
-
}
|
|
5913
|
-
case "harmony_finalize_card_attachment": {
|
|
5914
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5915
|
-
const storagePath = z.string().parse(args.storagePath);
|
|
5916
|
-
const fileName = z.string().parse(args.fileName);
|
|
5917
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5918
|
-
const sha256 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5919
|
-
const size = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5920
|
-
return await client3.finalizeCardAttachment(cardId, {
|
|
5921
|
-
storagePath,
|
|
5922
|
-
fileName,
|
|
5923
|
-
fileType,
|
|
5924
|
-
sha256,
|
|
5925
|
-
size
|
|
5926
|
-
});
|
|
5927
|
-
}
|
|
5928
5983
|
case "harmony_share_artifact": {
|
|
5929
5984
|
const artifactId = z.string().uuid().parse(args.artifactId);
|
|
5930
5985
|
const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
|
|
@@ -5937,6 +5992,13 @@ async function handleToolCall(name, args, deps) {
|
|
|
5937
5992
|
const result = await client3.getCardExternalLinks(cardId);
|
|
5938
5993
|
return result;
|
|
5939
5994
|
}
|
|
5995
|
+
case "harmony_add_external_link": {
|
|
5996
|
+
const cardId = z.string().uuid().parse(args.cardId);
|
|
5997
|
+
const url = z.string().min(1).max(2048).parse(args.url);
|
|
5998
|
+
const title = args.title ? z.string().max(200).parse(args.title) : undefined;
|
|
5999
|
+
const result = await client3.addExternalLink(cardId, url, title);
|
|
6000
|
+
return { success: true, ...result };
|
|
6001
|
+
}
|
|
5940
6002
|
case "harmony_classify_card": {
|
|
5941
6003
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5942
6004
|
const result = await client3.classifyCard(cardId);
|
|
@@ -5990,10 +6052,12 @@ async function handleToolCall(name, args, deps) {
|
|
|
5990
6052
|
]).parse(args.commentType) : undefined;
|
|
5991
6053
|
const supersedesId = args.supersedesId !== undefined ? z.string().uuid().parse(args.supersedesId) : undefined;
|
|
5992
6054
|
const confirmsId = args.confirmsId !== undefined ? z.string().uuid().parse(args.confirmsId) : undefined;
|
|
6055
|
+
const replyToId = args.replyToId !== undefined ? z.string().uuid().parse(args.replyToId) : undefined;
|
|
5993
6056
|
const result = await client3.addComment(cardId, body, {
|
|
5994
6057
|
commentType,
|
|
5995
6058
|
supersedesId,
|
|
5996
|
-
confirmsId
|
|
6059
|
+
confirmsId,
|
|
6060
|
+
replyToId
|
|
5997
6061
|
});
|
|
5998
6062
|
return { success: true, ...result };
|
|
5999
6063
|
}
|
|
@@ -6193,10 +6257,14 @@ async function handleToolCall(name, args, deps) {
|
|
|
6193
6257
|
mergedRecentActions = callerRecentActions;
|
|
6194
6258
|
}
|
|
6195
6259
|
const runActivity = (callerActions || []).map((a) => a.description).filter((d) => typeof d === "string" && d.length > 0);
|
|
6260
|
+
const reportedStatus = args.status;
|
|
6261
|
+
if (reportedStatus) {
|
|
6262
|
+
noteSessionStatus(cardId, reportedStatus, deps.getScopeId?.());
|
|
6263
|
+
}
|
|
6196
6264
|
const result = await client3.updateAgentProgress(cardId, {
|
|
6197
6265
|
agentIdentifier,
|
|
6198
6266
|
agentName,
|
|
6199
|
-
status:
|
|
6267
|
+
status: reportedStatus,
|
|
6200
6268
|
progressPercent,
|
|
6201
6269
|
currentTask: args.currentTask,
|
|
6202
6270
|
blockers: args.blockers,
|
|
@@ -6853,21 +6921,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
6853
6921
|
const result = await client3.getPlaybook(playbookId);
|
|
6854
6922
|
return { success: true, playbook: result.playbook, runs: result.runs };
|
|
6855
6923
|
}
|
|
6856
|
-
case "harmony_run_playbook":
|
|
6857
|
-
|
|
6858
|
-
const result = await client3.runPlaybook(playbookId);
|
|
6859
|
-
return { success: true, run: result.run };
|
|
6860
|
-
}
|
|
6924
|
+
case "harmony_run_playbook":
|
|
6925
|
+
return deprecatedRemovedToolResult("harmony_run_playbook");
|
|
6861
6926
|
case "harmony_create_playbook": {
|
|
6862
6927
|
const workspaceId = args.workspaceId || getWorkspaceId();
|
|
6863
6928
|
const name2 = z.string().min(1).max(200).parse(args.name);
|
|
6864
|
-
const stepsVersion = args.stepsVersion !== undefined ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion) : undefined;
|
|
6865
6929
|
const result = await client3.createPlaybook({
|
|
6866
6930
|
workspaceId,
|
|
6867
6931
|
name: name2,
|
|
6868
6932
|
description: args.description,
|
|
6869
|
-
steps: args.steps
|
|
6870
|
-
stepsVersion
|
|
6933
|
+
steps: args.steps
|
|
6871
6934
|
});
|
|
6872
6935
|
return { success: true, playbook: result.playbook };
|
|
6873
6936
|
}
|
|
@@ -6882,14 +6945,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
6882
6945
|
});
|
|
6883
6946
|
return { success: true, playbook: result.playbook };
|
|
6884
6947
|
}
|
|
6885
|
-
case "harmony_save_card_as_playbook":
|
|
6886
|
-
|
|
6887
|
-
const result = await client3.savePlaybookFromCard({
|
|
6888
|
-
cardId,
|
|
6889
|
-
name: args.name
|
|
6890
|
-
});
|
|
6891
|
-
return { success: true, playbook: result.playbook };
|
|
6892
|
-
}
|
|
6948
|
+
case "harmony_save_card_as_playbook":
|
|
6949
|
+
return deprecatedRemovedToolResult("harmony_save_card_as_playbook");
|
|
6893
6950
|
case "harmony_signup": {
|
|
6894
6951
|
const email = z.string().email().max(254).parse(args.email);
|
|
6895
6952
|
const password = z.string().min(8).max(128).parse(args.password);
|