@simplepush/cli 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +119 -15
- package/dist/main.mjs.map +1 -1
- package/package.json +2 -2
package/dist/main.mjs
CHANGED
|
@@ -13,6 +13,9 @@ import { Client, DownloadError, OrgClient, TypeFilter, decryptSubmission, decryp
|
|
|
13
13
|
import { mkdir, stat, writeFile } from "node:fs/promises";
|
|
14
14
|
import { connect, createConnection } from "node:net";
|
|
15
15
|
import path, { basename, extname, join } from "node:path";
|
|
16
|
+
//#region package.json
|
|
17
|
+
var version = "0.6.0";
|
|
18
|
+
//#endregion
|
|
16
19
|
//#region src/errors.ts
|
|
17
20
|
/** No CLI session saved — `sp auth login` hasn't been run (or was logged out). */
|
|
18
21
|
var NotLoggedIn = class extends Data.TaggedError("NotLoggedIn") {};
|
|
@@ -1887,7 +1890,7 @@ const formatOption$4 = Options.choice("format", ["json", "pretty"]).pipe(Options
|
|
|
1887
1890
|
const sinceOption$1 = mappedText("since", resolveSince).pipe(Options.optional, Options.withDescription("Only items created at or after this instant: ISO-8601, or a relative window like 7d, 12h, 30m."));
|
|
1888
1891
|
const untilOption$1 = mappedText("until", (raw) => resolveUntil(raw).toISOString()).pipe(Options.optional, Options.withDescription("Only items created at or before this instant (same forms as --since)."));
|
|
1889
1892
|
const memberOption$3 = Options.text("member").pipe(Options.optional, Options.withDescription("Only items involving this person: a usr_ id, or a member name on an org."));
|
|
1890
|
-
const limitOption$
|
|
1893
|
+
const limitOption$2 = Options.integer("limit").pipe(Options.optional, Options.withDescription("Page size (server default 50). With --all this is the page size, not a cap."));
|
|
1891
1894
|
const cursorOption = Options.text("cursor").pipe(Options.optional, Options.withDescription("Continue a previous page: pass the cursor it reported."));
|
|
1892
1895
|
const allOption = Options.boolean("all").pipe(Options.withDescription("Follow cursors until the last page instead of printing one page and a cursor."));
|
|
1893
1896
|
const STATUSES = [
|
|
@@ -2119,7 +2122,7 @@ function extractRaw(v) {
|
|
|
2119
2122
|
const eventTypeOption = Options.text("type").pipe(Options.withDescription("Filter by event type. Repeatable."), Options.repeated);
|
|
2120
2123
|
const sinceOption = mappedText("since", resolveSince).pipe(Options.withDescription("Replay from this point. Accepts `24h`, `7d`, or an ISO 8601 timestamp."), Options.optional);
|
|
2121
2124
|
const untilOption = mappedText("until", resolveUntil).pipe(Options.withDescription("Stop at this timestamp. Forces a finite range, so `--follow` is ignored."), Options.optional);
|
|
2122
|
-
const limitOption = Options.integer("limit").pipe(Options.withDescription("Maximum number of events to print, then exit."), Options.optional);
|
|
2125
|
+
const limitOption$1 = Options.integer("limit").pipe(Options.withDescription("Maximum number of events to print, then exit."), Options.optional);
|
|
2123
2126
|
const followOption = Options.boolean("follow").pipe(Options.withAlias("f"), Options.withDescription("After history is drained, keep streaming live instead of exiting. Only meaningful with `--since`."));
|
|
2124
2127
|
const memberOption$2 = Options.text("member").pipe(Options.optional, Options.withDescription("Only events by this person: a usr_ id, or the actor's name."));
|
|
2125
2128
|
const formatOption$3 = Options.choice("format", [
|
|
@@ -2134,7 +2137,7 @@ const eventsCommand = Command.make("events", {
|
|
|
2134
2137
|
member: memberOption$2,
|
|
2135
2138
|
since: sinceOption,
|
|
2136
2139
|
until: untilOption,
|
|
2137
|
-
limit: limitOption,
|
|
2140
|
+
limit: limitOption$1,
|
|
2138
2141
|
follow: followOption,
|
|
2139
2142
|
format: formatOption$3,
|
|
2140
2143
|
direct: directOption,
|
|
@@ -2417,7 +2420,7 @@ const getCommand = Command.make("get", {
|
|
|
2417
2420
|
topic: topicOption,
|
|
2418
2421
|
member: memberOption$3,
|
|
2419
2422
|
group: groupOption,
|
|
2420
|
-
limit: limitOption$
|
|
2423
|
+
limit: limitOption$2,
|
|
2421
2424
|
cursor: cursorOption,
|
|
2422
2425
|
all: allOption,
|
|
2423
2426
|
format: formatOption$4,
|
|
@@ -2432,6 +2435,100 @@ const getCommand = Command.make("get", {
|
|
|
2432
2435
|
return Effect.fail(new UserError({ message: `cannot read '${args.what}': ${hint}` }));
|
|
2433
2436
|
})).pipe(Command.withDescription("Read what came back: 'tasks' or 'submissions' for filtered listings, a tsk_ id for one task with its subtasks, a sub_ id for one subtask, a grptsk_ id for a group's per-recipient roster."));
|
|
2434
2437
|
//#endregion
|
|
2438
|
+
//#region src/commands/search.ts
|
|
2439
|
+
const KINDS = [
|
|
2440
|
+
"task",
|
|
2441
|
+
"subtask",
|
|
2442
|
+
"answer",
|
|
2443
|
+
"reply",
|
|
2444
|
+
"notification",
|
|
2445
|
+
"notification_answer",
|
|
2446
|
+
"submission"
|
|
2447
|
+
];
|
|
2448
|
+
const kindOption = Options.text("kind").pipe(Options.repeated, Options.mapTryCatch((values) => {
|
|
2449
|
+
const flat = values.flatMap((v) => v.split(",")).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
2450
|
+
const bad = flat.filter((s) => !KINDS.includes(s));
|
|
2451
|
+
if (bad.length > 0) throw new Error(`unknown kind ${bad.join(", ")} — use ${KINDS.join(", ")}`);
|
|
2452
|
+
return flat;
|
|
2453
|
+
}, (e) => HelpDoc.p(e instanceof Error ? e.message : String(e))), Options.withDescription("Only these hit kinds (repeatable or comma-separated)."));
|
|
2454
|
+
function parsePoint(raw) {
|
|
2455
|
+
const parts = raw.split(",");
|
|
2456
|
+
if (parts.length === 2) {
|
|
2457
|
+
const latitude = Number(parts[0].trim());
|
|
2458
|
+
const longitude = Number(parts[1].trim());
|
|
2459
|
+
if (Number.isFinite(latitude) && Number.isFinite(longitude) && Math.abs(latitude) <= 90 && Math.abs(longitude) <= 180) return {
|
|
2460
|
+
latitude,
|
|
2461
|
+
longitude
|
|
2462
|
+
};
|
|
2463
|
+
}
|
|
2464
|
+
throw new Error(`expected \`lat,lng\` with lat in [-90,90] and lng in [-180,180], got '${raw}'`);
|
|
2465
|
+
}
|
|
2466
|
+
const nearOption = Options.text("near").pipe(Options.mapTryCatch(parsePoint, (e) => HelpDoc.p(e instanceof Error ? e.message : String(e))), Options.optional, Options.withDescription("Center of a radius filter as `lat,lng`; requires --radius. Hits come back with their point and its distance, nearest first when no words are given."));
|
|
2467
|
+
const radiusOption = Options.integer("radius").pipe(Options.optional, Options.withDescription("Radius around --near, in meters (1..1000000)."));
|
|
2468
|
+
const withinOption = Options.text("within").pipe(Options.mapTryCatch((raw) => {
|
|
2469
|
+
const points = raw.split(";").map((s) => s.trim()).filter((s) => s.length > 0).map(parsePoint);
|
|
2470
|
+
if (points.length < 3) throw new Error("--within needs at least 3 `lat,lng` points separated by `;`");
|
|
2471
|
+
return points;
|
|
2472
|
+
}, (e) => HelpDoc.p(e instanceof Error ? e.message : String(e))), Options.optional, Options.withDescription("Polygon to search inside: `lat,lng` corners joined with `;` (at least 3). Not combinable with --near/--radius; hits carry no distance and come newest first without words."));
|
|
2473
|
+
const limitOption = Options.integer("limit").pipe(Options.optional, Options.withDescription("Best hits to return; server default 20, at most 100."));
|
|
2474
|
+
/** One block per hit: id, kind, when, then whatever the hit carries. */
|
|
2475
|
+
function formatHit(h) {
|
|
2476
|
+
return [
|
|
2477
|
+
`${h.ref} [${h.kind}] ${h.createdAt}`,
|
|
2478
|
+
h.title !== void 0 ? ` ${h.title}` : void 0,
|
|
2479
|
+
h.actor !== void 0 ? ` by: ${h.actor}` : void 0,
|
|
2480
|
+
h.snippet !== void 0 ? ` ${h.snippet}` : void 0,
|
|
2481
|
+
h.location !== void 0 ? ` at: ${h.location.latitude},${h.location.longitude}${h.location.distanceMeters !== void 0 ? ` (${Math.round(h.location.distanceMeters)}m away)` : ""}` : void 0
|
|
2482
|
+
].filter((l) => l !== void 0).join("\n");
|
|
2483
|
+
}
|
|
2484
|
+
const searchCommand = Command.make("search", {
|
|
2485
|
+
words: Args.text({ name: "words" }).pipe(Args.withDescription("The words to look for; all must appear. Quote a phrase (nested quotes) for adjacency. Optional when --near/--radius or --within is given."), Args.repeated),
|
|
2486
|
+
kind: kindOption,
|
|
2487
|
+
since: sinceOption$1,
|
|
2488
|
+
until: untilOption$1,
|
|
2489
|
+
member: memberOption$3,
|
|
2490
|
+
near: nearOption,
|
|
2491
|
+
radius: radiusOption,
|
|
2492
|
+
within: withinOption,
|
|
2493
|
+
limit: limitOption,
|
|
2494
|
+
format: formatOption$4,
|
|
2495
|
+
...credentialOptions
|
|
2496
|
+
}, (args) => withQueryClient(args, (ctx) => Effect.gen(function* () {
|
|
2497
|
+
const query = args.words.join(" ").trim();
|
|
2498
|
+
const near = Option.getOrUndefined(args.near);
|
|
2499
|
+
const radius = Option.getOrUndefined(args.radius);
|
|
2500
|
+
const within = Option.getOrUndefined(args.within);
|
|
2501
|
+
const problem = near !== void 0 && radius === void 0 ? "--near requires --radius (meters)" : radius !== void 0 && near === void 0 ? "--radius requires --near" : within !== void 0 && near !== void 0 ? "--within cannot be combined with --near/--radius" : query === "" && near === void 0 && within === void 0 ? "give words to search for, or an area (--near with --radius, or --within)" : void 0;
|
|
2502
|
+
if (problem !== void 0) return yield* Effect.fail(new UserError({ message: problem }));
|
|
2503
|
+
const opts = {
|
|
2504
|
+
...args.kind.length > 0 ? { kind: args.kind } : {},
|
|
2505
|
+
...Option.match(args.since, {
|
|
2506
|
+
onNone: () => ({}),
|
|
2507
|
+
onSome: (since) => ({ since })
|
|
2508
|
+
}),
|
|
2509
|
+
...Option.match(args.until, {
|
|
2510
|
+
onNone: () => ({}),
|
|
2511
|
+
onSome: (until) => ({ until })
|
|
2512
|
+
}),
|
|
2513
|
+
...Option.match(args.member, {
|
|
2514
|
+
onNone: () => ({}),
|
|
2515
|
+
onSome: (member) => ({ member })
|
|
2516
|
+
}),
|
|
2517
|
+
...Option.match(args.limit, {
|
|
2518
|
+
onNone: () => ({}),
|
|
2519
|
+
onSome: (limit) => ({ limit })
|
|
2520
|
+
}),
|
|
2521
|
+
...near !== void 0 && radius !== void 0 ? {
|
|
2522
|
+
near,
|
|
2523
|
+
radiusMeters: radius
|
|
2524
|
+
} : {},
|
|
2525
|
+
...within !== void 0 ? { within } : {}
|
|
2526
|
+
};
|
|
2527
|
+
const res = yield* sdkCall("search", () => ctx.client.search(query === "" ? void 0 : query, opts));
|
|
2528
|
+
for (const h of res.hits) yield* ctx.out.print(args.format === "json" ? JSON.stringify(h) : formatHit(h));
|
|
2529
|
+
if (res.hits.length === 0 && args.format === "pretty") yield* ctx.out.info("no hits");
|
|
2530
|
+
}))).pipe(Command.withDescription("Ranked full-text and location search over everything this credential reads, across all time. Words match literally plus stemmed in the org's configured languages; --near/--radius or --within search by place instead of or on top of words."));
|
|
2531
|
+
//#endregion
|
|
2435
2532
|
//#region src/input-spec.ts
|
|
2436
2533
|
const SETTING_RE = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
2437
2534
|
function looksLikeSetting(seg) {
|
|
@@ -2786,6 +2883,7 @@ const broadcastOption$1 = Options.boolean("broadcast").pipe(Options.withAlias("b
|
|
|
2786
2883
|
const orgTopicOption$1 = Options.text("org-topic").pipe(Options.withAlias("o"), Options.withDescription("Send to an org topic by value (from `sp org topics list`). Org send; mutually exclusive with --member, --broadcast, and -k/--topic (the personal topic)."), Options.optional);
|
|
2787
2884
|
const tagOption$1 = Options.text("tag").pipe(Options.withDescription("Optional notification tag — recipients can use it to coalesce / replace prior notifications with the same tag."), Options.optional);
|
|
2788
2885
|
const imageOption = Options.text("image").pipe(Options.withDescription("Image URL to show in the push (PNG/JPEG/GIF). Renders on iOS + Android. Mutually exclusive with --audio. URLs only — file uploads are SDK-only."), Options.optional);
|
|
2886
|
+
const linkOption$2 = Options.text("link").pipe(Options.withAlias("l"), Options.withDescription("A URL shown as an \"Open link\" button on the push. Any scheme: https opens the browser, an app's deep link (unifi-protect://...) opens that app. Mutually exclusive with the input flags."), Options.optional);
|
|
2789
2887
|
const audioOption = Options.text("audio").pipe(Options.withDescription("Audio URL to play inline in the push (AIFF/WAV/MP3/M4A; iOS only). Mutually exclusive with --image. URLs only."), Options.optional);
|
|
2790
2888
|
const noEncryptOption$2 = Options.boolean("no-encrypt").pipe(Options.withDescription("Send the body in plaintext even when an unlocked vault is available."));
|
|
2791
2889
|
const actionInputOption = Options.text("action-input").pipe(Options.withAlias("a"), Options.withDescription("Add an actions input: tap-buttons the recipient answers with (e.g. Accept/Deny). Format: `[description;]key=Label[:style],...`, actions comma-separated; style is default|destructive. Use `\\,` for a literal comma in a label. A notification carries at most one input."), Options.optional);
|
|
@@ -2835,6 +2933,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2835
2933
|
tag: tagOption$1,
|
|
2836
2934
|
image: imageOption,
|
|
2837
2935
|
audio: audioOption,
|
|
2936
|
+
link: linkOption$2,
|
|
2838
2937
|
"text-input": textInputOption,
|
|
2839
2938
|
"choice-input": choiceInputOption,
|
|
2840
2939
|
"action-input": actionInputOption,
|
|
@@ -2864,6 +2963,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2864
2963
|
const message = args.content;
|
|
2865
2964
|
const imageUrl = Option.getOrUndefined(args.image);
|
|
2866
2965
|
const audioUrl = Option.getOrUndefined(args.audio);
|
|
2966
|
+
const linkUrl = Option.getOrUndefined(args.link);
|
|
2867
2967
|
if (imageUrl !== void 0 && audioUrl !== void 0) return yield* Effect.fail(new UserError({ message: "only one of --image or --audio may be set" }));
|
|
2868
2968
|
const mediaUrl = imageUrl ?? audioUrl;
|
|
2869
2969
|
const mediaKind = imageUrl !== void 0 ? "image" : "audio";
|
|
@@ -2872,6 +2972,7 @@ const notifyCommand = Command.make("notify", {
|
|
|
2872
2972
|
if (notifyMediaContentType(mediaUrl, mediaKind) === null) return yield* Effect.fail(new UserError({ message: `--${mediaKind} URL must point to a supported ${mediaKind} type (by extension); got "${mediaUrl}"` }));
|
|
2873
2973
|
}
|
|
2874
2974
|
const input = yield* parseNotificationInput(args["text-input"], Option.getOrUndefined(args["choice-input"]), Option.getOrUndefined(args["action-input"]));
|
|
2975
|
+
if (input !== void 0 && linkUrl !== void 0) return yield* Effect.fail(new UserError({ message: "a notification carries either an input or --link, not both: the input's buttons take the action slots, so the link would never be shown" }));
|
|
2875
2976
|
if (isOrgTarget) {
|
|
2876
2977
|
const api = yield* Api;
|
|
2877
2978
|
const vault = yield* (yield* VaultAccess).forSendOrPlaintext(args.noEncrypt);
|
|
@@ -2888,7 +2989,8 @@ const notifyCommand = Command.make("notify", {
|
|
|
2888
2989
|
...tagOpt !== void 0 ? { tag: tagOpt } : {},
|
|
2889
2990
|
...input !== void 0 ? { input } : {},
|
|
2890
2991
|
...imageUrl !== void 0 ? { image: imageUrl } : {},
|
|
2891
|
-
...audioUrl !== void 0 ? { audio: audioUrl } : {}
|
|
2992
|
+
...audioUrl !== void 0 ? { audio: audioUrl } : {},
|
|
2993
|
+
...linkUrl !== void 0 ? { link: linkUrl } : {}
|
|
2892
2994
|
};
|
|
2893
2995
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
2894
2996
|
const client = yield* acquireOrgClient({
|
|
@@ -2948,7 +3050,8 @@ const notifyCommand = Command.make("notify", {
|
|
|
2948
3050
|
...tagOpt !== void 0 ? { tag: tagOpt } : {},
|
|
2949
3051
|
...input !== void 0 ? { input } : {},
|
|
2950
3052
|
...imageUrl !== void 0 ? { image: imageUrl } : {},
|
|
2951
|
-
...audioUrl !== void 0 ? { audio: audioUrl } : {}
|
|
3053
|
+
...audioUrl !== void 0 ? { audio: audioUrl } : {},
|
|
3054
|
+
...linkUrl !== void 0 ? { link: linkUrl } : {}
|
|
2952
3055
|
};
|
|
2953
3056
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
2954
3057
|
const client = yield* acquireClient({
|
|
@@ -3715,7 +3818,7 @@ const fileInput$1 = repeatedText("file-input", void 0, "Add a file upload input.
|
|
|
3715
3818
|
const locationInput$1 = repeatedText("location-input", void 0, "Add a location input (the recipient shares their device GPS position from the app). Format: `description[;key=value...]`. Settings: `required=true|false`. Repeatable.");
|
|
3716
3819
|
const linkOption$1 = repeatedText("link", "l", "Attach a remote URL (a link attachment). Repeatable. For local files use --file.");
|
|
3717
3820
|
const fileOption$1 = repeatedText("file", "f", "Attach a local file, uploaded as a file attachment (encrypted under the send's key — topic password or org master key — when the send is encrypted). Repeatable.");
|
|
3718
|
-
const
|
|
3821
|
+
const autoCommitOption$1 = Options.boolean("auto-commit").pipe(Options.withDescription("Complete the task as inputs are filled, without an explicit Submit. Default is form mode: the recipient submits everything at once."));
|
|
3719
3822
|
const waitOption$1 = Options.boolean("wait").pipe(Options.withDescription("Block until the task is completed; print the result to stdout. Requires exactly one input on the request."));
|
|
3720
3823
|
const replyOption$1 = Options.choice("reply", [
|
|
3721
3824
|
"one-shot",
|
|
@@ -3744,7 +3847,7 @@ const taskCommand = Command.make("task", {
|
|
|
3744
3847
|
"location-input": locationInput$1,
|
|
3745
3848
|
link: linkOption$1,
|
|
3746
3849
|
file: fileOption$1,
|
|
3747
|
-
|
|
3850
|
+
"auto-commit": autoCommitOption$1,
|
|
3748
3851
|
wait: waitOption$1,
|
|
3749
3852
|
reply: replyOption$1,
|
|
3750
3853
|
member: memberOption,
|
|
@@ -3795,7 +3898,7 @@ const taskCommand = Command.make("task", {
|
|
|
3795
3898
|
inputs,
|
|
3796
3899
|
links: [...args.link],
|
|
3797
3900
|
files: [...args.file],
|
|
3798
|
-
autoCommit:
|
|
3901
|
+
autoCommit: args["auto-commit"],
|
|
3799
3902
|
reply: Option.getOrUndefined(args.reply),
|
|
3800
3903
|
markdown: args.markdown,
|
|
3801
3904
|
noEncrypt: args["no-encrypt"],
|
|
@@ -3822,7 +3925,7 @@ const taskCommand = Command.make("task", {
|
|
|
3822
3925
|
inputs,
|
|
3823
3926
|
links: [...args.link],
|
|
3824
3927
|
...files.length > 0 ? { files } : {},
|
|
3825
|
-
autoCommit:
|
|
3928
|
+
autoCommit: args["auto-commit"],
|
|
3826
3929
|
...Option.isSome(args.reply) ? { reply: args.reply.value } : {},
|
|
3827
3930
|
...args.markdown ? { contentFormat: "markdown" } : {},
|
|
3828
3931
|
...expiresAt !== void 0 ? { expiresAt } : {}
|
|
@@ -4029,7 +4132,7 @@ const photoInput = Options.text("photo-input").pipe(Options.withDescription("Add
|
|
|
4029
4132
|
const voiceRecordingInput = Options.text("voice-recording-input").pipe(Options.withDescription("Add a voice recording input. Format: `description[;key=value...]`. Settings: `required=true|false`. Repeatable."), Options.repeated);
|
|
4030
4133
|
const fileInput = Options.text("file-input").pipe(Options.withDescription("Add a file upload input. Format: `description[;key=value...]`. Settings: `required=true|false`. Repeatable."), Options.repeated);
|
|
4031
4134
|
const locationInput = Options.text("location-input").pipe(Options.withDescription("Add a location input (the recipient shares their device GPS position from the app). Format: `description[;key=value...]`. Settings: `required=true|false`. Repeatable."), Options.repeated);
|
|
4032
|
-
const
|
|
4135
|
+
const autoCommitOption = Options.boolean("auto-commit").pipe(Options.withDescription("Complete the subtask as inputs are filled, without an explicit Submit. Default is form mode: the recipient submits everything at once."));
|
|
4033
4136
|
const waitOption = Options.boolean("wait").pipe(Options.withDescription("Block until the subtask is completed; print the result to stdout. Requires at least one input on the append. On a group append, the first member's completion wins."));
|
|
4034
4137
|
const formatOption = Options.choice("format", ["text", "json"]).pipe(Options.withDescription("stdout format for an append: `text` (the bare sub_ id(s), default) or `json` (a `sent` line piped to `sp collect`)."), Options.withDefault("text"));
|
|
4035
4138
|
const replyOption = Options.choice("reply", [
|
|
@@ -4054,7 +4157,7 @@ const subtaskCommand = Command.make("subtask", {
|
|
|
4054
4157
|
"location-input": locationInput,
|
|
4055
4158
|
link: linkOption,
|
|
4056
4159
|
file: fileOption,
|
|
4057
|
-
|
|
4160
|
+
"auto-commit": autoCommitOption,
|
|
4058
4161
|
wait: waitOption,
|
|
4059
4162
|
format: formatOption,
|
|
4060
4163
|
reply: replyOption,
|
|
@@ -4084,7 +4187,7 @@ const subtaskCommand = Command.make("subtask", {
|
|
|
4084
4187
|
...content !== void 0 ? { content } : {},
|
|
4085
4188
|
...inputs.length > 0 ? { inputs } : {},
|
|
4086
4189
|
links: [...args.link],
|
|
4087
|
-
autoCommit:
|
|
4190
|
+
autoCommit: args["auto-commit"],
|
|
4088
4191
|
...Option.isSome(args.reply) ? { reply: args.reply.value } : {},
|
|
4089
4192
|
...args.markdown ? { contentFormat: "markdown" } : {}
|
|
4090
4193
|
};
|
|
@@ -4243,11 +4346,12 @@ const root = Command.make("simplepush").pipe(Command.withSubcommands([
|
|
|
4243
4346
|
taskCommand,
|
|
4244
4347
|
subtaskCommand,
|
|
4245
4348
|
cancelCommand,
|
|
4246
|
-
getCommand
|
|
4349
|
+
getCommand,
|
|
4350
|
+
searchCommand
|
|
4247
4351
|
]));
|
|
4248
4352
|
const cli = Command.run(root, {
|
|
4249
4353
|
name: "Simplepush CLI",
|
|
4250
|
-
version
|
|
4354
|
+
version
|
|
4251
4355
|
});
|
|
4252
4356
|
const MainLive = Layer.mergeAll(CliOutput.Default, Sodium.Default, AuthStore.Default, VaultStore.Default, InviteStore.Default, Api.Default, VaultAccess.Default).pipe(Layer.provideMerge(FetchHttpClient.layer), Layer.provideMerge(NodeContext.layer));
|
|
4253
4357
|
/** Render any failure through the typed-error table, then re-fail so the
|