@gethmy/mcp 2.12.0 → 2.13.1

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/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,6 +687,32 @@ 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[] }> {
@@ -694,6 +732,35 @@ export class HarmonyApiClient {
694
732
  return this.request("POST", "/artifacts", data);
695
733
  }
696
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
+
697
764
  async createArtifactShareLink(
698
765
  artifactId: string,
699
766
  expiresAt?: string,
@@ -1747,6 +1814,40 @@ export class HarmonyApiClient {
1747
1814
  return this.request("GET", `/playbooks/${playbookId}`);
1748
1815
  }
1749
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
+
1750
1851
  async createPlaybook(data: {
1751
1852
  workspaceId: string;
1752
1853
  name: string;