@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,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../../base");
4
+ const output_1 = require("../../../lib/output");
5
+ const paginate_1 = require("../../../lib/paginate");
6
+ const vault_requests_1 = require("../../../lib/vault-requests");
7
+ class VaultRequestsList extends base_1.BaseCommand {
8
+ // No --project on purpose: the queue is org-level, exactly like the web vault page — the backend
9
+ // collects the pending requests across every visible project, and asking for one project would
10
+ // hide the review you were about to do on another.
11
+ static description = 'List the secret changes waiting for a second approval, across every visible project. Shows the name and the intent, never the proposed value.';
12
+ static examples = ['<%= config.bin %> vault requests list', '<%= config.bin %> vault requests list --json'];
13
+ async run() {
14
+ await this.parse(VaultRequestsList);
15
+ const data = (await (0, paginate_1.fetchAllPages)(this.api, vault_requests_1.CHANGE_REQUESTS_PATH)).map((row) => (0, vault_requests_1.withoutValue)(row));
16
+ if (!this.jsonEnabled()) {
17
+ // An empty queue is good news, not an empty result set: renderTable's "(no results)" under a
18
+ // header row reads like a failed search, and the reviewer needs the opposite reading.
19
+ if (data.length === 0) {
20
+ this.log('No secret change request is waiting for a decision.');
21
+ }
22
+ else {
23
+ this.log((0, output_1.renderTable)(vault_requests_1.CHANGE_REQUEST_HEADERS, data.map((row) => (0, vault_requests_1.changeRequestRow)(row))));
24
+ }
25
+ }
26
+ return { data, meta: (0, paginate_1.aggregatedMeta)(data.length) };
27
+ }
28
+ }
29
+ exports.default = VaultRequestsList;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class VaultRequestsReject 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
+ reason: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,52 @@
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 vault_requests_1 = require("../../../lib/vault-requests");
7
+ class VaultRequestsReject extends base_1.BaseCommand {
8
+ static description = 'Reject a pending secret change request with a reason. Nothing changes in the vault: the request freezes as rejected and the reason reaches whoever asked.';
9
+ static examples = [
10
+ '<%= config.bin %> vault requests reject <id> --reason "rotate it on staging first"',
11
+ '<%= config.bin %> vault requests reject <id> -r "wrong key" --json',
12
+ ];
13
+ static args = {
14
+ id: core_1.Args.string({ description: 'Change request id (from "vault requests list")', required: true }),
15
+ };
16
+ static flags = {
17
+ reason: core_1.Flags.string({
18
+ char: 'r',
19
+ description: 'Why the change is refused — recorded for the audit and sent to whoever asked',
20
+ required: true,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { args, flags } = await this.parse(VaultRequestsReject);
25
+ // A rejection freezes the request for good: it cannot be decided again, and the only thing left
26
+ // to the person who asked is the reason. Whitespace would satisfy the required flag and be
27
+ // refused by the server anyway (R422-CHANGEREQUEST-001), so it is refused here, before the call.
28
+ const reason = flags.reason.trim();
29
+ if (reason === '') {
30
+ this.error('Refusing to reject with an empty --reason: say why, so whoever asked can fix it and ask again.', {
31
+ exit: 2,
32
+ });
33
+ }
34
+ let res;
35
+ try {
36
+ res = await this.api.post(`${vault_requests_1.CHANGE_REQUESTS_PATH}/${encodeURIComponent(args.id)}/reject`, { reason });
37
+ }
38
+ catch (error) {
39
+ throw (0, vault_requests_1.describeDecisionError)(error);
40
+ }
41
+ const decided = (0, vault_requests_1.withoutValue)(res.data ?? {});
42
+ if (!this.jsonEnabled()) {
43
+ const label = (0, vault_requests_1.changeRequestLabel)(decided);
44
+ this.log(label ? `Change request rejected: ${label} is unchanged.` : 'Change request rejected: nothing changed.');
45
+ const summary = (0, vault_requests_1.changeRequestSummary)(decided);
46
+ if (Object.keys(summary).length > 0)
47
+ this.log((0, output_1.renderRecord)(summary));
48
+ }
49
+ return { ...res, data: decided };
50
+ }
51
+ }
52
+ exports.default = VaultRequestsReject;
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadCreate extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ 'scheduled-at': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'due-at': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ ticket: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ team: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ title: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<unknown>;
15
+ }
@@ -0,0 +1,45 @@
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 workload_1 = require("../../lib/workload");
7
+ class WorkloadCreate extends base_1.BaseCommand {
8
+ static description = 'Create a workload action (non-dev activity: fair, meeting, call…) on one of your teams. Add the people with `workload participant add`.';
9
+ static examples = [
10
+ '<%= config.bin %> workload create --team Marketing --title "Fiera di Rimini"',
11
+ '<%= config.bin %> workload create --team Marketing --title "Riunione firma accordo" --scheduled-at 2026-09-01T09:00:00Z --due-at 2026-09-10T18:00:00Z',
12
+ '<%= config.bin %> workload create --team Marketing --title "Materiale stand" --status in_progress --ticket DRFL-3',
13
+ ];
14
+ static flags = {
15
+ team: core_1.Flags.string({
16
+ description: 'Team id (UUID) or name — the action belongs to it and cannot be moved later',
17
+ required: true,
18
+ }),
19
+ title: core_1.Flags.string({ description: 'What the activity is', required: true }),
20
+ ...workload_1.actionFieldFlags,
21
+ };
22
+ async run() {
23
+ const { flags } = await this.parse(WorkloadCreate);
24
+ const teamId = await this.resolveTeamId(flags.team);
25
+ const body = { team_id: teamId, title: flags.title };
26
+ (0, workload_1.applyActionBody)(body, flags);
27
+ // Il code umano ("DRFL-3") si risolve qui: il server accetta solo l'id, e uno che non può
28
+ // vedere lo scarta in silenzio invece di rifiutarlo.
29
+ const ticketId = flags.ticket ? await this.resolveTicketId(flags.ticket) : undefined;
30
+ if (flags.ticket !== undefined)
31
+ body.ticket_id = ticketId ?? null;
32
+ const res = await this.api.post(workload_1.WORKLOAD_ACTIONS_PATH, body);
33
+ const data = res.data ?? {};
34
+ if ((0, workload_1.ticketLinkMissing)(flags.ticket, ticketId, data)) {
35
+ this.warn(`Ticket ${flags.ticket} is not visible to you: the action was created without it.`);
36
+ }
37
+ if (!this.jsonEnabled()) {
38
+ this.log('Workload action created:');
39
+ this.log((0, output_1.renderRecord)(data));
40
+ this.log((0, workload_1.participantsLine)(data));
41
+ }
42
+ return res;
43
+ }
44
+ }
45
+ exports.default = WorkloadCreate;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadDelete 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
+ static flags: {
9
+ confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,26 @@
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 workload_1 = require("../../lib/workload");
6
+ class WorkloadDelete extends base_1.BaseCommand {
7
+ static args = {
8
+ id: core_1.Args.string({ description: 'Workload action id', required: true }),
9
+ };
10
+ static description = 'Delete a workload action (irreversible; a linked ticket survives and only loses the link)';
11
+ static examples = ['<%= config.bin %> workload delete <action-id> --confirm'];
12
+ static flags = {
13
+ confirm: core_1.Flags.boolean({ description: 'Required: confirm the irreversible deletion' }),
14
+ };
15
+ async run() {
16
+ const { args, flags } = await this.parse(WorkloadDelete);
17
+ if (!flags.confirm) {
18
+ this.error('Refusing to delete without --confirm (the action is irreversible).', { exit: 2 });
19
+ }
20
+ await this.api.delete(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.id)}`);
21
+ if (!this.jsonEnabled())
22
+ this.log(`Deleted workload action ${args.id}`);
23
+ return { deleted: args.id };
24
+ }
25
+ }
26
+ exports.default = WorkloadDelete;
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadList 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
+ };
8
+ run(): Promise<unknown>;
9
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../base");
4
+ const output_1 = require("../../lib/output");
5
+ const workload_1 = require("../../lib/workload");
6
+ class WorkloadList extends base_1.BaseCommand {
7
+ static description = 'List the workload actions of the teams you belong to (newest first)';
8
+ static examples = ['<%= config.bin %> workload list', '<%= config.bin %> workload list --page 2 --json'];
9
+ static flags = { ...base_1.pageFlag };
10
+ async run() {
11
+ const { flags } = await this.parse(WorkloadList);
12
+ const res = await this.api.get(`${workload_1.WORKLOAD_ACTIONS_PATH}?page=${flags.page}`);
13
+ const actions = res.data ?? [];
14
+ if (!this.jsonEnabled()) {
15
+ this.log((0, output_1.renderTable)(['TITLE', 'STATUS', 'TEAM', 'PEOPLE', 'SCHEDULED', 'DUE', 'TICKET', 'ID'], actions.map((action) => [
16
+ String(action.title ?? ''),
17
+ (0, output_1.statusCell)(action.status),
18
+ String(action.team ?? ''),
19
+ String((Array.isArray(action.participants) ? action.participants : []).length),
20
+ String(action.scheduled_at ?? '-'),
21
+ String(action.due_at ?? '-'),
22
+ String(action.ticket_code ?? '-'),
23
+ String(action.id ?? ''),
24
+ ])));
25
+ }
26
+ return res;
27
+ }
28
+ }
29
+ exports.default = WorkloadList;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class WorkloadParticipantAdd extends BaseCommand {
3
+ static args: {
4
+ action: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ member: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ run(): Promise<unknown>;
10
+ }
@@ -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
+ const output_1 = require("../../../lib/output");
6
+ const workload_1 = require("../../../lib/workload");
7
+ class WorkloadParticipantAdd extends base_1.BaseCommand {
8
+ static args = {
9
+ action: core_1.Args.string({ description: 'Workload action id', required: true }),
10
+ member: core_1.Args.string({ description: 'Participant account id or email (must be on the action team)', required: true }),
11
+ };
12
+ static description = 'Add someone to a workload action (they must belong to the team that owns it)';
13
+ static examples = ['<%= config.bin %> workload participant add <action-id> ada@acme.com'];
14
+ async run() {
15
+ const { args } = await this.parse(WorkloadParticipantAdd);
16
+ const accountId = await this.resolveMemberId(args.member);
17
+ const res = await this.api.post(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.action)}/participants`, { account_id: accountId });
18
+ const data = res.data ?? {};
19
+ if (!this.jsonEnabled()) {
20
+ this.log(`Added ${args.member} to workload action ${args.action}:`);
21
+ this.log((0, output_1.renderRecord)(data));
22
+ this.log((0, workload_1.participantsLine)(data));
23
+ }
24
+ return res;
25
+ }
26
+ }
27
+ exports.default = WorkloadParticipantAdd;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class WorkloadParticipantRemove extends BaseCommand {
3
+ static args: {
4
+ action: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ member: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,23 @@
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 workload_1 = require("../../../lib/workload");
6
+ class WorkloadParticipantRemove extends base_1.BaseCommand {
7
+ static args = {
8
+ action: core_1.Args.string({ description: 'Workload action id', required: true }),
9
+ member: core_1.Args.string({ description: 'Participant account id or email', required: true }),
10
+ };
11
+ static description = 'Remove someone from a workload action (idempotent: removing who is not there succeeds)';
12
+ static examples = ['<%= config.bin %> workload participant remove <action-id> ada@acme.com'];
13
+ async run() {
14
+ const { args } = await this.parse(WorkloadParticipantRemove);
15
+ const accountId = await this.resolveMemberId(args.member);
16
+ await this.api.delete(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.action)}/participants/${encodeURIComponent(accountId)}`);
17
+ if (!this.jsonEnabled()) {
18
+ this.log(`Removed ${args.member} from workload action ${args.action}`);
19
+ }
20
+ return { removed: accountId };
21
+ }
22
+ }
23
+ exports.default = WorkloadParticipantRemove;
@@ -0,0 +1,17 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadPromote extends BaseCommand {
3
+ static args: {
4
+ action: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ priority: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ kind: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ };
16
+ run(): Promise<unknown>;
17
+ }
@@ -0,0 +1,58 @@
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 limits_1 = require("../../lib/limits");
6
+ const output_1 = require("../../lib/output");
7
+ const ticket_lookup_1 = require("../../lib/ticket-lookup");
8
+ const workload_1 = require("../../lib/workload");
9
+ class WorkloadPromote extends base_1.BaseCommand {
10
+ static args = {
11
+ action: core_1.Args.string({ description: 'Workload action id', required: true }),
12
+ };
13
+ static description = 'Generate a ticket from a workload action and link it back (the action keeps existing; an already linked action is refused)';
14
+ static examples = [
15
+ '<%= config.bin %> workload promote <action-id> --project acme-api',
16
+ '<%= config.bin %> workload promote <action-id> -p acme-api --title "Implement the partner API" --description "Agreed in the meeting" --kind story --priority High',
17
+ ];
18
+ static flags = {
19
+ ...base_1.projectFlag,
20
+ title: core_1.Flags.string({
21
+ description: `Ticket title (default: the action title, max ${limits_1.LENGTH_LIMITS.title} characters)`,
22
+ }),
23
+ description: core_1.Flags.string({ description: `Ticket description (max ${limits_1.LENGTH_LIMITS.description} characters)` }),
24
+ kind: core_1.Flags.string({ description: 'Ticket kind (default: task)', options: ['bug', 'story', 'task', 'epic'] }),
25
+ ...ticket_lookup_1.newTicketLookupFlags,
26
+ };
27
+ async run() {
28
+ const { args, flags } = await this.parse(WorkloadPromote);
29
+ // Il ticket nasce qui: valgono i tetti di `tickets create`, e si leggono tutti in un rifiuto
30
+ // solo, prima di qualunque chiamata (CYCL-32).
31
+ const tooLong = (0, limits_1.tooLongMessage)([
32
+ { flag: '--title', value: flags.title, max: limits_1.LENGTH_LIMITS.title, orthography: true },
33
+ { flag: '--description', value: flags.description, max: limits_1.LENGTH_LIMITS.description, orthography: true },
34
+ ]);
35
+ if (tooLong)
36
+ this.error(tooLong, { exit: 2 });
37
+ const projectId = await this.resolveProjectId(flags.project);
38
+ const body = { project_id: projectId };
39
+ if (flags.title !== undefined)
40
+ body.title = flags.title;
41
+ if (flags.description !== undefined)
42
+ body.description = flags.description;
43
+ if (flags.kind !== undefined)
44
+ body.kind = flags.kind;
45
+ if (flags.status !== undefined)
46
+ body.status_id = await this.resolveTicketLookupId(ticket_lookup_1.TICKET_STATUS, flags.status);
47
+ if (flags.priority !== undefined) {
48
+ body.priority_id = await this.resolveTicketLookupId(ticket_lookup_1.TICKET_PRIORITY, flags.priority);
49
+ }
50
+ const res = await this.api.post(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.action)}/promotion`, body);
51
+ if (!this.jsonEnabled()) {
52
+ this.log('Ticket created from the workload action:');
53
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
54
+ }
55
+ return res;
56
+ }
57
+ }
58
+ exports.default = WorkloadPromote;
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadShow 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,24 @@
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 workload_1 = require("../../lib/workload");
7
+ class WorkloadShow extends base_1.BaseCommand {
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Workload action id', required: true }),
10
+ };
11
+ static description = 'Show one workload action (an action of another team answers 404, never 403)';
12
+ static examples = ['<%= config.bin %> workload show <action-id>'];
13
+ async run() {
14
+ const { args } = await this.parse(WorkloadShow);
15
+ const res = await this.api.get(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.id)}`);
16
+ if (!this.jsonEnabled()) {
17
+ const data = res.data ?? {};
18
+ this.log((0, output_1.renderRecord)(data));
19
+ this.log((0, workload_1.participantsLine)(data));
20
+ }
21
+ return res;
22
+ }
23
+ }
24
+ exports.default = WorkloadShow;
@@ -0,0 +1,17 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class WorkloadUpdate 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
+ static flags: {
9
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ 'scheduled-at': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ 'due-at': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ ticket: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
+ title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ };
16
+ run(): Promise<unknown>;
17
+ }
@@ -0,0 +1,45 @@
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 workload_1 = require("../../lib/workload");
7
+ class WorkloadUpdate extends base_1.BaseCommand {
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Workload action id', required: true }),
10
+ };
11
+ static description = 'Update a workload action (only the passed fields change). The team never changes: moving an action would change who can see it.';
12
+ static examples = [
13
+ '<%= config.bin %> workload update <action-id> --status done',
14
+ '<%= config.bin %> workload update <action-id> --title "Fiera 2027" --due-at 2027-09-10T18:00:00Z',
15
+ '<%= config.bin %> workload update <action-id> --ticket ""',
16
+ ];
17
+ static flags = {
18
+ title: core_1.Flags.string({ description: 'New title' }),
19
+ ...workload_1.actionFieldFlags,
20
+ };
21
+ async run() {
22
+ const { args, flags } = await this.parse(WorkloadUpdate);
23
+ const body = {};
24
+ if (flags.title !== undefined)
25
+ body.title = flags.title;
26
+ (0, workload_1.applyActionBody)(body, flags);
27
+ const ticketId = flags.ticket ? await this.resolveTicketId(flags.ticket) : undefined;
28
+ if (flags.ticket !== undefined)
29
+ body.ticket_id = ticketId ?? null;
30
+ const res = await this.api.put(`${workload_1.WORKLOAD_ACTIONS_PATH}/${encodeURIComponent(args.id)}`, body);
31
+ const data = res.data ?? {};
32
+ // Su una modifica il rifiuto silenzioso del server non lascia le cose come stavano: azzera il
33
+ // campo, quindi porta via anche il ticket che era collegato prima. Dirlo per intero.
34
+ if ((0, workload_1.ticketLinkMissing)(flags.ticket, ticketId, data)) {
35
+ this.warn(`Ticket ${flags.ticket} is not visible to you: the action now has no linked ticket at all, not even the one it had before.`);
36
+ }
37
+ if (!this.jsonEnabled()) {
38
+ this.log('Workload action updated:');
39
+ this.log((0, output_1.renderRecord)(data));
40
+ this.log((0, workload_1.participantsLine)(data));
41
+ }
42
+ return res;
43
+ }
44
+ }
45
+ exports.default = WorkloadUpdate;
@@ -22,9 +22,22 @@ export declare const ErrorCodes: {
22
22
  readonly Team: {
23
23
  readonly notFound: "C404-TEM-001";
24
24
  };
25
+ readonly ErrorGroup: {
26
+ readonly notFound: "C404-ERG-001";
27
+ };
28
+ readonly MetricGroup: {
29
+ readonly notFound: "C404-MTG-001";
30
+ };
25
31
  readonly Member: {
26
32
  readonly notFound: "C404-MBR-001";
27
33
  };
34
+ readonly ServiceAccount: {
35
+ readonly boundaryMismatch: "C404-SVA-001";
36
+ readonly restrictionNotApplied: "C500-SVA-002";
37
+ };
38
+ readonly Ticket: {
39
+ readonly notFound: "C404-TKT-001";
40
+ };
28
41
  readonly Knowledge: {
29
42
  readonly publishUnavailable: "C404-KNW-001";
30
43
  };
@@ -38,6 +51,10 @@ export declare const ErrorCodes: {
38
51
  readonly expired: "C408-DEV-001";
39
52
  readonly failed: "C400-DEV-002";
40
53
  };
54
+ readonly Ask: {
55
+ readonly timeout: "C408-ASK-001";
56
+ readonly failed: "C502-ASK-002";
57
+ };
41
58
  readonly Input: {
42
59
  readonly invalid: "C400-INP-001";
43
60
  };
@@ -27,9 +27,37 @@ exports.ErrorCodes = {
27
27
  Team: {
28
28
  notFound: 'C404-TEM-001',
29
29
  },
30
+ // Gruppi di monitoring chiesti a un'operazione in massa e non ritrovati nella risposta. Il server
31
+ // filtra la selezione sul progetto e risponde 200 su ciò che resta (`scope.where(id:)`), quindi
32
+ // un id di un altro progetto — o di un dato ormai vecchio — sparisce senza una parola: chi ha
33
+ // chiesto di chiudere trenta gruppi ne vedrebbe chiusi ventotto e nessuno glielo direbbe (CYCL-44).
34
+ ErrorGroup: {
35
+ notFound: 'C404-ERG-001',
36
+ },
37
+ MetricGroup: {
38
+ notFound: 'C404-MTG-001',
39
+ },
30
40
  Member: {
31
41
  notFound: 'C404-MBR-001',
32
42
  },
43
+ // Il confine ambienti di un account di servizio, chiesto e non applicato (CYCL-46). Il server
44
+ // interseca i code ricevuti con quelli dell'organizzazione e risponde 200 su ciò che resta: un
45
+ // refuso non restringe niente, CANCELLA il confine — e una allow-list vuota vuol dire «ogni
46
+ // ambiente», cioè l'opposto di quello che si stava chiedendo, senza una parola. Il comando
47
+ // controlla i code prima di scrivere, ma leggere gli ambienti chiede un permesso che può mancare:
48
+ // il confronto fra chiesto e applicato resta la rete sotto, e vale in entrambi i versi (un code
49
+ // sparito, o uno comparso che nessuno aveva chiesto).
50
+ ServiceAccount: {
51
+ boundaryMismatch: 'C404-SVA-001',
52
+ restrictionNotApplied: 'C500-SVA-002',
53
+ },
54
+ // Un ticket indicato per collegarlo altrove (una attività del carico di lavoro) e non trovato: il
55
+ // riferimento non è né un id né un code leggibile ("DRFL-3"), oppure quel code non esiste tra i
56
+ // ticket visibili. Il server, ricevendo un id che non si può vedere, salverebbe «nessun ticket»
57
+ // senza dire niente (CYCL-42).
58
+ Ticket: {
59
+ notFound: 'C404-TKT-001',
60
+ },
33
61
  // Il backend risponde 404 senza codice applicativo sulla route della pubblicazione atomica:
34
62
  // non è il progetto a mancare, è il server a essere più vecchio del comando (CYCL-8).
35
63
  Knowledge: {
@@ -47,6 +75,14 @@ exports.ErrorCodes = {
47
75
  expired: 'C408-DEV-001',
48
76
  failed: 'C400-DEV-002',
49
77
  },
78
+ // Attesa di una risposta preparata altrove (l'assistente, «chiedi ai ticket»). `timeout` non è un
79
+ // guasto del server: la domanda è partita e la risposta sta ancora arrivando, è il comando che ha
80
+ // smesso di aspettare — il messaggio dice dove ritrovarla. `failed` copre il caso in cui il
81
+ // server dichiara fallita la risposta senza allegare un codice proprio (CYCL-43).
82
+ Ask: {
83
+ timeout: 'C408-ASK-001',
84
+ failed: 'C502-ASK-002',
85
+ },
50
86
  // The command line itself was rejected (missing/unknown flag or arg, value outside the allowed
51
87
  // options, a `this.error(...)` guard): the message says what to fix, and it never reached the
52
88
  // server — the opposite of System.unexpected, which stays for real failures (CYCL-33).
package/dist/lib/api.d.ts CHANGED
@@ -22,7 +22,7 @@ export interface UploadFile {
22
22
  filename: string;
23
23
  data: Blob;
24
24
  }
25
- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
25
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
26
26
  export declare class CliApi {
27
27
  private readonly config;
28
28
  /**
@@ -47,6 +47,12 @@ export declare class CliApi {
47
47
  get<T = unknown>(path: string, opts?: RequestOptions): Promise<Envelope<T>>;
48
48
  post<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<Envelope<T>>;
49
49
  put<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<Envelope<T>>;
50
+ /**
51
+ * PATCH. Rails routes a resourceful `update` under both PUT and PATCH, so most commands here use
52
+ * `put`; a custom member route declared with `patch` (error group assignment, CYCL-44) answers to
53
+ * PATCH alone, and sending PUT to it is a plain 404.
54
+ */
55
+ patch<T = unknown>(path: string, body?: unknown, opts?: RequestOptions): Promise<Envelope<T>>;
50
56
  delete<T = unknown>(path: string, opts?: RequestOptions): Promise<Envelope<T>>;
51
57
  /**
52
58
  * Download a binary payload (e.g. a ticket attachment). The endpoint redirects to a signed
package/dist/lib/api.js CHANGED
@@ -117,6 +117,14 @@ class CliApi {
117
117
  put(path, body, opts) {
118
118
  return this.request('PUT', path, { ...opts, body });
119
119
  }
120
+ /**
121
+ * PATCH. Rails routes a resourceful `update` under both PUT and PATCH, so most commands here use
122
+ * `put`; a custom member route declared with `patch` (error group assignment, CYCL-44) answers to
123
+ * PATCH alone, and sending PUT to it is a plain 404.
124
+ */
125
+ patch(path, body, opts) {
126
+ return this.request('PATCH', path, { ...opts, body });
127
+ }
120
128
  delete(path, opts) {
121
129
  return this.request('DELETE', path, opts);
122
130
  }