@gethmy/mcp 2.11.2 → 2.13.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.
@@ -944,6 +944,9 @@ var TIMINGS = {
944
944
  QUERY_STALE_TIME: 1000 * 60 * 5,
945
945
  QUERY_GC_TIME: 1000 * 60 * 60 * 24
946
946
  };
947
+ // ../harmony-shared/dist/stageHandoff.js
948
+ var HANDOFF_MARKER = "harmony:stage-handoff";
949
+ var HANDOFF_BLOCK_RE = new RegExp("```json\\s*\\n//\\s*" + HANDOFF_MARKER + "\\s*\\n([\\s\\S]*?)\\n```", "m");
947
950
  // src/api-client.ts
948
951
  init_config();
949
952
  var RETRY_CONFIG = {
@@ -1303,9 +1306,29 @@ class HarmonyApiClient {
1303
1306
  async uploadCardAttachment(cardId, data) {
1304
1307
  return this.request("POST", `/cards/${cardId}/attachments`, data);
1305
1308
  }
1309
+ async requestCardAttachmentUploadUrl(cardId, data) {
1310
+ return this.request("POST", `/cards/${cardId}/attachment-upload-url`, data);
1311
+ }
1312
+ async finalizeCardAttachment(cardId, data) {
1313
+ return this.request("POST", `/cards/${cardId}/attachments/finalize`, data);
1314
+ }
1306
1315
  async getCardExternalLinks(cardId) {
1307
1316
  return this.request("GET", `/cards/${cardId}/external-links`);
1308
1317
  }
1318
+ async uploadArtifact(data) {
1319
+ return this.request("POST", "/artifacts", data);
1320
+ }
1321
+ async requestArtifactUploadUrl(data) {
1322
+ return this.request("POST", "/artifacts/upload-url", data);
1323
+ }
1324
+ async finalizeArtifact(data) {
1325
+ return this.request("POST", "/artifacts/finalize", data);
1326
+ }
1327
+ async createArtifactShareLink(artifactId, expiresAt) {
1328
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
1329
+ expires_at: expiresAt
1330
+ });
1331
+ }
1309
1332
  async classifyCard(cardId) {
1310
1333
  return this.request("POST", `/cards/${cardId}/classify`);
1311
1334
  }
@@ -1772,6 +1795,30 @@ ${planContent.trim()}`;
1772
1795
  title: cardData.title
1773
1796
  };
1774
1797
  }
1798
+ async listPlaybooks(workspaceId) {
1799
+ return this.request("GET", `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`);
1800
+ }
1801
+ async getPlaybook(playbookId) {
1802
+ return this.request("GET", `/playbooks/${playbookId}`);
1803
+ }
1804
+ async getPlaybookVersion(playbookId, version) {
1805
+ return this.request("GET", `/playbooks/${encodeURIComponent(playbookId)}/versions/${version}`);
1806
+ }
1807
+ async recordStageGateEvidence(insert) {
1808
+ return this.request("POST", `/cards/${encodeURIComponent(insert.card_id)}/stage-gate-evidence`, insert);
1809
+ }
1810
+ async createPlaybook(data) {
1811
+ return this.request("POST", "/playbooks", data);
1812
+ }
1813
+ async updatePlaybook(playbookId, updates) {
1814
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
1815
+ }
1816
+ async runPlaybook(playbookId) {
1817
+ return this.request("POST", `/playbooks/${playbookId}/run`);
1818
+ }
1819
+ async savePlaybookFromCard(data) {
1820
+ return this.request("POST", "/playbooks/from-card", data);
1821
+ }
1775
1822
  }
1776
1823
  var _promptModules = null;
1777
1824
  async function loadPromptModules() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gethmy/mcp",
3
- "version": "2.11.2",
3
+ "version": "2.13.0",
4
4
  "description": "MCP server for Harmony Kanban board - enables AI coding agents to manage your boards",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/api-client.ts CHANGED
@@ -2,6 +2,9 @@ import {
2
2
  type AgentRunEventDraft,
3
3
  type Comment,
4
4
  getDisplayLinkType,
5
+ type PlaybookVersionDef,
6
+ type StageGateEvidenceInsert,
7
+ type StageGateEvidenceRow,
5
8
  serializeCommentThread,
6
9
  type WorkspaceAgent,
7
10
  } from "@harmony/shared";
@@ -143,6 +146,15 @@ export interface CardAttachment {
143
146
  signed_url_expires_in: number;
144
147
  }
145
148
 
149
+ /** Response of a `*-upload-url` endpoint: a one-shot signed Supabase Storage
150
+ * URL the caller PUTs raw bytes to, plus the service-chosen path that the
151
+ * matching `finalize` call validates and registers. */
152
+ export interface SignedUpload {
153
+ uploadUrl: string;
154
+ token: string;
155
+ storagePath: string;
156
+ }
157
+
146
158
  export interface CardExternalLinkRow {
147
159
  id: string;
148
160
  card_id: string;
@@ -675,12 +687,89 @@ export class HarmonyApiClient {
675
687
  return this.request("POST", `/cards/${cardId}/attachments`, data);
676
688
  }
677
689
 
690
+ // Step 1 of the direct-to-storage attachment handshake: mint a signed upload
691
+ // URL for a server-chosen path under the card. The caller PUTs raw bytes to
692
+ // `uploadUrl`, then calls finalizeCardAttachment with the returned storagePath.
693
+ async requestCardAttachmentUploadUrl(
694
+ cardId: string,
695
+ data: { fileName: string; fileType?: string; size: number },
696
+ ): Promise<SignedUpload & { fileType: string }> {
697
+ return this.request("POST", `/cards/${cardId}/attachment-upload-url`, data);
698
+ }
699
+
700
+ // Step 2: validate the uploaded object (size + magic-byte content-type +
701
+ // optional sha256) and insert the attachment row. The server deletes the
702
+ // object and rejects on any mismatch.
703
+ async finalizeCardAttachment(
704
+ cardId: string,
705
+ data: {
706
+ storagePath: string;
707
+ fileName: string;
708
+ fileType?: string;
709
+ sha256?: string;
710
+ size?: number;
711
+ },
712
+ ): Promise<{ attachment: CardAttachment }> {
713
+ return this.request("POST", `/cards/${cardId}/attachments/finalize`, data);
714
+ }
715
+
678
716
  async getCardExternalLinks(
679
717
  cardId: string,
680
718
  ): Promise<{ external_links: CardExternalLinkRow[] }> {
681
719
  return this.request("GET", `/cards/${cardId}/external-links`);
682
720
  }
683
721
 
722
+ // ============ ARTIFACTS (hosted HTML documents) ============
723
+
724
+ async uploadArtifact(data: {
725
+ title?: string;
726
+ cardId?: string;
727
+ planId?: string;
728
+ workspaceId?: string;
729
+ contentType?: string;
730
+ data: string;
731
+ }): Promise<{ artifact: Record<string, unknown> }> {
732
+ return this.request("POST", "/artifacts", data);
733
+ }
734
+
735
+ // Step 1 of the direct-to-storage artifact handshake: mint a signed upload
736
+ // URL for a server-chosen path. The caller PUTs raw HTML bytes to `uploadUrl`,
737
+ // then calls finalizeArtifact with the returned storagePath.
738
+ async requestArtifactUploadUrl(data: {
739
+ title?: string;
740
+ cardId?: string;
741
+ planId?: string;
742
+ workspaceId?: string;
743
+ contentType?: string;
744
+ size?: number;
745
+ }): Promise<SignedUpload> {
746
+ return this.request("POST", "/artifacts/upload-url", data);
747
+ }
748
+
749
+ // Step 2: validate the uploaded object (size + HTML magic-byte sniff +
750
+ // optional sha256) and insert the artifact row. The server deletes the
751
+ // object and rejects on any mismatch.
752
+ async finalizeArtifact(data: {
753
+ storagePath: string;
754
+ sha256?: string;
755
+ size?: number;
756
+ title?: string;
757
+ cardId?: string;
758
+ planId?: string;
759
+ workspaceId?: string;
760
+ }): Promise<{ artifact: Record<string, unknown> }> {
761
+ return this.request("POST", "/artifacts/finalize", data);
762
+ }
763
+
764
+ async createArtifactShareLink(
765
+ artifactId: string,
766
+ expiresAt?: string,
767
+ ): Promise<{ link: Record<string, unknown> }> {
768
+ return this.request("POST", `/artifacts/${artifactId}/share`, {
769
+ expires_at: expiresAt,
770
+ });
771
+ }
772
+
684
773
  async classifyCard(
685
774
  cardId: string,
686
775
  ): Promise<{ classification: CardClassificationResult }> {
@@ -1709,6 +1798,90 @@ export class HarmonyApiClient {
1709
1798
  title: cardData.title,
1710
1799
  };
1711
1800
  }
1801
+
1802
+ // ============ PLAYBOOKS (Method/Loop layer) ============
1803
+
1804
+ async listPlaybooks(workspaceId: string): Promise<{ playbooks: unknown[] }> {
1805
+ return this.request(
1806
+ "GET",
1807
+ `/playbooks?workspaceId=${encodeURIComponent(workspaceId)}`,
1808
+ );
1809
+ }
1810
+
1811
+ async getPlaybook(
1812
+ playbookId: string,
1813
+ ): Promise<{ playbook: unknown; runs: unknown[] }> {
1814
+ return this.request("GET", `/playbooks/${playbookId}`);
1815
+ }
1816
+
1817
+ /**
1818
+ * Fetch the pinned, immutable stage-def snapshot for `(playbookId, version)`.
1819
+ * The agent daemon's stage executor (#514) resolves a card's `current_stage`
1820
+ * against this frozen def — never live `playbooks.steps` — so editing a
1821
+ * Playbook never rewrites an in-flight card.
1822
+ */
1823
+ async getPlaybookVersion(
1824
+ playbookId: string,
1825
+ version: number,
1826
+ ): Promise<{
1827
+ version: PlaybookVersionDef & { playbook_id: string; version: number };
1828
+ }> {
1829
+ return this.request(
1830
+ "GET",
1831
+ `/playbooks/${encodeURIComponent(playbookId)}/versions/${version}`,
1832
+ );
1833
+ }
1834
+
1835
+ /**
1836
+ * Persist a stage gate evidence row (Playbooks P1 #3, card #516). The daemon
1837
+ * collects + evaluates a gate then POSTs the resulting evidence here; the edge
1838
+ * writes it with the service-role client (the table has no INSERT RLS policy,
1839
+ * so this is the only write path). Returns the inserted row.
1840
+ */
1841
+ async recordStageGateEvidence(
1842
+ insert: StageGateEvidenceInsert,
1843
+ ): Promise<{ evidence: StageGateEvidenceRow }> {
1844
+ return this.request(
1845
+ "POST",
1846
+ `/cards/${encodeURIComponent(insert.card_id)}/stage-gate-evidence`,
1847
+ insert,
1848
+ );
1849
+ }
1850
+
1851
+ async createPlaybook(data: {
1852
+ workspaceId: string;
1853
+ name: string;
1854
+ description?: string;
1855
+ steps?: unknown;
1856
+ stepsVersion?: number;
1857
+ triggerType?: string;
1858
+ }): Promise<{ playbook: unknown }> {
1859
+ return this.request("POST", "/playbooks", data);
1860
+ }
1861
+
1862
+ async updatePlaybook(
1863
+ playbookId: string,
1864
+ updates: {
1865
+ name?: string;
1866
+ description?: string;
1867
+ steps?: unknown;
1868
+ enabled?: boolean;
1869
+ state?: string;
1870
+ },
1871
+ ): Promise<{ playbook: unknown }> {
1872
+ return this.request("PATCH", `/playbooks/${playbookId}`, updates);
1873
+ }
1874
+
1875
+ async runPlaybook(playbookId: string): Promise<{ run: unknown }> {
1876
+ return this.request("POST", `/playbooks/${playbookId}/run`);
1877
+ }
1878
+
1879
+ async savePlaybookFromCard(data: {
1880
+ cardId: string;
1881
+ name?: string;
1882
+ }): Promise<{ playbook: unknown }> {
1883
+ return this.request("POST", "/playbooks/from-card", data);
1884
+ }
1712
1885
  }
1713
1886
 
1714
1887
  // Shared types for generateCardPrompt to avoid inline assertions