salt-agent-sdk 0.29.0 → 0.32.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/dist/client.d.ts CHANGED
@@ -95,6 +95,36 @@ export interface PostMessageResult {
95
95
  delivered_as?: DeliveredAs;
96
96
  [key: string]: unknown;
97
97
  }
98
+ /** How often a subscriber gets an account's posts by email. */
99
+ export type PostSubscriptionCadence = "instant" | "daily" | "weekly";
100
+ /** `subscribeToPostsByEmail` result. 202 `check_your_email` always, for any well-formed email (it never says whether
101
+ * the address was already subscribed); 201 `active` with the `cadence` when the caller is signed in and the email is
102
+ * their own verified account email. */
103
+ export type PostSubscribeResult = {
104
+ status: "check_your_email";
105
+ } | {
106
+ status: "active";
107
+ cadence: PostSubscriptionCadence;
108
+ };
109
+ /** `GET /api/v1/me/post_subscribers`: active email subscribers to your posts, counts only, never addresses. */
110
+ export interface PostSubscriberCount {
111
+ count: number;
112
+ by_cadence: {
113
+ instant: number;
114
+ daily: number;
115
+ weekly: number;
116
+ };
117
+ }
118
+ /** One row of `GET /api/v1/me/post_subscriptions`: an account whose posts you get by email. */
119
+ export interface MyPostSubscription {
120
+ id: SaltId;
121
+ cadence: PostSubscriptionCadence;
122
+ status: "pending" | "active" | "unsubscribed";
123
+ account: {
124
+ username: string;
125
+ display_name: string;
126
+ };
127
+ }
98
128
  /** One row of `GET /api/v1/contacts/incoming`: an account that added the caller and that the caller has not
99
129
  * added back. `added_at` is when they added you. */
100
130
  export interface IncomingContact {
@@ -814,6 +844,10 @@ export interface Mandate {
814
844
  approved_by?: "self" | null;
815
845
  /** The pending request to change a running plan's settings, or null. See `requestStrategyTune`. */
816
846
  tune_request?: StrategyTuneRequest | null;
847
+ /** Strategy mandates: the keys the person keeps fixed (`lockPlan`); `tunePlan` on one is refused 422 `plan_locked`. Top level, not inside `strategy`. */
848
+ locks?: PlanLock[];
849
+ /** Strategy mandates: when the plan first checks in (Allow time plus review cadence); null until Allowed. */
850
+ first_check_in_at?: string | null;
817
851
  /** Strategy mandates: money paid under the plan, per currency (this month and in total). Measured, never estimated. */
818
852
  spend?: {
819
853
  money: {
@@ -860,8 +894,118 @@ export interface MandateExercise {
860
894
  created_at: string;
861
895
  decided_at?: string;
862
896
  expires_at?: string;
897
+ /** Salt's plain label for who or what the act goes to (an approve-first ask), when it sends one. */
898
+ target_label?: string;
899
+ /** One plain sentence for the act ("Posted on your profile"), derived on read. `summary` stays the structured hash. */
900
+ summary_text?: string;
901
+ /** Plain words for where the act lands ("Your profile", "A public room", "Ravi (@ravi)"), never the agent's own text. */
902
+ where?: string | null;
903
+ /** `paid` is 0 USD for an act that spends nothing, the amount for a payment, null when unknown; `ai_usd` is null unless known. */
904
+ cost?: {
905
+ ai_usd: number | null;
906
+ paid: {
907
+ amount: string;
908
+ currency: string;
909
+ } | null;
910
+ };
863
911
  [key: string]: unknown;
864
912
  }
913
+ /** What a person can use, from `getReadiness`: counts and names only. */
914
+ export interface Readiness {
915
+ person_id: SaltId;
916
+ wallets: number;
917
+ shop: boolean;
918
+ /** Services connected now and not waiting to be reconnected. */
919
+ connections: {
920
+ service: string;
921
+ name: string;
922
+ }[];
923
+ followers: number;
924
+ contacts: number;
925
+ email_subscribers: number;
926
+ }
927
+ /** One target in a `PlanSummary`. `actual` is filled by Salt only for `source: "reported"`; otherwise `measured_by` is `"agent"`. */
928
+ export interface PlanSummaryTarget {
929
+ metric: string;
930
+ target: number;
931
+ unit?: string | null;
932
+ deadline?: string | null;
933
+ source: string;
934
+ source_label?: string;
935
+ actual: number | null;
936
+ actual_at?: string | null;
937
+ reported: boolean;
938
+ note?: string | null;
939
+ measured_by?: "agent";
940
+ [key: string]: unknown;
941
+ }
942
+ /** The plan in one read (`getPlanSummary`). No message content. */
943
+ export interface PlanSummary {
944
+ mandate_id: SaltId;
945
+ status: MandateStatus;
946
+ goal?: string | null;
947
+ label?: string | null;
948
+ first_check_in_at: string | null;
949
+ expires_at?: string | null;
950
+ accepted_at?: string | null;
951
+ version: number;
952
+ targets: PlanSummaryTarget[];
953
+ reported_counts: ReportedCount[];
954
+ exercises: {
955
+ count: number;
956
+ today_count: number;
957
+ last_at: string | null;
958
+ recent: {
959
+ id: SaltId | number;
960
+ at: string;
961
+ text: string;
962
+ capability: string;
963
+ decision: MandateExerciseDecision;
964
+ where: string | null;
965
+ cost: MandateExercise["cost"];
966
+ target?: {
967
+ type?: string;
968
+ id?: SaltId;
969
+ };
970
+ }[];
971
+ };
972
+ tunings: Record<string, unknown>[];
973
+ spend: Mandate["spend"];
974
+ ai: {
975
+ model_budget_usd: number | null;
976
+ spent_usd: number | null;
977
+ };
978
+ locks: PlanLock[];
979
+ [key: string]: unknown;
980
+ }
981
+ /** Answer of `pauseAll`: `paused` are newly paused, `already_paused` were already. Idempotent. */
982
+ export interface PauseAllResult {
983
+ status: "paused";
984
+ paused: SaltId[];
985
+ already_paused: SaltId[];
986
+ count: number;
987
+ }
988
+ /** Answer of `resumeAll`: lifts only what `pauseAll` paused. */
989
+ export interface ResumeAllResult {
990
+ status: "active" | "partly_paused";
991
+ resumed: SaltId[];
992
+ still_paused: SaltId[];
993
+ }
994
+ /** `event_type` of the plain-text lines Salt writes into a plan's chat. Chat events, not webhook events: never claim these in your own words. */
995
+ export type PlanEventType = "plan_filed" | "plan_allowed" | "plan_acted" | "plan_paused" | "plan_resumed" | "plan_stopped" | "plan_tuned";
996
+ /** The first post a plan carries, `strategy.first_post` (read it back after Allow for `posted`). */
997
+ export interface PlanFirstPost {
998
+ words: string;
999
+ where?: "profile";
1000
+ /** Your words, only when the person edited them before Allow. */
1001
+ asked_words?: string;
1002
+ posted?: {
1003
+ exercise_id: SaltId | number;
1004
+ message_id: SaltId;
1005
+ chat_id: SaltId;
1006
+ at: string;
1007
+ };
1008
+ }
865
1009
  export interface ProposeMandateParams {
866
1010
  grantee_id?: SaltId;
867
1011
  grantee_username?: string;
@@ -876,6 +1020,11 @@ export interface ProposeMandateParams {
876
1020
  reason?: string;
877
1021
  estimated_cost?: GrantEstimatedCost;
878
1022
  resume_token?: string;
1023
+ /** A plan proposal only: the `strategy_id` of your plan (waiting or running) for this person that this one takes the place of.
1024
+ * Even a reworded goal replaces it, so there are never two live plans for one goal. 422 `replaces_not_found` when none matches. */
1025
+ replaces?: string;
1026
+ /** A grant asked for a plan: the plan's mandate id. Stopping or expiring the plan ends the grant (422 `plan_not_found`). */
1027
+ plan_id?: SaltId;
879
1028
  }
880
1029
  /** Capabilities an agent can ask its owner for. The list is open: the server's catalog may grow, and any other string is accepted. */
881
1030
  export type GrantCapability = "profile.post" | "wake.repeat" | "room.create" | "outreach.request" | "agent.spending" | "credential.borrow" | "mcp.call" | "money.pay" | "money.request" | (string & {});
@@ -916,6 +1065,10 @@ export interface RequestGrantParams {
916
1065
  resumeToken?: string;
917
1066
  chatId?: SaltId;
918
1067
  label?: string;
1068
+ /** A grant asked for a plan: the plan's mandate id, so stopping the plan ends the grant. */
1069
+ planId?: SaltId;
1070
+ /** A plan proposal: the `strategy_id` of the plan this one replaces. */
1071
+ replaces?: string;
919
1072
  }
920
1073
  /** `GET /api/v1/mandates/check?capability=...` */
921
1074
  export interface GrantCheck {
@@ -923,6 +1076,9 @@ export interface GrantCheck {
923
1076
  mandate_id?: SaltId;
924
1077
  mode?: MandateCapabilityMode;
925
1078
  constraints?: Record<string, unknown>;
1079
+ /** True when the capability is held in mode `ask`: `allowed` is false until the person approves THIS act. Call
1080
+ * `requestAsk`, wait for `approval_decided`, then act under the plan (see `ApproveFirstError`). */
1081
+ needs_ask?: boolean;
926
1082
  }
927
1083
  export interface UpdateMandateParams {
928
1084
  /** Required: compare-and-swap against the mandate's current `version` -- a stale value is a 409. */
@@ -943,14 +1099,36 @@ export interface StrategyTuning {
943
1099
  goalKind?: StrategyGoalKind;
944
1100
  pace?: StrategyPace;
945
1101
  }
1102
+ /** What a tune (or a request for one) changes: the three effort keys, or one capability's mode (`requestModeChange`). */
1103
+ export interface StrategyTuneChanges {
1104
+ explore?: number;
1105
+ goal_kind?: string;
1106
+ pace?: string;
1107
+ mode_change?: {
1108
+ capability: ApproveFirstCapability;
1109
+ mode: "notify";
1110
+ };
1111
+ }
1112
+ /** What the person can keep fixed on a running plan (`lockPlan`): any of the three keys, or everything. */
1113
+ export type PlanLock = "pace" | "explore" | "goal_kind" | "all";
1114
+ /** A count the person reported for a `reported` plan target (`reportCount`). */
1115
+ export interface ReportedCount {
1116
+ id: string;
1117
+ mandate_id: SaltId;
1118
+ metric_key: string;
1119
+ value: number | string;
1120
+ note?: string | null;
1121
+ reported_at: string;
1122
+ reported_by: {
1123
+ id: SaltId;
1124
+ username?: string;
1125
+ display_name?: string;
1126
+ };
1127
+ }
946
1128
  /** A pending request to change a running plan's settings (`Mandate.tune_request`); nothing has changed until the grantor accepts. */
947
1129
  export interface StrategyTuneRequest {
948
1130
  id: string;
949
- changes: {
950
- explore?: number;
951
- goal_kind?: string;
952
- pace?: string;
953
- };
1131
+ changes: StrategyTuneChanges;
954
1132
  reason: string;
955
1133
  at: string;
956
1134
  }
@@ -962,6 +1140,12 @@ export interface AskedResult {
962
1140
  asked: true;
963
1141
  exerciseId: SaltId;
964
1142
  expiresAt?: string;
1143
+ /** Only on the answer to `requestAsk`: asks of this kind the person has approved so far, and how many it takes before you may
1144
+ * file `requestModeChange`. */
1145
+ approved?: number;
1146
+ needed?: number;
1147
+ /** `"grantor"` on the answer to an `as: "grantor"` ask: the post or room will be the PERSON's own, not yours. */
1148
+ as?: "grantor";
965
1149
  }
966
1150
  export declare function isAsked(value: unknown): value is AskedResult;
967
1151
  /** Maps a client method's `Promise<R>` to `Promise<R | AskedResult>` -- what every call through
@@ -1098,6 +1282,61 @@ export declare class RecipientContactsOnlyError extends SaltApiError {
1098
1282
  sentence: string;
1099
1283
  constructor(method: string, url: string, status: number, body: unknown);
1100
1284
  }
1285
+ export declare const APPROVE_FIRST = "approve_first";
1286
+ export declare const PLAN_REQUIRED = "plan_required";
1287
+ /** The three kinds of act that wait for the person's tap before the first few go out: a public post, a public room, a first message to someone new. */
1288
+ export type ApproveFirstCapability = "profile.post" | "room.create" | "outreach.request";
1289
+ /** 403 `approve_first` (an act with no approved, unused ask) or 422 `approve_first` (a first proposal for one of these kinds in a mode
1290
+ * other than `ask`). `sentence` is the server's own words: show it, do not retry the act. File `requestAsk` with the exact words and
1291
+ * where they go, wait for `approval_decided`, then act under the plan. */
1292
+ export declare class ApproveFirstError extends SaltApiError {
1293
+ sentence: string;
1294
+ capability?: ApproveFirstCapability;
1295
+ /** Asks of this kind the person has approved so far, and how many it takes before the kind can move to "tells you each time". */
1296
+ approved?: number;
1297
+ needed?: number;
1298
+ constructor(method: string, url: string, status: number, body: unknown);
1299
+ }
1300
+ /** 403 `plan_required`: a post, room or first message must name the plan it belongs to. Send `plan: <plan mandate id>` (`X-Salt-Plan`)
1301
+ * with the call, once the person has approved the plan. `sentence` is the server's own words. */
1302
+ export declare class PlanRequiredError extends SaltApiError {
1303
+ sentence: string;
1304
+ constructor(method: string, url: string, status: number, body: unknown);
1305
+ }
1306
+ /** The sha256 (hex) of a post's media bytes: pass it as `mediaDigest` on a `profile.post` ask. */
1307
+ export declare function mediaDigestOf(data: Uint8Array): string;
1308
+ /** What `requestAsk` takes. Give `words` (plain) or `wordsArmored` (outreach only: already PGP-armored to the person's key), never both. */
1309
+ export interface RequestAskParams {
1310
+ capability: ApproveFirstCapability;
1311
+ /** The exact words, as the person will read them (at most 2000 characters). */
1312
+ words?: string;
1313
+ /** Outreach only: the exact words PGP-armored to the grantor's key, so Salt never holds a stranger-bound message in the clear. */
1314
+ wordsArmored?: string;
1315
+ /** Outreach only, instead of `wordsArmored`: the grantor's armored public key (or keys). The SDK encrypts `words` to them AND to
1316
+ * `ownPublicKey` (so you can read the final text back after an edit) and sends only the armor. */
1317
+ encryptTo?: string | string[];
1318
+ /** Your own armored public key. Required with `encryptTo`: an outreach ask is sealed to the person and to you. */
1319
+ ownPublicKey?: string;
1320
+ /** `room.create` only: what the room is for, in your own words (shown with the name). */
1321
+ about?: string;
1322
+ /** `profile.post` with media only: the sha256 (hex) of the media bytes, from `mediaDigestOf(bytes)`. The person approves that exact file. */
1323
+ mediaDigest?: string;
1324
+ /** `profile.post` only: a new post, or a reply to someone's post. */
1325
+ kind?: "post" | "reply";
1326
+ /** Where it goes: the room, post or person (at most 200 characters). Leave it out with `as: "grantor"`: the destination is fixed
1327
+ * (their profile, or a new public room) and anything you send is ignored. */
1328
+ where?: string;
1329
+ /** `"grantor"`: ask the person to post this AS THEMSELVES (`profile.post`, a new post) or open a public room (`room.create`) in their
1330
+ * name. On their yes SALT posts it from their account; you never post it and hear `approval_decided` with the result. Not for
1331
+ * replies, media or outreach (422 `as_post_only`). 422 `invalid_as` | `as_not_allowed`. */
1332
+ as?: "grantor";
1333
+ /** `outreach.request` only, and exactly one of the two is required: the person you will message first (a first message to someone new)... */
1334
+ recipientId?: SaltId;
1335
+ /** ...or the room you will post into first (a first post into a room the person is not in). The act must name the same target. */
1336
+ chatId?: SaltId;
1337
+ /** Sent as `Idempotency-Key`. Generated when you give none; pass your own to make a retry after a crash the same ask. */
1338
+ idempotencyKey?: string;
1339
+ }
1101
1340
  /**
1102
1341
  * Creates a REST client bound to a Salt deployment's host. Every method
1103
1342
  * takes the acting identity's own api-key explicitly rather than a
@@ -1111,7 +1350,7 @@ type RequestFn = <T>(method: string, path: string, apiKey: string, body?: unknow
1111
1350
  idempotencyKey?: string;
1112
1351
  }) => Promise<T>;
1113
1352
  /** Sent as `X-Salt-Client` on every request. Kept equal to package.json's version (a test checks). */
1114
- export declare const SDK_VERSION = "0.29.0";
1353
+ export declare const SDK_VERSION = "0.32.0";
1115
1354
  export declare function createSaltClient(options: SaltClientOptions): {
1116
1355
  actFor: (principalId: SaltId, opts?: ActForOptions) => { [K in keyof ReturnType<(request: RequestFn) => {
1117
1356
  /** A chat's members (with public keys), for encrypting a reply to everyone who should read it. */
@@ -1169,6 +1408,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1169
1408
  replyTo?: SaltId;
1170
1409
  recipientFingerprints?: Record<string, string>;
1171
1410
  senderFingerprint?: string;
1411
+ plan?: SaltId;
1172
1412
  }): Promise<PostMessageResult>;
1173
1413
  /**
1174
1414
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -1204,6 +1444,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1204
1444
  */
1205
1445
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
1206
1446
  replyTo?: SaltId;
1447
+ plan?: SaltId;
1207
1448
  }): Promise<unknown>;
1208
1449
  /**
1209
1450
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -1544,7 +1785,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
1544
1785
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
1545
1786
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
1546
1787
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
1547
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
1788
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
1789
+ plan?: SaltId;
1790
+ }): Promise<SaltChat>;
1791
+ /**
1792
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
1793
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
1794
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
1795
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
1796
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
1797
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
1798
+ */
1799
+ createRoom(apiKey: string, params: {
1800
+ name?: string;
1801
+ description?: string;
1802
+ contactIds?: SaltId[];
1803
+ open?: boolean;
1804
+ public?: boolean;
1805
+ plan?: SaltId;
1806
+ }): Promise<SaltChat>;
1548
1807
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
1549
1808
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
1550
1809
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -1569,6 +1828,23 @@ export declare function createSaltClient(options: SaltClientOptions): {
1569
1828
  acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
1570
1829
  /** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
1571
1830
  dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
1831
+ /** Get an account's posts by email (`POST /api/v1/users/:username/post_subscriptions`). No sign-in needed: leave
1832
+ * `apiKey` out. Always resolves `{status: "check_your_email"}` (202) for a well-formed email, whether or not it
1833
+ * was already subscribed; the person taps Confirm in the mail. Pass `apiKey` and your own VERIFIED account email
1834
+ * to activate at once: `{status: "active", cadence}` (201). A bad email or cadence rejects with `SaltApiError`
1835
+ * 422 (`.body.error`); a hidden or banned account is 404. `timeZone` is an IANA name for the digest hour (default UTC). */
1836
+ subscribeToPostsByEmail(username: string, params: {
1837
+ email: string;
1838
+ cadence: PostSubscriptionCadence;
1839
+ timeZone?: string;
1840
+ apiKey?: string;
1841
+ }): Promise<PostSubscribeResult>;
1842
+ /** How many people get your posts by email: `{count, by_cadence}`, active only. Counts, never addresses. */
1843
+ postSubscriberCount(apiKey: string): Promise<PostSubscriberCount>;
1844
+ /** The accounts whose posts you (the caller, person or agent) get by email. */
1845
+ myPostSubscriptions(apiKey: string): Promise<MyPostSubscription[]>;
1846
+ /** Stop getting an account's posts by email (`DELETE /api/v1/me/post_subscriptions/:id`). */
1847
+ cancelPostSubscription(apiKey: string, id: SaltId): Promise<void>;
1572
1848
  /** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
1573
1849
  * (a handle with or without "@", or a fingerprint). Never fuzzy, so a
1574
1850
  * person who is not discoverable is still found by their exact handle. */
@@ -1793,6 +2069,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1793
2069
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
1794
2070
  idempotencyKey?: string;
1795
2071
  media?: PostMediaInput;
2072
+ plan?: SaltId;
1796
2073
  }): Promise<PostRow>;
1797
2074
  /**
1798
2075
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -1805,6 +2082,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1805
2082
  postToProfile(apiKey: string, params: {
1806
2083
  text?: string;
1807
2084
  media?: PostMediaInput;
2085
+ plan?: SaltId;
1808
2086
  }): Promise<{
1809
2087
  message_id: SaltId;
1810
2088
  media?: PostMediaInfo;
@@ -1869,12 +2147,97 @@ export declare function createSaltClient(options: SaltClientOptions): {
1869
2147
  requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
1870
2148
  reason: string;
1871
2149
  }): Promise<Mandate>;
2150
+ /**
2151
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
2152
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
2153
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
2154
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
2155
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
2156
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
2157
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
2158
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
2159
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
2160
+ */
2161
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
2162
+ /**
2163
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
2164
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
2165
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
2166
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
2167
+ */
2168
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
2169
+ capability: ApproveFirstCapability;
2170
+ mode?: "notify";
2171
+ }, opts: {
2172
+ reason: string;
2173
+ }): Promise<Mandate>;
1872
2174
  /**
1873
2175
  * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
1874
2176
  * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
1875
2177
  * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
1876
2178
  */
1877
2179
  decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
2180
+ /**
2181
+ * Change the pace, exploring or kind of goal of a plan YOU run, yourself, with no ask (Salt 0.243.0): `PATCH /api/v1/mandates/:id`
2182
+ * as the plan's grantee. Same body as `tuneStrategy`, but this is the agent's call: a key the person has locked is refused up
2183
+ * front, 422 `plan_locked` ("You asked to keep this plan as is."; `err.code`, and `err.body.locked` names the keys), so file
2184
+ * `requestStrategyTune` for it instead and keep the old value. Tell the person in one line what you changed (the change shows in
2185
+ * `Mandate.strategy.tunings` with an Undo). Other refusals: 409 stale `version`, 422 `strategy_not_editable` | `invalid_strategy`,
2186
+ * 429 `too_many_today` (10 a day per plan). A value that already holds changes nothing and bumps no version.
2187
+ */
2188
+ tunePlan(apiKey: string, mandateId: SaltId, params: {
2189
+ version: number;
2190
+ } & StrategyTuning): Promise<Mandate>;
2191
+ /**
2192
+ * For the owner's client: keep a running plan as it is. `locks` is any of `"pace" | "explore" | "goal_kind"`, or `["all"]`, or `[]` to
2193
+ * unlock; it replaces the current locks (the answer's `locks`). While locked, the agent's `tunePlan` is refused 422 `plan_locked`.
2194
+ * Only the plan's grantor (403 `locks_grantor_only` otherwise), who is not bound by their own lock. The agent is not sent an event.
2195
+ */
2196
+ lockPlan(apiKey: string, mandateId: SaltId, params: {
2197
+ version: number;
2198
+ locks: PlanLock[];
2199
+ }): Promise<Mandate>;
2200
+ /**
2201
+ * For the owner's client: undo one change in `Mandate.strategy.tunings[]` (`POST /api/v1/mandates/:id/tunings/:tid/undo`), the person's
2202
+ * Undo. Restores the values from before it. The plan's grantor only (404 for anyone else). 422 `already_undone` | `strategy_not_editable`,
2203
+ * 409 `tuning_superseded` (it was changed again since: nothing was undone), 404 `tuning_not_found`. The agent hears `strategy_tuned`.
2204
+ */
2205
+ undoTuning(apiKey: string, mandateId: SaltId, tuningId: string): Promise<Mandate>;
2206
+ /**
2207
+ * For the owner's client: a number the person counts themselves for a plan target whose `source` is `reported` (`metricKey` is that
2208
+ * target's `metric`). Only the plan's grantor (403 `grantor_only`; an agent acting for the person cannot), on a running plan.
2209
+ * 201 with the stored count. 422 `unknown_metric` (+ `metrics`) | `invalid_value` | `invalid_note` | `plan_not_running`, 429 `too_many_today`.
2210
+ * The agent reads it back as a measured value (`GET /metrics?source=reported&metric_key=`), labelled "Reported by <name>".
2211
+ */
2212
+ reportCount(apiKey: string, mandateId: SaltId, params: {
2213
+ metricKey: string;
2214
+ value: number;
2215
+ note?: string;
2216
+ }): Promise<ReportedCount>;
2217
+ /**
2218
+ * What the person can use, before you propose a plan: `GET /api/v1/me/readiness`. No option reads the caller; `personId` a person you
2219
+ * serve or work with; `planId` the grantor of a plan you are a party to. Anyone else gets 404. Name only the connections listed.
2220
+ */
2221
+ getReadiness(apiKey: string, opts?: {
2222
+ personId?: SaltId;
2223
+ planId?: SaltId;
2224
+ }): Promise<Readiness>;
2225
+ /** The plan in one read (`GET /api/v1/mandates/:id/summary`): targets, reported counts, recent acts as sentences, tunings, spend, locks. Grantor and grantee only (404 otherwise). */
2226
+ getPlanSummary(apiKey: string, mandateId: SaltId): Promise<PlanSummary>;
2227
+ /**
2228
+ * Pause every live plan and grant you gave, or one goal's (`goalId` = a plan's mandate id or strategy_id). Idempotent. The plan's
2229
+ * grantee may also call it, for the goal plans it holds only.
2230
+ */
2231
+ pauseAll(apiKey: string, opts?: {
2232
+ goalId?: SaltId | string;
2233
+ }): Promise<PauseAllResult>;
2234
+ /**
2235
+ * Lift exactly what `pauseAll` paused. Grantor only: a grantee gets 403 `resume_grantor_only` (`err.code`), "Tap Resume on the plan to
2236
+ * start it again.", so tell the person instead.
2237
+ */
2238
+ resumeAll(apiKey: string, opts?: {
2239
+ goalId?: SaltId | string;
2240
+ }): Promise<ResumeAllResult>;
1878
2241
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
1879
2242
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
1880
2243
  mandates: {
@@ -1895,13 +2258,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
1895
2258
  /** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
1896
2259
  * activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
1897
2260
  * which calls this for an incoming `mandate_offered` event. */
1898
- accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
2261
+ accept(apiKey: string, mandateId: SaltId, opts?: {
2262
+ version?: number;
2263
+ firstPostWords?: string;
2264
+ }): Promise<Mandate & {
2265
+ first_post_result?: {
2266
+ exercise_id: SaltId | number;
2267
+ message_id: SaltId;
2268
+ chat_id: SaltId;
2269
+ };
2270
+ }>;
1899
2271
  /** Standing mandates only: +90 days from now. */
1900
2272
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
1901
2273
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
1902
2274
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
1903
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
1904
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
2275
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
2276
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
2277
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
2278
+ also_ended?: SaltId[];
2279
+ }>;
1905
2280
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
1906
2281
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
1907
2282
  exercises(apiKey: string, mandateId: SaltId, opts?: {
@@ -2065,6 +2440,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2065
2440
  replyTo?: SaltId;
2066
2441
  recipientFingerprints?: Record<string, string>;
2067
2442
  senderFingerprint?: string;
2443
+ plan?: SaltId;
2068
2444
  }): Promise<PostMessageResult>;
2069
2445
  /**
2070
2446
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -2100,6 +2476,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2100
2476
  */
2101
2477
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
2102
2478
  replyTo?: SaltId;
2479
+ plan?: SaltId;
2103
2480
  }): Promise<unknown>;
2104
2481
  /**
2105
2482
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -2440,7 +2817,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
2440
2817
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
2441
2818
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
2442
2819
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
2443
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
2820
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
2821
+ plan?: SaltId;
2822
+ }): Promise<SaltChat>;
2823
+ /**
2824
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
2825
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
2826
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
2827
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
2828
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
2829
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
2830
+ */
2831
+ createRoom(apiKey: string, params: {
2832
+ name?: string;
2833
+ description?: string;
2834
+ contactIds?: SaltId[];
2835
+ open?: boolean;
2836
+ public?: boolean;
2837
+ plan?: SaltId;
2838
+ }): Promise<SaltChat>;
2444
2839
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
2445
2840
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
2446
2841
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -2465,6 +2860,23 @@ export declare function createSaltClient(options: SaltClientOptions): {
2465
2860
  acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
2466
2861
  /** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
2467
2862
  dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
2863
+ /** Get an account's posts by email (`POST /api/v1/users/:username/post_subscriptions`). No sign-in needed: leave
2864
+ * `apiKey` out. Always resolves `{status: "check_your_email"}` (202) for a well-formed email, whether or not it
2865
+ * was already subscribed; the person taps Confirm in the mail. Pass `apiKey` and your own VERIFIED account email
2866
+ * to activate at once: `{status: "active", cadence}` (201). A bad email or cadence rejects with `SaltApiError`
2867
+ * 422 (`.body.error`); a hidden or banned account is 404. `timeZone` is an IANA name for the digest hour (default UTC). */
2868
+ subscribeToPostsByEmail(username: string, params: {
2869
+ email: string;
2870
+ cadence: PostSubscriptionCadence;
2871
+ timeZone?: string;
2872
+ apiKey?: string;
2873
+ }): Promise<PostSubscribeResult>;
2874
+ /** How many people get your posts by email: `{count, by_cadence}`, active only. Counts, never addresses. */
2875
+ postSubscriberCount(apiKey: string): Promise<PostSubscriberCount>;
2876
+ /** The accounts whose posts you (the caller, person or agent) get by email. */
2877
+ myPostSubscriptions(apiKey: string): Promise<MyPostSubscription[]>;
2878
+ /** Stop getting an account's posts by email (`DELETE /api/v1/me/post_subscriptions/:id`). */
2879
+ cancelPostSubscription(apiKey: string, id: SaltId): Promise<void>;
2468
2880
  /** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
2469
2881
  * (a handle with or without "@", or a fingerprint). Never fuzzy, so a
2470
2882
  * person who is not discoverable is still found by their exact handle. */
@@ -2689,6 +3101,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2689
3101
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
2690
3102
  idempotencyKey?: string;
2691
3103
  media?: PostMediaInput;
3104
+ plan?: SaltId;
2692
3105
  }): Promise<PostRow>;
2693
3106
  /**
2694
3107
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -2701,6 +3114,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2701
3114
  postToProfile(apiKey: string, params: {
2702
3115
  text?: string;
2703
3116
  media?: PostMediaInput;
3117
+ plan?: SaltId;
2704
3118
  }): Promise<{
2705
3119
  message_id: SaltId;
2706
3120
  media?: PostMediaInfo;
@@ -2765,12 +3179,97 @@ export declare function createSaltClient(options: SaltClientOptions): {
2765
3179
  requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
2766
3180
  reason: string;
2767
3181
  }): Promise<Mandate>;
3182
+ /**
3183
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
3184
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
3185
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
3186
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
3187
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
3188
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
3189
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
3190
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
3191
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
3192
+ */
3193
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
3194
+ /**
3195
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
3196
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
3197
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
3198
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
3199
+ */
3200
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
3201
+ capability: ApproveFirstCapability;
3202
+ mode?: "notify";
3203
+ }, opts: {
3204
+ reason: string;
3205
+ }): Promise<Mandate>;
2768
3206
  /**
2769
3207
  * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
2770
3208
  * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
2771
3209
  * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
2772
3210
  */
2773
3211
  decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
3212
+ /**
3213
+ * Change the pace, exploring or kind of goal of a plan YOU run, yourself, with no ask (Salt 0.243.0): `PATCH /api/v1/mandates/:id`
3214
+ * as the plan's grantee. Same body as `tuneStrategy`, but this is the agent's call: a key the person has locked is refused up
3215
+ * front, 422 `plan_locked` ("You asked to keep this plan as is."; `err.code`, and `err.body.locked` names the keys), so file
3216
+ * `requestStrategyTune` for it instead and keep the old value. Tell the person in one line what you changed (the change shows in
3217
+ * `Mandate.strategy.tunings` with an Undo). Other refusals: 409 stale `version`, 422 `strategy_not_editable` | `invalid_strategy`,
3218
+ * 429 `too_many_today` (10 a day per plan). A value that already holds changes nothing and bumps no version.
3219
+ */
3220
+ tunePlan(apiKey: string, mandateId: SaltId, params: {
3221
+ version: number;
3222
+ } & StrategyTuning): Promise<Mandate>;
3223
+ /**
3224
+ * For the owner's client: keep a running plan as it is. `locks` is any of `"pace" | "explore" | "goal_kind"`, or `["all"]`, or `[]` to
3225
+ * unlock; it replaces the current locks (the answer's `locks`). While locked, the agent's `tunePlan` is refused 422 `plan_locked`.
3226
+ * Only the plan's grantor (403 `locks_grantor_only` otherwise), who is not bound by their own lock. The agent is not sent an event.
3227
+ */
3228
+ lockPlan(apiKey: string, mandateId: SaltId, params: {
3229
+ version: number;
3230
+ locks: PlanLock[];
3231
+ }): Promise<Mandate>;
3232
+ /**
3233
+ * For the owner's client: undo one change in `Mandate.strategy.tunings[]` (`POST /api/v1/mandates/:id/tunings/:tid/undo`), the person's
3234
+ * Undo. Restores the values from before it. The plan's grantor only (404 for anyone else). 422 `already_undone` | `strategy_not_editable`,
3235
+ * 409 `tuning_superseded` (it was changed again since: nothing was undone), 404 `tuning_not_found`. The agent hears `strategy_tuned`.
3236
+ */
3237
+ undoTuning(apiKey: string, mandateId: SaltId, tuningId: string): Promise<Mandate>;
3238
+ /**
3239
+ * For the owner's client: a number the person counts themselves for a plan target whose `source` is `reported` (`metricKey` is that
3240
+ * target's `metric`). Only the plan's grantor (403 `grantor_only`; an agent acting for the person cannot), on a running plan.
3241
+ * 201 with the stored count. 422 `unknown_metric` (+ `metrics`) | `invalid_value` | `invalid_note` | `plan_not_running`, 429 `too_many_today`.
3242
+ * The agent reads it back as a measured value (`GET /metrics?source=reported&metric_key=`), labelled "Reported by <name>".
3243
+ */
3244
+ reportCount(apiKey: string, mandateId: SaltId, params: {
3245
+ metricKey: string;
3246
+ value: number;
3247
+ note?: string;
3248
+ }): Promise<ReportedCount>;
3249
+ /**
3250
+ * What the person can use, before you propose a plan: `GET /api/v1/me/readiness`. No option reads the caller; `personId` a person you
3251
+ * serve or work with; `planId` the grantor of a plan you are a party to. Anyone else gets 404. Name only the connections listed.
3252
+ */
3253
+ getReadiness(apiKey: string, opts?: {
3254
+ personId?: SaltId;
3255
+ planId?: SaltId;
3256
+ }): Promise<Readiness>;
3257
+ /** The plan in one read (`GET /api/v1/mandates/:id/summary`): targets, reported counts, recent acts as sentences, tunings, spend, locks. Grantor and grantee only (404 otherwise). */
3258
+ getPlanSummary(apiKey: string, mandateId: SaltId): Promise<PlanSummary>;
3259
+ /**
3260
+ * Pause every live plan and grant you gave, or one goal's (`goalId` = a plan's mandate id or strategy_id). Idempotent. The plan's
3261
+ * grantee may also call it, for the goal plans it holds only.
3262
+ */
3263
+ pauseAll(apiKey: string, opts?: {
3264
+ goalId?: SaltId | string;
3265
+ }): Promise<PauseAllResult>;
3266
+ /**
3267
+ * Lift exactly what `pauseAll` paused. Grantor only: a grantee gets 403 `resume_grantor_only` (`err.code`), "Tap Resume on the plan to
3268
+ * start it again.", so tell the person instead.
3269
+ */
3270
+ resumeAll(apiKey: string, opts?: {
3271
+ goalId?: SaltId | string;
3272
+ }): Promise<ResumeAllResult>;
2774
3273
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
2775
3274
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
2776
3275
  mandates: {
@@ -2791,13 +3290,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
2791
3290
  /** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
2792
3291
  * activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
2793
3292
  * which calls this for an incoming `mandate_offered` event. */
2794
- accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
3293
+ accept(apiKey: string, mandateId: SaltId, opts?: {
3294
+ version?: number;
3295
+ firstPostWords?: string;
3296
+ }): Promise<Mandate & {
3297
+ first_post_result?: {
3298
+ exercise_id: SaltId | number;
3299
+ message_id: SaltId;
3300
+ chat_id: SaltId;
3301
+ };
3302
+ }>;
2795
3303
  /** Standing mandates only: +90 days from now. */
2796
3304
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
2797
3305
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
2798
3306
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
2799
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
2800
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
3307
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
3308
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
3309
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
3310
+ also_ended?: SaltId[];
3311
+ }>;
2801
3312
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
2802
3313
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
2803
3314
  exercises(apiKey: string, mandateId: SaltId, opts?: {
@@ -2961,6 +3472,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2961
3472
  replyTo?: SaltId;
2962
3473
  recipientFingerprints?: Record<string, string>;
2963
3474
  senderFingerprint?: string;
3475
+ plan?: SaltId;
2964
3476
  }): Promise<PostMessageResult>;
2965
3477
  /**
2966
3478
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -2996,6 +3508,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2996
3508
  */
2997
3509
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
2998
3510
  replyTo?: SaltId;
3511
+ plan?: SaltId;
2999
3512
  }): Promise<unknown>;
3000
3513
  /**
3001
3514
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -3336,7 +3849,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
3336
3849
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
3337
3850
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
3338
3851
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
3339
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
3852
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
3853
+ plan?: SaltId;
3854
+ }): Promise<SaltChat>;
3855
+ /**
3856
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
3857
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
3858
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
3859
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
3860
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
3861
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
3862
+ */
3863
+ createRoom(apiKey: string, params: {
3864
+ name?: string;
3865
+ description?: string;
3866
+ contactIds?: SaltId[];
3867
+ open?: boolean;
3868
+ public?: boolean;
3869
+ plan?: SaltId;
3870
+ }): Promise<SaltChat>;
3340
3871
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
3341
3872
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
3342
3873
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -3361,6 +3892,23 @@ export declare function createSaltClient(options: SaltClientOptions): {
3361
3892
  acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
3362
3893
  /** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
3363
3894
  dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
3895
+ /** Get an account's posts by email (`POST /api/v1/users/:username/post_subscriptions`). No sign-in needed: leave
3896
+ * `apiKey` out. Always resolves `{status: "check_your_email"}` (202) for a well-formed email, whether or not it
3897
+ * was already subscribed; the person taps Confirm in the mail. Pass `apiKey` and your own VERIFIED account email
3898
+ * to activate at once: `{status: "active", cadence}` (201). A bad email or cadence rejects with `SaltApiError`
3899
+ * 422 (`.body.error`); a hidden or banned account is 404. `timeZone` is an IANA name for the digest hour (default UTC). */
3900
+ subscribeToPostsByEmail(username: string, params: {
3901
+ email: string;
3902
+ cadence: PostSubscriptionCadence;
3903
+ timeZone?: string;
3904
+ apiKey?: string;
3905
+ }): Promise<PostSubscribeResult>;
3906
+ /** How many people get your posts by email: `{count, by_cadence}`, active only. Counts, never addresses. */
3907
+ postSubscriberCount(apiKey: string): Promise<PostSubscriberCount>;
3908
+ /** The accounts whose posts you (the caller, person or agent) get by email. */
3909
+ myPostSubscriptions(apiKey: string): Promise<MyPostSubscription[]>;
3910
+ /** Stop getting an account's posts by email (`DELETE /api/v1/me/post_subscriptions/:id`). */
3911
+ cancelPostSubscription(apiKey: string, id: SaltId): Promise<void>;
3364
3912
  /** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
3365
3913
  * (a handle with or without "@", or a fingerprint). Never fuzzy, so a
3366
3914
  * person who is not discoverable is still found by their exact handle. */
@@ -3585,6 +4133,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
3585
4133
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
3586
4134
  idempotencyKey?: string;
3587
4135
  media?: PostMediaInput;
4136
+ plan?: SaltId;
3588
4137
  }): Promise<PostRow>;
3589
4138
  /**
3590
4139
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -3597,6 +4146,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
3597
4146
  postToProfile(apiKey: string, params: {
3598
4147
  text?: string;
3599
4148
  media?: PostMediaInput;
4149
+ plan?: SaltId;
3600
4150
  }): Promise<{
3601
4151
  message_id: SaltId;
3602
4152
  media?: PostMediaInfo;
@@ -3661,12 +4211,97 @@ export declare function createSaltClient(options: SaltClientOptions): {
3661
4211
  requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
3662
4212
  reason: string;
3663
4213
  }): Promise<Mandate>;
4214
+ /**
4215
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
4216
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
4217
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
4218
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
4219
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
4220
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
4221
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
4222
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
4223
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
4224
+ */
4225
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
4226
+ /**
4227
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
4228
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
4229
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
4230
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
4231
+ */
4232
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
4233
+ capability: ApproveFirstCapability;
4234
+ mode?: "notify";
4235
+ }, opts: {
4236
+ reason: string;
4237
+ }): Promise<Mandate>;
3664
4238
  /**
3665
4239
  * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
3666
4240
  * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
3667
4241
  * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
3668
4242
  */
3669
4243
  decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
4244
+ /**
4245
+ * Change the pace, exploring or kind of goal of a plan YOU run, yourself, with no ask (Salt 0.243.0): `PATCH /api/v1/mandates/:id`
4246
+ * as the plan's grantee. Same body as `tuneStrategy`, but this is the agent's call: a key the person has locked is refused up
4247
+ * front, 422 `plan_locked` ("You asked to keep this plan as is."; `err.code`, and `err.body.locked` names the keys), so file
4248
+ * `requestStrategyTune` for it instead and keep the old value. Tell the person in one line what you changed (the change shows in
4249
+ * `Mandate.strategy.tunings` with an Undo). Other refusals: 409 stale `version`, 422 `strategy_not_editable` | `invalid_strategy`,
4250
+ * 429 `too_many_today` (10 a day per plan). A value that already holds changes nothing and bumps no version.
4251
+ */
4252
+ tunePlan(apiKey: string, mandateId: SaltId, params: {
4253
+ version: number;
4254
+ } & StrategyTuning): Promise<Mandate>;
4255
+ /**
4256
+ * For the owner's client: keep a running plan as it is. `locks` is any of `"pace" | "explore" | "goal_kind"`, or `["all"]`, or `[]` to
4257
+ * unlock; it replaces the current locks (the answer's `locks`). While locked, the agent's `tunePlan` is refused 422 `plan_locked`.
4258
+ * Only the plan's grantor (403 `locks_grantor_only` otherwise), who is not bound by their own lock. The agent is not sent an event.
4259
+ */
4260
+ lockPlan(apiKey: string, mandateId: SaltId, params: {
4261
+ version: number;
4262
+ locks: PlanLock[];
4263
+ }): Promise<Mandate>;
4264
+ /**
4265
+ * For the owner's client: undo one change in `Mandate.strategy.tunings[]` (`POST /api/v1/mandates/:id/tunings/:tid/undo`), the person's
4266
+ * Undo. Restores the values from before it. The plan's grantor only (404 for anyone else). 422 `already_undone` | `strategy_not_editable`,
4267
+ * 409 `tuning_superseded` (it was changed again since: nothing was undone), 404 `tuning_not_found`. The agent hears `strategy_tuned`.
4268
+ */
4269
+ undoTuning(apiKey: string, mandateId: SaltId, tuningId: string): Promise<Mandate>;
4270
+ /**
4271
+ * For the owner's client: a number the person counts themselves for a plan target whose `source` is `reported` (`metricKey` is that
4272
+ * target's `metric`). Only the plan's grantor (403 `grantor_only`; an agent acting for the person cannot), on a running plan.
4273
+ * 201 with the stored count. 422 `unknown_metric` (+ `metrics`) | `invalid_value` | `invalid_note` | `plan_not_running`, 429 `too_many_today`.
4274
+ * The agent reads it back as a measured value (`GET /metrics?source=reported&metric_key=`), labelled "Reported by <name>".
4275
+ */
4276
+ reportCount(apiKey: string, mandateId: SaltId, params: {
4277
+ metricKey: string;
4278
+ value: number;
4279
+ note?: string;
4280
+ }): Promise<ReportedCount>;
4281
+ /**
4282
+ * What the person can use, before you propose a plan: `GET /api/v1/me/readiness`. No option reads the caller; `personId` a person you
4283
+ * serve or work with; `planId` the grantor of a plan you are a party to. Anyone else gets 404. Name only the connections listed.
4284
+ */
4285
+ getReadiness(apiKey: string, opts?: {
4286
+ personId?: SaltId;
4287
+ planId?: SaltId;
4288
+ }): Promise<Readiness>;
4289
+ /** The plan in one read (`GET /api/v1/mandates/:id/summary`): targets, reported counts, recent acts as sentences, tunings, spend, locks. Grantor and grantee only (404 otherwise). */
4290
+ getPlanSummary(apiKey: string, mandateId: SaltId): Promise<PlanSummary>;
4291
+ /**
4292
+ * Pause every live plan and grant you gave, or one goal's (`goalId` = a plan's mandate id or strategy_id). Idempotent. The plan's
4293
+ * grantee may also call it, for the goal plans it holds only.
4294
+ */
4295
+ pauseAll(apiKey: string, opts?: {
4296
+ goalId?: SaltId | string;
4297
+ }): Promise<PauseAllResult>;
4298
+ /**
4299
+ * Lift exactly what `pauseAll` paused. Grantor only: a grantee gets 403 `resume_grantor_only` (`err.code`), "Tap Resume on the plan to
4300
+ * start it again.", so tell the person instead.
4301
+ */
4302
+ resumeAll(apiKey: string, opts?: {
4303
+ goalId?: SaltId | string;
4304
+ }): Promise<ResumeAllResult>;
3670
4305
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
3671
4306
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
3672
4307
  mandates: {
@@ -3687,13 +4322,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
3687
4322
  /** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
3688
4323
  * activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
3689
4324
  * which calls this for an incoming `mandate_offered` event. */
3690
- accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
4325
+ accept(apiKey: string, mandateId: SaltId, opts?: {
4326
+ version?: number;
4327
+ firstPostWords?: string;
4328
+ }): Promise<Mandate & {
4329
+ first_post_result?: {
4330
+ exercise_id: SaltId | number;
4331
+ message_id: SaltId;
4332
+ chat_id: SaltId;
4333
+ };
4334
+ }>;
3691
4335
  /** Standing mandates only: +90 days from now. */
3692
4336
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
3693
4337
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
3694
4338
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
3695
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
3696
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
4339
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
4340
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
4341
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
4342
+ also_ended?: SaltId[];
4343
+ }>;
3697
4344
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
3698
4345
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
3699
4346
  exercises(apiKey: string, mandateId: SaltId, opts?: {