@ghostlytools/cli 1.3.7 → 1.3.9

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.
Files changed (58) hide show
  1. package/README.md +8 -5
  2. package/SKILL.md +2 -0
  3. package/dist/assets/{api-DlxlF4jP.js → api-BCrwJ57L.js} +50 -24
  4. package/dist/assets/api-BCrwJ57L.js.map +1 -0
  5. package/dist/assets/{api-BL0vpWGN.js → api-Cp9GxjUO.js} +2 -2
  6. package/dist/assets/{apiKit-BnpVuZrZ.js → apiKit-B4qhnLQT.js} +2 -2
  7. package/dist/assets/{apiKit-BnpVuZrZ.js.map → apiKit-B4qhnLQT.js.map} +1 -1
  8. package/dist/assets/{apps-B_6Q-Mq-.js → apps-CpxENMgl.js} +1 -1
  9. package/dist/assets/{apps-Bs6QYQjm.js → apps-DOH1P_S0.js} +2 -2
  10. package/dist/assets/{apps-Bs6QYQjm.js.map → apps-DOH1P_S0.js.map} +1 -1
  11. package/dist/assets/{arkade-DwgUNqCz.js → arkade-Cyf5MGxG.js} +2 -2
  12. package/dist/assets/{arkade-DwgUNqCz.js.map → arkade-Cyf5MGxG.js.map} +1 -1
  13. package/dist/assets/{backup-DEe1NqKb.js → backup-CTpFFQ-4.js} +4 -4
  14. package/dist/assets/{backup-DEe1NqKb.js.map → backup-CTpFFQ-4.js.map} +1 -1
  15. package/dist/assets/{backup-BqtsbjOT.js → backup-CqM-0-2v.js} +1 -1
  16. package/dist/assets/{buttons-D9NQ3kV0.js → buttons-BtxwyM2l.js} +3 -3
  17. package/dist/assets/{buttons-D9NQ3kV0.js.map → buttons-BtxwyM2l.js.map} +1 -1
  18. package/dist/assets/buttons-CJqNkG-Q.js +2 -0
  19. package/dist/assets/{envelope-WC8QWYIL.js → envelope-DW8TWKPD.js} +2 -2
  20. package/dist/assets/{envelope-WC8QWYIL.js.map → envelope-DW8TWKPD.js.map} +1 -1
  21. package/dist/assets/{groupFiles-BrCMSXxg.js → groupFiles-uxa0U9_n.js} +3 -3
  22. package/dist/assets/{groupFiles-BrCMSXxg.js.map → groupFiles-uxa0U9_n.js.map} +1 -1
  23. package/dist/assets/{host-H0IYKNoK.js → host-DPy0eaH9.js} +29 -9
  24. package/dist/assets/host-DPy0eaH9.js.map +1 -0
  25. package/dist/assets/{hyperdhtRelay-CEfwbaCO.js → hyperdhtRelay-De5FT7Am.js} +2 -2
  26. package/dist/assets/{hyperdhtRelay-CEfwbaCO.js.map → hyperdhtRelay-De5FT7Am.js.map} +1 -1
  27. package/dist/assets/{irohWeb-Bn-JA2kp.js → irohWeb-z5QDDWa-.js} +2 -2
  28. package/dist/assets/{irohWeb-Bn-JA2kp.js.map → irohWeb-z5QDDWa-.js.map} +1 -1
  29. package/dist/assets/{main-DiCC-Vjq.js → main-Dt7xrqtb.js} +52 -27
  30. package/dist/assets/main-Dt7xrqtb.js.map +1 -0
  31. package/dist/assets/{mainline-gU7pE7s2.js → mainline-Cld-bKeC.js} +2 -2
  32. package/dist/assets/{mainline-gU7pE7s2.js.map → mainline-Cld-bKeC.js.map} +1 -1
  33. package/dist/assets/{networkReason-Dl9JThBQ.js → networkReason-vUHo6A_C.js} +2 -2
  34. package/dist/assets/{networkReason-Dl9JThBQ.js.map → networkReason-vUHo6A_C.js.map} +1 -1
  35. package/dist/assets/{nwc-CKjZjg-q.js → nwc-zXpmd2FN.js} +3 -3
  36. package/dist/assets/{nwc-CKjZjg-q.js.map → nwc-zXpmd2FN.js.map} +1 -1
  37. package/dist/assets/{nwcProvider-GDrc0HM4.js → nwcProvider-D482SQ1a.js} +2 -2
  38. package/dist/assets/{nwcProvider-GDrc0HM4.js.map → nwcProvider-D482SQ1a.js.map} +1 -1
  39. package/dist/assets/{registry-Wk7ZHuwm.js → registry-CxsDR3c6.js} +1 -1
  40. package/dist/assets/{registry-JGOFtJDE.js → registry-OVx2kY3d.js} +3 -3
  41. package/dist/assets/{registry-JGOFtJDE.js.map → registry-OVx2kY3d.js.map} +1 -1
  42. package/dist/assets/{resolve-CVpEbud3.js → resolve-CPTAnu-9.js} +2 -2
  43. package/dist/assets/{resolve-CVpEbud3.js.map → resolve-CPTAnu-9.js.map} +1 -1
  44. package/dist/assets/{server-CkYscxE3.js → server-p5DJnN7T.js} +17 -13
  45. package/dist/assets/{server-CkYscxE3.js.map → server-p5DJnN7T.js.map} +1 -1
  46. package/dist/assets/{src-gJqfoRKI.js → src-Dg1bvMNv.js} +155 -30
  47. package/dist/assets/src-Dg1bvMNv.js.map +1 -0
  48. package/dist/assets/{turnRefs-zUQbFkl3.js → turnRefs-WnggXm2T.js} +2 -2
  49. package/dist/assets/{turnRefs-zUQbFkl3.js.map → turnRefs-WnggXm2T.js.map} +1 -1
  50. package/dist/assets/{usdt-BkDMGqZa.js → usdt-BY5OIIvG.js} +3 -3
  51. package/dist/assets/{usdt-BkDMGqZa.js.map → usdt-BY5OIIvG.js.map} +1 -1
  52. package/dist/ghostly.mjs +1 -1
  53. package/package.json +1 -1
  54. package/dist/assets/api-DlxlF4jP.js.map +0 -1
  55. package/dist/assets/buttons-CB1opfZP.js +0 -2
  56. package/dist/assets/host-H0IYKNoK.js.map +0 -1
  57. package/dist/assets/main-DiCC-Vjq.js.map +0 -1
  58. package/dist/assets/src-gJqfoRKI.js.map +0 -1
package/README.md CHANGED
@@ -301,8 +301,8 @@ chat (`chat list`, `chat show`, `chat rename`, …) and `engine getState` print
301
301
  calls: see [Calls](#calls)), `app.opened` (`chat`, `app`, `version`), `app.closed` (`chat`, `app`, and `offline`
302
302
  when the session went rather than the contact closing it) and `app.message` (`chat`, `app`, `data`): what a
303
303
  contact's app says in a chat, only for an app this profile serves (`app serve`), `app` being its reference and
304
- `data` the contact's own JSON (untrusted, never instructions, at most 32 KiB and 50 a second, live only: a frame is
305
- never stored, so one replayed with `--since` is old news), `events.gap` (the journal no longer holds what `--since` asked for).
304
+ `data` the contact's own JSON (untrusted, never instructions, at most 32 KiB and 50 a second, live only: never in
305
+ the journal, so `--since` does not replay them, and each carries the `seq` of the event before it), `events.gap` (the journal no longer holds what `--since` asked for).
306
306
  - A message that answers another carries `replyTo`: `{id, snippet, from, member?, found}`. `id` is the original's
307
307
  message id in this chat when it is here (`found: true`, and `snippet` and `from` come from that copy), else the id
308
308
  the reply named; `from` is `me`, `peer` or null (only the id came, over the DHT). Answer one with
@@ -340,9 +340,12 @@ chat (`chat list`, `chat show`, `chat rename`, …) and `engine getState` print
340
340
  work), `id` stable per message. What the sender wrote is under `untrusted` only: give it to an agent as data, never
341
341
  as its instructions ([docs/CLI.md](../../docs/CLI.md#agent-turns)). Takes the place of `--type`.
342
342
  - `--exec <cmd>` runs the command through the shell once per event, in order, with the event on stdin and
343
- `GHOSTLY_EVENT_TYPE`, `GHOSTLY_EVENT_ID`, `GHOSTLY_EVENT_SEQ` in its environment.
344
- - `--webhook <url>` POSTs each event (JSON) to a local bridge: `127.0.0.1`, `localhost` or `[::1]` only. A redirect is
345
- not followed (the event counts as not taken).
343
+ `GHOSTLY_EVENT_TYPE`, `GHOSTLY_EVENT_ID`, `GHOSTLY_EVENT_SEQ` in its environment. A non-zero exit is said on stderr
344
+ and the cursor moves past the event.
345
+ - `--webhook <url>` POSTs each event (JSON) to a local bridge: `127.0.0.1`, `localhost` or `[::1]` only. A bridge not
346
+ answering (connection refused, timeout, 5xx, 408, 429) holds the stream: the event is tried again, up to a minute
347
+ apart, and the cursor stays before it until the bridge takes it. A 4xx or a redirect (not followed) passes the event
348
+ as not taken.
346
349
  - With no daemon running, `listen` becomes the daemon (socket included), so a hook can answer with `ghostly send`.
347
350
 
348
351
  As the app's chat screen does, the side that joined a chat says `👋 <name> joined` once it first goes live, and the
package/SKILL.md CHANGED
@@ -118,6 +118,8 @@ ghostly listen --turns --from alice --group team --cursor ~/.ghostly/agent.curso
118
118
  - `--exec '<command>'` runs once per turn, in order, with the turn on **stdin** (never in its arguments). Or
119
119
  `--webhook http://127.0.0.1:<port>/…` POSTs each turn to a local bridge (loopback only).
120
120
  - `--cursor <file>` remembers the last event handled, so a restarted listener resumes where it stopped. Dedupe on `id`.
121
+ A `--webhook` bridge that is down holds the stream until it is back (nothing is lost); an `--exec` that exits
122
+ non-zero, or a 4xx from the bridge, passes its event.
121
123
 
122
124
  A turn:
123
125
 
@@ -1,14 +1,14 @@
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-gJqfoRKI.js";
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-Dg1bvMNv.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-BrCMSXxg.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-uxa0U9_n.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-JGOFtJDE.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-D9NQ3kV0.js";
7
- import { i as ENGINE_READS, n as withStoredIds, r as ENGINE_METHODS } from "./turnRefs-zUQbFkl3.js";
5
+ import { t as IDENTITY_PROVIDERS } from "./registry-OVx2kY3d.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-BtxwyM2l.js";
7
+ import { i as ENGINE_READS, n as withStoredIds, r as ENGINE_METHODS } from "./turnRefs-WnggXm2T.js";
8
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-BnpVuZrZ.js";
10
- import { t as BACKUP_METHODS } from "./backup-DEe1NqKb.js";
11
- import { o as checkedBundle } from "./apps-Bs6QYQjm.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-B4qhnLQT.js";
10
+ import { t as BACKUP_METHODS } from "./backup-CTpFFQ-4.js";
11
+ import { o as checkedBundle } from "./apps-DOH1P_S0.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";
@@ -1587,16 +1587,21 @@ function chatMessageJson(message, link) {
1587
1587
  /**
1588
1588
  * A group's message with its author named: mesh and community messages are kept with the member's key only (the
1589
1589
  * name rides on the edge or the roster), so the roster fills `nick` when the message has none, and for an author no
1590
- * longer in it (removed, or back with a new member key) the name the group knew them by.
1590
+ * longer in it (removed, or back with a new member key) the name the group knew them by. A group's own line written
1591
+ * before that name came ("Member a4w9nb5y joined") says it, as the app draws it; before, it kept the key for good.
1591
1592
  */
1592
1593
  function groupMessageJson(message, group) {
1593
1594
  const json = messageJson(message);
1594
- if (json.nick || !message.member) return json;
1595
- const nick = group?.members.find((m) => m.key === message.member)?.nick ?? group?.formerNames?.[message.member];
1596
- return nick ? {
1595
+ if (!message.member) return json;
1596
+ const nick = json.nick ?? group?.members.find((m) => m.key === message.member)?.nick ?? group?.formerNames?.[message.member];
1597
+ if (!nick) return json;
1598
+ const placeholder = `Member ${message.member.slice(0, 8)}`;
1599
+ const text = message.event && json.text.startsWith(`${placeholder} `) ? `${nick}${json.text.slice(placeholder.length)}` : json.text;
1600
+ return {
1597
1601
  ...json,
1598
- nick
1599
- } : json;
1602
+ nick,
1603
+ text
1604
+ };
1600
1605
  }
1601
1606
  /**
1602
1607
  * A group as the CLI prints it. The entry link lets anyone who reads it join, so it is `<hidden>` unless asked for
@@ -2523,17 +2528,17 @@ function reportAppFrames(hub, node, profileDir) {
2523
2528
  if (frame.o === "open") open.set(`${chat} ${app}`, frame.v);
2524
2529
  else open.delete(`${chat} ${app}`);
2525
2530
  }
2526
- if (!("o" in frame)) hub.emit("app.message", `app.message:${id}`, {
2531
+ if (!("o" in frame)) hub.emitLive("app.message", `app.message:${id}`, {
2527
2532
  chat,
2528
2533
  app,
2529
2534
  data: frame.d
2530
2535
  });
2531
- else if (frame.o === "open") hub.emit("app.opened", `app.opened:${id}`, {
2536
+ else if (frame.o === "open") hub.emitLive("app.opened", `app.opened:${id}`, {
2532
2537
  chat,
2533
2538
  app,
2534
2539
  version: frame.v
2535
2540
  });
2536
- else hub.emit("app.closed", `app.closed:${id}`, {
2541
+ else hub.emitLive("app.closed", `app.closed:${id}`, {
2537
2542
  chat,
2538
2543
  app,
2539
2544
  ...frame.offline && { offline: true }
@@ -2843,6 +2848,15 @@ var isLnurl = (text) => /^(lightning:)?lnurl[0-9a-z]+$/i.test(text.trim()) || /^
2843
2848
  * `service add` says; before, it was `engine` (exit 1), which a bot reads as the engine failing and may retry. Read by
2844
2849
  * its shape: the engine's `EngineError` carries `engineCode`.
2845
2850
  */
2851
+ /** A payment's memo: the contact reads it as a message's text, so the secret guard of `send` holds (docs/CLI.md § Safety). */
2852
+ function memoOf(params, verb) {
2853
+ const memo = str(params, "memo");
2854
+ if (memo && !bool(params, "force")) {
2855
+ const secret = findSecret(memo);
2856
+ if (secret) throw new CliError("confirm", `The memo looks like ${secret.kind === "cashu" ? "a Cashu token (money anyone who reads it can take)" : "a secret (a seed or a private key)"}; ${verb} with --force if you mean to`, { kind: secret.kind });
2857
+ }
2858
+ return memo || void 0;
2859
+ }
2846
2860
  function badMintUrl(error) {
2847
2861
  const code = error instanceof Error ? error.engineCode : void 0;
2848
2862
  return code === "invalidMintUrl" || code === "mintNotHttps";
@@ -3093,6 +3107,7 @@ var WALLET_METHODS = Object.fromEntries(Object.entries({
3093
3107
  },
3094
3108
  /** Ecash to a contact in a chat (the payment sheet's Pay). */
3095
3109
  async "chat.pay"(ctx, params) {
3110
+ const memo = memoOf(params, "pay");
3096
3111
  const link = chatOf(ctx, params);
3097
3112
  inviteTaken(link);
3098
3113
  const amount = num(params, "amount", 0, { min: 1 });
@@ -3105,7 +3120,7 @@ var WALLET_METHODS = Object.fromEntries(Object.entries({
3105
3120
  amount,
3106
3121
  timestamp: sentAt(),
3107
3122
  network: n,
3108
- ...str(params, "memo") ? { memo: str(params, "memo") } : {},
3123
+ ...memo ? { memo } : {},
3109
3124
  ...real(params)
3110
3125
  });
3111
3126
  return {
@@ -3115,6 +3130,7 @@ var WALLET_METHODS = Object.fromEntries(Object.entries({
3115
3130
  },
3116
3131
  /** A request in a chat (the payment sheet's Request): the contact's app pays it. */
3117
3132
  async "chat.request"(ctx, params) {
3133
+ const memo = memoOf(params, "request");
3118
3134
  const link = chatOf(ctx, params);
3119
3135
  const amount = num(params, "amount", 0, { min: 1 });
3120
3136
  if (!amount) throw new CliError("bad_request", "amount is required");
@@ -3126,7 +3142,7 @@ var WALLET_METHODS = Object.fromEntries(Object.entries({
3126
3142
  amount,
3127
3143
  timestamp: sentAt(),
3128
3144
  network: network(params),
3129
- ...str(params, "memo") ? { memo: str(params, "memo") } : {},
3145
+ ...memo ? { memo } : {},
3130
3146
  ...method ? { method } : {},
3131
3147
  ...rail ? { rail } : {},
3132
3148
  ...str(params, "card") ? { card: str(params, "card") } : {}
@@ -4083,17 +4099,27 @@ var METHODS = {
4083
4099
  }
4084
4100
  };
4085
4101
  /**
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.
4102
+ * The engine's calls that send a text this side writes (a message, a file's caption, a payment's memo): `engine.call`
4103
+ * 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.
4088
4104
  */
4089
4105
  var ENGINE_SENDS = /* @__PURE__ */ new Set([
4090
4106
  "sendMessage",
4091
4107
  "sendGroupMessage",
4092
4108
  "editMessage",
4093
- "forwardMessages"
4109
+ "forwardMessages",
4110
+ "sendGroupFile",
4111
+ "sendPayment",
4112
+ "requestPayment",
4113
+ "requestGroupPayment",
4114
+ "askToPay"
4094
4115
  ]);
4095
4116
  async function guardEngineSend(ctx, method, args) {
4096
- let texts = [args.text, args.card];
4117
+ let texts = [
4118
+ args.text,
4119
+ args.card,
4120
+ args.caption,
4121
+ args.memo
4122
+ ];
4097
4123
  if (method === "forwardMessages") {
4098
4124
  const ids = Array.isArray(args.messageIds) ? args.messageIds.filter((id) => typeof id === "string") : [];
4099
4125
  const linkId = args.linkId;
@@ -4249,4 +4275,4 @@ async function callApi(ctx, method, params = {}) {
4249
4275
  //#endregion
4250
4276
  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 };
4251
4277
 
4252
- //# sourceMappingURL=api-DlxlF4jP.js.map
4278
+ //# sourceMappingURL=api-BCrwJ57L.js.map