@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/index.js
CHANGED
|
@@ -1452,6 +1452,8 @@ function serializeCommentThread(comments, options = {}) {
|
|
|
1452
1452
|
const tags = [];
|
|
1453
1453
|
if (c.edited_at)
|
|
1454
1454
|
tags.push("edited");
|
|
1455
|
+
if (c.reply_to_id)
|
|
1456
|
+
tags.push(`reply to ${ref(c.reply_to_id)}`);
|
|
1455
1457
|
if (c.supersedes_id)
|
|
1456
1458
|
tags.push(`supersedes ${ref(c.supersedes_id)}`);
|
|
1457
1459
|
if (c.confirms_id)
|
|
@@ -1786,6 +1788,33 @@ class HarmonyApiClient {
|
|
|
1786
1788
|
const query = params.toString() ? `?${params.toString()}` : "";
|
|
1787
1789
|
return this.request("GET", `/board/${projectId}${query}`);
|
|
1788
1790
|
}
|
|
1791
|
+
async getFullBoard(projectId, options) {
|
|
1792
|
+
const { pageSize = 200, ...boardOpts } = options ?? {};
|
|
1793
|
+
const cards = [];
|
|
1794
|
+
let offset = 0;
|
|
1795
|
+
let last = null;
|
|
1796
|
+
for (;; ) {
|
|
1797
|
+
const page = await this.getBoard(projectId, {
|
|
1798
|
+
...boardOpts,
|
|
1799
|
+
limit: pageSize,
|
|
1800
|
+
offset
|
|
1801
|
+
});
|
|
1802
|
+
last = page;
|
|
1803
|
+
const pageCards = page.cards ?? [];
|
|
1804
|
+
cards.push(...pageCards);
|
|
1805
|
+
const hasMore = page.pagination?.hasMore ?? false;
|
|
1806
|
+
if (!hasMore || pageCards.length === 0)
|
|
1807
|
+
break;
|
|
1808
|
+
offset += pageSize;
|
|
1809
|
+
}
|
|
1810
|
+
return {
|
|
1811
|
+
project: last?.project,
|
|
1812
|
+
columns: last?.columns ?? [],
|
|
1813
|
+
cards,
|
|
1814
|
+
labels: last?.labels ?? [],
|
|
1815
|
+
totalCards: last?.pagination?.totalCards ?? cards.length
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1789
1818
|
async createCard(projectId, data) {
|
|
1790
1819
|
return this.request("POST", "/cards", { projectId, ...data });
|
|
1791
1820
|
}
|
|
@@ -1863,6 +1892,12 @@ class HarmonyApiClient {
|
|
|
1863
1892
|
async getCardExternalLinks(cardId) {
|
|
1864
1893
|
return this.request("GET", `/cards/${cardId}/external-links`);
|
|
1865
1894
|
}
|
|
1895
|
+
async addExternalLink(cardId, url, title) {
|
|
1896
|
+
return this.request("POST", `/cards/${cardId}/external-links`, {
|
|
1897
|
+
url,
|
|
1898
|
+
title
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1866
1901
|
async uploadArtifact(data) {
|
|
1867
1902
|
return this.request("POST", "/artifacts", data);
|
|
1868
1903
|
}
|
|
@@ -1914,6 +1949,7 @@ class HarmonyApiClient {
|
|
|
1914
1949
|
commentType: opts?.commentType,
|
|
1915
1950
|
supersedesId: opts?.supersedesId,
|
|
1916
1951
|
confirmsId: opts?.confirmsId,
|
|
1952
|
+
replyToId: opts?.replyToId,
|
|
1917
1953
|
agentSessionId: opts?.agentSessionId
|
|
1918
1954
|
});
|
|
1919
1955
|
}
|
|
@@ -2366,12 +2402,6 @@ ${planContent.trim()}`;
|
|
|
2366
2402
|
async updatePlaybook(playbookId, updates) {
|
|
2367
2403
|
return this.request("PATCH", `/playbooks/${playbookId}`, updates);
|
|
2368
2404
|
}
|
|
2369
|
-
async runPlaybook(playbookId) {
|
|
2370
|
-
return this.request("POST", `/playbooks/${playbookId}/run`);
|
|
2371
|
-
}
|
|
2372
|
-
async savePlaybookFromCard(data) {
|
|
2373
|
-
return this.request("POST", "/playbooks/from-card", data);
|
|
2374
|
-
}
|
|
2375
2405
|
}
|
|
2376
2406
|
var _promptModules = null;
|
|
2377
2407
|
async function loadPromptModules() {
|
|
@@ -2452,7 +2482,7 @@ function initAutoSession(callback, getClient2, getClientInfo, scopeId = DEFAULT_
|
|
|
2452
2482
|
scope.clientGetter = getClient2;
|
|
2453
2483
|
scope.clientInfoGetter = getClientInfo ?? null;
|
|
2454
2484
|
if (!inactivityTimer) {
|
|
2455
|
-
inactivityTimer = setInterval(
|
|
2485
|
+
inactivityTimer = setInterval(sweepTick, CHECK_INTERVAL_MS);
|
|
2456
2486
|
}
|
|
2457
2487
|
}
|
|
2458
2488
|
async function trackActivity(cardId, options) {
|
|
@@ -2494,7 +2524,8 @@ async function trackActivity(cardId, options) {
|
|
|
2494
2524
|
lastActivityAt: now,
|
|
2495
2525
|
isExplicit: false,
|
|
2496
2526
|
agentIdentifier,
|
|
2497
|
-
agentName
|
|
2527
|
+
agentName,
|
|
2528
|
+
status: "working"
|
|
2498
2529
|
});
|
|
2499
2530
|
}
|
|
2500
2531
|
function markExplicit(cardId, options) {
|
|
@@ -2513,7 +2544,8 @@ function markExplicit(cardId, options) {
|
|
|
2513
2544
|
lastActivityAt: Date.now(),
|
|
2514
2545
|
isExplicit: true,
|
|
2515
2546
|
agentIdentifier: options?.agentIdentifier ?? "explicit",
|
|
2516
|
-
agentName: options?.agentName ?? "Explicit Agent"
|
|
2547
|
+
agentName: options?.agentName ?? "Explicit Agent",
|
|
2548
|
+
status: "working"
|
|
2517
2549
|
});
|
|
2518
2550
|
}
|
|
2519
2551
|
}
|
|
@@ -2559,6 +2591,31 @@ function checkInactivity() {
|
|
|
2559
2591
|
}
|
|
2560
2592
|
}
|
|
2561
2593
|
}
|
|
2594
|
+
function noteSessionStatus(cardId, status, scopeId = DEFAULT_SCOPE) {
|
|
2595
|
+
const session = scopes.get(scopeId)?.sessions.get(cardId);
|
|
2596
|
+
if (session)
|
|
2597
|
+
session.status = status;
|
|
2598
|
+
}
|
|
2599
|
+
function heartbeatActiveSessions() {
|
|
2600
|
+
for (const scope of scopes.values()) {
|
|
2601
|
+
const client3 = scope.clientGetter?.();
|
|
2602
|
+
if (!client3)
|
|
2603
|
+
continue;
|
|
2604
|
+
for (const session of scope.sessions.values()) {
|
|
2605
|
+
if ((session.status ?? "working") !== "working")
|
|
2606
|
+
continue;
|
|
2607
|
+
client3.updateAgentProgress(session.cardId, {
|
|
2608
|
+
agentIdentifier: session.agentIdentifier,
|
|
2609
|
+
agentName: session.agentName,
|
|
2610
|
+
status: "working"
|
|
2611
|
+
}).catch(() => {});
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
function sweepTick() {
|
|
2616
|
+
checkInactivity();
|
|
2617
|
+
heartbeatActiveSessions();
|
|
2618
|
+
}
|
|
2562
2619
|
async function autoEndSession(scope, client3, cardId, status) {
|
|
2563
2620
|
if (!scope.sessions.delete(cardId))
|
|
2564
2621
|
return;
|
|
@@ -3235,7 +3292,7 @@ Start work on a Harmony card. Card reference: $ARGUMENTS
|
|
|
3235
3292
|
## 1. Find & Fetch Card
|
|
3236
3293
|
|
|
3237
3294
|
Parse the reference and fetch the card:
|
|
3238
|
-
- \`#42\` or \`42\` → \`
|
|
3295
|
+
- \`#42\` or \`42\` → \`harmony_get_card\` with \`shortId: 42\`
|
|
3239
3296
|
- UUID → \`harmony_get_card\` with \`cardId\`
|
|
3240
3297
|
- Name/text → \`harmony_search_cards\` with \`query\`
|
|
3241
3298
|
|
|
@@ -3289,7 +3346,7 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
|
3289
3346
|
|
|
3290
3347
|
## Key Tools Reference
|
|
3291
3348
|
|
|
3292
|
-
**Cards:** \`harmony_get_card\`, \`
|
|
3349
|
+
**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\`
|
|
3293
3350
|
|
|
3294
3351
|
**Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
|
|
3295
3352
|
|
|
@@ -3483,6 +3540,37 @@ function requireExactlyOneScope(scope) {
|
|
|
3483
3540
|
throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
|
|
3484
3541
|
}
|
|
3485
3542
|
}
|
|
3543
|
+
var DEPRECATED_TOOL_ALIASES = {
|
|
3544
|
+
harmony_get_card_by_short_id: "harmony_get_card",
|
|
3545
|
+
harmony_bulk_get_cards: "harmony_get_card",
|
|
3546
|
+
harmony_upload_artifact: "harmony_upload",
|
|
3547
|
+
harmony_upload_card_attachment: "harmony_upload",
|
|
3548
|
+
harmony_request_artifact_upload_url: "harmony_request_upload_url",
|
|
3549
|
+
harmony_request_card_attachment_upload_url: "harmony_request_upload_url",
|
|
3550
|
+
harmony_finalize_artifact: "harmony_finalize_upload",
|
|
3551
|
+
harmony_finalize_card_attachment: "harmony_finalize_upload"
|
|
3552
|
+
};
|
|
3553
|
+
var _warnedDeprecatedTools = new Set;
|
|
3554
|
+
function warnDeprecatedTool(oldName) {
|
|
3555
|
+
if (_warnedDeprecatedTools.has(oldName))
|
|
3556
|
+
return;
|
|
3557
|
+
_warnedDeprecatedTools.add(oldName);
|
|
3558
|
+
const replacement = DEPRECATED_TOOL_ALIASES[oldName];
|
|
3559
|
+
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.`);
|
|
3560
|
+
}
|
|
3561
|
+
var DEPRECATED_REMOVED_TOOLS = {
|
|
3562
|
+
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.",
|
|
3563
|
+
harmony_save_card_as_playbook: "The steps_version=1 automation macro was removed. Build a stage playbook with harmony_create_playbook instead."
|
|
3564
|
+
};
|
|
3565
|
+
var _warnedRemovedTools = new Set;
|
|
3566
|
+
function deprecatedRemovedToolResult(name) {
|
|
3567
|
+
const message = DEPRECATED_REMOVED_TOOLS[name];
|
|
3568
|
+
if (!_warnedRemovedTools.has(name)) {
|
|
3569
|
+
_warnedRemovedTools.add(name);
|
|
3570
|
+
console.error(`[harmony-mcp] Tool "${name}" is deprecated and no longer functional — ${message}`);
|
|
3571
|
+
}
|
|
3572
|
+
return { success: false, deprecated: true, message };
|
|
3573
|
+
}
|
|
3486
3574
|
var SIGNED_UPLOAD_TIMEOUT_MS = 30000;
|
|
3487
3575
|
async function putToSignedUrl(uploadUrl, bytes, contentType) {
|
|
3488
3576
|
let res;
|
|
@@ -3810,44 +3898,29 @@ var TOOLS = {
|
|
|
3810
3898
|
}
|
|
3811
3899
|
},
|
|
3812
3900
|
harmony_get_card: {
|
|
3813
|
-
description: "
|
|
3814
|
-
inputSchema: {
|
|
3815
|
-
type: "object",
|
|
3816
|
-
properties: {
|
|
3817
|
-
cardId: { type: "string", description: "Card UUID" }
|
|
3818
|
-
},
|
|
3819
|
-
required: ["cardId"]
|
|
3820
|
-
}
|
|
3821
|
-
},
|
|
3822
|
-
harmony_get_card_by_short_id: {
|
|
3823
|
-
description: "Get a card by its short ID (e.g., #42) within a project",
|
|
3901
|
+
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.",
|
|
3824
3902
|
inputSchema: {
|
|
3825
3903
|
type: "object",
|
|
3826
3904
|
properties: {
|
|
3827
|
-
|
|
3905
|
+
cardId: {
|
|
3828
3906
|
type: "string",
|
|
3829
|
-
description: "
|
|
3907
|
+
description: "Card UUID — full detail for one card."
|
|
3830
3908
|
},
|
|
3831
3909
|
shortId: {
|
|
3832
3910
|
type: "number",
|
|
3833
|
-
description: "Short ID
|
|
3834
|
-
}
|
|
3835
|
-
},
|
|
3836
|
-
required: ["shortId"]
|
|
3837
|
-
}
|
|
3838
|
-
},
|
|
3839
|
-
harmony_bulk_get_cards: {
|
|
3840
|
-
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.",
|
|
3841
|
-
inputSchema: {
|
|
3842
|
-
type: "object",
|
|
3843
|
-
properties: {
|
|
3911
|
+
description: "Short ID (e.g. 42 for card #42) — full detail, project-scoped."
|
|
3912
|
+
},
|
|
3844
3913
|
shortIds: {
|
|
3845
3914
|
type: "array",
|
|
3846
3915
|
items: { type: "number" },
|
|
3847
|
-
description: "
|
|
3916
|
+
description: "Short IDs, e.g. [400, 401, 402] — compact summaries in one call. Max 100."
|
|
3917
|
+
},
|
|
3918
|
+
projectId: {
|
|
3919
|
+
type: "string",
|
|
3920
|
+
description: "Project ID for shortId/shortIds (optional if context set)."
|
|
3848
3921
|
}
|
|
3849
3922
|
},
|
|
3850
|
-
required: [
|
|
3923
|
+
required: []
|
|
3851
3924
|
}
|
|
3852
3925
|
},
|
|
3853
3926
|
harmony_bulk_archive_cards: {
|
|
@@ -4002,174 +4075,144 @@ var TOOLS = {
|
|
|
4002
4075
|
required: ["cardId"]
|
|
4003
4076
|
}
|
|
4004
4077
|
},
|
|
4005
|
-
|
|
4006
|
-
description:
|
|
4078
|
+
harmony_upload: {
|
|
4079
|
+
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.",
|
|
4007
4080
|
inputSchema: {
|
|
4008
4081
|
type: "object",
|
|
4009
4082
|
properties: {
|
|
4010
|
-
|
|
4083
|
+
target: {
|
|
4084
|
+
type: "string",
|
|
4085
|
+
enum: ["card_attachment", "artifact"],
|
|
4086
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4087
|
+
},
|
|
4088
|
+
cardId: {
|
|
4089
|
+
type: "string",
|
|
4090
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4091
|
+
},
|
|
4092
|
+
planId: {
|
|
4093
|
+
type: "string",
|
|
4094
|
+
description: "Plan UUID (artifact only — link the artifact to a plan)."
|
|
4095
|
+
},
|
|
4096
|
+
workspaceId: {
|
|
4097
|
+
type: "string",
|
|
4098
|
+
description: "Workspace UUID (artifact only — standalone artifact)."
|
|
4099
|
+
},
|
|
4011
4100
|
filePath: {
|
|
4012
4101
|
type: "string",
|
|
4013
|
-
description: "Absolute path to a local file the
|
|
4102
|
+
description: "Absolute path to a local file the server can read. Mutually exclusive with base64Data."
|
|
4014
4103
|
},
|
|
4015
4104
|
base64Data: {
|
|
4016
4105
|
type: "string",
|
|
4017
|
-
description: "Base64-encoded
|
|
4106
|
+
description: "Base64-encoded bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
|
|
4018
4107
|
},
|
|
4019
4108
|
fileName: {
|
|
4020
4109
|
type: "string",
|
|
4021
|
-
description: "File name including extension (
|
|
4110
|
+
description: "File name including extension (card_attachment: required with base64Data, else defaults to the filePath basename)."
|
|
4111
|
+
},
|
|
4112
|
+
title: {
|
|
4113
|
+
type: "string",
|
|
4114
|
+
description: "Artifact display title (defaults to the file basename)."
|
|
4022
4115
|
},
|
|
4023
4116
|
contentType: {
|
|
4024
4117
|
type: "string",
|
|
4025
|
-
description: "Optional MIME type (
|
|
4118
|
+
description: "Optional MIME type (card_attachment; inferred from the extension when omitted)."
|
|
4026
4119
|
}
|
|
4027
4120
|
},
|
|
4028
|
-
required: ["
|
|
4121
|
+
required: ["target"]
|
|
4029
4122
|
}
|
|
4030
4123
|
},
|
|
4031
|
-
|
|
4032
|
-
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
|
|
4124
|
+
harmony_request_upload_url: {
|
|
4125
|
+
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.",
|
|
4033
4126
|
inputSchema: {
|
|
4034
4127
|
type: "object",
|
|
4035
4128
|
properties: {
|
|
4036
|
-
|
|
4037
|
-
fileName: {
|
|
4129
|
+
target: {
|
|
4038
4130
|
type: "string",
|
|
4039
|
-
|
|
4131
|
+
enum: ["card_attachment", "artifact"],
|
|
4132
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4040
4133
|
},
|
|
4041
|
-
|
|
4134
|
+
cardId: {
|
|
4042
4135
|
type: "string",
|
|
4043
|
-
description: "
|
|
4136
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4044
4137
|
},
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
description: "File size in bytes (rejected early if over 5MB)."
|
|
4048
|
-
}
|
|
4049
|
-
},
|
|
4050
|
-
required: ["cardId", "fileName", "size"]
|
|
4051
|
-
}
|
|
4052
|
-
},
|
|
4053
|
-
harmony_finalize_card_attachment: {
|
|
4054
|
-
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.",
|
|
4055
|
-
inputSchema: {
|
|
4056
|
-
type: "object",
|
|
4057
|
-
properties: {
|
|
4058
|
-
cardId: { type: "string", description: "Card UUID" },
|
|
4059
|
-
storagePath: {
|
|
4138
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4139
|
+
workspaceId: {
|
|
4060
4140
|
type: "string",
|
|
4061
|
-
description: "
|
|
4141
|
+
description: "Workspace UUID (artifact only)."
|
|
4062
4142
|
},
|
|
4063
4143
|
fileName: {
|
|
4064
4144
|
type: "string",
|
|
4065
|
-
description: "File name including extension (
|
|
4145
|
+
description: "File name including extension (required for card_attachment)."
|
|
4066
4146
|
},
|
|
4147
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4067
4148
|
fileType: {
|
|
4068
4149
|
type: "string",
|
|
4069
|
-
description: "
|
|
4150
|
+
description: "card_attachment MIME type (inferred from the extension when omitted)."
|
|
4070
4151
|
},
|
|
4071
|
-
|
|
4152
|
+
contentType: {
|
|
4072
4153
|
type: "string",
|
|
4073
|
-
description: "
|
|
4154
|
+
description: "artifact MIME type; only 'text/html' is accepted (the default)."
|
|
4074
4155
|
},
|
|
4075
4156
|
size: {
|
|
4076
4157
|
type: "number",
|
|
4077
|
-
description: "
|
|
4158
|
+
description: "File size in bytes (rejected early if over the target's limit)."
|
|
4078
4159
|
}
|
|
4079
4160
|
},
|
|
4080
|
-
required: ["
|
|
4081
|
-
}
|
|
4082
|
-
},
|
|
4083
|
-
harmony_classify_card: {
|
|
4084
|
-
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`.",
|
|
4085
|
-
inputSchema: {
|
|
4086
|
-
type: "object",
|
|
4087
|
-
properties: {
|
|
4088
|
-
cardId: { type: "string", description: "Card UUID" }
|
|
4089
|
-
},
|
|
4090
|
-
required: ["cardId"]
|
|
4161
|
+
required: ["target"]
|
|
4091
4162
|
}
|
|
4092
4163
|
},
|
|
4093
|
-
|
|
4094
|
-
description: "
|
|
4164
|
+
harmony_finalize_upload: {
|
|
4165
|
+
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.",
|
|
4095
4166
|
inputSchema: {
|
|
4096
4167
|
type: "object",
|
|
4097
4168
|
properties: {
|
|
4098
|
-
|
|
4169
|
+
target: {
|
|
4099
4170
|
type: "string",
|
|
4100
|
-
|
|
4171
|
+
enum: ["card_attachment", "artifact"],
|
|
4172
|
+
description: "What to finalize: a card file attachment or a hosted HTML artifact."
|
|
4101
4173
|
},
|
|
4102
|
-
|
|
4103
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4104
|
-
workspaceId: {
|
|
4174
|
+
storagePath: {
|
|
4105
4175
|
type: "string",
|
|
4106
|
-
description: "
|
|
4176
|
+
description: "The storagePath returned by harmony_request_upload_url."
|
|
4107
4177
|
},
|
|
4108
|
-
|
|
4178
|
+
cardId: {
|
|
4109
4179
|
type: "string",
|
|
4110
|
-
description: "
|
|
4180
|
+
description: "Card UUID. Required for card_attachment; scope for artifact."
|
|
4111
4181
|
},
|
|
4112
|
-
|
|
4182
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4183
|
+
workspaceId: {
|
|
4113
4184
|
type: "string",
|
|
4114
|
-
description: "
|
|
4115
|
-
}
|
|
4116
|
-
|
|
4117
|
-
required: []
|
|
4118
|
-
}
|
|
4119
|
-
},
|
|
4120
|
-
harmony_request_artifact_upload_url: {
|
|
4121
|
-
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.",
|
|
4122
|
-
inputSchema: {
|
|
4123
|
-
type: "object",
|
|
4124
|
-
properties: {
|
|
4125
|
-
title: {
|
|
4185
|
+
description: "Workspace UUID (artifact only)."
|
|
4186
|
+
},
|
|
4187
|
+
fileName: {
|
|
4126
4188
|
type: "string",
|
|
4127
|
-
description: "
|
|
4189
|
+
description: "File name including extension (required for card_attachment)."
|
|
4128
4190
|
},
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
workspaceId: {
|
|
4191
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4192
|
+
fileType: {
|
|
4132
4193
|
type: "string",
|
|
4133
|
-
description: "
|
|
4194
|
+
description: "card_attachment MIME type; inferred from the extension when omitted."
|
|
4134
4195
|
},
|
|
4135
|
-
|
|
4196
|
+
sha256: {
|
|
4136
4197
|
type: "string",
|
|
4137
|
-
description: "
|
|
4198
|
+
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4138
4199
|
},
|
|
4139
4200
|
size: {
|
|
4140
4201
|
type: "number",
|
|
4141
|
-
description: "
|
|
4202
|
+
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4142
4203
|
}
|
|
4143
4204
|
},
|
|
4144
|
-
required: []
|
|
4205
|
+
required: ["target", "storagePath"]
|
|
4145
4206
|
}
|
|
4146
4207
|
},
|
|
4147
|
-
|
|
4148
|
-
description: "
|
|
4208
|
+
harmony_classify_card: {
|
|
4209
|
+
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`.",
|
|
4149
4210
|
inputSchema: {
|
|
4150
4211
|
type: "object",
|
|
4151
4212
|
properties: {
|
|
4152
|
-
|
|
4153
|
-
type: "string",
|
|
4154
|
-
description: "The storagePath returned by harmony_request_artifact_upload_url."
|
|
4155
|
-
},
|
|
4156
|
-
title: { type: "string", description: "Display title." },
|
|
4157
|
-
cardId: { type: "string", description: "Link to this card (UUID)." },
|
|
4158
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4159
|
-
workspaceId: {
|
|
4160
|
-
type: "string",
|
|
4161
|
-
description: "Attach to this workspace as a standalone artifact (UUID)."
|
|
4162
|
-
},
|
|
4163
|
-
sha256: {
|
|
4164
|
-
type: "string",
|
|
4165
|
-
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4166
|
-
},
|
|
4167
|
-
size: {
|
|
4168
|
-
type: "number",
|
|
4169
|
-
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4170
|
-
}
|
|
4213
|
+
cardId: { type: "string", description: "Card UUID" }
|
|
4171
4214
|
},
|
|
4172
|
-
required: ["
|
|
4215
|
+
required: ["cardId"]
|
|
4173
4216
|
}
|
|
4174
4217
|
},
|
|
4175
4218
|
harmony_share_artifact: {
|
|
@@ -4199,6 +4242,27 @@ var TOOLS = {
|
|
|
4199
4242
|
required: ["cardId"]
|
|
4200
4243
|
}
|
|
4201
4244
|
},
|
|
4245
|
+
harmony_add_external_link: {
|
|
4246
|
+
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.",
|
|
4247
|
+
inputSchema: {
|
|
4248
|
+
type: "object",
|
|
4249
|
+
properties: {
|
|
4250
|
+
cardId: {
|
|
4251
|
+
type: "string",
|
|
4252
|
+
description: "Card UUID"
|
|
4253
|
+
},
|
|
4254
|
+
url: {
|
|
4255
|
+
type: "string",
|
|
4256
|
+
description: "The URL to attach"
|
|
4257
|
+
},
|
|
4258
|
+
title: {
|
|
4259
|
+
type: "string",
|
|
4260
|
+
description: "Optional human-readable title for the link"
|
|
4261
|
+
}
|
|
4262
|
+
},
|
|
4263
|
+
required: ["cardId", "url"]
|
|
4264
|
+
}
|
|
4265
|
+
},
|
|
4202
4266
|
harmony_create_subtask: {
|
|
4203
4267
|
description: "Create a subtask on a card",
|
|
4204
4268
|
inputSchema: {
|
|
@@ -4250,7 +4314,7 @@ var TOOLS = {
|
|
|
4250
4314
|
}
|
|
4251
4315
|
},
|
|
4252
4316
|
harmony_add_comment: {
|
|
4253
|
-
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.",
|
|
4317
|
+
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.",
|
|
4254
4318
|
inputSchema: {
|
|
4255
4319
|
type: "object",
|
|
4256
4320
|
properties: {
|
|
@@ -4276,6 +4340,10 @@ var TOOLS = {
|
|
|
4276
4340
|
confirmsId: {
|
|
4277
4341
|
type: "string",
|
|
4278
4342
|
description: "Comment id this comment reaffirms"
|
|
4343
|
+
},
|
|
4344
|
+
replyToId: {
|
|
4345
|
+
type: "string",
|
|
4346
|
+
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."
|
|
4279
4347
|
}
|
|
4280
4348
|
},
|
|
4281
4349
|
required: ["cardId", "body"]
|
|
@@ -5146,7 +5214,7 @@ var TOOLS = {
|
|
|
5146
5214
|
}
|
|
5147
5215
|
},
|
|
5148
5216
|
harmony_list_playbook: {
|
|
5149
|
-
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version,
|
|
5217
|
+
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, and state. Read-only.",
|
|
5150
5218
|
inputSchema: {
|
|
5151
5219
|
type: "object",
|
|
5152
5220
|
properties: {
|
|
@@ -5168,21 +5236,8 @@ var TOOLS = {
|
|
|
5168
5236
|
required: ["playbookId"]
|
|
5169
5237
|
}
|
|
5170
5238
|
},
|
|
5171
|
-
harmony_run_playbook: {
|
|
5172
|
-
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.",
|
|
5173
|
-
inputSchema: {
|
|
5174
|
-
type: "object",
|
|
5175
|
-
properties: {
|
|
5176
|
-
playbookId: {
|
|
5177
|
-
type: "string",
|
|
5178
|
-
description: "Playbook ID to run (UUID)"
|
|
5179
|
-
}
|
|
5180
|
-
},
|
|
5181
|
-
required: ["playbookId"]
|
|
5182
|
-
}
|
|
5183
|
-
},
|
|
5184
5239
|
harmony_create_playbook: {
|
|
5185
|
-
description: "Create a new playbook in a workspace.
|
|
5240
|
+
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.",
|
|
5186
5241
|
inputSchema: {
|
|
5187
5242
|
type: "object",
|
|
5188
5243
|
properties: {
|
|
@@ -5192,14 +5247,9 @@ var TOOLS = {
|
|
|
5192
5247
|
},
|
|
5193
5248
|
name: { type: "string", description: "Playbook name" },
|
|
5194
5249
|
description: { type: "string", description: "Playbook description" },
|
|
5195
|
-
stepsVersion: {
|
|
5196
|
-
type: "number",
|
|
5197
|
-
enum: [1, 2],
|
|
5198
|
-
description: "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1."
|
|
5199
|
-
},
|
|
5200
5250
|
steps: {
|
|
5201
5251
|
type: "array",
|
|
5202
|
-
description: "
|
|
5252
|
+
description: "The playbook's ordered stage objects.",
|
|
5203
5253
|
items: { type: "object" }
|
|
5204
5254
|
}
|
|
5205
5255
|
},
|
|
@@ -5219,7 +5269,7 @@ var TOOLS = {
|
|
|
5219
5269
|
description: { type: "string", description: "New description" },
|
|
5220
5270
|
steps: {
|
|
5221
5271
|
type: "array",
|
|
5222
|
-
description: "New
|
|
5272
|
+
description: "New ordered stage objects.",
|
|
5223
5273
|
items: { type: "object" }
|
|
5224
5274
|
},
|
|
5225
5275
|
enabled: {
|
|
@@ -5235,20 +5285,6 @@ var TOOLS = {
|
|
|
5235
5285
|
required: ["playbookId"]
|
|
5236
5286
|
}
|
|
5237
5287
|
},
|
|
5238
|
-
harmony_save_card_as_playbook: {
|
|
5239
|
-
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.",
|
|
5240
|
-
inputSchema: {
|
|
5241
|
-
type: "object",
|
|
5242
|
-
properties: {
|
|
5243
|
-
cardId: { type: "string", description: "Card ID to template (UUID)" },
|
|
5244
|
-
name: {
|
|
5245
|
-
type: "string",
|
|
5246
|
-
description: "Name for the new playbook (defaults to the card title)"
|
|
5247
|
-
}
|
|
5248
|
-
},
|
|
5249
|
-
required: ["cardId"]
|
|
5250
|
-
}
|
|
5251
|
-
},
|
|
5252
5288
|
harmony_signup: {
|
|
5253
5289
|
description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
|
|
5254
5290
|
inputSchema: {
|
|
@@ -5648,23 +5684,33 @@ async function handleToolCall(name, args, deps) {
|
|
|
5648
5684
|
});
|
|
5649
5685
|
return { success: true, ...result, count: result.cards.length };
|
|
5650
5686
|
}
|
|
5687
|
+
case "harmony_get_card_by_short_id":
|
|
5688
|
+
case "harmony_bulk_get_cards":
|
|
5651
5689
|
case "harmony_get_card": {
|
|
5690
|
+
if (name !== "harmony_get_card")
|
|
5691
|
+
warnDeprecatedTool(name);
|
|
5692
|
+
const hasShortIds = args.shortIds != null;
|
|
5693
|
+
const hasShortId = args.shortId != null;
|
|
5694
|
+
const hasCardId = args.cardId != null;
|
|
5695
|
+
if ([hasShortIds, hasShortId, hasCardId].filter(Boolean).length !== 1) {
|
|
5696
|
+
throw new Error("Provide exactly one of: cardId (UUID), shortId (number), or shortIds (number[]).");
|
|
5697
|
+
}
|
|
5698
|
+
if (hasShortIds) {
|
|
5699
|
+
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5700
|
+
const projectId = getProjectId();
|
|
5701
|
+
const result2 = await client3.bulkGetCards(projectId, shortIds);
|
|
5702
|
+
return { success: true, ...result2 };
|
|
5703
|
+
}
|
|
5704
|
+
if (hasShortId) {
|
|
5705
|
+
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5706
|
+
const projectId = args.projectId || getProjectId();
|
|
5707
|
+
const result2 = await client3.getCardByShortId(projectId, shortId);
|
|
5708
|
+
return { success: true, ...result2 };
|
|
5709
|
+
}
|
|
5652
5710
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5653
5711
|
const result = await client3.getCard(cardId);
|
|
5654
5712
|
return { success: true, ...result };
|
|
5655
5713
|
}
|
|
5656
|
-
case "harmony_get_card_by_short_id": {
|
|
5657
|
-
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5658
|
-
const projectId = args.projectId || getProjectId();
|
|
5659
|
-
const result = await client3.getCardByShortId(projectId, shortId);
|
|
5660
|
-
return { success: true, ...result };
|
|
5661
|
-
}
|
|
5662
|
-
case "harmony_bulk_get_cards": {
|
|
5663
|
-
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5664
|
-
const projectId = getProjectId();
|
|
5665
|
-
const result = await client3.bulkGetCards(projectId, shortIds);
|
|
5666
|
-
return { success: true, ...result };
|
|
5667
|
-
}
|
|
5668
5714
|
case "harmony_bulk_archive_cards": {
|
|
5669
5715
|
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5670
5716
|
const projectId = getProjectId();
|
|
@@ -5764,58 +5810,58 @@ async function handleToolCall(name, args, deps) {
|
|
|
5764
5810
|
const result = await client3.getCardAttachments(cardId);
|
|
5765
5811
|
return result;
|
|
5766
5812
|
}
|
|
5767
|
-
case "harmony_upload_card_attachment":
|
|
5768
|
-
|
|
5813
|
+
case "harmony_upload_card_attachment":
|
|
5814
|
+
case "harmony_upload_artifact":
|
|
5815
|
+
case "harmony_upload": {
|
|
5816
|
+
if (name !== "harmony_upload")
|
|
5817
|
+
warnDeprecatedTool(name);
|
|
5818
|
+
const target = name === "harmony_upload_card_attachment" ? "card_attachment" : name === "harmony_upload_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5769
5819
|
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5770
5820
|
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5771
|
-
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5772
|
-
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5773
5821
|
if (filePath && base64Data) {
|
|
5774
5822
|
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5775
5823
|
}
|
|
5776
|
-
if (
|
|
5777
|
-
const
|
|
5778
|
-
const
|
|
5779
|
-
const
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5824
|
+
if (target === "card_attachment") {
|
|
5825
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5826
|
+
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5827
|
+
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5828
|
+
if (filePath) {
|
|
5829
|
+
const bytes = await readFileForUpload(filePath, MAX_ATTACHMENT_SIZE, "attachment");
|
|
5830
|
+
const resolvedName = fileName || basename(filePath);
|
|
5831
|
+
const signed = await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5832
|
+
fileName: resolvedName,
|
|
5833
|
+
fileType: contentType,
|
|
5834
|
+
size: bytes.byteLength
|
|
5835
|
+
});
|
|
5836
|
+
await putToSignedUrl(signed.uploadUrl, bytes, contentType || signed.fileType || "application/octet-stream");
|
|
5837
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5838
|
+
storagePath: signed.storagePath,
|
|
5839
|
+
fileName: resolvedName,
|
|
5840
|
+
fileType: contentType || signed.fileType,
|
|
5841
|
+
sha256: sha256Hex(bytes),
|
|
5842
|
+
size: bytes.byteLength
|
|
5843
|
+
});
|
|
5796
5844
|
}
|
|
5797
|
-
if (
|
|
5798
|
-
|
|
5845
|
+
if (base64Data) {
|
|
5846
|
+
if (!fileName) {
|
|
5847
|
+
throw new Error("fileName is required when using base64Data.");
|
|
5848
|
+
}
|
|
5849
|
+
if (base64ByteLength(base64Data) > MAX_ATTACHMENT_SIZE) {
|
|
5850
|
+
throw new Error(`File is over the 5MB attachment limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5851
|
+
}
|
|
5852
|
+
return await client3.uploadCardAttachment(cardId2, {
|
|
5853
|
+
fileName,
|
|
5854
|
+
data: base64Data,
|
|
5855
|
+
fileType: contentType
|
|
5856
|
+
});
|
|
5799
5857
|
}
|
|
5800
|
-
|
|
5801
|
-
fileName,
|
|
5802
|
-
data: base64Data,
|
|
5803
|
-
fileType: contentType
|
|
5804
|
-
});
|
|
5858
|
+
throw new Error("Provide either filePath or base64Data.");
|
|
5805
5859
|
}
|
|
5806
|
-
throw new Error("Provide either filePath or base64Data.");
|
|
5807
|
-
}
|
|
5808
|
-
case "harmony_upload_artifact": {
|
|
5809
5860
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5810
5861
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5811
5862
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
5812
5863
|
const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
|
|
5813
5864
|
requireExactlyOneScope({ cardId, planId, workspaceId });
|
|
5814
|
-
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5815
|
-
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5816
|
-
if (filePath && base64Data) {
|
|
5817
|
-
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5818
|
-
}
|
|
5819
5865
|
if (filePath) {
|
|
5820
5866
|
const bytes = await readFileForUpload(filePath, MAX_ARTIFACT_SIZE, "artifact");
|
|
5821
5867
|
const resolvedTitle = title || basename(filePath);
|
|
@@ -5840,7 +5886,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
5840
5886
|
}
|
|
5841
5887
|
if (base64Data) {
|
|
5842
5888
|
if (base64ByteLength(base64Data) > MAX_ARTIFACT_SIZE) {
|
|
5843
|
-
throw new Error(`Artifact is over the 2MB limit. Use the
|
|
5889
|
+
throw new Error(`Artifact is over the 2MB limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5844
5890
|
}
|
|
5845
5891
|
return await client3.uploadArtifact({
|
|
5846
5892
|
title,
|
|
@@ -5852,7 +5898,26 @@ async function handleToolCall(name, args, deps) {
|
|
|
5852
5898
|
}
|
|
5853
5899
|
throw new Error("Provide either filePath or base64Data.");
|
|
5854
5900
|
}
|
|
5855
|
-
case "harmony_request_artifact_upload_url":
|
|
5901
|
+
case "harmony_request_artifact_upload_url":
|
|
5902
|
+
case "harmony_request_card_attachment_upload_url":
|
|
5903
|
+
case "harmony_request_upload_url": {
|
|
5904
|
+
if (name !== "harmony_request_upload_url")
|
|
5905
|
+
warnDeprecatedTool(name);
|
|
5906
|
+
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);
|
|
5907
|
+
if (target === "card_attachment") {
|
|
5908
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5909
|
+
const fileName = z.string().parse(args.fileName);
|
|
5910
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5911
|
+
const size2 = z.number().positive().parse(args.size);
|
|
5912
|
+
if (size2 > MAX_ATTACHMENT_SIZE) {
|
|
5913
|
+
throw new Error(`Declared size ${size2} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5914
|
+
}
|
|
5915
|
+
return await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5916
|
+
fileName,
|
|
5917
|
+
fileType,
|
|
5918
|
+
size: size2
|
|
5919
|
+
});
|
|
5920
|
+
}
|
|
5856
5921
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5857
5922
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5858
5923
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5872,8 +5937,27 @@ async function handleToolCall(name, args, deps) {
|
|
|
5872
5937
|
size
|
|
5873
5938
|
});
|
|
5874
5939
|
}
|
|
5875
|
-
case "harmony_finalize_artifact":
|
|
5940
|
+
case "harmony_finalize_artifact":
|
|
5941
|
+
case "harmony_finalize_card_attachment":
|
|
5942
|
+
case "harmony_finalize_upload": {
|
|
5943
|
+
if (name !== "harmony_finalize_upload")
|
|
5944
|
+
warnDeprecatedTool(name);
|
|
5945
|
+
const target = name === "harmony_finalize_card_attachment" ? "card_attachment" : name === "harmony_finalize_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5876
5946
|
const storagePath = z.string().parse(args.storagePath);
|
|
5947
|
+
if (target === "card_attachment") {
|
|
5948
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5949
|
+
const fileName = z.string().parse(args.fileName);
|
|
5950
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5951
|
+
const sha2562 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5952
|
+
const size2 = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5953
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5954
|
+
storagePath,
|
|
5955
|
+
fileName,
|
|
5956
|
+
fileType,
|
|
5957
|
+
sha256: sha2562,
|
|
5958
|
+
size: size2
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5877
5961
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5878
5962
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5879
5963
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5891,35 +5975,6 @@ async function handleToolCall(name, args, deps) {
|
|
|
5891
5975
|
workspaceId
|
|
5892
5976
|
});
|
|
5893
5977
|
}
|
|
5894
|
-
case "harmony_request_card_attachment_upload_url": {
|
|
5895
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5896
|
-
const fileName = z.string().parse(args.fileName);
|
|
5897
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5898
|
-
const size = z.number().positive().parse(args.size);
|
|
5899
|
-
if (size > MAX_ATTACHMENT_SIZE) {
|
|
5900
|
-
throw new Error(`Declared size ${size} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5901
|
-
}
|
|
5902
|
-
return await client3.requestCardAttachmentUploadUrl(cardId, {
|
|
5903
|
-
fileName,
|
|
5904
|
-
fileType,
|
|
5905
|
-
size
|
|
5906
|
-
});
|
|
5907
|
-
}
|
|
5908
|
-
case "harmony_finalize_card_attachment": {
|
|
5909
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5910
|
-
const storagePath = z.string().parse(args.storagePath);
|
|
5911
|
-
const fileName = z.string().parse(args.fileName);
|
|
5912
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5913
|
-
const sha256 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5914
|
-
const size = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5915
|
-
return await client3.finalizeCardAttachment(cardId, {
|
|
5916
|
-
storagePath,
|
|
5917
|
-
fileName,
|
|
5918
|
-
fileType,
|
|
5919
|
-
sha256,
|
|
5920
|
-
size
|
|
5921
|
-
});
|
|
5922
|
-
}
|
|
5923
5978
|
case "harmony_share_artifact": {
|
|
5924
5979
|
const artifactId = z.string().uuid().parse(args.artifactId);
|
|
5925
5980
|
const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
|
|
@@ -5932,6 +5987,13 @@ async function handleToolCall(name, args, deps) {
|
|
|
5932
5987
|
const result = await client3.getCardExternalLinks(cardId);
|
|
5933
5988
|
return result;
|
|
5934
5989
|
}
|
|
5990
|
+
case "harmony_add_external_link": {
|
|
5991
|
+
const cardId = z.string().uuid().parse(args.cardId);
|
|
5992
|
+
const url = z.string().min(1).max(2048).parse(args.url);
|
|
5993
|
+
const title = args.title ? z.string().max(200).parse(args.title) : undefined;
|
|
5994
|
+
const result = await client3.addExternalLink(cardId, url, title);
|
|
5995
|
+
return { success: true, ...result };
|
|
5996
|
+
}
|
|
5935
5997
|
case "harmony_classify_card": {
|
|
5936
5998
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5937
5999
|
const result = await client3.classifyCard(cardId);
|
|
@@ -5985,10 +6047,12 @@ async function handleToolCall(name, args, deps) {
|
|
|
5985
6047
|
]).parse(args.commentType) : undefined;
|
|
5986
6048
|
const supersedesId = args.supersedesId !== undefined ? z.string().uuid().parse(args.supersedesId) : undefined;
|
|
5987
6049
|
const confirmsId = args.confirmsId !== undefined ? z.string().uuid().parse(args.confirmsId) : undefined;
|
|
6050
|
+
const replyToId = args.replyToId !== undefined ? z.string().uuid().parse(args.replyToId) : undefined;
|
|
5988
6051
|
const result = await client3.addComment(cardId, body, {
|
|
5989
6052
|
commentType,
|
|
5990
6053
|
supersedesId,
|
|
5991
|
-
confirmsId
|
|
6054
|
+
confirmsId,
|
|
6055
|
+
replyToId
|
|
5992
6056
|
});
|
|
5993
6057
|
return { success: true, ...result };
|
|
5994
6058
|
}
|
|
@@ -6188,10 +6252,14 @@ async function handleToolCall(name, args, deps) {
|
|
|
6188
6252
|
mergedRecentActions = callerRecentActions;
|
|
6189
6253
|
}
|
|
6190
6254
|
const runActivity = (callerActions || []).map((a) => a.description).filter((d) => typeof d === "string" && d.length > 0);
|
|
6255
|
+
const reportedStatus = args.status;
|
|
6256
|
+
if (reportedStatus) {
|
|
6257
|
+
noteSessionStatus(cardId, reportedStatus, deps.getScopeId?.());
|
|
6258
|
+
}
|
|
6191
6259
|
const result = await client3.updateAgentProgress(cardId, {
|
|
6192
6260
|
agentIdentifier,
|
|
6193
6261
|
agentName,
|
|
6194
|
-
status:
|
|
6262
|
+
status: reportedStatus,
|
|
6195
6263
|
progressPercent,
|
|
6196
6264
|
currentTask: args.currentTask,
|
|
6197
6265
|
blockers: args.blockers,
|
|
@@ -6848,21 +6916,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
6848
6916
|
const result = await client3.getPlaybook(playbookId);
|
|
6849
6917
|
return { success: true, playbook: result.playbook, runs: result.runs };
|
|
6850
6918
|
}
|
|
6851
|
-
case "harmony_run_playbook":
|
|
6852
|
-
|
|
6853
|
-
const result = await client3.runPlaybook(playbookId);
|
|
6854
|
-
return { success: true, run: result.run };
|
|
6855
|
-
}
|
|
6919
|
+
case "harmony_run_playbook":
|
|
6920
|
+
return deprecatedRemovedToolResult("harmony_run_playbook");
|
|
6856
6921
|
case "harmony_create_playbook": {
|
|
6857
6922
|
const workspaceId = args.workspaceId || getWorkspaceId();
|
|
6858
6923
|
const name2 = z.string().min(1).max(200).parse(args.name);
|
|
6859
|
-
const stepsVersion = args.stepsVersion !== undefined ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion) : undefined;
|
|
6860
6924
|
const result = await client3.createPlaybook({
|
|
6861
6925
|
workspaceId,
|
|
6862
6926
|
name: name2,
|
|
6863
6927
|
description: args.description,
|
|
6864
|
-
steps: args.steps
|
|
6865
|
-
stepsVersion
|
|
6928
|
+
steps: args.steps
|
|
6866
6929
|
});
|
|
6867
6930
|
return { success: true, playbook: result.playbook };
|
|
6868
6931
|
}
|
|
@@ -6877,14 +6940,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
6877
6940
|
});
|
|
6878
6941
|
return { success: true, playbook: result.playbook };
|
|
6879
6942
|
}
|
|
6880
|
-
case "harmony_save_card_as_playbook":
|
|
6881
|
-
|
|
6882
|
-
const result = await client3.savePlaybookFromCard({
|
|
6883
|
-
cardId,
|
|
6884
|
-
name: args.name
|
|
6885
|
-
});
|
|
6886
|
-
return { success: true, playbook: result.playbook };
|
|
6887
|
-
}
|
|
6943
|
+
case "harmony_save_card_as_playbook":
|
|
6944
|
+
return deprecatedRemovedToolResult("harmony_save_card_as_playbook");
|
|
6888
6945
|
case "harmony_signup": {
|
|
6889
6946
|
const email = z.string().email().max(254).parse(args.email);
|
|
6890
6947
|
const password = z.string().min(8).max(128).parse(args.password);
|