@quire-io/quire-cli 0.1.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 +33 -0
- package/LICENSE +15 -0
- package/README.md +69 -0
- package/dist/cli.js +209 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/chat.js +200 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/colors.js +34 -0
- package/dist/commands/colors.js.map +1 -0
- package/dist/commands/comment.js +128 -0
- package/dist/commands/comment.js.map +1 -0
- package/dist/commands/doc.js +139 -0
- package/dist/commands/doc.js.map +1 -0
- package/dist/commands/insight.js +234 -0
- package/dist/commands/insight.js.map +1 -0
- package/dist/commands/login.js +78 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.js +25 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/mine.js +61 -0
- package/dist/commands/mine.js.map +1 -0
- package/dist/commands/notify.js +25 -0
- package/dist/commands/notify.js.map +1 -0
- package/dist/commands/org.js +99 -0
- package/dist/commands/org.js.map +1 -0
- package/dist/commands/partner.js +36 -0
- package/dist/commands/partner.js.map +1 -0
- package/dist/commands/project.js +346 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/resolve.js +61 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/status.js +130 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sublist.js +143 -0
- package/dist/commands/sublist.js.map +1 -0
- package/dist/commands/tag.js +108 -0
- package/dist/commands/tag.js.map +1 -0
- package/dist/commands/task.js +767 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/undo.js +64 -0
- package/dist/commands/undo.js.map +1 -0
- package/dist/commands/user.js +24 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/commands/whoami.js +34 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config.js +37 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.js +28 -0
- package/dist/credentials.js.map +1 -0
- package/dist/errors.js +56 -0
- package/dist/errors.js.map +1 -0
- package/dist/log.js +37 -0
- package/dist/log.js.map +1 -0
- package/dist/oauth/config.js +22 -0
- package/dist/oauth/config.js.map +1 -0
- package/dist/oauth/loopback.js +101 -0
- package/dist/oauth/loopback.js.map +1 -0
- package/dist/oauth/pkce.js +16 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/options.js +2 -0
- package/dist/options.js.map +1 -0
- package/dist/output/colors.js +77 -0
- package/dist/output/colors.js.map +1 -0
- package/dist/output/columns.js +22 -0
- package/dist/output/columns.js.map +1 -0
- package/dist/output/keyvalue.js +18 -0
- package/dist/output/keyvalue.js.map +1 -0
- package/dist/output/render.js +30 -0
- package/dist/output/render.js.map +1 -0
- package/dist/output/table.js +35 -0
- package/dist/output/table.js.map +1 -0
- package/dist/quire-client.js +74 -0
- package/dist/quire-client.js.map +1 -0
- package/dist/util/attach-input.js +65 -0
- package/dist/util/attach-input.js.map +1 -0
- package/dist/util/bulk-input.js +80 -0
- package/dist/util/bulk-input.js.map +1 -0
- package/dist/util/confirm.js +31 -0
- package/dist/util/confirm.js.map +1 -0
- package/dist/util/field-flags.js +52 -0
- package/dist/util/field-flags.js.map +1 -0
- package/dist/util/open-url.js +39 -0
- package/dist/util/open-url.js.map +1 -0
- package/dist/util/recurrence.js +53 -0
- package/dist/util/recurrence.js.map +1 -0
- package/dist/util/retry-after.js +56 -0
- package/dist/util/retry-after.js.map +1 -0
- package/dist/util/task-id.js +34 -0
- package/dist/util/task-id.js.map +1 -0
- package/dist/util/text-input.js +26 -0
- package/dist/util/text-input.js.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ValidationError } from "../errors.js";
|
|
2
|
+
import { renderList, renderObject } from "../output/render.js";
|
|
3
|
+
import { createQuireClient } from "../quire-client.js";
|
|
4
|
+
import { resolveAttachInput } from "../util/attach-input.js";
|
|
5
|
+
import { confirmDestructive } from "../util/confirm.js";
|
|
6
|
+
import { resolveTaskOid } from "../util/task-id.js";
|
|
7
|
+
import { resolveTextInput } from "../util/text-input.js";
|
|
8
|
+
const COMMENT_FIELDS = [
|
|
9
|
+
{ label: "OID", get: (c) => c.oid },
|
|
10
|
+
{ label: "When", get: (c) => c.createdAt },
|
|
11
|
+
{ label: "Who", get: (c) => c.createdBy?.name },
|
|
12
|
+
{ label: "Pinned at", get: (c) => c.pinAt },
|
|
13
|
+
{ label: "Text", get: (c) => c.descriptionText },
|
|
14
|
+
{ label: "URL", get: (c) => c.url },
|
|
15
|
+
];
|
|
16
|
+
const ATTACHMENT_FIELDS = [
|
|
17
|
+
{ label: "Name", get: (a) => a.name },
|
|
18
|
+
{ label: "URL", get: (a) => a.url },
|
|
19
|
+
{ label: "Length", get: (a) => String(a.length) },
|
|
20
|
+
{ label: "Created at", get: (a) => a.createdAt },
|
|
21
|
+
];
|
|
22
|
+
export function registerCommentCommand(program) {
|
|
23
|
+
const comment = program.command("comment").description("Quire task comments.");
|
|
24
|
+
comment
|
|
25
|
+
.command("list <task-id>")
|
|
26
|
+
.description("List comments on a task. <task-id> = OID, project-slug/#408, or URL.")
|
|
27
|
+
.action(async (taskId) => {
|
|
28
|
+
const root = program.opts();
|
|
29
|
+
const client = createQuireClient({ profile: root.profile });
|
|
30
|
+
const oid = await resolveTaskOid(client, taskId);
|
|
31
|
+
const comments = await client.getTaskComments(oid);
|
|
32
|
+
renderList(comments, root, {
|
|
33
|
+
columns: [
|
|
34
|
+
{
|
|
35
|
+
header: "WHEN",
|
|
36
|
+
get: (c) => c.createdAt ?? "",
|
|
37
|
+
},
|
|
38
|
+
{ header: "WHO", get: (c) => c.createdBy?.name ?? "" },
|
|
39
|
+
{
|
|
40
|
+
header: "TEXT",
|
|
41
|
+
get: (c) => (c.descriptionText ?? "").replace(/\s+/g, " ").trim(),
|
|
42
|
+
},
|
|
43
|
+
{ header: "OID", get: (c) => c.oid },
|
|
44
|
+
],
|
|
45
|
+
toId: (c) => c.oid,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
comment
|
|
49
|
+
.command("get <oid>")
|
|
50
|
+
.description("Show one comment.")
|
|
51
|
+
.action(async (oid) => {
|
|
52
|
+
const root = program.opts();
|
|
53
|
+
const client = createQuireClient({ profile: root.profile });
|
|
54
|
+
const c = await client.getComment(oid);
|
|
55
|
+
renderObject(c, root, { fields: COMMENT_FIELDS, toId: (c) => c.oid });
|
|
56
|
+
});
|
|
57
|
+
comment
|
|
58
|
+
.command("add <task-id>")
|
|
59
|
+
.description("Add a comment to a task. --text accepts '-' (stdin) or '@file' for long content.")
|
|
60
|
+
.requiredOption("--text <text>", "Comment text; use '-' for stdin or '@/path/to/file' to read from disk.")
|
|
61
|
+
.action(async (taskId, cmdOpts) => {
|
|
62
|
+
const root = program.opts();
|
|
63
|
+
const client = createQuireClient({ profile: root.profile });
|
|
64
|
+
const oid = await resolveTaskOid(client, taskId);
|
|
65
|
+
const text = await resolveTextInput(cmdOpts.text);
|
|
66
|
+
const c = await client.addComment(oid, text);
|
|
67
|
+
renderObject(c, root, { fields: COMMENT_FIELDS, toId: (c) => c.oid });
|
|
68
|
+
});
|
|
69
|
+
comment
|
|
70
|
+
.command("update <oid>")
|
|
71
|
+
.description("Update a comment. Pass --text to change the body, --pin / --unpin to toggle pinned.")
|
|
72
|
+
.option("--text <text>", "New comment text; '-' for stdin or '@file' for a file.")
|
|
73
|
+
.option("--pin", "Pin the comment.")
|
|
74
|
+
.option("--unpin", "Unpin the comment.")
|
|
75
|
+
.action(async (oid, cmdOpts) => {
|
|
76
|
+
const root = program.opts();
|
|
77
|
+
const client = createQuireClient({ profile: root.profile });
|
|
78
|
+
if (cmdOpts.pin === true && cmdOpts.unpin === true) {
|
|
79
|
+
throw new ValidationError("Cannot combine --pin and --unpin.");
|
|
80
|
+
}
|
|
81
|
+
const body = {};
|
|
82
|
+
if (cmdOpts.text !== undefined)
|
|
83
|
+
body.description = await resolveTextInput(cmdOpts.text);
|
|
84
|
+
if (cmdOpts.pin === true)
|
|
85
|
+
body.pinned = true;
|
|
86
|
+
if (cmdOpts.unpin === true)
|
|
87
|
+
body.pinned = false;
|
|
88
|
+
if (body.description === undefined && body.pinned === undefined) {
|
|
89
|
+
throw new ValidationError("`comment update` requires at least one of --text / --pin / --unpin.");
|
|
90
|
+
}
|
|
91
|
+
const c = await client.updateComment(oid, body);
|
|
92
|
+
renderObject(c, root, { fields: COMMENT_FIELDS, toId: (c) => c.oid });
|
|
93
|
+
});
|
|
94
|
+
comment
|
|
95
|
+
.command("attach <oid> <file>")
|
|
96
|
+
.description("Attach a file to a comment. <file> = path on disk, or '-' to read bytes from stdin (then --filename is required).")
|
|
97
|
+
.option("--filename <name>", "Server-side filename (defaults to the basename of <file>; required when <file> = '-')")
|
|
98
|
+
.option("--content-type <mime>", "Content-Type header (defaults to extension-based guess; falls back to application/octet-stream)")
|
|
99
|
+
.action(async (oid, file, cmdOpts) => {
|
|
100
|
+
const root = program.opts();
|
|
101
|
+
const client = createQuireClient({ profile: root.profile });
|
|
102
|
+
const input = await resolveAttachInput(file, cmdOpts);
|
|
103
|
+
const a = await client.attachCommentFile(oid, input.filename, input.bytes, input.contentType);
|
|
104
|
+
renderObject(a, root, { fields: ATTACHMENT_FIELDS, toId: (a) => a.url });
|
|
105
|
+
});
|
|
106
|
+
comment
|
|
107
|
+
.command("delete <oid>")
|
|
108
|
+
.description("Delete a comment. Prompts for confirmation unless --yes is set.")
|
|
109
|
+
.action(async (oid) => {
|
|
110
|
+
const root = program.opts();
|
|
111
|
+
const client = createQuireClient({ profile: root.profile });
|
|
112
|
+
await confirmDestructive({
|
|
113
|
+
question: `Delete comment ${oid}? Run \`quire undo comment ${oid}\` to restore (Phase 5.5).`,
|
|
114
|
+
yes: root.yes,
|
|
115
|
+
});
|
|
116
|
+
await client.deleteComment(oid);
|
|
117
|
+
if (root.json === true) {
|
|
118
|
+
process.stdout.write(`${JSON.stringify({ oid, deleted: true })}\n`);
|
|
119
|
+
}
|
|
120
|
+
else if (root.quiet === true) {
|
|
121
|
+
process.stdout.write(`${oid}\n`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
process.stderr.write(`Deleted comment ${oid}.\n`);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=comment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/commands/comment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { looksLikeOid, parseQuireUrl } from "@quire-io/api-client";
|
|
2
|
+
import { ValidationError } from "../errors.js";
|
|
3
|
+
import { renderList, renderObject } from "../output/render.js";
|
|
4
|
+
import { createQuireClient } from "../quire-client.js";
|
|
5
|
+
import { confirmDestructive } from "../util/confirm.js";
|
|
6
|
+
import { resolveTextInput } from "../util/text-input.js";
|
|
7
|
+
const DOC_FIELDS = [
|
|
8
|
+
{ label: "Name", get: (d) => d.nameText ?? d.name },
|
|
9
|
+
{ label: "ID", get: (d) => d.id },
|
|
10
|
+
{ label: "OID", get: (d) => d.oid },
|
|
11
|
+
{ label: "Description", get: (d) => d.descriptionText },
|
|
12
|
+
{ label: "URL", get: (d) => d.url },
|
|
13
|
+
];
|
|
14
|
+
async function resolveDocOid(client, input) {
|
|
15
|
+
if (looksLikeOid(input))
|
|
16
|
+
return input;
|
|
17
|
+
if (/^https?:\/\//i.test(input)) {
|
|
18
|
+
const parsed = parseQuireUrl(input);
|
|
19
|
+
if (parsed?.kind === "document") {
|
|
20
|
+
const d = await client.getDocumentByProjectAndId(parsed.projectId, parsed.docId);
|
|
21
|
+
return d.oid;
|
|
22
|
+
}
|
|
23
|
+
throw new ValidationError(`URL is not a Quire document: "${input}"`);
|
|
24
|
+
}
|
|
25
|
+
const slug = input.match(/^([^/]+)\/(.+)$/);
|
|
26
|
+
if (slug) {
|
|
27
|
+
const projectId = slug[1];
|
|
28
|
+
const docId = slug[2];
|
|
29
|
+
const d = await client.getDocumentByProjectAndId(projectId, docId);
|
|
30
|
+
return d.oid;
|
|
31
|
+
}
|
|
32
|
+
throw new ValidationError(`Cannot resolve document: "${input}". Expected a doc OID, "project-slug/<doc-id>", or a full Quire document URL.`);
|
|
33
|
+
}
|
|
34
|
+
export function registerDocCommand(program) {
|
|
35
|
+
const doc = program.command("doc").description("Quire documents.");
|
|
36
|
+
doc
|
|
37
|
+
.command("list <project>")
|
|
38
|
+
.description("List documents in a project. <project> = OID, slug, or URL.")
|
|
39
|
+
.action(async (project) => {
|
|
40
|
+
const root = program.opts();
|
|
41
|
+
const client = createQuireClient({ profile: root.profile });
|
|
42
|
+
const oid = await client.resolveProjectOid(project);
|
|
43
|
+
const docs = await client.listDocuments("project", oid);
|
|
44
|
+
renderList(docs, root, {
|
|
45
|
+
columns: [
|
|
46
|
+
{ header: "ID", get: (d) => d.id },
|
|
47
|
+
{ header: "NAME", get: (d) => d.nameText ?? d.name },
|
|
48
|
+
{ header: "OID", get: (d) => d.oid },
|
|
49
|
+
],
|
|
50
|
+
toId: (d) => d.oid,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
doc
|
|
54
|
+
.command("get <id>")
|
|
55
|
+
.description("Show document details. <id> = OID, project-slug/<doc-id>, or URL.")
|
|
56
|
+
.action(async (id) => {
|
|
57
|
+
const root = program.opts();
|
|
58
|
+
const client = createQuireClient({ profile: root.profile });
|
|
59
|
+
const oid = await resolveDocOid(client, id);
|
|
60
|
+
const d = await client.getDocument(oid);
|
|
61
|
+
renderObject(d, root, { fields: DOC_FIELDS, toId: (d) => d.oid });
|
|
62
|
+
});
|
|
63
|
+
doc
|
|
64
|
+
.command("create <project>")
|
|
65
|
+
.description("Create a document in a project. --description accepts '-' (stdin) or '@file'.")
|
|
66
|
+
.requiredOption("--name <name>", "Document name (required)")
|
|
67
|
+
.option("--description <text>", "Document description; '-' for stdin or '@file' for a file")
|
|
68
|
+
.action(async (project, cmdOpts) => {
|
|
69
|
+
const root = program.opts();
|
|
70
|
+
const client = createQuireClient({ profile: root.profile });
|
|
71
|
+
const projectOid = await client.resolveProjectOid(project);
|
|
72
|
+
const description = cmdOpts.description !== undefined ? await resolveTextInput(cmdOpts.description) : undefined;
|
|
73
|
+
const d = await client.createDocument("project", projectOid, {
|
|
74
|
+
name: cmdOpts.name,
|
|
75
|
+
...(description !== undefined ? { description } : {}),
|
|
76
|
+
});
|
|
77
|
+
renderObject(d, root, { fields: DOC_FIELDS, toId: (d) => d.oid });
|
|
78
|
+
});
|
|
79
|
+
doc
|
|
80
|
+
.command("update <oid>")
|
|
81
|
+
.description("Update a document.")
|
|
82
|
+
.option("--name <name>", "New name")
|
|
83
|
+
.option("--description <text>", "New description ('-' for stdin, '@file' for a file)")
|
|
84
|
+
.option("--archive", "Archive the document")
|
|
85
|
+
.option("--unarchive", "Unarchive the document")
|
|
86
|
+
.action(async (oid, cmdOpts) => {
|
|
87
|
+
const root = program.opts();
|
|
88
|
+
const client = createQuireClient({ profile: root.profile });
|
|
89
|
+
if (cmdOpts.archive === true && cmdOpts.unarchive === true) {
|
|
90
|
+
throw new ValidationError("Cannot combine --archive and --unarchive.");
|
|
91
|
+
}
|
|
92
|
+
const description = cmdOpts.description !== undefined ? await resolveTextInput(cmdOpts.description) : undefined;
|
|
93
|
+
const body = {};
|
|
94
|
+
if (cmdOpts.name !== undefined)
|
|
95
|
+
body.name = cmdOpts.name;
|
|
96
|
+
if (description !== undefined)
|
|
97
|
+
body.description = description;
|
|
98
|
+
if (cmdOpts.archive === true)
|
|
99
|
+
body.archived = true;
|
|
100
|
+
if (cmdOpts.unarchive === true)
|
|
101
|
+
body.archived = false;
|
|
102
|
+
if (Object.keys(body).length === 0) {
|
|
103
|
+
throw new ValidationError("`doc update` requires at least one of --name / --description / --archive / --unarchive.");
|
|
104
|
+
}
|
|
105
|
+
const d = await client.updateDocument(oid, body);
|
|
106
|
+
renderObject(d, root, { fields: DOC_FIELDS, toId: (d) => d.oid });
|
|
107
|
+
});
|
|
108
|
+
doc
|
|
109
|
+
.command("delete <oid>")
|
|
110
|
+
.description("Delete a document. Prompts unless --yes.")
|
|
111
|
+
.action(async (oid) => {
|
|
112
|
+
const root = program.opts();
|
|
113
|
+
const client = createQuireClient({ profile: root.profile });
|
|
114
|
+
await confirmDestructive({
|
|
115
|
+
question: `Delete document ${oid}? Run \`quire doc undo-remove ${oid}\` (or \`quire undo document ${oid}\`) to restore.`,
|
|
116
|
+
yes: root.yes,
|
|
117
|
+
});
|
|
118
|
+
await client.deleteDocument(oid);
|
|
119
|
+
if (root.json === true) {
|
|
120
|
+
process.stdout.write(`${JSON.stringify({ oid, deleted: true })}\n`);
|
|
121
|
+
}
|
|
122
|
+
else if (root.quiet === true) {
|
|
123
|
+
process.stdout.write(`${oid}\n`);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
process.stderr.write(`Deleted document ${oid}.\n`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
doc
|
|
130
|
+
.command("undo-remove <oid>")
|
|
131
|
+
.description("Restore a deleted document.")
|
|
132
|
+
.action(async (oid) => {
|
|
133
|
+
const root = program.opts();
|
|
134
|
+
const client = createQuireClient({ profile: root.profile });
|
|
135
|
+
const d = await client.undoRemoveDocument(oid);
|
|
136
|
+
renderObject(d, root, { fields: DOC_FIELDS, toId: (d) => d.oid });
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc.js","sourceRoot":"","sources":["../../src/commands/doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { resolveColor } from "@quire-io/api-client";
|
|
2
|
+
import { ValidationError } from "../errors.js";
|
|
3
|
+
import { renderList, renderObject } from "../output/render.js";
|
|
4
|
+
import { createQuireClient } from "../quire-client.js";
|
|
5
|
+
import { confirmDestructive } from "../util/confirm.js";
|
|
6
|
+
import { buildFieldBody, FIELD_FIELDS } from "../util/field-flags.js";
|
|
7
|
+
import { resolveTextInput } from "../util/text-input.js";
|
|
8
|
+
const append = (val, prev) => [...(prev ?? []), val];
|
|
9
|
+
function normalizeInsightColor(input) {
|
|
10
|
+
if (input === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
const code = resolveColor(input);
|
|
13
|
+
if (code === undefined) {
|
|
14
|
+
throw new ValidationError(`Color "${input}" is not a recognized palette name or code. Use a name like 'red'/'blue' or a 2-digit code '00'..'57'.`);
|
|
15
|
+
}
|
|
16
|
+
return code;
|
|
17
|
+
}
|
|
18
|
+
const INSIGHT_FIELDS = [
|
|
19
|
+
{ label: "Name", get: (i) => i.nameText ?? i.name },
|
|
20
|
+
{ label: "ID", get: (i) => i.id },
|
|
21
|
+
{ label: "OID", get: (i) => i.oid },
|
|
22
|
+
{ label: "Description", get: (i) => i.descriptionText },
|
|
23
|
+
{ label: "Icon color", get: (i) => i.iconColor },
|
|
24
|
+
{ label: "URL", get: (i) => i.url },
|
|
25
|
+
];
|
|
26
|
+
export function registerInsightCommand(program) {
|
|
27
|
+
const insight = program.command("insight").description("Quire insights.");
|
|
28
|
+
insight
|
|
29
|
+
.command("list <project>")
|
|
30
|
+
.description("List insights on a project. <project> = OID, slug, or URL.")
|
|
31
|
+
.action(async (project) => {
|
|
32
|
+
const root = program.opts();
|
|
33
|
+
const client = createQuireClient({ profile: root.profile });
|
|
34
|
+
const oid = await client.resolveProjectOid(project);
|
|
35
|
+
const insights = await client.listInsights(oid);
|
|
36
|
+
renderList(insights, root, {
|
|
37
|
+
columns: [
|
|
38
|
+
{ header: "ID", get: (i) => i.id },
|
|
39
|
+
{ header: "NAME", get: (i) => i.nameText ?? i.name },
|
|
40
|
+
{ header: "OID", get: (i) => i.oid },
|
|
41
|
+
],
|
|
42
|
+
toId: (i) => i.oid,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
insight
|
|
46
|
+
.command("get <id>")
|
|
47
|
+
.description("Show insight details. <id> = insight OID.")
|
|
48
|
+
.action(async (id) => {
|
|
49
|
+
const root = program.opts();
|
|
50
|
+
const client = createQuireClient({ profile: root.profile });
|
|
51
|
+
const i = await client.getInsight(id);
|
|
52
|
+
renderObject(i, root, { fields: INSIGHT_FIELDS, toId: (i) => i.oid });
|
|
53
|
+
});
|
|
54
|
+
insight
|
|
55
|
+
.command("create <project>")
|
|
56
|
+
.description("Create an insight inside a project.")
|
|
57
|
+
.requiredOption("--name <name>", "Insight name (required)")
|
|
58
|
+
.option("--id <id>", "Caller-supplied id (must pass Quire's isValidId)")
|
|
59
|
+
.option("--description <text>", "Description; '-' for stdin or '@file' for a file")
|
|
60
|
+
.option("--icon-color <color>", "Color: name like 'red'/'blue' or 2-digit code")
|
|
61
|
+
.option("--image <url>", "Icon image URL")
|
|
62
|
+
.action(async (project, cmdOpts) => {
|
|
63
|
+
const root = program.opts();
|
|
64
|
+
const client = createQuireClient({ profile: root.profile });
|
|
65
|
+
const projectOid = await client.resolveProjectOid(project);
|
|
66
|
+
const description = cmdOpts.description !== undefined ? await resolveTextInput(cmdOpts.description) : undefined;
|
|
67
|
+
const iconColor = cmdOpts.iconColor !== undefined ? normalizeInsightColor(cmdOpts.iconColor) : undefined;
|
|
68
|
+
const i = await client.createInsight("project", projectOid, {
|
|
69
|
+
name: cmdOpts.name,
|
|
70
|
+
...(cmdOpts.id !== undefined ? { id: cmdOpts.id } : {}),
|
|
71
|
+
...(description !== undefined ? { description } : {}),
|
|
72
|
+
...(iconColor !== undefined ? { iconColor } : {}),
|
|
73
|
+
...(cmdOpts.image !== undefined ? { image: cmdOpts.image } : {}),
|
|
74
|
+
});
|
|
75
|
+
renderObject(i, root, { fields: INSIGHT_FIELDS, toId: (i) => i.oid });
|
|
76
|
+
});
|
|
77
|
+
insight
|
|
78
|
+
.command("update <oid>")
|
|
79
|
+
.description("Update an insight.")
|
|
80
|
+
.option("--name <name>")
|
|
81
|
+
.option("--description <text>", "'-' = stdin, '@file' = file")
|
|
82
|
+
.option("--icon-color <color>")
|
|
83
|
+
.option("--image <url>")
|
|
84
|
+
.option("--archive", "Archive the insight")
|
|
85
|
+
.option("--unarchive", "Unarchive the insight")
|
|
86
|
+
.action(async (oid, cmdOpts) => {
|
|
87
|
+
const root = program.opts();
|
|
88
|
+
const client = createQuireClient({ profile: root.profile });
|
|
89
|
+
if (cmdOpts.archive === true && cmdOpts.unarchive === true) {
|
|
90
|
+
throw new ValidationError("Cannot combine --archive and --unarchive.");
|
|
91
|
+
}
|
|
92
|
+
const description = cmdOpts.description !== undefined ? await resolveTextInput(cmdOpts.description) : undefined;
|
|
93
|
+
const iconColor = cmdOpts.iconColor !== undefined ? normalizeInsightColor(cmdOpts.iconColor) : undefined;
|
|
94
|
+
const body = {};
|
|
95
|
+
if (cmdOpts.name !== undefined)
|
|
96
|
+
body.name = cmdOpts.name;
|
|
97
|
+
if (description !== undefined)
|
|
98
|
+
body.description = description;
|
|
99
|
+
if (iconColor !== undefined)
|
|
100
|
+
body.iconColor = iconColor;
|
|
101
|
+
if (cmdOpts.image !== undefined)
|
|
102
|
+
body.image = cmdOpts.image;
|
|
103
|
+
if (cmdOpts.archive === true)
|
|
104
|
+
body.archived = true;
|
|
105
|
+
if (cmdOpts.unarchive === true)
|
|
106
|
+
body.archived = false;
|
|
107
|
+
if (Object.keys(body).length === 0) {
|
|
108
|
+
throw new ValidationError("`insight update` requires at least one change-flag.");
|
|
109
|
+
}
|
|
110
|
+
const i = await client.updateInsight(oid, body);
|
|
111
|
+
renderObject(i, root, { fields: INSIGHT_FIELDS, toId: (i) => i.oid });
|
|
112
|
+
});
|
|
113
|
+
insight
|
|
114
|
+
.command("delete <oid>")
|
|
115
|
+
.description("Delete an insight. Prompts unless --yes.")
|
|
116
|
+
.action(async (oid) => {
|
|
117
|
+
const root = program.opts();
|
|
118
|
+
const client = createQuireClient({ profile: root.profile });
|
|
119
|
+
await confirmDestructive({
|
|
120
|
+
question: `Delete insight ${oid}? Run \`quire insight undo-remove ${oid}\` (or \`quire undo insight ${oid}\`) to restore.`,
|
|
121
|
+
yes: root.yes,
|
|
122
|
+
});
|
|
123
|
+
await client.deleteInsight(oid);
|
|
124
|
+
if (root.json === true) {
|
|
125
|
+
process.stdout.write(`${JSON.stringify({ oid, deleted: true })}\n`);
|
|
126
|
+
}
|
|
127
|
+
else if (root.quiet === true) {
|
|
128
|
+
process.stdout.write(`${oid}\n`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
process.stderr.write(`Deleted insight ${oid}.\n`);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
insight
|
|
135
|
+
.command("undo-remove <oid>")
|
|
136
|
+
.description("Restore a deleted insight.")
|
|
137
|
+
.action(async (oid) => {
|
|
138
|
+
const root = program.opts();
|
|
139
|
+
const client = createQuireClient({ profile: root.profile });
|
|
140
|
+
const i = await client.undoRemoveInsight(oid);
|
|
141
|
+
renderObject(i, root, { fields: INSIGHT_FIELDS, toId: (i) => i.oid });
|
|
142
|
+
});
|
|
143
|
+
// -------- Custom field definitions on insights (Phase 5.3 slice C) --------
|
|
144
|
+
// Insights only support `formula` and `lookup` field types per the plan;
|
|
145
|
+
// the api accepts the body and lets the server validate.
|
|
146
|
+
const field = insight
|
|
147
|
+
.command("field")
|
|
148
|
+
.description("Manage custom-field definitions on an insight (formula / lookup types).");
|
|
149
|
+
field
|
|
150
|
+
.command("add <insight-oid>")
|
|
151
|
+
.description("Add a custom-field to an insight. Insights only allow formula / lookup types.")
|
|
152
|
+
.requiredOption("--name <name>", "Field name (required)")
|
|
153
|
+
.requiredOption("--type <type>", "Field type (insights: formula | lookup)")
|
|
154
|
+
.option("--hidden")
|
|
155
|
+
.option("--private")
|
|
156
|
+
.option("--percent")
|
|
157
|
+
.option("--multiple")
|
|
158
|
+
.option("--clear-on-dup")
|
|
159
|
+
.option("--extra <kv>", "key=value; repeat for type-specific config", append, [])
|
|
160
|
+
.action(async (insightOid, cmdOpts) => {
|
|
161
|
+
const root = program.opts();
|
|
162
|
+
const client = createQuireClient({ profile: root.profile });
|
|
163
|
+
const body = buildFieldBody(cmdOpts);
|
|
164
|
+
const f = await client.addInsightField(insightOid, body);
|
|
165
|
+
renderObject(f, root, { fields: FIELD_FIELDS, toId: (f) => f.name });
|
|
166
|
+
});
|
|
167
|
+
field
|
|
168
|
+
.command("update <insight-oid> <field-name>")
|
|
169
|
+
.description("Update a custom-field definition on an insight.")
|
|
170
|
+
.option("--type <type>", "New type")
|
|
171
|
+
.option("--hidden")
|
|
172
|
+
.option("--private")
|
|
173
|
+
.option("--percent")
|
|
174
|
+
.option("--multiple")
|
|
175
|
+
.option("--clear-on-dup")
|
|
176
|
+
.option("--extra <kv>", "key=value; repeat", append, [])
|
|
177
|
+
.action(async (insightOid, fieldName, cmdOpts) => {
|
|
178
|
+
const root = program.opts();
|
|
179
|
+
const client = createQuireClient({ profile: root.profile });
|
|
180
|
+
const body = buildFieldBody(cmdOpts);
|
|
181
|
+
if (Object.keys(body).length === 0) {
|
|
182
|
+
throw new ValidationError("`insight field update` requires at least one of --type / --hidden / --private / --percent / --multiple / --clear-on-dup / --extra.");
|
|
183
|
+
}
|
|
184
|
+
const f = await client.updateInsightField(insightOid, fieldName, body);
|
|
185
|
+
renderObject(f, root, { fields: FIELD_FIELDS, toId: (f) => f.name });
|
|
186
|
+
});
|
|
187
|
+
field
|
|
188
|
+
.command("rename <insight-oid> <field-name>")
|
|
189
|
+
.description("Rename an insight custom-field.")
|
|
190
|
+
.requiredOption("--new-name <new-name>", "New field name")
|
|
191
|
+
.action(async (insightOid, fieldName, cmdOpts) => {
|
|
192
|
+
const root = program.opts();
|
|
193
|
+
const client = createQuireClient({ profile: root.profile });
|
|
194
|
+
const f = await client.renameInsightField(insightOid, fieldName, cmdOpts.newName);
|
|
195
|
+
renderObject(f, root, { fields: FIELD_FIELDS, toId: (f) => f.name });
|
|
196
|
+
});
|
|
197
|
+
field
|
|
198
|
+
.command("move <insight-oid> <field-name>")
|
|
199
|
+
.description("Reorder an insight custom-field.")
|
|
200
|
+
.option("--before <field-name>", "Move just before this field")
|
|
201
|
+
.option("--to-end", "Move to the end of the field list")
|
|
202
|
+
.action(async (insightOid, fieldName, cmdOpts) => {
|
|
203
|
+
const root = program.opts();
|
|
204
|
+
const client = createQuireClient({ profile: root.profile });
|
|
205
|
+
if (cmdOpts.before !== undefined && cmdOpts.toEnd === true) {
|
|
206
|
+
throw new ValidationError("Cannot combine --before and --to-end.");
|
|
207
|
+
}
|
|
208
|
+
const before = cmdOpts.toEnd === true ? null : cmdOpts.before;
|
|
209
|
+
const f = await client.moveInsightField(insightOid, fieldName, before);
|
|
210
|
+
renderObject(f, root, { fields: FIELD_FIELDS, toId: (f) => f.name });
|
|
211
|
+
});
|
|
212
|
+
field
|
|
213
|
+
.command("remove <insight-oid> <field-name>")
|
|
214
|
+
.description("Remove a custom-field from an insight. Prompts unless --yes.")
|
|
215
|
+
.action(async (insightOid, fieldName) => {
|
|
216
|
+
const root = program.opts();
|
|
217
|
+
const client = createQuireClient({ profile: root.profile });
|
|
218
|
+
await confirmDestructive({
|
|
219
|
+
question: `Remove custom-field "${fieldName}" from insight ${insightOid}?`,
|
|
220
|
+
yes: root.yes,
|
|
221
|
+
});
|
|
222
|
+
await client.removeInsightField(insightOid, fieldName);
|
|
223
|
+
if (root.json === true) {
|
|
224
|
+
process.stdout.write(`${JSON.stringify({ insight: insightOid, field: fieldName, removed: true })}\n`);
|
|
225
|
+
}
|
|
226
|
+
else if (root.quiet === true) {
|
|
227
|
+
process.stdout.write(`${fieldName}\n`);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
process.stderr.write(`Removed custom-field "${fieldName}" from insight ${insightOid}.\n`);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=insight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insight.js","sourceRoot":"","sources":["../../src/commands/insight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { exchangeCode, QuireClient } from "@quire-io/api-client";
|
|
2
|
+
import { getApiServer, resolveConfigPaths } from "../config.js";
|
|
3
|
+
import { writeCredentials } from "../credentials.js";
|
|
4
|
+
import { CliError, ExitCode } from "../errors.js";
|
|
5
|
+
import { createLogger } from "../log.js";
|
|
6
|
+
import { QUIRE_CLI_CLIENT_ID, QUIRE_CLI_LOOPBACK_PORT } from "../oauth/config.js";
|
|
7
|
+
import { startLoopbackServer } from "../oauth/loopback.js";
|
|
8
|
+
import { generatePkce, generateState } from "../oauth/pkce.js";
|
|
9
|
+
import { openUrl } from "../util/open-url.js";
|
|
10
|
+
export function registerLoginCommand(program) {
|
|
11
|
+
program
|
|
12
|
+
.command("login")
|
|
13
|
+
.description("Sign in to Quire via OAuth (loopback redirect + PKCE).")
|
|
14
|
+
.action(async () => {
|
|
15
|
+
const root = program.opts();
|
|
16
|
+
const log = createLogger({ verbose: root.verbose === true, color: root.colorMode });
|
|
17
|
+
const apiServer = getApiServer();
|
|
18
|
+
const { codeVerifier, codeChallenge } = generatePkce();
|
|
19
|
+
const state = generateState();
|
|
20
|
+
const server = await startLoopbackServer({ port: QUIRE_CLI_LOOPBACK_PORT });
|
|
21
|
+
try {
|
|
22
|
+
const authorizeUrl = new URL(`${apiServer}/oauth`);
|
|
23
|
+
authorizeUrl.searchParams.set("response_type", "code");
|
|
24
|
+
authorizeUrl.searchParams.set("client_id", QUIRE_CLI_CLIENT_ID);
|
|
25
|
+
authorizeUrl.searchParams.set("redirect_uri", server.redirectUri);
|
|
26
|
+
authorizeUrl.searchParams.set("code_challenge", codeChallenge);
|
|
27
|
+
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
28
|
+
authorizeUrl.searchParams.set("state", state);
|
|
29
|
+
const url = authorizeUrl.toString();
|
|
30
|
+
log.info("Opening your browser to authorize the Quire CLI…");
|
|
31
|
+
log.info(`If the browser does not open, paste this URL:\n ${url}`);
|
|
32
|
+
try {
|
|
33
|
+
await openUrl(url);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
// Headless / no browser available — the URL was already printed.
|
|
37
|
+
log.debug(`openUrl() failed: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
const result = await server.waitForCallback();
|
|
40
|
+
if (result.state !== state) {
|
|
41
|
+
throw new CliError("OAuth state mismatch — refusing to exchange code. This usually means the redirect was tampered with or arrived from a different login attempt.", ExitCode.Validation);
|
|
42
|
+
}
|
|
43
|
+
const tokens = await exchangeCode({
|
|
44
|
+
apiServer,
|
|
45
|
+
clientId: QUIRE_CLI_CLIENT_ID,
|
|
46
|
+
code: result.code,
|
|
47
|
+
redirectUri: server.redirectUri,
|
|
48
|
+
codeVerifier,
|
|
49
|
+
});
|
|
50
|
+
// Capture userOid + display name from /me before persisting, so the
|
|
51
|
+
// credentials file is complete on first write.
|
|
52
|
+
const probe = new QuireClient({ tokens, apiServer });
|
|
53
|
+
const me = await probe.getMe();
|
|
54
|
+
writeCredentials({
|
|
55
|
+
accessToken: tokens.accessToken,
|
|
56
|
+
refreshToken: tokens.refreshToken,
|
|
57
|
+
expiresAt: tokens.expiresAt,
|
|
58
|
+
userOid: me.oid,
|
|
59
|
+
}, root.profile);
|
|
60
|
+
const { credentialsPath } = resolveConfigPaths(root.profile);
|
|
61
|
+
const displayName = me.nameText ?? me.name;
|
|
62
|
+
const emailSuffix = me.email ? ` (${me.email})` : "";
|
|
63
|
+
if (root.json === true) {
|
|
64
|
+
process.stdout.write(`${JSON.stringify(me)}\n`);
|
|
65
|
+
}
|
|
66
|
+
else if (root.quiet === true) {
|
|
67
|
+
process.stdout.write(`${me.oid}\n`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
log.info(`Logged in as ${displayName}${emailSuffix} — credentials saved to ${credentialsPath}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
server.close();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|