@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/cli.js
CHANGED
|
@@ -1457,6 +1457,8 @@ function serializeCommentThread(comments, options = {}) {
|
|
|
1457
1457
|
const tags = [];
|
|
1458
1458
|
if (c.edited_at)
|
|
1459
1459
|
tags.push("edited");
|
|
1460
|
+
if (c.reply_to_id)
|
|
1461
|
+
tags.push(`reply to ${ref(c.reply_to_id)}`);
|
|
1460
1462
|
if (c.supersedes_id)
|
|
1461
1463
|
tags.push(`supersedes ${ref(c.supersedes_id)}`);
|
|
1462
1464
|
if (c.confirms_id)
|
|
@@ -1868,6 +1870,12 @@ class HarmonyApiClient {
|
|
|
1868
1870
|
async getCardExternalLinks(cardId) {
|
|
1869
1871
|
return this.request("GET", `/cards/${cardId}/external-links`);
|
|
1870
1872
|
}
|
|
1873
|
+
async addExternalLink(cardId, url, title) {
|
|
1874
|
+
return this.request("POST", `/cards/${cardId}/external-links`, {
|
|
1875
|
+
url,
|
|
1876
|
+
title
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1871
1879
|
async uploadArtifact(data) {
|
|
1872
1880
|
return this.request("POST", "/artifacts", data);
|
|
1873
1881
|
}
|
|
@@ -1919,6 +1927,7 @@ class HarmonyApiClient {
|
|
|
1919
1927
|
commentType: opts?.commentType,
|
|
1920
1928
|
supersedesId: opts?.supersedesId,
|
|
1921
1929
|
confirmsId: opts?.confirmsId,
|
|
1930
|
+
replyToId: opts?.replyToId,
|
|
1922
1931
|
agentSessionId: opts?.agentSessionId
|
|
1923
1932
|
});
|
|
1924
1933
|
}
|
|
@@ -2371,12 +2380,6 @@ ${planContent.trim()}`;
|
|
|
2371
2380
|
async updatePlaybook(playbookId, updates) {
|
|
2372
2381
|
return this.request("PATCH", `/playbooks/${playbookId}`, updates);
|
|
2373
2382
|
}
|
|
2374
|
-
async runPlaybook(playbookId) {
|
|
2375
|
-
return this.request("POST", `/playbooks/${playbookId}/run`);
|
|
2376
|
-
}
|
|
2377
|
-
async savePlaybookFromCard(data) {
|
|
2378
|
-
return this.request("POST", "/playbooks/from-card", data);
|
|
2379
|
-
}
|
|
2380
2383
|
}
|
|
2381
2384
|
var _promptModules = null;
|
|
2382
2385
|
async function loadPromptModules() {
|
|
@@ -3240,7 +3243,7 @@ Start work on a Harmony card. Card reference: $ARGUMENTS
|
|
|
3240
3243
|
## 1. Find & Fetch Card
|
|
3241
3244
|
|
|
3242
3245
|
Parse the reference and fetch the card:
|
|
3243
|
-
- \`#42\` or \`42\` → \`
|
|
3246
|
+
- \`#42\` or \`42\` → \`harmony_get_card\` with \`shortId: 42\`
|
|
3244
3247
|
- UUID → \`harmony_get_card\` with \`cardId\`
|
|
3245
3248
|
- Name/text → \`harmony_search_cards\` with \`query\`
|
|
3246
3249
|
|
|
@@ -3294,7 +3297,7 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
|
3294
3297
|
|
|
3295
3298
|
## Key Tools Reference
|
|
3296
3299
|
|
|
3297
|
-
**Cards:** \`harmony_get_card\`, \`
|
|
3300
|
+
**Cards:** \`harmony_get_card\` (by \`cardId\`, \`shortId\`, or \`shortIds\`), \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
|
|
3298
3301
|
|
|
3299
3302
|
**Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
|
|
3300
3303
|
|
|
@@ -3488,6 +3491,37 @@ function requireExactlyOneScope(scope) {
|
|
|
3488
3491
|
throw new Error("Provide exactly one of cardId, planId, or workspaceId.");
|
|
3489
3492
|
}
|
|
3490
3493
|
}
|
|
3494
|
+
var DEPRECATED_TOOL_ALIASES = {
|
|
3495
|
+
harmony_get_card_by_short_id: "harmony_get_card",
|
|
3496
|
+
harmony_bulk_get_cards: "harmony_get_card",
|
|
3497
|
+
harmony_upload_artifact: "harmony_upload",
|
|
3498
|
+
harmony_upload_card_attachment: "harmony_upload",
|
|
3499
|
+
harmony_request_artifact_upload_url: "harmony_request_upload_url",
|
|
3500
|
+
harmony_request_card_attachment_upload_url: "harmony_request_upload_url",
|
|
3501
|
+
harmony_finalize_artifact: "harmony_finalize_upload",
|
|
3502
|
+
harmony_finalize_card_attachment: "harmony_finalize_upload"
|
|
3503
|
+
};
|
|
3504
|
+
var _warnedDeprecatedTools = new Set;
|
|
3505
|
+
function warnDeprecatedTool(oldName) {
|
|
3506
|
+
if (_warnedDeprecatedTools.has(oldName))
|
|
3507
|
+
return;
|
|
3508
|
+
_warnedDeprecatedTools.add(oldName);
|
|
3509
|
+
const replacement = DEPRECATED_TOOL_ALIASES[oldName];
|
|
3510
|
+
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.`);
|
|
3511
|
+
}
|
|
3512
|
+
var DEPRECATED_REMOVED_TOOLS = {
|
|
3513
|
+
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.",
|
|
3514
|
+
harmony_save_card_as_playbook: "The steps_version=1 automation macro was removed. Build a stage playbook with harmony_create_playbook instead."
|
|
3515
|
+
};
|
|
3516
|
+
var _warnedRemovedTools = new Set;
|
|
3517
|
+
function deprecatedRemovedToolResult(name) {
|
|
3518
|
+
const message = DEPRECATED_REMOVED_TOOLS[name];
|
|
3519
|
+
if (!_warnedRemovedTools.has(name)) {
|
|
3520
|
+
_warnedRemovedTools.add(name);
|
|
3521
|
+
console.error(`[harmony-mcp] Tool "${name}" is deprecated and no longer functional — ${message}`);
|
|
3522
|
+
}
|
|
3523
|
+
return { success: false, deprecated: true, message };
|
|
3524
|
+
}
|
|
3491
3525
|
var SIGNED_UPLOAD_TIMEOUT_MS = 30000;
|
|
3492
3526
|
async function putToSignedUrl(uploadUrl, bytes, contentType) {
|
|
3493
3527
|
let res;
|
|
@@ -3815,44 +3849,29 @@ var TOOLS = {
|
|
|
3815
3849
|
}
|
|
3816
3850
|
},
|
|
3817
3851
|
harmony_get_card: {
|
|
3818
|
-
description: "
|
|
3819
|
-
inputSchema: {
|
|
3820
|
-
type: "object",
|
|
3821
|
-
properties: {
|
|
3822
|
-
cardId: { type: "string", description: "Card UUID" }
|
|
3823
|
-
},
|
|
3824
|
-
required: ["cardId"]
|
|
3825
|
-
}
|
|
3826
|
-
},
|
|
3827
|
-
harmony_get_card_by_short_id: {
|
|
3828
|
-
description: "Get a card by its short ID (e.g., #42) within a project",
|
|
3852
|
+
description: "Fetch one or many cards. Provide exactly one of: `cardId` (UUID, full detail), " + "`shortId` (e.g. 42, full detail), or `shortIds` (array, max 100 — compact " + "summaries: id, shortId, title, column, priority, assignee, labels, archived, " + "plus any short ids not found). `shortId`/`shortIds` need project context. " + "Prefer one `shortIds` call over repeated single fetches for multiple cards.",
|
|
3829
3853
|
inputSchema: {
|
|
3830
3854
|
type: "object",
|
|
3831
3855
|
properties: {
|
|
3832
|
-
|
|
3856
|
+
cardId: {
|
|
3833
3857
|
type: "string",
|
|
3834
|
-
description: "
|
|
3858
|
+
description: "Card UUID — full detail for one card."
|
|
3835
3859
|
},
|
|
3836
3860
|
shortId: {
|
|
3837
3861
|
type: "number",
|
|
3838
|
-
description: "Short ID
|
|
3839
|
-
}
|
|
3840
|
-
},
|
|
3841
|
-
required: ["shortId"]
|
|
3842
|
-
}
|
|
3843
|
-
},
|
|
3844
|
-
harmony_bulk_get_cards: {
|
|
3845
|
-
description: "Fetch multiple cards by short id in one call. Returns compact summaries " + "(id, shortId, title, column, priority, assignee, labels, archived) plus " + "any short ids not found. Requires project context. Prefer this over " + "repeated harmony_get_card_by_short_id when referencing multiple cards.",
|
|
3846
|
-
inputSchema: {
|
|
3847
|
-
type: "object",
|
|
3848
|
-
properties: {
|
|
3862
|
+
description: "Short ID (e.g. 42 for card #42) — full detail, project-scoped."
|
|
3863
|
+
},
|
|
3849
3864
|
shortIds: {
|
|
3850
3865
|
type: "array",
|
|
3851
3866
|
items: { type: "number" },
|
|
3852
|
-
description: "
|
|
3867
|
+
description: "Short IDs, e.g. [400, 401, 402] — compact summaries in one call. Max 100."
|
|
3868
|
+
},
|
|
3869
|
+
projectId: {
|
|
3870
|
+
type: "string",
|
|
3871
|
+
description: "Project ID for shortId/shortIds (optional if context set)."
|
|
3853
3872
|
}
|
|
3854
3873
|
},
|
|
3855
|
-
required: [
|
|
3874
|
+
required: []
|
|
3856
3875
|
}
|
|
3857
3876
|
},
|
|
3858
3877
|
harmony_bulk_archive_cards: {
|
|
@@ -4007,174 +4026,144 @@ var TOOLS = {
|
|
|
4007
4026
|
required: ["cardId"]
|
|
4008
4027
|
}
|
|
4009
4028
|
},
|
|
4010
|
-
|
|
4011
|
-
description:
|
|
4029
|
+
harmony_upload: {
|
|
4030
|
+
description: 'Upload a file in one call. `target: "card_attachment"` attaches a file to a card ' + "(max 5MB; PNG/JPEG/GIF/WebP/HEIC/HEIF/PDF/DOC(X)/XLS(X)/TXT/CSV) — requires cardId. " + '`target: "artifact"` hosts a self-contained HTML doc (text/html, max 2MB) linked to ' + "exactly one of cardId/planId/workspaceId, rendered in-app in a sandboxed iframe. Provide " + "the bytes as `filePath` (local, direct-to-storage) or `base64Data` (small-file fallback). " + "Returns the attachment/artifact + a signed URL (artifact: use harmony_share_artifact for a " + "public link). Large files on the hosted MCP server: use harmony_request_upload_url + " + "harmony_finalize_upload instead.",
|
|
4012
4031
|
inputSchema: {
|
|
4013
4032
|
type: "object",
|
|
4014
4033
|
properties: {
|
|
4015
|
-
|
|
4034
|
+
target: {
|
|
4035
|
+
type: "string",
|
|
4036
|
+
enum: ["card_attachment", "artifact"],
|
|
4037
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4038
|
+
},
|
|
4039
|
+
cardId: {
|
|
4040
|
+
type: "string",
|
|
4041
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4042
|
+
},
|
|
4043
|
+
planId: {
|
|
4044
|
+
type: "string",
|
|
4045
|
+
description: "Plan UUID (artifact only — link the artifact to a plan)."
|
|
4046
|
+
},
|
|
4047
|
+
workspaceId: {
|
|
4048
|
+
type: "string",
|
|
4049
|
+
description: "Workspace UUID (artifact only — standalone artifact)."
|
|
4050
|
+
},
|
|
4016
4051
|
filePath: {
|
|
4017
4052
|
type: "string",
|
|
4018
|
-
description: "Absolute path to a local file the
|
|
4053
|
+
description: "Absolute path to a local file the server can read. Mutually exclusive with base64Data."
|
|
4019
4054
|
},
|
|
4020
4055
|
base64Data: {
|
|
4021
4056
|
type: "string",
|
|
4022
|
-
description: "Base64-encoded
|
|
4057
|
+
description: "Base64-encoded bytes (a `data:` URL prefix is accepted and stripped). Mutually exclusive with filePath."
|
|
4023
4058
|
},
|
|
4024
4059
|
fileName: {
|
|
4025
4060
|
type: "string",
|
|
4026
|
-
description: "File name including extension (
|
|
4061
|
+
description: "File name including extension (card_attachment: required with base64Data, else defaults to the filePath basename)."
|
|
4062
|
+
},
|
|
4063
|
+
title: {
|
|
4064
|
+
type: "string",
|
|
4065
|
+
description: "Artifact display title (defaults to the file basename)."
|
|
4027
4066
|
},
|
|
4028
4067
|
contentType: {
|
|
4029
4068
|
type: "string",
|
|
4030
|
-
description: "Optional MIME type (
|
|
4069
|
+
description: "Optional MIME type (card_attachment; inferred from the extension when omitted)."
|
|
4031
4070
|
}
|
|
4032
4071
|
},
|
|
4033
|
-
required: ["
|
|
4072
|
+
required: ["target"]
|
|
4034
4073
|
}
|
|
4035
4074
|
},
|
|
4036
|
-
|
|
4037
|
-
description: "Step 1 of the
|
|
4075
|
+
harmony_request_upload_url: {
|
|
4076
|
+
description: "Step 1 of the large-file / hosted-MCP upload handshake (use when the server can't read " + 'local disk). Mints a one-shot signed Storage upload URL. `target: "card_attachment"` ' + '(requires cardId, fileName, size; max 5MB) or `target: "artifact"` (one of ' + "cardId/planId/workspaceId; text/html, max 2MB). Returns { uploadUrl, token, storagePath, " + "[fileType] }. Then PUT the raw bytes to uploadUrl (no bytes through the model context) and " + "call harmony_finalize_upload with the storagePath.",
|
|
4038
4077
|
inputSchema: {
|
|
4039
4078
|
type: "object",
|
|
4040
4079
|
properties: {
|
|
4041
|
-
|
|
4042
|
-
fileName: {
|
|
4080
|
+
target: {
|
|
4043
4081
|
type: "string",
|
|
4044
|
-
|
|
4082
|
+
enum: ["card_attachment", "artifact"],
|
|
4083
|
+
description: "What to upload: a card file attachment or a hosted HTML artifact."
|
|
4045
4084
|
},
|
|
4046
|
-
|
|
4085
|
+
cardId: {
|
|
4047
4086
|
type: "string",
|
|
4048
|
-
description: "
|
|
4087
|
+
description: "Card UUID. Required for card_attachment; one of cardId/planId/workspaceId for artifact."
|
|
4049
4088
|
},
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
description: "File size in bytes (rejected early if over 5MB)."
|
|
4053
|
-
}
|
|
4054
|
-
},
|
|
4055
|
-
required: ["cardId", "fileName", "size"]
|
|
4056
|
-
}
|
|
4057
|
-
},
|
|
4058
|
-
harmony_finalize_card_attachment: {
|
|
4059
|
-
description: "Step 2 of the 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.",
|
|
4060
|
-
inputSchema: {
|
|
4061
|
-
type: "object",
|
|
4062
|
-
properties: {
|
|
4063
|
-
cardId: { type: "string", description: "Card UUID" },
|
|
4064
|
-
storagePath: {
|
|
4089
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4090
|
+
workspaceId: {
|
|
4065
4091
|
type: "string",
|
|
4066
|
-
description: "
|
|
4092
|
+
description: "Workspace UUID (artifact only)."
|
|
4067
4093
|
},
|
|
4068
4094
|
fileName: {
|
|
4069
4095
|
type: "string",
|
|
4070
|
-
description: "File name including extension (
|
|
4096
|
+
description: "File name including extension (required for card_attachment)."
|
|
4071
4097
|
},
|
|
4098
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4072
4099
|
fileType: {
|
|
4073
4100
|
type: "string",
|
|
4074
|
-
description: "
|
|
4101
|
+
description: "card_attachment MIME type (inferred from the extension when omitted)."
|
|
4075
4102
|
},
|
|
4076
|
-
|
|
4103
|
+
contentType: {
|
|
4077
4104
|
type: "string",
|
|
4078
|
-
description: "
|
|
4105
|
+
description: "artifact MIME type; only 'text/html' is accepted (the default)."
|
|
4079
4106
|
},
|
|
4080
4107
|
size: {
|
|
4081
4108
|
type: "number",
|
|
4082
|
-
description: "
|
|
4109
|
+
description: "File size in bytes (rejected early if over the target's limit)."
|
|
4083
4110
|
}
|
|
4084
4111
|
},
|
|
4085
|
-
required: ["
|
|
4086
|
-
}
|
|
4087
|
-
},
|
|
4088
|
-
harmony_classify_card: {
|
|
4089
|
-
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`.",
|
|
4090
|
-
inputSchema: {
|
|
4091
|
-
type: "object",
|
|
4092
|
-
properties: {
|
|
4093
|
-
cardId: { type: "string", description: "Card UUID" }
|
|
4094
|
-
},
|
|
4095
|
-
required: ["cardId"]
|
|
4112
|
+
required: ["target"]
|
|
4096
4113
|
}
|
|
4097
4114
|
},
|
|
4098
|
-
|
|
4099
|
-
description: "
|
|
4115
|
+
harmony_finalize_upload: {
|
|
4116
|
+
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.",
|
|
4100
4117
|
inputSchema: {
|
|
4101
4118
|
type: "object",
|
|
4102
4119
|
properties: {
|
|
4103
|
-
|
|
4120
|
+
target: {
|
|
4104
4121
|
type: "string",
|
|
4105
|
-
|
|
4122
|
+
enum: ["card_attachment", "artifact"],
|
|
4123
|
+
description: "What to finalize: a card file attachment or a hosted HTML artifact."
|
|
4106
4124
|
},
|
|
4107
|
-
|
|
4108
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4109
|
-
workspaceId: {
|
|
4125
|
+
storagePath: {
|
|
4110
4126
|
type: "string",
|
|
4111
|
-
description: "
|
|
4127
|
+
description: "The storagePath returned by harmony_request_upload_url."
|
|
4112
4128
|
},
|
|
4113
|
-
|
|
4129
|
+
cardId: {
|
|
4114
4130
|
type: "string",
|
|
4115
|
-
description: "
|
|
4131
|
+
description: "Card UUID. Required for card_attachment; scope for artifact."
|
|
4116
4132
|
},
|
|
4117
|
-
|
|
4133
|
+
planId: { type: "string", description: "Plan UUID (artifact only)." },
|
|
4134
|
+
workspaceId: {
|
|
4118
4135
|
type: "string",
|
|
4119
|
-
description: "
|
|
4120
|
-
}
|
|
4121
|
-
|
|
4122
|
-
required: []
|
|
4123
|
-
}
|
|
4124
|
-
},
|
|
4125
|
-
harmony_request_artifact_upload_url: {
|
|
4126
|
-
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.",
|
|
4127
|
-
inputSchema: {
|
|
4128
|
-
type: "object",
|
|
4129
|
-
properties: {
|
|
4130
|
-
title: {
|
|
4136
|
+
description: "Workspace UUID (artifact only)."
|
|
4137
|
+
},
|
|
4138
|
+
fileName: {
|
|
4131
4139
|
type: "string",
|
|
4132
|
-
description: "
|
|
4140
|
+
description: "File name including extension (required for card_attachment)."
|
|
4133
4141
|
},
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
workspaceId: {
|
|
4142
|
+
title: { type: "string", description: "Artifact display title." },
|
|
4143
|
+
fileType: {
|
|
4137
4144
|
type: "string",
|
|
4138
|
-
description: "
|
|
4145
|
+
description: "card_attachment MIME type; inferred from the extension when omitted."
|
|
4139
4146
|
},
|
|
4140
|
-
|
|
4147
|
+
sha256: {
|
|
4141
4148
|
type: "string",
|
|
4142
|
-
description: "
|
|
4149
|
+
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4143
4150
|
},
|
|
4144
4151
|
size: {
|
|
4145
4152
|
type: "number",
|
|
4146
|
-
description: "
|
|
4153
|
+
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4147
4154
|
}
|
|
4148
4155
|
},
|
|
4149
|
-
required: []
|
|
4156
|
+
required: ["target", "storagePath"]
|
|
4150
4157
|
}
|
|
4151
4158
|
},
|
|
4152
|
-
|
|
4153
|
-
description: "
|
|
4159
|
+
harmony_classify_card: {
|
|
4160
|
+
description: "Classify a card with the LLM classifier: sets `intent` (plan/think/implement/review), `complexity_score` (0-10), `model_tier` (simple/advanced/research), stamps `classified_at`, and applies the type label (feature/bug/idea). Call right after creating a card to classify it in-flow. Idempotent; never touches the user-owned `model_override`.",
|
|
4154
4161
|
inputSchema: {
|
|
4155
4162
|
type: "object",
|
|
4156
4163
|
properties: {
|
|
4157
|
-
|
|
4158
|
-
type: "string",
|
|
4159
|
-
description: "The storagePath returned by harmony_request_artifact_upload_url."
|
|
4160
|
-
},
|
|
4161
|
-
title: { type: "string", description: "Display title." },
|
|
4162
|
-
cardId: { type: "string", description: "Link to this card (UUID)." },
|
|
4163
|
-
planId: { type: "string", description: "Link to this plan (UUID)." },
|
|
4164
|
-
workspaceId: {
|
|
4165
|
-
type: "string",
|
|
4166
|
-
description: "Attach to this workspace as a standalone artifact (UUID)."
|
|
4167
|
-
},
|
|
4168
|
-
sha256: {
|
|
4169
|
-
type: "string",
|
|
4170
|
-
description: "Optional hex SHA-256 of the uploaded bytes; verified against the stored object."
|
|
4171
|
-
},
|
|
4172
|
-
size: {
|
|
4173
|
-
type: "number",
|
|
4174
|
-
description: "Optional byte size (advisory; re-validated server-side)."
|
|
4175
|
-
}
|
|
4164
|
+
cardId: { type: "string", description: "Card UUID" }
|
|
4176
4165
|
},
|
|
4177
|
-
required: ["
|
|
4166
|
+
required: ["cardId"]
|
|
4178
4167
|
}
|
|
4179
4168
|
},
|
|
4180
4169
|
harmony_share_artifact: {
|
|
@@ -4204,6 +4193,27 @@ var TOOLS = {
|
|
|
4204
4193
|
required: ["cardId"]
|
|
4205
4194
|
}
|
|
4206
4195
|
},
|
|
4196
|
+
harmony_add_external_link: {
|
|
4197
|
+
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.",
|
|
4198
|
+
inputSchema: {
|
|
4199
|
+
type: "object",
|
|
4200
|
+
properties: {
|
|
4201
|
+
cardId: {
|
|
4202
|
+
type: "string",
|
|
4203
|
+
description: "Card UUID"
|
|
4204
|
+
},
|
|
4205
|
+
url: {
|
|
4206
|
+
type: "string",
|
|
4207
|
+
description: "The URL to attach"
|
|
4208
|
+
},
|
|
4209
|
+
title: {
|
|
4210
|
+
type: "string",
|
|
4211
|
+
description: "Optional human-readable title for the link"
|
|
4212
|
+
}
|
|
4213
|
+
},
|
|
4214
|
+
required: ["cardId", "url"]
|
|
4215
|
+
}
|
|
4216
|
+
},
|
|
4207
4217
|
harmony_create_subtask: {
|
|
4208
4218
|
description: "Create a subtask on a card",
|
|
4209
4219
|
inputSchema: {
|
|
@@ -4255,7 +4265,7 @@ var TOOLS = {
|
|
|
4255
4265
|
}
|
|
4256
4266
|
},
|
|
4257
4267
|
harmony_add_comment: {
|
|
4258
|
-
description: "Post a comment on a card as the agent
|
|
4268
|
+
description: "Post a comment on a card as the agent — converse with the human in the open: report progress, ask a question, record a decision, or note a finding, instead of editing the card description. Set supersedesId to correct an earlier comment, confirmsId to reaffirm one. To answer an open question, reply to it with replyToId.",
|
|
4259
4269
|
inputSchema: {
|
|
4260
4270
|
type: "object",
|
|
4261
4271
|
properties: {
|
|
@@ -4281,6 +4291,10 @@ var TOOLS = {
|
|
|
4281
4291
|
confirmsId: {
|
|
4282
4292
|
type: "string",
|
|
4283
4293
|
description: "Comment id this comment reaffirms"
|
|
4294
|
+
},
|
|
4295
|
+
replyToId: {
|
|
4296
|
+
type: "string",
|
|
4297
|
+
description: "Comment id this is a one-level reply to. To answer an open question, reply to it. If you also set supersedesId/confirmsId, it must equal replyToId."
|
|
4284
4298
|
}
|
|
4285
4299
|
},
|
|
4286
4300
|
required: ["cardId", "body"]
|
|
@@ -4752,7 +4766,7 @@ var TOOLS = {
|
|
|
4752
4766
|
limit: { type: "number", description: "Max results (default: 20)" },
|
|
4753
4767
|
top_k: {
|
|
4754
4768
|
type: "number",
|
|
4755
|
-
description: "After
|
|
4769
|
+
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."
|
|
4756
4770
|
},
|
|
4757
4771
|
budget_tokens: {
|
|
4758
4772
|
type: "number",
|
|
@@ -4867,7 +4881,7 @@ var TOOLS = {
|
|
|
4867
4881
|
}
|
|
4868
4882
|
},
|
|
4869
4883
|
harmony_suggest_relations: {
|
|
4870
|
-
description: "Suggest existing memory entities that look related to a given entity, using the same hybrid vector+FTS similarity as recall
|
|
4884
|
+
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.",
|
|
4871
4885
|
inputSchema: {
|
|
4872
4886
|
type: "object",
|
|
4873
4887
|
properties: {
|
|
@@ -5151,7 +5165,7 @@ var TOOLS = {
|
|
|
5151
5165
|
}
|
|
5152
5166
|
},
|
|
5153
5167
|
harmony_list_playbook: {
|
|
5154
|
-
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version,
|
|
5168
|
+
description: "List a workspace's playbooks (reusable process definitions). Returns each playbook's name, version, and state. Read-only.",
|
|
5155
5169
|
inputSchema: {
|
|
5156
5170
|
type: "object",
|
|
5157
5171
|
properties: {
|
|
@@ -5173,21 +5187,8 @@ var TOOLS = {
|
|
|
5173
5187
|
required: ["playbookId"]
|
|
5174
5188
|
}
|
|
5175
5189
|
},
|
|
5176
|
-
harmony_run_playbook: {
|
|
5177
|
-
description: "Run a playbook server-side and return the finalized run. Only legacy automation playbooks (steps_version 1) are runnable; stage playbooks (steps_version 2) are rejected. The server drives every step to completion.",
|
|
5178
|
-
inputSchema: {
|
|
5179
|
-
type: "object",
|
|
5180
|
-
properties: {
|
|
5181
|
-
playbookId: {
|
|
5182
|
-
type: "string",
|
|
5183
|
-
description: "Playbook ID to run (UUID)"
|
|
5184
|
-
}
|
|
5185
|
-
},
|
|
5186
|
-
required: ["playbookId"]
|
|
5187
|
-
}
|
|
5188
|
-
},
|
|
5189
5190
|
harmony_create_playbook: {
|
|
5190
|
-
description: "Create a new playbook in a workspace.
|
|
5191
|
+
description: "Create a new playbook (a reusable process definition) in a workspace. A playbook is an ordered set of stages bound to board columns, run by people and the agent daemon as a card moves through them.",
|
|
5191
5192
|
inputSchema: {
|
|
5192
5193
|
type: "object",
|
|
5193
5194
|
properties: {
|
|
@@ -5197,14 +5198,9 @@ var TOOLS = {
|
|
|
5197
5198
|
},
|
|
5198
5199
|
name: { type: "string", description: "Playbook name" },
|
|
5199
5200
|
description: { type: "string", description: "Playbook description" },
|
|
5200
|
-
stepsVersion: {
|
|
5201
|
-
type: "number",
|
|
5202
|
-
enum: [1, 2],
|
|
5203
|
-
description: "1 = automation macro (tool steps), 2 = Method stage model (stage objects). Default 1."
|
|
5204
|
-
},
|
|
5205
5201
|
steps: {
|
|
5206
5202
|
type: "array",
|
|
5207
|
-
description: "
|
|
5203
|
+
description: "The playbook's ordered stage objects.",
|
|
5208
5204
|
items: { type: "object" }
|
|
5209
5205
|
}
|
|
5210
5206
|
},
|
|
@@ -5224,7 +5220,7 @@ var TOOLS = {
|
|
|
5224
5220
|
description: { type: "string", description: "New description" },
|
|
5225
5221
|
steps: {
|
|
5226
5222
|
type: "array",
|
|
5227
|
-
description: "New
|
|
5223
|
+
description: "New ordered stage objects.",
|
|
5228
5224
|
items: { type: "object" }
|
|
5229
5225
|
},
|
|
5230
5226
|
enabled: {
|
|
@@ -5240,20 +5236,6 @@ var TOOLS = {
|
|
|
5240
5236
|
required: ["playbookId"]
|
|
5241
5237
|
}
|
|
5242
5238
|
},
|
|
5243
|
-
harmony_save_card_as_playbook: {
|
|
5244
|
-
description: "Save an existing card as a new steps_version 1 (automation) playbook, seeding one create-card step from the card. Returns the created playbook.",
|
|
5245
|
-
inputSchema: {
|
|
5246
|
-
type: "object",
|
|
5247
|
-
properties: {
|
|
5248
|
-
cardId: { type: "string", description: "Card ID to template (UUID)" },
|
|
5249
|
-
name: {
|
|
5250
|
-
type: "string",
|
|
5251
|
-
description: "Name for the new playbook (defaults to the card title)"
|
|
5252
|
-
}
|
|
5253
|
-
},
|
|
5254
|
-
required: ["cardId"]
|
|
5255
|
-
}
|
|
5256
|
-
},
|
|
5257
5239
|
harmony_signup: {
|
|
5258
5240
|
description: "Create a new user account. Returns a JWT session for subsequent authenticated calls. No API key required.",
|
|
5259
5241
|
inputSchema: {
|
|
@@ -5653,23 +5635,33 @@ async function handleToolCall(name, args, deps) {
|
|
|
5653
5635
|
});
|
|
5654
5636
|
return { success: true, ...result, count: result.cards.length };
|
|
5655
5637
|
}
|
|
5638
|
+
case "harmony_get_card_by_short_id":
|
|
5639
|
+
case "harmony_bulk_get_cards":
|
|
5656
5640
|
case "harmony_get_card": {
|
|
5641
|
+
if (name !== "harmony_get_card")
|
|
5642
|
+
warnDeprecatedTool(name);
|
|
5643
|
+
const hasShortIds = args.shortIds != null;
|
|
5644
|
+
const hasShortId = args.shortId != null;
|
|
5645
|
+
const hasCardId = args.cardId != null;
|
|
5646
|
+
if ([hasShortIds, hasShortId, hasCardId].filter(Boolean).length !== 1) {
|
|
5647
|
+
throw new Error("Provide exactly one of: cardId (UUID), shortId (number), or shortIds (number[]).");
|
|
5648
|
+
}
|
|
5649
|
+
if (hasShortIds) {
|
|
5650
|
+
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5651
|
+
const projectId = getProjectId();
|
|
5652
|
+
const result2 = await client3.bulkGetCards(projectId, shortIds);
|
|
5653
|
+
return { success: true, ...result2 };
|
|
5654
|
+
}
|
|
5655
|
+
if (hasShortId) {
|
|
5656
|
+
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5657
|
+
const projectId = args.projectId || getProjectId();
|
|
5658
|
+
const result2 = await client3.getCardByShortId(projectId, shortId);
|
|
5659
|
+
return { success: true, ...result2 };
|
|
5660
|
+
}
|
|
5657
5661
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5658
5662
|
const result = await client3.getCard(cardId);
|
|
5659
5663
|
return { success: true, ...result };
|
|
5660
5664
|
}
|
|
5661
|
-
case "harmony_get_card_by_short_id": {
|
|
5662
|
-
const shortId = z.number().int().positive().parse(args.shortId);
|
|
5663
|
-
const projectId = args.projectId || getProjectId();
|
|
5664
|
-
const result = await client3.getCardByShortId(projectId, shortId);
|
|
5665
|
-
return { success: true, ...result };
|
|
5666
|
-
}
|
|
5667
|
-
case "harmony_bulk_get_cards": {
|
|
5668
|
-
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5669
|
-
const projectId = getProjectId();
|
|
5670
|
-
const result = await client3.bulkGetCards(projectId, shortIds);
|
|
5671
|
-
return { success: true, ...result };
|
|
5672
|
-
}
|
|
5673
5665
|
case "harmony_bulk_archive_cards": {
|
|
5674
5666
|
const shortIds = z.array(z.number().int().positive()).min(1).max(100).parse(args.shortIds);
|
|
5675
5667
|
const projectId = getProjectId();
|
|
@@ -5769,58 +5761,58 @@ async function handleToolCall(name, args, deps) {
|
|
|
5769
5761
|
const result = await client3.getCardAttachments(cardId);
|
|
5770
5762
|
return result;
|
|
5771
5763
|
}
|
|
5772
|
-
case "harmony_upload_card_attachment":
|
|
5773
|
-
|
|
5764
|
+
case "harmony_upload_card_attachment":
|
|
5765
|
+
case "harmony_upload_artifact":
|
|
5766
|
+
case "harmony_upload": {
|
|
5767
|
+
if (name !== "harmony_upload")
|
|
5768
|
+
warnDeprecatedTool(name);
|
|
5769
|
+
const target = name === "harmony_upload_card_attachment" ? "card_attachment" : name === "harmony_upload_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5774
5770
|
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5775
5771
|
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5776
|
-
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5777
|
-
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5778
5772
|
if (filePath && base64Data) {
|
|
5779
5773
|
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5780
5774
|
}
|
|
5781
|
-
if (
|
|
5782
|
-
const
|
|
5783
|
-
const
|
|
5784
|
-
const
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5775
|
+
if (target === "card_attachment") {
|
|
5776
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5777
|
+
const fileName = args.fileName != null ? z.string().parse(args.fileName) : undefined;
|
|
5778
|
+
const contentType = args.contentType != null ? z.string().parse(args.contentType) : undefined;
|
|
5779
|
+
if (filePath) {
|
|
5780
|
+
const bytes = await readFileForUpload(filePath, MAX_ATTACHMENT_SIZE, "attachment");
|
|
5781
|
+
const resolvedName = fileName || basename(filePath);
|
|
5782
|
+
const signed = await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5783
|
+
fileName: resolvedName,
|
|
5784
|
+
fileType: contentType,
|
|
5785
|
+
size: bytes.byteLength
|
|
5786
|
+
});
|
|
5787
|
+
await putToSignedUrl(signed.uploadUrl, bytes, contentType || signed.fileType || "application/octet-stream");
|
|
5788
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5789
|
+
storagePath: signed.storagePath,
|
|
5790
|
+
fileName: resolvedName,
|
|
5791
|
+
fileType: contentType || signed.fileType,
|
|
5792
|
+
sha256: sha256Hex(bytes),
|
|
5793
|
+
size: bytes.byteLength
|
|
5794
|
+
});
|
|
5801
5795
|
}
|
|
5802
|
-
if (
|
|
5803
|
-
|
|
5796
|
+
if (base64Data) {
|
|
5797
|
+
if (!fileName) {
|
|
5798
|
+
throw new Error("fileName is required when using base64Data.");
|
|
5799
|
+
}
|
|
5800
|
+
if (base64ByteLength(base64Data) > MAX_ATTACHMENT_SIZE) {
|
|
5801
|
+
throw new Error(`File is over the 5MB attachment limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5802
|
+
}
|
|
5803
|
+
return await client3.uploadCardAttachment(cardId2, {
|
|
5804
|
+
fileName,
|
|
5805
|
+
data: base64Data,
|
|
5806
|
+
fileType: contentType
|
|
5807
|
+
});
|
|
5804
5808
|
}
|
|
5805
|
-
|
|
5806
|
-
fileName,
|
|
5807
|
-
data: base64Data,
|
|
5808
|
-
fileType: contentType
|
|
5809
|
-
});
|
|
5809
|
+
throw new Error("Provide either filePath or base64Data.");
|
|
5810
5810
|
}
|
|
5811
|
-
throw new Error("Provide either filePath or base64Data.");
|
|
5812
|
-
}
|
|
5813
|
-
case "harmony_upload_artifact": {
|
|
5814
5811
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5815
5812
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5816
5813
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
5817
5814
|
const workspaceId = args.workspaceId != null ? z.string().uuid().parse(args.workspaceId) : undefined;
|
|
5818
5815
|
requireExactlyOneScope({ cardId, planId, workspaceId });
|
|
5819
|
-
const filePath = args.filePath != null ? z.string().parse(args.filePath) : undefined;
|
|
5820
|
-
const base64Data = args.base64Data != null ? z.string().parse(args.base64Data) : undefined;
|
|
5821
|
-
if (filePath && base64Data) {
|
|
5822
|
-
throw new Error("Provide either filePath or base64Data, not both.");
|
|
5823
|
-
}
|
|
5824
5816
|
if (filePath) {
|
|
5825
5817
|
const bytes = await readFileForUpload(filePath, MAX_ARTIFACT_SIZE, "artifact");
|
|
5826
5818
|
const resolvedTitle = title || basename(filePath);
|
|
@@ -5845,7 +5837,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
5845
5837
|
}
|
|
5846
5838
|
if (base64Data) {
|
|
5847
5839
|
if (base64ByteLength(base64Data) > MAX_ARTIFACT_SIZE) {
|
|
5848
|
-
throw new Error(`Artifact is over the 2MB limit. Use the
|
|
5840
|
+
throw new Error(`Artifact is over the 2MB limit. Use the harmony_request_upload_url + harmony_finalize_upload handshake for large files.`);
|
|
5849
5841
|
}
|
|
5850
5842
|
return await client3.uploadArtifact({
|
|
5851
5843
|
title,
|
|
@@ -5857,7 +5849,26 @@ async function handleToolCall(name, args, deps) {
|
|
|
5857
5849
|
}
|
|
5858
5850
|
throw new Error("Provide either filePath or base64Data.");
|
|
5859
5851
|
}
|
|
5860
|
-
case "harmony_request_artifact_upload_url":
|
|
5852
|
+
case "harmony_request_artifact_upload_url":
|
|
5853
|
+
case "harmony_request_card_attachment_upload_url":
|
|
5854
|
+
case "harmony_request_upload_url": {
|
|
5855
|
+
if (name !== "harmony_request_upload_url")
|
|
5856
|
+
warnDeprecatedTool(name);
|
|
5857
|
+
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);
|
|
5858
|
+
if (target === "card_attachment") {
|
|
5859
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5860
|
+
const fileName = z.string().parse(args.fileName);
|
|
5861
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5862
|
+
const size2 = z.number().positive().parse(args.size);
|
|
5863
|
+
if (size2 > MAX_ATTACHMENT_SIZE) {
|
|
5864
|
+
throw new Error(`Declared size ${size2} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5865
|
+
}
|
|
5866
|
+
return await client3.requestCardAttachmentUploadUrl(cardId2, {
|
|
5867
|
+
fileName,
|
|
5868
|
+
fileType,
|
|
5869
|
+
size: size2
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
5861
5872
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5862
5873
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5863
5874
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5877,8 +5888,27 @@ async function handleToolCall(name, args, deps) {
|
|
|
5877
5888
|
size
|
|
5878
5889
|
});
|
|
5879
5890
|
}
|
|
5880
|
-
case "harmony_finalize_artifact":
|
|
5891
|
+
case "harmony_finalize_artifact":
|
|
5892
|
+
case "harmony_finalize_card_attachment":
|
|
5893
|
+
case "harmony_finalize_upload": {
|
|
5894
|
+
if (name !== "harmony_finalize_upload")
|
|
5895
|
+
warnDeprecatedTool(name);
|
|
5896
|
+
const target = name === "harmony_finalize_card_attachment" ? "card_attachment" : name === "harmony_finalize_artifact" ? "artifact" : z.enum(["card_attachment", "artifact"]).parse(args.target);
|
|
5881
5897
|
const storagePath = z.string().parse(args.storagePath);
|
|
5898
|
+
if (target === "card_attachment") {
|
|
5899
|
+
const cardId2 = z.string().uuid().parse(args.cardId);
|
|
5900
|
+
const fileName = z.string().parse(args.fileName);
|
|
5901
|
+
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5902
|
+
const sha2562 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5903
|
+
const size2 = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5904
|
+
return await client3.finalizeCardAttachment(cardId2, {
|
|
5905
|
+
storagePath,
|
|
5906
|
+
fileName,
|
|
5907
|
+
fileType,
|
|
5908
|
+
sha256: sha2562,
|
|
5909
|
+
size: size2
|
|
5910
|
+
});
|
|
5911
|
+
}
|
|
5882
5912
|
const title = args.title != null ? z.string().parse(args.title) : undefined;
|
|
5883
5913
|
const cardId = args.cardId != null ? z.string().uuid().parse(args.cardId) : undefined;
|
|
5884
5914
|
const planId = args.planId != null ? z.string().uuid().parse(args.planId) : undefined;
|
|
@@ -5896,35 +5926,6 @@ async function handleToolCall(name, args, deps) {
|
|
|
5896
5926
|
workspaceId
|
|
5897
5927
|
});
|
|
5898
5928
|
}
|
|
5899
|
-
case "harmony_request_card_attachment_upload_url": {
|
|
5900
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5901
|
-
const fileName = z.string().parse(args.fileName);
|
|
5902
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5903
|
-
const size = z.number().positive().parse(args.size);
|
|
5904
|
-
if (size > MAX_ATTACHMENT_SIZE) {
|
|
5905
|
-
throw new Error(`Declared size ${size} bytes is over the ${MAX_ATTACHMENT_SIZE}-byte (5MB) attachment limit.`);
|
|
5906
|
-
}
|
|
5907
|
-
return await client3.requestCardAttachmentUploadUrl(cardId, {
|
|
5908
|
-
fileName,
|
|
5909
|
-
fileType,
|
|
5910
|
-
size
|
|
5911
|
-
});
|
|
5912
|
-
}
|
|
5913
|
-
case "harmony_finalize_card_attachment": {
|
|
5914
|
-
const cardId = z.string().uuid().parse(args.cardId);
|
|
5915
|
-
const storagePath = z.string().parse(args.storagePath);
|
|
5916
|
-
const fileName = z.string().parse(args.fileName);
|
|
5917
|
-
const fileType = args.fileType != null ? z.string().parse(args.fileType) : undefined;
|
|
5918
|
-
const sha256 = args.sha256 != null ? z.string().parse(args.sha256) : undefined;
|
|
5919
|
-
const size = args.size != null ? z.number().positive().parse(args.size) : undefined;
|
|
5920
|
-
return await client3.finalizeCardAttachment(cardId, {
|
|
5921
|
-
storagePath,
|
|
5922
|
-
fileName,
|
|
5923
|
-
fileType,
|
|
5924
|
-
sha256,
|
|
5925
|
-
size
|
|
5926
|
-
});
|
|
5927
|
-
}
|
|
5928
5929
|
case "harmony_share_artifact": {
|
|
5929
5930
|
const artifactId = z.string().uuid().parse(args.artifactId);
|
|
5930
5931
|
const expiresInDays = args.expiresInDays != null ? z.number().positive().parse(args.expiresInDays) : undefined;
|
|
@@ -5937,6 +5938,13 @@ async function handleToolCall(name, args, deps) {
|
|
|
5937
5938
|
const result = await client3.getCardExternalLinks(cardId);
|
|
5938
5939
|
return result;
|
|
5939
5940
|
}
|
|
5941
|
+
case "harmony_add_external_link": {
|
|
5942
|
+
const cardId = z.string().uuid().parse(args.cardId);
|
|
5943
|
+
const url = z.string().min(1).max(2048).parse(args.url);
|
|
5944
|
+
const title = args.title ? z.string().max(200).parse(args.title) : undefined;
|
|
5945
|
+
const result = await client3.addExternalLink(cardId, url, title);
|
|
5946
|
+
return { success: true, ...result };
|
|
5947
|
+
}
|
|
5940
5948
|
case "harmony_classify_card": {
|
|
5941
5949
|
const cardId = z.string().uuid().parse(args.cardId);
|
|
5942
5950
|
const result = await client3.classifyCard(cardId);
|
|
@@ -5990,10 +5998,12 @@ async function handleToolCall(name, args, deps) {
|
|
|
5990
5998
|
]).parse(args.commentType) : undefined;
|
|
5991
5999
|
const supersedesId = args.supersedesId !== undefined ? z.string().uuid().parse(args.supersedesId) : undefined;
|
|
5992
6000
|
const confirmsId = args.confirmsId !== undefined ? z.string().uuid().parse(args.confirmsId) : undefined;
|
|
6001
|
+
const replyToId = args.replyToId !== undefined ? z.string().uuid().parse(args.replyToId) : undefined;
|
|
5993
6002
|
const result = await client3.addComment(cardId, body, {
|
|
5994
6003
|
commentType,
|
|
5995
6004
|
supersedesId,
|
|
5996
|
-
confirmsId
|
|
6005
|
+
confirmsId,
|
|
6006
|
+
replyToId
|
|
5997
6007
|
});
|
|
5998
6008
|
return { success: true, ...result };
|
|
5999
6009
|
}
|
|
@@ -6853,21 +6863,16 @@ async function handleToolCall(name, args, deps) {
|
|
|
6853
6863
|
const result = await client3.getPlaybook(playbookId);
|
|
6854
6864
|
return { success: true, playbook: result.playbook, runs: result.runs };
|
|
6855
6865
|
}
|
|
6856
|
-
case "harmony_run_playbook":
|
|
6857
|
-
|
|
6858
|
-
const result = await client3.runPlaybook(playbookId);
|
|
6859
|
-
return { success: true, run: result.run };
|
|
6860
|
-
}
|
|
6866
|
+
case "harmony_run_playbook":
|
|
6867
|
+
return deprecatedRemovedToolResult("harmony_run_playbook");
|
|
6861
6868
|
case "harmony_create_playbook": {
|
|
6862
6869
|
const workspaceId = args.workspaceId || getWorkspaceId();
|
|
6863
6870
|
const name2 = z.string().min(1).max(200).parse(args.name);
|
|
6864
|
-
const stepsVersion = args.stepsVersion !== undefined ? z.union([z.literal(1), z.literal(2)]).parse(args.stepsVersion) : undefined;
|
|
6865
6871
|
const result = await client3.createPlaybook({
|
|
6866
6872
|
workspaceId,
|
|
6867
6873
|
name: name2,
|
|
6868
6874
|
description: args.description,
|
|
6869
|
-
steps: args.steps
|
|
6870
|
-
stepsVersion
|
|
6875
|
+
steps: args.steps
|
|
6871
6876
|
});
|
|
6872
6877
|
return { success: true, playbook: result.playbook };
|
|
6873
6878
|
}
|
|
@@ -6882,14 +6887,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
6882
6887
|
});
|
|
6883
6888
|
return { success: true, playbook: result.playbook };
|
|
6884
6889
|
}
|
|
6885
|
-
case "harmony_save_card_as_playbook":
|
|
6886
|
-
|
|
6887
|
-
const result = await client3.savePlaybookFromCard({
|
|
6888
|
-
cardId,
|
|
6889
|
-
name: args.name
|
|
6890
|
-
});
|
|
6891
|
-
return { success: true, playbook: result.playbook };
|
|
6892
|
-
}
|
|
6890
|
+
case "harmony_save_card_as_playbook":
|
|
6891
|
+
return deprecatedRemovedToolResult("harmony_save_card_as_playbook");
|
|
6893
6892
|
case "harmony_signup": {
|
|
6894
6893
|
const email = z.string().email().max(254).parse(args.email);
|
|
6895
6894
|
const password = z.string().min(8).max(128).parse(args.password);
|