bdy 1.25.6-dev → 1.25.8-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/distTs/package.json +1 -1
  2. package/distTs/src/cliCommand.js +43 -0
  3. package/distTs/src/cliIndex.js +10 -0
  4. package/distTs/src/command/agent/uninstall.js +1 -1
  5. package/distTs/src/command/artifact/delete.js +1 -2
  6. package/distTs/src/command/artifact/version/delete.js +1 -2
  7. package/distTs/src/command/context/add.js +38 -0
  8. package/distTs/src/command/context/list.js +33 -0
  9. package/distTs/src/command/context/remove.js +35 -0
  10. package/distTs/src/command/context/show.js +35 -0
  11. package/distTs/src/command/context/use.js +25 -0
  12. package/distTs/src/command/context.js +22 -0
  13. package/distTs/src/command/distro/delete.js +1 -2
  14. package/distTs/src/command/distro/route/delete.js +1 -2
  15. package/distTs/src/command/environment/delete.js +1 -2
  16. package/distTs/src/command/login.js +1 -0
  17. package/distTs/src/command/logout.js +1 -0
  18. package/distTs/src/command/pipeline/delete.js +1 -2
  19. package/distTs/src/command/pipeline/run/approve.js +3 -2
  20. package/distTs/src/command/pipeline/run/cancel.js +3 -2
  21. package/distTs/src/command/pipeline/run/find.js +87 -0
  22. package/distTs/src/command/pipeline/run/findFilters.js +68 -0
  23. package/distTs/src/command/pipeline/run/retry.js +5 -2
  24. package/distTs/src/command/pipeline/run/start.js +3 -2
  25. package/distTs/src/command/pipeline/run/status.js +3 -2
  26. package/distTs/src/command/pipeline/run.js +3 -0
  27. package/distTs/src/command/project/link.js +1 -0
  28. package/distTs/src/command/register.js +1 -0
  29. package/distTs/src/command/sandbox/destroy.js +1 -2
  30. package/distTs/src/command/sandbox/endpoint/delete.js +1 -2
  31. package/distTs/src/command/sandbox/exec/kill.js +1 -2
  32. package/distTs/src/command/sandbox/snapshot/delete.js +1 -2
  33. package/distTs/src/command/target/delete.js +1 -1
  34. package/distTs/src/command/target/exec/kill.js +2 -3
  35. package/distTs/src/command/whoami.js +7 -10
  36. package/distTs/src/command/workspace/get.js +2 -2
  37. package/distTs/src/command/workspace/set.js +1 -0
  38. package/distTs/src/input.js +240 -26
  39. package/distTs/src/output/pipeline.js +84 -13
  40. package/distTs/src/output.js +24 -5
  41. package/distTs/src/project/context.js +97 -0
  42. package/distTs/src/texts.js +275 -29
  43. package/distTs/src/tunnel/cfg.js +43 -4
  44. package/distTs/src/types/context.js +2 -0
  45. package/distTs/src/types/pipelineRunFind.js +2 -0
  46. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.25.6-dev",
4
+ "version": "1.25.8-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -52,11 +52,17 @@ class CliCommand extends commander_1.Command {
52
52
  hideVersionUpdate;
53
53
  agentPort;
54
54
  skipPre = false;
55
+ usesDefaultContext = false;
55
56
  defaultErrorFormat = 'text';
56
57
  metadata;
57
58
  constructor(name, metadata = {}) {
58
59
  super(name);
59
60
  this.metadata = metadata;
61
+ // Route options after a subcommand name to that subcommand, including
62
+ // --examples and its format, instead of consuming them in a parent group.
63
+ this.enablePositionalOptions();
64
+ this.option('--context <name>', texts_1.OPTION_CONTEXT);
65
+ this.option('--examples', texts_1.OPTION_EXAMPLES);
60
66
  }
61
67
  addOption(option) {
62
68
  if (option.long === '--format' && !option.argChoices) {
@@ -69,6 +75,43 @@ class CliCommand extends commander_1.Command {
69
75
  parseOptions(args) {
70
76
  output_1.default.errorFormat = this.defaultErrorFormat;
71
77
  output_1.default.errorExitCode = 1;
78
+ const delimiter = args.indexOf('--');
79
+ const optionArgs = delimiter < 0 ? args : args.slice(0, delimiter);
80
+ const examplesIndex = optionArgs.indexOf('--examples');
81
+ let subcommandBeforeExamples = false;
82
+ for (let i = 0; i < examplesIndex; i += 1) {
83
+ const arg = optionArgs[i];
84
+ const option = this.options.find((item) => item.long === arg || item.short === arg);
85
+ if (option?.required || option?.optional) {
86
+ i += 1;
87
+ }
88
+ else if (this.commands.some((child) => child.name() === arg || child.aliases().includes(arg))) {
89
+ subcommandBeforeExamples = true;
90
+ break;
91
+ }
92
+ }
93
+ if (examplesIndex >= 0 &&
94
+ !optionArgs.includes('--help') &&
95
+ !optionArgs.includes('-h') &&
96
+ !subcommandBeforeExamples) {
97
+ const formats = optionArgs.flatMap((arg, index) => arg === '--format'
98
+ ? [optionArgs[index + 1]]
99
+ : arg.startsWith('--format=')
100
+ ? [arg.slice('--format='.length)]
101
+ : []);
102
+ const format = formats.length ? formats.at(-1) : 'text';
103
+ if (typeof format !== 'string' || !['text', 'json', 'jsonl'].includes(format)) {
104
+ this.error(`Invalid examples format '${format}'. Choose text, json or jsonl.`);
105
+ }
106
+ const path = [this.name()];
107
+ let parent = this.parent;
108
+ while (parent) {
109
+ path.unshift(parent.name());
110
+ parent = parent.parent;
111
+ }
112
+ output_1.default.examples(path.join(' '), this.examples, format);
113
+ output_1.default.exitNormal();
114
+ }
72
115
  const formatOption = this.options.find((option) => option.long === '--format');
73
116
  const exitCodeOption = this.options.some((option) => option.long === '--exit-code');
74
117
  if ((formatOption && this.defaultErrorFormat === 'text') ||
@@ -30,10 +30,19 @@ const environment_1 = __importDefault(require("./command/environment"));
30
30
  const register_1 = __importDefault(require("./command/register"));
31
31
  const mcp_1 = __importDefault(require("./command/mcp"));
32
32
  const discover_1 = __importDefault(require("./command/discover"));
33
+ const context_1 = __importDefault(require("./command/context"));
34
+ const input_1 = __importDefault(require("./input"));
33
35
  const cliError_1 = __importDefault(require("./cliError"));
36
+ const cliCommand_1 = __importDefault(require("./cliCommand"));
34
37
  const texts_2 = require("./texts");
35
38
  function cliIndex() {
36
39
  const program = (0, utils_1.newCommand)('bdy', texts_1.DESC_PROGRAM);
40
+ program.hook('preAction', (_, command) => {
41
+ const options = command.optsWithGlobals();
42
+ input_1.default.configureContext(command instanceof cliCommand_1.default && command.usesDefaultContext
43
+ ? { ...options, context: 'default' }
44
+ : options);
45
+ });
37
46
  program.hook('preAction', pre_1.default);
38
47
  program.configureHelp({
39
48
  formatHelp: utils_1.formatHelp,
@@ -65,6 +74,7 @@ function cliIndex() {
65
74
  program.addCommand(api_1.default);
66
75
  program.addCommand(mcp_1.default);
67
76
  program.addCommand(discover_1.default);
77
+ program.addCommand(context_1.default);
68
78
  program.action((_, cmd) => {
69
79
  if (cmd.args.length > 0) {
70
80
  output_1.default.exitError(new cliError_1.default('unknown_command', (0, texts_1.ERR_COMMAND_NOT_FOUND)(cmd.args[0]), (0, texts_2.TXT_CLI_USAGE_HINT)('bdy')));
@@ -16,7 +16,7 @@ commandAgentUninstall.action(async (options) => {
16
16
  if (!hasRights) {
17
17
  output_1.default.exitError(texts_1.ERR_AGENT_ADMIN_RIGHTS);
18
18
  }
19
- const confirmed = options.force || (await output_1.default.confirm(texts_1.TXY_AGENT_CONFIRM_DELETE));
19
+ const confirmed = await output_1.default.confirmDestructive(options.force, texts_1.TXY_AGENT_CONFIRM_DELETE);
20
20
  if (!confirmed)
21
21
  output_1.default.exitNormal();
22
22
  try {
@@ -30,8 +30,7 @@ commandArtifactDelete.action(async (identifier, options) => {
30
30
  if (!data.artifact_id) {
31
31
  output_1.default.exitError(texts_1.ERR_ARTIFACT_NOT_FOUND);
32
32
  }
33
- const confirmed = options.force ||
34
- (await output_1.default.confirm((0, texts_1.TXT_ARTIFACT_DELETE_CONFIRM)(identifier)));
33
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_ARTIFACT_DELETE_CONFIRM)(identifier));
35
34
  if (confirmed) {
36
35
  await client.deleteArtifact(workspace, data.artifact_id);
37
36
  output_1.default.exitSuccess(texts_1.TXT_ARTIFACT_DELETED);
@@ -34,8 +34,7 @@ commandArtifactVersionDelete.action(async (identifier, version, options) => {
34
34
  if (!data || !data.artifact_version_id) {
35
35
  output_1.default.exitError(texts_1.ERR_ARTIFACT_VERSION_NOT_FOUND);
36
36
  }
37
- const confirmed = options.force ||
38
- (await output_1.default.confirm((0, texts_1.TXT_ARTIFACT_VERSION_DELETE_CONFIRM)(identifier, version)));
37
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_ARTIFACT_VERSION_DELETE_CONFIRM)(identifier, version));
39
38
  if (!confirmed)
40
39
  output_1.default.exitNormal();
41
40
  await client.deleteArtifactVersion(workspace, data.artifact_id, data.artifact_version_id);
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const input_1 = __importDefault(require("../../input"));
8
+ const output_1 = __importDefault(require("../../output"));
9
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
10
+ const cliError_1 = __importDefault(require("../../cliError"));
11
+ const texts_1 = require("../../texts");
12
+ const command = (0, utils_1.newCommand)('add', texts_1.DESC_CONTEXT_ADD, {
13
+ requiredScopes: [],
14
+ examples: texts_1.EXAMPLE_CONTEXT_ADD,
15
+ helpText: texts_1.HELP_CONTEXT_ADD,
16
+ });
17
+ command.skipPre = true;
18
+ command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
19
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
20
+ command.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
21
+ command.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
22
+ command.option('--token <token>', texts_1.OPTION_CONTEXT_TOKEN);
23
+ command.option('--api <endpoint>', texts_1.OPTION_CONTEXT_API);
24
+ command.option('--from-link', texts_1.OPTION_CONTEXT_LINK);
25
+ command.option('--from-git', texts_1.OPTION_CONTEXT_GIT);
26
+ command.option('--remote <name>', texts_1.OPTION_CONTEXT_REMOTE);
27
+ command.action((name, options) => {
28
+ input_1.default.contextEditableName(name);
29
+ if (Object.hasOwn(cfg_1.default.getContexts(), name))
30
+ throw new cliError_1.default('usage_error', (0, texts_1.ERR_CONTEXT_EXISTS)(name));
31
+ const context = input_1.default.contextDefinition(options);
32
+ cfg_1.default.setContext(name, context);
33
+ if (options.format === 'json')
34
+ output_1.default.json({ name, source: context.source });
35
+ else
36
+ output_1.default.normal((0, texts_1.TXT_CONTEXT_SAVED)(name));
37
+ });
38
+ exports.default = command;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const output_1 = __importDefault(require("../../output"));
8
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
9
+ const texts_1 = require("../../texts");
10
+ const command = (0, utils_1.newCommand)('list', texts_1.DESC_CONTEXT_LIST, {
11
+ requiredScopes: [],
12
+ examples: texts_1.EXAMPLE_CONTEXT_LIST,
13
+ helpText: texts_1.HELP_CONTEXT_LIST,
14
+ });
15
+ command.skipPre = true;
16
+ command.alias('ls');
17
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
18
+ command.action((options) => {
19
+ const builtins = ['default', 'git', 'link'];
20
+ const active = cfg_1.default.getActiveContext();
21
+ const values = [...builtins, ...Object.keys(cfg_1.default.getContexts()).sort()].map((name) => ({
22
+ name,
23
+ active: name === active,
24
+ builtin: builtins.includes(name),
25
+ source: cfg_1.default.getContext(name)?.source || 'default',
26
+ }));
27
+ if (options.format === 'json')
28
+ output_1.default.json(values);
29
+ else
30
+ for (const item of values)
31
+ output_1.default.normal(`${item.active ? '*' : ' '} ${item.name}`);
32
+ });
33
+ exports.default = command;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const input_1 = __importDefault(require("../../input"));
8
+ const output_1 = __importDefault(require("../../output"));
9
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
10
+ const texts_1 = require("../../texts");
11
+ const command = (0, utils_1.newCommand)('remove', texts_1.DESC_CONTEXT_REMOVE, {
12
+ requiredScopes: [],
13
+ examples: texts_1.EXAMPLE_CONTEXT_REMOVE,
14
+ helpText: texts_1.HELP_CONTEXT_REMOVE,
15
+ });
16
+ command.skipPre = true;
17
+ command.alias('rm');
18
+ command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
19
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
20
+ command.option('-f, --force', texts_1.OPTION_CONFIRM_FORCE);
21
+ command.action(async (name, options) => {
22
+ input_1.default.contextEditableName(name);
23
+ cfg_1.default.getContext(name);
24
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_CONTEXT_REMOVE_CONFIRM)(name), options.format === 'json');
25
+ if (confirmed)
26
+ cfg_1.default.removeContext(name);
27
+ if (options.format === 'json')
28
+ output_1.default.json({
29
+ removed: confirmed ? name : null,
30
+ active: cfg_1.default.getActiveContext(),
31
+ });
32
+ else if (confirmed)
33
+ output_1.default.normal((0, texts_1.TXT_CONTEXT_REMOVED)(name));
34
+ });
35
+ exports.default = command;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const input_1 = __importDefault(require("../../input"));
8
+ const output_1 = __importDefault(require("../../output"));
9
+ const texts_1 = require("../../texts");
10
+ const command = (0, utils_1.newCommand)('show', texts_1.DESC_CONTEXT_SHOW, {
11
+ requiredScopes: [],
12
+ examples: texts_1.EXAMPLE_CONTEXT_SHOW,
13
+ helpText: texts_1.HELP_CONTEXT_SHOW,
14
+ });
15
+ command.skipPre = true;
16
+ command.argument('[name]', texts_1.OPTION_CONTEXT_NAME);
17
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
18
+ command.action((name, options, cmd) => {
19
+ if (name)
20
+ input_1.default.configureContext({ ...cmd.optsWithGlobals(), context: name });
21
+ const result = input_1.default.showContext();
22
+ if (options.format === 'json')
23
+ output_1.default.json(result);
24
+ else
25
+ output_1.default.object({
26
+ [texts_1.TXT_CONTEXT_LABEL]: result.name,
27
+ [texts_1.TXT_CONTEXT_SOURCE_LABEL]: result.source,
28
+ [texts_1.TXT_CONTEXT_WORKSPACE_LABEL]: `${result.workspace || '-'} (${result.sources.workspace || '-'})`,
29
+ [texts_1.TXT_CONTEXT_PROJECT_LABEL]: `${result.project || '-'} (${result.sources.project || '-'})`,
30
+ [texts_1.TXT_CONTEXT_API_LABEL]: `${result.api} (${result.sources.api})`,
31
+ [texts_1.TXT_CONTEXT_REMOTE_LABEL]: result.remote || '-',
32
+ [texts_1.TXT_CONTEXT_TOKEN_LABEL]: `${result.token.available ? texts_1.TXT_CONTEXT_TOKEN_AVAILABLE : texts_1.TXT_CONTEXT_TOKEN_MISSING} (${result.token.source || '-'})`,
33
+ });
34
+ });
35
+ exports.default = command;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../utils");
7
+ const output_1 = __importDefault(require("../../output"));
8
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
9
+ const texts_1 = require("../../texts");
10
+ const command = (0, utils_1.newCommand)('use', texts_1.DESC_CONTEXT_USE, {
11
+ requiredScopes: [],
12
+ examples: texts_1.EXAMPLE_CONTEXT_USE,
13
+ helpText: texts_1.HELP_CONTEXT_USE,
14
+ });
15
+ command.skipPre = true;
16
+ command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
17
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
18
+ command.action((name, options) => {
19
+ cfg_1.default.setActiveContext(name);
20
+ if (options.format === 'json')
21
+ output_1.default.json({ active: name });
22
+ else
23
+ output_1.default.normal((0, texts_1.TXT_CONTEXT_ACTIVE)(name));
24
+ });
25
+ exports.default = command;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../utils");
7
+ const texts_1 = require("../texts");
8
+ const add_1 = __importDefault(require("./context/add"));
9
+ const list_1 = __importDefault(require("./context/list"));
10
+ const show_1 = __importDefault(require("./context/show"));
11
+ const use_1 = __importDefault(require("./context/use"));
12
+ const remove_1 = __importDefault(require("./context/remove"));
13
+ const commandContext = (0, utils_1.newCommand)('context', texts_1.DESC_CONTEXT, {
14
+ requiredScopes: [],
15
+ helpText: texts_1.HELP_CONTEXT,
16
+ });
17
+ commandContext.addCommand(add_1.default);
18
+ commandContext.addCommand(list_1.default);
19
+ commandContext.addCommand(show_1.default);
20
+ commandContext.addCommand(use_1.default);
21
+ commandContext.addCommand(remove_1.default);
22
+ exports.default = commandContext;
@@ -30,8 +30,7 @@ commandDistroDelete.action(async (identifier, options) => {
30
30
  if (!data || !data.distribution_id) {
31
31
  output_1.default.exitError(texts_1.ERR_COMMAND_DISTRO_NOT_FOUND);
32
32
  }
33
- const confirmed = options.force ||
34
- (await output_1.default.confirm((0, texts_1.TXT_COMMAND_DISTRO_DELETE_CONFIRM)(identifier)));
33
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_COMMAND_DISTRO_DELETE_CONFIRM)(identifier));
35
34
  if (confirmed) {
36
35
  await client.deleteDistribution(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, data.distribution_id);
37
36
  output_1.default.exitSuccess(texts_1.TXT_COMMAND_DISTRO_DELETED);
@@ -31,8 +31,7 @@ commandDistroRouteDelete.action(async (identifier, routeId, options) => {
31
31
  if (!data?.distribution_id) {
32
32
  output_1.default.exitError(texts_1.ERR_COMMAND_DISTRO_NOT_FOUND);
33
33
  }
34
- const confirmed = options.force ||
35
- (await output_1.default.confirm((0, texts_1.TXT_COMMAND_ROUTE_DELETE_CONFIRM)(identifier, routeId)));
34
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_COMMAND_ROUTE_DELETE_CONFIRM)(identifier, routeId));
36
35
  if (confirmed) {
37
36
  await client.deleteRoute(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, data.distribution_id, routeId);
38
37
  output_1.default.exitSuccess(texts_1.TXT_COMMAND_ROUTE_DELETED);
@@ -18,8 +18,7 @@ commandEnvironmentDelete.action(async (identifier, options) => {
18
18
  const client = input_1.default.restApiTokenClient();
19
19
  const environment_id = await input_1.default.environmentId(client, workspace, identifier, options,
20
20
  /* strictProject */ true);
21
- const confirmed = options.force ||
22
- (await output_1.default.confirm((0, texts_1.TXT_ENVIRONMENT_DELETE_CONFIRM)(identifier)));
21
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_ENVIRONMENT_DELETE_CONFIRM)(identifier));
23
22
  if (!confirmed)
24
23
  output_1.default.exitNormal();
25
24
  await client.deleteEnvironment(workspace, environment_id);
@@ -293,6 +293,7 @@ async function authorize(options, forceRegisterEmail, forceRegisterName) {
293
293
  }
294
294
  }
295
295
  const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
296
+ commandLogin.usesDefaultContext = true;
296
297
  commandLogin.alias('sign-in');
297
298
  commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
298
299
  commandLogin.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
@@ -9,6 +9,7 @@ const texts_1 = require("../texts");
9
9
  const utils_1 = require("../utils");
10
10
  const input_1 = __importDefault(require("../input"));
11
11
  const commandLogout = (0, utils_1.newCommand)('logout', texts_1.DESC_COMMAND_LOGOUT);
12
+ commandLogout.usesDefaultContext = true;
12
13
  const tryRemovingApp = async () => {
13
14
  try {
14
15
  const clientId = cfg_1.default.getApiClientId();
@@ -30,8 +30,7 @@ commandPipelineDelete.action(async (identifier, options) => {
30
30
  if (!data.pipeline_id) {
31
31
  output_1.default.exitError(texts_1.ERR_PIPELINE_NOT_FOUND);
32
32
  }
33
- const confirmed = options.force ||
34
- (await output_1.default.confirm((0, texts_1.TXT_PIPELINE_DELETE_CONFIRM)(identifier)));
33
+ const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_PIPELINE_DELETE_CONFIRM)(identifier));
35
34
  if (confirmed) {
36
35
  await client.deletePipeline(workspace, project, data.pipeline_id);
37
36
  output_1.default.exitSuccess(texts_1.TXT_PIPELINE_DELETED);
@@ -12,13 +12,14 @@ const pipeline_1 = require("../../../types/pipeline");
12
12
  const commandPipelineRunApprove = (0, utils_1.newCommand)('approve', texts_1.DESC_COMMAND_PIPELINE_RUN_APPLY, {
13
13
  requiredScopes: [utils_1.REST_API_SCOPE.PIPELINE_RUN],
14
14
  examples: texts_1.EXAMPLE_PIPELINE_RUN_APPLY,
15
- helpText: texts_1.HELP_PIPELINE_RUN_STATUS,
15
+ helpText: texts_1.HELP_PIPELINE_RUN_STATUS + texts_1.HELP_PIPELINE_RUN_FAILED_LOGS,
16
16
  });
17
17
  commandPipelineRunApprove.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
18
18
  commandPipelineRunApprove.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
19
19
  commandPipelineRunApprove.option('-n, --no-wait', texts_1.OPTION_PIPELINE_RUN_NO_WAIT);
20
20
  commandPipelineRunApprove.option('--no-follow', texts_1.OPTION_PIPELINE_RUN_NO_FOLLOW);
21
21
  commandPipelineRunApprove.option('--exit-code', texts_1.OPTION_EXEC_EXIT_CODE);
22
+ commandPipelineRunApprove.option('--failed-logs', texts_1.OPTION_PIPELINE_RUN_FAILED_LOGS);
22
23
  commandPipelineRunApprove.option('--format <text|jsonl>', texts_1.OPTION_EXEC_FORMAT_JSONL);
23
24
  commandPipelineRunApprove.argument('<identifier>', texts_1.OPTION_PIPELINE_IDENTIFIER);
24
25
  commandPipelineRunApprove.argument('<run-id>', texts_1.OPTION_PIPELINE_RUN_ID);
@@ -55,6 +56,6 @@ commandPipelineRunApprove.action(async (identifier, runId, runActionId, options)
55
56
  };
56
57
  await client.pipelineRunApply(workspace, project, pipelineId, rid, body);
57
58
  const OutputPipeline = require('../../../output/pipeline').default;
58
- await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode);
59
+ await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode, !!options.failedLogs);
59
60
  });
60
61
  exports.default = commandPipelineRunApprove;
@@ -10,13 +10,14 @@ const execution_1 = require("./execution");
10
10
  const commandPipelineRunCancel = (0, utils_1.newCommand)('cancel', texts_1.DESC_COMMAND_PIPELINE_RUN_CANCEL, {
11
11
  requiredScopes: [utils_1.REST_API_SCOPE.PIPELINE_RUN],
12
12
  examples: texts_1.EXAMPLE_PIPELINE_RUN_CANCEL,
13
- helpText: texts_1.HELP_PIPELINE_RUN_STATUS,
13
+ helpText: texts_1.HELP_PIPELINE_RUN_STATUS + texts_1.HELP_PIPELINE_RUN_FAILED_LOGS,
14
14
  });
15
15
  commandPipelineRunCancel.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
16
16
  commandPipelineRunCancel.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
17
17
  commandPipelineRunCancel.option('-n, --no-wait', texts_1.OPTION_PIPELINE_RUN_NO_WAIT);
18
18
  commandPipelineRunCancel.option('--no-follow', texts_1.OPTION_PIPELINE_RUN_NO_FOLLOW);
19
19
  commandPipelineRunCancel.option('--exit-code', texts_1.OPTION_EXEC_EXIT_CODE);
20
+ commandPipelineRunCancel.option('--failed-logs', texts_1.OPTION_PIPELINE_RUN_FAILED_LOGS);
20
21
  commandPipelineRunCancel.option('--format <text|jsonl>', texts_1.OPTION_EXEC_FORMAT_JSONL);
21
22
  commandPipelineRunCancel.argument('<identifier>', texts_1.OPTION_PIPELINE_IDENTIFIER);
22
23
  commandPipelineRunCancel.argument('<run-id>', texts_1.OPTION_PIPELINE_RUN_ID);
@@ -28,6 +29,6 @@ commandPipelineRunCancel.action(async (identifier, runId, options) => {
28
29
  const pipelineId = await (0, execution_1.resolvePipelineId)(client, workspace, project, identifier);
29
30
  await client.pipelineRunCancel(workspace, project, pipelineId, rid);
30
31
  const OutputPipeline = require('../../../output/pipeline').default;
31
- await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode);
32
+ await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode, !!options.failedLogs);
32
33
  });
33
34
  exports.default = commandPipelineRunCancel;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../../utils");
7
+ const input_1 = __importDefault(require("../../../input"));
8
+ const output_1 = __importDefault(require("../../../output"));
9
+ const execution_1 = require("./execution");
10
+ const findFilters_1 = require("./findFilters");
11
+ const texts_1 = require("../../../texts");
12
+ const command = (0, utils_1.newCommand)('find', texts_1.DESC_COMMAND_PIPELINE_RUN_FIND, {
13
+ requiredScopes: [utils_1.REST_API_SCOPE.PIPELINE_READ],
14
+ examples: texts_1.EXAMPLE_PIPELINE_RUN_FIND,
15
+ helpText: texts_1.HELP_PIPELINE_RUN_FIND,
16
+ });
17
+ command.argument('<identifier>', texts_1.OPTION_PIPELINE_IDENTIFIER);
18
+ command.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
19
+ command.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
20
+ command.option('--last <number>', texts_1.OPTION_PIPELINE_RUN_FIND_LAST, '100');
21
+ for (const { flag, argument, description } of findFilters_1.pipelineRunFindFilters) {
22
+ command.option(`${flag} ${argument}`, description);
23
+ }
24
+ command.option('--format <text|json>', texts_1.OPTION_FORMAT);
25
+ command.action(async (identifier, options) => {
26
+ const { last, filters } = input_1.default.pipelineRunFind(options);
27
+ const workspace = input_1.default.restApiWorkspace(options.workspace);
28
+ const project = input_1.default.restApiProject(options.project);
29
+ const client = input_1.default.restApiTokenClient();
30
+ const pipelineId = await (0, execution_1.resolvePipelineId)(client, workspace, project, identifier);
31
+ const executions = [];
32
+ // Keep page size fixed: changing it on the last request changes page offsets.
33
+ const perPage = Math.min(last, 100);
34
+ const seen = new Set();
35
+ let scanned = 0;
36
+ let fetched = 0;
37
+ let hasMore = false;
38
+ for (let page = 1; scanned < last; page += 1) {
39
+ const result = await client.getPipelineRuns(workspace, project, pipelineId, page, perPage);
40
+ const batch = result.executions;
41
+ fetched += batch.length;
42
+ let hasMoreInBatch = false;
43
+ for (const run of batch) {
44
+ // New runs shift page offsets; repeated IDs must not consume the window.
45
+ if (seen.has(run.id))
46
+ continue;
47
+ if (scanned === last) {
48
+ hasMoreInBatch = true;
49
+ break;
50
+ }
51
+ seen.add(run.id);
52
+ scanned += 1;
53
+ if (findFilters_1.pipelineRunFindFilters.every(({ key, pick }) => {
54
+ const value = filters[key];
55
+ return value === undefined || pick(run).includes(value);
56
+ }))
57
+ executions.push(run);
58
+ }
59
+ if (!batch.length) {
60
+ hasMore = false;
61
+ break;
62
+ }
63
+ // Compare pagination progress (including duplicates) with the current total.
64
+ // total_page_count may be absent or based on an uncapped size.
65
+ const total = result.total_element_count;
66
+ const hasTotal = typeof total === 'number' && Number.isInteger(total) && total >= 0;
67
+ hasMore = hasMoreInBatch || !hasTotal || fetched < total;
68
+ if (!hasMore)
69
+ break;
70
+ if (scanned === last && !hasTotal && !hasMoreInBatch) {
71
+ // Without a total, probe for existence only. These runs are not searched
72
+ // or included in scanned; even a short page does not prove exhaustion.
73
+ const next = await client.getPipelineRuns(workspace, project, pipelineId, page + 1, perPage);
74
+ hasMore = next.executions.some((run) => !seen.has(run.id));
75
+ }
76
+ }
77
+ executions.sort((a, b) => b.id - a.id);
78
+ const result = { last, scanned, has_more: hasMore, executions };
79
+ if (options.format === 'json')
80
+ output_1.default.json(result);
81
+ else {
82
+ const OutputPipeline = require('../../../output/pipeline').default;
83
+ OutputPipeline.findRuns(result);
84
+ }
85
+ output_1.default.exitNormal();
86
+ });
87
+ exports.default = command;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pipelineRunFindFilters = void 0;
4
+ const texts_1 = require("../../../texts");
5
+ /** One source for CLI options, validation names, filter types and matching. */
6
+ exports.pipelineRunFindFilters = [
7
+ {
8
+ key: 'branch',
9
+ flag: '--branch',
10
+ argument: '<name>',
11
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_BRANCH,
12
+ pick: (run) => [run.branch?.name],
13
+ },
14
+ {
15
+ key: 'tag',
16
+ flag: '--tag',
17
+ argument: '<name>',
18
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_TAG,
19
+ pick: (run) => [run.tag?.name],
20
+ },
21
+ {
22
+ key: 'pr',
23
+ flag: '--pr',
24
+ argument: '<number>',
25
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_PR,
26
+ pick: (run) => [run.pull_request?.name],
27
+ },
28
+ {
29
+ key: 'revision',
30
+ flag: '--revision',
31
+ argument: '<revision>',
32
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_REVISION,
33
+ pick: (run) => [run.to_revision?.revision],
34
+ },
35
+ {
36
+ key: 'fromRevision',
37
+ flag: '--from-revision',
38
+ argument: '<revision>',
39
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_FROM_REVISION,
40
+ pick: (run) => [run.from_revision?.revision],
41
+ },
42
+ {
43
+ key: 'environment',
44
+ flag: '--environment',
45
+ argument: '<identifier>',
46
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_ENVIRONMENT,
47
+ pick: (run) => [run.environment?.identifier],
48
+ },
49
+ {
50
+ key: 'artifact',
51
+ flag: '--artifact',
52
+ argument: '<identifier[:version]>',
53
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_ARTIFACT,
54
+ pick: (run) => [
55
+ run.artifact?.identifier,
56
+ run.artifact?.identifier && run.artifact_version?.version
57
+ ? `${run.artifact.identifier}:${run.artifact_version.version}`
58
+ : undefined,
59
+ ],
60
+ },
61
+ {
62
+ key: 'status',
63
+ flag: '--status',
64
+ argument: '<status>',
65
+ description: texts_1.OPTION_PIPELINE_RUN_FIND_STATUS,
66
+ pick: (run) => [run.status],
67
+ },
68
+ ];
@@ -10,13 +10,16 @@ const execution_1 = require("./execution");
10
10
  const commandPipelineRunRetry = (0, utils_1.newCommand)('retry', texts_1.DESC_COMMAND_PIPELINE_RUN_RETRY, {
11
11
  requiredScopes: [utils_1.REST_API_SCOPE.PIPELINE_RUN],
12
12
  examples: texts_1.EXAMPLE_PIPELINE_RUN_RETRY,
13
- helpText: texts_1.HELP_PIPELINE_RUN_STATUS,
13
+ helpText: texts_1.HELP_PIPELINE_RUN_STATUS +
14
+ texts_1.HELP_PIPELINE_RUN_FAILED_LOGS +
15
+ texts_1.HELP_PIPELINE_RUN_RETRY,
14
16
  });
15
17
  commandPipelineRunRetry.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
16
18
  commandPipelineRunRetry.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
17
19
  commandPipelineRunRetry.option('-n, --no-wait', texts_1.OPTION_PIPELINE_RUN_NO_WAIT);
18
20
  commandPipelineRunRetry.option('--no-follow', texts_1.OPTION_PIPELINE_RUN_NO_FOLLOW);
19
21
  commandPipelineRunRetry.option('--exit-code', texts_1.OPTION_EXEC_EXIT_CODE);
22
+ commandPipelineRunRetry.option('--failed-logs', texts_1.OPTION_PIPELINE_RUN_FAILED_LOGS);
20
23
  commandPipelineRunRetry.option('--format <text|jsonl>', texts_1.OPTION_EXEC_FORMAT_JSONL);
21
24
  commandPipelineRunRetry.argument('<identifier>', texts_1.OPTION_PIPELINE_IDENTIFIER);
22
25
  commandPipelineRunRetry.argument('<run-id>', texts_1.OPTION_PIPELINE_RUN_ID);
@@ -28,6 +31,6 @@ commandPipelineRunRetry.action(async (identifier, runId, options) => {
28
31
  const pipelineId = await (0, execution_1.resolvePipelineId)(client, workspace, project, identifier);
29
32
  await client.pipelineRunRetry(workspace, project, pipelineId, rid);
30
33
  const OutputPipeline = require('../../../output/pipeline').default;
31
- await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode);
34
+ await OutputPipeline.runStatus(client, workspace, project, identifier, pipelineId, rid, !options.wait, !options.follow, options.format === 'jsonl', !!options.exitCode, !!options.failedLogs);
32
35
  });
33
36
  exports.default = commandPipelineRunRetry;