@formigio/fazemos-cli 0.10.8 → 0.10.10

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.
package/dist/api.d.ts CHANGED
@@ -29,6 +29,14 @@ export interface ApiOptions {
29
29
  projectSlug?: string;
30
30
  allProjects?: boolean;
31
31
  noProjectHeader?: boolean;
32
+ /**
33
+ * Extra request headers merged on top of the standard auth/org/project
34
+ * headers. Used by callers that need optimistic-concurrency or other
35
+ * out-of-band headers (e.g., I30 force-transition's `If-Match: <n>` opt-in).
36
+ * Caller-supplied keys win on conflict — this is intentional so a caller
37
+ * can override `Content-Type` if needed.
38
+ */
39
+ headers?: Record<string, string>;
32
40
  }
33
41
  /**
34
42
  * Resolve the project id to send as X-Fazemos-Project-Id on a scoped call.
package/dist/api.js CHANGED
@@ -119,6 +119,14 @@ export async function api(method, path, body, opts = {}) {
119
119
  headers['X-Fazemos-Project-Id'] = projectId;
120
120
  }
121
121
  }
122
+ // I30 — caller-supplied extra headers (e.g., If-Match for opt-in optimistic
123
+ // concurrency on force-transition). Applied last so callers can override
124
+ // anything we set above on purpose.
125
+ if (opts.headers) {
126
+ for (const [k, v] of Object.entries(opts.headers)) {
127
+ headers[k] = v;
128
+ }
129
+ }
122
130
  // Build URL with optional ?view=all append. We don't try to be clever
123
131
  // about merging with existing query strings here — callers that use
124
132
  // --all-projects know they're on GET list endpoints with no other query.
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4022,18 +4022,114 @@ pipelines
4022
4022
  process.exit(1);
4023
4023
  }
4024
4024
  });
4025
+ // I30 — `pl force-cancel` removed. Replaced by the generalised
4026
+ // `pl force-transition pipeline <id> --to cancelled` admin endpoint, which
4027
+ // covers the same emergency cancel path plus 12 more entity/state combos
4028
+ // across pipelines, steps, and executions. No shim: callers update or 404.
4025
4029
  pipelines
4026
- .command('force-cancel')
4027
- .description('Force-cancel a stuck pipeline instance from any state. Admin/owner only. Bypasses normal state transition rules.')
4028
- .argument('<id>', 'Instance ID')
4029
- .option('-r, --reason <reason>', 'Reason for force-cancel')
4030
- .action(async (id, opts) => {
4031
- try {
4032
- const body = {};
4030
+ .command('force-transition')
4031
+ .description('Force an entity (pipeline, step, or execution) into a target state. Admin / org owner / project member only. ' +
4032
+ 'Bypasses normal state transition rules and fires the appropriate subscriber chain (audit log, ECS stop, ' +
4033
+ 'agent reset, token revoke, etc.). Use only when the normal lifecycle is stuck.')
4034
+ .argument('<entity-type>', 'Entity type: pipeline | step | execution')
4035
+ .argument('<id>', 'Entity ID (pipeline_instance / step_instance / execution UUID)')
4036
+ .requiredOption('--to <state>', 'Target state (e.g., cancelled, failed, completed, in_progress, ...)')
4037
+ .option('-r, --reason <reason>', 'Free-form audit reason (recorded in audit_log)')
4038
+ .option('--output-data-file <path>', 'Path to a JSON file with output_data. Required when forcing a step with a structured output schema to "completed".')
4039
+ .option('--expect-version <n>', 'Optimistic-concurrency guard: send If-Match: "<n>" so the API rejects the call (409) ' +
4040
+ 'if the current entity version differs. Omit to bypass version checking (default).')
4041
+ .option('--json', 'Print the raw API response as JSON (machine-readable)')
4042
+ .action(async (entityType, id, opts) => {
4043
+ try {
4044
+ const valid = ['pipeline', 'step', 'execution'];
4045
+ if (!valid.includes(entityType)) {
4046
+ console.error(chalk.red(`Invalid entity-type "${entityType}". Must be one of: ${valid.join(', ')}`));
4047
+ process.exit(1);
4048
+ }
4049
+ if (!opts.to || typeof opts.to !== 'string' || !opts.to.trim()) {
4050
+ console.error(chalk.red('--to <state> is required'));
4051
+ process.exit(1);
4052
+ }
4053
+ // Body field names match the API contract verbatim:
4054
+ // target_state — required
4055
+ // reason — optional, free-form audit string
4056
+ // output_data — required for step→completed when the step has an
4057
+ // output schema; carrier rejects with 400 OUTPUT_DATA_*
4058
+ // otherwise.
4059
+ const body = { target_state: opts.to };
4033
4060
  if (opts.reason)
4034
4061
  body.reason = opts.reason;
4035
- const data = await api('POST', `/api/pipeline-instances/${id}/force-cancel`, body);
4036
- console.log(chalk.green(`Force-cancelled: ${data.instance?.name || id}`));
4062
+ if (opts.outputDataFile) {
4063
+ if (entityType !== 'step') {
4064
+ console.error(chalk.red('--output-data-file is only valid when entity-type is "step"'));
4065
+ process.exit(1);
4066
+ }
4067
+ let raw;
4068
+ try {
4069
+ raw = readFileSync(resolve(opts.outputDataFile), 'utf-8');
4070
+ }
4071
+ catch (err) {
4072
+ console.error(chalk.red(`Cannot read --output-data-file "${opts.outputDataFile}": ${err.message}`));
4073
+ process.exit(1);
4074
+ return;
4075
+ }
4076
+ let parsed;
4077
+ try {
4078
+ parsed = JSON.parse(raw);
4079
+ }
4080
+ catch (err) {
4081
+ console.error(chalk.red(`Invalid JSON in --output-data-file "${opts.outputDataFile}": ${err.message}`));
4082
+ process.exit(1);
4083
+ return;
4084
+ }
4085
+ body.output_data = parsed;
4086
+ }
4087
+ // --expect-version <n> opts the caller in to optimistic concurrency.
4088
+ // Default is bypass (no header) per the I30 spec Decision #4.
4089
+ const apiOpts = {};
4090
+ if (opts.expectVersion !== undefined) {
4091
+ const n = Number(opts.expectVersion);
4092
+ if (!Number.isInteger(n)) {
4093
+ console.error(chalk.red(`--expect-version must be an integer; got "${opts.expectVersion}"`));
4094
+ process.exit(1);
4095
+ }
4096
+ apiOpts.headers = { 'If-Match': String(n) };
4097
+ }
4098
+ const path = `/api/admin/force-transition/${entityType}/${id}`;
4099
+ const data = (await api('POST', path, body, apiOpts));
4100
+ if (opts.json) {
4101
+ console.log(JSON.stringify(data, null, 2));
4102
+ return;
4103
+ }
4104
+ // Human-readable summary. Per-entity payloads diverge (instance / step /
4105
+ // execution) so we surface whichever is present and always echo the
4106
+ // forensic fields (audit_log_id, subscribers_fired, subscriber_failures,
4107
+ // orphan_executions_cancelled).
4108
+ const entityPayload = data?.instance || data?.step || data?.execution || null;
4109
+ const label = entityPayload?.name || entityPayload?.step_name || entityPayload?.id || id;
4110
+ console.log(chalk.green(`Force-transitioned ${entityType} ${label} → ${opts.to}`));
4111
+ if (data?.audit_log_id) {
4112
+ console.log(chalk.gray(` audit_log_id: ${data.audit_log_id}`));
4113
+ }
4114
+ const fired = Array.isArray(data?.subscribers_fired) ? data.subscribers_fired : [];
4115
+ if (fired.length) {
4116
+ console.log(chalk.gray(` subscribers_fired: ${fired.join(', ')}`));
4117
+ }
4118
+ const failures = Array.isArray(data?.subscriber_failures)
4119
+ ? data.subscriber_failures
4120
+ : [];
4121
+ if (failures.length) {
4122
+ console.log(chalk.yellow(` subscriber_failures: ${failures.length}`));
4123
+ for (const f of failures) {
4124
+ console.log(chalk.yellow(` - ${f.id || f.subscriber || '?'}: ${f.error}`));
4125
+ }
4126
+ }
4127
+ const orphans = Array.isArray(data?.orphan_executions_cancelled)
4128
+ ? data.orphan_executions_cancelled
4129
+ : [];
4130
+ if (orphans.length) {
4131
+ console.log(chalk.gray(` orphan_executions_cancelled: ${orphans.join(', ')}`));
4132
+ }
4037
4133
  }
4038
4134
  catch (err) {
4039
4135
  console.error(chalk.red(err.message));
@@ -4058,7 +4154,7 @@ pipelines
4058
4154
  });
4059
4155
  pipelines
4060
4156
  .command('set-status')
4061
- .description('Update instance status. Allowed: paused, cancelled. Use "pl force-cancel" for stuck instances.')
4157
+ .description('Update instance status. Allowed: paused, cancelled. Use "pl force-transition pipeline <id> --to cancelled" for stuck instances.')
4062
4158
  .argument('<id>', 'Instance ID')
4063
4159
  .requiredOption('--status <status>', 'New status (paused or cancelled)')
4064
4160
  .action(async (id, opts) => {
@@ -4066,7 +4162,7 @@ pipelines
4066
4162
  const valid = ['paused', 'cancelled'];
4067
4163
  if (!valid.includes(opts.status)) {
4068
4164
  console.error(chalk.red(`Invalid status. Must be one of: ${valid.join(', ')}`));
4069
- console.error(chalk.yellow('Tip: Use "pl force-cancel" to cancel stuck pipelines from any state.'));
4165
+ console.error(chalk.yellow('Tip: Use "pl force-transition pipeline <id> --to cancelled" to cancel stuck pipelines from any state.'));
4070
4166
  process.exit(1);
4071
4167
  }
4072
4168
  const data = await api('PATCH', `/api/pipeline-instances/${id}/status`, { status: opts.status });