@ghostlytools/cli 1.3.2 → 1.3.4
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 +7 -7
- package/SKILL.md +2 -1
- package/dist/assets/{api-SYPJgFRU.js → api-BCwaCbKh.js} +2 -2
- package/dist/assets/{api-aup3Amud.js → api-Bp_hWAiU.js} +100 -20
- package/dist/assets/api-Bp_hWAiU.js.map +1 -0
- package/dist/assets/{apiKit-DYkVEs6r.js → apiKit-3MLUyuhL.js} +21 -6
- package/dist/assets/apiKit-3MLUyuhL.js.map +1 -0
- package/dist/assets/{apps-DcZKu29s.js → apps-B6gqk4GD.js} +1 -1
- package/dist/assets/{apps-Rbk2HHXb.js → apps-BXw3Ui_3.js} +91 -24
- package/dist/assets/apps-BXw3Ui_3.js.map +1 -0
- package/dist/assets/{arkade-CuWlNnCz.js → arkade-CyplNY_v.js} +2 -2
- package/dist/assets/{arkade-CuWlNnCz.js.map → arkade-CyplNY_v.js.map} +1 -1
- package/dist/assets/{backup-CJWLDHuS.js → backup-BGE4BDzf.js} +6 -6
- package/dist/assets/{backup-CJWLDHuS.js.map → backup-BGE4BDzf.js.map} +1 -1
- package/dist/assets/{backup-CSMw2GHv.js → backup-Cm8ptQQA.js} +1 -1
- package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
- package/dist/assets/{buttons-QEnAGWoC.js → buttons-52NT4sA_.js} +4 -4
- package/dist/assets/{buttons-QEnAGWoC.js.map → buttons-52NT4sA_.js.map} +1 -1
- package/dist/assets/buttons-PCvHRlkS.js +2 -0
- package/dist/assets/{envelope-K27mzoyu.js → envelope-CsRRCrL3.js} +2 -2
- package/dist/assets/{envelope-K27mzoyu.js.map → envelope-CsRRCrL3.js.map} +1 -1
- package/dist/assets/{errors-DO5z6h_l.js → errors-B-zMxbcd.js} +6 -5
- package/dist/assets/{errors-DO5z6h_l.js.map → errors-B-zMxbcd.js.map} +1 -1
- package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -1
- package/dist/assets/{ghostly_iroh_web-Dvzh3Y6E.js → ghostly_iroh_web-BsAEFIjl.js} +30 -36
- package/dist/assets/ghostly_iroh_web-BsAEFIjl.js.map +1 -0
- package/dist/assets/ghostly_iroh_web_bg.wasm +0 -0
- package/dist/assets/{groupFiles-DHTrTA4I.js → groupFiles-BurezP4Z.js} +47 -21
- package/dist/assets/{groupFiles-DHTrTA4I.js.map → groupFiles-BurezP4Z.js.map} +1 -1
- package/dist/assets/{host-C7hA-Za7.js → host-C74Sy5jT.js} +211 -42
- package/dist/assets/host-C74Sy5jT.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-BVoWY2ua.js → hyperdhtRelay-D0MvfMzX.js} +2 -2
- package/dist/assets/{hyperdhtRelay-BVoWY2ua.js.map → hyperdhtRelay-D0MvfMzX.js.map} +1 -1
- package/dist/assets/{irohWeb-BJPk9bMn.js → irohWeb-DynqwRwl.js} +3 -3
- package/dist/assets/{irohWeb-BJPk9bMn.js.map → irohWeb-DynqwRwl.js.map} +1 -1
- package/dist/assets/{main-DC8cUkDx.js → main-DNzQOdNG.js} +168 -57
- package/dist/assets/main-DNzQOdNG.js.map +1 -0
- package/dist/assets/{mainline-CxbxpoU4.js → mainline-COqCHn1R.js} +2 -2
- package/dist/assets/{mainline-CxbxpoU4.js.map → mainline-COqCHn1R.js.map} +1 -1
- package/dist/assets/{networkReason-D42iNuUB.js → networkReason-WikfjkIw.js} +2 -2
- package/dist/assets/{networkReason-D42iNuUB.js.map → networkReason-WikfjkIw.js.map} +1 -1
- package/dist/assets/{nwc-Cm4sYgLv.js → nwc-ClsjYuyP.js} +3 -3
- package/dist/assets/{nwc-Cm4sYgLv.js.map → nwc-ClsjYuyP.js.map} +1 -1
- package/dist/assets/{nwcProvider-0D7vdPDd.js → nwcProvider-ksMYZra9.js} +2 -2
- package/dist/assets/{nwcProvider-0D7vdPDd.js.map → nwcProvider-ksMYZra9.js.map} +1 -1
- package/dist/assets/{profiles-BHc9pEYg.js → profiles-gPCjLOQq.js} +2 -2
- package/dist/assets/{profiles-BHc9pEYg.js.map → profiles-gPCjLOQq.js.map} +1 -1
- package/dist/assets/{registry-CVdSZW5l.js → registry-CJh9L_kF.js} +17 -32
- package/dist/assets/registry-CJh9L_kF.js.map +1 -0
- package/dist/assets/{registry-CLolR0kM.js → registry-S7SFF_JB.js} +1 -1
- package/dist/assets/{resolve-BnlEajYz.js → resolve-BJxBhU5j.js} +18 -3
- package/dist/assets/resolve-BJxBhU5j.js.map +1 -0
- package/dist/assets/{server-CJNEKxzE.js → server-C05N9q4G.js} +298 -100
- package/dist/assets/server-C05N9q4G.js.map +1 -0
- package/dist/assets/{src-yMUQvdyL.js → src-RQ6OJOUO.js} +322 -104
- package/dist/assets/src-RQ6OJOUO.js.map +1 -0
- package/dist/assets/{turnRefs-B2a8to9q.js → turnRefs-u-U75DFx.js} +2 -2
- package/dist/assets/{turnRefs-B2a8to9q.js.map → turnRefs-u-U75DFx.js.map} +1 -1
- package/dist/assets/{usdt-DesFeDiG.js → usdt-A1B3r3Mq.js} +3 -3
- package/dist/assets/{usdt-DesFeDiG.js.map → usdt-A1B3r3Mq.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +1 -1
- package/dist/assets/api-aup3Amud.js.map +0 -1
- package/dist/assets/apiKit-DYkVEs6r.js.map +0 -1
- package/dist/assets/apps-Rbk2HHXb.js.map +0 -1
- package/dist/assets/buttons-CGRqZ7z0.js +0 -2
- package/dist/assets/ghostly_iroh_web-Dvzh3Y6E.js.map +0 -1
- package/dist/assets/host-C7hA-Za7.js.map +0 -1
- package/dist/assets/main-DC8cUkDx.js.map +0 -1
- package/dist/assets/registry-CVdSZW5l.js.map +0 -1
- package/dist/assets/resolve-BnlEajYz.js.map +0 -1
- package/dist/assets/server-CJNEKxzE.js.map +0 -1
- package/dist/assets/src-yMUQvdyL.js.map +0 -1
package/README.md
CHANGED
|
@@ -93,8 +93,8 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
93
93
|
|---|---|
|
|
94
94
|
| `app init <dir> [--name <name>] [--title <title>] [--force]` | Start an app (WISP 1200, Apps), run here with no profile or daemon: a small working one in `<dir>` (made when missing), which `app publish <dir>` signs as it is. It writes `ghostly-app.json` (`view: chat`, the `chat` permission), an `index.html` that says hello to the same app on the contact's side, typed against `@ghostlytools/sdk/app`, and a `README.md` with build, publish, verify and how to list it in a store. The name is `--name` (a lowercase letter, then up to 31 lowercase letters, digits or hyphens), else the folder's (`My App` gives `my-app`); the title is `--title` (one line, up to 40 characters), else the name's. When one of the three files is there nothing is written and it is `refused` (`details.reason` `exists`, `details.files`), unless `--force`, which replaces those three only. Answers `{dir, name, title, files, replaced?, next}` |
|
|
95
95
|
| `app open <chat> <ref\|name> [--no-card]`, `app close <chat> <ref\|name>` | A served app in a chat, as a bot (WISP 1200, Apps; needs the daemon, and `app serve` first). `app open` says the app is open on this side, in the version served, and sends the contact the app's card ("opened Chess", with what their app needs to get the same app and check it), unless their app is open in that chat already or `--no-card`. The two sides talk once both opened it; while the app stays open here, the engine says so again on every session that comes back. It answers `{chat, app, version, card, peer, live}`: `card` is the card's message id or null, `peer` the version the contact has open or null. A card that cannot go leaves nothing open. `app close` ends it: `{chat, app, closed}`. What is open is kept in memory: a restarted daemon opens again. `unavailable` in a one-shot, or on a daemon that started before the first app was served (`daemon restart`); `not_found` for an app not served; `refused`, in the engine's words, for a chat that is not a paired 1:1 chat |
|
|
96
|
-
| `app publish <dir> --key <file> [--out <file>] [--sequence n]`, `app verify <bundle\|url>` | The publisher tools of WISP 1200 (Apps), run here with no profile or daemon. `app publish` bundles and signs an app: `<dir>/ghostly-app.json` holds the manifest's fields but `publisher`, `sequence` and `files`, and every other file in `<dir>` goes in (dot files are left out and listed in `skipped`). It writes `<dir>/app.ghostlyapp` (or `--out`), its `sequence` one more than the bundle already there, which only the same key may follow (`--sequence n` sets it, refused unless higher). `--key` names the publisher key file, a PKCS #8 PEM: made owner-only on first use (back it up: an app is updated only with its key), refused when others may read it or when it is inside `<dir>`, never printed; a folder holding any private key file is refused (`details.reason` `private-key`). `app verify` checks a bundle from a file or an `https` URL as a client does (jsDelivr only at a full commit, 16 MiB at most) and answers its manifest and digest, or `refused` (exit 1) with the WISP's reason in `details.reason` |
|
|
97
|
-
| `app revoke <dir> --key <file> (--digest <digest>… \| --up-to <sequence>) [--reason <text>] [--bundle <file>]` | Revoke versions of your app (WISP 1200 · Revocation): by digest (base64url, as `app verify` prints it; `--digest` again for each, up to 64) or every version up to a `sequence`, with an optional one-line reason. The statement names the app of `<dir>/app.ghostlyapp` (or `--bundle`), is signed with that app's publisher key (any other key is refused, and none is made here), and is added to `<dir>/ghostly-revoke.json`, published beside the bundle; a client that reads it stops those versions. Answers `{app, digests \| upTo, current, added, revocations, file}`; `current` says whether the bundle in `<dir>` is among them |
|
|
96
|
+
| `app publish <dir> --key <file> [--out <file>] [--sequence n]`, `app verify <bundle\|url>` | The publisher tools of WISP 1200 (Apps), run here with no profile or daemon. `app publish` bundles and signs an app: `<dir>/ghostly-app.json` holds the manifest's fields but `publisher`, `sequence` and `files`, and every other file in `<dir>` goes in (dot files are left out and listed in `skipped`). It writes `<dir>/app.ghostlyapp` (or `--out`), its `sequence` one more than the bundle already there, which only the same key may follow (`--sequence n` sets it, refused unless higher); a sequence that `<dir>/ghostly-revoke.json` already revokes is `refused` (`details.reason` `revoked`, `details.sequence` the first one it leaves alone). `--key` names the publisher key file, a PKCS #8 PEM: made owner-only on first use (back it up: an app is updated only with its key), refused when others may read it or when it is inside `<dir>`, never printed; a folder holding any private key file is refused (`details.reason` `private-key`). `app verify` checks a bundle from a file or an `https` URL as a client does (jsDelivr only at a full commit, 16 MiB at most) and answers its manifest and digest, or `refused` (exit 1) with the WISP's reason in `details.reason` |
|
|
97
|
+
| `app revoke <dir> --key <file> (--digest <digest>… \| --up-to <sequence>) [--reason <text>] [--bundle <file>] [--force]` | Revoke versions of your app (WISP 1200 · Revocation): by digest (base64url, as `app verify` prints it; `--digest` again for each, up to 64) or every version up to a `sequence`, with an optional one-line reason. Clients keep a revocation for good, so `--up-to` past the bundle's own sequence is a usage error unless `--force` (versions published from elsewhere), and `app publish` refuses a sequence the folder's `ghostly-revoke.json` already stops, naming the `--sequence` that clears it. The statement names the app of `<dir>/app.ghostlyapp` (or `--bundle`), is signed with that app's publisher key (any other key is refused, and none is made here), and is added to `<dir>/ghostly-revoke.json`, published beside the bundle; a client that reads it stops those versions. Answers `{app, digests \| upTo, current, added, revocations, file}`; `current` says whether the bundle in `<dir>` is among them |
|
|
98
98
|
| `app send <chat> <ref\|name> <json\|->` | One message of a served app's own protocol to the same app on the contact's side (WISP 1200, Apps; needs the daemon): any JSON value, on the command line or `-` for stdin, at most 32 KiB, at most 48 a second. It goes on the live session only, while both sides have the app open, and is never kept for later: `{chat, app, sent: true}`, or an error whose `details.reason` is the WISP's name for why it did not go: `not-open` (`refused`: `app open` first), `too-large` (`bad_request`), `offline` and `peer-closed` (`unavailable`: the chat is not live, or the contact's app is not open; wait for `app.opened`), `too-fast` (`refused`). The contact's messages come as `app.message` events |
|
|
99
99
|
| `app serve <bundle\|url> --grant chat [--grant name] [--url <url>]`, `app served`, `app unserve <ref\|name>` | Serve an app as a bot (WISP 1200, Apps): the profile speaks the app's messages in its chats itself, and no app runs here. `app serve` reads the signed bundle from a file or an `https` URL and checks it as `app verify` does (`refused` with the WISP's reason in `details.reason`). Each permission the manifest asks needs its `--grant`: `chat` (talk to the same app on the contact's side) and `name` (the profile's name in that chat); one left out is `confirm` (exit 5), naming it in `details.missing`. `internet` cannot be granted (no page runs here), a permission the app does not ask is `bad_request`, and an app that does not ask for `chat` is `refused`. A newer version replaces the one served; an older one, or another bundle under the same `sequence`, is `refused`. It answers `{served: {ref, title, version, sequence, digest, url?, permissions, granted, servedAt}, offered, restart?}`; `url` is where a contact's app reads the bundle (`--url`, else the URL served from, else the manifest's first source). The list is kept in the profile's folder (`apps.json`). A profile's engine offers `apps/1` to contacts only while it serves an app, and reads the list when it starts: `offered` says whether it does now, and `restart: true` that `daemon restart` is needed for it. `app served` answers `{apps, offered, restart?}`; `app unserve` removes one by its reference or its name |
|
|
100
100
|
| `button press <chat\|group> <message> <button> [--wait none\|sent\|delivered] [--timeout s]` | Press a button of someone else's question, as a tap in the app does (WISP 406 · Message Buttons): the reply carries the button's label, and the asker hears `button.pressed`. `<message>` is the question's id (its event or `chat history`), `<button>` a button's id from its `card`. Refused (exit 1) like a tap: closed buttons, a second answer past `--once`, a second press within a second. A one-shot in a chat waits until it went out, as `send`. Answers `{chat \| group, messageId, button, label, replyId, delivery \| edges}` |
|
|
@@ -115,7 +115,7 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
115
115
|
| `chat wait <chat> [--until live\|text\|paired] [--timeout s]` | Wait for a chat to go live, carry text, or see its contact. Live means a session that exists now, in this run of the daemon: a chat that was live before a restart counts once its contact answers again |
|
|
116
116
|
| `daemon [--detach] [--timeout s]`, `daemon status`, `daemon stop [--timeout s]`, `daemon restart [--timeout s]` | Keep the profile online; `status` names its version and its socket (`socket`, for the [socket API](#the-socket-api)); `restart` stops it and starts this release's code in the background ([After an upgrade](#after-an-upgrade)). Ctrl-C, SIGTERM and the terminal closing (SIGHUP) stop it cleanly |
|
|
117
117
|
| `edit <chat> <message> [text… \| --text <text> \| --stdin] [--force] [--wait none\|confirmed] [--timeout s]` | Replace the text of a message you sent (1:1 chats, `group edit` for a group; `<message>` is the `messageId` `send` gave, or its wire id). The contact sees it in place, marked edited; `--wait confirmed` waits for its app to confirm (the default without a daemon). At most 100 edits a message, no time limit; an older contact app gets it once it shows edits |
|
|
118
|
-
| `engine <method> [json \| -] [--confirm-real] [--show-secret]`, `engine --list` | Any call of the app's engine |
|
|
118
|
+
| `engine <method> [json \| -] [--confirm-real] [--show-secret] [--force]`, `engine --list` | Any call of the app's engine |
|
|
119
119
|
| `events [--since seq]` | What the event journal holds, without following |
|
|
120
120
|
| `file list <chat\|group>`, `file accept\|decline\|pause\|resume\|cancel [<chat>] <file>` | Transfers; a file over 25 MiB waits for `file accept` (files/3), and so does a group's file that did not come by itself (over 8 MiB). A file's id names its chat or its group, so `<chat>` may be left out |
|
|
121
121
|
| `file resend [<chat>] <file>`, `file request [<chat>] <file>` | A file that stopped moving: sent again from here, or asked for again from the contact (a group's file: from whoever holds it); either goes on from the bytes the receiver holds (files/3) |
|
|
@@ -123,7 +123,7 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
123
123
|
| `file send <chat\|group> <path> [--name n] [--mime t] [--voice [ms] [--peaks …]] [--reply <message>]` | A file, or a voice note (its length and waveform measured from the file unless given); `--reply` quotes a message, as `send --reply` does. To a group (`group:<id>` when a chat has the same name), up to 100 MiB: every member sees it at once and each member's app fetches it from a member who has it (WISP 503) |
|
|
124
124
|
| `file wait [<chat>] <file> [--timeout s]` | Wait until a transfer ends: exit `0` when the file is all here, `1` with the transfer's error when it failed (`details.retry`: `file resend` can go on), `4` on timeout (default 300 s) |
|
|
125
125
|
| `forward <chat\|group> <message>… --to <chat\|group>… [--force] [--wait none\|sent] [--timeout s]` | Forward messages to up to 5 chats and groups (`--to` again for each; `group:<id>` names a group when a chat has the same name; an id that starts with a dash is taken as it is, `--to -Ab…` or `--to=-Ab…`). Each is a new message of yours that says it was forwarded (`forwarded`, the hop count) and nothing of who wrote it. Files go from the bytes this profile holds, never fetched again; a group takes texts only. A text that looks like a seed, a key or ecash needs `--force`. Answers `{from, results: [{to, kind, messageIds, error}]}`; any refusal fails the command (exit 1) with the results in `details`. `--wait sent`: each text on its way (a group's taken by an edge), each file's transfer done |
|
|
126
|
-
| `group create <name> [--mesh]`, `group join <link
|
|
126
|
+
| `group create <name> [--mesh]`, `group join [<link> \| -]` | A community (a link anyone can open), or a private mesh. `group join` reads the link from stdin when none is given or `-` (on the command line it shows in `ps` and the shell's history, and the CLI warns). `group join` with the link of a community the profile was removed from asks to be let in again, and keeps its history |
|
|
127
127
|
| `group edit <group> <message> [text… \| --text <text> \| --stdin] [--mention <member>]… [--force]` | Replace the text of a message you sent to the group (`<message>` is the `messageId` `group send` gave). Every member sees it in place, marked edited; mentions whose `@name` is still in the text stay, `--mention` adds more. Answers `{group, messageId, edits, sent, edges}`; `--wait sent` and `--timeout` as for `group send`. The text the message already has is no edit: `sent: false, unchanged: true`. A private group's members whose edge is down get it when it opens, a community's with the catch-up; a member on an older app keeps the old text |
|
|
128
128
|
| `group hub <group> <member> [--pin \| --exclude \| --auto]` | Past 16 members: pin a member as a hub, keep one from being a hub, or leave it to their app (a daemon offers itself) |
|
|
129
129
|
| `group invite <group> <chat>`, `group remove <group> <member>`, `group admin <group> <member>` | Membership, for the admin (each prints the group; `--show-secret` for its link) |
|
|
@@ -139,7 +139,7 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
139
139
|
| `identity providers`, `identity list` | Kinds of proof and their signers; this profile's proofs |
|
|
140
140
|
| `identity share\|withdraw <chat> <id>`, `identity contact <chat>`, `identity recheck <chat> <id>`, `identity remove <id>` | Show a proof to a contact; what a contact showed, as checked here |
|
|
141
141
|
| `invite create [--label <name>]` | A new chat's `ghostly1…` invite and its link |
|
|
142
|
-
| `invite join <invite-or-link> [--label <name>]` | Join a chat (your own invite is refused) |
|
|
142
|
+
| `invite join [<invite-or-link> \| -] [--label <name>]` | Join a chat (your own invite is refused). The invite comes from stdin when none is given or `-`, out of `ps` and the shell's history; on the command line the CLI warns |
|
|
143
143
|
| `lightning default <card>`, `lightning rename <card> <name>` | Lightning cards: which receives by default |
|
|
144
144
|
| `listen [--since seq] [--cursor file] [--type t]… [--turns] [--from <chat\|key>]… [--group <group>]… [--exec cmd] [--webhook url] [--print]` | The event stream; `--from` and `--group` an allowlist, `--turns` one `agent.turn` per message to answer ([Events](#events)) |
|
|
145
145
|
| `message retry\|delete\|details <chat> <message>` | One message |
|
|
@@ -157,12 +157,12 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
157
157
|
| `service peer <chat>`, `service open <chat> <service> [--port p]`, `service close <chat> <service>` | A contact's app on a loopback port here (daemon). `url` is a link for your browser, `http://<random>.localhost:<port>/.ghostly-open/<token>`: it sets the service's cookie and shows the app on a host name of its own; any other host name, or a request without that cookie, gets 404. Chrome, Edge and curl reach `*.localhost` names by themselves; Safari and Node's `fetch` on macOS may not (add the name to `/etc/hosts` for them) |
|
|
158
158
|
| `settings get [--show-secret]`, `settings set <key> <json>` | Relays, Iroh relays, the HyperDHT relay, ICE servers, `sendTyping` (false: contacts are never told you type), … |
|
|
159
159
|
| `status` | The profile, its chats, whether WebRTC and calls run, the last event seq |
|
|
160
|
-
| `store sign <index> --key <file> [--out <dir>]` | Sign a store index (WISP 1200 · Stores) with the store key file (kept offline; made when missing
|
|
160
|
+
| `store sign <index> --key <file> [--out <dir>]` | Sign a store index (WISP 1200 · Stores) with the store key file (kept offline; made when missing, the index names no `key` and no signed index is in the output folder): writes `ghostly-store.json`, canonical, and `ghostly-store.sig` beside the index or in `--out`. Refused, with the reason, when a client would refuse the index (`expires` more than 90 days ahead, a bad field), or when the index already there has a higher `sequence` (`rollback`), the same one with other content (`equivocation`), or is signed by another key (`store-key`: another store is another `--out`) |
|
|
161
161
|
| `task send <chat\|group> --title <title> [--status s] [--progress n \| --steps a/b] [--step "…"] [--item state:text]… [--pr-url url --pr-number n --additions n --deletions n --files n --pr-state s --pr-checks c] [--branch b] [--tag label]… [--parent task] [--link url]… [--id id] [--json json\|-\|file] [--force]`, `task update <chat\|group> <task> [fields…]` | A task card for a bot's work (WISP 405 · Status Cards): a title, a status (queued, running, blocked, done, failed, cancelled), progress, the step it is on, up to 20 steps or log lines (`--item done:Codec`; a lowercase word before the colon must be an item state: pending, running, done, failed or skipped) and its pull request, shown as a small card that apps without cards read as text. Optional, and ignored by apps from before them: where the pull request stands (`--pr-state draft`, `open`, `merged` or `closed`; an open one puts the task in the board's Review column) and its checks (`--pr-checks passing`, `failing` or `pending`), up to 3 tags of 24 characters (`--tag core --tag web`; an update's tags replace the card's), and `--parent <task>`, a task of yours in the same chat that this one is a part of (sent first; its parts stack under it on the board). `send` prints the task's id and message; `update` merges the fields given over the card (an update's `--item` list replaces the card's: give all of them) and edits its message, at most once per 2.5 s (sooner updates merge into the next). `--json` takes the whole card; `null` in it removes a field. Only the CLI sends cards: the app shows them |
|
|
162
162
|
| `typing <chat> [--kind typing\|recording\|thinking] [--status "<text>"] [--for s] [--stop]` | Show the contact you are writing, recording or thinking, or a short status line in its place ("Transcribing your audio…", 40 characters, no links): live chats only, it holds 6 s there; `--for s` keeps it on that long (up to 600 s; a one-shot stays that long once the chat is live, and stops with `live: false` when it is not live within 15 s); a new kind or status shows at once; a message to the chat or `--stop` ends it |
|
|
163
163
|
| `usage send [<chat\|group>] [--all] --left <percent> [--window "5 h"] [--resets <time>] [--label Claude] [--account <name>] [--also week=80@<time>]… [--used n --limit n] [--id id] [--json json\|-\|file] [--force]` | How much of a quota the bot has left (WISP 405 § Usage): the percent (or `--used` of `--limit`), what it is of, the account, the window, when it resets, and up to 3 other windows (`--also week=80@2026-10-10T00:00:00Z`). The app shows a small meter on the chat's row and in its header, amber under 20%, red under 5%, muted once 6 h old or past the reset. One card per chat: the first report sends it, later ones edit it in place (quiet, paced as `task update`'s); each report is whole, so a field it leaves out goes. `--all` reports to every 1:1 chat with a contact. See [docs/AI-AGENTS.md](../../docs/AI-AGENTS.md#reporting-usage) for where a bot gets its numbers |
|
|
164
164
|
| `version` | This CLI's version, `{"version":"…"}` (also `ghostly --version`) |
|
|
165
|
-
| `wallet create <type> [--network testnet] [--provider id] [--value name=value]… [--stdin] [--invite code] [--api-key key]` | A wallet: `cashu`, `lightning` (a card: its source's form in `--value`), `arkade`, `spark` (on Mainnet, `--api-key` is your Breez API key), `bitcoin` (BDK), `fedimint` (`--invite` is the federation's invite code), `usdt`. With `--stdin`, secret fields come as `name=value` lines on stdin (`api-key=…` too), out of `ps` and the shell's history |
|
|
165
|
+
| `wallet create <type> [--network testnet] [--provider id] [--value name=value]… [--stdin] [--invite code] [--api-key key]` | A wallet: `cashu`, `lightning` (a card: its source's form in `--value`), `arkade`, `spark` (on Mainnet, `--api-key` is your Breez API key), `bitcoin` (BDK), `fedimint` (`--invite` is the federation's invite code), `usdt`. With `--stdin`, secret fields come as `name=value` lines on stdin (`api-key=…` too), out of `ps` and the shell's history; a `--value` the source's form marks secret (an NWC URI, a macaroon, a rune, an RPC password) is warned about |
|
|
166
166
|
| `wallet faucet <type>`, `wallet add-mint <url> [--primary]` | Test coins; another Cashu mint |
|
|
167
167
|
| `wallet list [--network n]` | Wallets and balances, and what `wallet create` can make on each network |
|
|
168
168
|
| `wallet receive <sats>`, `wallet address <type>`, `wallet redeem [<token>]`, `wallet history` | Receive, and what came and went. `wallet redeem` reads the token from stdin when none is given, which keeps it out of `ps` and the shell's history |
|
package/SKILL.md
CHANGED
|
@@ -358,7 +358,8 @@ proof needs a person who holds the key: leave that to the owner.
|
|
|
358
358
|
|
|
359
359
|
- Output is JSON. A failure is `{"error":{"code","message"}}` with exit 1 (failed), 2 (usage), 3 (not found),
|
|
360
360
|
4 (timed out) or 5 (needs `--force`, `--yes` or `--confirm-real`).
|
|
361
|
-
- `send`
|
|
361
|
+
- `send` (and `ghostly engine sendMessage` and the other sends through `engine`) refuses text that looks like a recovery
|
|
362
|
+
phrase, a private key or a Cashu token unless `--force`.
|
|
362
363
|
- Spending real money (Mainnet) needs `--confirm-real`.
|
|
363
364
|
- Seeds, keys and backups are never printed without `--show-secret`; `group show` and `group list` hide entry links, and
|
|
364
365
|
`chat list` and `chat show` a pending chat's invite code.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as findChat, s as findGroup } from "./apiKit-
|
|
2
|
-
import { a as hideStateSecrets, i as groupSendRefused, n as SETTABLE, o as mentionsFor, r as callApi, s as redactSettings, t as API_METHODS } from "./api-
|
|
1
|
+
import { a as findChat, s as findGroup } from "./apiKit-3MLUyuhL.js";
|
|
2
|
+
import { a as hideStateSecrets, i as groupSendRefused, n as SETTABLE, o as mentionsFor, r as callApi, s as redactSettings, t as API_METHODS } from "./api-Bp_hWAiU.js";
|
|
3
3
|
export { API_METHODS, SETTABLE, callApi, findChat, findGroup, groupSendRefused, hideStateSecrets, mentionsFor, redactSettings };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $n as GROUP_FILE_LIMITS, Bo as GhostlyHttpError, Cl as randomBytes$1, Fo as AWAITING_PEER_MS, Hr as TYPING_REFRESH_MS, Qa as appCardId, Sc as ownInviteRefusal, Vr as TYPING_KINDS, Wo as LIMITS, Wr as sanitizeTypingStatus, Xi as identityStatement, Za as STATUS_CARD_LIMITS, _a as VOICE_LIMITS, _l as MAX_AVATAR_LENGTH, _o as isAppRef, at as groupName, ba as parseVoiceMeta, bc as inviteLink, ci as APP_DATA_MAX_BYTES, eo as cardLine, ga as PLAYABLE_AUDIO, ha as sanitizeMime, m as APP_PERMISSIONS, ma as sanitizeFileName, no as checkStatusCard, po as appRef, va as baseMime, vl as sanitizeAvatar, wa as readImageMeta, wl as toBase64Url, xa as voicePeaksOf, y as isAppUrl } from "./src-RQ6OJOUO.js";
|
|
2
2
|
import { c as fileStore } from "./idb-B5L8wuOm.js";
|
|
3
|
-
import { O as waitingGroupFile, T as removeStored, U as iceServerProblem, W as iceServerSetting, i as groupOfFile, l as replyRef, n as groupFileId, v as paymentNetwork } from "./groupFiles-
|
|
3
|
+
import { O as waitingGroupFile, T as removeStored, U as iceServerProblem, W as iceServerSetting, i as groupOfFile, l as replyRef, n as groupFileId, v as paymentNetwork } from "./groupFiles-BurezP4Z.js";
|
|
4
4
|
import { f as FILE_BYTES_STEP, o as fileBytes, s as fileBytesOf } from "./fileBytes-Di7VZtmU.js";
|
|
5
|
-
import { t as IDENTITY_PROVIDERS } from "./registry-
|
|
6
|
-
import { a as waitForEdit, c as findSecret, i as pressable, n as buttonsCard, o as waitForGroupFrame, s as waitForMessage, t as BUTTON_METHODS } from "./buttons-
|
|
7
|
-
import { i as ENGINE_READS, n as withStoredIds, r as ENGINE_METHODS } from "./turnRefs-
|
|
8
|
-
import { t as CliError } from "./errors-
|
|
9
|
-
import { _ as str, a as findChat, c as groupOf, d as messageOf, f as node, g as state, h as sentAt, i as chatOrGroup, l as inviteTaken, m as oneOf, n as bool, o as findChatOrGroup, p as num, r as chatOf, s as findGroup, u as list, v as waitForState } from "./apiKit-
|
|
10
|
-
import { t as BACKUP_METHODS } from "./backup-
|
|
11
|
-
import { o as checkedBundle } from "./apps-
|
|
5
|
+
import { t as IDENTITY_PROVIDERS } from "./registry-CJh9L_kF.js";
|
|
6
|
+
import { a as waitForEdit, c as findSecret, i as pressable, n as buttonsCard, o as waitForGroupFrame, s as waitForMessage, t as BUTTON_METHODS } from "./buttons-52NT4sA_.js";
|
|
7
|
+
import { i as ENGINE_READS, n as withStoredIds, r as ENGINE_METHODS } from "./turnRefs-u-U75DFx.js";
|
|
8
|
+
import { i as localFileError, r as asCliError, t as CliError } from "./errors-B-zMxbcd.js";
|
|
9
|
+
import { _ as str, a as findChat, c as groupOf, d as messageOf, f as node, g as state, h as sentAt, i as chatOrGroup, l as inviteTaken, m as oneOf, n as bool, o as findChatOrGroup, p as num, r as chatOf, s as findGroup, u as list, v as waitForState } from "./apiKit-3MLUyuhL.js";
|
|
10
|
+
import { t as BACKUP_METHODS } from "./backup-BGE4BDzf.js";
|
|
11
|
+
import { o as checkedBundle } from "./apps-BXw3Ui_3.js";
|
|
12
12
|
import { generateMnemonic } from "@scure/bip39";
|
|
13
13
|
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
14
14
|
import { openAsBlob, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -999,6 +999,17 @@ function cardTexts(value, out = []) {
|
|
|
999
999
|
return out;
|
|
1000
1000
|
}
|
|
1001
1001
|
/**
|
|
1002
|
+
* The first text in `value` (a card's fields, a message's text…) that looks like a seed, a private key or a Cashu token,
|
|
1003
|
+
* read as given and as a card carries it (`cardLine`).
|
|
1004
|
+
*/
|
|
1005
|
+
function secretIn(value) {
|
|
1006
|
+
for (const text of cardTexts(value)) {
|
|
1007
|
+
const secret = findSecret(text) ?? findSecret(cardLine(text, Infinity) ?? "");
|
|
1008
|
+
if (secret) return secret;
|
|
1009
|
+
}
|
|
1010
|
+
return null;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1002
1013
|
* The secret guard `send` has (docs/CLI.md § Safety): a card whose text looks like a seed, a private key or a Cashu
|
|
1003
1014
|
* token goes only with `--force`. `fields` are what this command gives (an update's own, not the card it merges over).
|
|
1004
1015
|
* A card's text is read as given and as the card carries it (`cardLine`): a line loses its invisible characters on the
|
|
@@ -1273,7 +1284,10 @@ async function reportUsage(ctx, ref, fields, params) {
|
|
|
1273
1284
|
updated: true
|
|
1274
1285
|
};
|
|
1275
1286
|
}
|
|
1276
|
-
/**
|
|
1287
|
+
/**
|
|
1288
|
+
* `usage send`: one chat or group, or (`all`) every 1:1 chat with a contact; a chat that refuses is said (its
|
|
1289
|
+
* `{code, message}`), not fatal, unless every chat refused: then nothing was reported and the call fails.
|
|
1290
|
+
*/
|
|
1277
1291
|
async function sendUsage(ctx, params) {
|
|
1278
1292
|
const fields = fieldsOf(params);
|
|
1279
1293
|
if (!bool(params, "all")) return reportUsage(ctx, str(params, "chat", true), fields, params);
|
|
@@ -1284,16 +1298,31 @@ async function sendUsage(ctx, params) {
|
|
|
1284
1298
|
kind: "usage",
|
|
1285
1299
|
id: typeof fields.id === "string" && fields.id ? fields.id : USAGE_CARD_ID
|
|
1286
1300
|
});
|
|
1301
|
+
oneOf(params, "wait", ["none", "sent"], "none");
|
|
1302
|
+
num(params, "timeout", 30, {
|
|
1303
|
+
min: 1,
|
|
1304
|
+
max: 3600
|
|
1305
|
+
});
|
|
1287
1306
|
const chats = state(ctx).links.filter((link) => link.profile && link.peerPubKeyZ32);
|
|
1288
1307
|
const results = [];
|
|
1308
|
+
const failed = [];
|
|
1289
1309
|
for (const link of chats) try {
|
|
1290
1310
|
results.push(await reportUsage(ctx, link.id, fields, params));
|
|
1291
1311
|
} catch (error) {
|
|
1312
|
+
const refusal = {
|
|
1313
|
+
chat: link.id,
|
|
1314
|
+
error: asCliError(error)
|
|
1315
|
+
};
|
|
1316
|
+
failed.push(refusal);
|
|
1292
1317
|
results.push({
|
|
1293
1318
|
chat: link.id,
|
|
1294
|
-
error: error
|
|
1319
|
+
error: refusal.error.toJSON()
|
|
1295
1320
|
});
|
|
1296
1321
|
}
|
|
1322
|
+
if (failed.length && failed.length === chats.length) {
|
|
1323
|
+
const codes = new Set(failed.map((f) => f.error.code));
|
|
1324
|
+
throw new CliError(codes.size === 1 ? failed[0].error.code : "refused", `No chat took the usage card: ${failed.map((f) => `${f.chat}: ${f.error.message}`).join("; ")}`, { chats: results });
|
|
1325
|
+
}
|
|
1297
1326
|
return { chats: results };
|
|
1298
1327
|
}
|
|
1299
1328
|
var STATUS_CARD_METHODS = {
|
|
@@ -1622,7 +1651,15 @@ function findMember(group, ref) {
|
|
|
1622
1651
|
const byKey = others.filter((m) => m.key === ref);
|
|
1623
1652
|
const matches = byKey.length ? byKey : others.filter((m) => m.key.startsWith(ref) || m.nick?.trim().toLowerCase() === lower);
|
|
1624
1653
|
if (matches.length === 1) return matches[0];
|
|
1625
|
-
throw
|
|
1654
|
+
throw matches.length ? new CliError("bad_request", `${JSON.stringify(ref)} names more than one member`) : noMember(group, ref);
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* A ref no other member answers to. When it is this profile's own key (or a prefix of it), it says so: "No member"
|
|
1658
|
+
* read as if this profile were not in the group.
|
|
1659
|
+
*/
|
|
1660
|
+
function noMember(group, ref) {
|
|
1661
|
+
if (group.members.some((m) => m.me && m.key.startsWith(ref))) return new CliError("bad_request", `${JSON.stringify(ref)} is you: name another member of ${group.name}`);
|
|
1662
|
+
return new CliError("not_found", `No member ${JSON.stringify(ref)} in ${group.name}`);
|
|
1626
1663
|
}
|
|
1627
1664
|
/**
|
|
1628
1665
|
* A picture as Ghostly sends it: a square JPEG data URL, checked as a contact would check it. The app scales and
|
|
@@ -1632,8 +1669,8 @@ async function pictureFrom(path) {
|
|
|
1632
1669
|
let bytes;
|
|
1633
1670
|
try {
|
|
1634
1671
|
bytes = await readFile(resolve(path));
|
|
1635
|
-
} catch {
|
|
1636
|
-
throw new CliError("not_found", `No file ${path}`);
|
|
1672
|
+
} catch (error) {
|
|
1673
|
+
throw localFileError(error, path) ?? new CliError("not_found", `No file ${path}`);
|
|
1637
1674
|
}
|
|
1638
1675
|
const url = `data:image/jpeg;base64,${bytes.toString("base64")}`;
|
|
1639
1676
|
const checked = sanitizeAvatar(url);
|
|
@@ -1894,7 +1931,12 @@ var IDENTITY_METHODS = {
|
|
|
1894
1931
|
};
|
|
1895
1932
|
}
|
|
1896
1933
|
if (signer.kind === "redirect") throw new CliError("unavailable", `${signer.label} needs a browser window: make this proof in the app`);
|
|
1897
|
-
const
|
|
1934
|
+
const subject = str(params, "subject");
|
|
1935
|
+
if (!subject) {
|
|
1936
|
+
const what = p.subject ? `, its ${p.subject.label.toLowerCase()}${p.subject.placeholder ? ` (${p.subject.placeholder})` : ""}` : "";
|
|
1937
|
+
throw new CliError("bad_request", `${p.label} takes a subject${what}: ghostly identity add ${p.id} <subject>`);
|
|
1938
|
+
}
|
|
1939
|
+
const { draftId, binding } = await begin(ctx, p, subject, params);
|
|
1898
1940
|
const statement = identityStatement(binding);
|
|
1899
1941
|
drafts.set(draftId, {
|
|
1900
1942
|
draftId,
|
|
@@ -3123,6 +3165,7 @@ var WALLET_METHODS = Object.fromEntries(Object.entries({
|
|
|
3123
3165
|
const nets = params.networks === void 0 ? void 0 : (() => {
|
|
3124
3166
|
const value = params.networks;
|
|
3125
3167
|
if (!Array.isArray(value) || !value.every((v) => v === "mainnet" || v === "testnet")) throw new CliError("bad_request", "networks must list mainnet and/or testnet");
|
|
3168
|
+
if (value.length === 0) throw new CliError("bad_request", "networks must list mainnet and/or testnet: to stop taking it, --off");
|
|
3126
3169
|
return value;
|
|
3127
3170
|
})();
|
|
3128
3171
|
await node(ctx).setChatPaymentMethods({
|
|
@@ -3249,6 +3292,18 @@ var TRANSPORT_NAMES = {
|
|
|
3249
3292
|
"iroh/1": "iroh/1",
|
|
3250
3293
|
"hyperdht/1": "hyperdht/1"
|
|
3251
3294
|
};
|
|
3295
|
+
/** The engine keeps a chat's name to 48 UTF-16 units (renameLink). */
|
|
3296
|
+
var CHAT_NAME_UNITS = 48;
|
|
3297
|
+
/**
|
|
3298
|
+
* A chat's name on this side (`chat rename`, an invite's `--label`): what the engine keeps whole, on one line, refused
|
|
3299
|
+
* with the rule as a profile's or a group's name is. Taken as given, the engine cut it at 48 UTF-16 units without a
|
|
3300
|
+
* word (half an emoji left as a lone surrogate) and kept line breaks. Counted as the engine counts: an emoji is two.
|
|
3301
|
+
*/
|
|
3302
|
+
function chatName(params, name) {
|
|
3303
|
+
const value = str(params, name);
|
|
3304
|
+
if (value !== void 0 && (value.trim().length > CHAT_NAME_UNITS || /\p{Cc}/u.test(value.trim()))) throw new CliError("bad_request", `A chat's name is up to ${CHAT_NAME_UNITS} characters on one line (an emoji counts as two)`);
|
|
3305
|
+
return value;
|
|
3306
|
+
}
|
|
3252
3307
|
/** Code points before `index` (UTF-16) in `text`: mentions count code points (WISP 902 § Mentions). */
|
|
3253
3308
|
var codePoints = (text, index) => [...text.slice(0, index)].length;
|
|
3254
3309
|
/**
|
|
@@ -3266,7 +3321,8 @@ function mentionsFor(text, refs, group) {
|
|
|
3266
3321
|
const lower = ref.toLowerCase();
|
|
3267
3322
|
const byKey = group.members.filter((m) => !m.me && m.key === ref);
|
|
3268
3323
|
const matches = byKey.length ? byKey : group.members.filter((m) => !m.me && (m.key.startsWith(ref) || m.nick?.trim().toLowerCase() === lower));
|
|
3269
|
-
if (matches.length
|
|
3324
|
+
if (matches.length > 1) throw new CliError("bad_request", `${JSON.stringify(ref)} names more than one member`);
|
|
3325
|
+
if (!matches.length) throw noMember(group, ref);
|
|
3270
3326
|
key = matches[0].key;
|
|
3271
3327
|
spelled = [
|
|
3272
3328
|
matches[0].nick?.trim(),
|
|
@@ -3409,7 +3465,7 @@ var METHODS = {
|
|
|
3409
3465
|
};
|
|
3410
3466
|
},
|
|
3411
3467
|
async "invite.create"(ctx, params) {
|
|
3412
|
-
const label =
|
|
3468
|
+
const label = chatName(params, "label");
|
|
3413
3469
|
const { linkId, inviteCode } = await node(ctx).createLink();
|
|
3414
3470
|
if (label) await node(ctx).renameLink({
|
|
3415
3471
|
linkId,
|
|
@@ -3433,6 +3489,7 @@ var METHODS = {
|
|
|
3433
3489
|
},
|
|
3434
3490
|
async "invite.join"(ctx, params) {
|
|
3435
3491
|
let invite = str(params, "invite", true).trim();
|
|
3492
|
+
const label = chatName(params, "label");
|
|
3436
3493
|
const hash = invite.indexOf("#");
|
|
3437
3494
|
if (/^https?:\/\//i.test(invite) && hash !== -1) invite = invite.slice(hash + 1);
|
|
3438
3495
|
let linkId;
|
|
@@ -3445,7 +3502,6 @@ var METHODS = {
|
|
|
3445
3502
|
if (/does not look like/i.test(message)) throw new CliError("bad_request", message);
|
|
3446
3503
|
throw error;
|
|
3447
3504
|
}
|
|
3448
|
-
const label = str(params, "label");
|
|
3449
3505
|
if (label) await node(ctx).renameLink({
|
|
3450
3506
|
linkId,
|
|
3451
3507
|
label
|
|
@@ -3718,7 +3774,7 @@ var METHODS = {
|
|
|
3718
3774
|
const link = chatNotGroup(ctx, params, "group rename", "<name...>");
|
|
3719
3775
|
await node(ctx).renameLink({
|
|
3720
3776
|
linkId: link.id,
|
|
3721
|
-
label:
|
|
3777
|
+
label: chatName(params, "name") ?? ""
|
|
3722
3778
|
});
|
|
3723
3779
|
return chatJson(findChat(state(ctx).links, link.id));
|
|
3724
3780
|
},
|
|
@@ -4016,6 +4072,7 @@ var METHODS = {
|
|
|
4016
4072
|
if (raw !== void 0 && (raw === null || typeof raw !== "object" || Array.isArray(raw))) throw new CliError("bad_request", "params must be an object");
|
|
4017
4073
|
let args = raw;
|
|
4018
4074
|
if (args && "confirmedReal" in args && !bool(params, "confirmReal")) throw new CliError("confirm", `${method} spends real money: pass --confirm-real (confirmReal: true over the socket) to confirm it`);
|
|
4075
|
+
if (args && ENGINE_SENDS.has(method) && !bool(params, "force")) await guardEngineSend(ctx, method, args);
|
|
4019
4076
|
if (method === "getMessages") return node(ctx).getMessages(str(args ?? {}, "linkId", true));
|
|
4020
4077
|
if (method === "getState") return state(ctx);
|
|
4021
4078
|
if (method === "setActiveLink") inviteShown.get(ctx)?.();
|
|
@@ -4025,6 +4082,29 @@ var METHODS = {
|
|
|
4025
4082
|
return await target.call(node(ctx), args) ?? null;
|
|
4026
4083
|
}
|
|
4027
4084
|
};
|
|
4085
|
+
/**
|
|
4086
|
+
* The engine's calls that send a text this side writes: `engine.call` runs the secret guard of `send`, `edit` and
|
|
4087
|
+
* `forward` on them too (docs/CLI.md § Safety), so a raw call is no way around it. `force: true` (`--force`) sends it.
|
|
4088
|
+
*/
|
|
4089
|
+
var ENGINE_SENDS = /* @__PURE__ */ new Set([
|
|
4090
|
+
"sendMessage",
|
|
4091
|
+
"sendGroupMessage",
|
|
4092
|
+
"editMessage",
|
|
4093
|
+
"forwardMessages"
|
|
4094
|
+
]);
|
|
4095
|
+
async function guardEngineSend(ctx, method, args) {
|
|
4096
|
+
let texts = [args.text, args.card];
|
|
4097
|
+
if (method === "forwardMessages") {
|
|
4098
|
+
const ids = Array.isArray(args.messageIds) ? args.messageIds.filter((id) => typeof id === "string") : [];
|
|
4099
|
+
const linkId = args.linkId;
|
|
4100
|
+
texts = typeof linkId === "string" && linkId ? await Promise.all(ids.map(async (id) => {
|
|
4101
|
+
const message = await node(ctx).getMessage(linkId, id);
|
|
4102
|
+
return message && !message.file ? message.text : null;
|
|
4103
|
+
})) : [];
|
|
4104
|
+
}
|
|
4105
|
+
const secret = secretIn(texts);
|
|
4106
|
+
if (secret) throw new CliError("confirm", `The text looks like ${secret.kind === "cashu" ? "a Cashu token (money anyone who reads it can take)" : "a secret (a seed or a private key)"}; call ${method} with --force if you mean to`, { kind: secret.kind });
|
|
4107
|
+
}
|
|
4028
4108
|
/** Reacts to a message of a chat or a group (`group:<id>`): `emoji`, or `remove` for "" (WISP 400 § Reactions). */
|
|
4029
4109
|
async function react(ctx, linkId, params) {
|
|
4030
4110
|
const messageId = str(params, "message", true);
|
|
@@ -4169,4 +4249,4 @@ async function callApi(ctx, method, params = {}) {
|
|
|
4169
4249
|
//#endregion
|
|
4170
4250
|
export { flushCardUpdates as _, hideStateSecrets as a, paymentJson as c, nodeLocalFetch as d, chatJson as f, resumeHolds as g, groupMessageJson as h, groupSendRefused as i, reportAppFrames as l, groupJson as m, SETTABLE as n, mentionsFor as o, chatMessageJson as p, callApi as r, redactSettings as s, API_METHODS as t, servedApps as u };
|
|
4171
4251
|
|
|
4172
|
-
//# sourceMappingURL=api-
|
|
4252
|
+
//# sourceMappingURL=api-Bp_hWAiU.js.map
|