@shortcut-cli/shortcut-cli 3.8.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +549 -10
- package/build/bin/short-api.js +21 -22
- package/build/bin/short-create.js +58 -38
- package/build/bin/short-custom-field.js +50 -0
- package/build/bin/short-custom-fields.js +29 -0
- package/build/bin/short-doc.js +38 -41
- package/build/bin/short-docs.js +34 -27
- package/build/bin/short-epic.js +147 -36
- package/build/bin/short-epics.js +23 -24
- package/build/bin/short-find.js +4 -5
- package/build/bin/short-install.js +73 -29
- package/build/bin/short-iteration.js +180 -0
- package/build/bin/short-iterations.js +62 -0
- package/build/bin/short-label.js +130 -0
- package/build/bin/short-labels.js +27 -0
- package/build/bin/short-members.js +17 -21
- package/build/bin/short-objective.js +151 -0
- package/build/bin/short-objectives.js +63 -0
- package/build/bin/short-projects.js +17 -21
- package/build/bin/short-search.js +23 -32
- package/build/bin/short-story.js +350 -104
- package/build/bin/short-team.js +78 -0
- package/build/bin/short-teams.js +28 -0
- package/build/bin/short-workflows.js +12 -16
- package/build/bin/short-workspace.js +27 -28
- package/build/bin/short.js +5 -8
- package/build/lib/client.js +7 -9
- package/build/lib/configure.js +20 -29
- package/build/lib/spinner.js +3 -8
- package/build/lib/stories.js +171 -129
- package/build/package.js +3 -16
- package/package.json +67 -67
- package/build/_virtual/rolldown_runtime.js +0 -29
package/build/bin/short-api.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let debug = require("debug");
|
|
7
|
-
debug = require_rolldown_runtime.__toESM(debug);
|
|
8
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import client from "../lib/client.js";
|
|
3
|
+
import spinner from "../lib/spinner.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import debugging from "debug";
|
|
9
6
|
//#region src/bin/short-api.ts
|
|
10
|
-
const debug
|
|
7
|
+
const debug = debugging("short-api");
|
|
11
8
|
const log = console.log;
|
|
12
9
|
const logError = console.error;
|
|
13
|
-
const spin =
|
|
10
|
+
const spin = spinner();
|
|
14
11
|
const parseKeyVal = (input, separator = "=") => {
|
|
15
12
|
const parts = input.split(separator);
|
|
16
|
-
return [parts.shift(), parts.join(separator)];
|
|
13
|
+
return [parts.shift() ?? "", parts.join(separator)];
|
|
17
14
|
};
|
|
18
15
|
const collect = (val, memo) => {
|
|
19
16
|
memo.push(val);
|
|
20
17
|
return memo;
|
|
21
18
|
};
|
|
22
|
-
const program =
|
|
19
|
+
const program = new Command().description("Make a request to the Shortcut API.").arguments("<path>").option("-X, --method <method>", "The HTTP method to use.", "GET").option("-H, --header <header>", "Add a header to the request (e.g., \"Content-Type: application/json\"). Can be specified multiple times.", collect, []).option("-f, --raw-field <key=value>", "Add a string parameter. Can be specified multiple times.", collect, []).on("--help", () => {
|
|
23
20
|
log("");
|
|
24
21
|
log("Examples:");
|
|
25
22
|
log(` $ short api /search/iterations -f page_size=10 -f query=123`);
|
|
@@ -27,6 +24,7 @@ const program = commander.default.description("Make a request to the Shortcut AP
|
|
|
27
24
|
log(" # jq can be used to shorten the response output.");
|
|
28
25
|
log(` $ short api /search/iterations -f page_size=10 -f query=123 | jq '.data[] | {id, name}'`);
|
|
29
26
|
}).parse(process.argv);
|
|
27
|
+
const opts = program.opts();
|
|
30
28
|
const main = async () => {
|
|
31
29
|
const [path] = program.args;
|
|
32
30
|
if (!path) {
|
|
@@ -34,18 +32,18 @@ const main = async () => {
|
|
|
34
32
|
program.help();
|
|
35
33
|
process.exit(1);
|
|
36
34
|
}
|
|
37
|
-
const method = (
|
|
35
|
+
const method = (opts.method || "GET").toUpperCase();
|
|
38
36
|
const headers = {};
|
|
39
37
|
const params = {};
|
|
40
|
-
if (
|
|
38
|
+
if (opts.header) opts.header.forEach((h) => {
|
|
41
39
|
const [key, value] = parseKeyVal(h, ":");
|
|
42
40
|
headers[key] = value;
|
|
43
|
-
debug
|
|
41
|
+
debug(`adding header: ${key}: ${value}`);
|
|
44
42
|
});
|
|
45
|
-
if (
|
|
43
|
+
if (opts.rawField) opts.rawField.forEach((f) => {
|
|
46
44
|
const [key, value] = parseKeyVal(f);
|
|
47
45
|
params[key] = value;
|
|
48
|
-
debug
|
|
46
|
+
debug(`adding raw field: ${key}: ${value}`);
|
|
49
47
|
});
|
|
50
48
|
const requestOptions = {
|
|
51
49
|
path: "/api/v3" + (path.startsWith("/") ? "" : "/") + path,
|
|
@@ -61,17 +59,18 @@ const main = async () => {
|
|
|
61
59
|
if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
|
62
60
|
} else requestOptions.query = params;
|
|
63
61
|
try {
|
|
64
|
-
debug
|
|
62
|
+
debug("request options:", requestOptions);
|
|
65
63
|
spin.start();
|
|
66
|
-
const response = await
|
|
64
|
+
const response = await client.request(requestOptions);
|
|
67
65
|
spin.stop(true);
|
|
68
66
|
log(JSON.stringify(response.data, null, 2));
|
|
69
67
|
} catch (err) {
|
|
70
68
|
spin.stop(true);
|
|
71
|
-
|
|
69
|
+
const error = err;
|
|
70
|
+
logError("Error calling API:", error.response ? JSON.stringify(error.response.data, null, 2) : error.message);
|
|
72
71
|
process.exit(1);
|
|
73
72
|
}
|
|
74
73
|
};
|
|
75
74
|
main();
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
//#endregion
|
|
76
|
+
export {};
|
|
@@ -1,56 +1,76 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
9
|
-
let child_process = require("child_process");
|
|
10
|
-
|
|
2
|
+
import { loadConfig } from "../lib/configure.js";
|
|
3
|
+
import client from "../lib/client.js";
|
|
4
|
+
import spinner from "../lib/spinner.js";
|
|
5
|
+
import stories_default from "../lib/stories.js";
|
|
6
|
+
import { Command, Option } from "commander";
|
|
7
|
+
import { exec } from "child_process";
|
|
11
8
|
//#region src/bin/short-create.ts
|
|
12
|
-
const config =
|
|
13
|
-
const spin =
|
|
9
|
+
const config = loadConfig();
|
|
10
|
+
const spin = spinner();
|
|
14
11
|
const log = console.log;
|
|
15
|
-
const
|
|
12
|
+
const opts = new Command().usage("[options]").description("create a story with provided details").option("-d, --description [text]", "Set description of story", "").option("-e, --estimate [number]", "Set estimate of story").option("--epic [id|name]", "Set epic of story").option("--git-branch", "Checkout git branch from story slug <mention-name>/ch<id>/<type>-<title>\n as required by the Git integration: https://bit.ly/2RKO1FF").option("--git-branch-short", "Checkout git branch from story slug <mention-name>/ch<id>/<title>").option("-i, --iteration [id|name]", "Set iteration of story").option("-I, --idonly", "Print only ID of story result").option("-l, --label [id|name]", "Stories with label id/name, by regex", "").option("-o, --owners [id|name]", "Set owners of story, comma-separated", "").option("-O, --open", "Open story in browser").option("-p, --project [id|name]", "Set project of story, required if --state is not set", "").option("-T, --team [id|name]", "Set team of story", "").option("-t, --title [text]", "Set title of story, required", "").option("-s, --state [id|name]", "Set workflow state of story, required if --project is not set", "").addOption(new Option("-y, --type <name>", "Set type of story").choices([
|
|
13
|
+
"feature",
|
|
14
|
+
"bug",
|
|
15
|
+
"chore"
|
|
16
|
+
]).default("feature")).parse(process.argv).opts();
|
|
16
17
|
const main = async () => {
|
|
17
|
-
const entities = await
|
|
18
|
-
if (!
|
|
18
|
+
const entities = await stories_default.fetchEntities();
|
|
19
|
+
if (!opts.idonly) spin.start();
|
|
20
|
+
const project = opts.project ? stories_default.findProject(entities, opts.project) : void 0;
|
|
21
|
+
const group = opts.team ? stories_default.findGroup(entities, opts.team) : void 0;
|
|
22
|
+
const state = opts.state ? stories_default.findState(entities, opts.state) : void 0;
|
|
23
|
+
const epic = opts.epic ? stories_default.findEpic(entities, opts.epic) : void 0;
|
|
24
|
+
const iteration = opts.iteration ? stories_default.findIteration(entities, opts.iteration) : void 0;
|
|
19
25
|
const update = {
|
|
20
|
-
name:
|
|
21
|
-
story_type:
|
|
22
|
-
description: `${
|
|
23
|
-
estimate: program.estimate || void 0
|
|
26
|
+
name: opts.title ?? "",
|
|
27
|
+
story_type: opts.type,
|
|
28
|
+
description: `${opts.description}`
|
|
24
29
|
};
|
|
25
|
-
if (
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
if (
|
|
29
|
-
if (
|
|
30
|
-
if (
|
|
31
|
-
if (
|
|
32
|
-
if (
|
|
30
|
+
if (project) update.project_id = project.id;
|
|
31
|
+
if (group) update.group_id = group.id;
|
|
32
|
+
if (state) update.workflow_state_id = state.id;
|
|
33
|
+
if (epic) update.epic_id = epic.id;
|
|
34
|
+
if (iteration) update.iteration_id = iteration.id;
|
|
35
|
+
if (opts.estimate) update.estimate = parseInt(opts.estimate, 10);
|
|
36
|
+
if (opts.owners) update.owner_ids = stories_default.findOwnerIds(entities, opts.owners);
|
|
37
|
+
if (opts.label) update.labels = stories_default.findLabelNames(entities, opts.label);
|
|
33
38
|
let story;
|
|
34
39
|
if (!update.name) {
|
|
35
|
-
if (!
|
|
40
|
+
if (!opts.idonly) spin.stop(true);
|
|
36
41
|
log("Must provide --title");
|
|
42
|
+
} else if (opts.project && !project) {
|
|
43
|
+
if (!opts.idonly) spin.stop(true);
|
|
44
|
+
log(`Project ${opts.project} not found`);
|
|
45
|
+
} else if (opts.state && !state) {
|
|
46
|
+
if (!opts.idonly) spin.stop(true);
|
|
47
|
+
log(`State ${opts.state} not found`);
|
|
48
|
+
} else if (opts.team && !group) {
|
|
49
|
+
if (!opts.idonly) spin.stop(true);
|
|
50
|
+
log(`Team ${opts.team} not found`);
|
|
51
|
+
} else if (opts.epic && !epic) {
|
|
52
|
+
if (!opts.idonly) spin.stop(true);
|
|
53
|
+
log(`Epic ${opts.epic} not found`);
|
|
54
|
+
} else if (opts.iteration && !iteration) {
|
|
55
|
+
if (!opts.idonly) spin.stop(true);
|
|
56
|
+
log(`Iteration ${opts.iteration} not found`);
|
|
37
57
|
} else if (!update.project_id && !update.workflow_state_id) {
|
|
38
|
-
if (!
|
|
58
|
+
if (!opts.idonly) spin.stop(true);
|
|
39
59
|
log("Must provide --project or --state");
|
|
40
60
|
} else try {
|
|
41
|
-
story = await
|
|
42
|
-
} catch (
|
|
61
|
+
story = await client.createStory(update).then((r) => r.data);
|
|
62
|
+
} catch (_e) {
|
|
43
63
|
log("Error creating story");
|
|
44
64
|
}
|
|
45
|
-
if (!
|
|
65
|
+
if (!opts.idonly) spin.stop(true);
|
|
46
66
|
if (story) {
|
|
47
|
-
const hydrateStory =
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
else if (
|
|
51
|
-
if (
|
|
67
|
+
const hydrateStory = stories_default.hydrateStory(entities, story);
|
|
68
|
+
stories_default.printDetailedStory(hydrateStory);
|
|
69
|
+
if (opts.gitBranch) stories_default.checkoutStoryBranch(hydrateStory);
|
|
70
|
+
else if (opts.gitBranchShort) stories_default.checkoutStoryBranch(hydrateStory, `${config.mentionName}/sc-${story.id}/`);
|
|
71
|
+
if (opts.open) exec("open " + stories_default.storyURL(story));
|
|
52
72
|
}
|
|
53
73
|
};
|
|
54
74
|
main();
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
//#endregion
|
|
76
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import client from "../lib/client.js";
|
|
3
|
+
import spinner from "../lib/spinner.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
//#region src/bin/short-custom-field.ts
|
|
7
|
+
const spin = spinner();
|
|
8
|
+
const log = console.log;
|
|
9
|
+
const program = new Command().argument("<id>").usage("<id> [options]").description("view a custom field by id").parse(process.argv);
|
|
10
|
+
const id = program.args[0];
|
|
11
|
+
if (!id) {
|
|
12
|
+
program.outputHelp();
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
async function main() {
|
|
16
|
+
if (!id) process.exit(1);
|
|
17
|
+
spin.start();
|
|
18
|
+
try {
|
|
19
|
+
const field = await client.getCustomField(id).then((r) => r.data);
|
|
20
|
+
spin.stop(true);
|
|
21
|
+
printField(field);
|
|
22
|
+
} catch (e) {
|
|
23
|
+
spin.stop(true);
|
|
24
|
+
const error = e;
|
|
25
|
+
if (error.response?.status === 404) log(`Custom field ${id} not found`);
|
|
26
|
+
else log(`Error fetching custom field: ${error.message ?? String(e)}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function printField(field) {
|
|
31
|
+
log(chalk.bold(field.id) + chalk.blue(` ${field.name}`));
|
|
32
|
+
log(chalk.bold("Type: ") + ` ${field.field_type}`);
|
|
33
|
+
log(chalk.bold("Enabled: ") + ` ${field.enabled}`);
|
|
34
|
+
log(chalk.bold("Story Types: ") + ` ${(field.story_types || []).join(", ") || "_"}`);
|
|
35
|
+
log(chalk.bold("Position: ") + ` ${field.position}`);
|
|
36
|
+
log(chalk.bold("Fixed: ") + ` ${field.fixed_position || false}`);
|
|
37
|
+
if (field.canonical_name) log(chalk.bold("Canonical: ") + ` ${field.canonical_name}`);
|
|
38
|
+
if (field.description) log(chalk.bold("Description: ") + ` ${field.description}`);
|
|
39
|
+
if (field.values?.length) {
|
|
40
|
+
log(chalk.bold("Values:"));
|
|
41
|
+
field.values.forEach((value) => {
|
|
42
|
+
log(` - ${value.value} (${value.id}) enabled=${value.enabled} position=${value.position}${value.color_key ? ` color=${value.color_key}` : ""}`);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
log(chalk.bold("Created: ") + ` ${field.created_at}`);
|
|
46
|
+
log(chalk.bold("Updated: ") + ` ${field.updated_at}`);
|
|
47
|
+
}
|
|
48
|
+
main();
|
|
49
|
+
//#endregion
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import client from "../lib/client.js";
|
|
3
|
+
import spinner from "../lib/spinner.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
//#region src/bin/short-custom-fields.ts
|
|
7
|
+
const spin = spinner();
|
|
8
|
+
const log = console.log;
|
|
9
|
+
const opts = new Command().description("Display custom fields available for stories").option("-d, --disabled", "List custom fields including disabled", "").option("-s, --search [query]", "List custom fields with name containing query", "").parse(process.argv).opts();
|
|
10
|
+
async function main() {
|
|
11
|
+
spin.start();
|
|
12
|
+
const fields = await client.listCustomFields().then((r) => r.data);
|
|
13
|
+
spin.stop(true);
|
|
14
|
+
const searchMatch = new RegExp(opts.search ?? "", "i");
|
|
15
|
+
fields.filter((field) => !!`${field.id} ${field.name} ${field.description || ""}`.match(searchMatch)).forEach(printFieldSummary);
|
|
16
|
+
}
|
|
17
|
+
function printFieldSummary(field) {
|
|
18
|
+
if (!field.enabled && !opts.disabled) return;
|
|
19
|
+
log(chalk.bold(field.id) + chalk.blue(` ${field.name}`));
|
|
20
|
+
log(chalk.bold("Type: ") + ` ${field.field_type}`);
|
|
21
|
+
log(chalk.bold("Enabled: ") + ` ${field.enabled}`);
|
|
22
|
+
log(chalk.bold("Story Types: ") + ` ${(field.story_types || []).join(", ") || "_"}`);
|
|
23
|
+
log(chalk.bold("Values: ") + ` ${field.values?.length || 0}`);
|
|
24
|
+
if (field.description) log(chalk.bold("Description: ") + ` ${field.description}`);
|
|
25
|
+
log();
|
|
26
|
+
}
|
|
27
|
+
main();
|
|
28
|
+
//#endregion
|
|
29
|
+
export {};
|
package/build/bin/short-doc.js
CHANGED
|
@@ -1,37 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
os = require_rolldown_runtime.__toESM(os);
|
|
9
|
-
let child_process = require("child_process");
|
|
10
|
-
let chalk = require("chalk");
|
|
11
|
-
chalk = require_rolldown_runtime.__toESM(chalk);
|
|
12
|
-
|
|
2
|
+
import client from "../lib/client.js";
|
|
3
|
+
import spinner from "../lib/spinner.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import { exec } from "child_process";
|
|
7
|
+
import chalk from "chalk";
|
|
13
8
|
//#region src/bin/short-doc.ts
|
|
14
|
-
const spin =
|
|
9
|
+
const spin = spinner();
|
|
15
10
|
const log = console.log;
|
|
16
|
-
const program =
|
|
11
|
+
const program = new Command().usage("[command] [options]").description("view, create, or update a doc");
|
|
17
12
|
program.command("view <id>").description("view a doc by ID").option("--html", "Include HTML content in output").option("-O, --open", "Open doc in browser").option("-q, --quiet", "Print only doc content, no metadata").action(viewDoc);
|
|
18
13
|
program.command("create").description("create a new doc").option("-t, --title <text>", "Set title of doc (required)").option("-c, --content <text>", "Set content of doc (required)").option("--markdown", "Treat content as markdown (default is HTML)").option("-I, --idonly", "Print only ID of doc result").option("-O, --open", "Open doc in browser").action(createDoc);
|
|
19
14
|
program.command("update <id>").description("update an existing doc").option("-t, --title <text>", "Update title of doc").option("-c, --content <text>", "Update content of doc").option("--markdown", "Treat content as markdown (default is HTML)").option("-O, --open", "Open doc in browser").action(updateDoc);
|
|
20
15
|
program.command("delete <id>").description("delete a doc").option("--confirm", "Confirm deletion without prompting").action(deleteDoc);
|
|
21
16
|
const args = process.argv.slice(2);
|
|
22
|
-
if (args.length > 0 && isUUID(args[0])) process.argv.splice(2, 0, "view");
|
|
17
|
+
if (args.length > 0 && args[0] && isUUID(args[0])) process.argv.splice(2, 0, "view");
|
|
23
18
|
program.parse(process.argv);
|
|
24
19
|
if (args.length === 0) {
|
|
25
20
|
program.outputHelp();
|
|
26
21
|
process.exit(1);
|
|
27
|
-
} else if (args.length > 0 && !isUUID(args[0])) {
|
|
28
|
-
|
|
22
|
+
} else if (args.length > 0 && args[0] && !isUUID(args[0])) {
|
|
23
|
+
const validCommands = [
|
|
29
24
|
"view",
|
|
30
25
|
"create",
|
|
31
26
|
"update",
|
|
32
27
|
"delete"
|
|
33
|
-
]
|
|
34
|
-
|
|
28
|
+
];
|
|
29
|
+
const firstArg = args[0];
|
|
30
|
+
if (!validCommands.includes(firstArg) && !firstArg.startsWith("-")) {
|
|
31
|
+
console.error(`Error: Unknown command or invalid doc ID: ${firstArg}`);
|
|
35
32
|
console.error("Run \"short doc --help\" for usage information.");
|
|
36
33
|
process.exit(1);
|
|
37
34
|
}
|
|
@@ -45,10 +42,10 @@ async function viewDoc(id, options) {
|
|
|
45
42
|
try {
|
|
46
43
|
const params = {};
|
|
47
44
|
if (options.html) params.content_format = "html";
|
|
48
|
-
doc = await
|
|
45
|
+
doc = await client.getDoc(id, Object.keys(params).length > 0 ? params : void 0).then((r) => r.data);
|
|
49
46
|
} catch (e) {
|
|
50
47
|
if (!options.quiet) spin.stop(true);
|
|
51
|
-
log("Error fetching doc:", e.message
|
|
48
|
+
log("Error fetching doc:", e.message ?? String(e));
|
|
52
49
|
process.exit(1);
|
|
53
50
|
}
|
|
54
51
|
if (!options.quiet) spin.stop(true);
|
|
@@ -73,17 +70,17 @@ async function createDoc(options) {
|
|
|
73
70
|
};
|
|
74
71
|
let doc;
|
|
75
72
|
try {
|
|
76
|
-
const result = await
|
|
77
|
-
doc = await
|
|
73
|
+
const result = await client.createDoc(docData);
|
|
74
|
+
doc = await client.getDoc(result.data.id).then((r) => r.data);
|
|
78
75
|
} catch (e) {
|
|
79
76
|
if (!options.idonly) spin.stop(true);
|
|
80
|
-
log("Error creating doc:", e.message
|
|
77
|
+
log("Error creating doc:", e.message ?? String(e));
|
|
81
78
|
process.exit(1);
|
|
82
79
|
}
|
|
83
80
|
if (!options.idonly) spin.stop(true);
|
|
84
81
|
if (options.idonly) log(doc.id);
|
|
85
82
|
else {
|
|
86
|
-
log(chalk.
|
|
83
|
+
log(chalk.green("Doc created successfully!"));
|
|
87
84
|
printDoc(doc);
|
|
88
85
|
}
|
|
89
86
|
if (options.open) openURL(doc.app_url);
|
|
@@ -102,14 +99,14 @@ async function updateDoc(id, options) {
|
|
|
102
99
|
}
|
|
103
100
|
let doc;
|
|
104
101
|
try {
|
|
105
|
-
doc = await
|
|
102
|
+
doc = await client.updateDoc(id, docData).then((r) => r.data);
|
|
106
103
|
} catch (e) {
|
|
107
104
|
spin.stop(true);
|
|
108
|
-
log("Error updating doc:", e.message
|
|
105
|
+
log("Error updating doc:", e.message ?? String(e));
|
|
109
106
|
process.exit(1);
|
|
110
107
|
}
|
|
111
108
|
spin.stop(true);
|
|
112
|
-
log(chalk.
|
|
109
|
+
log(chalk.green("Doc updated successfully!"));
|
|
113
110
|
printDoc(doc);
|
|
114
111
|
if (options.open) openURL(doc.app_url);
|
|
115
112
|
}
|
|
@@ -121,35 +118,35 @@ async function deleteDoc(id, options) {
|
|
|
121
118
|
}
|
|
122
119
|
spin.start();
|
|
123
120
|
try {
|
|
124
|
-
await
|
|
121
|
+
await client.deleteDoc(id, {});
|
|
125
122
|
} catch (e) {
|
|
126
123
|
spin.stop(true);
|
|
127
|
-
log("Error deleting doc:", e.message
|
|
124
|
+
log("Error deleting doc:", e.message ?? String(e));
|
|
128
125
|
process.exit(1);
|
|
129
126
|
}
|
|
130
127
|
spin.stop(true);
|
|
131
|
-
log(chalk.
|
|
128
|
+
log(chalk.green(`Doc ${id} deleted successfully.`));
|
|
132
129
|
}
|
|
133
130
|
function printDoc(doc, includeHtml = false) {
|
|
134
|
-
log(chalk.
|
|
135
|
-
log(chalk.
|
|
136
|
-
log(chalk.
|
|
137
|
-
log(chalk.
|
|
138
|
-
if (doc.created_at !== doc.updated_at) log(chalk.
|
|
139
|
-
if (doc.archived) log(chalk.
|
|
131
|
+
log(chalk.blue.bold(doc.title || "(Untitled)"));
|
|
132
|
+
log(chalk.bold("ID:") + ` ${doc.id}`);
|
|
133
|
+
log(chalk.bold("URL:") + ` ${doc.app_url}`);
|
|
134
|
+
log(chalk.bold("Created:") + ` ${doc.created_at}`);
|
|
135
|
+
if (doc.created_at !== doc.updated_at) log(chalk.bold("Updated:") + ` ${doc.updated_at}`);
|
|
136
|
+
if (doc.archived) log(chalk.bold("Archived:") + ` ${doc.archived}`);
|
|
140
137
|
log();
|
|
141
138
|
if (doc.content_markdown) {
|
|
142
|
-
log(chalk.
|
|
139
|
+
log(chalk.bold("Content (Markdown):"));
|
|
143
140
|
log(doc.content_markdown);
|
|
144
141
|
}
|
|
145
142
|
if (includeHtml && doc.content_html) {
|
|
146
143
|
log();
|
|
147
|
-
log(chalk.
|
|
144
|
+
log(chalk.bold("Content (HTML):"));
|
|
148
145
|
log(doc.content_html);
|
|
149
146
|
}
|
|
150
147
|
}
|
|
151
148
|
function openURL(url) {
|
|
152
|
-
|
|
149
|
+
exec(`${os.platform() === "darwin" ? "open" : "xdg-open"} '${url}'`);
|
|
153
150
|
}
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
//#endregion
|
|
152
|
+
export {};
|
package/build/bin/short-docs.js
CHANGED
|
@@ -1,51 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
let commander = require("commander");
|
|
6
|
-
commander = require_rolldown_runtime.__toESM(commander);
|
|
7
|
-
|
|
2
|
+
import client from "../lib/client.js";
|
|
3
|
+
import spinner from "../lib/spinner.js";
|
|
4
|
+
import { Command } from "commander";
|
|
8
5
|
//#region src/bin/short-docs.ts
|
|
9
|
-
const spin =
|
|
6
|
+
const spin = spinner("Loading docs... %s ");
|
|
10
7
|
const log = console.log;
|
|
11
|
-
const
|
|
12
|
-
Use --title to search docs by title.`).usage("[options]").option("-a, --archived", "Search for archived docs (requires --title)").option("-m, --mine", "Search for docs created by me (requires --title)").option("-f, --following", "Search for docs I am following (requires --title)").option("-t, --title [text]", "Search docs by title (required for search filters)").option("-q, --quiet", "Print only doc output, no loading dialog").option("-I, --idonly", "Print only IDs of doc results").parse(process.argv);
|
|
8
|
+
const opts = new Command().description(`List and search Shortcut Docs. By default, lists all docs you have access to.
|
|
9
|
+
Use --title to search docs by title.`).usage("[options]").option("-a, --archived", "Search for archived docs (requires --title)").option("-m, --mine", "Search for docs created by me (requires --title)").option("-f, --following", "Search for docs I am following (requires --title)").option("-t, --title [text]", "Search docs by title (required for search filters)").option("-q, --quiet", "Print only doc output, no loading dialog").option("-I, --idonly", "Print only IDs of doc results").parse(process.argv).opts();
|
|
13
10
|
const main = async () => {
|
|
14
|
-
if (!
|
|
11
|
+
if (!opts.quiet) spin.start();
|
|
15
12
|
let docs = [];
|
|
16
13
|
try {
|
|
17
|
-
if (
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (program.following) searchParams.followed_by_me = true;
|
|
22
|
-
docs = (await require_lib_client.default.searchDocuments(searchParams)).data.data;
|
|
14
|
+
if (opts.title) if (!opts.archived && !opts.mine && !opts.following) {
|
|
15
|
+
const result = await client.listDocs();
|
|
16
|
+
const title = opts.title.toLowerCase();
|
|
17
|
+
docs = result.data.filter((doc) => (doc.title || "").toLowerCase().includes(title));
|
|
23
18
|
} else {
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const searchParams = { title: opts.title };
|
|
20
|
+
if (opts.archived !== void 0) searchParams.archived = !!opts.archived;
|
|
21
|
+
if (opts.mine) searchParams.created_by_me = true;
|
|
22
|
+
if (opts.following) searchParams.followed_by_me = true;
|
|
23
|
+
docs = (await client.searchDocuments(searchParams)).data.data;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
if (opts.archived || opts.mine || opts.following) {
|
|
27
|
+
if (!opts.quiet) spin.stop(true);
|
|
26
28
|
log("Note: --archived, --mine, and --following require --title for searching.");
|
|
27
29
|
log("Listing all docs instead...");
|
|
28
|
-
if (!
|
|
30
|
+
if (!opts.quiet) spin.start();
|
|
29
31
|
}
|
|
30
|
-
docs = (await
|
|
32
|
+
docs = (await client.listDocs()).data;
|
|
31
33
|
}
|
|
32
34
|
} catch (e) {
|
|
33
|
-
if (!
|
|
34
|
-
log("Error fetching docs:", e.message
|
|
35
|
+
if (!opts.quiet) spin.stop(true);
|
|
36
|
+
log("Error fetching docs:", e.message ?? String(e));
|
|
35
37
|
process.exit(1);
|
|
36
38
|
}
|
|
37
|
-
if (!
|
|
39
|
+
if (!opts.quiet) spin.stop(true);
|
|
38
40
|
if (docs.length === 0) {
|
|
39
41
|
log("No docs found.");
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
|
-
docs.forEach((doc) =>
|
|
44
|
+
docs.forEach((doc) => {
|
|
45
|
+
printDoc(doc);
|
|
46
|
+
});
|
|
43
47
|
};
|
|
44
48
|
const printDoc = (doc) => {
|
|
45
|
-
if (
|
|
49
|
+
if (opts.idonly) {
|
|
50
|
+
log(doc.id);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
46
53
|
log(`${doc.id} ${doc.title || "(Untitled)"}`);
|
|
47
54
|
log(`\tURL: ${doc.app_url}`);
|
|
48
55
|
};
|
|
49
56
|
main();
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
//#endregion
|
|
58
|
+
export {};
|