@gethmy/mcp 2.13.3 → 2.14.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 +273 -274
- package/dist/index.js +273 -274
- package/dist/lib/api-client.js +143 -140
- package/dist/lib/oauth-refresh.js +350 -0
- package/package.json +6 -2
- package/src/api-client.ts +13 -12
- package/src/server.ts +389 -322
- 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)
|
|
@@ -1863,6 +1865,12 @@ class HarmonyApiClient {
|
|
|
1863
1865
|
async getCardExternalLinks(cardId) {
|
|
1864
1866
|
return this.request("GET", `/cards/${cardId}/external-links`);
|
|
1865
1867
|
}
|
|
1868
|
+
async addExternalLink(cardId, url, title) {
|
|
1869
|
+
return this.request("POST", `/cards/${cardId}/external-links`, {
|
|
1870
|
+
url,
|
|
1871
|
+
title
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1866
1874
|
async uploadArtifact(data) {
|
|
1867
1875
|
return this.request("POST", "/artifacts", data);
|
|
1868
1876
|
}
|
|
@@ -1914,6 +1922,7 @@ class HarmonyApiClient {
|
|
|
1914
1922
|
commentType: opts?.commentType,
|
|
1915
1923
|
supersedesId: opts?.supersedesId,
|
|
1916
1924
|
confirmsId: opts?.confirmsId,
|
|
1925
|
+
replyToId: opts?.replyToId,
|
|
1917
1926
|
agentSessionId: opts?.agentSessionId
|
|
1918
1927
|
});
|
|
1919
1928
|
}
|
|
@@ -2366,12 +2375,6 @@ ${planContent.trim()}`;
|
|
|
2366
2375
|
async updatePlaybook(playbookId, updates) {
|
|
2367
2376
|
return this.request("PATCH", `/playbooks/${playbookId}`, updates);
|
|
2368
2377
|
}
|
|
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
2378
|
}
|
|
2376
2379
|
var _promptModules = null;
|
|
2377
2380
|
async function loadPromptModules() {
|
|
@@ -3235,7 +3238,7 @@ Start work on a Harmony card. Card reference: $ARGUMENTS
|
|
|
3235
3238
|
## 1. Find & Fetch Card
|
|
3236
3239
|
|
|
3237
3240
|
Parse the reference and fetch the card:
|
|
3238
|
-
- \`#42\` or \`42\` → \`
|
|
3241
|
+
- \`#42\` or \`42\` → \`harmony_get_card\` with \`shortId: 42\`
|
|
3239
3242
|
- UUID → \`harmony_get_card\` with \`cardId\`
|
|
3240
3243
|
- Name/text → \`harmony_search_cards\` with \`query\`
|
|
3241
3244
|
|
|
@@ -3289,7 +3292,7 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
|
3289
3292
|
|
|
3290
3293
|
## Key Tools Reference
|
|
3291
3294
|
|
|
3292
|
-
**Cards:** \`harmony_get_card\`, \`
|
|
3295
|
+
**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
3296
|
|
|
3294
3297
|
**Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
|
|
3295
3298
|
|
|
@@ -3483,6 +3486,37 @@ function requireExactlyOneScope(scope) {
|
|
|
3483
3486
|
throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
|
|
3484
3487
|
}
|
|
3485
3488
|
}
|
|
3489
|
+
var DEPRECATED_TOOL_ALIASES = {
|
|
3490
|
+
harmony_get_card_by_short_id: "harmony_get_card",
|
|
3491
|
+
harmony_bulk_get_cards: "harmony_get_card",
|
|
3492
|
+
harmony_upload_artifact: "harmony_upload",
|
|
3493
|
+
harmony_upload_card_attachment: "harmony_upload",
|
|
3494
|
+
harmony_request_artifact_upload_url: "harmony_request_upload_url",
|
|
3495
|
+
harmony_request_card_attachment_upload_url: "harmony_request_upload_url",
|
|
3496
|
+
harmony_finalize_artifact: "harmony_finalize_upload",
|
|
3497
|
+
harmony_finalize_card_attachment: "harmony_finalize_upload"
|
|
3498
|
+
};
|
|
3499
|
+
var _warnedDeprecatedTools = new Set;
|
|
3500
|
+
function warnDeprecatedTool(oldName) {
|
|
3501
|
+
if (_warnedDeprecatedTools.has(oldName))
|
|
3502
|
+
return;
|
|
3503
|
+
_warnedDeprecatedTools.add(oldName);
|
|
3504
|
+
const replacement = DEPRECATED_TOOL_ALIASES[oldName];
|
|
3505
|
+
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.`);
|
|
3506
|
+
}
|
|
3507
|
+
var DEPRECATED_REMOVED_TOOLS = {
|
|
3508
|
+
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.",
|
|
3509
|
+
harmony_save_card_as_playbook: "The steps_version=1 automation macro was removed. Build a stage playbook with harmony_create_playbook instead."
|
|
3510
|
+
};
|
|
3511
|
+
var _warnedRemovedTools = new Set;
|
|
3512
|
+
function deprecatedRemovedToolResult(name) {
|
|
3513
|
+
const message = DEPRECATED_REMOVED_TOOLS[name];
|
|
3514
|
+
if (!_warnedRemovedTools.has(name)) {
|
|
3515
|
+
_warnedRemovedTools.add(name);
|
|
3516
|
+
console.error(`[harmony-mcp] Tool "${name}" is deprecated and no longer functional — ${message}`);
|
|
3517
|
+
}
|
|
3518
|
+
return { success: false, deprecated: true, message };
|
|
3519
|
+
}
|
|
3486
3520
|
var SIGNED_UPLOAD_TIMEOUT_MS = 30000;
|
|
3487
3521
|
async function putToSignedUrl(uploadUrl, bytes, contentType) {
|
|
3488
3522
|
let res;
|
|
@@ -3810,44 +3844,29 @@ var TOOLS = {
|
|
|
3810
3844
|
}
|
|
3811
3845
|
},
|
|
3812
3846
|
harmony_get_card: {
|
|
3813
|
-
description: "
|
|
3847
|
+
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.",
|
|
3814
3848
|
inputSchema: {
|
|
3815
3849
|
type: "object",
|
|
3816
3850
|
properties: {
|
|
3817
|
-
cardId: {
|
|
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",
|
|
3824
|
-
inputSchema: {
|
|
3825
|
-
type: "object",
|
|
3826
|
-
properties: {
|
|
3827
|
-
projectId: {
|
|
3851
|
+
cardId: {
|
|
3828
3852
|
type: "string",
|
|
3829
|
-
description: "
|
|
3853
|
+
description: "Card UUID — full detail for one card."
|
|
3830
3854
|
},
|
|
3831
3855
|
shortId: {
|
|
3832
3856
|
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: {
|
|
3857
|
+
description: "Short ID (e.g. 42 for card #42) — full detail, project-scoped."
|
|
3858
|
+
},
|
|
3844
3859
|
shortIds: {
|
|
3845
3860
|
type: "array",
|
|
3846
3861
|
items: { type: "number" },
|
|
3847
|
-
description: "
|
|
3862
|
+
description: "Short IDs, e.g. [400, 401, 402] — compact summaries in one call. Max 100."
|
|
3863
|
+
},
|
|
3864
|
+
projectId: {
|
|
3865
|
+
type: "string",
|
|
3866
|
+
description: "Project ID for shortId/shortIds (optional if context set)."
|
|
3848
3867
|
}
|
|
3849
3868
|
},
|
|
3850
|
-
required: [
|
|
3869
|
+
required: []
|
|
3851
3870
|
}
|
|
3852
3871
|
},
|
|
3853
3872
|
harmony_bulk_archive_cards: {
|
|
@@ -4002,174 +4021,144 @@ var TOOLS = {
|
|
|
4002
4021
|
required: ["cardId"]
|
|
4003
4022
|
}
|
|
4004
4023
|
},
|
|
4005
|
-
|
|
4006
|
-
description:
|
|
4024
|
+
harmony_upload: {
|
|
4025
|
+
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
4026
|
inputSchema: {
|
|
4008
4027
|
type: "object",
|
|
4009
4028
|
properties: {
|
|
4010
|
-
|
|
4029
|
+
target: {
|
|
4030
|
+
type: "string",
|
|
4031
|
+
enum: ["card_attachment", "artifact"],
|
|
4032
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4033
|
+
},
|
|
4034
|
+
cardId: {
|
|
4035
|
+
type: "string",
|
|
4036
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4037
|
+
},
|
|
4038
|
+
planId: {
|
|
4039
|
+
type: "string",
|
|
4040
|
+
description: "Plan UUID (artifact only — link the artifact to a plan)."
|
|
4041
|
+
},
|
|
4042
|
+
workspaceId: {
|
|
4043
|
+
type: "string",
|
|
4044
|
+
description: "Workspace UUID (artifact only — standalone artifact)."
|
|
4045
|
+
},
|
|
4011
4046
|
filePath: {
|
|
4012
4047
|
type: "string",
|
|
4013
|
-
description: "Absolute path to a local file the
|
|
4048
|
+
description: "Absolute path to a local file the server can read. Mutually exclusive with base64Data."
|
|
4014
4049
|
},
|
|
4015
4050
|
base64Data: {
|
|
4016
4051
|
type: "string",
|
|
4017
|
-
description: "Base64-encoded
|
|
4052
|
+
description: "Base64-encoded bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
|
|
4018
4053
|
},
|
|
4019
4054
|
fileName: {
|
|
4020
4055
|
type: "string",
|
|
4021
|
-
description: "File name including extension (
|
|
4056
|
+
description: "File name including extension (card_attachment: required with base64Data, else defaults to the filePath basename)."
|
|
4057
|
+
},
|
|
4058
|
+
title: {
|
|
4059
|
+
type: "string",
|
|
4060
|
+
description: "Artifact display title (defaults to the file basename)."
|
|
4022
4061
|
},
|
|
4023
4062
|
contentType: {
|
|
4024
4063
|
type: "string",
|
|
4025
|
-
description: "Optional MIME type (
|
|
4064
|
+
description: "Optional MIME type (card_attachment; inferred from the extension when omitted)."
|
|
4026
4065
|
}
|
|
4027
4066
|
},
|
|
4028
|
-
required: ["
|
|
4067
|
+
required: ["target"]
|
|
4029
4068
|
}
|
|
4030
4069
|
},
|
|
4031
|
-
|
|
4032
|
-
description: "Step 1 of the
|
|
4070
|
+
harmony_request_upload_url: {
|
|
4071
|
+
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
4072
|
inputSchema: {
|
|
4034
4073
|
type: "object",
|
|
4035
4074
|
properties: {
|
|
4036
|
-
|
|
4037
|
-
fileName: {
|
|
4075
|
+
target: {
|
|
4038
4076
|
type: "string",
|
|
4039
|
-
|
|
4077
|
+
enum: ["card_attachment", "artifact"],
|
|
4078
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4040
4079
|
},
|
|
4041
|
-
|
|
4080
|
+
cardId: {
|
|
4042
4081
|
type: "string",
|
|
4043
|
-
description: "
|
|
4082
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4044
4083
|
},
|
|
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 agent-driven card-attachment upload. After PUTting the bytes to the signed uploadUrl from harmony_request_card_attachment_upload_url, call this with the returned 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), and — when you pass sha256 — an integrity check, deleting the object and failing on any mismatch. Returns the stored attachment with a short-lived signed URL.",
|
|
4055
|
-
inputSchema: {
|
|
4056
|
-
type: "object",
|
|
4057
|
-
properties: {
|
|
4058
|
-
cardId: { type: "string", description: "Card UUID" },
|
|
4059
|
-
storagePath: {
|
|
4084
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4085
|
+
workspaceId: {
|
|
4060
4086
|
type: "string",
|
|
4061
|
-
description: "
|
|
4087
|
+
description: "Workspace UUID (artifact only)."
|
|
4062
4088
|
},
|
|
4063
4089
|
fileName: {
|
|
4064
4090
|
type: "string",
|
|
4065
|
-
description: "File name including extension (
|
|
4091
|
+
description: "File name including extension (required for card_attachment)."
|
|
4066
4092
|
},
|
|
4093
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4067
4094
|
fileType: {
|
|
4068
4095
|
type: "string",
|
|
4069
|
-
description: "
|
|
4096
|
+
description: "card_attachment MIME type (inferred from the extension when omitted)."
|
|
4070
4097
|
},
|
|
4071
|
-
|
|
4098
|
+
contentType: {
|
|
4072
4099
|
type: "string",
|
|
4073
|
-
description: "
|
|
4100
|
+
description: "artifact MIME type; only 'text/html' is accepted (the default)."
|
|
4074
4101
|
},
|
|
4075
4102
|
size: {
|
|
4076
4103
|
type: "number",
|
|
4077
|
-
description: "
|
|
4104
|
+
description: "File size in bytes (rejected early if over the target's limit)."
|
|
4078
4105
|
}
|
|
4079
4106
|
},
|
|
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), and `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the canonical type label (feature/bug/idea). Use this right after creating a card (e.g. in the `hmy-new` flow) so it's classified in-flow instead of waiting for it to surface on the web board. Idempotent — safe to re-run. 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"]
|
|
4107
|
+
required: ["target"]
|
|
4091
4108
|
}
|
|
4092
4109
|
},
|
|
4093
|
-
|
|
4094
|
-
description: "
|
|
4110
|
+
harmony_finalize_upload: {
|
|
4111
|
+
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
4112
|
inputSchema: {
|
|
4096
4113
|
type: "object",
|
|
4097
4114
|
properties: {
|
|
4098
|
-
|
|
4115
|
+
target: {
|
|
4099
4116
|
type: "string",
|
|
4100
|
-
|
|
4117
|
+
enum: ["card_attachment", "artifact"],
|
|
4118
|
+
description: "What to finalize: a card file attachment or a hosted HTML artifact."
|
|
4101
4119
|
},
|
|
4102
|
-
|
|
4103
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4104
|
-
workspaceId: {
|
|
4120
|
+
storagePath: {
|
|
4105
4121
|
type: "string",
|
|
4106
|
-
description: "
|
|
4122
|
+
description: "The storagePath returned by harmony_request_upload_url."
|
|
4107
4123
|
},
|
|
4108
|
-
|
|
4124
|
+
cardId: {
|
|
4109
4125
|
type: "string",
|
|
4110
|
-
description: "
|
|
4126
|
+
description: "Card UUID. Required for card_attachment; scope for artifact."
|
|
4111
4127
|
},
|
|
4112
|
-
|
|
4128
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4129
|
+
workspaceId: {
|
|
4113
4130
|
type: "string",
|
|
4114
|
-
description: "
|
|
4115
|
-
}
|
|
4116
|
-
|
|
4117
|
-
required: []
|
|
4118
|
-
}
|
|
4119
|
-
},
|
|
4120
|
-
harmony_request_artifact_upload_url: {
|
|
4121
|
-
description: "Step 1 of the agent-driven artifact upload — use this for large files or when running against the hosted MCP server (which cannot read your local disk), instead of streaming base64 through the model context. Mints a one-shot signed Supabase Storage upload URL for a server-chosen path. Provide exactly one of cardId/planId/workspaceId, optionally a title and the byte size. Returns { uploadUrl, token, storagePath }. Next: PUT the raw HTML bytes straight to uploadUrl (e.g. `curl -X PUT --data-binary @doc.html '<uploadUrl>'`), then call harmony_finalize_artifact with the returned storagePath. Only text/html, max 2MB.",
|
|
4122
|
-
inputSchema: {
|
|
4123
|
-
type: "object",
|
|
4124
|
-
properties: {
|
|
4125
|
-
title: {
|
|
4131
|
+
description: "Workspace UUID (artifact only)."
|
|
4132
|
+
},
|
|
4133
|
+
fileName: {
|
|
4126
4134
|
type: "string",
|
|
4127
|
-
description: "
|
|
4135
|
+
description: "File name including extension (required for card_attachment)."
|
|
4128
4136
|
},
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
workspaceId: {
|
|
4137
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4138
|
+
fileType: {
|
|
4132
4139
|
type: "string",
|
|
4133
|
-
description: "
|
|
4140
|
+
description: "card_attachment MIME type; inferred from the extension when omitted."
|
|
4134
4141
|
},
|
|
4135
|
-
|
|
4142
|
+
sha256: {
|
|
4136
4143
|
type: "string",
|
|
4137
|
-
description: "
|
|
4144
|
+
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4138
4145
|
},
|
|
4139
4146
|
size: {
|
|
4140
4147
|
type: "number",
|
|
4141
|
-
description: "
|
|
4148
|
+
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4142
4149
|
}
|
|
4143
4150
|
},
|
|
4144
|
-
required: []
|
|
4151
|
+
required: ["target", "storagePath"]
|
|
4145
4152
|
}
|
|
4146
4153
|
},
|
|
4147
|
-
|
|
4148
|
-
description: "
|
|
4154
|
+
harmony_classify_card: {
|
|
4155
|
+
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
4156
|
inputSchema: {
|
|
4150
4157
|
type: "object",
|
|
4151
4158
|
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
|
-
}
|
|
4159
|
+
cardId: { type: "string", description: "Card UUID" }
|
|
4171
4160
|
},
|
|
4172
|
-
required: ["
|
|
4161
|
+
required: ["cardId"]
|
|
4173
4162
|
}
|
|
4174
4163
|
},
|
|
4175
4164
|
harmony_share_artifact: {
|
|
@@ -4199,6 +4188,27 @@ var TOOLS = {
|
|
|
4199
4188
|
required: ["cardId"]
|
|
4200
4189
|
}
|
|
4201
4190
|
},
|
|
4191
|
+
harmony_add_external_link: {
|
|
4192
|
+
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.",
|
|
4193
|
+
inputSchema: {
|
|
4194
|
+
type: "object",
|
|
4195
|
+
properties: {
|
|
4196
|
+
cardId: {
|
|
4197
|
+
type: "string",
|
|
4198
|
+
description: "Card UUID"
|
|
4199
|
+
},
|
|
4200
|
+
url: {
|
|
4201
|
+
type: "string",
|
|
4202
|
+
description: "The URL to attach"
|
|
4203
|
+
},
|
|
4204
|
+
title: {
|
|
4205
|
+
type: "string",
|
|
4206
|
+
description: "Optional human-readable title for the link"
|
|
4207
|
+
}
|
|
4208
|
+
},
|
|
4209
|
+
required: ["cardId", "url"]
|
|
4210
|
+
}
|
|
4211
|
+
},
|
|
4202
4212
|
harmony_create_subtask: {
|
|
4203
4213
|
description: "Create a subtask on a card",
|
|
4204
4214
|
inputSchema: {
|
|
@@ -4250,7 +4260,7 @@ var TOOLS = {
|
|
|
4250
4260
|
}
|
|
4251
4261
|
},
|
|
4252
4262
|
harmony_add_comment: {
|
|
4253
|
-
description: "Post a comment on a card as the agent
|
|
4263
|
+
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
4264
|
inputSchema: {
|
|
4255
4265
|
type: "object",
|
|
4256
4266
|
properties: {
|
|
@@ -4276,6 +4286,10 @@ var TOOLS = {
|
|
|
4276
4286
|
confirmsId: {
|
|
4277
4287
|
type: "string",
|
|
4278
4288
|
description: "Comment id this comment reaffirms"
|
|
4289
|
+
},
|
|
4290
|
+
replyToId: {
|
|
4291
|
+
type: "string",
|
|
4292
|
+
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
4293
|
}
|
|
4280
4294
|
},
|
|
4281
4295
|
required: ["cardId", "body"]
|
|
@@ -4747,7 +4761,7 @@ var TOOLS = {
|
|
|
4747
4761
|
limit: { type: "number", description: "Max results (default: 20)" },
|
|
4748
4762
|
top_k: {
|
|
4749
4763
|
type: "number",
|
|
4750
|
-
description: "After
|
|
4764
|
+
description: "After rescoring (relevance × recency × importance), keep this many top entries. Defaults to `limit`. Over-fetch with a large `limit` then trim to a tight top-k."
|
|
4751
4765
|
},
|
|
4752
4766
|
budget_tokens: {
|
|
4753
4767
|
type: "number",
|
|
@@ -4862,7 +4876,7 @@ var TOOLS = {
|
|
|
4862
4876
|
}
|
|
4863
4877
|
},
|
|
4864
4878
|
harmony_suggest_relations: {
|
|
4865
|
-
description: "Suggest existing memory entities that look related to a given entity, using the same hybrid vector+FTS similarity as recall
|
|
4879
|
+
description: "Suggest existing memory entities that look related to a given entity, using the same hybrid vector+FTS similarity as recall. Read-only: NEVER creates relations — only proposes candidates to relate explicitly via harmony_relate. Surfaces 'these look related — link?' candidates that would activate graph-walk retrieval.",
|
|
4866
4880
|
inputSchema: {
|
|
4867
4881
|
type: "object",
|
|
4868
4882
|
properties: {
|
|
@@ -5146,7 +5160,7 @@ var TOOLS = {
|
|
|
5146
5160
|
}
|
|
5147
5161
|
},
|
|
5148
5162
|
harmony_list_playbook: {
|
|
5149
|
-
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version,
|
|
5163
|
+
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, and state. Read-only.",
|
|
5150
5164
|
inputSchema: {
|
|
5151
5165
|
type: "object",
|
|
5152
5166
|
properties: {
|
|
@@ -5168,21 +5182,8 @@ var TOOLS = {
|
|
|
5168
5182
|
required: ["playbookId"]
|
|
5169
5183
|
}
|
|
5170
5184
|
},
|
|
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
5185
|
harmony_create_playbook: {
|
|
5185
|
-
description: "Create a new playbook in a workspace.
|
|
5186
|
+
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
5187
|
inputSchema: {
|
|
5187
5188
|
type: "object",
|
|
5188
5189
|
properties: {
|
|
@@ -5192,14 +5193,9 @@ var TOOLS = {
|
|
|
5192
5193
|
},
|
|
5193
5194
|
name: { type: "string", description: "Playbook name" },
|
|
5194
5195
|
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
5196
|
steps: {
|
|
5201
5197
|
type: "array",
|
|
5202
|
-
description: "
|
|
5198
|
+
description: "The playbook's ordered stage objects.",
|
|
5203
5199
|
items: { type: "object" }
|
|
5204
5200
|
}
|
|
5205
5201
|
},
|
|
@@ -5219,7 +5215,7 @@ var TOOLS = {
|
|
|
5219
5215
|
description: { type: "string", description: "New description" },
|
|
5220
5216
|
steps: {
|
|
5221
5217
|
type: "array",
|
|
5222
|
-
description: "New
|
|
5218
|
+
description: "New ordered stage objects.",
|
|
5223
5219
|
items: { type: "object" }
|
|
5224
5220
|
},
|
|
5225
5221
|
enabled: {
|
|
@@ -5235,20 +5231,6 @@ var TOOLS = {
|
|
|
5235
5231
|
required: ["playbookId"]
|
|
5236
5232
|
}
|
|
5237
5233
|
},
|
|
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
5234
|
harmony_signup: {
|
|
5253
5235
|
description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
|
|
5254
5236
|
inputSchema: {
|
|
@@ -5648,23 +5630,33 @@ async function handleToolCall(name, args, deps) {
|
|
|
5648
5630
|
});
|
|
5649
5631
|
return { success: true, ...result, count: result.cards.length };
|
|
5650
5632
|
}
|
|
5633
|
+
case "harmony_get_card_by_short_id":
|
|
5634
|
+
case "harmony_bulk_get_cards":
|
|
5651
5635
|
case "harmony_get_card": {
|
|
5636
|
+
if (name !== "harmony_get_card")
|
|
5637
|
+
warnDeprecatedTool(name);
|
|
5638
|
+
const hasShortIds = args.shortIds != null;
|
|
5639
|
+
const hasShortId = args.shortId != null;
|
|
5640
|
+
const hasCardId = args.cardId != null;
|
|
5641
|
+
if ([hasShortIds, hasShortId, hasCardId].filter(Boolean).length !== 1) {
|
|
5642
|
+
throw new Error("Provide exactly one of: cardId (UUID), shortId (number), or shortIds (number[]).");
|
|
5643
|
+
}
|
|
5644
|
+
if (hasShortIds) {
|
|
5645
|
+
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5646
|
+
const projectId = getProjectId();
|
|
5647
|
+
const result2 = await client3.bulkGetCards(projectId, shortIds);
|
|
5648
|
+
return { success: true, ...result2 };
|
|
5649
|
+
}
|
|
5650
|
+
if (hasShortId) {
|
|
5651
|
+
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5652
|
+
const projectId = args.projectId || getProjectId();
|
|
5653
|
+
const result2 = await client3.getCardByShortId(projectId, shortId);
|
|
5654
|
+
return { success: true, ...result2 };
|
|
5655
|
+
}
|
|
5652
5656
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5653
5657
|
const result = await client3.getCard(cardId);
|
|
5654
5658
|
return { success: true, ...result };
|
|
5655
5659
|
}
|
|
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
5660
|
case "harmony_bulk_archive_cards": {
|
|
5669
5661
|
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5670
5662
|
const projectId = getProjectId();
|
|
@@ -5764,58 +5756,58 @@ async function handleToolCall(name, args, deps) {
|
|
|
5764
5756
|
const result = await client3.getCardAttachments(cardId);
|
|
5765
5757
|
return result;
|
|
5766
5758
|
}
|
|
5767
|
-
case "harmony_upload_card_attachment":
|
|
5768
|
-
|
|
5759
|
+
case "harmony_upload_card_attachment":
|
|
5760
|
+
case "harmony_upload_artifact":
|
|
5761
|
+
case "harmony_upload": {
|
|
5762
|
+
if (name !== "harmony_upload")
|
|
5763
|
+
warnDeprecatedTool(name);
|
|
5764
|
+
const target = name === "harmony_upload_card_attachment" ? "card_attachment" : name === "harmony_upload_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5769
5765
|
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5770
5766
|
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
5767
|
if (filePath && base64Data) {
|
|
5774
5768
|
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5775
5769
|
}
|
|
5776
|
-
if (
|
|
5777
|
-
const
|
|
5778
|
-
const
|
|
5779
|
-
const
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5770
|
+
if (target === "card_attachment") {
|
|
5771
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5772
|
+
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5773
|
+
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5774
|
+
if (filePath) {
|
|
5775
|
+
const bytes = await readFileForUpload(filePath, MAX_ATTACHMENT_SIZE, "attachment");
|
|
5776
|
+
const resolvedName = fileName || basename(filePath);
|
|
5777
|
+
const signed = await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5778
|
+
fileName: resolvedName,
|
|
5779
|
+
fileType: contentType,
|
|
5780
|
+
size: bytes.byteLength
|
|
5781
|
+
});
|
|
5782
|
+
await putToSignedUrl(signed.uploadUrl, bytes, contentType || signed.fileType || "application/octet-stream");
|
|
5783
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5784
|
+
storagePath: signed.storagePath,
|
|
5785
|
+
fileName: resolvedName,
|
|
5786
|
+
fileType: contentType || signed.fileType,
|
|
5787
|
+
sha256: sha256Hex(bytes),
|
|
5788
|
+
size: bytes.byteLength
|
|
5789
|
+
});
|
|
5796
5790
|
}
|
|
5797
|
-
if (
|
|
5798
|
-
|
|
5791
|
+
if (base64Data) {
|
|
5792
|
+
if (!fileName) {
|
|
5793
|
+
throw new Error("fileName is required when using base64Data.");
|
|
5794
|
+
}
|
|
5795
|
+
if (base64ByteLength(base64Data) > MAX_ATTACHMENT_SIZE) {
|
|
5796
|
+
throw new Error(`File is over the 5MB attachment limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5797
|
+
}
|
|
5798
|
+
return await client3.uploadCardAttachment(cardId2, {
|
|
5799
|
+
fileName,
|
|
5800
|
+
data: base64Data,
|
|
5801
|
+
fileType: contentType
|
|
5802
|
+
});
|
|
5799
5803
|
}
|
|
5800
|
-
|
|
5801
|
-
fileName,
|
|
5802
|
-
data: base64Data,
|
|
5803
|
-
fileType: contentType
|
|
5804
|
-
});
|
|
5804
|
+
throw new Error("Provide either filePath or base64Data.");
|
|
5805
5805
|
}
|
|
5806
|
-
throw new Error("Provide either filePath or base64Data.");
|
|
5807
|
-
}
|
|
5808
|
-
case "harmony_upload_artifact": {
|
|
5809
5806
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5810
5807
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5811
5808
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
5812
5809
|
const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
|
|
5813
5810
|
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
5811
|
if (filePath) {
|
|
5820
5812
|
const bytes = await readFileForUpload(filePath, MAX_ARTIFACT_SIZE, "artifact");
|
|
5821
5813
|
const resolvedTitle = title || basename(filePath);
|
|
@@ -5840,7 +5832,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
5840
5832
|
}
|
|
5841
5833
|
if (base64Data) {
|
|
5842
5834
|
if (base64ByteLength(base64Data) > MAX_ARTIFACT_SIZE) {
|
|
5843
|
-
throw new Error(`Artifact is over the 2MB limit. Use the
|
|
5835
|
+
throw new Error(`Artifact is over the 2MB limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5844
5836
|
}
|
|
5845
5837
|
return await client3.uploadArtifact({
|
|
5846
5838
|
title,
|
|
@@ -5852,7 +5844,26 @@ async function handleToolCall(name, args, deps) {
|
|
|
5852
5844
|
}
|
|
5853
5845
|
throw new Error("Provide either filePath or base64Data.");
|
|
5854
5846
|
}
|
|
5855
|
-
case "harmony_request_artifact_upload_url":
|
|
5847
|
+
case "harmony_request_artifact_upload_url":
|
|
5848
|
+
case "harmony_request_card_attachment_upload_url":
|
|
5849
|
+
case "harmony_request_upload_url": {
|
|
5850
|
+
if (name !== "harmony_request_upload_url")
|
|
5851
|
+
warnDeprecatedTool(name);
|
|
5852
|
+
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);
|
|
5853
|
+
if (target === "card_attachment") {
|
|
5854
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5855
|
+
const fileName = z.string().parse(args.fileName);
|
|
5856
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5857
|
+
const size2 = z.number().positive().parse(args.size);
|
|
5858
|
+
if (size2 > MAX_ATTACHMENT_SIZE) {
|
|
5859
|
+
throw new Error(`Declared size ${size2} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5860
|
+
}
|
|
5861
|
+
return await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5862
|
+
fileName,
|
|
5863
|
+
fileType,
|
|
5864
|
+
size: size2
|
|
5865
|
+
});
|
|
5866
|
+
}
|
|
5856
5867
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5857
5868
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5858
5869
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5872,8 +5883,27 @@ async function handleToolCall(name, args, deps) {
|
|
|
5872
5883
|
size
|
|
5873
5884
|
});
|
|
5874
5885
|
}
|
|
5875
|
-
case "harmony_finalize_artifact":
|
|
5886
|
+
case "harmony_finalize_artifact":
|
|
5887
|
+
case "harmony_finalize_card_attachment":
|
|
5888
|
+
case "harmony_finalize_upload": {
|
|
5889
|
+
if (name !== "harmony_finalize_upload")
|
|
5890
|
+
warnDeprecatedTool(name);
|
|
5891
|
+
const target = name === "harmony_finalize_card_attachment" ? "card_attachment" : name === "harmony_finalize_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5876
5892
|
const storagePath = z.string().parse(args.storagePath);
|
|
5893
|
+
if (target === "card_attachment") {
|
|
5894
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5895
|
+
const fileName = z.string().parse(args.fileName);
|
|
5896
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5897
|
+
const sha2562 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5898
|
+
const size2 = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5899
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5900
|
+
storagePath,
|
|
5901
|
+
fileName,
|
|
5902
|
+
fileType,
|
|
5903
|
+
sha256: sha2562,
|
|
5904
|
+
size: size2
|
|
5905
|
+
});
|
|
5906
|
+
}
|
|
5877
5907
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5878
5908
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5879
5909
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5891,35 +5921,6 @@ async function handleToolCall(name, args, deps) {
|
|
|
5891
5921
|
workspaceId
|
|
5892
5922
|
});
|
|
5893
5923
|
}
|
|
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
5924
|
case "harmony_share_artifact": {
|
|
5924
5925
|
const artifactId = z.string().uuid().parse(args.artifactId);
|
|
5925
5926
|
const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
|
|
@@ -5932,6 +5933,13 @@ async function handleToolCall(name, args, deps) {
|
|
|
5932
5933
|
const result = await client3.getCardExternalLinks(cardId);
|
|
5933
5934
|
return result;
|
|
5934
5935
|
}
|
|
5936
|
+
case "harmony_add_external_link": {
|
|
5937
|
+
const cardId = z.string().uuid().parse(args.cardId);
|
|
5938
|
+
const url = z.string().min(1).max(2048).parse(args.url);
|
|
5939
|
+
const title = args.title ? z.string().max(200).parse(args.title) : undefined;
|
|
5940
|
+
const result = await client3.addExternalLink(cardId, url, title);
|
|
5941
|
+
return { success: true, ...result };
|
|
5942
|
+
}
|
|
5935
5943
|
case "harmony_classify_card": {
|
|
5936
5944
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5937
5945
|
const result = await client3.classifyCard(cardId);
|
|
@@ -5985,10 +5993,12 @@ async function handleToolCall(name, args, deps) {
|
|
|
5985
5993
|
]).parse(args.commentType) : undefined;
|
|
5986
5994
|
const supersedesId = args.supersedesId !== undefined ? z.string().uuid().parse(args.supersedesId) : undefined;
|
|
5987
5995
|
const confirmsId = args.confirmsId !== undefined ? z.string().uuid().parse(args.confirmsId) : undefined;
|
|
5996
|
+
const replyToId = args.replyToId !== undefined ? z.string().uuid().parse(args.replyToId) : undefined;
|
|
5988
5997
|
const result = await client3.addComment(cardId, body, {
|
|
5989
5998
|
commentType,
|
|
5990
5999
|
supersedesId,
|
|
5991
|
-
confirmsId
|
|
6000
|
+
confirmsId,
|
|
6001
|
+
replyToId
|
|
5992
6002
|
});
|
|
5993
6003
|
return { success: true, ...result };
|
|
5994
6004
|
}
|
|
@@ -6848,21 +6858,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
6848
6858
|
const result = await client3.getPlaybook(playbookId);
|
|
6849
6859
|
return { success: true, playbook: result.playbook, runs: result.runs };
|
|
6850
6860
|
}
|
|
6851
|
-
case "harmony_run_playbook":
|
|
6852
|
-
|
|
6853
|
-
const result = await client3.runPlaybook(playbookId);
|
|
6854
|
-
return { success: true, run: result.run };
|
|
6855
|
-
}
|
|
6861
|
+
case "harmony_run_playbook":
|
|
6862
|
+
return deprecatedRemovedToolResult("harmony_run_playbook");
|
|
6856
6863
|
case "harmony_create_playbook": {
|
|
6857
6864
|
const workspaceId = args.workspaceId || getWorkspaceId();
|
|
6858
6865
|
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
6866
|
const result = await client3.createPlaybook({
|
|
6861
6867
|
workspaceId,
|
|
6862
6868
|
name: name2,
|
|
6863
6869
|
description: args.description,
|
|
6864
|
-
steps: args.steps
|
|
6865
|
-
stepsVersion
|
|
6870
|
+
steps: args.steps
|
|
6866
6871
|
});
|
|
6867
6872
|
return { success: true, playbook: result.playbook };
|
|
6868
6873
|
}
|
|
@@ -6877,14 +6882,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
6877
6882
|
});
|
|
6878
6883
|
return { success: true, playbook: result.playbook };
|
|
6879
6884
|
}
|
|
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
|
-
}
|
|
6885
|
+
case "harmony_save_card_as_playbook":
|
|
6886
|
+
return deprecatedRemovedToolResult("harmony_save_card_as_playbook");
|
|
6888
6887
|
case "harmony_signup": {
|
|
6889
6888
|
const email = z.string().email().max(254).parse(args.email);
|
|
6890
6889
|
const password = z.string().min(8).max(128).parse(args.password);
|