@quire-io/quire-cli 0.1.6 → 1.0.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/CHANGES.md +23 -0
- package/README.md +5 -1
- package/dist/cli.js +2 -188
- package/dist/cli.js.map +1 -1
- package/dist/commands/chat.js +18 -2
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/dashboard.js +203 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/doc.js +22 -2
- package/dist/commands/doc.js.map +1 -1
- package/dist/commands/insight.js +6 -2
- package/dist/commands/insight.js.map +1 -1
- package/dist/commands/org.js +7 -1
- package/dist/commands/org.js.map +1 -1
- package/dist/commands/project.js +7 -1
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/reminder.js +207 -0
- package/dist/commands/reminder.js.map +1 -0
- package/dist/commands/sublist.js +6 -2
- package/dist/commands/sublist.js.map +1 -1
- package/dist/commands/task.js +23 -0
- package/dist/commands/task.js.map +1 -1
- package/dist/commands/undo.js +6 -0
- package/dist/commands/undo.js.map +1 -1
- package/dist/output/columns.js +1 -0
- package/dist/output/columns.js.map +1 -1
- package/dist/program.js +228 -0
- package/dist/program.js.map +1 -0
- package/dist/util/member-flags.js +40 -0
- package/dist/util/member-flags.js.map +1 -0
- package/dist/util/reminder-lead.js +60 -0
- package/dist/util/reminder-lead.js.map +1 -0
- package/package.json +4 -2
package/dist/program.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the whole `quire` command tree.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from cli.ts — which is the executable entry point and runs
|
|
5
|
+
* on import — so that tooling can construct the tree without invoking the
|
|
6
|
+
* CLI. scripts/gen-coverage.ts walks the object this returns, which is what
|
|
7
|
+
* keeps COVERAGE.md honest: the doc is generated from the same tree the CLI
|
|
8
|
+
* actually registers, not a second hand-written list of it.
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from "commander";
|
|
11
|
+
import { registerChatCommand } from "./commands/chat.js";
|
|
12
|
+
import { registerColorsCommand } from "./commands/colors.js";
|
|
13
|
+
import { registerCommentCommand } from "./commands/comment.js";
|
|
14
|
+
import { registerDashboardCommand } from "./commands/dashboard.js";
|
|
15
|
+
import { registerDocCommand } from "./commands/doc.js";
|
|
16
|
+
import { registerInsightCommand } from "./commands/insight.js";
|
|
17
|
+
import { registerLoginCommand } from "./commands/login.js";
|
|
18
|
+
import { registerLogoutCommand } from "./commands/logout.js";
|
|
19
|
+
import { registerMineCommand } from "./commands/mine.js";
|
|
20
|
+
import { registerNotifyCommand } from "./commands/notify.js";
|
|
21
|
+
import { registerOrgCommand } from "./commands/org.js";
|
|
22
|
+
import { registerPartnerCommand } from "./commands/partner.js";
|
|
23
|
+
import { registerProjectCommand } from "./commands/project.js";
|
|
24
|
+
import { registerReminderCommand } from "./commands/reminder.js";
|
|
25
|
+
import { registerResolveCommand } from "./commands/resolve.js";
|
|
26
|
+
import { registerStatusCommand } from "./commands/status.js";
|
|
27
|
+
import { registerSublistCommand } from "./commands/sublist.js";
|
|
28
|
+
import { registerTagCommand } from "./commands/tag.js";
|
|
29
|
+
import { registerTaskCommand } from "./commands/task.js";
|
|
30
|
+
import { registerUndoCommand } from "./commands/undo.js";
|
|
31
|
+
import { registerUserCommand } from "./commands/user.js";
|
|
32
|
+
import { registerWhoamiCommand } from "./commands/whoami.js";
|
|
33
|
+
import { readVersion } from "./version.js";
|
|
34
|
+
export function buildProgram() {
|
|
35
|
+
const program = new Command();
|
|
36
|
+
program
|
|
37
|
+
.name("quire")
|
|
38
|
+
.description("Command-line interface for the Quire API.")
|
|
39
|
+
.version(readVersion(), "-v, --version", "Print the CLI version")
|
|
40
|
+
.option("--verbose", "Enable verbose (debug) logging on stderr")
|
|
41
|
+
.option("--json", "Emit raw API JSON (no human formatting)")
|
|
42
|
+
.option("-q, --quiet", "Print only IDs (one per line) — designed for xargs pipelines")
|
|
43
|
+
.option("--color-mode <mode>", "Color output mode: always|never|auto", "auto")
|
|
44
|
+
.option("--profile <name>", "Use a named credential profile (default: $QUIRE_PROFILE or 'default')")
|
|
45
|
+
.option("--yes", "Auto-confirm destructive prompts (required for non-interactive mutating commands)")
|
|
46
|
+
.option("--no-truncate", "Disable per-cell truncation in human-readable tables");
|
|
47
|
+
registerLoginCommand(program);
|
|
48
|
+
registerLogoutCommand(program);
|
|
49
|
+
registerWhoamiCommand(program);
|
|
50
|
+
registerUserCommand(program);
|
|
51
|
+
registerOrgCommand(program);
|
|
52
|
+
registerProjectCommand(program);
|
|
53
|
+
registerPartnerCommand(program);
|
|
54
|
+
registerTaskCommand(program);
|
|
55
|
+
registerMineCommand(program);
|
|
56
|
+
registerTagCommand(program);
|
|
57
|
+
registerSublistCommand(program);
|
|
58
|
+
registerStatusCommand(program);
|
|
59
|
+
registerCommentCommand(program);
|
|
60
|
+
registerChatCommand(program);
|
|
61
|
+
registerDocCommand(program);
|
|
62
|
+
registerInsightCommand(program);
|
|
63
|
+
registerDashboardCommand(program);
|
|
64
|
+
registerReminderCommand(program);
|
|
65
|
+
registerResolveCommand(program);
|
|
66
|
+
registerColorsCommand(program);
|
|
67
|
+
registerNotifyCommand(program);
|
|
68
|
+
registerUndoCommand(program);
|
|
69
|
+
program.addHelpText("after", `
|
|
70
|
+
Auth:
|
|
71
|
+
quire login Sign in via OAuth (loopback + PKCE)
|
|
72
|
+
quire logout Remove local credentials (server-side token stays valid; revoke at quire.io/apps)
|
|
73
|
+
quire whoami Show the signed-in user
|
|
74
|
+
quire user get <oid> Show one user by OID
|
|
75
|
+
|
|
76
|
+
Orgs / projects:
|
|
77
|
+
quire org list List your organizations
|
|
78
|
+
quire org get <id> Show one organization
|
|
79
|
+
quire org update <id> Update name / description / followers (--follower / --add-follower / --remove-follower)
|
|
80
|
+
quire org limit <id> Show API rate-limit usage for an organization
|
|
81
|
+
quire project list List projects you can see (or --org <id> to scope)
|
|
82
|
+
quire project get <id> Show one project
|
|
83
|
+
quire project update <id> Update name / description / dates / archive / public / followers (--follower / --add-follower / --remove-follower)
|
|
84
|
+
quire project members <id> List a project's members
|
|
85
|
+
quire project export <id> Export the project as CSV (default) or JSON (--format json [--output file])
|
|
86
|
+
|
|
87
|
+
Tasks (read):
|
|
88
|
+
quire task list <project> List tasks in a project
|
|
89
|
+
quire task get <id> Show task details (id = OID, slug/#N, or URL)
|
|
90
|
+
quire task tree <id> Render the recursive subtree (default depth 3)
|
|
91
|
+
quire task search <query> Search tasks; scope with --project / --org / --folder; filter with --assignee / --follower / --tag
|
|
92
|
+
quire task subtasks <id> List a task's direct subtasks
|
|
93
|
+
quire task comments <id> List a task's comments
|
|
94
|
+
quire mine List tasks assigned to me; scope with --project / --inbox / --org / --all-orgs
|
|
95
|
+
|
|
96
|
+
Tasks (write):
|
|
97
|
+
quire task create <project> --name "..." Create a new task (--parent / --sibling+--position to nest; --assignee / --follower)
|
|
98
|
+
quire task subtask <parent> --name "..." Shorthand for "task create --parent"
|
|
99
|
+
quire task update <id> Update fields: --name / --status / --priority / --add-tag / etc.
|
|
100
|
+
Followers: --follower (full replace) / --add-follower / --remove-follower
|
|
101
|
+
Follower values: OID, ID, email, 'me', 'app', or 'inherit' (the parent task's followers)
|
|
102
|
+
quire task complete <id> / uncomplete <id> Toggle status to 100 / 0
|
|
103
|
+
quire task move <id> --to <id|root> Re-parent within the same project
|
|
104
|
+
quire task transfer <id> --to <project> Cross-project transfer (--keep-tags / --keep-status / --invite)
|
|
105
|
+
quire task dates <id> --start ... --due ... Set / clear dates (pass 'null' to clear)
|
|
106
|
+
quire task peekaboo <id> [--reshow-at ISO | --show] Hide or un-hide a task
|
|
107
|
+
quire task delete <id> Delete a task (prompts unless --yes)
|
|
108
|
+
quire task undo-remove <oid> Restore a deleted task
|
|
109
|
+
quire task attach <id> <file> Attach a file to a task ('-' = stdin; --filename / --content-type optional)
|
|
110
|
+
|
|
111
|
+
Tasks (bulk):
|
|
112
|
+
quire task bulk-create <project> --from-file tasks.json Create up to 300 tasks atomically
|
|
113
|
+
quire task bulk-subtasks <parent> --from-file tasks.json Create up to 300 subtasks under one parent
|
|
114
|
+
quire task bulk-update <project> --from-file updates.json Update many tasks atomically (each item needs an oid)
|
|
115
|
+
quire task bulk-delete <project> --from-file ids.txt Delete many (prompts unless --yes); refs one per line or JSON array
|
|
116
|
+
quire task bulk-move <project> --to <id|root> --from-file ids.txt
|
|
117
|
+
quire task bulk-transfer <project> --to <project> --from-file ids.txt
|
|
118
|
+
quire task bulk-approve <project> --state request|approve|reject|change --from-file ids.txt
|
|
119
|
+
|
|
120
|
+
Tasks (approval / timelogs / recurrence):
|
|
121
|
+
quire task approve <id> --state ... Set a task's approval state
|
|
122
|
+
Add --comment <text|-|@file> [--comment-pinned / --comment-as-user] to post a companion comment
|
|
123
|
+
quire task revoke-approval <id> Revoke any approval state
|
|
124
|
+
quire task timelog add <id> --start --end [--user / --billable / --note]
|
|
125
|
+
quire task timelog update <id> --start --end [--new-start / --new-end / --note / ...]
|
|
126
|
+
quire task timelog remove <id> --start --end (prompts unless --yes)
|
|
127
|
+
--recurrence-freq / --recurrence-interval / --recurrence-byweekday / --recurrence-until
|
|
128
|
+
Add / clear recurrence on "task create" / "task subtask" / "task update"
|
|
129
|
+
|
|
130
|
+
Project metadata (approval categories):
|
|
131
|
+
quire project approval-category add <project> --id ... --name ... [--claimer / --approver]
|
|
132
|
+
quire project approval-category update <project> <id> [--name / --claimer / --approver / --claimers-anyone / --claimers-admins-only / ...]
|
|
133
|
+
quire project approval-category remove <project> <id> (prompts unless --yes)
|
|
134
|
+
|
|
135
|
+
Project metadata (custom-field definitions):
|
|
136
|
+
quire project field add <project> --name --type [--hidden / --private / --percent / --multiple / --clear-on-dup / --extra k=v]
|
|
137
|
+
quire project field update <project> <name> [--type / --hidden / --private / --percent / --multiple / --extra k=v]
|
|
138
|
+
quire project field rename <project> <name> --new-name ...
|
|
139
|
+
quire project field move <project> <name> [--before <name>] [--to-end]
|
|
140
|
+
quire project field remove <project> <name> (prompts unless --yes)
|
|
141
|
+
quire insight field add <insight-oid> --name --type [...] (formula / lookup only)
|
|
142
|
+
quire insight field {update / rename / move / remove} (same flag shape as project field)
|
|
143
|
+
|
|
144
|
+
Project metadata (read):
|
|
145
|
+
quire tag list <project> List tags defined on a project (also: 'tag get <oid>')
|
|
146
|
+
quire sublist list <project> List sublists on a project (also: 'sublist get <oid>')
|
|
147
|
+
quire status list <project> List custom statuses on a project (also: 'status get <project> <value>')
|
|
148
|
+
quire partner list <project> List partner orgs (external teams) on a project
|
|
149
|
+
quire partner get <oid> Show one partner organization
|
|
150
|
+
|
|
151
|
+
Project metadata (write):
|
|
152
|
+
quire tag create <project> Create a tag (--name / --color)
|
|
153
|
+
quire tag update <oid> Update tag --name / --color
|
|
154
|
+
quire tag delete <oid> Delete a tag (prompts unless --yes)
|
|
155
|
+
quire sublist create <project> Create a sublist (--name / --description / --member / --members-admins-only)
|
|
156
|
+
quire sublist update <oid> Update sublist (--name / --description / --start / --due / --archive / --unarchive)
|
|
157
|
+
quire sublist add-task <oid> <task> Add a task to a sublist
|
|
158
|
+
quire sublist remove-task <oid> <task> Remove a task from a sublist
|
|
159
|
+
quire sublist delete <oid> Delete a sublist (prompts unless --yes)
|
|
160
|
+
quire sublist undo-remove <oid> Restore a deleted sublist
|
|
161
|
+
quire status create <project> Create a status (--name / --value / --color)
|
|
162
|
+
quire status update <project> <value> Update a status (--name / --color / --new-value)
|
|
163
|
+
quire status delete <project> <value> Delete a status (prompts unless --yes)
|
|
164
|
+
|
|
165
|
+
Comments / chats / docs / insights / dashboards (read):
|
|
166
|
+
quire comment list <task> List comments on a task (alias for "quire task comments"; also: 'comment get <oid>')
|
|
167
|
+
quire chat list <project> List chats / chat get <id> / chat comments <id>
|
|
168
|
+
quire doc list <project> List documents / doc get <id>
|
|
169
|
+
quire insight list <project> List insights / insight get <id>
|
|
170
|
+
quire dashboard list <owner> List dashboards / dashboard get <id> ([--owner-type project|organization|folder|smart-folder])
|
|
171
|
+
|
|
172
|
+
Comments (write):
|
|
173
|
+
quire comment add <task> --text "..." Add a comment ('-' = stdin, '@file' = read file)
|
|
174
|
+
quire comment update <oid> Update --text and/or --pin / --unpin
|
|
175
|
+
quire comment attach <oid> <file> Attach a file to a comment ('-' = stdin; --filename / --content-type optional)
|
|
176
|
+
quire comment delete <oid> Delete a comment (prompts unless --yes)
|
|
177
|
+
|
|
178
|
+
Chats / docs / insights / dashboards (write):
|
|
179
|
+
quire chat create <project> --name [--description / --partner / --follower / --member / --members-admins-only]
|
|
180
|
+
quire chat update <oid> [--name / --description / --archive / --unarchive / --follower / --add-follower / --remove-follower]
|
|
181
|
+
quire chat delete <oid> (prompts unless --yes)
|
|
182
|
+
quire chat undo-remove <oid>
|
|
183
|
+
quire chat comment add <chat-id> --text [--pin]
|
|
184
|
+
quire doc create <project> --name [--description / --follower / --member / --members-admins-only]
|
|
185
|
+
quire doc update <oid> [--name / --description / --archive / --unarchive / --follower / --add-follower / --remove-follower]
|
|
186
|
+
quire doc delete <oid> (prompts unless --yes)
|
|
187
|
+
quire doc undo-remove <oid>
|
|
188
|
+
quire insight create <project> --name [--id / --description / --icon-color / --image / --member / --members-admins-only]
|
|
189
|
+
quire insight update <oid> [--name / --description / --icon-color / --image / --archive / --unarchive]
|
|
190
|
+
quire insight delete <oid> (prompts unless --yes)
|
|
191
|
+
quire insight undo-remove <oid>
|
|
192
|
+
quire insight run <oid> Run an insight and print the aggregated rows ([--group-by member|section] [--status active|completed|all])
|
|
193
|
+
quire dashboard create <owner> --name [--owner-type / --id / --description / --icon-color / --image / --partner / --start / --due / --member]
|
|
194
|
+
quire dashboard update <oid> [--id / --name / --description / --icon-color / --image / --start / --due / --archive / --unarchive] ('null' clears a date)
|
|
195
|
+
quire dashboard delete <oid> (prompts unless --yes)
|
|
196
|
+
quire dashboard undo-remove <oid>
|
|
197
|
+
|
|
198
|
+
Reminders:
|
|
199
|
+
quire reminder list <owner> List reminders ([--owner-type project|organization|folder|smart-folder|task]; '-' = your Inbox)
|
|
200
|
+
A project's list includes its tasks' reminders; ordered by OID, not fire time
|
|
201
|
+
quire reminder get <oid> Show one reminder
|
|
202
|
+
quire reminder create <owner> [--owner-type / --when / --lead / --name / --partner / --member / --recurrence-*]
|
|
203
|
+
--when is required unless the task already has a start or due date (that supplies the fire time)
|
|
204
|
+
--lead '<n>m' | '<n>d' | '<n>d@HH:mm', repeatable (max 30); omit for one notification at the fire time
|
|
205
|
+
quire reminder update <oid> [--when / --lead / --name / --clear-recurrence / --recurrence-*] ('null' clears --when / --name)
|
|
206
|
+
Members and partner are create-only — recreate the reminder to change who can see it
|
|
207
|
+
quire reminder delete <oid> Delete permanently — no trash, no undo (prompts unless --yes)
|
|
208
|
+
|
|
209
|
+
Record visibility (create-only):
|
|
210
|
+
--member <user> Restrict a sublist / doc / chat / insight / dashboard / reminder to these users; repeat for multiple
|
|
211
|
+
--members-admins-only Restrict it to the owner's admins
|
|
212
|
+
Omit both for every member of the owner. Cannot be changed after creation.
|
|
213
|
+
|
|
214
|
+
Generic undo:
|
|
215
|
+
quire undo <kind> <oid> kind = task | chat | comment | dashboard | document | insight | sublist
|
|
216
|
+
|
|
217
|
+
URL resolver:
|
|
218
|
+
quire resolve <url> Paste any Quire URL, get the typed resource back
|
|
219
|
+
|
|
220
|
+
Notifications:
|
|
221
|
+
quire notify --message ... Send an in-app notification to yourself ('-' / '@file' for stdin / file)
|
|
222
|
+
|
|
223
|
+
Reference:
|
|
224
|
+
quire colors List Quire's 48-slot palette (code, hex, name)
|
|
225
|
+
`);
|
|
226
|
+
return program;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=program.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
const append = (val, prev) => [...(prev ?? []), val];
|
|
3
|
+
/** Adds the two shared member options to a `create` command. */
|
|
4
|
+
export function addMemberOptions(cmd) {
|
|
5
|
+
return cmd
|
|
6
|
+
.option("--member <user>", "Restrict visibility to this user (OID, ID, email, or 'me'); repeat for multiple. Omit for every member of the owner. Cannot be changed after creation.", append, [])
|
|
7
|
+
.option("--members-admins-only", "Restrict visibility to the owner's admins (empty member list). Cannot be changed after creation.");
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the flags to the wire value, or `undefined` when the field should be
|
|
11
|
+
* left off the request entirely. Unlike `project approval-category add` — where
|
|
12
|
+
* `--claimers-admins-only` silently overrides `--claimer` — combining the two
|
|
13
|
+
* is an error here, because the result is immutable once created.
|
|
14
|
+
*/
|
|
15
|
+
export function resolveMembers(flags) {
|
|
16
|
+
const hasList = (flags.member?.length ?? 0) > 0;
|
|
17
|
+
if (flags.membersAdminsOnly === true) {
|
|
18
|
+
if (hasList) {
|
|
19
|
+
throw new ValidationError("Cannot combine --member with --members-admins-only.");
|
|
20
|
+
}
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
return hasList ? flags.member : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Render a record's `members` for `… get` output. The server returns all three
|
|
27
|
+
* states explicitly, so `null` (everyone) and `[]` (admins only) are told
|
|
28
|
+
* apart the same way `project approval-category` renders claimers / approvers.
|
|
29
|
+
*
|
|
30
|
+
* As of the Sep 21 2026 server release these are user objects; older servers
|
|
31
|
+
* sent bare OID strings, so both shapes are accepted.
|
|
32
|
+
*/
|
|
33
|
+
export function formatMembers(members) {
|
|
34
|
+
if (members === null || members === undefined)
|
|
35
|
+
return "(everyone)";
|
|
36
|
+
if (members.length === 0)
|
|
37
|
+
return "(admins only)";
|
|
38
|
+
return members.map((m) => (typeof m === "string" ? m : (m.name ?? m.oid))).join(", ");
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=member-flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"member-flags.js","sourceRoot":"","sources":["../../src/util/member-flags.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,IAA0B,EAAY,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAO7F,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,OAAO,GAAG;SACP,MAAM,CACL,iBAAiB,EACjB,wJAAwJ,EACxJ,MAAM,EACN,EAAc,CACf;SACA,MAAM,CAAC,uBAAuB,EAAE,kGAAkG,CAAC,CAAC;AACzI,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,eAAe,CAAC,qDAAqD,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,OAAuE;IACnG,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IACnE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC;IACjD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
/** Quire caps a lead at 10,000 days out, and a reminder at 30 leads. */
|
|
3
|
+
const MAX_DAYS = 10_000;
|
|
4
|
+
const MAX_MINUTES = MAX_DAYS * 24 * 60;
|
|
5
|
+
const MAX_LEADS = 30;
|
|
6
|
+
const LEAD_RE = /^(\d+)(m|d)?(?:@(\d{1,2}):(\d{2}))?$/;
|
|
7
|
+
function parseLead(spec) {
|
|
8
|
+
const m = LEAD_RE.exec(spec.trim());
|
|
9
|
+
if (!m) {
|
|
10
|
+
throw new ValidationError(`Invalid --lead "${spec}". Expected <n>m (minutes), <n>d (days), or <n>d@HH:mm — e.g. '30m', '2d', '1d@09:00'.`);
|
|
11
|
+
}
|
|
12
|
+
const value = Number.parseInt(m[1], 10);
|
|
13
|
+
const unit = m[2] ?? "m";
|
|
14
|
+
const hh = m[3];
|
|
15
|
+
const mm = m[4];
|
|
16
|
+
if (hh !== undefined && unit !== "d") {
|
|
17
|
+
throw new ValidationError(`Invalid --lead "${spec}". The @HH:mm suffix is only valid on a day lead — e.g. '1d@09:00'.`);
|
|
18
|
+
}
|
|
19
|
+
if (unit === "d") {
|
|
20
|
+
if (value > MAX_DAYS) {
|
|
21
|
+
throw new ValidationError(`--lead "${spec}" exceeds Quire's maximum of ${MAX_DAYS} days.`);
|
|
22
|
+
}
|
|
23
|
+
const lead = { days: value };
|
|
24
|
+
if (hh !== undefined && mm !== undefined) {
|
|
25
|
+
const hours = Number.parseInt(hh, 10);
|
|
26
|
+
const mins = Number.parseInt(mm, 10);
|
|
27
|
+
if (hours > 23 || mins > 59) {
|
|
28
|
+
throw new ValidationError(`Invalid --lead "${spec}". The time must be 24-hour HH:mm, 00:00-23:59.`);
|
|
29
|
+
}
|
|
30
|
+
lead.at = `${String(hours).padStart(2, "0")}:${mm}`;
|
|
31
|
+
}
|
|
32
|
+
return lead;
|
|
33
|
+
}
|
|
34
|
+
if (value > MAX_MINUTES) {
|
|
35
|
+
throw new ValidationError(`--lead "${spec}" exceeds Quire's maximum of ${MAX_DAYS} days.`);
|
|
36
|
+
}
|
|
37
|
+
return { minutes: value };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Parse every `--lead` value. Returns `undefined` when the flag was not
|
|
41
|
+
* passed, so the caller can omit the field and let Quire apply its default of
|
|
42
|
+
* one notification at the fire time.
|
|
43
|
+
*/
|
|
44
|
+
export function parseLeads(specs) {
|
|
45
|
+
if (specs === undefined || specs.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (specs.length > MAX_LEADS) {
|
|
48
|
+
throw new ValidationError(`A reminder carries at most ${MAX_LEADS} leads; got ${specs.length}.`);
|
|
49
|
+
}
|
|
50
|
+
return specs.map(parseLead);
|
|
51
|
+
}
|
|
52
|
+
/** Render a reminder's leads back in the `--lead` grammar, for `… get` output. */
|
|
53
|
+
export function formatLeads(leads) {
|
|
54
|
+
if (leads === undefined || leads.length === 0)
|
|
55
|
+
return undefined;
|
|
56
|
+
return leads
|
|
57
|
+
.map((l) => (l.days !== undefined ? `${l.days}d${l.at !== undefined ? `@${l.at}` : ""}` : `${l.minutes ?? 0}m`))
|
|
58
|
+
.join(", ");
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=reminder-lead.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reminder-lead.js","sourceRoot":"","sources":["../../src/util/reminder-lead.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quire-io/quire-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Command-line interface for the Quire API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
"build": "tsc",
|
|
25
25
|
"start": "node dist/cli.js",
|
|
26
26
|
"typecheck": "tsc --noEmit",
|
|
27
|
+
"gen-coverage": "tsx scripts/gen-coverage.ts",
|
|
28
|
+
"check-coverage": "tsx scripts/gen-coverage.ts && git diff --exit-code COVERAGE.md",
|
|
27
29
|
"test": "vitest run",
|
|
28
30
|
"test:watch": "vitest",
|
|
29
31
|
"test:live": "vitest run --config vitest.live.config.ts",
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
"url": "https://github.com/quire-io/quire-cli/issues"
|
|
49
51
|
},
|
|
50
52
|
"dependencies": {
|
|
51
|
-
"@quire-io/api-client": "^0.
|
|
53
|
+
"@quire-io/api-client": "^1.0.0",
|
|
52
54
|
"commander": "^12.1.0"
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|