@sanity/workflow-cli 0.12.0 → 0.14.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.
Files changed (55) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +77 -48
  3. package/dist/commands/{abort.d.ts → editorial-workflows/abort.d.ts} +4 -2
  4. package/dist/commands/{abort.js → editorial-workflows/abort.js} +8 -7
  5. package/dist/commands/{definition → editorial-workflows/definition}/delete.d.ts +4 -2
  6. package/dist/commands/{definition → editorial-workflows/definition}/delete.js +7 -6
  7. package/dist/commands/{definition → editorial-workflows/definition}/diff.d.ts +3 -1
  8. package/dist/commands/{definition → editorial-workflows/definition}/diff.js +8 -7
  9. package/dist/commands/{definition → editorial-workflows/definition}/list.d.ts +2 -1
  10. package/dist/commands/{definition → editorial-workflows/definition}/list.js +21 -21
  11. package/dist/commands/{definition → editorial-workflows/definition}/show.d.ts +3 -2
  12. package/dist/commands/{definition → editorial-workflows/definition}/show.js +7 -6
  13. package/dist/commands/{deploy.d.ts → editorial-workflows/deploy.d.ts} +4 -2
  14. package/dist/commands/{deploy.js → editorial-workflows/deploy.js} +26 -19
  15. package/dist/commands/{diagnose.d.ts → editorial-workflows/diagnose.d.ts} +3 -1
  16. package/dist/commands/{diagnose.js → editorial-workflows/diagnose.js} +8 -7
  17. package/dist/commands/{fire-action.d.ts → editorial-workflows/fire-action.d.ts} +4 -2
  18. package/dist/commands/{fire-action.js → editorial-workflows/fire-action.js} +9 -8
  19. package/dist/commands/{list.d.ts → editorial-workflows/list.d.ts} +2 -1
  20. package/dist/commands/{list.js → editorial-workflows/list.js} +24 -24
  21. package/dist/commands/editorial-workflows/nuke.d.ts +13 -0
  22. package/dist/commands/{nuke.js → editorial-workflows/nuke.js} +22 -17
  23. package/dist/commands/{reset-activity.d.ts → editorial-workflows/reset-activity.d.ts} +2 -1
  24. package/dist/commands/{reset-activity.js → editorial-workflows/reset-activity.js} +2 -1
  25. package/dist/commands/{set-stage.d.ts → editorial-workflows/set-stage.d.ts} +5 -3
  26. package/dist/commands/{set-stage.js → editorial-workflows/set-stage.js} +7 -6
  27. package/dist/commands/{show.d.ts → editorial-workflows/show.d.ts} +2 -1
  28. package/dist/commands/{show.js → editorial-workflows/show.js} +40 -26
  29. package/dist/commands/{start.d.ts → editorial-workflows/start.d.ts} +4 -2
  30. package/dist/commands/{start.js → editorial-workflows/start.js} +10 -9
  31. package/dist/commands/{tail.d.ts → editorial-workflows/tail.d.ts} +2 -1
  32. package/dist/commands/{tail.js → editorial-workflows/tail.js} +6 -5
  33. package/dist/hooks/finally/telemetry.js +2 -2
  34. package/dist/hooks/prerun/telemetry.d.ts +4 -3
  35. package/dist/lib/base-command.d.ts +4 -6
  36. package/dist/lib/base-command.js +6 -0
  37. package/dist/lib/context.d.ts +24 -9
  38. package/dist/lib/context.js +15 -6
  39. package/dist/lib/flags.d.ts +27 -4
  40. package/dist/lib/flags.js +17 -1
  41. package/dist/lib/nuke.d.ts +15 -1
  42. package/dist/lib/nuke.js +22 -1
  43. package/dist/lib/prompt.d.ts +3 -2
  44. package/dist/lib/select-deployment.d.ts +43 -16
  45. package/dist/lib/select-deployment.js +66 -15
  46. package/dist/lib/share-definitions.d.ts +23 -28
  47. package/dist/lib/share-definitions.js +26 -38
  48. package/dist/lib/telemetry-setup.d.ts +2 -2
  49. package/dist/lib/telemetry.d.ts +18 -10
  50. package/dist/lib/telemetry.js +5 -2
  51. package/dist/lib/ui.d.ts +12 -0
  52. package/dist/lib/ui.js +9 -0
  53. package/oclif.manifest.json +223 -66
  54. package/package.json +11 -9
  55. package/dist/commands/nuke.d.ts +0 -11
@@ -3,20 +3,22 @@ import { Flags } from '@oclif/core';
3
3
  import { computeDiffEntries, errorMessage, workflow, } from '@sanity/workflow-engine';
4
4
  import logSymbols from 'log-symbols';
5
5
  import ora from 'ora';
6
- import { WorkflowCommand } from "../lib/base-command.js";
7
- import { clientFor, resolveTokenOrFail } from "../lib/client.js";
8
- import { selectDefinitions, validateOrFail } from "../lib/definitions.js";
9
- import { diffReport } from "../lib/diff.js";
10
- import { fail, isAuthRejection } from "../lib/fail.js";
11
- import { tagFlags } from "../lib/flags.js";
12
- import { loadWorkflowConfig } from "../lib/load-config.js";
13
- import { deploymentToTarget, selectDeployments } from "../lib/select-deployment.js";
14
- import { shareDefinitionsAfterDeploy } from "../lib/share-definitions.js";
15
- import { cliTelemetry } from "../lib/telemetry.js";
16
- import { groupBanner } from "../lib/ui.js";
6
+ import { WorkflowCommand } from "../../lib/base-command.js";
7
+ import { clientFor, resolveTokenOrFail } from "../../lib/client.js";
8
+ import { selectDefinitions, validateOrFail } from "../../lib/definitions.js";
9
+ import { diffReport } from "../../lib/diff.js";
10
+ import { fail, isAuthRejection } from "../../lib/fail.js";
11
+ import { deploymentFlags } from "../../lib/flags.js";
12
+ import { loadWorkflowConfig } from "../../lib/load-config.js";
13
+ import { deploymentLabel, deploymentToTarget, selectDeployments, } from "../../lib/select-deployment.js";
14
+ import { shareDefinitionsAfterDeploy } from "../../lib/share-definitions.js";
15
+ import { cliTelemetry } from "../../lib/telemetry.js";
16
+ import { groupBanner } from "../../lib/ui.js";
17
17
  export default class Deploy extends WorkflowCommand {
18
+ static aliases = ['deploy'];
18
19
  static description = 'Validate, diff, and deploy workflow definitions to the resource bound by the selected deployment.';
19
20
  static examples = [
21
+ '<%= config.bin %> deploy --deployment review-prod',
20
22
  '<%= config.bin %> deploy --tag prod',
21
23
  '<%= config.bin %> deploy --all-tags',
22
24
  '<%= config.bin %> deploy --check',
@@ -24,11 +26,15 @@ export default class Deploy extends WorkflowCommand {
24
26
  '<%= config.bin %> deploy --only productLaunch',
25
27
  ];
26
28
  static flags = {
27
- ...tagFlags,
29
+ ...deploymentFlags,
30
+ tag: Flags.string({
31
+ description: 'Workflow environment tag (e.g. prod, test) — deploys every deployment carrying the tag (a tag is an environment group).',
32
+ exclusive: ['deployment'],
33
+ }),
28
34
  'all-tags': Flags.boolean({
29
- description: 'Deploy every deployment in the config, not just one tag.',
35
+ description: 'Deploy every deployment in the config, not just a selection.',
30
36
  default: false,
31
- exclusive: ['tag'],
37
+ exclusive: ['tag', 'deployment'],
32
38
  }),
33
39
  'dry-run': Flags.boolean({
34
40
  description: 'Validate + diff against the deployed version; do not write.',
@@ -43,14 +49,18 @@ export default class Deploy extends WorkflowCommand {
43
49
  }),
44
50
  'share-defs': Flags.boolean({
45
51
  allowNo: true,
46
- description: 'Share the definition documents newly created by this deploy with Sanity — the full document, verbatim (structure, names, filters, effect configuration, seeded values), plus its deployment coordinates (project and dataset, or resource id); never content documents, instances, or your Sanity auth token. Opt-out: an interactive terminal is asked once (the answer is remembered), while unattended runs (CI / non-TTY / DO_NOT_TRACK) share nothing unless --share-defs is passed. Use --no-share-defs to opt out. An explicit --share-defs also sends telemetry for this deploy regardless of CI / DO_NOT_TRACK.',
52
+ description: 'Share the definition documents newly created by this deploy with Sanity — the full document, verbatim (structure, names, filters, effect configuration, seeded values), plus its deployment coordinates (project and dataset, or resource id); never content documents, instances, or your Sanity auth token. Sharing is the default in every environment, including CI / non-TTY / DO_NOT_TRACK. Use --no-share-defs to opt out.',
47
53
  }),
48
54
  };
49
55
  async run() {
50
56
  const { flags } = await this.parse(Deploy);
51
57
  validateModeFlags(flags.check, flags['dry-run']);
52
58
  const config = await loadWorkflowConfig();
53
- const batches = buildBatches(selectDeployments(config, { tag: flags.tag, allTags: flags['all-tags'] }), flags.only);
59
+ const batches = buildBatches(await selectDeployments(config, {
60
+ name: flags.deployment,
61
+ tag: flags.tag,
62
+ allTags: flags['all-tags'],
63
+ }), flags.only);
54
64
  const log = (line) => this.log(line);
55
65
  if (flags.check) {
56
66
  await reconcileBatches({
@@ -144,9 +154,6 @@ export function validateModeFlags(check, dryRun) {
144
154
  fail('Pass either --check or --dry-run, not both.');
145
155
  }
146
156
  }
147
- function deploymentLabel({ name, tag }) {
148
- return `${name} (${tag})`;
149
- }
150
157
  export function buildBatches(deployments, only) {
151
158
  return deployments.map((deployment) => {
152
159
  const context = deployments.length > 1 ? `${deploymentLabel(deployment)} — ` : '';
@@ -1,5 +1,5 @@
1
1
  import { type Diagnosis, type DiagnoseInput, type SuggestedRemediation, type WorkflowEvaluation } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
3
  /** The `--json` transitions payload: raw derived state (atom GROQ, negation,
4
4
  * pivotality, solvable requirement) — structure for scripts, never baked
5
5
  * English. Pure so the shape is a testable contract. */
@@ -32,6 +32,7 @@ export declare function renderDiagnosis({ diagnosis, input, remediations, explan
32
32
  explanations?: ReadonlyMap<string, string> | undefined;
33
33
  }): string[];
34
34
  export default class Diagnose extends WorkflowCommand {
35
+ static aliases: string[];
35
36
  static description: string;
36
37
  static examples: string[];
37
38
  static args: {
@@ -39,6 +40,7 @@ export default class Diagnose extends WorkflowCommand {
39
40
  };
40
41
  static flags: {
41
42
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
43
+ deployment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
42
44
  tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
43
45
  };
44
46
  run(): Promise<void>;
@@ -2,12 +2,12 @@ import { styleText } from 'node:util';
2
2
  import { Args } from '@oclif/core';
3
3
  import { diagnoseInputFromEvaluation, workflow, unsatisfiedTransitionSummaries, } from '@sanity/workflow-engine';
4
4
  import logSymbols from 'log-symbols';
5
- import { WorkflowCommand } from "../lib/base-command.js";
6
- import { resolveInstanceContext } from "../lib/context.js";
7
- import { fail, failureDetail } from "../lib/fail.js";
8
- import { jsonFlags, tagFlags } from "../lib/flags.js";
9
- import { baseEngineArgs } from "../lib/operation-args.js";
10
- import { formatTimestamp, sectionHeader, activityIcon } from "../lib/ui.js";
5
+ import { WorkflowCommand } from "../../lib/base-command.js";
6
+ import { resolveInstanceContext } from "../../lib/context.js";
7
+ import { fail, failureDetail } from "../../lib/fail.js";
8
+ import { instanceFlags, jsonFlags } from "../../lib/flags.js";
9
+ import { baseEngineArgs } from "../../lib/operation-args.js";
10
+ import { formatTimestamp, sectionHeader, activityIcon } from "../../lib/ui.js";
11
11
  import { instanceHeader } from "./show.js";
12
12
  function formatAssignee(a) {
13
13
  return a.type === 'user' ? `user:${a.id}` : `role:${a.role}`;
@@ -212,6 +212,7 @@ export function renderDiagnosis({ diagnosis, input, remediations, explanations,
212
212
  return lines;
213
213
  }
214
214
  export default class Diagnose extends WorkflowCommand {
215
+ static aliases = ['diagnose'];
215
216
  static description = "Explain why a workflow instance is or isn't progressing, and what would unstick it.";
216
217
  static examples = [
217
218
  '<%= config.bin %> diagnose wf-instance.abc123',
@@ -222,7 +223,7 @@ export default class Diagnose extends WorkflowCommand {
222
223
  instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
223
224
  };
224
225
  static flags = {
225
- ...tagFlags,
226
+ ...instanceFlags,
226
227
  ...jsonFlags,
227
228
  };
228
229
  async run() {
@@ -1,6 +1,6 @@
1
1
  import { type AvailableAction } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
3
- import { type WriteOutcome, type WriteReport } from '../lib/ops-report.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
+ import { type WriteOutcome, type WriteReport } from '../../lib/ops-report.ts';
4
4
  /**
5
5
  * The list-mode body: every action on the current stage's activities, marked
6
6
  * fireable or not (with the disabling reason), plus a hint showing the
@@ -30,6 +30,7 @@ export declare function fireActionReport({ result, activity, action, }: {
30
30
  action: string;
31
31
  }): WriteReport;
32
32
  export default class FireAction extends WorkflowCommand {
33
+ static aliases: string[];
33
34
  static description: string;
34
35
  static examples: string[];
35
36
  static args: {
@@ -40,6 +41,7 @@ export default class FireAction extends WorkflowCommand {
40
41
  activity: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
41
42
  action: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
42
43
  param: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
44
+ deployment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
43
45
  tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
44
46
  };
45
47
  run(): Promise<void>;
@@ -2,13 +2,13 @@ import { styleText } from 'node:util';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { actionRendering, actionDisabledDetail, deniedGuardLabels, workflow, } from '@sanity/workflow-engine';
4
4
  import logSymbols from 'log-symbols';
5
- import { WorkflowCommand } from "../lib/base-command.js";
6
- import { resolveInstanceContext } from "../lib/context.js";
7
- import { fail, failOnThrow, failureDetail } from "../lib/fail.js";
8
- import { jsonFlags, tagFlags } from "../lib/flags.js";
9
- import { baseEngineArgs } from "../lib/operation-args.js";
10
- import { cascadeTail, opsAppliedLines, runWriteVerb, } from "../lib/ops-report.js";
11
- import { parseParams } from "../lib/params.js";
5
+ import { WorkflowCommand } from "../../lib/base-command.js";
6
+ import { resolveInstanceContext } from "../../lib/context.js";
7
+ import { fail, failOnThrow, failureDetail } from "../../lib/fail.js";
8
+ import { instanceFlags, jsonFlags } from "../../lib/flags.js";
9
+ import { baseEngineArgs } from "../../lib/operation-args.js";
10
+ import { cascadeTail, opsAppliedLines, runWriteVerb, } from "../../lib/ops-report.js";
11
+ import { parseParams } from "../../lib/params.js";
12
12
  import { instanceHeader } from "./show.js";
13
13
  function reasonText(reason) {
14
14
  if (reason.kind === 'mutation-guard-denied') {
@@ -82,6 +82,7 @@ export function fireActionReport({ result, activity, action, }) {
82
82
  };
83
83
  }
84
84
  export default class FireAction extends WorkflowCommand {
85
+ static aliases = ['fire-action'];
85
86
  static description = 'Fire an action on an instance to unstick a waiting activity — the write acts as the configured token. Omit --action to list what can be fired.';
86
87
  static examples = [
87
88
  '<%= config.bin %> fire-action wf-instance.abc123',
@@ -92,7 +93,7 @@ export default class FireAction extends WorkflowCommand {
92
93
  instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
93
94
  };
94
95
  static flags = {
95
- ...tagFlags,
96
+ ...instanceFlags,
96
97
  activity: Flags.string({
97
98
  description: 'Activity the action belongs to. Required to fire; omit --action to list.',
98
99
  }),
@@ -1,5 +1,5 @@
1
1
  import { type TerminalState } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
3
  interface InstanceRow {
4
4
  _id: string;
5
5
  definition: string;
@@ -45,6 +45,7 @@ export declare function instanceRow(r: InstanceRow): {
45
45
  lastChangedAt: string;
46
46
  };
47
47
  export default class List extends WorkflowCommand {
48
+ static aliases: string[];
48
49
  static description: string;
49
50
  static examples: string[];
50
51
  static flags: {
@@ -1,12 +1,12 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import { WORKFLOW_INSTANCE_TYPE, assertReadableModel, documentPrefilter, inFlightFilter, instanceWatchesDocument, tagScopeFilter, terminalState, } from '@sanity/workflow-engine';
3
3
  import logSymbols from 'log-symbols';
4
- import { WorkflowCommand } from "../lib/base-command.js";
5
- import { resolveReadTargets } from "../lib/context.js";
6
- import { failOnThrow } from "../lib/fail.js";
7
- import { tagFlags } from "../lib/flags.js";
8
- import { runReadAcrossTargets } from "../lib/read-fanout.js";
9
- import { clipToLimit, formatAge, formatTable } from "../lib/ui.js";
4
+ import { WorkflowCommand } from "../../lib/base-command.js";
5
+ import { resolveReadTargets } from "../../lib/context.js";
6
+ import { failOnThrow } from "../../lib/fail.js";
7
+ import { tagFlags } from "../../lib/flags.js";
8
+ import { runReadAcrossTargets } from "../../lib/read-fanout.js";
9
+ import { formatAge, logClippedTable } from "../../lib/ui.js";
10
10
  export function buildListQuery(flags) {
11
11
  const filters = [`_type == "${WORKFLOW_INSTANCE_TYPE}"`];
12
12
  const params = {};
@@ -56,6 +56,7 @@ export function instanceRow(r) {
56
56
  };
57
57
  }
58
58
  export default class List extends WorkflowCommand {
59
+ static aliases = ['list'];
59
60
  static description = 'List workflow instances in the configured dataset (in-flight by default).';
60
61
  static examples = [
61
62
  '<%= config.bin %> list',
@@ -100,24 +101,23 @@ export default class List extends WorkflowCommand {
100
101
  this.log(`${logSymbols.info} no instances match`);
101
102
  return;
102
103
  }
103
- const { rows, note } = clipToLimit(fetched, flags.limit);
104
- const lines = formatTable(['instance', 'workflow', 'tag', 'stage', 'status', 'updated'], rows.map((r) => {
105
- const row = instanceRow(r);
106
- return [
107
- row._id,
108
- row.definition,
109
- row.tag,
110
- row.currentStage,
111
- row.status,
112
- formatAge(row.lastChangedAt),
113
- ];
114
- }));
115
- for (const line of lines) {
116
- this.log(line);
117
- }
118
- if (note) {
119
- this.log(note);
120
- }
104
+ logClippedTable({
105
+ rows: fetched,
106
+ limit: flags.limit,
107
+ headers: ['instance', 'workflow', 'tag', 'stage', 'status', 'updated'],
108
+ toCells: (r) => {
109
+ const row = instanceRow(r);
110
+ return [
111
+ row._id,
112
+ row.definition,
113
+ row.tag,
114
+ row.currentStage,
115
+ row.status,
116
+ formatAge(row.lastChangedAt),
117
+ ];
118
+ },
119
+ log: (line) => this.log(line),
120
+ });
121
121
  },
122
122
  });
123
123
  if (failures.length > 0) {
@@ -0,0 +1,13 @@
1
+ import { WorkflowCommand } from '../../lib/base-command.ts';
2
+ export default class Nuke extends WorkflowCommand {
3
+ static aliases: string[];
4
+ static summary: string;
5
+ static description: string;
6
+ static examples: string[];
7
+ static flags: {
8
+ deployment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -2,29 +2,34 @@ import { Flags } from '@oclif/core';
2
2
  import { input } from '@sanity/cli-core/ux';
3
3
  import { resourceGdr } from '@sanity/workflow-engine';
4
4
  import logSymbols from 'log-symbols';
5
- import { WorkflowCommand } from "../lib/base-command.js";
6
- import { clientFor, resolveApiHost, resolveTokenOrFail } from "../lib/client.js";
7
- import { dedupeResources } from "../lib/context.js";
8
- import { fail } from "../lib/fail.js";
9
- import { loadWorkflowConfig } from "../lib/load-config.js";
10
- import { confirmationMatches, executeNuke, formatNukeSummary, involvedTargets, planCounts, renderNukePlan, resolveNukePlan, } from "../lib/nuke.js";
11
- import { runWriteVerb } from "../lib/ops-report.js";
12
- import { canPromptOnStderr } from "../lib/prompt.js";
13
- import { selectDeployment } from "../lib/select-deployment.js";
5
+ import { WorkflowCommand } from "../../lib/base-command.js";
6
+ import { clientFor, resolveApiHost, resolveTokenOrFail } from "../../lib/client.js";
7
+ import { dedupeResources } from "../../lib/context.js";
8
+ import { fail } from "../../lib/fail.js";
9
+ import { loadWorkflowConfig } from "../../lib/load-config.js";
10
+ import { confirmationMatches, executeNuke, formatNukeSummary, involvedTargets, planCounts, refuseOverlappingNuke, renderNukePlan, resolveNukePlan, sweptResources, } from "../../lib/nuke.js";
11
+ import { runWriteVerb } from "../../lib/ops-report.js";
12
+ import { canPromptOnStderr } from "../../lib/prompt.js";
13
+ import { selectDeployment } from "../../lib/select-deployment.js";
14
14
  export default class Nuke extends WorkflowCommand {
15
+ static aliases = ['nuke'];
15
16
  static summary = 'Delete every engine-owned document for a deployment tag — the dev-period big red button.';
16
17
  static description = 'The reset for a dataset holding engine documents the versioned upgrade framework cannot yet ' +
17
18
  "migrate: deletes the tag's instances, definitions, and guards (across every alias-bound " +
18
19
  'resource). Content documents are never touched. Prints a dry-run plan, then requires you to ' +
19
20
  'type back every involved dataset (--force skips the prompt; the plan still prints).';
20
21
  static examples = [
21
- '<%= config.bin %> nuke --tag plugin-dev',
22
+ '<%= config.bin %> nuke --deployment plugin-dev',
22
23
  '<%= config.bin %> nuke --tag plugin-dev --force',
23
24
  ];
24
25
  static flags = {
26
+ deployment: Flags.string({
27
+ description: 'The deployment name to reset.',
28
+ exactlyOne: ['deployment', 'tag'],
29
+ }),
25
30
  tag: Flags.string({
26
- description: 'The deployment tag to reset. Required a destructive reset never guesses the environment.',
27
- required: true,
31
+ description: 'The deployment tag to reset (while it names exactly one deployment).',
32
+ exactlyOne: ['deployment', 'tag'],
28
33
  }),
29
34
  force: Flags.boolean({
30
35
  description: 'Skip the confirmation prompt (for scripts/CI). The plan still prints.',
@@ -34,7 +39,8 @@ export default class Nuke extends WorkflowCommand {
34
39
  async run() {
35
40
  const { flags } = await this.parse(Nuke);
36
41
  const config = await loadWorkflowConfig();
37
- const deployment = selectDeployment(config, { tag: flags.tag });
42
+ const deployment = selectDeployment(config, { name: flags.deployment, tag: flags.tag });
43
+ refuseOverlappingNuke(config.deployments, deployment);
38
44
  const targets = buildTargets(deployment, await resolveTokenOrFail());
39
45
  const plan = await resolveNukePlan({ tag: deployment.tag, targets });
40
46
  const apiHost = resolveApiHost() ?? 'https://api.sanity.io (production default)';
@@ -57,12 +63,11 @@ export default class Nuke extends WorkflowCommand {
57
63
  }
58
64
  }
59
65
  function buildTargets(deployment, token) {
60
- const engineResource = deployment.workflowResource;
61
- const aliasResources = (deployment.resourceAliases ?? []).map((binding) => binding.resource);
62
- return dedupeResources([engineResource, ...aliasResources]).map((resource) => ({
66
+ const engineGdr = resourceGdr(deployment.workflowResource);
67
+ return dedupeResources(sweptResources(deployment)).map((resource) => ({
63
68
  resource,
64
69
  client: clientFor(resource, token),
65
- holdsEngineDocs: resourceGdr(resource) === resourceGdr(engineResource),
70
+ holdsEngineDocs: resourceGdr(resource) === engineGdr,
66
71
  }));
67
72
  }
68
73
  async function confirmOrFail(targets) {
@@ -1,5 +1,6 @@
1
- import { StubCommand } from '../lib/stub.ts';
1
+ import { StubCommand } from '../../lib/stub.ts';
2
2
  export default class ResetActivity extends StubCommand {
3
+ static hiddenAliases: string[];
3
4
  static hidden: boolean;
4
5
  static description: string;
5
6
  static args: {
@@ -1,6 +1,7 @@
1
1
  import { Args } from '@oclif/core';
2
- import { StubCommand } from "../lib/stub.js";
2
+ import { StubCommand } from "../../lib/stub.js";
3
3
  export default class ResetActivity extends StubCommand {
4
+ static hiddenAliases = ['reset-activity'];
4
5
  static hidden = true;
5
6
  static description = 'Reset a failed activity on an in-flight instance — back to pending (re-run) or to skipped (bypass).';
6
7
  static args = {
@@ -1,8 +1,9 @@
1
1
  import { type SetStageArgs, type WorkflowInstance } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
3
- import { type EngineScope } from '../lib/operation-args.ts';
4
- import { type WriteOutcome, type WriteReport } from '../lib/ops-report.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
+ import { type EngineScope } from '../../lib/operation-args.ts';
4
+ import { type WriteOutcome, type WriteReport } from '../../lib/ops-report.ts';
5
5
  export default class SetStage extends WorkflowCommand {
6
+ static aliases: string[];
6
7
  static description: string;
7
8
  static examples: string[];
8
9
  static args: {
@@ -11,6 +12,7 @@ export default class SetStage extends WorkflowCommand {
11
12
  static flags: {
12
13
  to: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
14
  reason: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ deployment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
16
  tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
17
  };
16
18
  run(): Promise<void>;
@@ -1,12 +1,13 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { workflow } from '@sanity/workflow-engine';
4
- import { WorkflowCommand } from "../lib/base-command.js";
5
- import { resolveInstanceContext } from "../lib/context.js";
6
- import { tagFlags } from "../lib/flags.js";
7
- import { buildOperationArgs } from "../lib/operation-args.js";
8
- import { cascadeTail, opsAppliedLines, runWriteVerb, } from "../lib/ops-report.js";
4
+ import { WorkflowCommand } from "../../lib/base-command.js";
5
+ import { resolveInstanceContext } from "../../lib/context.js";
6
+ import { instanceFlags } from "../../lib/flags.js";
7
+ import { buildOperationArgs } from "../../lib/operation-args.js";
8
+ import { cascadeTail, opsAppliedLines, runWriteVerb, } from "../../lib/ops-report.js";
9
9
  export default class SetStage extends WorkflowCommand {
10
+ static aliases = ['set-stage'];
10
11
  static description = "Force an instance into a stage, regardless of its declared transitions and filters — the engine's setStage admin override. The target stage's enter lifecycle still runs (auto-activities start, stage guards reconcile), and the post-move cascade can immediately auto-transition the instance onward.";
11
12
  static examples = [
12
13
  '<%= config.bin %> set-stage wf-instance.abc123 --to ready',
@@ -19,7 +20,7 @@ export default class SetStage extends WorkflowCommand {
19
20
  }),
20
21
  };
21
22
  static flags = {
22
- ...tagFlags,
23
+ ...instanceFlags,
23
24
  to: Flags.string({
24
25
  required: true,
25
26
  description: 'Target stage name.',
@@ -1,6 +1,7 @@
1
1
  import { type WorkflowInstance } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
3
  export default class Show extends WorkflowCommand {
4
+ static aliases: string[];
4
5
  static description: string;
5
6
  static examples: string[];
6
7
  static args: {
@@ -2,11 +2,12 @@ import { styleText } from 'node:util';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { abortReason, displayTitle, terminalState, } from '@sanity/workflow-engine';
4
4
  import logSymbols from 'log-symbols';
5
- import { WorkflowCommand } from "../lib/base-command.js";
6
- import { findInstance, resolveReadTargets } from "../lib/context.js";
7
- import { tagFlags } from "../lib/flags.js";
8
- import { formatKeyValue, formatTimestamp, sectionHeader, activityIcon } from "../lib/ui.js";
5
+ import { WorkflowCommand } from "../../lib/base-command.js";
6
+ import { findInstance, resolveReadTargets } from "../../lib/context.js";
7
+ import { tagFlags } from "../../lib/flags.js";
8
+ import { formatKeyValue, formatTimestamp, sectionHeader, activityIcon } from "../../lib/ui.js";
9
9
  export default class Show extends WorkflowCommand {
10
+ static aliases = ['show'];
10
11
  static description = 'Show the state, activities, and effects of a workflow instance.';
11
12
  static examples = [
12
13
  '<%= config.bin %> show wf-instance.abc123',
@@ -67,27 +68,40 @@ export function instanceHeader(instance) {
67
68
  return [title, ...rows].join('\n');
68
69
  }
69
70
  export function describeInstance(instance, options) {
70
- const lines = [sectionHeader('Stages')];
71
- for (const stage of instance.stages) {
72
- const marker = stage.exitedAt
73
- ? styleText('dim', ` (exited ${formatTimestamp(stage.exitedAt)})`)
74
- : styleText('cyan', ' (current)');
75
- lines.push(` • ${stage.name}${marker}`);
76
- for (const activity of stage.activities ?? []) {
77
- lines.push(` ${activityIcon[activity.status]} ${activity.name} ${styleText('dim', `[${activity.status}]`)}`);
78
- }
79
- }
80
- if (instance.pendingEffects.length > 0) {
81
- lines.push('', sectionHeader('Pending effects'));
82
- for (const eff of instance.pendingEffects) {
83
- lines.push(` • ${eff.name} ${styleText('dim', `(key=${eff._key})`)}`);
84
- }
85
- }
86
- if (options.includeHistory) {
87
- lines.push('', sectionHeader('History'));
88
- for (const entry of instance.history) {
89
- lines.push(` ${styleText('dim', `[${formatTimestamp(entry.at)}]`)} ${displayTitle(entry._type)}`);
90
- }
71
+ return [
72
+ ...stageLines(instance),
73
+ ...pendingEffectLines(instance),
74
+ ...(options.includeHistory ? historyLines(instance) : []),
75
+ ];
76
+ }
77
+ function stageLines(instance) {
78
+ return [
79
+ sectionHeader('Stages'),
80
+ ...instance.stages.flatMap((stage) => [
81
+ ` • ${stage.name}${stageMarker(stage)}`,
82
+ ...(stage.activities ?? []).map((activity) => ` ${activityIcon[activity.status]} ${activity.name} ${styleText('dim', `[${activity.status}]`)}`),
83
+ ]),
84
+ ];
85
+ }
86
+ function stageMarker(stage) {
87
+ return stage.exitedAt
88
+ ? styleText('dim', ` (exited ${formatTimestamp(stage.exitedAt)})`)
89
+ : styleText('cyan', ' (current)');
90
+ }
91
+ function pendingEffectLines(instance) {
92
+ if (instance.pendingEffects.length === 0) {
93
+ return [];
91
94
  }
92
- return lines;
95
+ return [
96
+ '',
97
+ sectionHeader('Pending effects'),
98
+ ...instance.pendingEffects.map((eff) => ` • ${eff.name} ${styleText('dim', `(key=${eff._key})`)}`),
99
+ ];
100
+ }
101
+ function historyLines(instance) {
102
+ return [
103
+ '',
104
+ sectionHeader('History'),
105
+ ...instance.history.map((entry) => ` ${styleText('dim', `[${formatTimestamp(entry.at)}]`)} ${displayTitle(entry._type)}`),
106
+ ];
93
107
  }
@@ -1,7 +1,8 @@
1
1
  import { StartNotSettledError, type InitialFieldValue, type StartInstanceArgs, type WorkflowInstance } from '@sanity/workflow-engine';
2
- import { WorkflowCommand } from '../lib/base-command.ts';
3
- import { type EngineScope } from '../lib/operation-args.ts';
2
+ import { WorkflowCommand } from '../../lib/base-command.ts';
3
+ import { type EngineScope } from '../../lib/operation-args.ts';
4
4
  export default class Start extends WorkflowCommand {
5
+ static aliases: string[];
5
6
  static description: string;
6
7
  static examples: string[];
7
8
  static args: {
@@ -12,6 +13,7 @@ export default class Start extends WorkflowCommand {
12
13
  version: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  field: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
14
15
  'instance-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ deployment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
17
  tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
18
  };
17
19
  run(): Promise<void>;
@@ -1,15 +1,16 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { Args, Flags } from '@oclif/core';
3
3
  import { buildInitialFields, errorMessage, StartNotPrimedError, StartNotSettledError, startRefusal, workflow, } from '@sanity/workflow-engine';
4
- import { WorkflowCommand } from "../lib/base-command.js";
5
- import { resolveContext } from "../lib/context.js";
6
- import { fetchDeployedDefinition } from "../lib/definitions.js";
7
- import { fail, failOnThrow, failureDetail } from "../lib/fail.js";
8
- import { jsonFlags, tagFlags } from "../lib/flags.js";
9
- import { baseEngineArgs } from "../lib/operation-args.js";
10
- import { runWriteVerb } from "../lib/ops-report.js";
11
- import { parseParams } from "../lib/params.js";
4
+ import { WorkflowCommand } from "../../lib/base-command.js";
5
+ import { resolveContext } from "../../lib/context.js";
6
+ import { fetchDeployedDefinition } from "../../lib/definitions.js";
7
+ import { fail, failOnThrow, failureDetail } from "../../lib/fail.js";
8
+ import { deploymentFlags, jsonFlags } from "../../lib/flags.js";
9
+ import { baseEngineArgs } from "../../lib/operation-args.js";
10
+ import { runWriteVerb } from "../../lib/ops-report.js";
11
+ import { parseParams } from "../../lib/params.js";
12
12
  export default class Start extends WorkflowCommand {
13
+ static aliases = ['start'];
13
14
  static description = 'Start a workflow instance from a deployed definition. Supply values for the ' +
14
15
  "workflow's input-sourced fields with --field (e.g. the subject document ref).";
15
16
  static examples = [
@@ -22,7 +23,7 @@ export default class Start extends WorkflowCommand {
22
23
  name: Args.string({ required: true, description: 'Workflow definition name.' }),
23
24
  };
24
25
  static flags = {
25
- ...tagFlags,
26
+ ...deploymentFlags,
26
27
  version: Flags.integer({
27
28
  description: 'Definition version to start from (default: highest deployed).',
28
29
  }),
@@ -1,5 +1,6 @@
1
- import { WorkflowCommand } from '../lib/base-command.ts';
1
+ import { WorkflowCommand } from '../../lib/base-command.ts';
2
2
  export default class Tail extends WorkflowCommand {
3
+ static aliases: string[];
3
4
  static description: string;
4
5
  static examples: string[];
5
6
  static args: {