@ghostlytools/cli 1.3.10 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/SKILL.md +7 -4
- package/dist/assets/{api-Cp9GxjUO.js → api-BqLfti32.js} +2 -2
- package/dist/assets/{api-BCrwJ57L.js → api-JMkEO0RR.js} +130 -50
- package/dist/assets/api-JMkEO0RR.js.map +1 -0
- package/dist/assets/{apiKit-B4qhnLQT.js → apiKit-BpIUCwa-.js} +3 -3
- package/dist/assets/{apiKit-B4qhnLQT.js.map → apiKit-BpIUCwa-.js.map} +1 -1
- package/dist/assets/{apps-CpxENMgl.js → apps-BdfyGVZ1.js} +1 -1
- package/dist/assets/{apps-DOH1P_S0.js → apps-Bettj7WQ.js} +6 -6
- package/dist/assets/apps-Bettj7WQ.js.map +1 -0
- package/dist/assets/{arkade-Cyf5MGxG.js → arkade-CP4HvKaa.js} +2 -2
- package/dist/assets/{arkade-Cyf5MGxG.js.map → arkade-CP4HvKaa.js.map} +1 -1
- package/dist/assets/{backup-CqM-0-2v.js → backup-BbO2zLjx.js} +1 -1
- package/dist/assets/{backup-CTpFFQ-4.js → backup-BmBtta66.js} +7 -7
- package/dist/assets/{backup-CTpFFQ-4.js.map → backup-BmBtta66.js.map} +1 -1
- package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
- package/dist/assets/bitcoindevkit_bg-B-iLWrmX.js.map +1 -1
- package/dist/assets/blobFiles-B0rNnHlO.js +35 -0
- package/dist/assets/blobFiles-B0rNnHlO.js.map +1 -0
- package/dist/assets/{buttons-BtxwyM2l.js → buttons-YgijrprJ.js} +4 -4
- package/dist/assets/{buttons-BtxwyM2l.js.map → buttons-YgijrprJ.js.map} +1 -1
- package/dist/assets/buttons-_GBlxAti.js +2 -0
- package/dist/assets/{endpoint-BOTFMpfS.js → endpoint-Cl3cgAYl.js} +3 -2
- package/dist/assets/endpoint-Cl3cgAYl.js.map +1 -0
- package/dist/assets/{envelope-DW8TWKPD.js → envelope-C7vnmsJN.js} +2 -2
- package/dist/assets/{envelope-DW8TWKPD.js.map → envelope-C7vnmsJN.js.map} +1 -1
- package/dist/assets/{errors-B-zMxbcd.js → errors-BLSPp0tK.js} +3 -1
- package/dist/assets/errors-BLSPp0tK.js.map +1 -0
- package/dist/assets/{fileBytes-Di7VZtmU.js → fileBytes-B-fqGdEd.js} +3 -3
- package/dist/assets/{fileBytes-Di7VZtmU.js.map → fileBytes-B-fqGdEd.js.map} +1 -1
- package/dist/assets/{fileBytes-CgbibpbV.js → fileBytes-C2jycN_7.js} +1 -1
- package/dist/assets/{fileBytes-CfSXjTFa.js → fileBytes-D6fqFQEX.js} +6 -3
- package/dist/assets/fileBytes-D6fqFQEX.js.map +1 -0
- package/dist/assets/fileBytesIdb-DOxm_BKt.js +2 -0
- package/dist/assets/{fileBytesIdb-D5u6H8X_.js → fileBytesIdb-_HnxdacI.js} +3 -3
- package/dist/assets/{fileBytesIdb-D5u6H8X_.js.map → fileBytesIdb-_HnxdacI.js.map} +1 -1
- package/dist/assets/{fileBytesOpfs-Dd1N4ERH.js → fileBytesOpfs-p_CANncD.js} +3 -3
- package/dist/assets/{fileBytesOpfs-Dd1N4ERH.js.map → fileBytesOpfs-p_CANncD.js.map} +1 -1
- package/dist/assets/{groupFiles-uxa0U9_n.js → groupFiles-sIdGq4AV.js} +5 -5
- package/dist/assets/groupFiles-sIdGq4AV.js.map +1 -0
- package/dist/assets/{host-BbDWamRc.js → host-Drd-c4VO.js} +43 -20
- package/dist/assets/host-Drd-c4VO.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-De5FT7Am.js → hyperdhtRelay-13aQ4KOf.js} +2 -2
- package/dist/assets/{hyperdhtRelay-De5FT7Am.js.map → hyperdhtRelay-13aQ4KOf.js.map} +1 -1
- package/dist/assets/{idb-B5L8wuOm.js → idb-CMVgtn2k.js} +59 -6
- package/dist/assets/idb-CMVgtn2k.js.map +1 -0
- package/dist/assets/{irohWeb-z5QDDWa-.js → irohWeb-DHCxSvHF.js} +2 -2
- package/dist/assets/{irohWeb-z5QDDWa-.js.map → irohWeb-DHCxSvHF.js.map} +1 -1
- package/dist/assets/{main-_q4Fgypp.js → main-BWAwKY4f.js} +476 -141
- package/dist/assets/main-BWAwKY4f.js.map +1 -0
- package/dist/assets/{mainline-Cld-bKeC.js → mainline-CsG-DdJ5.js} +2 -2
- package/dist/assets/{mainline-Cld-bKeC.js.map → mainline-CsG-DdJ5.js.map} +1 -1
- package/dist/assets/{networkReason-vUHo6A_C.js → networkReason-B91upMCb.js} +3 -3
- package/dist/assets/{networkReason-vUHo6A_C.js.map → networkReason-B91upMCb.js.map} +1 -1
- package/dist/assets/{nwc-zXpmd2FN.js → nwc-BFv67iSz.js} +3 -3
- package/dist/assets/{nwc-zXpmd2FN.js.map → nwc-BFv67iSz.js.map} +1 -1
- package/dist/assets/{nwcProvider-D482SQ1a.js → nwcProvider-BKNFdH9v.js} +2 -2
- package/dist/assets/{nwcProvider-D482SQ1a.js.map → nwcProvider-BKNFdH9v.js.map} +1 -1
- package/dist/assets/{profiles-gPCjLOQq.js → profiles-DSxPYdlU.js} +13 -3
- package/dist/assets/profiles-DSxPYdlU.js.map +1 -0
- package/dist/assets/{registry-CxsDR3c6.js → registry-CHPd_hf7.js} +1 -1
- package/dist/assets/{registry-OVx2kY3d.js → registry-qbnWmwCE.js} +3 -3
- package/dist/assets/registry-qbnWmwCE.js.map +1 -0
- package/dist/assets/{resolve-CPTAnu-9.js → resolve-B63_uSu7.js} +2 -2
- package/dist/assets/{resolve-CPTAnu-9.js.map → resolve-B63_uSu7.js.map} +1 -1
- package/dist/assets/{restoredRows-Db3oUTko.js → restoredRows-DeBImGRd.js} +2 -2
- package/dist/assets/{restoredRows-Db3oUTko.js.map → restoredRows-DeBImGRd.js.map} +1 -1
- package/dist/assets/{server-C-EkLCCt.js → server-Cd1dLOB8.js} +1456 -228
- package/dist/assets/server-Cd1dLOB8.js.map +1 -0
- package/dist/assets/{src-Dg1bvMNv.js → src-DzXL-GYu.js} +7277 -5975
- package/dist/assets/src-DzXL-GYu.js.map +1 -0
- package/dist/assets/turnRefs-BCtM10d3.js +357 -0
- package/dist/assets/turnRefs-BCtM10d3.js.map +1 -0
- package/dist/assets/{usdt-BY5OIIvG.js → usdt-B7JWDhQV.js} +3 -3
- package/dist/assets/{usdt-BY5OIIvG.js.map → usdt-B7JWDhQV.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +7 -6
- package/skills/ghostly/README.md +41 -0
- package/skills/ghostly/SKILL.md +79 -0
- package/skills/ghostly/scripts/listen +67 -0
- package/skills/ghostly/scripts/react +25 -0
- package/skills/ghostly/scripts/say +44 -0
- package/skills/ghostly/scripts/status +27 -0
- package/dist/assets/api-BCrwJ57L.js.map +0 -1
- package/dist/assets/apps-DOH1P_S0.js.map +0 -1
- package/dist/assets/buttons-CJqNkG-Q.js +0 -2
- package/dist/assets/endpoint-BOTFMpfS.js.map +0 -1
- package/dist/assets/errors-B-zMxbcd.js.map +0 -1
- package/dist/assets/fileBytes-CfSXjTFa.js.map +0 -1
- package/dist/assets/fileBytesIdb-CFP-DSkZ.js +0 -2
- package/dist/assets/groupFiles-uxa0U9_n.js.map +0 -1
- package/dist/assets/host-BbDWamRc.js.map +0 -1
- package/dist/assets/idb-B5L8wuOm.js.map +0 -1
- package/dist/assets/main-_q4Fgypp.js.map +0 -1
- package/dist/assets/profiles-gPCjLOQq.js.map +0 -1
- package/dist/assets/registry-OVx2kY3d.js.map +0 -1
- package/dist/assets/server-C-EkLCCt.js.map +0 -1
- package/dist/assets/src-Dg1bvMNv.js.map +0 -1
- package/dist/assets/turnRefs-WnggXm2T.js +0 -323
- package/dist/assets/turnRefs-WnggXm2T.js.map +0 -1
package/README.md
CHANGED
|
@@ -68,6 +68,10 @@ requests, tips and "balance" in a chat, with test coins: [examples/payment-bot.m
|
|
|
68
68
|
A Claude Code agent on `listen --turns` with an allowlist (it will not start without one), "thinking" while it works
|
|
69
69
|
and `send --reply` for its answer: [examples/claude-code-agent.sh](examples/claude-code-agent.sh).
|
|
70
70
|
|
|
71
|
+
Agents: [skills/ghostly](skills/ghostly) is a skill for an AI coding agent (Claude Code first) that talks to its
|
|
72
|
+
owner over Ghostly: `listen`, `say` (with buttons), `status` and `react`, in `sh`, and only the owner's chat gives it
|
|
73
|
+
orders.
|
|
74
|
+
|
|
71
75
|
## Profiles
|
|
72
76
|
|
|
73
77
|
Each profile is a folder, `~/.ghostly/profiles/<name>/` (0700; files 0600), with its own chats, keys and wallets.
|
|
@@ -84,7 +88,10 @@ waits until the message went out. Bots should run the daemon: a one-shot is offl
|
|
|
84
88
|
|
|
85
89
|
Every command prints one JSON object on stdout. A failure prints `{"error":{"code","message"}}` and exits with:
|
|
86
90
|
`1` failed (the engine or the network refused), `2` usage, `3` not found, `4` timed out, `5` needs a confirmation
|
|
87
|
-
(`--force`, `--yes`, `--confirm-real`). A
|
|
91
|
+
(`--force`, `--yes`, `--confirm-real`). A daemon that does not answer a read or `daemon status` within 15 seconds, or
|
|
92
|
+
a command that waits (`chat wait`, `file wait`, `--wait`) within its `--timeout` plus 10, is a timeout too (`4`,
|
|
93
|
+
`details.method`); `ghostly daemon restart` is the way out ([docs/CLI.md](../../docs/CLI.md#what-it-does)). A `<chat>` is
|
|
94
|
+
its id, a unique prefix of it, or its name; a `<group>` too.
|
|
88
95
|
|
|
89
96
|
The rows are in alphabetical order of their first command, and every command of `ghostly help` has one
|
|
90
97
|
(`test/readme.test.ts` checks both).
|
|
@@ -113,9 +120,9 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
113
120
|
| `chat transport <chat> <auto\|dht\|webrtc\|iroh\|hyperdht>` | What carries the chat |
|
|
114
121
|
| `chat verify <chat> --code <code>` | Mark the contact verified after comparing the codes out of band |
|
|
115
122
|
| `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
|
-
| `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 |
|
|
123
|
+
| `daemon [--detach] [--timeout s]`, `daemon status [--timeout s]`, `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
124
|
| `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] [--force]`, `engine --list` | Any call of the app's engine |
|
|
125
|
+
| `engine <method> [json \| -] [--confirm-real] [--show-secret] [--yes] [--force]`, `engine --list [--verbose]` | Any call of the app's engine; `--verbose` lists what each takes (`{ linkId, label }`, `?` for an optional key). A call given less than it takes is refused as `bad_request`. One that deletes chats or groups (`clearProfileData`, `removeLink`, `leaveGroup`, `forgetGroup`, `deviceRemove`) needs `--yes`; `clearProfileData` answers what it removed and stops a daemon. One that sends a text that looks like a secret (`sendMessage`, `sendGroupMessage`, `editMessage`, `forwardMessages`) needs `--force` |
|
|
119
126
|
| `events [--since seq]` | What the event journal holds, without following |
|
|
120
127
|
| `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
128
|
| `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) |
|
|
@@ -167,6 +174,8 @@ The rows are in alphabetical order of their first command, and every command of
|
|
|
167
174
|
| `wallet list [--network n]` | Wallets and balances, and what `wallet create` can make on each network |
|
|
168
175
|
| `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 |
|
|
169
176
|
| `wallet remove <type> [--network n] [--card id] [--accept-loss]` | Refused while it holds money or waits for some, unless `--accept-loss` |
|
|
177
|
+
| `x401 credential add <file\|-> [--label name]`, `x401 credential list [--show-secret]`, `x401 credential remove <id>` | x401 credentials ([WISP 3xx](../../docs/wisps/3xx-x401.md), a draft: test credentials only): keep an issued SD-JWT VC bound to a key from `x401 key new` (a label is up to 80 characters on one line), list them (claim paths; values only with `--show-secret`), remove one with its key. Never shared with contacts |
|
|
178
|
+
| `x401 key new` | A fresh P-256 holder key, one per credential: give its public JWK to the issuer. The 8 newest keys wait for a credential; a ninth drops the oldest (`dropped` names it) |
|
|
170
179
|
|
|
171
180
|
Help: `ghostly help` lists every command; `ghostly help file` (or `ghostly file --help`) a group; `ghostly help file
|
|
172
181
|
save` (or `ghostly file save --help`) one command, with its options. `-h` works too, except after `--`.
|
|
@@ -372,7 +381,7 @@ receive|address|redeem`, `wallet.mint.add`, `lightning.default|rename`, `pay`, `
|
|
|
372
381
|
`identity.providers|list|add|complete|cancel|remove|share|withdraw|contact|recheck`, `service.list|add|remove|enable|share|peer|open|close`,
|
|
373
382
|
`call.start|answer|hangup|list|get|flush|auto`,
|
|
374
383
|
`events.replay`, `events.subscribe`, `daemon.stop`, `daemon.hello`, and `engine.call` with
|
|
375
|
-
`{"method":"<engine call>","params":{…},"confirmReal":false}` for anything else the app does. Parameters are the
|
|
384
|
+
`{"method":"<engine call>","params":{…},"confirmReal":false,"yes":false}` for anything else the app does. Parameters are the
|
|
376
385
|
commands' (see `src/api.ts`). Errors: `{"id":…,"error":{"code","message","details"?}}` with the codes above.
|
|
377
386
|
|
|
378
387
|
Before its first request, a program can check that the socket is the profile's daemon and not a process that opened
|
package/SKILL.md
CHANGED
|
@@ -95,13 +95,14 @@ ghostly chat wait alice --until live # returns once Alice opened the link in
|
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
Give the link to the person through the channel your owner chose. To join someone else's invite instead:
|
|
98
|
-
`
|
|
98
|
+
`printf '%s' '<ghostly1… or https://ghostly.tools/#ghostly1…>' | ghostly invite join --label bob` (on stdin, not in `ps`
|
|
99
|
+
or the shell's history). `ghostly chat list` shows every
|
|
99
100
|
chat; a `<chat>` is its id, a unique prefix of it, or its name.
|
|
100
101
|
|
|
101
102
|
Names are for people at a terminal. A contact chooses its own name, a group's admin its group's name and a member its
|
|
102
103
|
name in a group, so in a script or an agent keep the **id** (`chat` and `group` in every answer and event, a member's
|
|
103
104
|
key) and address by it: `<chat id>`, `group:<group id>`, `<member key>`. Where a command takes a chat or a group, a
|
|
104
|
-
name that a contact gave itself and that also names one of your groups is refused (exit
|
|
105
|
+
name that a contact gave itself and that also names one of your groups is refused (exit 1, `bad_request`) and both ids are shown.
|
|
105
106
|
|
|
106
107
|
### 5. Be woken: listen with an allowlist
|
|
107
108
|
|
|
@@ -189,7 +190,7 @@ or open one because its sender asks: files come from other people.
|
|
|
189
190
|
### 9. Groups and mentions
|
|
190
191
|
|
|
191
192
|
```bash
|
|
192
|
-
|
|
193
|
+
printf '%s' '<group link>' | ghostly group join # a link your owner gave you; on stdin, not in ps
|
|
193
194
|
ghostly group create "Support" # a community {"group","link"}; --mesh for a private group
|
|
194
195
|
ghostly group send Support "Thanks @Ana, on it" --mention Ana --reply <message id>
|
|
195
196
|
ghostly group history Support # each message names its member (key) and nick
|
|
@@ -368,7 +369,9 @@ proof needs a person who holds the key: leave that to the owner.
|
|
|
368
369
|
|
|
369
370
|
## Anything else
|
|
370
371
|
|
|
371
|
-
Every call of the app's engine is reachable: `ghostly engine --list
|
|
372
|
+
Every call of the app's engine is reachable: `ghostly engine --list --verbose` (each call with what it takes), then `ghostly engine <method> '<json params>'`.
|
|
373
|
+
A call that deletes chats or groups (`clearProfileData`, `removeLink`, `leaveGroup`, `forgetGroup`, `deviceRemove`)
|
|
374
|
+
needs `--yes`; `clearProfileData` stops a running daemon after it answers.
|
|
372
375
|
Not on the CLI yet: Bark wallets, OpenID Connect proofs, and video in calls (voice only). More:
|
|
373
376
|
[AI agents on Ghostly](https://ghostly.tools/developers/agents), the
|
|
374
377
|
[CLI guide](https://github.com/MiguelMedeiros/ghostly/blob/main/docs/CLI.md), the
|
|
@@ -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-BpIUCwa-.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-JMkEO0RR.js";
|
|
3
3
|
export { API_METHODS, SETTABLE, callApi, findChat, findGroup, groupSendRefused, hideStateSecrets, mentionsFor, redactSettings };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { $
|
|
2
|
-
import {
|
|
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-
|
|
4
|
-
import { f as FILE_BYTES_STEP, o as fileBytes, s as fileBytesOf } from "./fileBytes-
|
|
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
|
|
8
|
-
import { i as localFileError, r as asCliError, 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 {
|
|
11
|
-
import {
|
|
1
|
+
import { $l as randomBytes$1, Ac as isAppRef, Ba as appCardId, Bi as identityStatement, Ec as appRef, Ha as cardLine, Ic as readImageMeta, Jl as sanitizeAvatar, Mr as TYPING_REFRESH_MS, Pr as sanitizeTypingStatus, Qc as ownInviteRefusal, Qr as APP_DATA_MAX_BYTES, Un as GROUP_FILE_LIMITS, Wa as checkStatusCard, Xc as inviteLink, Y as groupName, aa as sanitizeMime, ca as baseMime, da as voicePeaksOf, eu as toBase64Url, ho as GhostlyHttpError, ia as sanitizeFileName, jr as TYPING_KINDS, lo as AWAITING_PEER_MS, oa as PLAYABLE_AUDIO, pc as APP_PERMISSIONS, ql as MAX_AVATAR_LENGTH, sa as VOICE_LIMITS, ua as parseVoiceMeta, vc as isAppUrl, yo as LIMITS, za as STATUS_CARD_LIMITS } from "./src-DzXL-GYu.js";
|
|
2
|
+
import { l as fileStore } from "./idb-CMVgtn2k.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-sIdGq4AV.js";
|
|
4
|
+
import { f as FILE_BYTES_STEP, o as fileBytes, s as fileBytesOf } from "./fileBytes-B-fqGdEd.js";
|
|
5
|
+
import { t as IDENTITY_PROVIDERS } from "./registry-qbnWmwCE.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-YgijrprJ.js";
|
|
7
|
+
import { a as ENGINE_PARAMS, i as ENGINE_METHODS, l as engineParamsProblem, n as withStoredIds, o as ENGINE_READS, r as DESTRUCTIVE_CALLS, s as READ_PARAMS } from "./turnRefs-BCtM10d3.js";
|
|
8
|
+
import { i as localFileError, r as asCliError, t as CliError } from "./errors-BLSPp0tK.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-BpIUCwa-.js";
|
|
10
|
+
import { a as checkShownName } from "./profiles-DSxPYdlU.js";
|
|
11
|
+
import { t as BACKUP_METHODS } from "./backup-BmBtta66.js";
|
|
12
|
+
import { o as checkedBundle } from "./apps-Bettj7WQ.js";
|
|
12
13
|
import { generateMnemonic } from "@scure/bip39";
|
|
13
14
|
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
14
15
|
import { openAsBlob, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -2058,6 +2059,47 @@ var IDENTITY_METHODS = {
|
|
|
2058
2059
|
}
|
|
2059
2060
|
};
|
|
2060
2061
|
//#endregion
|
|
2062
|
+
//#region src/x401.ts
|
|
2063
|
+
/**
|
|
2064
|
+
* x401 credentials (WISP 3xx): the holder keys and issued credentials a bot keeps to show a website who stands behind
|
|
2065
|
+
* it. Here only keeping them: `x401 fetch`, which presents one, comes later. Claim values are printed only with
|
|
2066
|
+
* `--show-secret`; the credential itself and the holder keys never leave the profile.
|
|
2067
|
+
*/
|
|
2068
|
+
/** The engine's refusals (a credential that does not read, expired, bound to another key) are the caller's to fix. */
|
|
2069
|
+
async function engine$1(work) {
|
|
2070
|
+
try {
|
|
2071
|
+
return await work();
|
|
2072
|
+
} catch (error) {
|
|
2073
|
+
throw new CliError("bad_request", error instanceof Error ? error.message : String(error));
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
var X401_METHODS = {
|
|
2077
|
+
/** `dropped`: the oldest key still waiting, gone for this one (a profile keeps the 8 newest waiting). */
|
|
2078
|
+
async "x401.key.new"(ctx) {
|
|
2079
|
+
const { id, jwk, dropped } = await node(ctx).newX401HolderKey();
|
|
2080
|
+
return {
|
|
2081
|
+
key: id,
|
|
2082
|
+
jwk,
|
|
2083
|
+
...dropped ? { dropped } : {}
|
|
2084
|
+
};
|
|
2085
|
+
},
|
|
2086
|
+
async "x401.credential.add"(ctx, params) {
|
|
2087
|
+
const label = str(params, "label");
|
|
2088
|
+
return { credential: await engine$1(() => node(ctx).addX401Credential({
|
|
2089
|
+
credential: str(params, "credential", true),
|
|
2090
|
+
...label ? { label } : {}
|
|
2091
|
+
})) };
|
|
2092
|
+
},
|
|
2093
|
+
async "x401.credential.list"(ctx, params) {
|
|
2094
|
+
return { credentials: await node(ctx).x401Credentials({ values: bool(params, "showSecret") }) };
|
|
2095
|
+
},
|
|
2096
|
+
async "x401.credential.remove"(ctx, params) {
|
|
2097
|
+
const id = str(params, "id", true);
|
|
2098
|
+
if (!await node(ctx).removeX401Credential({ id })) throw new CliError("not_found", `No x401 credential ${JSON.stringify(id)} (ghostly x401 credential list)`);
|
|
2099
|
+
return { removed: id };
|
|
2100
|
+
}
|
|
2101
|
+
};
|
|
2102
|
+
//#endregion
|
|
2061
2103
|
//#region src/services.ts
|
|
2062
2104
|
/**
|
|
2063
2105
|
* Shared services (WISP 700/701, WISP 1100 phase 3b): a web app on this machine a contact may open over the chat's live
|
|
@@ -3392,6 +3434,8 @@ function showUntilPaired(ctx, linkId) {
|
|
|
3392
3434
|
});
|
|
3393
3435
|
inviteShown.set(ctx, stop);
|
|
3394
3436
|
}
|
|
3437
|
+
/** V8's words for reading what a value does not have: an `engine.call` given a parameter of the wrong kind. */
|
|
3438
|
+
var BAD_VALUE = /^Cannot (destructure|read properties of (undefined|null))|is not (a function|iterable)/;
|
|
3395
3439
|
var METHODS = {
|
|
3396
3440
|
...WALLET_METHODS,
|
|
3397
3441
|
...FILE_METHODS,
|
|
@@ -3399,6 +3443,7 @@ var METHODS = {
|
|
|
3399
3443
|
...BUTTON_METHODS,
|
|
3400
3444
|
...GROUP_ADMIN_METHODS,
|
|
3401
3445
|
...IDENTITY_METHODS,
|
|
3446
|
+
...X401_METHODS,
|
|
3402
3447
|
...SERVICE_METHODS,
|
|
3403
3448
|
...BACKUP_METHODS,
|
|
3404
3449
|
...CALL_METHODS,
|
|
@@ -3437,11 +3482,7 @@ var METHODS = {
|
|
|
3437
3482
|
},
|
|
3438
3483
|
async "profile.set"(ctx, params) {
|
|
3439
3484
|
const patch = {};
|
|
3440
|
-
|
|
3441
|
-
if (name !== void 0) {
|
|
3442
|
-
if (typeof name !== "string" || [...name].length > 64) throw new CliError("bad_request", "name must be a string of up to 64 characters");
|
|
3443
|
-
patch.nick = name.trim();
|
|
3444
|
-
}
|
|
3485
|
+
if (params.name !== void 0) patch.nick = checkShownName(params.name);
|
|
3445
3486
|
if (params.shareProfile !== void 0) patch.shareProfile = bool(params, "shareProfile");
|
|
3446
3487
|
await node(ctx).updateSettings({ settings: patch });
|
|
3447
3488
|
return METHODS["profile.get"](ctx, {});
|
|
@@ -3458,6 +3499,10 @@ var METHODS = {
|
|
|
3458
3499
|
if (kind === "strings" && !(Array.isArray(value) && value.every((v) => typeof v === "string"))) throw new CliError("bad_request", `${key} must be a list of strings`);
|
|
3459
3500
|
if (kind === "string" && typeof value !== "string") throw new CliError("bad_request", `${key} must be a string`);
|
|
3460
3501
|
if (kind === "boolean" && typeof value !== "boolean") throw new CliError("bad_request", `${key} must be true or false`);
|
|
3502
|
+
if (key === "nick") {
|
|
3503
|
+
patch.nick = checkShownName(value, key);
|
|
3504
|
+
continue;
|
|
3505
|
+
}
|
|
3461
3506
|
if (kind === "ice") {
|
|
3462
3507
|
if (!(Array.isArray(value) && value.every((v) => v && typeof v === "object"))) throw new CliError("bad_request", `${key} must be a list of ICE servers`);
|
|
3463
3508
|
const servers = value.map(iceServerSetting);
|
|
@@ -3553,6 +3598,10 @@ var METHODS = {
|
|
|
3553
3598
|
"sent",
|
|
3554
3599
|
"delivered"
|
|
3555
3600
|
], "none");
|
|
3601
|
+
const ms = num(params, "timeout", 30, {
|
|
3602
|
+
min: 1,
|
|
3603
|
+
max: 3600
|
|
3604
|
+
}) * 1e3;
|
|
3556
3605
|
const replyTo = str(params, "reply");
|
|
3557
3606
|
const card = buttonsCard(params);
|
|
3558
3607
|
endTyping(ctx, { linkId: link.id }, false);
|
|
@@ -3565,10 +3614,7 @@ var METHODS = {
|
|
|
3565
3614
|
if (result.error) throw /not in this chat|cannot be replied to/.test(result.error) ? new CliError("not_found", result.error) : new CliError(result.refused ? "refused" : "unavailable", result.error);
|
|
3566
3615
|
if (!result.messageId) throw new CliError("bad_request", "Nothing to send");
|
|
3567
3616
|
let message = await node(ctx).getMessage(link.id, result.messageId);
|
|
3568
|
-
if (wait !== "none") message = await waitForMessage(ctx, link.id, result.messageId, wait,
|
|
3569
|
-
min: 1,
|
|
3570
|
-
max: 3600
|
|
3571
|
-
}) * 1e3);
|
|
3617
|
+
if (wait !== "none") message = await waitForMessage(ctx, link.id, result.messageId, wait, ms);
|
|
3572
3618
|
return {
|
|
3573
3619
|
chat: link.id,
|
|
3574
3620
|
messageId: result.messageId,
|
|
@@ -3593,6 +3639,10 @@ var METHODS = {
|
|
|
3593
3639
|
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)"}; edit with --force if you mean to`, { kind: secret.kind });
|
|
3594
3640
|
}
|
|
3595
3641
|
const wait = oneOf(params, "wait", ["none", "confirmed"], "none");
|
|
3642
|
+
const ms = num(params, "timeout", 30, {
|
|
3643
|
+
min: 1,
|
|
3644
|
+
max: 3600
|
|
3645
|
+
}) * 1e3;
|
|
3596
3646
|
const result = await node(ctx).editMessage({
|
|
3597
3647
|
linkId: link.id,
|
|
3598
3648
|
messageId,
|
|
@@ -3601,10 +3651,7 @@ var METHODS = {
|
|
|
3601
3651
|
if (result.error) throw editRefused(await messageOf(ctx, link.id, messageId), messageId, "chat", result.error, result.refused);
|
|
3602
3652
|
const id = result.messageId ?? messageId;
|
|
3603
3653
|
let message = await node(ctx).getMessage(link.id, id);
|
|
3604
|
-
if (wait === "confirmed" && message?.edit?.pending) message = await waitForEdit(ctx, link.id, id,
|
|
3605
|
-
min: 1,
|
|
3606
|
-
max: 3600
|
|
3607
|
-
}) * 1e3);
|
|
3654
|
+
if (wait === "confirmed" && message?.edit?.pending) message = await waitForEdit(ctx, link.id, id, ms);
|
|
3608
3655
|
return {
|
|
3609
3656
|
chat: link.id,
|
|
3610
3657
|
messageId: id,
|
|
@@ -3705,6 +3752,10 @@ var METHODS = {
|
|
|
3705
3752
|
});
|
|
3706
3753
|
}
|
|
3707
3754
|
const wait = oneOf(params, "wait", ["none", "sent"], "none");
|
|
3755
|
+
const ms = num(params, "timeout", 30, {
|
|
3756
|
+
min: 1,
|
|
3757
|
+
max: 3600
|
|
3758
|
+
}) * 1e3;
|
|
3708
3759
|
let results;
|
|
3709
3760
|
try {
|
|
3710
3761
|
({results} = await node(ctx).forwardMessages({
|
|
@@ -3715,14 +3766,11 @@ var METHODS = {
|
|
|
3715
3766
|
} catch (error) {
|
|
3716
3767
|
throw new CliError("refused", error instanceof Error ? error.message : String(error));
|
|
3717
3768
|
}
|
|
3718
|
-
const ms = num(params, "timeout", 30, {
|
|
3719
|
-
min: 1,
|
|
3720
|
-
max: 3600
|
|
3721
|
-
}) * 1e3;
|
|
3722
3769
|
const out = results.map((result, i) => ({
|
|
3723
3770
|
to: to[i].id,
|
|
3724
3771
|
kind: to[i].group ? "group" : "chat",
|
|
3725
3772
|
messageIds: result.messageIds,
|
|
3773
|
+
sent: result.sent,
|
|
3726
3774
|
error: result.error
|
|
3727
3775
|
}));
|
|
3728
3776
|
if (wait === "sent") for (const [i, result] of out.entries()) for (const messageId of result.messageIds) {
|
|
@@ -3916,6 +3964,10 @@ var METHODS = {
|
|
|
3916
3964
|
const mentions = mentionsFor(text, list(params, "mentions"), group);
|
|
3917
3965
|
const replyTo = str(params, "reply");
|
|
3918
3966
|
const wait = oneOf(params, "wait", ["none", "sent"], "none");
|
|
3967
|
+
const ms = num(params, "timeout", 30, {
|
|
3968
|
+
min: 1,
|
|
3969
|
+
max: 3600
|
|
3970
|
+
}) * 1e3;
|
|
3919
3971
|
const card = buttonsCard(params);
|
|
3920
3972
|
endTyping(ctx, { groupId: group.id }, false);
|
|
3921
3973
|
const result = await node(ctx).sendGroupMessage({
|
|
@@ -3927,10 +3979,7 @@ var METHODS = {
|
|
|
3927
3979
|
});
|
|
3928
3980
|
if (result.error) throw result.refused ? new CliError("refused", result.error) : groupSendRefused(result.error);
|
|
3929
3981
|
const messageId = result.messageId ?? null;
|
|
3930
|
-
const edges = messageId ? wait === "sent" ? await waitForGroupFrame(ctx, group.id, messageId, void 0,
|
|
3931
|
-
min: 1,
|
|
3932
|
-
max: 3600
|
|
3933
|
-
}) * 1e3) : node(ctx).groupTaken({
|
|
3982
|
+
const edges = messageId ? wait === "sent" ? await waitForGroupFrame(ctx, group.id, messageId, void 0, ms) : node(ctx).groupTaken({
|
|
3934
3983
|
groupId: group.id,
|
|
3935
3984
|
messageId
|
|
3936
3985
|
}) : 0;
|
|
@@ -3960,6 +4009,10 @@ var METHODS = {
|
|
|
3960
4009
|
}
|
|
3961
4010
|
const mentions = mentionsFor(text, list(params, "mentions"), group);
|
|
3962
4011
|
const wait = oneOf(params, "wait", ["none", "sent"], "none");
|
|
4012
|
+
const ms = num(params, "timeout", 30, {
|
|
4013
|
+
min: 1,
|
|
4014
|
+
max: 3600
|
|
4015
|
+
}) * 1e3;
|
|
3963
4016
|
const linkId = `group:${group.id}`;
|
|
3964
4017
|
const before = (await node(ctx).getMessage(linkId, messageId))?.edit?.seq ?? 0;
|
|
3965
4018
|
const result = await node(ctx).editMessage({
|
|
@@ -3979,10 +4032,7 @@ var METHODS = {
|
|
|
3979
4032
|
edges: 0,
|
|
3980
4033
|
unchanged: true
|
|
3981
4034
|
};
|
|
3982
|
-
const edges = !edits ? 0 : wait === "sent" ? await waitForGroupFrame(ctx, group.id, messageId, edits,
|
|
3983
|
-
min: 1,
|
|
3984
|
-
max: 3600
|
|
3985
|
-
}) * 1e3) : node(ctx).groupTaken({
|
|
4035
|
+
const edges = !edits ? 0 : wait === "sent" ? await waitForGroupFrame(ctx, group.id, messageId, edits, ms) : node(ctx).groupTaken({
|
|
3986
4036
|
groupId: group.id,
|
|
3987
4037
|
messageId,
|
|
3988
4038
|
edit: edits
|
|
@@ -4086,19 +4136,52 @@ var METHODS = {
|
|
|
4086
4136
|
if (!ENGINE_METHODS.includes(method) && !ENGINE_READS.includes(method)) throw new CliError("not_found", `The engine has no call ${method}`);
|
|
4087
4137
|
const raw = params.params;
|
|
4088
4138
|
if (raw !== void 0 && (raw === null || typeof raw !== "object" || Array.isArray(raw))) throw new CliError("bad_request", "params must be an object");
|
|
4089
|
-
|
|
4139
|
+
const args = raw;
|
|
4090
4140
|
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`);
|
|
4141
|
+
const deletes = DESTRUCTIVE_CALLS.get(method);
|
|
4142
|
+
if (deletes && !bool(params, "yes")) throw new CliError("confirm", `${method} ${deletes}; pass --yes (yes: true over the socket) to go on`);
|
|
4143
|
+
if (method === "clearProfileData") return clearProfile(ctx);
|
|
4144
|
+
const takes = ENGINE_PARAMS[method] ?? READ_PARAMS[method];
|
|
4145
|
+
const wrong = (why, rawError) => new CliError("bad_request", `${method} takes ${takes || "no parameters"}: ${why} (ghostly engine --list --verbose)`, {
|
|
4146
|
+
takes,
|
|
4147
|
+
...rawError ? { rawError } : {}
|
|
4148
|
+
});
|
|
4149
|
+
const problem = engineParamsProblem(method, args);
|
|
4150
|
+
if (problem) throw wrong(problem);
|
|
4091
4151
|
if (args && ENGINE_SENDS.has(method) && !bool(params, "force")) await guardEngineSend(ctx, method, args);
|
|
4092
4152
|
if (method === "getMessages") return node(ctx).getMessages(str(args ?? {}, "linkId", true));
|
|
4093
4153
|
if (method === "getState") return state(ctx);
|
|
4094
4154
|
if (method === "setActiveLink") inviteShown.get(ctx)?.();
|
|
4095
4155
|
const target = node(ctx)[method];
|
|
4096
4156
|
if (typeof target !== "function") throw new CliError("not_found", `The engine has no call ${method}`);
|
|
4097
|
-
|
|
4098
|
-
|
|
4157
|
+
try {
|
|
4158
|
+
return await target.call(node(ctx), args) ?? null;
|
|
4159
|
+
} catch (error) {
|
|
4160
|
+
if (error instanceof TypeError && BAD_VALUE.test(error.message)) throw wrong("a parameter of the wrong kind", error.message);
|
|
4161
|
+
throw error;
|
|
4162
|
+
}
|
|
4099
4163
|
}
|
|
4100
4164
|
};
|
|
4101
4165
|
/**
|
|
4166
|
+
* "Clear all data": the engine withdraws what it can, stops and empties its stores; the app reloads its page after it.
|
|
4167
|
+
* A daemon would go on serving the stopped engine's memory (chats and groups that are gone, new ones that are not
|
|
4168
|
+
* kept): it stops once it has answered, and the next command starts on the emptied profile.
|
|
4169
|
+
*/
|
|
4170
|
+
async function clearProfile(ctx) {
|
|
4171
|
+
const { links, groups } = state(ctx);
|
|
4172
|
+
await node(ctx).clearProfileData();
|
|
4173
|
+
const cleared = {
|
|
4174
|
+
chats: links.length,
|
|
4175
|
+
groups: groups.length
|
|
4176
|
+
};
|
|
4177
|
+
if (ctx.mode !== "daemon" || !ctx.stop) return { cleared };
|
|
4178
|
+
setTimeout(() => ctx.stop(), 10);
|
|
4179
|
+
return {
|
|
4180
|
+
cleared,
|
|
4181
|
+
stopped: true
|
|
4182
|
+
};
|
|
4183
|
+
}
|
|
4184
|
+
/**
|
|
4102
4185
|
* The engine's calls that send a text this side writes (a message, a file's caption, a payment's memo): `engine.call`
|
|
4103
4186
|
* runs the secret guard of `send`, `edit` and `forward` on them too (docs/CLI.md § Safety), so a raw call is no way around it. `force: true` (`--force`) sends it.
|
|
4104
4187
|
*/
|
|
@@ -4244,20 +4327,17 @@ function history(messages, params, json = messageJson) {
|
|
|
4244
4327
|
});
|
|
4245
4328
|
const before = params.before;
|
|
4246
4329
|
const after = params.after;
|
|
4247
|
-
|
|
4248
|
-
const
|
|
4330
|
+
const sorted = messages.slice().sort((a, b) => a.timestamp - b.timestamp);
|
|
4331
|
+
const bound = (value, side) => {
|
|
4249
4332
|
if (value === void 0 || value === null) return;
|
|
4250
|
-
if (typeof value === "number")
|
|
4251
|
-
list = list.filter((m) => side === "before" ? m.timestamp < value : m.timestamp > value);
|
|
4252
|
-
return;
|
|
4253
|
-
}
|
|
4333
|
+
if (typeof value === "number") return (m) => side === "before" ? m.timestamp < value : m.timestamp > value;
|
|
4254
4334
|
if (typeof value !== "string") throw new CliError("bad_request", `${side} must be a timestamp or a message id`);
|
|
4255
|
-
const index =
|
|
4335
|
+
const index = sorted.findIndex((m) => m.id === value);
|
|
4256
4336
|
if (index === -1) throw new CliError("not_found", `No message ${value}`);
|
|
4257
|
-
|
|
4337
|
+
return (_, at) => side === "before" ? at < index : at > index;
|
|
4258
4338
|
};
|
|
4259
|
-
|
|
4260
|
-
|
|
4339
|
+
const bounds = [bound(before, "before"), bound(after, "after")].filter((b) => b !== void 0);
|
|
4340
|
+
const list = sorted.filter((m, at) => bounds.every((within) => within(m, at)));
|
|
4261
4341
|
const more = after !== void 0 && after !== null ? list.length > limit : list.length > limit;
|
|
4262
4342
|
return {
|
|
4263
4343
|
messages: (after !== void 0 && after !== null ? list.slice(0, limit) : list.slice(-limit)).map((m) => json(m)),
|
|
@@ -4275,4 +4355,4 @@ async function callApi(ctx, method, params = {}) {
|
|
|
4275
4355
|
//#endregion
|
|
4276
4356
|
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 };
|
|
4277
4357
|
|
|
4278
|
-
//# sourceMappingURL=api-
|
|
4358
|
+
//# sourceMappingURL=api-JMkEO0RR.js.map
|