@copado/agentia-cli 0.56.0-alpha.0 → 0.57.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ import { AgentiaCommand } from '../../../lib/agentia-command.js';
2
+ import { type PromotionRunResult } from '../../../lib/promotion-run.js';
3
+ export default class PromotionRun extends AgentiaCommand {
4
+ static args: {
5
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static description: string;
8
+ static examples: string[];
9
+ static flags: {
10
+ 'deployment-step-id': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'ignored-metadata-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ operation: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'recreate-promotion-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ resume: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ 'wait-timeout': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
17
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<PromotionRunResult>;
20
+ protected toErrorJson(err: unknown): unknown;
21
+ private execute;
22
+ private hooks;
23
+ }
@@ -0,0 +1,137 @@
1
+ import { confirm } from '@inquirer/prompts';
2
+ import { Args, Flags } from '@oclif/core';
3
+ import { AgentiaCommand } from '../../../lib/agentia-command.js';
4
+ import { formatPromotionRunResult, isPromotionRunExecutionError, parseIgnoredMetadataJson, performPromotionResume, performPromotionRun, PROMOTION_OPERATIONS, PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS, promotionRunErrorJson, PromotionRunValidationError, } from '../../../lib/promotion-run.js';
5
+ export default class PromotionRun extends AgentiaCommand {
6
+ static args = {
7
+ id: Args.string({
8
+ description: '18-character Salesforce Promotion ID',
9
+ required: true,
10
+ }),
11
+ };
12
+ static description = [
13
+ 'Preflight, start, and optionally wait for a Copado promotion execution.',
14
+ 'Use --resume to continue an existing failed or conflict-resolved execution without starting a duplicate promotion.',
15
+ ].join(' ');
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --operation merge',
18
+ '<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --operation merge_and_deploy --json',
19
+ '<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --resume a4NXXXXXXXXXXXXXXX',
20
+ ];
21
+ static flags = {
22
+ 'deployment-step-id': Flags.string({
23
+ description: 'Ordered deployment-step Salesforce ID. Can be provided multiple times.',
24
+ multiple: true,
25
+ }),
26
+ 'ignored-metadata-json': Flags.string({
27
+ description: 'JSON array to persist through ignored-metadata before starting the promotion.',
28
+ }),
29
+ operation: Flags.string({
30
+ description: 'Promotion operation. Required unless --resume is used.',
31
+ options: [...PROMOTION_OPERATIONS],
32
+ }),
33
+ 'recreate-promotion-branch': Flags.boolean({
34
+ description: 'Recreate the promotion branch before execution. Requires confirmation or --yes.',
35
+ }),
36
+ resume: Flags.string({
37
+ description: 'Resume this existing JobExecution ID instead of calling the promotion run endpoint.',
38
+ }),
39
+ wait: Flags.boolean({
40
+ allowNo: true,
41
+ default: true,
42
+ description: 'Poll promotion and deployment executions to terminal status.',
43
+ }),
44
+ 'wait-timeout': Flags.integer({
45
+ default: PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS,
46
+ description: 'Maximum total seconds to wait for promotion and deployment executions.',
47
+ }),
48
+ yes: Flags.boolean({
49
+ char: 'y',
50
+ default: false,
51
+ description: 'Confirm promotion branch recreation without prompting.',
52
+ }),
53
+ };
54
+ async run() {
55
+ const { args, flags } = await this.parse(PromotionRun);
56
+ const runFlags = flags;
57
+ if (!Number.isInteger(runFlags['wait-timeout']) || runFlags['wait-timeout'] <= 0) {
58
+ this.error('--wait-timeout must be a positive integer.', { exit: 2 });
59
+ }
60
+ if (runFlags.resume !== undefined && runFlags.operation !== undefined) {
61
+ this.error('Use --resume or --operation, not both.', { exit: 2 });
62
+ }
63
+ if (runFlags.resume === undefined && runFlags.operation === undefined) {
64
+ this.error('--operation is required unless --resume is used.', { exit: 2 });
65
+ }
66
+ if (runFlags.resume !== undefined) {
67
+ if (runFlags['deployment-step-id'] !== undefined ||
68
+ runFlags['ignored-metadata-json'] !== undefined ||
69
+ runFlags['recreate-promotion-branch'] === true) {
70
+ this.error('--resume cannot be combined with run request flags.', { exit: 2 });
71
+ }
72
+ return this.execute(() => performPromotionResume({
73
+ hooks: this.hooks(),
74
+ jobExecutionId: runFlags.resume,
75
+ promotionId: args.id,
76
+ timeoutSeconds: runFlags['wait-timeout'],
77
+ wait: runFlags.wait,
78
+ }));
79
+ }
80
+ if (runFlags['recreate-promotion-branch'] === true && !runFlags.yes) {
81
+ if (this.jsonEnabled() || !process.stdin.isTTY) {
82
+ this.error('Promotion branch recreation requires confirmation. Pass --yes for headless or JSON execution.', {
83
+ exit: 2,
84
+ });
85
+ }
86
+ const confirmed = await confirm({
87
+ default: false,
88
+ message: `Recreate the promotion branch for ${args.id}? Existing promotion branch changes may be replaced.`,
89
+ });
90
+ if (!confirmed) {
91
+ this.error('Promotion canceled.', { exit: 1 });
92
+ }
93
+ }
94
+ return this.execute(() => performPromotionRun({
95
+ deploymentStepIds: runFlags['deployment-step-id'],
96
+ hooks: this.hooks(),
97
+ ignoredMetadata: parseIgnoredMetadataJson(runFlags['ignored-metadata-json']),
98
+ operation: runFlags.operation,
99
+ promotionId: args.id,
100
+ recreatePromotionBranch: runFlags['recreate-promotion-branch'],
101
+ timeoutSeconds: runFlags['wait-timeout'],
102
+ wait: runFlags.wait,
103
+ }));
104
+ }
105
+ toErrorJson(err) {
106
+ const base = super.toErrorJson(err);
107
+ return promotionRunErrorJson(base, err);
108
+ }
109
+ async execute(action) {
110
+ try {
111
+ const result = await action();
112
+ this.display(() => this.log(formatPromotionRunResult(result)));
113
+ return result;
114
+ }
115
+ catch (error) {
116
+ if (error instanceof PromotionRunValidationError) {
117
+ this.error(error.message, { exit: 2 });
118
+ }
119
+ if (isPromotionRunExecutionError(error)) {
120
+ this.display(() => {
121
+ if (error.result !== undefined) {
122
+ this.log(formatPromotionRunResult(error.result));
123
+ }
124
+ });
125
+ error.oclif = { exit: 1 };
126
+ }
127
+ throw error;
128
+ }
129
+ }
130
+ hooks() {
131
+ return {
132
+ log: (message) => this.display(() => this.log(message)),
133
+ withSpinner: (message, action) => this.withSpinner(message, action),
134
+ };
135
+ }
136
+ }
137
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../src/commands/cicd/promotion/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { AgentiaCommand } from '../../../lib/agentia-command.js';
2
+ import { type PromotionRunResult } from '../../../lib/promotion-run.js';
3
+ export type WorkPromoteResult = PromotionRunResult & {
4
+ workItemId: string;
5
+ };
6
+ export default class WorkPromote extends AgentiaCommand {
7
+ static args: {
8
+ id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
9
+ };
10
+ static description: string;
11
+ static examples: string[];
12
+ static flags: {
13
+ cloud: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ deploy: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ 'deployment-step-id': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ 'ignored-metadata-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ 'promotion-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ 'recreate-promotion-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
+ 'wait-timeout': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
21
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
+ };
23
+ run(): Promise<WorkPromoteResult>;
24
+ protected toErrorJson(err: unknown): unknown;
25
+ }
@@ -0,0 +1,141 @@
1
+ import { confirm } from '@inquirer/prompts';
2
+ import { Args, Flags } from '@oclif/core';
3
+ import { AgentiaCommand } from '../../../lib/agentia-command.js';
4
+ import { formatPromotionRunResult, isPromotionRunExecutionError, parseIgnoredMetadataJson, performPromotionRun, PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS, promotionRunErrorJson, PromotionRunValidationError, resolvePromotionIdForWorkItem, } from '../../../lib/promotion-run.js';
5
+ import { resolveWorkItemId, WorkActiveResolutionError } from '../../../lib/work-active.js';
6
+ export default class WorkPromote extends AgentiaCommand {
7
+ static args = {
8
+ id: Args.string({
9
+ description: 'User Story ID (defaults to the active work item from `work set`)',
10
+ required: false,
11
+ }),
12
+ };
13
+ static description = [
14
+ 'Promote the explicit or active User Story through its Copado Promotion.',
15
+ 'Requires --cloud and selects promote-only unless --deploy is passed.',
16
+ ].join(' ');
17
+ static examples = [
18
+ '<%= config.bin %> <%= command.id %> --cloud',
19
+ '<%= config.bin %> <%= command.id %> a07XXXXXXXXXXXXXXX --cloud --promotion-id a0BXXXXXXXXXXXXXXX',
20
+ '<%= config.bin %> <%= command.id %> --cloud --deploy --json',
21
+ ];
22
+ static flags = {
23
+ cloud: Flags.boolean({
24
+ default: false,
25
+ description: 'Use the Copado cloud promotion API. Required for this command.',
26
+ }),
27
+ deploy: Flags.boolean({
28
+ default: false,
29
+ description: 'Use merge_and_deploy instead of promote-only merge.',
30
+ }),
31
+ 'deployment-step-id': Flags.string({
32
+ description: 'Ordered deployment-step Salesforce ID. Can be provided multiple times with --deploy.',
33
+ multiple: true,
34
+ }),
35
+ 'ignored-metadata-json': Flags.string({
36
+ description: 'JSON array to persist through ignored-metadata before starting the promotion.',
37
+ }),
38
+ 'promotion-id': Flags.string({
39
+ description: 'Explicit 18-character Promotion ID when the User Story belongs to multiple promotions.',
40
+ }),
41
+ 'recreate-promotion-branch': Flags.boolean({
42
+ description: 'Recreate the promotion branch before execution. Requires confirmation or --yes.',
43
+ }),
44
+ wait: Flags.boolean({
45
+ allowNo: true,
46
+ default: true,
47
+ description: 'Poll promotion and deployment executions to terminal status.',
48
+ }),
49
+ 'wait-timeout': Flags.integer({
50
+ default: PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS,
51
+ description: 'Maximum total seconds to wait for promotion and deployment executions.',
52
+ }),
53
+ yes: Flags.boolean({
54
+ char: 'y',
55
+ default: false,
56
+ description: 'Confirm promotion branch recreation without prompting.',
57
+ }),
58
+ };
59
+ async run() {
60
+ const { args, flags } = await this.parse(WorkPromote);
61
+ const promoteFlags = flags;
62
+ if (!promoteFlags.cloud) {
63
+ this.error('Only cloud promotion is supported for this command. Pass --cloud.', { exit: 2 });
64
+ }
65
+ if (!Number.isInteger(promoteFlags['wait-timeout']) || promoteFlags['wait-timeout'] <= 0) {
66
+ this.error('--wait-timeout must be a positive integer.', { exit: 2 });
67
+ }
68
+ if (!promoteFlags.deploy && promoteFlags['deployment-step-id'] !== undefined) {
69
+ this.error('--deployment-step-id requires --deploy.', { exit: 2 });
70
+ }
71
+ let workItemId;
72
+ try {
73
+ workItemId = await resolveWorkItemId(args.id);
74
+ }
75
+ catch (error) {
76
+ if (error instanceof WorkActiveResolutionError) {
77
+ this.error(error.message, {
78
+ exit: 1,
79
+ suggestions: [`${this.config.bin} cicd work set <id>`],
80
+ });
81
+ }
82
+ throw error;
83
+ }
84
+ try {
85
+ const promotionId = await this.withSpinner('Resolving User Story promotion', () => resolvePromotionIdForWorkItem(workItemId, promoteFlags['promotion-id']));
86
+ if (promoteFlags['recreate-promotion-branch'] === true && !promoteFlags.yes) {
87
+ if (this.jsonEnabled() || !process.stdin.isTTY) {
88
+ this.error('Promotion branch recreation requires confirmation. Pass --yes for headless or JSON execution.', {
89
+ exit: 2,
90
+ });
91
+ }
92
+ const confirmed = await confirm({
93
+ default: false,
94
+ message: `Recreate the promotion branch for ${promotionId}? Existing promotion branch changes may be replaced.`,
95
+ });
96
+ if (!confirmed) {
97
+ this.error('Promotion canceled.', { exit: 1 });
98
+ }
99
+ }
100
+ const result = await performPromotionRun({
101
+ deploymentStepIds: promoteFlags['deployment-step-id'],
102
+ hooks: {
103
+ log: (message) => this.display(() => this.log(message)),
104
+ withSpinner: (message, action) => this.withSpinner(message, action),
105
+ },
106
+ ignoredMetadata: parseIgnoredMetadataJson(promoteFlags['ignored-metadata-json']),
107
+ operation: promoteFlags.deploy ? 'merge_and_deploy' : 'merge',
108
+ promotionId,
109
+ recreatePromotionBranch: promoteFlags['recreate-promotion-branch'],
110
+ timeoutSeconds: promoteFlags['wait-timeout'],
111
+ wait: promoteFlags.wait,
112
+ });
113
+ const workResult = { ...result, workItemId };
114
+ this.display(() => {
115
+ this.log(`User Story: ${workItemId}`);
116
+ this.log(formatPromotionRunResult(result));
117
+ });
118
+ return workResult;
119
+ }
120
+ catch (error) {
121
+ if (error instanceof PromotionRunValidationError) {
122
+ this.error(error.message, { exit: 2 });
123
+ }
124
+ if (isPromotionRunExecutionError(error)) {
125
+ this.display(() => {
126
+ if (error.result !== undefined) {
127
+ this.log(`User Story: ${workItemId}`);
128
+ this.log(formatPromotionRunResult(error.result));
129
+ }
130
+ });
131
+ error.oclif = { exit: 1 };
132
+ }
133
+ throw error;
134
+ }
135
+ }
136
+ toErrorJson(err) {
137
+ const base = super.toErrorJson(err);
138
+ return promotionRunErrorJson(base, err);
139
+ }
140
+ }
141
+ //# sourceMappingURL=promote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promote.js","sourceRoot":"","sources":["../../../../src/commands/cicd/work/promote.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { type PipelineConnection, type PipelineDescribe, type PipelineListFilter
10
10
  import { type ProjectDefaultScope } from '../project-defaults.js';
11
11
  import { type Project, type ProjectListFilters } from '../project-types.js';
12
12
  import { type PromotionConflict, type PromotionConflictMode, type PromotionConflictResolutionResult, type PromotionConflictUndoResult } from '../promotion-conflicts.js';
13
+ import { type PromotionOperation } from '../promotion-run.js';
13
14
  import { type PromotionDetail, type PromotionListFilters } from '../promotion-types.js';
14
15
  import { type GitRepository, type RepositoryValidateResult } from '../repository-types.js';
15
16
  import { type User } from '../user-types.js';
@@ -178,12 +179,26 @@ declare function environmentGet(args: {
178
179
  environment: Environment;
179
180
  }>;
180
181
  type PromotionListArgs = PromotionListFilters;
182
+ type PromotionRunArgs = {
183
+ confirmRecreate?: boolean;
184
+ deploymentStepIds?: string[];
185
+ ignoredMetadata?: unknown[];
186
+ operation?: PromotionOperation;
187
+ promotionId: string;
188
+ recreatePromotionBranch?: boolean;
189
+ resumeJobExecutionId?: string;
190
+ wait?: boolean;
191
+ waitTimeout?: number;
192
+ };
181
193
  declare function promotionList(args?: PromotionListArgs): Promise<Record<string, unknown>>;
182
194
  declare function promotionGet(args: {
183
195
  id: string;
184
196
  }): Promise<{
185
197
  promotion: PromotionDetail;
186
198
  }>;
199
+ declare function promotionRun(args: PromotionRunArgs): Promise<{
200
+ result: import("../promotion-run.js").PromotionRunResult;
201
+ }>;
187
202
  declare function environmentCreate(args: EnvironmentCreateArgs): Promise<{
188
203
  environment: Environment;
189
204
  }>;
@@ -475,6 +490,33 @@ export declare const agentiaMcpToolHandlers: {
475
490
  assignedToMe?: boolean;
476
491
  ownedByMe?: boolean;
477
492
  }) => Promise<Record<string, unknown>>;
493
+ workPromote: (args?: {
494
+ cloud?: boolean;
495
+ confirmRecreate?: boolean;
496
+ deploy?: boolean;
497
+ deploymentStepIds?: string[];
498
+ id?: string;
499
+ ignoredMetadata?: unknown[];
500
+ promotionId?: string;
501
+ recreatePromotionBranch?: boolean;
502
+ wait?: boolean;
503
+ waitTimeout?: number;
504
+ }) => Promise<{
505
+ workItemId: string;
506
+ context: Record<string, unknown>;
507
+ deploymentSteps: import("../promotion-run.js").PromotionDeploymentStep[];
508
+ ignoredMetadata?: unknown[];
509
+ jobMonitors: import("../promotion-run.js").PromotionJobMonitor[];
510
+ mode: "resume" | "run";
511
+ operation?: PromotionOperation;
512
+ promotionAfter?: PromotionDetail;
513
+ promotionBefore: PromotionDetail;
514
+ promotionId: string;
515
+ request?: import("../promotion-run.js").PromotionRunRequest;
516
+ resultId: string;
517
+ run: import("../promotion-run.js").PromotionRunResponse;
518
+ wait: boolean;
519
+ }>;
478
520
  workPush: () => Promise<import("../work-types.js").WorkPushResult>;
479
521
  workSet: (args: {
480
522
  baseBranch?: string;
@@ -996,6 +1038,7 @@ export declare const agentiaMcpToolHandlers: {
996
1038
  promotionConflictUnresolve: typeof promotionConflictUnresolve;
997
1039
  promotionGet: typeof promotionGet;
998
1040
  promotionList: typeof promotionList;
1041
+ promotionRun: typeof promotionRun;
999
1042
  repositoryCreate: typeof repositoryCreate;
1000
1043
  repositoryDelete: typeof repositoryDelete;
1001
1044
  repositoryGet: typeof repositoryGet;
@@ -27,6 +27,7 @@ import { buildSetValues, collectSelectedKeys } from '../project-default-flags.js
27
27
  import { PROJECT_DEFAULT_KEYS } from '../project-defaults.js';
28
28
  import { normalizeProject, normalizeProjectsListPage, projectEndpoint, projectsListEndpoint, } from '../project-types.js';
29
29
  import { buildPromotionConflictResolutionRequest, normalizePromotionConflicts, PROMOTION_CONFLICT_MODES, promotionConflictContentEndpoint, promotionConflictResolveEndpoint, promotionConflictsEndpoint, promotionConflictUndoEndpoint, withPromotionConflictErrorTranslation, } from '../promotion-conflicts.js';
30
+ import { performPromotionResume, performPromotionRun, PROMOTION_OPERATIONS, PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS, } from '../promotion-run.js';
30
31
  import { normalizePromotionDetail, normalizePromotionsListPage, promotionEndpoint, promotionListEndpoint, } from '../promotion-types.js';
31
32
  import { REPOSITORY_STRING_VALIDATION_KEYS, validateNonEmptyStringFields as validateRepositoryNonEmptyStringFields, } from '../repository-flags.js';
32
33
  import { normalizeRepositoriesListPage, normalizeRepository, normalizeRepositoryValidateResult, repositoriesEndpoint, REPOSITORY_AUTH_TYPES, REPOSITORY_PROVIDERS, REPOSITORY_SOURCE_FORMATS, repositoryEndpoint, repositoryResetEndpoint, repositoryValidateEndpoint, withRequiredRepositoryFields, } from '../repository-types.js';
@@ -52,6 +53,10 @@ async function environmentGet(args) {
52
53
  });
53
54
  return { environment };
54
55
  }
56
+ const silentPromotionRunHooks = {
57
+ log() { },
58
+ withSpinner: async (_message, action) => action(),
59
+ };
55
60
  async function promotionList(args = {}) {
56
61
  const response = await CicdGateway.call({
57
62
  endpoint: promotionListEndpoint(args),
@@ -66,6 +71,45 @@ async function promotionGet(args) {
66
71
  });
67
72
  return { promotion: normalizePromotionDetail(response) };
68
73
  }
74
+ async function promotionRun(args) {
75
+ const waitTimeout = args.waitTimeout ?? PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS;
76
+ if (!Number.isInteger(waitTimeout) || waitTimeout <= 0) {
77
+ throw new Error('waitTimeout must be a positive integer.');
78
+ }
79
+ if (args.recreatePromotionBranch === true && args.confirmRecreate !== true) {
80
+ throw new Error('recreatePromotionBranch requires confirmRecreate=true.');
81
+ }
82
+ if (args.resumeJobExecutionId !== undefined) {
83
+ if (args.operation !== undefined ||
84
+ args.deploymentStepIds !== undefined ||
85
+ args.ignoredMetadata !== undefined ||
86
+ args.recreatePromotionBranch !== undefined) {
87
+ throw new Error('resumeJobExecutionId cannot be combined with run request fields.');
88
+ }
89
+ const result = await performPromotionResume({
90
+ hooks: silentPromotionRunHooks,
91
+ jobExecutionId: args.resumeJobExecutionId,
92
+ promotionId: args.promotionId,
93
+ timeoutSeconds: waitTimeout,
94
+ wait: args.wait ?? true,
95
+ });
96
+ return { result };
97
+ }
98
+ if (args.operation === undefined) {
99
+ throw new Error('operation is required unless resumeJobExecutionId is provided.');
100
+ }
101
+ const result = await performPromotionRun({
102
+ deploymentStepIds: args.deploymentStepIds,
103
+ hooks: silentPromotionRunHooks,
104
+ ignoredMetadata: args.ignoredMetadata,
105
+ operation: args.operation,
106
+ promotionId: args.promotionId,
107
+ recreatePromotionBranch: args.recreatePromotionBranch,
108
+ timeoutSeconds: waitTimeout,
109
+ wait: args.wait ?? true,
110
+ });
111
+ return { result };
112
+ }
69
113
  async function environmentCreate(args) {
70
114
  const payload = buildCreatePayload(args.name, {
71
115
  'apex-test-level': args.apexTestLevel,
@@ -776,6 +820,7 @@ export const agentiaMcpToolHandlers = {
776
820
  promotionConflictUnresolve,
777
821
  promotionGet,
778
822
  promotionList,
823
+ promotionRun,
779
824
  repositoryCreate,
780
825
  repositoryDelete,
781
826
  repositoryGet,
@@ -912,6 +957,34 @@ export function registerAgentiaMcpTools(server) {
912
957
  },
913
958
  title: 'Agentia Promotion Get',
914
959
  }, (args) => safelyHandleTool(() => promotionGet(args)));
960
+ server.registerTool('agentia_promotion_run', {
961
+ description: 'Preflight, start, and optionally wait for a Copado promotion. Can also resume an existing execution without starting a duplicate run.',
962
+ inputSchema: {
963
+ confirmRecreate: z
964
+ .boolean()
965
+ .optional()
966
+ .describe('Required true when recreatePromotionBranch is true because MCP cannot prompt.'),
967
+ deploymentStepIds: z
968
+ .array(z.string())
969
+ .optional()
970
+ .describe('Ordered deployment-step Salesforce IDs. The gateway order is used when omitted.'),
971
+ ignoredMetadata: z.array(z.unknown()).optional().describe('Ignored metadata persisted before starting the run.'),
972
+ operation: z
973
+ .enum(PROMOTION_OPERATIONS)
974
+ .optional()
975
+ .describe('Promotion operation. Required unless resumeJobExecutionId is supplied.'),
976
+ promotionId: z.string().describe('18-character Salesforce Promotion ID.'),
977
+ recreatePromotionBranch: z.boolean().optional().describe('Recreate the promotion branch before execution.'),
978
+ resumeJobExecutionId: z.string().optional().describe('Resume this existing promotion execution instead of /run.'),
979
+ wait: z.boolean().optional().describe('Poll all created executions to terminal status. Defaults to true.'),
980
+ waitTimeout: z
981
+ .number()
982
+ .int()
983
+ .optional()
984
+ .describe(`Maximum total wait in seconds. Defaults to ${PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS}.`),
985
+ },
986
+ title: 'Agentia Promotion Run',
987
+ }, (args) => safelyHandleTool(() => promotionRun(args)));
915
988
  server.registerTool('agentia_job_list', {
916
989
  description: 'List Copado job executions via the CICD gateway.',
917
990
  inputSchema: {