@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.
Files changed (94) hide show
  1. package/CHANGES.md +33 -0
  2. package/LICENSE +15 -0
  3. package/README.md +69 -0
  4. package/dist/cli.js +209 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/chat.js +200 -0
  7. package/dist/commands/chat.js.map +1 -0
  8. package/dist/commands/colors.js +34 -0
  9. package/dist/commands/colors.js.map +1 -0
  10. package/dist/commands/comment.js +128 -0
  11. package/dist/commands/comment.js.map +1 -0
  12. package/dist/commands/doc.js +139 -0
  13. package/dist/commands/doc.js.map +1 -0
  14. package/dist/commands/insight.js +234 -0
  15. package/dist/commands/insight.js.map +1 -0
  16. package/dist/commands/login.js +78 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/logout.js +25 -0
  19. package/dist/commands/logout.js.map +1 -0
  20. package/dist/commands/mine.js +61 -0
  21. package/dist/commands/mine.js.map +1 -0
  22. package/dist/commands/notify.js +25 -0
  23. package/dist/commands/notify.js.map +1 -0
  24. package/dist/commands/org.js +99 -0
  25. package/dist/commands/org.js.map +1 -0
  26. package/dist/commands/partner.js +36 -0
  27. package/dist/commands/partner.js.map +1 -0
  28. package/dist/commands/project.js +346 -0
  29. package/dist/commands/project.js.map +1 -0
  30. package/dist/commands/resolve.js +61 -0
  31. package/dist/commands/resolve.js.map +1 -0
  32. package/dist/commands/status.js +130 -0
  33. package/dist/commands/status.js.map +1 -0
  34. package/dist/commands/sublist.js +143 -0
  35. package/dist/commands/sublist.js.map +1 -0
  36. package/dist/commands/tag.js +108 -0
  37. package/dist/commands/tag.js.map +1 -0
  38. package/dist/commands/task.js +767 -0
  39. package/dist/commands/task.js.map +1 -0
  40. package/dist/commands/undo.js +64 -0
  41. package/dist/commands/undo.js.map +1 -0
  42. package/dist/commands/user.js +24 -0
  43. package/dist/commands/user.js.map +1 -0
  44. package/dist/commands/whoami.js +34 -0
  45. package/dist/commands/whoami.js.map +1 -0
  46. package/dist/config.js +37 -0
  47. package/dist/config.js.map +1 -0
  48. package/dist/credentials.js +28 -0
  49. package/dist/credentials.js.map +1 -0
  50. package/dist/errors.js +56 -0
  51. package/dist/errors.js.map +1 -0
  52. package/dist/log.js +37 -0
  53. package/dist/log.js.map +1 -0
  54. package/dist/oauth/config.js +22 -0
  55. package/dist/oauth/config.js.map +1 -0
  56. package/dist/oauth/loopback.js +101 -0
  57. package/dist/oauth/loopback.js.map +1 -0
  58. package/dist/oauth/pkce.js +16 -0
  59. package/dist/oauth/pkce.js.map +1 -0
  60. package/dist/options.js +2 -0
  61. package/dist/options.js.map +1 -0
  62. package/dist/output/colors.js +77 -0
  63. package/dist/output/colors.js.map +1 -0
  64. package/dist/output/columns.js +22 -0
  65. package/dist/output/columns.js.map +1 -0
  66. package/dist/output/keyvalue.js +18 -0
  67. package/dist/output/keyvalue.js.map +1 -0
  68. package/dist/output/render.js +30 -0
  69. package/dist/output/render.js.map +1 -0
  70. package/dist/output/table.js +35 -0
  71. package/dist/output/table.js.map +1 -0
  72. package/dist/quire-client.js +74 -0
  73. package/dist/quire-client.js.map +1 -0
  74. package/dist/util/attach-input.js +65 -0
  75. package/dist/util/attach-input.js.map +1 -0
  76. package/dist/util/bulk-input.js +80 -0
  77. package/dist/util/bulk-input.js.map +1 -0
  78. package/dist/util/confirm.js +31 -0
  79. package/dist/util/confirm.js.map +1 -0
  80. package/dist/util/field-flags.js +52 -0
  81. package/dist/util/field-flags.js.map +1 -0
  82. package/dist/util/open-url.js +39 -0
  83. package/dist/util/open-url.js.map +1 -0
  84. package/dist/util/recurrence.js +53 -0
  85. package/dist/util/recurrence.js.map +1 -0
  86. package/dist/util/retry-after.js +56 -0
  87. package/dist/util/retry-after.js.map +1 -0
  88. package/dist/util/task-id.js +34 -0
  89. package/dist/util/task-id.js.map +1 -0
  90. package/dist/util/text-input.js +26 -0
  91. package/dist/util/text-input.js.map +1 -0
  92. package/dist/version.js +19 -0
  93. package/dist/version.js.map +1 -0
  94. 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":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,IAA0B,EAAY,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAE7F,SAAS,qBAAqB,CAAC,KAAyB;IACtD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,eAAe,CACvB,UAAU,KAAK,wGAAwG,CACxH,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,cAAc,GAAG;IACrB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAsC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE;IACxF,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;IACjD,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;IACpD,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,CAA+B,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE;IACrF,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAyB,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE;IACxE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;CACtD,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAE1E,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAChD,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE;YACzB,OAAO,EAAE;gBACP,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;gBAClC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE;gBACpD,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;aACrC;YACD,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,KAAK,EAAE,EAAU,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,qCAAqC,CAAC;SAClD,cAAc,CAAC,eAAe,EAAE,yBAAyB,CAAC;SAC1D,MAAM,CAAC,WAAW,EAAE,kDAAkD,CAAC;SACvE,MAAM,CAAC,sBAAsB,EAAE,kDAAkD,CAAC;SAClF,MAAM,CAAC,sBAAsB,EAAE,+CAA+C,CAAC;SAC/E,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAAC;SACzC,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,OAE/B,EAAE,EAAE;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzG,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,UAAU,EAAE;YAC1D,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC,CAAC;QACH,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,eAAe,CAAC;SACvB,MAAM,CAAC,sBAAsB,EAAE,6BAA6B,CAAC;SAC7D,MAAM,CAAC,sBAAsB,CAAC;SAC9B,MAAM,CAAC,eAAe,CAAC;SACvB,MAAM,CAAC,WAAW,EAAE,qBAAqB,CAAC;SAC1C,MAAM,CAAC,aAAa,EAAE,uBAAuB,CAAC;SAC9C,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,OAG3B,EAAE,EAAE;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC3D,MAAM,IAAI,eAAe,CAAC,2CAA2C,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChH,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzG,MAAM,IAAI,GAAoG,EAAE,CAAC;QACjH,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzD,IAAI,WAAW,KAAK,SAAS;YAAE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC9D,IAAI,SAAS,KAAK,SAAS;YAAE,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QACxD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5D,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACnD,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI;YAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,eAAe,CAAC,qDAAqD,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChD,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,0CAA0C,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,kBAAkB,CAAC;YACvB,QAAQ,EAAE,kBAAkB,GAAG,qCAAqC,GAAG,+BAA+B,GAAG,iBAAiB;YAC1H,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;QACtE,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,KAAK,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC9C,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEL,6EAA6E;IAC7E,yEAAyE;IACzE,yDAAyD;IAEzD,MAAM,KAAK,GAAG,OAAO;SAClB,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,yEAAyE,CAAC,CAAC;IAE1F,KAAK;SACF,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,+EAA+E,CAAC;SAC5F,cAAc,CAAC,eAAe,EAAE,uBAAuB,CAAC;SACxD,cAAc,CAAC,eAAe,EAAE,yCAAyC,CAAC;SAC1E,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC,gBAAgB,CAAC;SACxB,MAAM,CAAC,cAAc,EAAE,4CAA4C,EAAE,MAAM,EAAE,EAAc,CAAC;SAC5F,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,OAAmB,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,UAAU,EAAE,IAAsC,CAAC,CAAC;QAC3F,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,mCAAmC,CAAC;SAC5C,WAAW,CAAC,iDAAiD,CAAC;SAC9D,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC;SACnC,MAAM,CAAC,UAAU,CAAC;SAClB,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC,gBAAgB,CAAC;SACxB,MAAM,CAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,EAAE,EAAc,CAAC;SACnE,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,SAAiB,EAAE,OAAiC,EAAE,EAAE;QACzF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,eAAe,CAAC,oIAAoI,CAAC,CAAC;QAClK,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACvE,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,mCAAmC,CAAC;SAC5C,WAAW,CAAC,iCAAiC,CAAC;SAC9C,cAAc,CAAC,uBAAuB,EAAE,gBAAgB,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,SAAiB,EAAE,OAA4B,EAAE,EAAE;QACpF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAClF,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,iCAAiC,CAAC;SAC1C,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,uBAAuB,EAAE,6BAA6B,CAAC;SAC9D,MAAM,CAAC,UAAU,EAAE,mCAAmC,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,SAAiB,EAAE,OAA6C,EAAE,EAAE;QACrG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC3D,MAAM,IAAI,eAAe,CAAC,uCAAuC,CAAC,CAAC;QACrE,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QAC9D,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACvE,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEL,KAAK;SACF,OAAO,CAAC,mCAAmC,CAAC;SAC5C,WAAW,CAAC,8DAA8D,CAAC;SAC3E,MAAM,CAAC,KAAK,EAAE,UAAkB,EAAE,SAAiB,EAAE,EAAE;QACtD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;QACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5D,MAAM,kBAAkB,CAAC;YACvB,QAAQ,EAAE,wBAAwB,SAAS,kBAAkB,UAAU,GAAG;YAC1E,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,kBAAkB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACvD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;QACxG,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,SAAS,kBAAkB,UAAU,KAAK,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -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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"}