@bussolabs/closeyourit-cli 0.22.0 → 0.23.1

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 (116) hide show
  1. package/README.md +44 -3
  2. package/dist/base.d.ts +23 -0
  3. package/dist/base.js +64 -4
  4. package/dist/commands/assistant/ask.d.ts +24 -0
  5. package/dist/commands/assistant/ask.js +112 -0
  6. package/dist/commands/assistant/conversations/create.d.ts +9 -0
  7. package/dist/commands/assistant/conversations/create.js +25 -0
  8. package/dist/commands/assistant/conversations/delete.d.ts +12 -0
  9. package/dist/commands/assistant/conversations/delete.js +25 -0
  10. package/dist/commands/assistant/conversations/list.d.ts +10 -0
  11. package/dist/commands/assistant/conversations/list.js +30 -0
  12. package/dist/commands/assistant/conversations/show.d.ts +9 -0
  13. package/dist/commands/assistant/conversations/show.js +25 -0
  14. package/dist/commands/errors/assign.d.ts +14 -0
  15. package/dist/commands/errors/assign.js +52 -0
  16. package/dist/commands/errors/bulk-triage.d.ts +11 -0
  17. package/dist/commands/errors/bulk-triage.js +41 -0
  18. package/dist/commands/errors/delete.d.ts +13 -0
  19. package/dist/commands/errors/delete.js +28 -0
  20. package/dist/commands/errors/grouping-rules/create.d.ts +15 -0
  21. package/dist/commands/errors/grouping-rules/create.js +44 -0
  22. package/dist/commands/errors/grouping-rules/delete.d.ts +13 -0
  23. package/dist/commands/errors/grouping-rules/delete.js +27 -0
  24. package/dist/commands/errors/grouping-rules/list.d.ts +10 -0
  25. package/dist/commands/errors/grouping-rules/list.js +28 -0
  26. package/dist/commands/errors/grouping-rules/update.d.ts +18 -0
  27. package/dist/commands/errors/grouping-rules/update.js +43 -0
  28. package/dist/commands/errors/merge.d.ts +14 -0
  29. package/dist/commands/errors/merge.js +39 -0
  30. package/dist/commands/errors/split.d.ts +13 -0
  31. package/dist/commands/errors/split.js +34 -0
  32. package/dist/commands/invitations/create.js +9 -2
  33. package/dist/commands/invitations/resend.js +8 -2
  34. package/dist/commands/kb/attach.d.ts +12 -0
  35. package/dist/commands/kb/attach.js +49 -0
  36. package/dist/commands/kb/attachment-download.d.ts +14 -0
  37. package/dist/commands/kb/attachment-download.js +38 -0
  38. package/dist/commands/kb/attachments.d.ts +9 -0
  39. package/dist/commands/kb/attachments.js +36 -0
  40. package/dist/commands/kb/create.d.ts +4 -1
  41. package/dist/commands/kb/create.js +41 -5
  42. package/dist/commands/kb/detach.d.ts +13 -0
  43. package/dist/commands/kb/detach.js +26 -0
  44. package/dist/commands/kb/show.js +3 -0
  45. package/dist/commands/kb/update.d.ts +4 -0
  46. package/dist/commands/kb/update.js +69 -21
  47. package/dist/commands/metrics/bulk-triage.d.ts +11 -0
  48. package/dist/commands/metrics/bulk-triage.js +44 -0
  49. package/dist/commands/service-accounts/show.d.ts +9 -0
  50. package/dist/commands/service-accounts/show.js +26 -0
  51. package/dist/commands/service-accounts/tokens/list.d.ts +12 -0
  52. package/dist/commands/service-accounts/tokens/list.js +40 -0
  53. package/dist/commands/service-accounts/update.d.ts +31 -0
  54. package/dist/commands/service-accounts/update.js +105 -0
  55. package/dist/commands/shared/delete.d.ts +12 -0
  56. package/dist/commands/shared/delete.js +30 -0
  57. package/dist/commands/shared/list.d.ts +6 -0
  58. package/dist/commands/shared/list.js +45 -0
  59. package/dist/commands/shared/set.d.ts +14 -0
  60. package/dist/commands/shared/set.js +41 -0
  61. package/dist/commands/tickets/ask.d.ts +13 -0
  62. package/dist/commands/tickets/ask.js +81 -0
  63. package/dist/commands/tickets/dependencies/add.d.ts +15 -0
  64. package/dist/commands/tickets/dependencies/add.js +62 -0
  65. package/dist/commands/tickets/dependencies/list.d.ts +12 -0
  66. package/dist/commands/tickets/dependencies/list.js +37 -0
  67. package/dist/commands/tickets/dependencies/remove.d.ts +14 -0
  68. package/dist/commands/tickets/dependencies/remove.js +59 -0
  69. package/dist/commands/tickets/work-context.d.ts +15 -0
  70. package/dist/commands/tickets/work-context.js +130 -0
  71. package/dist/commands/vault/requests/approve.d.ts +9 -0
  72. package/dist/commands/vault/requests/approve.js +40 -0
  73. package/dist/commands/vault/requests/list.d.ts +6 -0
  74. package/dist/commands/vault/requests/list.js +29 -0
  75. package/dist/commands/vault/requests/reject.d.ts +12 -0
  76. package/dist/commands/vault/requests/reject.js +52 -0
  77. package/dist/commands/workload/create.d.ts +15 -0
  78. package/dist/commands/workload/create.js +45 -0
  79. package/dist/commands/workload/delete.d.ts +12 -0
  80. package/dist/commands/workload/delete.js +26 -0
  81. package/dist/commands/workload/list.d.ts +9 -0
  82. package/dist/commands/workload/list.js +29 -0
  83. package/dist/commands/workload/participant/add.d.ts +10 -0
  84. package/dist/commands/workload/participant/add.js +27 -0
  85. package/dist/commands/workload/participant/remove.d.ts +10 -0
  86. package/dist/commands/workload/participant/remove.js +23 -0
  87. package/dist/commands/workload/promote.d.ts +17 -0
  88. package/dist/commands/workload/promote.js +58 -0
  89. package/dist/commands/workload/show.d.ts +9 -0
  90. package/dist/commands/workload/show.js +24 -0
  91. package/dist/commands/workload/update.d.ts +17 -0
  92. package/dist/commands/workload/update.js +45 -0
  93. package/dist/errors/error-codes.d.ts +17 -0
  94. package/dist/errors/error-codes.js +36 -0
  95. package/dist/lib/api.d.ts +7 -1
  96. package/dist/lib/api.js +8 -0
  97. package/dist/lib/assistant.d.ts +29 -0
  98. package/dist/lib/assistant.js +76 -0
  99. package/dist/lib/bulk-triage.d.ts +35 -0
  100. package/dist/lib/bulk-triage.js +55 -0
  101. package/dist/lib/grouping-rules.d.ts +28 -0
  102. package/dist/lib/grouping-rules.js +39 -0
  103. package/dist/lib/knowledge.d.ts +15 -0
  104. package/dist/lib/knowledge.js +36 -0
  105. package/dist/lib/output.js +10 -0
  106. package/dist/lib/poll.d.ts +51 -0
  107. package/dist/lib/poll.js +59 -0
  108. package/dist/lib/service-accounts.d.ts +65 -0
  109. package/dist/lib/service-accounts.js +132 -0
  110. package/dist/lib/vault-requests.d.ts +38 -0
  111. package/dist/lib/vault-requests.js +125 -0
  112. package/dist/lib/workload.d.ts +37 -0
  113. package/dist/lib/workload.js +64 -0
  114. package/oclif.manifest.json +6290 -4001
  115. package/opencli.json +2164 -549
  116. package/package.json +27 -3
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class ErrorsBulkTriage extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ action: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ group: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ const error_codes_1 = require("../../errors/error-codes");
6
+ const bulk_triage_1 = require("../../lib/bulk-triage");
7
+ const output_1 = require("../../lib/output");
8
+ class ErrorsBulkTriage extends base_1.BaseCommand {
9
+ static description = 'Resolve, ignore or reopen several error groups in one call';
10
+ static examples = [
11
+ '<%= config.bin %> errors bulk-triage -p acme-api --action resolve --group <id-a> --group <id-b>',
12
+ '<%= config.bin %> errors bulk-triage -p acme-api --action ignore --group <id-a> --json',
13
+ ];
14
+ static flags = {
15
+ ...base_1.projectFlag,
16
+ action: core_1.Flags.string({ description: 'What to do with them', options: [...bulk_triage_1.TRIAGE_ACTIONS], required: true }),
17
+ group: core_1.Flags.string({ description: 'Error group id (repeatable)', multiple: true, required: true }),
18
+ };
19
+ async run() {
20
+ const { flags } = await this.parse(ErrorsBulkTriage);
21
+ const projectId = await this.resolveProjectId(flags.project);
22
+ const ids = (0, bulk_triage_1.uniqueIds)(flags.group);
23
+ const res = await this.api.post(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_groups/bulk_triage`, { bulk_action: flags.action, ids });
24
+ const groups = res.data ?? [];
25
+ if (!this.jsonEnabled()) {
26
+ this.log((0, bulk_triage_1.triagedLine)(groups.length, 'error group', flags.action));
27
+ this.log((0, output_1.renderTable)(['ID', 'TITLE', 'STATUS'], groups.map((group) => [String(group.id ?? ''), String(group.title ?? ''), (0, output_1.statusCell)(group.status)])));
28
+ }
29
+ // After printing: the groups that did change are worth showing even when the selection was not
30
+ // whole, and only then does the command refuse to call it a success.
31
+ (0, bulk_triage_1.assertNothingDropped)({
32
+ action: flags.action,
33
+ code: error_codes_1.ErrorCodes.ErrorGroup.notFound,
34
+ noun: 'error group',
35
+ requested: ids,
36
+ rows: groups,
37
+ });
38
+ return res;
39
+ }
40
+ }
41
+ exports.default = ErrorsBulkTriage;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class ErrorsDelete extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ class ErrorsDelete extends base_1.BaseCommand {
6
+ static description = 'Delete an error group and every occurrence it holds (irreversible)';
7
+ static examples = ['<%= config.bin %> errors delete <group-id> --project acme-api --confirm'];
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Error group id', required: true }),
10
+ };
11
+ static flags = {
12
+ ...base_1.projectFlag,
13
+ confirm: core_1.Flags.boolean({ description: 'Required: confirm the irreversible deletion' }),
14
+ };
15
+ async run() {
16
+ const { args, flags } = await this.parse(ErrorsDelete);
17
+ if (!flags.confirm) {
18
+ this.error('Refusing to delete without --confirm (the group and its occurrences are gone for good).', { exit: 2 });
19
+ }
20
+ const projectId = await this.resolveProjectId(flags.project);
21
+ const res = await this.api.delete(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_groups/${encodeURIComponent(args.id)}`);
22
+ if (!this.jsonEnabled()) {
23
+ this.log(`Deleted error group ${args.id} and its occurrences.`);
24
+ }
25
+ return res;
26
+ }
27
+ }
28
+ exports.default = ErrorsDelete;
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class ErrorsGroupingRulesCreate extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ field: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ operator: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ value: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'fingerprint-key': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ position: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<unknown>;
15
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../../base");
5
+ const grouping_rules_1 = require("../../../lib/grouping-rules");
6
+ const output_1 = require("../../../lib/output");
7
+ class ErrorsGroupingRulesCreate extends base_1.BaseCommand {
8
+ static description = 'Add a grouping rule: occurrences that match it are grouped under one key';
9
+ static examples = [
10
+ '<%= config.bin %> errors grouping-rules create -p acme-api --field message --operator contains --value "timeout" --fingerprint-key net-timeout',
11
+ '<%= config.bin %> errors grouping-rules create -p acme-api --field culprit --operator starts_with --value "app/jobs/" --fingerprint-key jobs --position 2',
12
+ ];
13
+ static flags = {
14
+ ...base_1.projectFlag,
15
+ field: core_1.Flags.string({
16
+ description: 'Occurrence field the rule looks at',
17
+ options: [...grouping_rules_1.GROUPING_RULE_FIELDS],
18
+ required: true,
19
+ }),
20
+ operator: core_1.Flags.string({
21
+ description: 'How the field is compared (always case-insensitive)',
22
+ options: [...grouping_rules_1.GROUPING_RULE_OPERATORS],
23
+ required: true,
24
+ }),
25
+ value: core_1.Flags.string({ description: 'Text to compare the field against', required: true }),
26
+ 'fingerprint-key': core_1.Flags.string({
27
+ description: 'Grouping key: rules sharing it send their occurrences to the same group',
28
+ required: true,
29
+ }),
30
+ position: core_1.Flags.integer({ description: 'Order of application (lower runs first)' }),
31
+ active: core_1.Flags.boolean({ allowNo: true, description: 'Whether the rule applies at ingest' }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(ErrorsGroupingRulesCreate);
35
+ const projectId = await this.resolveProjectId(flags.project);
36
+ const res = await this.api.post(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_grouping_rules`, (0, grouping_rules_1.groupingRuleBody)(flags));
37
+ if (!this.jsonEnabled()) {
38
+ this.log('Grouping rule created:');
39
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
40
+ }
41
+ return res;
42
+ }
43
+ }
44
+ exports.default = ErrorsGroupingRulesCreate;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class ErrorsGroupingRulesDelete extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../../base");
5
+ class ErrorsGroupingRulesDelete extends base_1.BaseCommand {
6
+ static description = 'Delete a grouping rule (the groups it already made stay where they are)';
7
+ static examples = ['<%= config.bin %> errors grouping-rules delete <rule-id> --project acme-api --confirm'];
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Grouping rule id', required: true }),
10
+ };
11
+ static flags = {
12
+ ...base_1.projectFlag,
13
+ confirm: core_1.Flags.boolean({ description: 'Required: confirm the deletion' }),
14
+ };
15
+ async run() {
16
+ const { args, flags } = await this.parse(ErrorsGroupingRulesDelete);
17
+ if (!flags.confirm) {
18
+ this.error('Refusing to delete without --confirm.', { exit: 2 });
19
+ }
20
+ const projectId = await this.resolveProjectId(flags.project);
21
+ await this.api.delete(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_grouping_rules/${encodeURIComponent(args.id)}`);
22
+ if (!this.jsonEnabled())
23
+ this.log(`Deleted grouping rule ${args.id}.`);
24
+ return { deleted: args.id };
25
+ }
26
+ }
27
+ exports.default = ErrorsGroupingRulesDelete;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class ErrorsGroupingRulesList extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ page: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../../base");
4
+ const output_1 = require("../../../lib/output");
5
+ class ErrorsGroupingRulesList extends base_1.BaseCommand {
6
+ static description = 'List the custom grouping rules of a project, in the order they are applied';
7
+ static examples = ['<%= config.bin %> errors grouping-rules list --project acme-api'];
8
+ static flags = { ...base_1.projectFlag, ...base_1.pageFlag };
9
+ async run() {
10
+ const { flags } = await this.parse(ErrorsGroupingRulesList);
11
+ const projectId = await this.resolveProjectId(flags.project);
12
+ const res = await this.api.get(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_grouping_rules?page=${flags.page}`);
13
+ const rules = res.data ?? [];
14
+ if (!this.jsonEnabled()) {
15
+ this.log((0, output_1.renderTable)(['POS', 'FIELD', 'OPERATOR', 'VALUE', 'GROUPS AS', 'ACTIVE', 'ID'], rules.map((rule) => [
16
+ String(rule.position ?? ''),
17
+ String(rule.field ?? ''),
18
+ String(rule.operator ?? ''),
19
+ String(rule.value ?? ''),
20
+ String(rule.fingerprint_key ?? ''),
21
+ (0, output_1.statusCell)(rule.active === true ? 'active' : 'paused'),
22
+ String(rule.id ?? ''),
23
+ ])));
24
+ }
25
+ return res;
26
+ }
27
+ }
28
+ exports.default = ErrorsGroupingRulesList;
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class ErrorsGroupingRulesUpdate extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ field: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ operator: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ value: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ 'fingerprint-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ position: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ };
17
+ run(): Promise<unknown>;
18
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../../base");
5
+ const grouping_rules_1 = require("../../../lib/grouping-rules");
6
+ const output_1 = require("../../../lib/output");
7
+ class ErrorsGroupingRulesUpdate extends base_1.BaseCommand {
8
+ static description = 'Change a grouping rule: what it matches, where it sends, when it runs, or turn it off';
9
+ static examples = [
10
+ '<%= config.bin %> errors grouping-rules update <rule-id> -p acme-api --value "connection reset"',
11
+ '<%= config.bin %> errors grouping-rules update <rule-id> -p acme-api --position 0',
12
+ '<%= config.bin %> errors grouping-rules update <rule-id> -p acme-api --no-active',
13
+ ];
14
+ static args = {
15
+ id: core_1.Args.string({ description: 'Grouping rule id', required: true }),
16
+ };
17
+ static flags = {
18
+ ...base_1.projectFlag,
19
+ field: core_1.Flags.string({ description: 'Occurrence field the rule looks at', options: [...grouping_rules_1.GROUPING_RULE_FIELDS] }),
20
+ operator: core_1.Flags.string({ description: 'How the field is compared', options: [...grouping_rules_1.GROUPING_RULE_OPERATORS] }),
21
+ value: core_1.Flags.string({ description: 'Text to compare the field against' }),
22
+ 'fingerprint-key': core_1.Flags.string({ description: 'Grouping key the matching occurrences land on' }),
23
+ position: core_1.Flags.integer({ description: 'Order of application (lower runs first)' }),
24
+ active: core_1.Flags.boolean({ allowNo: true, description: 'Whether the rule applies at ingest' }),
25
+ };
26
+ async run() {
27
+ const { args, flags } = await this.parse(ErrorsGroupingRulesUpdate);
28
+ const body = (0, grouping_rules_1.groupingRuleBody)(flags);
29
+ // An empty PATCH would come back 200 with the rule untouched, and the command would announce an
30
+ // update that never happened. Say it before the call instead.
31
+ if (Object.keys(body).length === 0) {
32
+ this.error('Nothing to update: pass at least one of --field, --operator, --value, --fingerprint-key, --position, --active/--no-active.', { exit: 2 });
33
+ }
34
+ const projectId = await this.resolveProjectId(flags.project);
35
+ const res = await this.api.put(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_grouping_rules/${encodeURIComponent(args.id)}`, body);
36
+ if (!this.jsonEnabled()) {
37
+ this.log('Grouping rule updated:');
38
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
39
+ }
40
+ return res;
41
+ }
42
+ }
43
+ exports.default = ErrorsGroupingRulesUpdate;
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class ErrorsMerge extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ group: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ };
13
+ run(): Promise<unknown>;
14
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ const output_1 = require("../../lib/output");
6
+ class ErrorsMerge extends base_1.BaseCommand {
7
+ static description = 'Merge error groups into one: the occurrences move, the absorbed groups disappear (irreversible)';
8
+ static examples = [
9
+ '<%= config.bin %> errors merge <primary-id> --project acme-api --group <duplicate-a> --group <duplicate-b> --confirm',
10
+ ];
11
+ static args = {
12
+ id: core_1.Args.string({ description: 'Error group that keeps everything (the primary)', required: true }),
13
+ };
14
+ static flags = {
15
+ ...base_1.projectFlag,
16
+ group: core_1.Flags.string({ description: 'Error group to absorb (repeatable)', multiple: true, required: true }),
17
+ confirm: core_1.Flags.boolean({ description: 'Required: confirm the irreversible merge' }),
18
+ };
19
+ async run() {
20
+ const { args, flags } = await this.parse(ErrorsMerge);
21
+ if (!flags.confirm) {
22
+ this.error('Refusing to merge without --confirm (the action is irreversible).', { exit: 2 });
23
+ }
24
+ const projectId = await this.resolveProjectId(flags.project);
25
+ // The ids travel raw — not deduplicated, not filtered, not looked up first. All-or-nothing is
26
+ // the server's to keep (`Errors::Merge#resolve_sources!`): one id it cannot find in the project
27
+ // aborts the whole merge. Tidying the list here would hand it a set it can always resolve, so
28
+ // the groups it did find would be merged and the rest silently forgotten — on an operation
29
+ // nothing can undo.
30
+ const res = await this.api.post(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_groups/${encodeURIComponent(args.id)}/merge`, { ids: flags.group });
31
+ if (!this.jsonEnabled()) {
32
+ const merged = res.meta?.merged;
33
+ this.log(`Merged ${merged ?? flags.group.length} error groups into ${args.id}:`);
34
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
35
+ }
36
+ return res;
37
+ }
38
+ }
39
+ exports.default = ErrorsMerge;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class ErrorsSplit extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ event: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ const output_1 = require("../../lib/output");
6
+ class ErrorsSplit extends base_1.BaseCommand {
7
+ static description = 'Split an error group: pull some occurrences out into a new one';
8
+ static examples = [
9
+ '<%= config.bin %> errors split <group-id> --project acme-api --event <event-a> --event <event-b>',
10
+ ];
11
+ static args = {
12
+ id: core_1.Args.string({ description: 'Error group to split', required: true }),
13
+ };
14
+ static flags = {
15
+ ...base_1.projectFlag,
16
+ event: core_1.Flags.string({ description: 'Occurrence id to pull out (repeatable)', multiple: true, required: true }),
17
+ };
18
+ async run() {
19
+ const { args, flags } = await this.parse(ErrorsSplit);
20
+ const projectId = await this.resolveProjectId(flags.project);
21
+ // Raw ids again: `Errors::Split` refuses the whole split if one occurrence is not in this group,
22
+ // and that refusal is only possible while the list it receives is the list that was written.
23
+ const res = await this.api.post(`/cli/v1/projects/${encodeURIComponent(projectId)}/error_groups/${encodeURIComponent(args.id)}/split`, { event_ids: flags.event });
24
+ if (!this.jsonEnabled()) {
25
+ // Counted off the group that was born, not off the flags that were typed: the server
26
+ // deduplicates the ids it receives, so the same occurrence named twice moves once.
27
+ const moved = Number(res.data?.events_count ?? flags.event.length);
28
+ this.log(`Split ${moved} occurrence${moved === 1 ? '' : 's'} out of ${args.id} into a new error group:`);
29
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
30
+ }
31
+ return res;
32
+ }
33
+ }
34
+ exports.default = ErrorsSplit;
@@ -6,7 +6,7 @@ class InvitationsCreate extends base_1.BaseCommand {
6
6
  static args = {
7
7
  email: core_1.Args.string({ description: 'Email address to invite', required: true }),
8
8
  };
9
- static description = 'Invite a person to the organization. Prints the acceptance link (shown only once).';
9
+ static description = 'Invite a person to the organization. Prints the acceptance link.';
10
10
  static examples = [
11
11
  '<%= config.bin %> invitations create client@acme.com',
12
12
  '<%= config.bin %> invitations create teammate@acme.com --role member',
@@ -30,7 +30,14 @@ class InvitationsCreate extends base_1.BaseCommand {
30
30
  this.log('');
31
31
  this.log(` accept link: ${invitation.accept_url ?? '-'}`);
32
32
  this.log('');
33
- this.warn('Email delivery is not wired in production send this link to the invitee manually.');
33
+ // The server reports whether mail actually goes out (email_delivery). This used to be a fixed
34
+ // sentence printed every time, which said nothing about the real state of delivery.
35
+ if (invitation.email_delivery === false) {
36
+ this.warn('Email delivery is off on the server — send this link to the invitee yourself.');
37
+ }
38
+ else {
39
+ this.log('The invitation email is on its way; send the link yourself if it never lands.');
40
+ }
34
41
  }
35
42
  return res;
36
43
  }
@@ -6,7 +6,7 @@ class InvitationsResend extends base_1.BaseCommand {
6
6
  static args = {
7
7
  id: core_1.Args.string({ description: 'Invitation id (UUID)', required: true }),
8
8
  };
9
- static description = 'Resend a pending invitation. Prints the acceptance link (shown only once).';
9
+ static description = 'Resend a pending invitation. Prints the acceptance link.';
10
10
  static examples = ['<%= config.bin %> invitations resend <invitation-uuid>'];
11
11
  async run() {
12
12
  const { args } = await this.parse(InvitationsResend);
@@ -17,7 +17,13 @@ class InvitationsResend extends base_1.BaseCommand {
17
17
  this.log('');
18
18
  this.log(` accept link: ${invitation.accept_url ?? '-'}`);
19
19
  this.log('');
20
- this.warn('Email delivery is not wired in production send this link to the invitee manually.');
20
+ // Same as `invitations create`: only the server knows whether mail is being delivered.
21
+ if (invitation.email_delivery === false) {
22
+ this.warn('Email delivery is off on the server — send this link to the invitee yourself.');
23
+ }
24
+ else {
25
+ this.log('The invitation email is on its way; send the link yourself if it never lands.');
26
+ }
21
27
  }
22
28
  return res;
23
29
  }
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class KbAttach extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ file: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const node_path_1 = require("node:path");
5
+ const core_1 = require("@oclif/core");
6
+ const base_1 = require("../../base");
7
+ const output_1 = require("../../lib/output");
8
+ class KbAttach extends base_1.BaseCommand {
9
+ static description = 'Attach one or more local files to a knowledge page';
10
+ static examples = [
11
+ '<%= config.bin %> kb attach <page-id> --file ./rollback.sh',
12
+ '<%= config.bin %> kb attach <page-id> --file ./diagram.png --file ./checklist.pdf',
13
+ ];
14
+ static args = {
15
+ id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
16
+ };
17
+ static flags = {
18
+ file: core_1.Flags.string({ description: 'Path to a local file to upload (repeatable)', multiple: true, required: true }),
19
+ };
20
+ async run() {
21
+ const { args, flags } = await this.parse(KbAttach);
22
+ // Tutti i file si leggono PRIMA di caricarne uno: il server rifiuta il lotto intero se un file
23
+ // non è ammesso, e un percorso sbagliato deve fermare il comando allo stesso modo — non a metà.
24
+ const files = [];
25
+ for (const path of flags.file) {
26
+ try {
27
+ // eslint-disable-next-line no-await-in-loop
28
+ const buf = await (0, promises_1.readFile)(path);
29
+ files.push({ field: 'files[]', filename: (0, node_path_1.basename)(path), data: new Blob([buf]) });
30
+ }
31
+ catch {
32
+ this.error(`File not found or unreadable: ${path}`, { exit: 2 });
33
+ }
34
+ }
35
+ const res = await this.api.upload('POST', `/cli/v1/knowledge/pages/${encodeURIComponent(args.id)}/attachments`, files);
36
+ const attachments = res.data ?? [];
37
+ if (!this.jsonEnabled()) {
38
+ this.log(`Attached ${files.length} file${files.length === 1 ? '' : 's'} to knowledge page ${args.id}:`);
39
+ this.log((0, output_1.renderTable)(['ID', 'FILENAME', 'CONTENT_TYPE', 'BYTE_SIZE'], attachments.map((attachment) => [
40
+ String(attachment.id ?? ''),
41
+ String(attachment.filename ?? ''),
42
+ String(attachment.content_type ?? ''),
43
+ String(attachment.byte_size ?? ''),
44
+ ])));
45
+ }
46
+ return res;
47
+ }
48
+ }
49
+ exports.default = KbAttach;
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class KbAttachmentDownload extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ attachment: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ out: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ filename: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ };
13
+ run(): Promise<unknown>;
14
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const node_path_1 = require("node:path");
5
+ const core_1 = require("@oclif/core");
6
+ const base_1 = require("../../base");
7
+ class KbAttachmentDownload extends base_1.BaseCommand {
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
10
+ attachment: core_1.Args.string({ description: 'Attachment id', required: true }),
11
+ };
12
+ // Il server consegna il binario con tipo neutro e disposition attachment: il file finisce sul
13
+ // disco e basta, nessun canale lo apre né lo esegue per conto di chi lo scarica.
14
+ static description = "Download a knowledge page's attachment to disk";
15
+ static examples = [
16
+ '<%= config.bin %> kb attachment-download <page-id> <attachment-id>',
17
+ '<%= config.bin %> kb attachment-download <page-id> <attachment-id> --out ./downloads',
18
+ ];
19
+ static flags = {
20
+ out: core_1.Flags.string({ default: '.', description: 'Output directory' }),
21
+ filename: core_1.Flags.string({ description: 'Override the output filename' }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(KbAttachmentDownload);
25
+ const { data, filename } = await this.api.download(`/cli/v1/knowledge/pages/${encodeURIComponent(args.id)}/attachments/${encodeURIComponent(args.attachment)}/download`);
26
+ // Il nome che arriva dal server è ridotto all'ultimo segmento: un `filename` con dei separatori
27
+ // dentro, letto da Content-Disposition, scriverebbe fuori da --out invece che dentro. `--filename`
28
+ // no: quello lo scrive chi lancia il comando, e sceglie lui dove mettere il file.
29
+ const name = flags.filename ?? (filename === undefined ? args.attachment : (0, node_path_1.basename)(filename));
30
+ const dest = (0, node_path_1.join)(flags.out, name);
31
+ await (0, promises_1.writeFile)(dest, data);
32
+ if (!this.jsonEnabled()) {
33
+ this.log(`Saved ${data.byteLength} bytes → ${dest}`);
34
+ }
35
+ return { bytes: data.byteLength, filename: name, path: dest };
36
+ }
37
+ }
38
+ exports.default = KbAttachmentDownload;
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class KbAttachments extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<unknown>;
9
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ const output_1 = require("../../lib/output");
6
+ const paginate_1 = require("../../lib/paginate");
7
+ class KbAttachments extends base_1.BaseCommand {
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Knowledge page id', required: true }),
10
+ };
11
+ static description = "List a knowledge page's attachments";
12
+ static examples = [
13
+ '<%= config.bin %> kb attachments <page-id>',
14
+ '<%= config.bin %> kb attachments <page-id> --json',
15
+ ];
16
+ async run() {
17
+ const { args } = await this.parse(KbAttachments);
18
+ // Elenco completo, non la sola prima pagina: il comando non ha un --page, quindi fermarsi a
19
+ // cento allegati significherebbe nasconderne il resto senza modo di chiederli.
20
+ const attachments = await (0, paginate_1.fetchAllPages)(this.api, `/cli/v1/knowledge/pages/${encodeURIComponent(args.id)}/attachments`);
21
+ if (!this.jsonEnabled()) {
22
+ this.log((0, output_1.renderTable)(['ID', 'FILENAME', 'CONTENT_TYPE', 'BYTE_SIZE', 'SCRIPT', 'CREATED_AT'], attachments.map((attachment) => [
23
+ String(attachment.id ?? ''),
24
+ String(attachment.filename ?? ''),
25
+ String(attachment.content_type ?? ''),
26
+ String(attachment.byte_size ?? ''),
27
+ // Il server dichiara se il file è uno script: sapere che si sta scaricando qualcosa di
28
+ // eseguibile è la sola cosa che l'elenco può dire prima che il file sia sul disco.
29
+ attachment.script === undefined ? '' : (attachment.script ? 'yes' : 'no'),
30
+ String(attachment.created_at ?? ''),
31
+ ])));
32
+ }
33
+ return { data: attachments, meta: (0, paginate_1.aggregatedMeta)(attachments.length) };
34
+ }
35
+ }
36
+ exports.default = KbAttachments;