@sanity/workflow-cli 0.7.0 → 0.8.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.
- package/README.md +20 -20
- package/dist/commands/definition/diff.js +1 -1
- package/dist/commands/definition/list.d.ts +2 -2
- package/dist/commands/definition/list.js +3 -3
- package/dist/commands/definition/show.d.ts +5 -3
- package/dist/commands/definition/show.js +10 -10
- package/dist/commands/deploy.js +0 -1
- package/dist/commands/diagnose.d.ts +1 -1
- package/dist/commands/diagnose.js +28 -25
- package/dist/commands/fire-action.d.ts +4 -4
- package/dist/commands/fire-action.js +24 -24
- package/dist/commands/list.d.ts +2 -2
- package/dist/commands/list.js +8 -8
- package/dist/commands/{retry-task.d.ts → retry-activity.d.ts} +2 -2
- package/dist/commands/{retry-task.js → retry-activity.js} +3 -3
- package/dist/commands/set-stage.js +1 -1
- package/dist/commands/show.d.ts +1 -1
- package/dist/commands/show.js +5 -5
- package/dist/lib/definitions.js +1 -1
- package/dist/lib/diff.d.ts +2 -1
- package/dist/lib/diff.js +2 -2
- package/dist/lib/ui.d.ts +3 -3
- package/dist/lib/ui.js +2 -2
- package/oclif.manifest.json +22 -22
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Command-line tool for deploying, inspecting, and administering Sanity workflow
|
|
|
4
4
|
definitions and instances.
|
|
5
5
|
|
|
6
6
|
> [!WARNING]
|
|
7
|
-
> Early access, restricted. `retry-
|
|
7
|
+
> Early access, restricted. `retry-activity` and `set-stage` are still stubs —
|
|
8
8
|
> they print their parsed input and exit non-zero. The "wired" commands below
|
|
9
9
|
> talk to a real Sanity dataset using `SANITY_*` env vars.
|
|
10
10
|
|
|
@@ -75,25 +75,25 @@ built or standalone CLI instead resolves the package's compiled `dist`.
|
|
|
75
75
|
|
|
76
76
|
## Command status
|
|
77
77
|
|
|
78
|
-
| Command
|
|
79
|
-
|
|
|
80
|
-
| `deploy`
|
|
81
|
-
| `deploy --check`
|
|
82
|
-
| `deploy --dry-run`
|
|
83
|
-
| `deploy --only <id>`
|
|
84
|
-
| `list`
|
|
85
|
-
| `show <instance-id>`
|
|
86
|
-
| `diagnose <instance-id>`
|
|
87
|
-
| `tail <instance-id>`
|
|
88
|
-
| `abort <instance-id>`
|
|
89
|
-
| `retry-
|
|
90
|
-
| `move-stage <instance-id> --to <stage-id>`
|
|
91
|
-
| `fire-action <instance-id>`
|
|
92
|
-
| `set-stage <instance-id> --to <stage-id>`
|
|
93
|
-
| `definition list`
|
|
94
|
-
| `definition show <id>`
|
|
95
|
-
| `definition diff <id>`
|
|
96
|
-
| `definition delete <name>`
|
|
78
|
+
| Command | Status |
|
|
79
|
+
| -------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
80
|
+
| `deploy` | wired — calls `workflow.deployDefinitions` over the `WORKFLOW_DEFS` module |
|
|
81
|
+
| `deploy --check` | wired — runs `validateDefinition` over the local batch + a duplicate-id check |
|
|
82
|
+
| `deploy --dry-run` | wired — fetches existing docs and renders a coloured JSON diff per change |
|
|
83
|
+
| `deploy --only <id>` | wired — filters deploy/check/dry-run to one `definition` |
|
|
84
|
+
| `list` | wired — `client.fetch` over `workflow.instance` documents |
|
|
85
|
+
| `show <instance-id>` | wired — `client.getDocument` |
|
|
86
|
+
| `diagnose <instance-id>` | wired — one `workflow.evaluate` call, classifies why the instance is/isn't progressing |
|
|
87
|
+
| `tail <instance-id>` | wired — `client.listen()` over the instance, prints new history entries |
|
|
88
|
+
| `abort <instance-id>` | wired — calls `workflow.abortInstance` (hard stop: cancels pending effects, lifts guards) |
|
|
89
|
+
| `retry-activity <instance-id> <activity-id>` | stub |
|
|
90
|
+
| `move-stage <instance-id> --to <stage-id>` | wired — calls `workflow.setStage` (runs guards + onEnter effects) |
|
|
91
|
+
| `fire-action <instance-id>` | wired — `workflow.evaluate` lists actions; `workflow.fireAction` fires one |
|
|
92
|
+
| `set-stage <instance-id> --to <stage-id>` | stub (engine has no guard-bypass path yet) |
|
|
93
|
+
| `definition list` | wired — `client.fetch` over `workflow.definition` documents |
|
|
94
|
+
| `definition show <id>` | wired — `client.fetch`, latest version unless `--version` |
|
|
95
|
+
| `definition diff <id>` | wired — diffs the in-code definition against the deployed latest (`--version` to pin) |
|
|
96
|
+
| `definition delete <name>` | wired — calls `workflow.deleteDefinition` (refuses on live instances unless `--cascade`) |
|
|
97
97
|
|
|
98
98
|
## Known gaps
|
|
99
99
|
|
|
@@ -30,7 +30,7 @@ export default class DefinitionDiff extends Command {
|
|
|
30
30
|
let deployed;
|
|
31
31
|
try {
|
|
32
32
|
deployed = await fetchDeployedDefinition(client, args.definition, config, flags.version);
|
|
33
|
-
spinner.succeed(`Diffed ${args.definition}
|
|
33
|
+
spinner.succeed(`Diffed ${args.definition}`);
|
|
34
34
|
}
|
|
35
35
|
catch (error) {
|
|
36
36
|
spinner.fail('Diff failed');
|
|
@@ -2,7 +2,7 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
import { type WorkflowRole } from '@sanity/workflow-engine';
|
|
3
3
|
interface DefinitionListFlags {
|
|
4
4
|
tag?: string | undefined;
|
|
5
|
-
'workflow-
|
|
5
|
+
'workflow-name'?: string | undefined;
|
|
6
6
|
limit: number;
|
|
7
7
|
}
|
|
8
8
|
export interface DefinitionListRow {
|
|
@@ -24,7 +24,7 @@ export default class DefinitionList extends Command {
|
|
|
24
24
|
static examples: string[];
|
|
25
25
|
static flags: {
|
|
26
26
|
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
|
-
'workflow-
|
|
27
|
+
'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
28
|
tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
29
29
|
};
|
|
30
30
|
run(): Promise<void>;
|
|
@@ -21,8 +21,8 @@ export function buildDefinitionListQuery(flags) {
|
|
|
21
21
|
params.tag = flags.tag;
|
|
22
22
|
filters.push(tagScopeFilter());
|
|
23
23
|
}
|
|
24
|
-
if (flags['workflow-
|
|
25
|
-
params.name = flags['workflow-
|
|
24
|
+
if (flags['workflow-name']) {
|
|
25
|
+
params.name = flags['workflow-name'];
|
|
26
26
|
filters.push('name == $name');
|
|
27
27
|
}
|
|
28
28
|
const instanceMatch = instanceFilters.join(' && ');
|
|
@@ -50,7 +50,7 @@ export default class DefinitionList extends Command {
|
|
|
50
50
|
description: 'The maximum number of definitions to return.',
|
|
51
51
|
default: 100,
|
|
52
52
|
}),
|
|
53
|
-
'workflow-
|
|
53
|
+
'workflow-name': Flags.string({
|
|
54
54
|
description: 'Filter to a single workflow definition name (e.g. product-launch)',
|
|
55
55
|
}),
|
|
56
56
|
};
|
|
@@ -24,10 +24,12 @@ export default class DefinitionShow extends Command {
|
|
|
24
24
|
* title, then the human title, description, and deploy `tag` as aligned
|
|
25
25
|
* detail rows. `tag` is deployment metadata (the partition), not part of the
|
|
26
26
|
* authored definition, so it's passed separately and omitted when unknown. */
|
|
27
|
-
export declare function definitionHeader(def: WorkflowDefinition
|
|
27
|
+
export declare function definitionHeader(def: WorkflowDefinition & {
|
|
28
|
+
version: number;
|
|
29
|
+
}, tag?: string): string;
|
|
28
30
|
/**
|
|
29
|
-
* The body lines for `definition show`: every stage with its
|
|
30
|
-
*
|
|
31
|
+
* The body lines for `definition show`: every stage with its activities and each
|
|
32
|
+
* activity's actions. Pure so it can be asserted without driving the oclif command.
|
|
31
33
|
*/
|
|
32
34
|
export declare function describeDefinition(def: WorkflowDefinition): string[];
|
|
33
35
|
export {};
|
|
@@ -36,8 +36,8 @@ export default class DefinitionShow extends Command {
|
|
|
36
36
|
version: flags.version,
|
|
37
37
|
});
|
|
38
38
|
const client = loadClient();
|
|
39
|
-
//
|
|
40
|
-
//
|
|
39
|
+
// A deployed document: the authored {@link WorkflowDefinition} plus the
|
|
40
|
+
// deploy-stamped envelope (`version`, `contentHash`, `tag`).
|
|
41
41
|
const def = await client.fetch(groq, params);
|
|
42
42
|
if (!def) {
|
|
43
43
|
const at = flags.version ? `v${flags.version}` : 'latest';
|
|
@@ -71,24 +71,24 @@ function actionLine(action) {
|
|
|
71
71
|
const status = statusOp ? styleText('dim', ` → ${statusOp.status}`) : '';
|
|
72
72
|
return ` · ${action.name}${status}`;
|
|
73
73
|
}
|
|
74
|
-
/** A `-
|
|
75
|
-
function
|
|
76
|
-
const title =
|
|
77
|
-
return [` - ${
|
|
74
|
+
/** A `- activity` line followed by one line per action it exposes. */
|
|
75
|
+
function activityBlock(activity) {
|
|
76
|
+
const title = activity.title ? styleText('dim', ` — ${activity.title}`) : '';
|
|
77
|
+
return [` - ${activity.name}${title}`, ...(activity.actions ?? []).map(actionLine)];
|
|
78
78
|
}
|
|
79
|
-
/** A `• stage` line (with initial/terminal markers) followed by its
|
|
79
|
+
/** A `• stage` line (with initial/terminal markers) followed by its activity blocks. */
|
|
80
80
|
function stageBlock(stage, initialStage) {
|
|
81
81
|
const title = stage.title ? styleText('dim', ` — ${stage.title}`) : '';
|
|
82
82
|
const terminal = isTerminalStage(stage) ? styleText('dim', ' (terminal)') : '';
|
|
83
83
|
const initial = stage.name === initialStage ? styleText('cyan', ' [initial]') : '';
|
|
84
84
|
return [
|
|
85
85
|
` • ${stage.name}${title}${terminal}${initial}`,
|
|
86
|
-
...(stage.
|
|
86
|
+
...(stage.activities ?? []).flatMap(activityBlock),
|
|
87
87
|
];
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
-
* The body lines for `definition show`: every stage with its
|
|
91
|
-
*
|
|
90
|
+
* The body lines for `definition show`: every stage with its activities and each
|
|
91
|
+
* activity's actions. Pure so it can be asserted without driving the oclif command.
|
|
92
92
|
*/
|
|
93
93
|
export function describeDefinition(def) {
|
|
94
94
|
return [
|
package/dist/commands/deploy.js
CHANGED
|
@@ -88,7 +88,6 @@ export function validateModeFlags(check, dryRun) {
|
|
|
88
88
|
export function deployResultLines(results) {
|
|
89
89
|
const symbols = {
|
|
90
90
|
created: logSymbols.success,
|
|
91
|
-
updated: logSymbols.info,
|
|
92
91
|
};
|
|
93
92
|
return results.map((r) => {
|
|
94
93
|
const symbol = symbols[r.status] ?? logSymbols.warning;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
import { type Diagnosis, type DiagnoseInput, type SuggestedRemediation } from '@sanity/workflow-engine';
|
|
3
3
|
/**
|
|
4
|
-
* The diagnosis body: the verdict line, the current stage's
|
|
4
|
+
* The diagnosis body: the verdict line, the current stage's activities +
|
|
5
5
|
* transitions as evidence (for any in-flight state), and the cause block with
|
|
6
6
|
* the engine's suggested fix when stuck. Pure so every verdict permutation is
|
|
7
7
|
* assertable without driving a live evaluation. Takes the engine's
|
|
@@ -6,25 +6,28 @@ import { loadClient } from "../lib/client.js";
|
|
|
6
6
|
import { loadWorkflowConfig } from "../lib/config.js";
|
|
7
7
|
import { fail } from "../lib/fail.js";
|
|
8
8
|
import { tagFlags } from "../lib/flags.js";
|
|
9
|
-
import { formatTimestamp, sectionHeader,
|
|
9
|
+
import { formatTimestamp, sectionHeader, activityIcon } from "../lib/ui.js";
|
|
10
10
|
import { instanceHeader } from "./show.js";
|
|
11
11
|
function formatAssignee(a) {
|
|
12
12
|
return a.type === 'user' ? `user:${a.id}` : `role:${a.role}`;
|
|
13
13
|
}
|
|
14
|
-
function
|
|
14
|
+
function activityLine(t, assignees) {
|
|
15
15
|
const who = assignees.length > 0
|
|
16
16
|
? styleText('dim', ` assigned → ${assignees.map(formatAssignee).join(', ')}`)
|
|
17
17
|
: '';
|
|
18
|
-
return ` ${
|
|
18
|
+
return ` ${activityIcon[t.status]} ${t.activity.name} ${styleText('dim', `[${t.status}]`)}${who}`;
|
|
19
19
|
}
|
|
20
20
|
function transitionLine(tr) {
|
|
21
21
|
const mark = tr.filterSatisfied ? styleText('green', 'ready') : styleText('red', 'false');
|
|
22
22
|
return ` → ${tr.transition.to} ${styleText('dim', tr.transition.filter ?? 'true')} ${mark}`;
|
|
23
23
|
}
|
|
24
24
|
function currentStageLines(input) {
|
|
25
|
-
const lines = [
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const lines = [
|
|
26
|
+
`${sectionHeader('Stage')} ${input.instance.currentStage}`,
|
|
27
|
+
sectionHeader('Activities'),
|
|
28
|
+
];
|
|
29
|
+
for (const t of input.activities) {
|
|
30
|
+
lines.push(activityLine(t, input.assignees[t.activity.name] ?? []));
|
|
28
31
|
}
|
|
29
32
|
if (input.transitions.length > 0) {
|
|
30
33
|
lines.push('', sectionHeader('Exit transitions'));
|
|
@@ -37,14 +40,14 @@ function currentStageLines(input) {
|
|
|
37
40
|
function failedEffectDetail(effect) {
|
|
38
41
|
const ran = effect.durationMs !== undefined ? ` (after ${effect.durationMs}ms)` : '';
|
|
39
42
|
return {
|
|
40
|
-
headline: `a failed effect is blocking
|
|
43
|
+
headline: `a failed effect is blocking activity '${effect.origin.name}'`,
|
|
41
44
|
why: [
|
|
42
45
|
styleText('red', `${logSymbols.error} failed effect: ${effect.name}`),
|
|
43
|
-
` queued by
|
|
46
|
+
` queued by activity '${effect.origin.name}', failed ${formatTimestamp(effect.ranAt)}${ran}`,
|
|
44
47
|
...(effect.error !== undefined ? [` error: ${effect.error.message}`] : []),
|
|
45
48
|
'',
|
|
46
|
-
`
|
|
47
|
-
`external system, so the
|
|
49
|
+
`Activity '${effect.origin.name}' is waiting on this effect. It failed against an`,
|
|
50
|
+
`external system, so the activity never completes and the stage can't advance.`,
|
|
48
51
|
],
|
|
49
52
|
};
|
|
50
53
|
}
|
|
@@ -58,12 +61,12 @@ function hungEffectDetail(effect) {
|
|
|
58
61
|
],
|
|
59
62
|
};
|
|
60
63
|
}
|
|
61
|
-
function
|
|
64
|
+
function failedActivityDetail(activity) {
|
|
62
65
|
return {
|
|
63
|
-
headline: `
|
|
66
|
+
headline: `activity '${activity}' failed`,
|
|
64
67
|
why: [
|
|
65
|
-
styleText('red', `${logSymbols.error}
|
|
66
|
-
`Any exit transition gated on '${
|
|
68
|
+
styleText('red', `${logSymbols.error} activity '${activity}' is in a terminal failed state.`),
|
|
69
|
+
`Any exit transition gated on '${activity}' being done can never fire.`,
|
|
67
70
|
],
|
|
68
71
|
};
|
|
69
72
|
}
|
|
@@ -76,31 +79,31 @@ function waitingLines(w) {
|
|
|
76
79
|
? `assigned to ${w.assignees.map(formatAssignee).join(', ')}`
|
|
77
80
|
: 'unassigned — anyone with permission can act';
|
|
78
81
|
return [
|
|
79
|
-
`${logSymbols.info}
|
|
82
|
+
`${logSymbols.info} activity '${w.activity}' is active (${who}),`,
|
|
80
83
|
`waiting for action: ${w.actions.join(' or ')}. This is the normal in-flight`,
|
|
81
84
|
`state — it advances when someone acts.`,
|
|
82
85
|
];
|
|
83
86
|
}
|
|
84
87
|
function blockedHeadline(b) {
|
|
85
88
|
const who = b.assignees.length > 0 ? ` for ${b.assignees.map(formatAssignee).join(', ')}` : '';
|
|
86
|
-
return `
|
|
89
|
+
return `activity '${b.activity}'${who} is not yet ready — unmet requirement(s): ${b.requirements.join(', ')}`;
|
|
87
90
|
}
|
|
88
91
|
function blockedLines(b) {
|
|
89
92
|
const who = b.assignees.length > 0
|
|
90
93
|
? `assigned to ${b.assignees.map(formatAssignee).join(', ')}`
|
|
91
94
|
: 'unassigned';
|
|
92
95
|
return [
|
|
93
|
-
`${logSymbols.info}
|
|
96
|
+
`${logSymbols.info} activity '${b.activity}' is visible but not yet executable (${who}).`,
|
|
94
97
|
`Unmet requirement(s): ${b.requirements.join(', ')}. It can't be acted on until`,
|
|
95
98
|
`those preconditions are met — check what would satisfy them (a prerequisite`,
|
|
96
|
-
`
|
|
99
|
+
`activity completing, required content landing). It will not advance on its own.`,
|
|
97
100
|
];
|
|
98
101
|
}
|
|
99
102
|
function noTransitionDetail() {
|
|
100
103
|
return {
|
|
101
104
|
headline: `no exit transition's filter is satisfied`,
|
|
102
105
|
why: [
|
|
103
|
-
`${logSymbols.info} every
|
|
106
|
+
`${logSymbols.info} every activity is resolved, but no exit transition's filter is true.`,
|
|
104
107
|
`Likely a routing state value a filter reads never got written.`,
|
|
105
108
|
],
|
|
106
109
|
};
|
|
@@ -114,7 +117,7 @@ function transitionUnevaluableDetail(transitions) {
|
|
|
114
117
|
return {
|
|
115
118
|
headline: `an exit transition's filter could not be evaluated`,
|
|
116
119
|
why: [
|
|
117
|
-
`${logSymbols.info} every
|
|
120
|
+
`${logSymbols.info} every activity is resolved, but ${transitions.join(', ')} reads an operand`,
|
|
118
121
|
`that is missing or unreadable (GROQ null), so routing is held rather than`,
|
|
119
122
|
`falling through. Make the data the filter reads readable — publish the`,
|
|
120
123
|
`subject (or fill the field) — and the instance advances on its own; no`,
|
|
@@ -125,7 +128,7 @@ function transitionUnevaluableDetail(transitions) {
|
|
|
125
128
|
const REMEDIATION_LABEL = {
|
|
126
129
|
'retry-effect': 'retry-effect',
|
|
127
130
|
'drain-effects': 're-run the effect drainer',
|
|
128
|
-
'reset-
|
|
131
|
+
'reset-activity': 'reset-activity',
|
|
129
132
|
'set-stage': 'move-stage',
|
|
130
133
|
abort: 'abort',
|
|
131
134
|
};
|
|
@@ -142,8 +145,8 @@ function causeDetail(cause) {
|
|
|
142
145
|
return failedEffectDetail(cause.effect);
|
|
143
146
|
case 'hung-effect':
|
|
144
147
|
return hungEffectDetail(cause.effect);
|
|
145
|
-
case 'failed-
|
|
146
|
-
return
|
|
148
|
+
case 'failed-activity':
|
|
149
|
+
return failedActivityDetail(cause.activity);
|
|
147
150
|
case 'no-transition-fires':
|
|
148
151
|
return noTransitionDetail();
|
|
149
152
|
case 'transition-unevaluable':
|
|
@@ -169,7 +172,7 @@ function statusLine(diagnosis) {
|
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
/**
|
|
172
|
-
* The diagnosis body: the verdict line, the current stage's
|
|
175
|
+
* The diagnosis body: the verdict line, the current stage's activities +
|
|
173
176
|
* transitions as evidence (for any in-flight state), and the cause block with
|
|
174
177
|
* the engine's suggested fix when stuck. Pure so every verdict permutation is
|
|
175
178
|
* assertable without driving a live evaluation. Takes the engine's
|
|
@@ -232,7 +235,7 @@ export default class Diagnose extends Command {
|
|
|
232
235
|
workflowResource: config.workflowResource,
|
|
233
236
|
instanceId: args.instanceId,
|
|
234
237
|
// Token-auth CLI can't hit /users/me; pin the same system actor the
|
|
235
|
-
// write verbs use. Transition filters and
|
|
238
|
+
// write verbs use. Transition filters and activity status are actor-
|
|
236
239
|
// independent. A requirement that reads $actor/$assigned/$can is the
|
|
237
240
|
// exception — it's evaluated against this system actor, so a `blocked`
|
|
238
241
|
// verdict on such a requirement reflects the engine's view, not a
|
|
@@ -9,7 +9,7 @@ import { type RanOp } from '../lib/ops-report.ts';
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function parseParams(pairs: string[]): Record<string, unknown>;
|
|
11
11
|
/**
|
|
12
|
-
* The list-mode body: every action on the current stage's
|
|
12
|
+
* The list-mode body: every action on the current stage's activities, marked
|
|
13
13
|
* fireable or not (with the disabling reason), plus a hint showing the
|
|
14
14
|
* flags to fire one. Pure so the populated/empty permutations assert
|
|
15
15
|
* without a live evaluation.
|
|
@@ -27,7 +27,7 @@ interface FireOutcome {
|
|
|
27
27
|
* {@link fireActionReport}. Pure so its shape is asserted directly. */
|
|
28
28
|
export declare function fireResultJson(result: FireOutcome, ids: {
|
|
29
29
|
instanceId: string;
|
|
30
|
-
|
|
30
|
+
activity: string;
|
|
31
31
|
action: string;
|
|
32
32
|
}): Record<string, unknown>;
|
|
33
33
|
export interface FireActionReport {
|
|
@@ -40,7 +40,7 @@ export interface FireActionReport {
|
|
|
40
40
|
* the fired / no-op / cascaded / ops permutations assert without a live
|
|
41
41
|
* fire.
|
|
42
42
|
*/
|
|
43
|
-
export declare function fireActionReport(result: FireOutcome,
|
|
43
|
+
export declare function fireActionReport(result: FireOutcome, activity: string, action: string): FireActionReport;
|
|
44
44
|
export default class FireAction extends Command {
|
|
45
45
|
static description: string;
|
|
46
46
|
static examples: string[];
|
|
@@ -48,7 +48,7 @@ export default class FireAction extends Command {
|
|
|
48
48
|
instanceId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
49
49
|
};
|
|
50
50
|
static flags: {
|
|
51
|
-
|
|
51
|
+
activity: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
52
52
|
action: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
53
53
|
param: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
|
|
54
54
|
as: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -44,8 +44,8 @@ function reasonText(reason) {
|
|
|
44
44
|
switch (reason.kind) {
|
|
45
45
|
case 'filter-failed':
|
|
46
46
|
return `action filter not satisfied${reason.detail ? ` (${reason.detail})` : ''}`;
|
|
47
|
-
case '
|
|
48
|
-
return `
|
|
47
|
+
case 'activity-not-active':
|
|
48
|
+
return `activity is ${reason.status}`;
|
|
49
49
|
case 'stage-terminal':
|
|
50
50
|
return `stage '${reason.stage}' is terminal`;
|
|
51
51
|
case 'mutation-guard-denied':
|
|
@@ -63,7 +63,7 @@ function actionLines(a) {
|
|
|
63
63
|
const mark = a.allowed ? logSymbols.success : logSymbols.error;
|
|
64
64
|
const title = a.title !== undefined ? styleText('dim', ` (${a.title})`) : '';
|
|
65
65
|
const lines = [
|
|
66
|
-
` ${mark} ${a.
|
|
66
|
+
` ${mark} ${a.activity} → ${a.action}${title} ${styleText('dim', `[activity ${a.activityStatus}]`)}`,
|
|
67
67
|
];
|
|
68
68
|
if (a.params.length > 0) {
|
|
69
69
|
lines.push(styleText('dim', ` params: ${a.params.map(paramLabel).join(', ')}`));
|
|
@@ -74,20 +74,20 @@ function actionLines(a) {
|
|
|
74
74
|
return lines;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
|
-
* The list-mode body: every action on the current stage's
|
|
77
|
+
* The list-mode body: every action on the current stage's activities, marked
|
|
78
78
|
* fireable or not (with the disabling reason), plus a hint showing the
|
|
79
79
|
* flags to fire one. Pure so the populated/empty permutations assert
|
|
80
80
|
* without a live evaluation.
|
|
81
81
|
*/
|
|
82
82
|
export function renderAvailableActions(actions, stage, instanceId) {
|
|
83
83
|
if (actions.length === 0) {
|
|
84
|
-
return [`No actions on the
|
|
84
|
+
return [`No actions on the activities of the current stage ('${stage}').`];
|
|
85
85
|
}
|
|
86
86
|
const lines = [styleText('bold', `Actions on stage '${stage}':`), ''];
|
|
87
87
|
for (const a of actions) {
|
|
88
88
|
lines.push(...actionLines(a));
|
|
89
89
|
}
|
|
90
|
-
lines.push('', styleText('dim', 'Fire one with:'), styleText('dim', ` fire-action ${instanceId} --
|
|
90
|
+
lines.push('', styleText('dim', 'Fire one with:'), styleText('dim', ` fire-action ${instanceId} --activity <activity> --action <action>`));
|
|
91
91
|
return lines;
|
|
92
92
|
}
|
|
93
93
|
/** The `--json` payload for a fired action — the structured counterpart of
|
|
@@ -95,7 +95,7 @@ export function renderAvailableActions(actions, stage, instanceId) {
|
|
|
95
95
|
export function fireResultJson(result, ids) {
|
|
96
96
|
return {
|
|
97
97
|
instanceId: ids.instanceId,
|
|
98
|
-
|
|
98
|
+
activity: ids.activity,
|
|
99
99
|
action: ids.action,
|
|
100
100
|
fired: result.fired,
|
|
101
101
|
cascaded: result.cascaded,
|
|
@@ -108,37 +108,37 @@ export function fireResultJson(result, ids) {
|
|
|
108
108
|
* the fired / no-op / cascaded / ops permutations assert without a live
|
|
109
109
|
* fire.
|
|
110
110
|
*/
|
|
111
|
-
export function fireActionReport(result,
|
|
111
|
+
export function fireActionReport(result, activity, action) {
|
|
112
112
|
const stage = styleText('bold', result.instance.currentStage);
|
|
113
113
|
if (!result.fired) {
|
|
114
114
|
return {
|
|
115
115
|
fired: false,
|
|
116
|
-
message: `fireAction returned without firing —
|
|
116
|
+
message: `fireAction returned without firing — activity '${activity}' is no longer active`,
|
|
117
117
|
opsLines: [],
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
120
|
const tail = result.cascaded > 0 ? `, then cascaded ${result.cascaded} auto-transition(s)` : '';
|
|
121
121
|
return {
|
|
122
122
|
fired: true,
|
|
123
|
-
message: `Fired ${styleText('bold', action)} on ${styleText('bold',
|
|
123
|
+
message: `Fired ${styleText('bold', action)} on ${styleText('bold', activity)} — now at ${stage}${tail}`,
|
|
124
124
|
opsLines: opsAppliedLines(result.ranOps),
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
127
|
export default class FireAction extends Command {
|
|
128
|
-
static description = "Fire an action on an instance — act on a user's behalf to unstick a waiting
|
|
128
|
+
static description = "Fire an action on an instance — act on a user's behalf to unstick a waiting activity. Omit --action to list what can be fired.";
|
|
129
129
|
static examples = [
|
|
130
130
|
'<%= config.bin %> fire-action wf-instance.abc123',
|
|
131
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
132
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
133
|
-
'<%= config.bin %> fire-action wf-instance.abc123 --
|
|
131
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve',
|
|
132
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve --as user.xyz --as-role editor',
|
|
133
|
+
'<%= config.bin %> fire-action wf-instance.abc123 --activity publish --action publish --param note=shipping',
|
|
134
134
|
];
|
|
135
135
|
static args = {
|
|
136
136
|
instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
|
|
137
137
|
};
|
|
138
138
|
static flags = {
|
|
139
139
|
...tagFlags,
|
|
140
|
-
|
|
141
|
-
description: '
|
|
140
|
+
activity: Flags.string({
|
|
141
|
+
description: 'Activity the action belongs to. Required to fire; omit --action to list.',
|
|
142
142
|
}),
|
|
143
143
|
action: Flags.string({
|
|
144
144
|
description: 'Action to fire. Omit to list the actions available on the instance.',
|
|
@@ -170,15 +170,15 @@ export default class FireAction extends Command {
|
|
|
170
170
|
await this.listActions(client, config, args.instanceId, actor, flags.json);
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
|
-
if (flags.
|
|
174
|
-
fail('fire-action usage error:', 'specify --
|
|
173
|
+
if (flags.activity === undefined) {
|
|
174
|
+
fail('fire-action usage error:', 'specify --activity for the action (or omit --action to list what can be fired)');
|
|
175
175
|
}
|
|
176
176
|
await this.fireOne({
|
|
177
177
|
client,
|
|
178
178
|
config,
|
|
179
179
|
instanceId: args.instanceId,
|
|
180
180
|
actor,
|
|
181
|
-
|
|
181
|
+
activity: flags.activity,
|
|
182
182
|
action: flags.action,
|
|
183
183
|
params: flags.param,
|
|
184
184
|
json: flags.json,
|
|
@@ -206,14 +206,14 @@ export default class FireAction extends Command {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
async fireOne(opts) {
|
|
209
|
-
const { client, config, instanceId, actor,
|
|
209
|
+
const { client, config, instanceId, actor, activity, action, json } = opts;
|
|
210
210
|
const params = failOnThrow('Invalid --param:', () => parseParams(opts.params));
|
|
211
211
|
const fireArgs = {
|
|
212
212
|
client,
|
|
213
213
|
tag: config.tag,
|
|
214
214
|
workflowResource: config.workflowResource,
|
|
215
215
|
instanceId,
|
|
216
|
-
|
|
216
|
+
activity,
|
|
217
217
|
action,
|
|
218
218
|
access: { actor },
|
|
219
219
|
params,
|
|
@@ -222,13 +222,13 @@ export default class FireAction extends Command {
|
|
|
222
222
|
const result = await workflow
|
|
223
223
|
.fireAction(fireArgs)
|
|
224
224
|
.catch((error) => fail('fireAction error:', errorMessage(error)));
|
|
225
|
-
this.log(JSON.stringify(fireResultJson(result, { instanceId,
|
|
225
|
+
this.log(JSON.stringify(fireResultJson(result, { instanceId, activity, action }), null, 2));
|
|
226
226
|
return;
|
|
227
227
|
}
|
|
228
|
-
const spinner = ora(`Firing ${action} on ${
|
|
228
|
+
const spinner = ora(`Firing ${action} on ${activity}…`).start();
|
|
229
229
|
try {
|
|
230
230
|
const result = await workflow.fireAction(fireArgs);
|
|
231
|
-
emitWriteReport(spinner, fireActionReport(result,
|
|
231
|
+
emitWriteReport(spinner, fireActionReport(result, activity, action), (line) => this.log(line));
|
|
232
232
|
}
|
|
233
233
|
catch (error) {
|
|
234
234
|
spinner.fail('Action rejected');
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ type InstanceStatus = 'aborted' | 'completed' | 'in-flight';
|
|
|
12
12
|
interface ListFlags {
|
|
13
13
|
'in-flight': boolean;
|
|
14
14
|
failed: boolean;
|
|
15
|
-
'workflow-
|
|
15
|
+
'workflow-name'?: string | undefined;
|
|
16
16
|
tag?: string | undefined;
|
|
17
17
|
limit: number;
|
|
18
18
|
}
|
|
@@ -41,7 +41,7 @@ export default class List extends Command {
|
|
|
41
41
|
static flags: {
|
|
42
42
|
'in-flight': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
43
43
|
failed: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
44
|
-
'workflow-
|
|
44
|
+
'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
45
45
|
limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
46
46
|
tag: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
47
47
|
};
|
package/dist/commands/list.js
CHANGED
|
@@ -15,11 +15,11 @@ export function buildListQuery(flags) {
|
|
|
15
15
|
const filters = [`_type == "${WORKFLOW_INSTANCE_TYPE}"`];
|
|
16
16
|
if (flags['in-flight'])
|
|
17
17
|
filters.push('!defined(completedAt)');
|
|
18
|
-
if (flags['workflow-
|
|
18
|
+
if (flags['workflow-name'])
|
|
19
19
|
filters.push('definition == $definition');
|
|
20
|
-
// Cheap approximation of --failed: any
|
|
20
|
+
// Cheap approximation of --failed: any activity in any stage with status "failed".
|
|
21
21
|
if (flags.failed)
|
|
22
|
-
filters.push('count(stages[].
|
|
22
|
+
filters.push('count(stages[].activities[status == "failed"]) > 0');
|
|
23
23
|
if (flags.tag)
|
|
24
24
|
filters.push(tagScopeFilter());
|
|
25
25
|
const groq = `*[${filters.join(' && ')}] | order(lastChangedAt desc) [0...$limit]{
|
|
@@ -32,8 +32,8 @@ export function buildListQuery(flags) {
|
|
|
32
32
|
lastChangedAt
|
|
33
33
|
}`;
|
|
34
34
|
const params = { limit: flags.limit };
|
|
35
|
-
if (flags['workflow-
|
|
36
|
-
params['definition'] = flags['workflow-
|
|
35
|
+
if (flags['workflow-name'])
|
|
36
|
+
params['definition'] = flags['workflow-name'];
|
|
37
37
|
if (flags.tag)
|
|
38
38
|
params['tag'] = flags.tag;
|
|
39
39
|
return { groq, params };
|
|
@@ -68,7 +68,7 @@ export default class List extends Command {
|
|
|
68
68
|
static examples = [
|
|
69
69
|
'<%= config.bin %> list',
|
|
70
70
|
'<%= config.bin %> list --in-flight',
|
|
71
|
-
'<%= config.bin %> list --workflow-
|
|
71
|
+
'<%= config.bin %> list --workflow-name productLaunch',
|
|
72
72
|
'<%= config.bin %> list --tag prod',
|
|
73
73
|
];
|
|
74
74
|
static flags = {
|
|
@@ -78,10 +78,10 @@ export default class List extends Command {
|
|
|
78
78
|
default: false,
|
|
79
79
|
}),
|
|
80
80
|
failed: Flags.boolean({
|
|
81
|
-
description: 'Only instances with at least one failed
|
|
81
|
+
description: 'Only instances with at least one failed activity.',
|
|
82
82
|
default: false,
|
|
83
83
|
}),
|
|
84
|
-
'workflow-
|
|
84
|
+
'workflow-name': Flags.string({
|
|
85
85
|
description: 'Filter by workflow definition name.',
|
|
86
86
|
}),
|
|
87
87
|
limit: Flags.integer({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StubCommand } from '../lib/stub.ts';
|
|
2
|
-
export default class
|
|
2
|
+
export default class RetryActivity extends StubCommand {
|
|
3
3
|
static hidden: boolean;
|
|
4
4
|
static description: string;
|
|
5
5
|
static args: {
|
|
6
6
|
instanceId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
-
|
|
7
|
+
activity: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
8
|
};
|
|
9
9
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Args } from '@oclif/core';
|
|
2
2
|
import { StubCommand } from "../lib/stub.js";
|
|
3
|
-
export default class
|
|
3
|
+
export default class RetryActivity extends StubCommand {
|
|
4
4
|
// Stubbed, so kept off the help + published surface until it's wired.
|
|
5
5
|
static hidden = true;
|
|
6
|
-
static description = 'Re-invoke a failed
|
|
6
|
+
static description = 'Re-invoke a failed activity on an in-flight instance.';
|
|
7
7
|
static args = {
|
|
8
8
|
instanceId: Args.string({ required: true, description: 'Workflow instance id.' }),
|
|
9
|
-
|
|
9
|
+
activity: Args.string({ required: true, description: 'Activity name within the current stage.' }),
|
|
10
10
|
};
|
|
11
11
|
}
|
|
@@ -4,7 +4,7 @@ export default class SetStage extends StubCommand {
|
|
|
4
4
|
// Stubbed, so kept off the help + published surface until it's wired.
|
|
5
5
|
static hidden = true;
|
|
6
6
|
// Engine note: workflow.setStage currently always runs guards + stage
|
|
7
|
-
// entry (
|
|
7
|
+
// entry (activity activation, effects). A "manual override" that bypasses
|
|
8
8
|
// them is engine work that hasn't landed; this command stub captures
|
|
9
9
|
// the intended surface only.
|
|
10
10
|
static description = "Force-set an instance's current stage, bypassing guards + effects (manual override).";
|
package/dist/commands/show.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export default class Show extends Command {
|
|
|
15
15
|
* `fire-action`): a bold workflow + id title, then aligned detail rows. */
|
|
16
16
|
export declare function instanceHeader(instance: WorkflowInstance): string;
|
|
17
17
|
/**
|
|
18
|
-
* The per-instance body lines: every stage with its
|
|
18
|
+
* The per-instance body lines: every stage with its activities, any pending
|
|
19
19
|
* effects, and (optionally) the history log. Pure so it can be asserted
|
|
20
20
|
* without driving the oclif command.
|
|
21
21
|
*/
|
package/dist/commands/show.js
CHANGED
|
@@ -3,9 +3,9 @@ import { Args, Command, Flags } from '@oclif/core';
|
|
|
3
3
|
import { abortReason } from '@sanity/workflow-engine';
|
|
4
4
|
import logSymbols from 'log-symbols';
|
|
5
5
|
import { loadClient } from "../lib/client.js";
|
|
6
|
-
import { formatKeyValue, formatTimestamp, sectionHeader,
|
|
6
|
+
import { formatKeyValue, formatTimestamp, sectionHeader, activityIcon } from "../lib/ui.js";
|
|
7
7
|
export default class Show extends Command {
|
|
8
|
-
static description = 'Show the state,
|
|
8
|
+
static description = 'Show the state, activities, and effects of a workflow instance.';
|
|
9
9
|
static examples = [
|
|
10
10
|
'<%= config.bin %> show wf-instance.abc123',
|
|
11
11
|
'<%= config.bin %> show wf-instance.abc123 --include history',
|
|
@@ -68,7 +68,7 @@ export function instanceHeader(instance) {
|
|
|
68
68
|
return [title, ...rows].join('\n');
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* The per-instance body lines: every stage with its
|
|
71
|
+
* The per-instance body lines: every stage with its activities, any pending
|
|
72
72
|
* effects, and (optionally) the history log. Pure so it can be asserted
|
|
73
73
|
* without driving the oclif command.
|
|
74
74
|
*/
|
|
@@ -79,8 +79,8 @@ export function describeInstance(instance, options) {
|
|
|
79
79
|
? styleText('dim', ` (exited ${formatTimestamp(stage.exitedAt)})`)
|
|
80
80
|
: styleText('cyan', ' (current)');
|
|
81
81
|
lines.push(` • ${stage.name}${marker}`);
|
|
82
|
-
for (const
|
|
83
|
-
lines.push(` ${
|
|
82
|
+
for (const activity of stage.activities) {
|
|
83
|
+
lines.push(` ${activityIcon[activity.status]} ${activity.name} ${styleText('dim', `[${activity.status}]`)}`);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
if (instance.pendingEffects.length > 0) {
|
package/dist/lib/definitions.js
CHANGED
|
@@ -115,7 +115,7 @@ export function collectValidationErrors(defs) {
|
|
|
115
115
|
}
|
|
116
116
|
catch (err) {
|
|
117
117
|
const message = err instanceof Error ? err.message : String(err);
|
|
118
|
-
errors.push(` · ${d.name}
|
|
118
|
+
errors.push(` · ${d.name}: ${message}`);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
return errors;
|
package/dist/lib/diff.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DiffEntry } from '@sanity/workflow-engine';
|
|
2
|
-
/** One summary line per diff entry, tagged create /
|
|
2
|
+
/** One summary line per diff entry, tagged create / unchanged. Definitions are
|
|
3
|
+
* immutable, so a content change is a new version (`create`), never an update. */
|
|
3
4
|
export declare function summaryLines(entries: DiffEntry[]): string[];
|
|
4
5
|
/** Render a JSON diff of `oldObj` → `newObj` as `+`/`-`/context lines. */
|
|
5
6
|
export declare function diffLines(oldObj: object, newObj: object): string[];
|
package/dist/lib/diff.js
CHANGED
|
@@ -2,11 +2,11 @@ import { styleText } from 'node:util';
|
|
|
2
2
|
import { diffJson } from 'diff';
|
|
3
3
|
import logSymbols from 'log-symbols';
|
|
4
4
|
import { sectionHeader } from "./ui.js";
|
|
5
|
-
/** One summary line per diff entry, tagged create /
|
|
5
|
+
/** One summary line per diff entry, tagged create / unchanged. Definitions are
|
|
6
|
+
* immutable, so a content change is a new version (`create`), never an update. */
|
|
6
7
|
export function summaryLines(entries) {
|
|
7
8
|
const tags = {
|
|
8
9
|
create: styleText('green', '+ create '),
|
|
9
|
-
update: styleText('yellow', '~ update '),
|
|
10
10
|
unchanged: styleText('dim', ' unchanged'),
|
|
11
11
|
};
|
|
12
12
|
return entries.map((e) => {
|
package/dist/lib/ui.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ActivityStatus } from '@sanity/workflow-engine';
|
|
2
2
|
/**
|
|
3
3
|
* A bold `Title:` section heading. Mirrors the Sanity CLI's `sectionHeader`
|
|
4
4
|
* (name + shape) so it folds into the shared helper when this CLI merges in.
|
|
@@ -13,9 +13,9 @@ export declare function formatKeyValue(key: string, value: string, options?: {
|
|
|
13
13
|
indent?: number;
|
|
14
14
|
padTo?: number;
|
|
15
15
|
}): string;
|
|
16
|
-
/** Status glyph per
|
|
16
|
+
/** Status glyph per activity state. log-symbols ship pre-colored (green ✔, red ✖),
|
|
17
17
|
* so those need no extra wrap; the rest carry their own state color. */
|
|
18
|
-
export declare const
|
|
18
|
+
export declare const activityIcon: Record<ActivityStatus, string>;
|
|
19
19
|
/** An engine ISO-8601 timestamp as an absolute `yyyy-MM-dd HH:mm:ss` — the
|
|
20
20
|
* Sanity CLI's audit-log format (see `backups/list`). For detail views. */
|
|
21
21
|
export declare function formatTimestamp(iso: string): string;
|
package/dist/lib/ui.js
CHANGED
|
@@ -21,9 +21,9 @@ export function formatKeyValue(key, value, options) {
|
|
|
21
21
|
const paddedKey = `${key}:`.padEnd(padTo > 0 ? padTo + 1 : key.length + 1);
|
|
22
22
|
return `${' '.repeat(indent)}${styleText('dim', paddedKey)} ${value}`;
|
|
23
23
|
}
|
|
24
|
-
/** Status glyph per
|
|
24
|
+
/** Status glyph per activity state. log-symbols ship pre-colored (green ✔, red ✖),
|
|
25
25
|
* so those need no extra wrap; the rest carry their own state color. */
|
|
26
|
-
export const
|
|
26
|
+
export const activityIcon = {
|
|
27
27
|
done: logSymbols.success,
|
|
28
28
|
active: styleText('cyan', '●'),
|
|
29
29
|
pending: styleText('dim', '○'),
|
package/oclif.manifest.json
CHANGED
|
@@ -152,12 +152,12 @@
|
|
|
152
152
|
"required": true
|
|
153
153
|
}
|
|
154
154
|
},
|
|
155
|
-
"description": "Fire an action on an instance — act on a user's behalf to unstick a waiting
|
|
155
|
+
"description": "Fire an action on an instance — act on a user's behalf to unstick a waiting activity. Omit --action to list what can be fired.",
|
|
156
156
|
"examples": [
|
|
157
157
|
"<%= config.bin %> fire-action wf-instance.abc123",
|
|
158
|
-
"<%= config.bin %> fire-action wf-instance.abc123 --
|
|
159
|
-
"<%= config.bin %> fire-action wf-instance.abc123 --
|
|
160
|
-
"<%= config.bin %> fire-action wf-instance.abc123 --
|
|
158
|
+
"<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve",
|
|
159
|
+
"<%= config.bin %> fire-action wf-instance.abc123 --activity approve --action approve --as user.xyz --as-role editor",
|
|
160
|
+
"<%= config.bin %> fire-action wf-instance.abc123 --activity publish --action publish --param note=shipping"
|
|
161
161
|
],
|
|
162
162
|
"flags": {
|
|
163
163
|
"tag": {
|
|
@@ -167,9 +167,9 @@
|
|
|
167
167
|
"multiple": false,
|
|
168
168
|
"type": "option"
|
|
169
169
|
},
|
|
170
|
-
"
|
|
171
|
-
"description": "
|
|
172
|
-
"name": "
|
|
170
|
+
"activity": {
|
|
171
|
+
"description": "Activity the action belongs to. Required to fire; omit --action to list.",
|
|
172
|
+
"name": "activity",
|
|
173
173
|
"hasDynamicHelp": false,
|
|
174
174
|
"multiple": false,
|
|
175
175
|
"type": "option"
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
"examples": [
|
|
234
234
|
"<%= config.bin %> list",
|
|
235
235
|
"<%= config.bin %> list --in-flight",
|
|
236
|
-
"<%= config.bin %> list --workflow-
|
|
236
|
+
"<%= config.bin %> list --workflow-name productLaunch",
|
|
237
237
|
"<%= config.bin %> list --tag prod"
|
|
238
238
|
],
|
|
239
239
|
"flags": {
|
|
@@ -251,14 +251,14 @@
|
|
|
251
251
|
"type": "boolean"
|
|
252
252
|
},
|
|
253
253
|
"failed": {
|
|
254
|
-
"description": "Only instances with at least one failed
|
|
254
|
+
"description": "Only instances with at least one failed activity.",
|
|
255
255
|
"name": "failed",
|
|
256
256
|
"allowNo": false,
|
|
257
257
|
"type": "boolean"
|
|
258
258
|
},
|
|
259
|
-
"workflow-
|
|
259
|
+
"workflow-name": {
|
|
260
260
|
"description": "Filter by workflow definition name.",
|
|
261
|
-
"name": "workflow-
|
|
261
|
+
"name": "workflow-name",
|
|
262
262
|
"hasDynamicHelp": false,
|
|
263
263
|
"multiple": false,
|
|
264
264
|
"type": "option"
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
"move-stage.js"
|
|
341
341
|
]
|
|
342
342
|
},
|
|
343
|
-
"retry-
|
|
343
|
+
"retry-activity": {
|
|
344
344
|
"aliases": [],
|
|
345
345
|
"args": {
|
|
346
346
|
"instanceId": {
|
|
@@ -348,18 +348,18 @@
|
|
|
348
348
|
"name": "instanceId",
|
|
349
349
|
"required": true
|
|
350
350
|
},
|
|
351
|
-
"
|
|
352
|
-
"description": "
|
|
353
|
-
"name": "
|
|
351
|
+
"activity": {
|
|
352
|
+
"description": "Activity name within the current stage.",
|
|
353
|
+
"name": "activity",
|
|
354
354
|
"required": true
|
|
355
355
|
}
|
|
356
356
|
},
|
|
357
|
-
"description": "Re-invoke a failed
|
|
357
|
+
"description": "Re-invoke a failed activity on an in-flight instance.",
|
|
358
358
|
"flags": {},
|
|
359
359
|
"hasDynamicHelp": false,
|
|
360
360
|
"hidden": true,
|
|
361
361
|
"hiddenAliases": [],
|
|
362
|
-
"id": "retry-
|
|
362
|
+
"id": "retry-activity",
|
|
363
363
|
"pluginAlias": "@sanity/workflow-cli",
|
|
364
364
|
"pluginName": "@sanity/workflow-cli",
|
|
365
365
|
"pluginType": "core",
|
|
@@ -368,7 +368,7 @@
|
|
|
368
368
|
"relativePath": [
|
|
369
369
|
"dist",
|
|
370
370
|
"commands",
|
|
371
|
-
"retry-
|
|
371
|
+
"retry-activity.js"
|
|
372
372
|
]
|
|
373
373
|
},
|
|
374
374
|
"set-stage": {
|
|
@@ -422,7 +422,7 @@
|
|
|
422
422
|
"required": true
|
|
423
423
|
}
|
|
424
424
|
},
|
|
425
|
-
"description": "Show the state,
|
|
425
|
+
"description": "Show the state, activities, and effects of a workflow instance.",
|
|
426
426
|
"examples": [
|
|
427
427
|
"<%= config.bin %> show wf-instance.abc123",
|
|
428
428
|
"<%= config.bin %> show wf-instance.abc123 --include history"
|
|
@@ -614,9 +614,9 @@
|
|
|
614
614
|
"multiple": false,
|
|
615
615
|
"type": "option"
|
|
616
616
|
},
|
|
617
|
-
"workflow-
|
|
617
|
+
"workflow-name": {
|
|
618
618
|
"description": "Filter to a single workflow definition name (e.g. product-launch)",
|
|
619
|
-
"name": "workflow-
|
|
619
|
+
"name": "workflow-name",
|
|
620
620
|
"hasDynamicHelp": false,
|
|
621
621
|
"multiple": false,
|
|
622
622
|
"type": "option"
|
|
@@ -681,5 +681,5 @@
|
|
|
681
681
|
]
|
|
682
682
|
}
|
|
683
683
|
},
|
|
684
|
-
"version": "0.
|
|
684
|
+
"version": "0.8.0"
|
|
685
685
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/workflow-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Command-line tool for deploying, inspecting, and administering Sanity workflow definitions and instances.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -53,15 +53,15 @@
|
|
|
53
53
|
"diff": "^9.0.0",
|
|
54
54
|
"log-symbols": "^7.0.1",
|
|
55
55
|
"ora": "^9.4.0",
|
|
56
|
-
"@sanity/workflow-engine": "0.
|
|
56
|
+
"@sanity/workflow-engine": "0.12.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/diff": "^8.0.0",
|
|
60
60
|
"@types/node": "^24.12.4",
|
|
61
61
|
"oclif": "^4.23.16",
|
|
62
62
|
"vitest": "^4.1.8",
|
|
63
|
-
"@sanity/workflow-engine-test": "0.
|
|
64
|
-
"@sanity/workflow-examples": "0.
|
|
63
|
+
"@sanity/workflow-engine-test": "0.7.0",
|
|
64
|
+
"@sanity/workflow-examples": "0.2.0"
|
|
65
65
|
},
|
|
66
66
|
"oclif": {
|
|
67
67
|
"bin": "sanity-workflows",
|