exponential-cli 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +246 -22
- 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 Command12 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -1882,10 +1882,167 @@ function createFeaturesCommand() {
|
|
|
1882
1882
|
return features;
|
|
1883
1883
|
}
|
|
1884
1884
|
|
|
1885
|
-
// src/commands/
|
|
1885
|
+
// src/commands/labels.ts
|
|
1886
1886
|
import { Command as Command7 } from "commander";
|
|
1887
|
+
import chalk4 from "chalk";
|
|
1888
|
+
var TRIAGE_LABELS = [
|
|
1889
|
+
{ slug: "needs-triage", name: "needs-triage", color: "avatar-orange" },
|
|
1890
|
+
{ slug: "needs-info", name: "needs-info", color: "avatar-yellow" },
|
|
1891
|
+
{ slug: "ready-for-agent", name: "ready-for-agent", color: "avatar-green" },
|
|
1892
|
+
{ slug: "ready-for-human", name: "ready-for-human", color: "avatar-lightBlue" },
|
|
1893
|
+
{ slug: "wontfix", name: "wontfix", color: "avatar-lightGray" }
|
|
1894
|
+
];
|
|
1895
|
+
var CUID_PATTERN = /^c[a-z0-9]{20,}$/i;
|
|
1896
|
+
function looksLikeCuid(value) {
|
|
1897
|
+
return CUID_PATTERN.test(value);
|
|
1898
|
+
}
|
|
1899
|
+
function outputTagsPretty(tags) {
|
|
1900
|
+
if (tags.length === 0) {
|
|
1901
|
+
console.log(chalk4.dim("No labels found."));
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
console.log();
|
|
1905
|
+
for (const tag of tags) {
|
|
1906
|
+
const scope = tag.workspaceId === null ? chalk4.cyan("global") : chalk4.magenta("workspace");
|
|
1907
|
+
const category = tag.category === null ? chalk4.dim("(label)") : chalk4.dim(`(${tag.category})`);
|
|
1908
|
+
console.log(
|
|
1909
|
+
` ${chalk4.bold(tag.slug)} ${tag.name} ${chalk4.gray(tag.color)} ${scope} ${category}`
|
|
1910
|
+
);
|
|
1911
|
+
}
|
|
1912
|
+
console.log();
|
|
1913
|
+
}
|
|
1914
|
+
function outputTagPretty(tag, prefix) {
|
|
1915
|
+
if (prefix) console.log(prefix);
|
|
1916
|
+
console.log(` ${chalk4.bold(tag.slug)} ${tag.name} ${chalk4.gray(tag.color)}`);
|
|
1917
|
+
}
|
|
1918
|
+
async function resolveLabelIds(client, workspaceId, values) {
|
|
1919
|
+
if (values.length === 0) return [];
|
|
1920
|
+
const bySlug = values.filter((v) => !looksLikeCuid(v));
|
|
1921
|
+
const byId = values.filter((v) => looksLikeCuid(v));
|
|
1922
|
+
if (bySlug.length === 0) return byId;
|
|
1923
|
+
const list = await client.labels.list({ workspaceId });
|
|
1924
|
+
const slugMap = new Map(list.allTags.map((t) => [t.slug, t.id]));
|
|
1925
|
+
const resolvedFromSlugs = [];
|
|
1926
|
+
const missing = [];
|
|
1927
|
+
for (const slug of bySlug) {
|
|
1928
|
+
const id = slugMap.get(slug);
|
|
1929
|
+
if (id === void 0) missing.push(slug);
|
|
1930
|
+
else resolvedFromSlugs.push(id);
|
|
1931
|
+
}
|
|
1932
|
+
if (missing.length > 0) {
|
|
1933
|
+
throw new Error(
|
|
1934
|
+
`Unknown label slug(s): ${missing.join(", ")}. Run \`exponential labels list --workspace <slug>\` to see available labels.`
|
|
1935
|
+
);
|
|
1936
|
+
}
|
|
1937
|
+
return [...byId, ...resolvedFromSlugs];
|
|
1938
|
+
}
|
|
1939
|
+
function createLabelsCommand() {
|
|
1940
|
+
const labels = new Command7("labels").description(
|
|
1941
|
+
"Manage labels (orthogonal tags applied to actions, tickets, features, and epics)."
|
|
1942
|
+
);
|
|
1943
|
+
labels.command("list").description("List labels visible in a workspace").option("--workspace <slug|id>", "Workspace slug or CUID").option(
|
|
1944
|
+
"--category <category>",
|
|
1945
|
+
'Filter by category. Use "label" for general labels, "null" for category-less labels, or omit to list all.'
|
|
1946
|
+
).action(
|
|
1947
|
+
async (options, cmd) => {
|
|
1948
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1949
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1950
|
+
try {
|
|
1951
|
+
const client = getClient();
|
|
1952
|
+
const workspaceId = await resolveWorkspaceId(client, options.workspace);
|
|
1953
|
+
const category = options.category === void 0 ? void 0 : options.category === "null" ? null : options.category;
|
|
1954
|
+
const result = await client.labels.list({ workspaceId, category });
|
|
1955
|
+
if (useJson) {
|
|
1956
|
+
console.log(JSON.stringify(result.allTags, null, 2));
|
|
1957
|
+
} else {
|
|
1958
|
+
outputTagsPretty(result.allTags);
|
|
1959
|
+
}
|
|
1960
|
+
} catch (error) {
|
|
1961
|
+
handleError(error, useJson);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
);
|
|
1965
|
+
labels.command("create").description("Create a workspace-scoped label").requiredOption("-n, --name <name>", "Label name").requiredOption("--color <token>", "Color token (e.g. avatar-green, brand-primary)").option("-d, --description <text>", "Description").option("--category <category>", 'Category. Omit (or pass "null") to create a general label.').option("--workspace <slug|id>", "Workspace slug or CUID").action(
|
|
1966
|
+
async (options, cmd) => {
|
|
1967
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1968
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1969
|
+
try {
|
|
1970
|
+
const client = getClient();
|
|
1971
|
+
const workspaceId = await resolveWorkspaceId(client, options.workspace);
|
|
1972
|
+
if (workspaceId === void 0) {
|
|
1973
|
+
throw new Error(
|
|
1974
|
+
"Workspace is required. Pass --workspace <slug|id> or set a default with `exponential workspaces set-default`."
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
const category = options.category === void 0 ? void 0 : options.category === "null" ? null : options.category;
|
|
1978
|
+
const tag = await client.labels.create({
|
|
1979
|
+
workspaceId,
|
|
1980
|
+
name: options.name,
|
|
1981
|
+
color: options.color,
|
|
1982
|
+
description: options.description,
|
|
1983
|
+
category
|
|
1984
|
+
});
|
|
1985
|
+
if (useJson) {
|
|
1986
|
+
console.log(JSON.stringify(tag, null, 2));
|
|
1987
|
+
} else {
|
|
1988
|
+
outputTagPretty(tag, chalk4.green("\n\u2713 Label created"));
|
|
1989
|
+
}
|
|
1990
|
+
} catch (error) {
|
|
1991
|
+
handleError(error, useJson);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
);
|
|
1995
|
+
labels.command("seed-triage").description("Idempotently seed the five canonical triage labels into a workspace.").option("--workspace <slug|id>", "Workspace slug or CUID").action(
|
|
1996
|
+
async (options, cmd) => {
|
|
1997
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1998
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
1999
|
+
try {
|
|
2000
|
+
const client = getClient();
|
|
2001
|
+
const workspaceId = await resolveWorkspaceId(client, options.workspace);
|
|
2002
|
+
if (workspaceId === void 0) {
|
|
2003
|
+
throw new Error(
|
|
2004
|
+
"Workspace is required. Pass --workspace <slug|id> or set a default with `exponential workspaces set-default`."
|
|
2005
|
+
);
|
|
2006
|
+
}
|
|
2007
|
+
const existing = await client.labels.list({ workspaceId });
|
|
2008
|
+
const existingSlugs = new Set(existing.allTags.map((t) => t.slug));
|
|
2009
|
+
const results = [];
|
|
2010
|
+
for (const def of TRIAGE_LABELS) {
|
|
2011
|
+
if (existingSlugs.has(def.slug)) {
|
|
2012
|
+
results.push({ slug: def.slug, status: "existed" });
|
|
2013
|
+
continue;
|
|
2014
|
+
}
|
|
2015
|
+
const tag = await client.labels.create({
|
|
2016
|
+
workspaceId,
|
|
2017
|
+
name: def.name,
|
|
2018
|
+
color: def.color
|
|
2019
|
+
});
|
|
2020
|
+
results.push({ slug: def.slug, status: "created", tag });
|
|
2021
|
+
}
|
|
2022
|
+
if (useJson) {
|
|
2023
|
+
console.log(JSON.stringify(results, null, 2));
|
|
2024
|
+
} else {
|
|
2025
|
+
console.log();
|
|
2026
|
+
console.log(chalk4.bold("Triage labels:"));
|
|
2027
|
+
for (const r of results) {
|
|
2028
|
+
const tag = chalk4.bold(r.slug);
|
|
2029
|
+
const status = r.status === "created" ? chalk4.green("created") : chalk4.dim("existed");
|
|
2030
|
+
console.log(` ${tag} ${status}`);
|
|
2031
|
+
}
|
|
2032
|
+
console.log();
|
|
2033
|
+
}
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
handleError(error, useJson);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
);
|
|
2039
|
+
return labels;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
// src/commands/products.ts
|
|
2043
|
+
import { Command as Command8 } from "commander";
|
|
1887
2044
|
function createProductsCommand() {
|
|
1888
|
-
const products = new
|
|
2045
|
+
const products = new Command8("products").description(
|
|
1889
2046
|
"Manage products. A workspace contains products; a product holds features and tickets."
|
|
1890
2047
|
);
|
|
1891
2048
|
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) => {
|
|
@@ -1948,9 +2105,9 @@ function createProductsCommand() {
|
|
|
1948
2105
|
}
|
|
1949
2106
|
|
|
1950
2107
|
// src/commands/projects.ts
|
|
1951
|
-
import { Command as
|
|
2108
|
+
import { Command as Command9 } from "commander";
|
|
1952
2109
|
function createProjectsCommand() {
|
|
1953
|
-
const projects = new
|
|
2110
|
+
const projects = new Command9("projects").description("Manage projects");
|
|
1954
2111
|
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) => {
|
|
1955
2112
|
const globalOpts = cmd.optsWithGlobals();
|
|
1956
2113
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -1973,7 +2130,10 @@ function createProjectsCommand() {
|
|
|
1973
2130
|
}
|
|
1974
2131
|
|
|
1975
2132
|
// src/commands/tickets.ts
|
|
1976
|
-
import { Command as
|
|
2133
|
+
import { Command as Command10 } from "commander";
|
|
2134
|
+
function collectRepeatable(value, previous) {
|
|
2135
|
+
return [...previous, value];
|
|
2136
|
+
}
|
|
1977
2137
|
var TICKET_STATUSES = [
|
|
1978
2138
|
"BACKLOG",
|
|
1979
2139
|
"NEEDS_REFINEMENT",
|
|
@@ -2013,10 +2173,15 @@ function validateTicketType(value) {
|
|
|
2013
2173
|
return value;
|
|
2014
2174
|
}
|
|
2015
2175
|
function createTicketsCommand() {
|
|
2016
|
-
const tickets = new
|
|
2176
|
+
const tickets = new Command10("tickets").description(
|
|
2017
2177
|
"Manage product backlog tickets. Tickets live under a product, link to features/epics, depend on each other, and can be implemented via actions."
|
|
2018
2178
|
);
|
|
2019
|
-
tickets.command("list").description("List tickets 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: ${TICKET_STATUSES.join(", ")}`).option("--type <type>", `Filter by type: ${TICKET_TYPES.join(", ")}`).option("--feature <id>", "Filter by feature CUID").option("--epic <id>", "Filter by epic CUID").option("--assignee <id>", "Filter by assignee user ID").
|
|
2179
|
+
tickets.command("list").description("List tickets 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: ${TICKET_STATUSES.join(", ")}`).option("--type <type>", `Filter by type: ${TICKET_TYPES.join(", ")}`).option("--feature <id>", "Filter by feature CUID").option("--epic <id>", "Filter by epic CUID").option("--assignee <id>", "Filter by assignee user ID").option(
|
|
2180
|
+
"--label <slug-or-id>",
|
|
2181
|
+
"Filter to tickets carrying this label (repeatable; AND semantics)",
|
|
2182
|
+
collectRepeatable,
|
|
2183
|
+
[]
|
|
2184
|
+
).action(
|
|
2020
2185
|
async (options, cmd) => {
|
|
2021
2186
|
const globalOpts = cmd.optsWithGlobals();
|
|
2022
2187
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2038,8 +2203,27 @@ function createTicketsCommand() {
|
|
|
2038
2203
|
epicId: options.epic,
|
|
2039
2204
|
assigneeId: options.assignee
|
|
2040
2205
|
});
|
|
2041
|
-
|
|
2042
|
-
|
|
2206
|
+
let filtered = list;
|
|
2207
|
+
if (options.label.length > 0) {
|
|
2208
|
+
const labelIds = new Set(
|
|
2209
|
+
await resolveLabelIds(client, workspaceId, options.label)
|
|
2210
|
+
);
|
|
2211
|
+
const ticketLabelSets = await Promise.all(
|
|
2212
|
+
list.map(
|
|
2213
|
+
(t) => client.labels.listForEntity({ entityType: "ticket", entityId: t.id }).then((tags) => new Set(tags.map((tag) => tag.id)))
|
|
2214
|
+
)
|
|
2215
|
+
);
|
|
2216
|
+
filtered = list.filter((_t, idx) => {
|
|
2217
|
+
const tagSet = ticketLabelSets[idx];
|
|
2218
|
+
if (tagSet === void 0) return false;
|
|
2219
|
+
for (const id of labelIds) {
|
|
2220
|
+
if (!tagSet.has(id)) return false;
|
|
2221
|
+
}
|
|
2222
|
+
return true;
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
if (useJson) outputTicketsJson(filtered);
|
|
2226
|
+
else outputTicketsPretty(filtered);
|
|
2043
2227
|
} catch (error) {
|
|
2044
2228
|
handleError(error, useJson);
|
|
2045
2229
|
}
|
|
@@ -2069,7 +2253,12 @@ function createTicketsCommand() {
|
|
|
2069
2253
|
handleError(error, useJson);
|
|
2070
2254
|
}
|
|
2071
2255
|
});
|
|
2072
|
-
tickets.command("create").description("Create a new ticket in a product").requiredOption("--product <slug|id>", "Product slug or CUID").requiredOption("-t, --title <title>", "Ticket title").option("-b, --body <text>", "Body (markdown supported)").option("--type <type>", `Ticket type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Initial status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", "Priority 0-4 (lower = higher)", parseInt).option("--points <n>", "Story points", parseFloat).option("--feature <id>", "Feature CUID to attach to").option("--epic <id>", "Epic CUID to attach to").option("--assignee <id>", "Assignee user ID").option("--branch <name>", "Branch name").option("--pr <url>", "Pull request URL").option("--workspace <slug|id>", "Workspace (required when --product is a slug)").
|
|
2256
|
+
tickets.command("create").description("Create a new ticket in a product").requiredOption("--product <slug|id>", "Product slug or CUID").requiredOption("-t, --title <title>", "Ticket title").option("-b, --body <text>", "Body (markdown supported)").option("--type <type>", `Ticket type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Initial status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", "Priority 0-4 (lower = higher)", parseInt).option("--points <n>", "Story points", parseFloat).option("--feature <id>", "Feature CUID to attach to").option("--epic <id>", "Epic CUID to attach to").option("--assignee <id>", "Assignee user ID").option("--branch <name>", "Branch name").option("--pr <url>", "Pull request URL").option("--workspace <slug|id>", "Workspace (required when --product is a slug)").option(
|
|
2257
|
+
"--label <slug-or-id>",
|
|
2258
|
+
"Label to attach (repeatable)",
|
|
2259
|
+
collectRepeatable,
|
|
2260
|
+
[]
|
|
2261
|
+
).action(
|
|
2073
2262
|
async (options, cmd) => {
|
|
2074
2263
|
const globalOpts = cmd.optsWithGlobals();
|
|
2075
2264
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2097,6 +2286,14 @@ function createTicketsCommand() {
|
|
|
2097
2286
|
branchName: options.branch,
|
|
2098
2287
|
prUrl: options.pr
|
|
2099
2288
|
});
|
|
2289
|
+
if (options.label.length > 0) {
|
|
2290
|
+
const tagIds = await resolveLabelIds(client, workspaceId, options.label);
|
|
2291
|
+
await client.labels.setEntityTags({
|
|
2292
|
+
entityType: "ticket",
|
|
2293
|
+
entityId: ticket.id,
|
|
2294
|
+
tagIds
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2100
2297
|
if (useJson) outputTicketJson(ticket);
|
|
2101
2298
|
else {
|
|
2102
2299
|
console.log("\n\u2713 Ticket created");
|
|
@@ -2107,7 +2304,17 @@ function createTicketsCommand() {
|
|
|
2107
2304
|
}
|
|
2108
2305
|
}
|
|
2109
2306
|
);
|
|
2110
|
-
tickets.command("update").description("Update an existing ticket").requiredOption("--id <id>", "Ticket CUID").option("-t, --title <title>", "New title").option("-b, --body <text>", "New body").option("--type <type>", `Type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", 'Priority 0-4 (or "null" to clear)').option("--points <n>", 'Story points (or "null" to clear)').option("--feature <id>", 'Feature CUID (or "null" to detach)').option("--epic <id>", 'Epic CUID (or "null" to detach)').option("--assignee <id>", 'Assignee user ID (or "null" to unassign)').option("--branch <name>", 'Branch name (or "null")').option("--pr <url>", 'PR URL (or "null")').
|
|
2307
|
+
tickets.command("update").description("Update an existing ticket").requiredOption("--id <id>", "Ticket CUID").option("-t, --title <title>", "New title").option("-b, --body <text>", "New body").option("--type <type>", `Type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", 'Priority 0-4 (or "null" to clear)').option("--points <n>", 'Story points (or "null" to clear)').option("--feature <id>", 'Feature CUID (or "null" to detach)').option("--epic <id>", 'Epic CUID (or "null" to detach)').option("--assignee <id>", 'Assignee user ID (or "null" to unassign)').option("--branch <name>", 'Branch name (or "null")').option("--pr <url>", 'PR URL (or "null")').option(
|
|
2308
|
+
"--add-label <slug-or-id>",
|
|
2309
|
+
"Label to attach to this ticket (repeatable)",
|
|
2310
|
+
collectRepeatable,
|
|
2311
|
+
[]
|
|
2312
|
+
).option(
|
|
2313
|
+
"--remove-label <slug-or-id>",
|
|
2314
|
+
"Label to detach from this ticket (repeatable)",
|
|
2315
|
+
collectRepeatable,
|
|
2316
|
+
[]
|
|
2317
|
+
).action(
|
|
2111
2318
|
async (options, cmd) => {
|
|
2112
2319
|
const globalOpts = cmd.optsWithGlobals();
|
|
2113
2320
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2148,6 +2355,22 @@ function createTicketsCommand() {
|
|
|
2148
2355
|
branchName: parseNullableString(options.branch),
|
|
2149
2356
|
prUrl: parseNullableString(options.pr)
|
|
2150
2357
|
});
|
|
2358
|
+
if (options.addLabel.length > 0 || options.removeLabel.length > 0) {
|
|
2359
|
+
const current = await client.labels.listForEntity({
|
|
2360
|
+
entityType: "ticket",
|
|
2361
|
+
entityId: options.id
|
|
2362
|
+
});
|
|
2363
|
+
const currentIds = new Set(current.map((t) => t.id));
|
|
2364
|
+
const addIds = await resolveLabelIds(client, void 0, options.addLabel);
|
|
2365
|
+
const removeIds = await resolveLabelIds(client, void 0, options.removeLabel);
|
|
2366
|
+
for (const id of addIds) currentIds.add(id);
|
|
2367
|
+
for (const id of removeIds) currentIds.delete(id);
|
|
2368
|
+
await client.labels.setEntityTags({
|
|
2369
|
+
entityType: "ticket",
|
|
2370
|
+
entityId: options.id,
|
|
2371
|
+
tagIds: [...currentIds]
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2151
2374
|
if (useJson) outputTicketJson(ticket);
|
|
2152
2375
|
else {
|
|
2153
2376
|
console.log("\n\u2713 Ticket updated");
|
|
@@ -2240,7 +2463,7 @@ function createTicketsCommand() {
|
|
|
2240
2463
|
handleError(error, useJson);
|
|
2241
2464
|
}
|
|
2242
2465
|
});
|
|
2243
|
-
const comment = new
|
|
2466
|
+
const comment = new Command10("comment").description("Manage comments on a ticket");
|
|
2244
2467
|
comment.command("add").description("Add a comment to a ticket").requiredOption("--id <id>", "Ticket CUID").requiredOption("-m, --message <text>", "Comment content (markdown supported)").action(async (options, cmd) => {
|
|
2245
2468
|
const globalOpts = cmd.optsWithGlobals();
|
|
2246
2469
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2279,10 +2502,10 @@ function createTicketsCommand() {
|
|
|
2279
2502
|
}
|
|
2280
2503
|
|
|
2281
2504
|
// src/commands/workspaces.ts
|
|
2282
|
-
import { Command as
|
|
2283
|
-
import
|
|
2505
|
+
import { Command as Command11 } from "commander";
|
|
2506
|
+
import chalk5 from "chalk";
|
|
2284
2507
|
function createWorkspacesCommand() {
|
|
2285
|
-
const workspaces = new
|
|
2508
|
+
const workspaces = new Command11("workspaces").description("Manage workspaces");
|
|
2286
2509
|
workspaces.command("list").description("List all workspaces").action(async (_options, cmd) => {
|
|
2287
2510
|
const globalOpts = cmd.optsWithGlobals();
|
|
2288
2511
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -2295,7 +2518,7 @@ function createWorkspacesCommand() {
|
|
|
2295
2518
|
const config = getConfig();
|
|
2296
2519
|
outputWorkspacesPretty(workspaces2);
|
|
2297
2520
|
if (config.defaultWorkspaceSlug) {
|
|
2298
|
-
console.log(
|
|
2521
|
+
console.log(chalk5.gray(`Default workspace: ${config.defaultWorkspaceSlug}`));
|
|
2299
2522
|
}
|
|
2300
2523
|
}
|
|
2301
2524
|
} catch (error) {
|
|
@@ -2308,10 +2531,10 @@ function createWorkspacesCommand() {
|
|
|
2308
2531
|
const workspaces2 = await client.workspaces.list();
|
|
2309
2532
|
const workspace = workspaces2.find((w) => w.slug === slug);
|
|
2310
2533
|
if (!workspace) {
|
|
2311
|
-
console.error(
|
|
2312
|
-
console.log(
|
|
2534
|
+
console.error(chalk5.red(`Workspace with slug "${slug}" not found.`));
|
|
2535
|
+
console.log(chalk5.gray("Available workspaces:"));
|
|
2313
2536
|
workspaces2.forEach((w) => {
|
|
2314
|
-
console.log(
|
|
2537
|
+
console.log(chalk5.gray(` - ${w.slug} (${w.name})`));
|
|
2315
2538
|
});
|
|
2316
2539
|
process.exit(1);
|
|
2317
2540
|
}
|
|
@@ -2319,7 +2542,7 @@ function createWorkspacesCommand() {
|
|
|
2319
2542
|
defaultWorkspaceId: workspace.id,
|
|
2320
2543
|
defaultWorkspaceSlug: workspace.slug
|
|
2321
2544
|
});
|
|
2322
|
-
console.log(
|
|
2545
|
+
console.log(chalk5.green(`Default workspace set to: ${workspace.name} (${workspace.slug})`));
|
|
2323
2546
|
} catch (error) {
|
|
2324
2547
|
handleError(error);
|
|
2325
2548
|
}
|
|
@@ -2328,7 +2551,7 @@ function createWorkspacesCommand() {
|
|
|
2328
2551
|
}
|
|
2329
2552
|
|
|
2330
2553
|
// src/index.ts
|
|
2331
|
-
var program = new
|
|
2554
|
+
var program = new Command12();
|
|
2332
2555
|
program.name("exponential").description(
|
|
2333
2556
|
[
|
|
2334
2557
|
"CLI to interact with Exponential productivity app.",
|
|
@@ -2344,6 +2567,7 @@ program.addCommand(createContactsCommand());
|
|
|
2344
2567
|
program.addCommand(createDealsCommand());
|
|
2345
2568
|
program.addCommand(createEpicsCommand());
|
|
2346
2569
|
program.addCommand(createFeaturesCommand());
|
|
2570
|
+
program.addCommand(createLabelsCommand());
|
|
2347
2571
|
program.addCommand(createProductsCommand());
|
|
2348
2572
|
program.addCommand(createProjectsCommand());
|
|
2349
2573
|
program.addCommand(createTicketsCommand());
|