exponential-cli 1.9.0 → 1.10.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/README.md +30 -0
- package/dist/index.js +624 -46
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command22 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -752,30 +752,59 @@ function outputStagesJson(stages) {
|
|
|
752
752
|
total: stages.length
|
|
753
753
|
}, null, 2));
|
|
754
754
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
const
|
|
755
|
+
var COMMENT_PARENT_KEYS = ["actionId", "ticketId", "goalId", "featureId", "pageId"];
|
|
756
|
+
function normalizeComment(comment) {
|
|
757
|
+
const raw = comment;
|
|
758
|
+
const parentKey = COMMENT_PARENT_KEYS.find((k) => k in raw) ?? "parentId";
|
|
759
|
+
const author = raw.author ?? raw.createdBy ?? null;
|
|
758
760
|
return {
|
|
759
761
|
id: comment.id,
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
author
|
|
764
|
-
|
|
765
|
-
|
|
762
|
+
parentKey,
|
|
763
|
+
parentId: raw[parentKey],
|
|
764
|
+
authorId: raw.authorId ?? raw.createdById,
|
|
765
|
+
author,
|
|
766
|
+
content: raw.content ?? raw.body ?? "",
|
|
767
|
+
createdAt: new Date(comment.createdAt),
|
|
768
|
+
updatedAt: new Date(comment.updatedAt),
|
|
769
|
+
parentCommentId: raw.parentId ?? null,
|
|
770
|
+
threadId: raw.threadId ?? null,
|
|
771
|
+
resolvedAt: raw.resolvedAt ? new Date(raw.resolvedAt) : null
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
function transformComment(comment) {
|
|
775
|
+
const n = normalizeComment(comment);
|
|
776
|
+
const out = {
|
|
777
|
+
id: n.id,
|
|
778
|
+
[n.parentKey]: n.parentId,
|
|
779
|
+
authorId: n.authorId,
|
|
780
|
+
content: n.content,
|
|
781
|
+
author: n.author,
|
|
782
|
+
createdAt: n.createdAt.toISOString(),
|
|
783
|
+
updatedAt: n.updatedAt.toISOString()
|
|
766
784
|
};
|
|
785
|
+
if (n.threadId !== null) out.threadId = n.threadId;
|
|
786
|
+
if (n.parentCommentId !== null && n.parentKey !== "parentId") {
|
|
787
|
+
out.parentCommentId = n.parentCommentId;
|
|
788
|
+
}
|
|
789
|
+
if (n.resolvedAt) out.resolvedAt = n.resolvedAt.toISOString();
|
|
790
|
+
return out;
|
|
767
791
|
}
|
|
768
792
|
function outputCommentJson(comment) {
|
|
769
793
|
console.log(JSON.stringify(transformComment(comment), null, 2));
|
|
770
794
|
}
|
|
771
795
|
function outputCommentPretty(comment) {
|
|
772
|
-
const
|
|
773
|
-
const
|
|
796
|
+
const n = normalizeComment(comment);
|
|
797
|
+
const author = n.author?.name ?? n.authorId;
|
|
798
|
+
const when = formatDate(n.createdAt);
|
|
799
|
+
const badges = [
|
|
800
|
+
n.parentCommentId && n.parentKey !== "parentId" ? chalk3.gray("(reply)") : "",
|
|
801
|
+
n.resolvedAt ? chalk3.green("(resolved)") : ""
|
|
802
|
+
].filter(Boolean).join(" ");
|
|
774
803
|
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
775
|
-
console.log(`${chalk3.bold(author)} ${chalk3.gray(`\u2014 ${when}`)}`);
|
|
776
|
-
console.log(chalk3.gray(` ID: ${
|
|
804
|
+
console.log(`${chalk3.bold(author)} ${chalk3.gray(`\u2014 ${when}`)}${badges ? ` ${badges}` : ""}`);
|
|
805
|
+
console.log(chalk3.gray(` ID: ${n.id}`));
|
|
777
806
|
console.log();
|
|
778
|
-
console.log(
|
|
807
|
+
console.log(n.content);
|
|
779
808
|
console.log();
|
|
780
809
|
}
|
|
781
810
|
function outputCommentsJson(comments) {
|
|
@@ -2235,7 +2264,7 @@ function createEpicsCommand() {
|
|
|
2235
2264
|
}
|
|
2236
2265
|
|
|
2237
2266
|
// src/commands/features.ts
|
|
2238
|
-
import { Command as
|
|
2267
|
+
import { Command as Command11 } from "commander";
|
|
2239
2268
|
|
|
2240
2269
|
// src/commands/stories.ts
|
|
2241
2270
|
import { Command as Command6 } from "commander";
|
|
@@ -2656,6 +2685,240 @@ function createAreasCommand() {
|
|
|
2656
2685
|
return areas;
|
|
2657
2686
|
}
|
|
2658
2687
|
|
|
2688
|
+
// src/commands/featureComments.ts
|
|
2689
|
+
import { Command as Command10 } from "commander";
|
|
2690
|
+
|
|
2691
|
+
// src/utils/mentions.ts
|
|
2692
|
+
function candidateLabels(member) {
|
|
2693
|
+
const labels = [member.id];
|
|
2694
|
+
if (member.name) {
|
|
2695
|
+
labels.push(member.name);
|
|
2696
|
+
const first = member.name.trim().split(/\s+/)[0];
|
|
2697
|
+
if (first) labels.push(first);
|
|
2698
|
+
}
|
|
2699
|
+
if (member.email) {
|
|
2700
|
+
labels.push(member.email);
|
|
2701
|
+
const local = member.email.split("@")[0];
|
|
2702
|
+
if (local) labels.push(local);
|
|
2703
|
+
}
|
|
2704
|
+
return labels;
|
|
2705
|
+
}
|
|
2706
|
+
function describe(member) {
|
|
2707
|
+
return member.name ?? member.email ?? member.id;
|
|
2708
|
+
}
|
|
2709
|
+
function resolveMember(members, token) {
|
|
2710
|
+
const needle = token.trim().toLowerCase().replace(/^@/, "");
|
|
2711
|
+
const exact = members.filter(
|
|
2712
|
+
(m) => m.id.toLowerCase() === needle || m.name?.toLowerCase() === needle || m.email?.toLowerCase() === needle
|
|
2713
|
+
);
|
|
2714
|
+
if (exact.length === 1) return exact[0];
|
|
2715
|
+
if (exact.length > 1) {
|
|
2716
|
+
throw new Error(
|
|
2717
|
+
`"${token}" matches ${exact.length} members. Use a user id instead: ${exact.map((m) => `${describe(m)} (${m.id})`).join(", ")}`
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
const partial = members.filter(
|
|
2721
|
+
(m) => candidateLabels(m).some((l) => l.toLowerCase() === needle)
|
|
2722
|
+
);
|
|
2723
|
+
if (partial.length === 1) return partial[0];
|
|
2724
|
+
if (partial.length > 1) {
|
|
2725
|
+
throw new Error(
|
|
2726
|
+
`"${token}" is ambiguous \u2014 matches ${partial.map((m) => `${describe(m)} (${m.id})`).join(", ")}. Use a full name, email, or user id.`
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
const known = members.map(describe).join(", ");
|
|
2730
|
+
throw new Error(
|
|
2731
|
+
`No workspace member matches "${token}". Members: ${known || "(none)"}. Run \`exponential workspaces members\` to see the roster.`
|
|
2732
|
+
);
|
|
2733
|
+
}
|
|
2734
|
+
function escapeRegExp(value) {
|
|
2735
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2736
|
+
}
|
|
2737
|
+
async function applyMentions(client, workspaceId, body, mentions) {
|
|
2738
|
+
if (!mentions || mentions.length === 0) return body;
|
|
2739
|
+
const members = await client.workspaces.listMembers(workspaceId);
|
|
2740
|
+
let result = body;
|
|
2741
|
+
const prepend = [];
|
|
2742
|
+
for (const token of mentions) {
|
|
2743
|
+
const member = resolveMember(members, token);
|
|
2744
|
+
const handle = token.trim().replace(/^@/, "");
|
|
2745
|
+
const inline = new RegExp(`@${escapeRegExp(handle)}(?![\\w-])`, "gi");
|
|
2746
|
+
const substituted = result.replace(inline, member.mentionSyntax);
|
|
2747
|
+
if (substituted !== result) {
|
|
2748
|
+
result = substituted;
|
|
2749
|
+
} else if (!result.includes(member.mentionSyntax)) {
|
|
2750
|
+
prepend.push(member.mentionSyntax);
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
return prepend.length > 0 ? `${prepend.join(" ")} ${result}` : result;
|
|
2754
|
+
}
|
|
2755
|
+
var MENTION_OPTION_DESCRIPTION = "Mention a workspace member by name, email, or id (repeatable). Writing @name in the message substitutes in place; otherwise the mention is prepended.";
|
|
2756
|
+
function collectMention(value, previous) {
|
|
2757
|
+
return [...previous, value];
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
// src/commands/featureComments.ts
|
|
2761
|
+
function createFeatureCommentsCommand() {
|
|
2762
|
+
const comment = new Command10("comment").description(
|
|
2763
|
+
"Read and post comments on a feature. Mention teammates with --mention."
|
|
2764
|
+
);
|
|
2765
|
+
comment.command("list").description("List comments on a feature").requiredOption("--feature <id>", "Feature ID").action(async (options, cmd) => {
|
|
2766
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2767
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2768
|
+
try {
|
|
2769
|
+
const client = getClient();
|
|
2770
|
+
const comments = await client.featureComments.list(options.feature);
|
|
2771
|
+
if (useJson) outputCommentsJson(comments);
|
|
2772
|
+
else outputCommentsPretty(comments);
|
|
2773
|
+
} catch (error) {
|
|
2774
|
+
handleError(error, useJson);
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
comment.command("add").description("Add a comment to a feature").requiredOption("--feature <id>", "Feature ID").requiredOption("-m, --message <text>", "Comment body (markdown supported)").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
2778
|
+
"--workspace <slug|id>",
|
|
2779
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
2780
|
+
).option("--scope <id>", "Attach to a scope's activity feed instead of the feature").action(
|
|
2781
|
+
async (options, cmd) => {
|
|
2782
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2783
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2784
|
+
try {
|
|
2785
|
+
const client = getClient();
|
|
2786
|
+
const body = options.mention.length > 0 ? await applyMentions(
|
|
2787
|
+
client,
|
|
2788
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
2789
|
+
options.message,
|
|
2790
|
+
options.mention
|
|
2791
|
+
) : options.message;
|
|
2792
|
+
const created = await client.featureComments.create({
|
|
2793
|
+
featureId: options.feature,
|
|
2794
|
+
scopeId: options.scope,
|
|
2795
|
+
body
|
|
2796
|
+
});
|
|
2797
|
+
if (useJson) {
|
|
2798
|
+
outputCommentJson(created);
|
|
2799
|
+
} else {
|
|
2800
|
+
console.log("\n\u2713 Comment added");
|
|
2801
|
+
outputCommentPretty(created);
|
|
2802
|
+
}
|
|
2803
|
+
} catch (error) {
|
|
2804
|
+
handleError(error, useJson);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
);
|
|
2808
|
+
comment.command("reply").description("Reply to a comment on a feature").requiredOption("--comment-id <id>", "Comment ID to reply to").requiredOption("-m, --message <text>", "Reply body (markdown supported)").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
2809
|
+
"--workspace <slug|id>",
|
|
2810
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
2811
|
+
).action(
|
|
2812
|
+
async (options, cmd) => {
|
|
2813
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2814
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2815
|
+
try {
|
|
2816
|
+
const client = getClient();
|
|
2817
|
+
const body = options.mention.length > 0 ? await applyMentions(
|
|
2818
|
+
client,
|
|
2819
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
2820
|
+
options.message,
|
|
2821
|
+
options.mention
|
|
2822
|
+
) : options.message;
|
|
2823
|
+
const created = await client.featureComments.reply({
|
|
2824
|
+
parentId: options.commentId,
|
|
2825
|
+
body
|
|
2826
|
+
});
|
|
2827
|
+
if (useJson) {
|
|
2828
|
+
outputCommentJson(created);
|
|
2829
|
+
} else {
|
|
2830
|
+
console.log("\n\u2713 Reply added");
|
|
2831
|
+
outputCommentPretty(created);
|
|
2832
|
+
}
|
|
2833
|
+
} catch (error) {
|
|
2834
|
+
handleError(error, useJson);
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
);
|
|
2838
|
+
comment.command("update").description("Update one of your own comments").requiredOption("--comment-id <id>", "Comment ID").requiredOption("-m, --message <text>", "New comment body").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
2839
|
+
"--workspace <slug|id>",
|
|
2840
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
2841
|
+
).action(
|
|
2842
|
+
async (options, cmd) => {
|
|
2843
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2844
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2845
|
+
try {
|
|
2846
|
+
const client = getClient();
|
|
2847
|
+
const body = options.mention.length > 0 ? await applyMentions(
|
|
2848
|
+
client,
|
|
2849
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
2850
|
+
options.message,
|
|
2851
|
+
options.mention
|
|
2852
|
+
) : options.message;
|
|
2853
|
+
const updated = await client.featureComments.update({
|
|
2854
|
+
commentId: options.commentId,
|
|
2855
|
+
body
|
|
2856
|
+
});
|
|
2857
|
+
if (useJson) {
|
|
2858
|
+
outputCommentJson(updated);
|
|
2859
|
+
} else {
|
|
2860
|
+
console.log("\n\u2713 Comment updated");
|
|
2861
|
+
outputCommentPretty(updated);
|
|
2862
|
+
}
|
|
2863
|
+
} catch (error) {
|
|
2864
|
+
handleError(error, useJson);
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
);
|
|
2868
|
+
comment.command("rm").description("Delete one of your own comments").requiredOption("--comment-id <id>", "Comment ID").action(async (options, cmd) => {
|
|
2869
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2870
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2871
|
+
try {
|
|
2872
|
+
const client = getClient();
|
|
2873
|
+
await client.featureComments.delete(options.commentId);
|
|
2874
|
+
if (useJson) {
|
|
2875
|
+
console.log(JSON.stringify({ deleted: true, id: options.commentId }, null, 2));
|
|
2876
|
+
} else {
|
|
2877
|
+
console.log("\u2713 Comment deleted");
|
|
2878
|
+
}
|
|
2879
|
+
} catch (error) {
|
|
2880
|
+
handleError(error, useJson);
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
comment.command("resolve").description("Resolve an anchored comment thread").requiredOption("--feature <id>", "Feature ID").requiredOption("--thread <id>", "Thread ID (anchored comments only)").action(async (options, cmd) => {
|
|
2884
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2885
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2886
|
+
try {
|
|
2887
|
+
const client = getClient();
|
|
2888
|
+
await client.featureComments.resolve({
|
|
2889
|
+
featureId: options.feature,
|
|
2890
|
+
threadId: options.thread
|
|
2891
|
+
});
|
|
2892
|
+
if (useJson) {
|
|
2893
|
+
console.log(JSON.stringify({ resolved: true, threadId: options.thread }, null, 2));
|
|
2894
|
+
} else {
|
|
2895
|
+
console.log("\u2713 Thread resolved");
|
|
2896
|
+
}
|
|
2897
|
+
} catch (error) {
|
|
2898
|
+
handleError(error, useJson);
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
comment.command("unresolve").description("Reopen a resolved comment thread").requiredOption("--feature <id>", "Feature ID").requiredOption("--thread <id>", "Thread ID (anchored comments only)").action(async (options, cmd) => {
|
|
2902
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
2903
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
2904
|
+
try {
|
|
2905
|
+
const client = getClient();
|
|
2906
|
+
await client.featureComments.unresolve({
|
|
2907
|
+
featureId: options.feature,
|
|
2908
|
+
threadId: options.thread
|
|
2909
|
+
});
|
|
2910
|
+
if (useJson) {
|
|
2911
|
+
console.log(JSON.stringify({ resolved: false, threadId: options.thread }, null, 2));
|
|
2912
|
+
} else {
|
|
2913
|
+
console.log("\u2713 Thread reopened");
|
|
2914
|
+
}
|
|
2915
|
+
} catch (error) {
|
|
2916
|
+
handleError(error, useJson);
|
|
2917
|
+
}
|
|
2918
|
+
});
|
|
2919
|
+
return comment;
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2659
2922
|
// src/commands/features.ts
|
|
2660
2923
|
var FEATURE_STATUSES = [
|
|
2661
2924
|
"IDEA",
|
|
@@ -2686,7 +2949,7 @@ function validateFeatureStatus(value) {
|
|
|
2686
2949
|
return value;
|
|
2687
2950
|
}
|
|
2688
2951
|
function createFeaturesCommand() {
|
|
2689
|
-
const features = new
|
|
2952
|
+
const features = new Command11("features").description(
|
|
2690
2953
|
"Manage features. A feature lives under a product and groups user stories, scopes, and tickets."
|
|
2691
2954
|
);
|
|
2692
2955
|
features.command("list").description("List features in a product").requiredOption("--product <slug|id>", "Product slug or CUID").option("--workspace <slug|id>", "Workspace (required when --product is a slug)").option("--status <status>", `Filter by status: ${FEATURE_STATUSES.join(", ")}`).action(
|
|
@@ -2934,11 +3197,12 @@ Aborted: ${reason}. Feature "${feature.name}" was NOT deleted.`);
|
|
|
2934
3197
|
features.addCommand(createScopesCommand());
|
|
2935
3198
|
features.addCommand(createRequirementsCommand());
|
|
2936
3199
|
features.addCommand(createAreasCommand());
|
|
3200
|
+
features.addCommand(createFeatureCommentsCommand());
|
|
2937
3201
|
return features;
|
|
2938
3202
|
}
|
|
2939
3203
|
|
|
2940
3204
|
// src/commands/labels.ts
|
|
2941
|
-
import { Command as
|
|
3205
|
+
import { Command as Command12 } from "commander";
|
|
2942
3206
|
import chalk5 from "chalk";
|
|
2943
3207
|
var TRIAGE_LABELS = [
|
|
2944
3208
|
{ slug: "needs-triage", name: "needs-triage", color: "avatar-orange" },
|
|
@@ -2992,7 +3256,7 @@ async function resolveLabelIds(client, workspaceId, values) {
|
|
|
2992
3256
|
return [...byId, ...resolvedFromSlugs];
|
|
2993
3257
|
}
|
|
2994
3258
|
function createLabelsCommand() {
|
|
2995
|
-
const labels = new
|
|
3259
|
+
const labels = new Command12("labels").description(
|
|
2996
3260
|
"Manage labels (orthogonal tags applied to actions, tickets, features, and epics)."
|
|
2997
3261
|
);
|
|
2998
3262
|
labels.command("list").description("List labels visible in a workspace").option("--workspace <slug|id>", "Workspace slug or CUID").option(
|
|
@@ -3095,7 +3359,7 @@ function createLabelsCommand() {
|
|
|
3095
3359
|
}
|
|
3096
3360
|
|
|
3097
3361
|
// src/commands/organizations.ts
|
|
3098
|
-
import { Command as
|
|
3362
|
+
import { Command as Command13 } from "commander";
|
|
3099
3363
|
var VALID_SIZES = [
|
|
3100
3364
|
"1-10",
|
|
3101
3365
|
"11-50",
|
|
@@ -3105,7 +3369,7 @@ var VALID_SIZES = [
|
|
|
3105
3369
|
"1000+"
|
|
3106
3370
|
];
|
|
3107
3371
|
function createOrganizationsCommand() {
|
|
3108
|
-
const organizations = new
|
|
3372
|
+
const organizations = new Command13("organizations").alias("orgs").description("Manage CRM organizations");
|
|
3109
3373
|
organizations.command("list").description("List organizations").requiredOption("--workspace <id>", "Workspace ID").option("--search <query>", "Search by name or description").option("--industry <industry>", "Filter by industry").option("--limit <n>", "Max results to return", parseInt).option("--cursor <cursor>", "Pagination cursor").action(async (options, cmd) => {
|
|
3110
3374
|
const globalOpts = cmd.optsWithGlobals();
|
|
3111
3375
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -3174,7 +3438,105 @@ function createOrganizationsCommand() {
|
|
|
3174
3438
|
|
|
3175
3439
|
// src/commands/pages.ts
|
|
3176
3440
|
import { readFileSync } from "fs";
|
|
3177
|
-
import { Command as
|
|
3441
|
+
import { Command as Command15 } from "commander";
|
|
3442
|
+
|
|
3443
|
+
// src/commands/pageComments.ts
|
|
3444
|
+
import { Command as Command14 } from "commander";
|
|
3445
|
+
function createPageCommentsCommand() {
|
|
3446
|
+
const comment = new Command14("comment").description(
|
|
3447
|
+
"Read and post comments on a page. Mention teammates with --mention."
|
|
3448
|
+
);
|
|
3449
|
+
comment.command("list").description("List comments on a page").requiredOption("--page <id>", "Page ID").action(async (options, cmd) => {
|
|
3450
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3451
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3452
|
+
try {
|
|
3453
|
+
const client = getClient();
|
|
3454
|
+
const comments = await client.pageComments.list(options.page);
|
|
3455
|
+
if (useJson) outputCommentsJson(comments);
|
|
3456
|
+
else outputCommentsPretty(comments);
|
|
3457
|
+
} catch (error) {
|
|
3458
|
+
handleError(error, useJson);
|
|
3459
|
+
}
|
|
3460
|
+
});
|
|
3461
|
+
comment.command("add").description("Add a comment to a page").requiredOption("--page <id>", "Page ID").requiredOption("-m, --message <text>", "Comment body (markdown supported)").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
3462
|
+
"--workspace <slug|id>",
|
|
3463
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
3464
|
+
).action(
|
|
3465
|
+
async (options, cmd) => {
|
|
3466
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3467
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3468
|
+
try {
|
|
3469
|
+
const client = getClient();
|
|
3470
|
+
const body = options.mention.length > 0 ? await applyMentions(
|
|
3471
|
+
client,
|
|
3472
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
3473
|
+
options.message,
|
|
3474
|
+
options.mention
|
|
3475
|
+
) : options.message;
|
|
3476
|
+
const created = await client.pageComments.create({
|
|
3477
|
+
pageId: options.page,
|
|
3478
|
+
body
|
|
3479
|
+
});
|
|
3480
|
+
if (useJson) {
|
|
3481
|
+
outputCommentJson(created);
|
|
3482
|
+
} else {
|
|
3483
|
+
console.log("\n\u2713 Comment added");
|
|
3484
|
+
outputCommentPretty(created);
|
|
3485
|
+
}
|
|
3486
|
+
} catch (error) {
|
|
3487
|
+
handleError(error, useJson);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
);
|
|
3491
|
+
comment.command("update").description("Update one of your own comments").requiredOption("--comment-id <id>", "Comment ID").requiredOption("-m, --message <text>", "New comment body").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
3492
|
+
"--workspace <slug|id>",
|
|
3493
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
3494
|
+
).action(
|
|
3495
|
+
async (options, cmd) => {
|
|
3496
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3497
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3498
|
+
try {
|
|
3499
|
+
const client = getClient();
|
|
3500
|
+
const body = options.mention.length > 0 ? await applyMentions(
|
|
3501
|
+
client,
|
|
3502
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
3503
|
+
options.message,
|
|
3504
|
+
options.mention
|
|
3505
|
+
) : options.message;
|
|
3506
|
+
const updated = await client.pageComments.update({
|
|
3507
|
+
commentId: options.commentId,
|
|
3508
|
+
body
|
|
3509
|
+
});
|
|
3510
|
+
if (useJson) {
|
|
3511
|
+
outputCommentJson(updated);
|
|
3512
|
+
} else {
|
|
3513
|
+
console.log("\n\u2713 Comment updated");
|
|
3514
|
+
outputCommentPretty(updated);
|
|
3515
|
+
}
|
|
3516
|
+
} catch (error) {
|
|
3517
|
+
handleError(error, useJson);
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
);
|
|
3521
|
+
comment.command("rm").description("Delete one of your own comments").requiredOption("--comment-id <id>", "Comment ID").action(async (options, cmd) => {
|
|
3522
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3523
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3524
|
+
try {
|
|
3525
|
+
const client = getClient();
|
|
3526
|
+
await client.pageComments.delete(options.commentId);
|
|
3527
|
+
if (useJson) {
|
|
3528
|
+
console.log(JSON.stringify({ deleted: true, id: options.commentId }, null, 2));
|
|
3529
|
+
} else {
|
|
3530
|
+
console.log("\u2713 Comment deleted");
|
|
3531
|
+
}
|
|
3532
|
+
} catch (error) {
|
|
3533
|
+
handleError(error, useJson);
|
|
3534
|
+
}
|
|
3535
|
+
});
|
|
3536
|
+
return comment;
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
// src/commands/pages.ts
|
|
3178
3540
|
function readBody(body, bodyFile) {
|
|
3179
3541
|
if (body !== void 0) return body;
|
|
3180
3542
|
if (bodyFile === void 0) return void 0;
|
|
@@ -3182,7 +3544,7 @@ function readBody(body, bodyFile) {
|
|
|
3182
3544
|
return readFileSync(bodyFile, "utf-8");
|
|
3183
3545
|
}
|
|
3184
3546
|
function createPagesCommand() {
|
|
3185
|
-
const pages = new
|
|
3547
|
+
const pages = new Command15("pages").description(
|
|
3186
3548
|
'Manage Knowledge pages (PRDs, research, technical specs). Link one to a feature with "features link-page".'
|
|
3187
3549
|
);
|
|
3188
3550
|
pages.command("list").description("List pages in a workspace").option("--workspace <slug|id>", "Workspace (defaults to the configured default)").option("--search <text>", "Filter by title/content").action(
|
|
@@ -3260,13 +3622,14 @@ function createPagesCommand() {
|
|
|
3260
3622
|
}
|
|
3261
3623
|
}
|
|
3262
3624
|
);
|
|
3625
|
+
pages.addCommand(createPageCommentsCommand());
|
|
3263
3626
|
return pages;
|
|
3264
3627
|
}
|
|
3265
3628
|
|
|
3266
3629
|
// src/commands/products.ts
|
|
3267
|
-
import { Command as
|
|
3630
|
+
import { Command as Command16 } from "commander";
|
|
3268
3631
|
function createProductsCommand() {
|
|
3269
|
-
const products = new
|
|
3632
|
+
const products = new Command16("products").description(
|
|
3270
3633
|
"Manage products. A workspace contains products; a product holds features and tickets."
|
|
3271
3634
|
);
|
|
3272
3635
|
products.command("list").description("List products in a workspace").option("--workspace <slug|id>", "Workspace slug or CUID (defaults to configured workspace)").action(async (options, cmd) => {
|
|
@@ -3329,9 +3692,9 @@ function createProductsCommand() {
|
|
|
3329
3692
|
}
|
|
3330
3693
|
|
|
3331
3694
|
// src/commands/projects.ts
|
|
3332
|
-
import { Command as
|
|
3695
|
+
import { Command as Command17 } from "commander";
|
|
3333
3696
|
function createProjectsCommand() {
|
|
3334
|
-
const projects = new
|
|
3697
|
+
const projects = new Command17("projects").description("Manage projects");
|
|
3335
3698
|
projects.command("list").description("List all projects").option("--workspace <id>", "Filter by workspace ID").option("--include-actions", "Include actions in output").action(async (options, cmd) => {
|
|
3336
3699
|
const globalOpts = cmd.optsWithGlobals();
|
|
3337
3700
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -3354,7 +3717,7 @@ function createProjectsCommand() {
|
|
|
3354
3717
|
}
|
|
3355
3718
|
|
|
3356
3719
|
// src/commands/search.ts
|
|
3357
|
-
import { Command as
|
|
3720
|
+
import { Command as Command18 } from "commander";
|
|
3358
3721
|
import chalk6 from "chalk";
|
|
3359
3722
|
var TYPE_LABELS = {
|
|
3360
3723
|
workspace: "Workspaces",
|
|
@@ -3373,7 +3736,7 @@ var TYPE_LABELS = {
|
|
|
3373
3736
|
product: "Products"
|
|
3374
3737
|
};
|
|
3375
3738
|
function createSearchCommand() {
|
|
3376
|
-
const search = new
|
|
3739
|
+
const search = new Command18("search").description(
|
|
3377
3740
|
"Global search across projects, actions, goals, workspaces and more \u2014 same coverage as the app's Cmd+K palette"
|
|
3378
3741
|
).argument("<query>", "Text to search for").option("-w, --workspace <slug>", "Restrict results to one workspace (slug or ID)").option("-l, --limit <n>", "Max results per entity type (1-25, default 10)").action(async (query, options, cmd) => {
|
|
3379
3742
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -3432,7 +3795,7 @@ ${TYPE_LABELS[type] ?? type}`));
|
|
|
3432
3795
|
}
|
|
3433
3796
|
|
|
3434
3797
|
// src/commands/tickets.ts
|
|
3435
|
-
import { Command as
|
|
3798
|
+
import { Command as Command19 } from "commander";
|
|
3436
3799
|
function collectRepeatable(value, previous) {
|
|
3437
3800
|
return [...previous, value];
|
|
3438
3801
|
}
|
|
@@ -3475,7 +3838,7 @@ function validateTicketType(value) {
|
|
|
3475
3838
|
return value;
|
|
3476
3839
|
}
|
|
3477
3840
|
function createTicketsCommand() {
|
|
3478
|
-
const tickets = new
|
|
3841
|
+
const tickets = new Command19("tickets").description(
|
|
3479
3842
|
"Manage product backlog tickets. Tickets live under a product, link to features/epics, depend on each other, and can be implemented via actions."
|
|
3480
3843
|
);
|
|
3481
3844
|
tickets.command("list").description(
|
|
@@ -3789,25 +4152,78 @@ function createTicketsCommand() {
|
|
|
3789
4152
|
handleError(error, useJson);
|
|
3790
4153
|
}
|
|
3791
4154
|
});
|
|
3792
|
-
const comment = new
|
|
3793
|
-
comment.command("
|
|
4155
|
+
const comment = new Command19("comment").description("Manage comments on a ticket");
|
|
4156
|
+
comment.command("list").description("List comments on a ticket").requiredOption("--id <id>", "Ticket CUID").action(async (options, cmd) => {
|
|
3794
4157
|
const globalOpts = cmd.optsWithGlobals();
|
|
3795
4158
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3796
4159
|
try {
|
|
3797
4160
|
const client = getClient();
|
|
3798
|
-
const
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
if (useJson) outputCommentJson(created);
|
|
3803
|
-
else {
|
|
3804
|
-
console.log("\n\u2713 Comment added");
|
|
3805
|
-
outputCommentPretty(created);
|
|
3806
|
-
}
|
|
4161
|
+
const ticket = await client.tickets.get(options.id);
|
|
4162
|
+
const comments = ticket.comments ?? [];
|
|
4163
|
+
if (useJson) outputCommentsJson(comments);
|
|
4164
|
+
else outputCommentsPretty(comments);
|
|
3807
4165
|
} catch (error) {
|
|
3808
4166
|
handleError(error, useJson);
|
|
3809
4167
|
}
|
|
3810
4168
|
});
|
|
4169
|
+
comment.command("add").description("Add a comment to a ticket").requiredOption("--id <id>", "Ticket CUID").requiredOption("-m, --message <text>", "Comment content (markdown supported)").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
4170
|
+
"--workspace <slug|id>",
|
|
4171
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
4172
|
+
).action(
|
|
4173
|
+
async (options, cmd) => {
|
|
4174
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4175
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4176
|
+
try {
|
|
4177
|
+
const client = getClient();
|
|
4178
|
+
const content = options.mention.length > 0 ? await applyMentions(
|
|
4179
|
+
client,
|
|
4180
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
4181
|
+
options.message,
|
|
4182
|
+
options.mention
|
|
4183
|
+
) : options.message;
|
|
4184
|
+
const created = await client.tickets.addComment({
|
|
4185
|
+
ticketId: options.id,
|
|
4186
|
+
content
|
|
4187
|
+
});
|
|
4188
|
+
if (useJson) outputCommentJson(created);
|
|
4189
|
+
else {
|
|
4190
|
+
console.log("\n\u2713 Comment added");
|
|
4191
|
+
outputCommentPretty(created);
|
|
4192
|
+
}
|
|
4193
|
+
} catch (error) {
|
|
4194
|
+
handleError(error, useJson);
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
);
|
|
4198
|
+
comment.command("update").description("Update one of your own ticket comments").requiredOption("--comment-id <id>", "Comment ID").requiredOption("-m, --message <text>", "New comment content").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
4199
|
+
"--workspace <slug|id>",
|
|
4200
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
4201
|
+
).action(
|
|
4202
|
+
async (options, cmd) => {
|
|
4203
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4204
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4205
|
+
try {
|
|
4206
|
+
const client = getClient();
|
|
4207
|
+
const content = options.mention.length > 0 ? await applyMentions(
|
|
4208
|
+
client,
|
|
4209
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
4210
|
+
options.message,
|
|
4211
|
+
options.mention
|
|
4212
|
+
) : options.message;
|
|
4213
|
+
const updated = await client.tickets.updateComment({
|
|
4214
|
+
id: options.commentId,
|
|
4215
|
+
content
|
|
4216
|
+
});
|
|
4217
|
+
if (useJson) outputCommentJson(updated);
|
|
4218
|
+
else {
|
|
4219
|
+
console.log("\n\u2713 Comment updated");
|
|
4220
|
+
outputCommentPretty(updated);
|
|
4221
|
+
}
|
|
4222
|
+
} catch (error) {
|
|
4223
|
+
handleError(error, useJson);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
);
|
|
3811
4227
|
comment.command("delete").description("Delete one of your own ticket comments").requiredOption("--comment-id <id>", "Comment ID").action(async (options, cmd) => {
|
|
3812
4228
|
const globalOpts = cmd.optsWithGlobals();
|
|
3813
4229
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -3828,10 +4244,10 @@ function createTicketsCommand() {
|
|
|
3828
4244
|
}
|
|
3829
4245
|
|
|
3830
4246
|
// src/commands/workspaces.ts
|
|
3831
|
-
import { Command as
|
|
4247
|
+
import { Command as Command20 } from "commander";
|
|
3832
4248
|
import chalk7 from "chalk";
|
|
3833
4249
|
function createWorkspacesCommand() {
|
|
3834
|
-
const workspaces = new
|
|
4250
|
+
const workspaces = new Command20("workspaces").description("Manage workspaces");
|
|
3835
4251
|
workspaces.command("list").description("List all workspaces").action(async (_options, cmd) => {
|
|
3836
4252
|
const globalOpts = cmd.optsWithGlobals();
|
|
3837
4253
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -3873,11 +4289,172 @@ function createWorkspacesCommand() {
|
|
|
3873
4289
|
handleError(error);
|
|
3874
4290
|
}
|
|
3875
4291
|
});
|
|
4292
|
+
workspaces.command("members").description(
|
|
4293
|
+
"List workspace members. Each row carries the exact @[Name](id) markup to paste into a comment to mention that person."
|
|
4294
|
+
).option("--workspace <slug|id>", "Workspace (defaults to your default workspace)").option("--search <text>", "Filter by name or email").action(
|
|
4295
|
+
async (options, cmd) => {
|
|
4296
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4297
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4298
|
+
try {
|
|
4299
|
+
const client = getClient();
|
|
4300
|
+
const workspaceId = await resolveWorkspaceId(client, options.workspace);
|
|
4301
|
+
let members = await client.workspaces.listMembers(workspaceId);
|
|
4302
|
+
if (options.search) {
|
|
4303
|
+
const needle = options.search.toLowerCase();
|
|
4304
|
+
members = members.filter(
|
|
4305
|
+
(m) => m.name?.toLowerCase().includes(needle) || m.email?.toLowerCase().includes(needle)
|
|
4306
|
+
);
|
|
4307
|
+
}
|
|
4308
|
+
if (useJson) {
|
|
4309
|
+
console.log(
|
|
4310
|
+
JSON.stringify({ members, total: members.length }, null, 2)
|
|
4311
|
+
);
|
|
4312
|
+
return;
|
|
4313
|
+
}
|
|
4314
|
+
if (members.length === 0) {
|
|
4315
|
+
console.log(chalk7.gray("No members found."));
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
console.log(chalk7.bold(`
|
|
4319
|
+
Members (${members.length})
|
|
4320
|
+
`));
|
|
4321
|
+
for (const m of members) {
|
|
4322
|
+
const label = m.name ?? m.email ?? m.id;
|
|
4323
|
+
const via = m.source === "team" ? chalk7.gray(
|
|
4324
|
+
` via team${m.teams.length ? `: ${m.teams.map((t) => t.name).join(", ")}` : ""}` + (m.teamRole ? ` [team ${m.teamRole}]` : "")
|
|
4325
|
+
) : "";
|
|
4326
|
+
console.log(`${chalk7.bold(label)} ${chalk7.gray(`(${m.role})`)}${via}`);
|
|
4327
|
+
if (m.email) console.log(chalk7.gray(` ${m.email}`));
|
|
4328
|
+
console.log(chalk7.gray(` mention: ${m.mentionSyntax}`));
|
|
4329
|
+
console.log();
|
|
4330
|
+
}
|
|
4331
|
+
} catch (error) {
|
|
4332
|
+
handleError(error, useJson);
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
);
|
|
3876
4336
|
return workspaces;
|
|
3877
4337
|
}
|
|
3878
4338
|
|
|
4339
|
+
// src/commands/goals.ts
|
|
4340
|
+
import { Command as Command21 } from "commander";
|
|
4341
|
+
function parseGoalId(value) {
|
|
4342
|
+
const id = Number(value);
|
|
4343
|
+
if (!Number.isInteger(id)) {
|
|
4344
|
+
throw new Error(
|
|
4345
|
+
`Goal id must be a whole number, got "${value}". Find one with \`exponential search "<goal title>"\`.`
|
|
4346
|
+
);
|
|
4347
|
+
}
|
|
4348
|
+
return id;
|
|
4349
|
+
}
|
|
4350
|
+
function createGoalsCommand() {
|
|
4351
|
+
const goals = new Command21("goals").description(
|
|
4352
|
+
'Work with goals. Find goal ids with `exponential search "<title>"`.'
|
|
4353
|
+
);
|
|
4354
|
+
const comment = new Command21("comment").description(
|
|
4355
|
+
"Read and post comments on a goal. Mention teammates with --mention."
|
|
4356
|
+
);
|
|
4357
|
+
comment.command("list").description("List comments on a goal").requiredOption("--goal <id>", "Goal ID (a number)").action(async (options, cmd) => {
|
|
4358
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4359
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4360
|
+
try {
|
|
4361
|
+
const client = getClient();
|
|
4362
|
+
const comments = await client.goalComments.list(parseGoalId(options.goal));
|
|
4363
|
+
if (useJson) outputCommentsJson(comments);
|
|
4364
|
+
else outputCommentsPretty(comments);
|
|
4365
|
+
} catch (error) {
|
|
4366
|
+
handleError(error, useJson);
|
|
4367
|
+
}
|
|
4368
|
+
});
|
|
4369
|
+
comment.command("add").description("Add a comment to a goal").requiredOption("--goal <id>", "Goal ID (a number)").requiredOption("-m, --message <text>", "Comment content (markdown supported)").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
4370
|
+
"--workspace <slug|id>",
|
|
4371
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
4372
|
+
).option("--parent-update <id>", "Thread under a specific goal update").action(
|
|
4373
|
+
async (options, cmd) => {
|
|
4374
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4375
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4376
|
+
try {
|
|
4377
|
+
const client = getClient();
|
|
4378
|
+
const goalId = parseGoalId(options.goal);
|
|
4379
|
+
const content = options.mention.length > 0 ? await applyMentions(
|
|
4380
|
+
client,
|
|
4381
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
4382
|
+
options.message,
|
|
4383
|
+
options.mention
|
|
4384
|
+
) : options.message;
|
|
4385
|
+
const created = await client.goalComments.add({
|
|
4386
|
+
goalId,
|
|
4387
|
+
content,
|
|
4388
|
+
parentUpdateId: options.parentUpdate
|
|
4389
|
+
});
|
|
4390
|
+
if (useJson) {
|
|
4391
|
+
outputCommentJson(created);
|
|
4392
|
+
} else {
|
|
4393
|
+
console.log("\n\u2713 Comment added");
|
|
4394
|
+
outputCommentPretty(created);
|
|
4395
|
+
}
|
|
4396
|
+
} catch (error) {
|
|
4397
|
+
handleError(error, useJson);
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
);
|
|
4401
|
+
comment.command("update").description("Update one of your own comments").requiredOption("--comment-id <id>", "Comment ID").requiredOption("-m, --message <text>", "New comment content").option("--mention <name>", MENTION_OPTION_DESCRIPTION, collectMention, []).option(
|
|
4402
|
+
"--workspace <slug|id>",
|
|
4403
|
+
"Workspace used to resolve --mention (defaults to your default workspace)"
|
|
4404
|
+
).action(
|
|
4405
|
+
async (options, cmd) => {
|
|
4406
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4407
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4408
|
+
try {
|
|
4409
|
+
const client = getClient();
|
|
4410
|
+
const content = options.mention.length > 0 ? await applyMentions(
|
|
4411
|
+
client,
|
|
4412
|
+
await resolveWorkspaceId(client, options.workspace),
|
|
4413
|
+
options.message,
|
|
4414
|
+
options.mention
|
|
4415
|
+
) : options.message;
|
|
4416
|
+
const updated = await client.goalComments.update({
|
|
4417
|
+
commentId: options.commentId,
|
|
4418
|
+
content
|
|
4419
|
+
});
|
|
4420
|
+
if (useJson) {
|
|
4421
|
+
outputCommentJson(updated);
|
|
4422
|
+
} else {
|
|
4423
|
+
console.log("\n\u2713 Comment updated");
|
|
4424
|
+
outputCommentPretty(updated);
|
|
4425
|
+
}
|
|
4426
|
+
} catch (error) {
|
|
4427
|
+
handleError(error, useJson);
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
);
|
|
4431
|
+
comment.command("rm").description("Delete one of your own comments").requiredOption("--comment-id <id>", "Comment ID").action(async (options, cmd) => {
|
|
4432
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4433
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4434
|
+
try {
|
|
4435
|
+
const client = getClient();
|
|
4436
|
+
await client.goalComments.delete(options.commentId);
|
|
4437
|
+
if (useJson) {
|
|
4438
|
+
console.log(JSON.stringify({ deleted: true, id: options.commentId }, null, 2));
|
|
4439
|
+
} else {
|
|
4440
|
+
console.log("\u2713 Comment deleted");
|
|
4441
|
+
}
|
|
4442
|
+
} catch (error) {
|
|
4443
|
+
handleError(error, useJson);
|
|
4444
|
+
}
|
|
4445
|
+
});
|
|
4446
|
+
goals.addCommand(comment);
|
|
4447
|
+
return goals;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
3879
4450
|
// src/index.ts
|
|
3880
|
-
|
|
4451
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
4452
|
+
import { dirname, join } from "path";
|
|
4453
|
+
import { fileURLToPath } from "url";
|
|
4454
|
+
var PKG_VERSION = JSON.parse(
|
|
4455
|
+
readFileSync2(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8")
|
|
4456
|
+
).version;
|
|
4457
|
+
var program = new Command22();
|
|
3881
4458
|
program.name("exponential").description(
|
|
3882
4459
|
[
|
|
3883
4460
|
"CLI to interact with Exponential productivity app.",
|
|
@@ -3886,7 +4463,7 @@ program.name("exponential").description(
|
|
|
3886
4463
|
" workspace -> product -> feature -> ticket -> action",
|
|
3887
4464
|
" epics are workspace-scoped and can group tickets and actions across products."
|
|
3888
4465
|
].join("\n")
|
|
3889
|
-
).version(
|
|
4466
|
+
).version(PKG_VERSION).option("--json", "Output as JSON (default when piped)").option("--pretty", "Force pretty-printed output");
|
|
3890
4467
|
program.addCommand(createAuthCommand());
|
|
3891
4468
|
program.addCommand(createActionsCommand());
|
|
3892
4469
|
program.addCommand(createContactsCommand());
|
|
@@ -3901,5 +4478,6 @@ program.addCommand(createProjectsCommand());
|
|
|
3901
4478
|
program.addCommand(createSearchCommand());
|
|
3902
4479
|
program.addCommand(createTicketsCommand());
|
|
3903
4480
|
program.addCommand(createWorkspacesCommand());
|
|
4481
|
+
program.addCommand(createGoalsCommand());
|
|
3904
4482
|
program.parse();
|
|
3905
4483
|
//# sourceMappingURL=index.js.map
|