@sanity/workflow-cli 0.26.0 → 0.28.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 (48) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +14 -15
  3. package/bin/run.js +3 -1
  4. package/dist/command-ids.d.ts +2 -0
  5. package/dist/command-ids.js +2 -0
  6. package/dist/commands/{editorial-workflows → workflows}/abort.d.ts +0 -1
  7. package/dist/commands/{editorial-workflows → workflows}/abort.js +2 -3
  8. package/dist/commands/{editorial-workflows → workflows}/definition/delete.d.ts +0 -1
  9. package/dist/commands/{editorial-workflows → workflows}/definition/delete.js +3 -4
  10. package/dist/commands/{editorial-workflows → workflows}/definition/diff.d.ts +0 -1
  11. package/dist/commands/{editorial-workflows → workflows}/definition/diff.js +2 -3
  12. package/dist/commands/{editorial-workflows → workflows}/definition/list.d.ts +0 -1
  13. package/dist/commands/{editorial-workflows → workflows}/definition/list.js +3 -4
  14. package/dist/commands/{editorial-workflows → workflows}/definition/show.d.ts +0 -1
  15. package/dist/commands/{editorial-workflows → workflows}/definition/show.js +0 -1
  16. package/dist/commands/{editorial-workflows → workflows}/deploy.d.ts +4 -3
  17. package/dist/commands/{editorial-workflows → workflows}/deploy.js +15 -9
  18. package/dist/commands/{editorial-workflows → workflows}/diagnose.d.ts +0 -1
  19. package/dist/commands/{editorial-workflows → workflows}/diagnose.js +3 -4
  20. package/dist/commands/{editorial-workflows → workflows}/fire-action.d.ts +0 -1
  21. package/dist/commands/{editorial-workflows → workflows}/fire-action.js +3 -4
  22. package/dist/commands/{editorial-workflows → workflows}/list.d.ts +0 -1
  23. package/dist/commands/{editorial-workflows → workflows}/list.js +6 -7
  24. package/dist/commands/{editorial-workflows → workflows}/nuke.d.ts +0 -1
  25. package/dist/commands/{editorial-workflows → workflows}/nuke.js +3 -4
  26. package/dist/commands/{editorial-workflows → workflows}/reset-activity.d.ts +0 -1
  27. package/dist/commands/{editorial-workflows → workflows}/reset-activity.js +2 -3
  28. package/dist/commands/{editorial-workflows → workflows}/set-stage.d.ts +0 -1
  29. package/dist/commands/{editorial-workflows → workflows}/set-stage.js +3 -4
  30. package/dist/commands/{editorial-workflows → workflows}/show.d.ts +0 -1
  31. package/dist/commands/{editorial-workflows → workflows}/show.js +3 -4
  32. package/dist/commands/{editorial-workflows → workflows}/start.d.ts +0 -1
  33. package/dist/commands/{editorial-workflows → workflows}/start.js +4 -5
  34. package/dist/commands/{editorial-workflows → workflows}/tail.d.ts +0 -1
  35. package/dist/commands/{editorial-workflows → workflows}/tail.js +1 -2
  36. package/dist/help.d.ts +9 -4
  37. package/dist/help.js +36 -8
  38. package/dist/lib/base-command.d.ts +3 -3
  39. package/dist/lib/base-command.js +4 -0
  40. package/dist/lib/context.d.ts +5 -4
  41. package/dist/lib/context.js +2 -1
  42. package/dist/lib/select-deployment.js +2 -1
  43. package/dist/lib/share-definitions.js +2 -1
  44. package/dist/lib/telemetry.d.ts +1 -3
  45. package/dist/standalone-argv.d.ts +14 -0
  46. package/dist/standalone-argv.js +54 -0
  47. package/oclif.manifest.json +105 -135
  48. package/package.json +6 -6
package/dist/help.js CHANGED
@@ -1,7 +1,28 @@
1
1
  import { Help } from '@oclif/core';
2
- export const isBareSurface = (idOrName) => !idOrName.startsWith('editorial-workflows');
3
- export const keepCommandAtRoot = (id) => id !== '' && isBareSurface(id);
2
+ import { WORKFLOWS_TOPIC } from "./command-ids.js";
3
+ const TOPIC_PREFIX = `${WORKFLOWS_TOPIC}:`;
4
+ const CANONICAL_EXAMPLE_PREFIX = `<%= config.bin %> ${WORKFLOWS_TOPIC} `;
5
+ const STANDALONE_EXAMPLE_PREFIX = '<%= config.bin %> ';
6
+ const HELP_COMMAND_ID = 'help';
7
+ export const standaloneSurfaceId = (id) => {
8
+ if (!id.startsWith(TOPIC_PREFIX))
9
+ return undefined;
10
+ return id.slice(TOPIC_PREFIX.length);
11
+ };
12
+ export const keepCommandAtRoot = (id) => id === HELP_COMMAND_ID || standaloneSurfaceId(id) !== undefined;
13
+ export const standaloneExample = (example) => {
14
+ if (typeof example === 'string') {
15
+ return example.replace(CANONICAL_EXAMPLE_PREFIX, STANDALONE_EXAMPLE_PREFIX);
16
+ }
17
+ return {
18
+ ...example,
19
+ command: example.command.replace(CANONICAL_EXAMPLE_PREFIX, STANDALONE_EXAMPLE_PREFIX),
20
+ };
21
+ };
4
22
  export default class WorkflowHelp extends Help {
23
+ async showCommandHelp(command) {
24
+ await super.showCommandHelp(withStandaloneSurface(command));
25
+ }
5
26
  async showRootHelp() {
6
27
  if (this.opts.all) {
7
28
  await super.showRootHelp();
@@ -9,15 +30,22 @@ export default class WorkflowHelp extends Help {
9
30
  }
10
31
  this.log(this.formatRoot());
11
32
  this.log('');
12
- const topics = this.sortedTopics.filter((topic) => isBareSurface(topic.name));
13
- if (topics.length > 0) {
14
- this.log(this.formatTopics(topics));
15
- this.log('');
16
- }
17
- const commands = this.sortedCommands.filter((command) => keepCommandAtRoot(command.id));
33
+ const commands = this.sortedCommands
34
+ .filter((command) => keepCommandAtRoot(command.id))
35
+ .map((command) => withStandaloneSurface(command));
18
36
  if (commands.length > 0) {
19
37
  this.log(this.formatCommands(commands));
20
38
  this.log('');
21
39
  }
22
40
  }
23
41
  }
42
+ function withStandaloneSurface(command) {
43
+ const shortId = standaloneSurfaceId(command.id);
44
+ if (shortId === undefined)
45
+ return command;
46
+ return {
47
+ ...command,
48
+ id: shortId,
49
+ examples: command.examples?.map((example) => standaloneExample(example)),
50
+ };
51
+ }
@@ -1,9 +1,9 @@
1
1
  import { Command } from '@oclif/core';
2
2
  /**
3
3
  * Base for workflow commands: prompt interrupts exit with the conventional
4
- * SIGINT code and no stack, while an auth rejection escaping `run` renders
5
- * through the clean {@link fail} path with {@link failureDetail}'s recovery
6
- * hint. Every other error propagates to oclif unchanged.
4
+ * SIGINT code and no stack; an auth rejection and a reader-floor
5
+ * acknowledgement failure both expected, user-fixable render through the
6
+ * clean {@link fail} path. Every other error propagates to oclif unchanged.
7
7
  */
8
8
  export declare abstract class WorkflowCommand extends Command {
9
9
  protected catch(err: Error & {
@@ -1,6 +1,7 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { Command } from '@oclif/core';
3
3
  import { exitCodes } from '@sanity/cli-core';
4
+ import { ReaderModelAcknowledgementError } from '@sanity/workflow-engine';
4
5
  import { fail, failureDetail, isAuthRejection } from "./fail.js";
5
6
  export class WorkflowCommand extends Command {
6
7
  async catch(err) {
@@ -11,6 +12,9 @@ export class WorkflowCommand extends Command {
11
12
  if (isAuthRejection(err)) {
12
13
  fail('Authentication failed:', failureDetail(err));
13
14
  }
15
+ if (err instanceof ReaderModelAcknowledgementError) {
16
+ fail('Reader-floor acknowledgement:', err.message);
17
+ }
14
18
  return super.catch(err);
15
19
  }
16
20
  }
@@ -17,10 +17,11 @@ export interface InstanceContext {
17
17
  instance: WorkflowInstance;
18
18
  }
19
19
  /**
20
- * The resolution a WRITE shares: discover the config, pick the deployment for
21
- * `--deployment` or `--tag` (or the sole one), and build an authenticated
22
- * client for that deployment's resource. A write acts on one specific
23
- * deployment, so a single, definite target is exactly what it needs.
20
+ * The resolution a deployment-scoped command shares (`start`, `definition
21
+ * delete`, `definition diff`): discover the config, pick the deployment for
22
+ * `--deployment` or `--tag` (or the sole one), assert that deployment's
23
+ * reader-floor acknowledgement, and build an authenticated client for its
24
+ * resource. Instance-id commands resolve elsewhere and do not gate here.
24
25
  */
25
26
  export declare function resolveContext(flags: {
26
27
  deployment?: string | undefined;
@@ -1,4 +1,4 @@
1
- import { assertReadableModel, resourceGdr, } from '@sanity/workflow-engine';
1
+ import { assertReadableModel, assertReaderModelAcknowledgement, resourceGdr, } from '@sanity/workflow-engine';
2
2
  import { clientFor, resolveTokenOrFail } from "./client.js";
3
3
  import { fail } from "./fail.js";
4
4
  import { loadWorkflowConfig } from "./load-config.js";
@@ -7,6 +7,7 @@ import { resourceLabel } from "./ui.js";
7
7
  export async function resolveContext(flags) {
8
8
  const config = await loadWorkflowConfig();
9
9
  const deployment = await selectDeployment(config, { name: flags.deployment, tag: flags.tag });
10
+ assertReaderModelAcknowledgement(deployment.expectedMinReaderModel, `Deployment ${deployment.name}`);
10
11
  return { deployment, client: clientFor(deployment.workflowResource, await resolveTokenOrFail()) };
11
12
  }
12
13
  function targetsFor(resources, token) {
@@ -1,4 +1,4 @@
1
- import { resourceAliasesToMap, } from '@sanity/workflow-engine';
1
+ import { assertReaderModelAcknowledgement, resourceAliasesToMap, } from '@sanity/workflow-engine';
2
2
  import { fail } from "./fail.js";
3
3
  import { canPromptOnStderr, selectOnStderr } from "./prompt.js";
4
4
  export function deploymentLabel({ name, tag }) {
@@ -70,6 +70,7 @@ function availableDeployments(config, deployments = config.deployments) {
70
70
  return `Available deployments: ${deployments.map(deploymentLabel).join(', ')}`;
71
71
  }
72
72
  export function deploymentToTarget(deployment) {
73
+ assertReaderModelAcknowledgement(deployment.expectedMinReaderModel, `Deployment ${deployment.name}`);
73
74
  return {
74
75
  expectedMinReaderModel: deployment.expectedMinReaderModel,
75
76
  tag: deployment.tag,
@@ -1,6 +1,7 @@
1
1
  import { styleText } from 'node:util';
2
2
  import { getUserConfig } from '@sanity/cli-core';
3
3
  import { assertReadableModel, definitionDeployedData, errorMessage, } from '@sanity/workflow-engine';
4
+ import { WORKFLOWS_DEPLOY_COMMAND_ID } from "../command-ids.js";
4
5
  import { buildDefinitionShowQuery } from "./definitions.js";
5
6
  import { canPromptOnStderr } from "./prompt.js";
6
7
  import { cliTelemetry, WorkflowDefinitionShared, WorkflowDefinitionSharingDecided, } from "./telemetry.js";
@@ -28,7 +29,7 @@ export function definitionShareMarker(args) {
28
29
  }
29
30
  export function shouldForceShareTelemetry(args) {
30
31
  const { commandId, argv } = args;
31
- if (commandId !== 'editorial-workflows:deploy') {
32
+ if (commandId !== WORKFLOWS_DEPLOY_COMMAND_ID) {
32
33
  return false;
33
34
  }
34
35
  const terminator = argv.indexOf('--');
@@ -117,9 +117,7 @@ export declare function raceWithDeadline<T>(work: Promise<T>, deadlineMs: number
117
117
  export declare function finishCliTelemetry(data: WorkflowCliCommandData): Promise<void>;
118
118
  /**
119
119
  * The command id a trace reports: the resolved class's canonical id when
120
- * oclif supplies it, else the id as typed. An alias invocation must report
121
- * under the same name as the canonical form — one command, one telemetry
122
- * identity.
120
+ * oclif supplies it, else the unresolved id from the hook.
123
121
  */
124
122
  export declare function traceCommandId(options: {
125
123
  id: string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * First argv tokens that belong under {@link WORKFLOWS_TOPIC}.
3
+ * Keep in sync with `src/commands/workflows/` (top-level command
4
+ * files plus the `definition` subtopic directory).
5
+ */
6
+ export declare const STANDALONE_ROOT_COMMANDS: readonly ["abort", "definition", "deploy", "diagnose", "fire-action", "list", "nuke", "reset-activity", "set-stage", "show", "start", "tail"];
7
+ /** Index of the first argv token that is not a flag (and not `--`). */
8
+ export declare function firstPositionalIndex(args: string[]): number;
9
+ /**
10
+ * Rewrite standalone CLI args so short forms resolve to topic-scoped command
11
+ * ids. Idempotent when the topic is already present. Unknown first tokens are
12
+ * left alone so oclif's own "command not found" path still runs.
13
+ */
14
+ export declare function rewriteStandaloneArgv(args: string[]): string[];
@@ -0,0 +1,54 @@
1
+ import { WORKFLOWS_TOPIC } from "./command-ids.js";
2
+ export const STANDALONE_ROOT_COMMANDS = [
3
+ 'abort',
4
+ 'definition',
5
+ 'deploy',
6
+ 'diagnose',
7
+ 'fire-action',
8
+ 'list',
9
+ 'nuke',
10
+ 'reset-activity',
11
+ 'set-stage',
12
+ 'show',
13
+ 'start',
14
+ 'tail',
15
+ ];
16
+ const rootCommandSet = new Set(STANDALONE_ROOT_COMMANDS);
17
+ export function firstPositionalIndex(args) {
18
+ for (let i = 0; i < args.length; i++) {
19
+ const token = args[i];
20
+ if (token === undefined)
21
+ continue;
22
+ if (token === '--')
23
+ return i + 1 < args.length ? i + 1 : -1;
24
+ if (!token.startsWith('-'))
25
+ return i;
26
+ }
27
+ return -1;
28
+ }
29
+ function stripScriptArgSeparator(args) {
30
+ return args[0] === '--' ? args.slice(1) : args;
31
+ }
32
+ export function rewriteStandaloneArgv(args) {
33
+ const normalized = stripScriptArgSeparator(args);
34
+ const i = firstPositionalIndex(normalized);
35
+ if (i === -1)
36
+ return normalized;
37
+ const first = normalized[i];
38
+ if (first === undefined || first === WORKFLOWS_TOPIC)
39
+ return normalized;
40
+ if (first === 'help') {
41
+ const commandIndex = firstPositionalIndex(normalized.slice(i + 1));
42
+ if (commandIndex === -1)
43
+ return normalized;
44
+ const absolute = i + 1 + commandIndex;
45
+ const command = normalized[absolute];
46
+ if (command === undefined || command === WORKFLOWS_TOPIC || !rootCommandSet.has(command)) {
47
+ return normalized;
48
+ }
49
+ return [...normalized.slice(0, absolute), WORKFLOWS_TOPIC, ...normalized.slice(absolute)];
50
+ }
51
+ if (!rootCommandSet.has(first))
52
+ return normalized;
53
+ return [...normalized.slice(0, i), WORKFLOWS_TOPIC, ...normalized.slice(i)];
54
+ }