twentythree-cli 1.0.1 → 1.0.2

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.
@@ -40,13 +40,14 @@ var Credentials = class Credentials extends _oclif_core.Command {
40
40
  require_auth_workspace_config.setCredentialDomain(domain);
41
41
  const s = _clack_prompts.spinner();
42
42
  s.start("Discovering workspaces...");
43
- let workspaces;
43
+ let workspaces = [];
44
44
  try {
45
45
  workspaces = await require_auth_token_refresh.fetchWorkspaceTokens(domain, trimmedToken);
46
46
  s.stop("Workspaces discovered");
47
47
  } catch (err) {
48
48
  s.stop("Failed to discover workspaces");
49
49
  this.error(`Could not discover workspaces: ${err instanceof Error ? err.message : String(err)}`, { exit: 1 });
50
+ return;
50
51
  }
51
52
  let selectedWorkspaces;
52
53
  if (workspaces.length > 1) {
@@ -0,0 +1,79 @@
1
+ const require_runtime = require("../../_virtual/_rolldown/runtime.cjs");
2
+ let _oclif_core = require("@oclif/core");
3
+ let _clack_prompts = require("@clack/prompts");
4
+ _clack_prompts = require_runtime.__toESM(_clack_prompts);
5
+ //#region src/commands/autocomplete/index.ts
6
+ var Autocomplete = class Autocomplete extends _oclif_core.Command {
7
+ static description = "Set up tab completion for your shell";
8
+ static agentMetadata = {
9
+ api_endpoint: "interactive",
10
+ auth_scope: "none",
11
+ output_shape: { type: "none" },
12
+ side_effects: "creates"
13
+ };
14
+ static examples = ["<%= config.bin %> autocomplete"];
15
+ async run() {
16
+ await this.parse(Autocomplete);
17
+ _clack_prompts.intro("Tab completion setup");
18
+ const rawShell = process.env.SHELL ?? "";
19
+ const detectedShell = rawShell.endsWith("zsh") ? "zsh" : rawShell.endsWith("bash") ? "bash" : null;
20
+ let shell;
21
+ if (detectedShell) {
22
+ const confirm = await _clack_prompts.confirm({ message: `Detected shell: ${detectedShell}. Set up completion for ${detectedShell}?` });
23
+ if (_clack_prompts.isCancel(confirm)) {
24
+ _clack_prompts.cancel("Cancelled");
25
+ return;
26
+ }
27
+ if (confirm) shell = detectedShell;
28
+ else {
29
+ const chosen = await _clack_prompts.select({
30
+ message: "Select your shell",
31
+ options: [{
32
+ value: "zsh",
33
+ label: "zsh"
34
+ }, {
35
+ value: "bash",
36
+ label: "bash"
37
+ }]
38
+ });
39
+ if (_clack_prompts.isCancel(chosen)) {
40
+ _clack_prompts.cancel("Cancelled");
41
+ return;
42
+ }
43
+ shell = chosen;
44
+ }
45
+ } else {
46
+ const chosen = await _clack_prompts.select({
47
+ message: "Select your shell",
48
+ options: [{
49
+ value: "zsh",
50
+ label: "zsh"
51
+ }, {
52
+ value: "bash",
53
+ label: "bash"
54
+ }]
55
+ });
56
+ if (_clack_prompts.isCancel(chosen)) {
57
+ _clack_prompts.cancel("Cancelled");
58
+ return;
59
+ }
60
+ shell = chosen;
61
+ }
62
+ const s = _clack_prompts.spinner();
63
+ s.start("Building completion cache...");
64
+ try {
65
+ await this.config.runCommand("autocomplete:create", []);
66
+ s.stop("Completion cache built");
67
+ } catch (err) {
68
+ s.stop("Failed to build completion cache");
69
+ this.error(`Could not build completion cache: ${err instanceof Error ? err.message : String(err)}`, { exit: 1 });
70
+ return;
71
+ }
72
+ const rcFile = shell === "zsh" ? "~/.zshrc" : "~/.bashrc";
73
+ const evalLine = `printf "$(twentythree autocomplete script ${shell})" >> ${rcFile}; source ${rcFile}`;
74
+ _clack_prompts.note(`Add tab completion to your shell by running:\n\n ${evalLine}\n\nThen restart your terminal or run: source ${rcFile}`, "Setup instructions");
75
+ _clack_prompts.outro("After setup, try: twentythree video <TAB>");
76
+ }
77
+ };
78
+ //#endregion
79
+ module.exports = Autocomplete;
@@ -52,7 +52,7 @@ var VideoList = class VideoList extends require_lib_base_command.AuthenticatedCo
52
52
  async run() {
53
53
  const { flags } = await this.parse(VideoList);
54
54
  this.printWorkspaceHeader();
55
- const videos = await require_lib_pagination.fetchAllPages(async (page, size) => {
55
+ const allVideos = await require_lib_pagination.fetchAllPages(async (page, size) => {
56
56
  const { data, error } = await this.apiClient.GET("/photo/list", { params: { query: {
57
57
  p: page,
58
58
  size,
@@ -65,6 +65,7 @@ var VideoList = class VideoList extends require_lib_base_command.AuthenticatedCo
65
65
  total_count: resp?.total_count
66
66
  };
67
67
  });
68
+ const videos = flags.limit !== void 0 ? allVideos.slice(0, flags.limit) : allVideos;
68
69
  if (this.jsonEnabled()) return require_lib_output.formatJsonOutput({
69
70
  ok: true,
70
71
  data: videos,
@@ -81,7 +81,7 @@ var VideoReplace = class VideoReplace extends require_lib_base_command.Authentic
81
81
  this.error(`File not found: ${args.file}`, { exit: 1 });
82
82
  }
83
83
  const { data: tokenData, error: tokenError } = await this.apiClient.GET("/photo/get-replace-token", { params: { query: { photo_id: Number(args.id) } } });
84
- if (tokenError) this.error(require_lib_term_map.applyCliTerms(String(tokenError)), { exit: 1 });
84
+ if (tokenError) this.error(require_lib_term_map.applyCliTerms(require_lib_output.formatApiError(tokenError)), { exit: 1 });
85
85
  const replaceToken = tokenData?.data?.replace_token;
86
86
  if (!replaceToken) this.error("Failed to obtain replace token from API", { exit: 1 });
87
87
  const totalBytes = (await (0, node_fs_promises.stat)(args.file)).size;
@@ -107,6 +107,7 @@ var VideoReplace = class VideoReplace extends require_lib_base_command.Authentic
107
107
  } finally {
108
108
  bar.finish();
109
109
  }
110
+ if (!result) return;
110
111
  const adminUrl = `https://${this.activeWorkspace.domain}/manage/video/${args.id}`;
111
112
  this.log(chalk.default.green(`Video ${args.id} replaced successfully`));
112
113
  this.log(`ID: ${args.id}`);
@@ -146,9 +146,12 @@ var VideoUpdate = class VideoUpdate extends require_lib_base_command.Authenticat
146
146
  initialValue: current.published_p ? "yes" : "no"
147
147
  });
148
148
  if ((0, _clack_prompts.isCancel)(publishedResult)) process.exit(2);
149
- body.title = titleResult;
150
- body.description = descriptionResult;
151
- body.tags = tagsResult;
149
+ const titleVal = titleResult;
150
+ const descriptionVal = descriptionResult;
151
+ const tagsVal = tagsResult;
152
+ if (titleVal !== "") body.title = titleVal;
153
+ if (descriptionVal !== "" || current.content_text === "") body.description = descriptionVal;
154
+ if (tagsVal !== "" || currentTags === "") body.tags = tagsVal;
152
155
  body.published_p = publishedResult === "yes" ? 1 : 0;
153
156
  } else {
154
157
  if (flags.title !== void 0) body.title = flags.title;
@@ -167,7 +170,7 @@ var VideoUpdate = class VideoUpdate extends require_lib_base_command.Authenticat
167
170
  body,
168
171
  headers: { "Content-Type": "application/x-www-form-urlencoded" }
169
172
  });
170
- if (updateError) this.error(require_lib_term_map.applyCliTerms(String(updateError)), { exit: 1 });
173
+ if (updateError) this.error(require_lib_term_map.applyCliTerms(require_lib_output.formatApiError(updateError)), { exit: 1 });
171
174
  this.log(chalk.default.green(`Video ${args.id} updated`));
172
175
  if (this.jsonEnabled()) return require_lib_output.formatJsonOutput({
173
176
  ok: true,
@@ -49,7 +49,10 @@ var WebinarMailPreview = class WebinarMailPreview extends require_lib_base_comma
49
49
  const { args, flags } = await this.parse(WebinarMailPreview);
50
50
  this.printWorkspaceHeader();
51
51
  const contextField = flags["webinar-id"] ? { live_id: Number(flags["webinar-id"]) } : flags["series-id"] ? { live_series_id: Number(flags["series-id"]) } : null;
52
- if (!contextField) this.error(require_lib_term_map.applyCliTerms("Either --webinar-id or --series-id is required"), { exit: 1 });
52
+ if (!contextField) {
53
+ this.error(require_lib_term_map.applyCliTerms("Either --webinar-id or --series-id is required"), { exit: 1 });
54
+ return;
55
+ }
53
56
  const query = new URLSearchParams({
54
57
  ...Object.fromEntries(Object.entries(contextField).map(([k, v]) => [k, String(v)])),
55
58
  live_mail_id: String(args.id)
@@ -57,8 +60,18 @@ var WebinarMailPreview = class WebinarMailPreview extends require_lib_base_comma
57
60
  const headers = {};
58
61
  if (this.activeWorkspace.bearer_token) headers["Authorization"] = `Bearer ${this.activeWorkspace.bearer_token}`;
59
62
  const response = await fetch(`${this.apiBaseUrl}live/mail/preview?${query}`, { headers });
60
- const html = await response.text();
61
- if (!response.ok) this.error(require_lib_term_map.applyCliTerms(`API error ${response.status}: ${html}`), { exit: 1 });
63
+ const body = await response.text();
64
+ if (!response.ok) {
65
+ let errMsg;
66
+ try {
67
+ const parsed = JSON.parse(body);
68
+ errMsg = parsed?.message ?? parsed?.error ?? `status ${response.status}`;
69
+ } catch {
70
+ errMsg = body.slice(0, 200) || `status ${response.status}`;
71
+ }
72
+ this.error(require_lib_term_map.applyCliTerms(`API error: ${errMsg}`), { exit: 1 });
73
+ }
74
+ const html = body;
62
75
  if (this.jsonEnabled()) return require_lib_output.formatJsonOutput({
63
76
  ok: true,
64
77
  data: html,
@@ -35,7 +35,21 @@ twentythree workspace list
35
35
  twentythree workspace use company.video23.com
36
36
  ```
37
37
 
38
- ## Step 3: Run your first command
38
+ ## Step 3: Enable tab completion (optional)
39
+
40
+ Run this once to set up `<TAB>` completion for all commands and flags:
41
+
42
+ ```bash
43
+ twentythree autocomplete
44
+ ```
45
+
46
+ The command detects your shell (bash or zsh), builds the completion cache, and shows the eval line to paste into your RC file. After sourcing your RC file or restarting your terminal, try:
47
+
48
+ ```bash
49
+ twentythree video <TAB>
50
+ ```
51
+
52
+ ## Step 4: Run your first command
39
53
 
40
54
  List the videos in your active workspace.
41
55
 
@@ -64,3 +78,5 @@ Run `twentythree <topic> --help` for help on any topic. For example:
64
78
  twentythree video --help
65
79
  twentythree auth --help
66
80
  ```
81
+
82
+ Use `<TAB>` after any command to discover subcommands and flags.