@michaelrwalker/stagehand 0.7.0 → 0.9.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 +22 -1
- package/dist/cache.d.ts +1 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +2 -2
- package/dist/cache.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/script.d.ts +55 -18
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +38 -6
- package/dist/script.js.map +1 -1
- package/dist/types.d.ts +71 -14
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/skills/building-scripts/branching-steps/SKILL.md +144 -0
- package/skills/building-scripts/command-line-flags/SKILL.md +115 -0
- package/skills/building-scripts/getting-started/SKILL.md +1 -1
- package/skills/building-scripts/prompting-the-user/SKILL.md +91 -0
- package/skills/building-scripts/structuring-phases-and-steps/SKILL.md +5 -1
- package/skills/building-scripts/typed-context-and-input/SKILL.md +1 -1
- package/skills/caching/caching-expensive-work/SKILL.md +3 -3
- package/skills/compensation-safety/adding-rollbacks/SKILL.md +3 -1
- package/skills/compensation-safety/cleaning-context/SKILL.md +1 -1
- package/skills/compensation-safety/conditional-steps/SKILL.md +19 -3
- package/skills/errors-results/handling-results-and-errors/SKILL.md +19 -4
- package/skills/observability/log-placement-and-rendering/SKILL.md +1 -1
- package/skills/observability/reporting-progress/SKILL.md +3 -1
- package/skills/reuse/reusable-routines-and-mounts/SKILL.md +3 -3
- package/skills/reuse/splitting-steps-across-files/SKILL.md +1 -1
|
@@ -10,7 +10,7 @@ description: >
|
|
|
10
10
|
metadata:
|
|
11
11
|
type: 'core'
|
|
12
12
|
library: 'stagehand'
|
|
13
|
-
library_version: '0.
|
|
13
|
+
library_version: '0.8.0'
|
|
14
14
|
sources:
|
|
15
15
|
- 'miaklwalker/stagehand:docs/guides/rollbacks.md'
|
|
16
16
|
- 'miaklwalker/stagehand:docs/reference/errors.md'
|
|
@@ -26,6 +26,8 @@ completed, first undone. The step that actually failed is never compensated: it
|
|
|
26
26
|
there's nothing to undo. A rollback gets no context by default; it has to name every key it needs
|
|
27
27
|
through `rollbackKeys`, which both narrows and permanently reserves them.
|
|
28
28
|
|
|
29
|
+
Rollback timing, retries and scope are specified exactly in docs/guides/error-handling.md (summary: skills/errors-results/handling-results-and-errors/SKILL.md, "The failure contract"). Notably, retries do not trigger rollback and the failed step is never rolled back.
|
|
30
|
+
|
|
29
31
|
## Setup
|
|
30
32
|
|
|
31
33
|
```ts
|
|
@@ -8,16 +8,17 @@ description: >
|
|
|
8
8
|
metadata:
|
|
9
9
|
type: 'core'
|
|
10
10
|
library: 'stagehand'
|
|
11
|
-
library_version: '0.
|
|
11
|
+
library_version: '0.8.0'
|
|
12
12
|
sources:
|
|
13
13
|
- 'miaklwalker/stagehand:docs/guides/phases-and-steps.md'
|
|
14
14
|
- 'miaklwalker/stagehand:docs/guides/reusable-scripts.md'
|
|
15
|
+
- 'miaklwalker/stagehand:docs/guides/flags.md'
|
|
15
16
|
- 'miaklwalker/stagehand:src/script.ts'
|
|
16
17
|
---
|
|
17
18
|
|
|
18
19
|
# Stagehand — Conditional Steps and Phases
|
|
19
20
|
|
|
20
|
-
`when` on `addStep` or `addPhase` is a function of `{ input, ctx }` (may be async) that gates whether the step, or every step in the phase, runs at all. A falsy result marks the step `"skipped"` — it never runs its handler and never runs its `rollback`.
|
|
21
|
+
`when` on `addStep` or `addPhase` is a function of `{ input, ctx, flags }` (may be async) that gates whether the step, or every step in the phase, runs at all. A falsy result marks the step `"skipped"` — it never runs its handler and never runs its `rollback`.
|
|
21
22
|
|
|
22
23
|
## Setup
|
|
23
24
|
|
|
@@ -58,7 +59,7 @@ new Script<{ environment: "development" | "production" }>({ name: "deploy" })
|
|
|
58
59
|
});
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
`when` sees the same `{ input, ctx }`
|
|
62
|
+
`when` sees the same `{ input, ctx, flags }` a handler does, so it can read anything an earlier step already put in context, and any `defineFlag` value (`when: ({ flags }) => !flags.quiet`).
|
|
62
63
|
|
|
63
64
|
### Gate an entire phase
|
|
64
65
|
|
|
@@ -87,6 +88,21 @@ A falsy phase-level `when` marks every step in `"Release"` `"skipped"` in one sh
|
|
|
87
88
|
|
|
88
89
|
`when` may return a promise; the script awaits it before deciding whether to run or skip the step (or, at phase level, the whole phase).
|
|
89
90
|
|
|
91
|
+
### Need the output either way? Use `addBranch`
|
|
92
|
+
|
|
93
|
+
A skipped step produces nothing, but `ctx` is still typed as though it ran. When later steps depend on the value, pick between two ways of producing it instead:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
.addBranch({
|
|
97
|
+
name: "resolve commit",
|
|
98
|
+
condition: ({ flags }) => Boolean(flags.sha),
|
|
99
|
+
onTrue: ({ flags }) => ({ sha: flags.sha as string }),
|
|
100
|
+
onFalse: async () => ({ sha: await git.head() }),
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
See skills/building-scripts/branching-steps/SKILL.md.
|
|
105
|
+
|
|
90
106
|
## Common Mistakes
|
|
91
107
|
|
|
92
108
|
### MEDIUM Skipped step's `clean` still runs
|
|
@@ -3,25 +3,40 @@ name: 'handling-results-and-errors'
|
|
|
3
3
|
description: >
|
|
4
4
|
Covers the RunResult discriminated union returned by run(), every exported error class
|
|
5
5
|
(StepFailedError, StepTimeoutError, ScriptAbortedError, RollbackFailedError, CacheShapeError,
|
|
6
|
-
SchemaValidationError
|
|
6
|
+
SchemaValidationError, UnknownFlagError, MissingFlagValueError, PromptCancelledError,
|
|
7
|
+
PromptUnavailableError), the isAbort(error) helper, and the throwOnError script option. Load this
|
|
7
8
|
for "branch correctly on a failed run," "tell a Ctrl-C cancellation apart from a real failure,"
|
|
8
9
|
or "get the phase/step name a failure happened at."
|
|
9
10
|
metadata:
|
|
10
11
|
type: 'core'
|
|
11
12
|
library: 'stagehand'
|
|
12
|
-
library_version: '0.
|
|
13
|
+
library_version: '0.8.0'
|
|
13
14
|
sources:
|
|
15
|
+
- 'miaklwalker/stagehand:docs/guides/error-handling.md'
|
|
14
16
|
- 'miaklwalker/stagehand:docs/guides/rollbacks.md'
|
|
15
17
|
- 'miaklwalker/stagehand:docs/guides/script-options-and-result.md'
|
|
16
18
|
- 'miaklwalker/stagehand:docs/reference/errors.md'
|
|
17
19
|
- 'miaklwalker/stagehand:src/errors.ts'
|
|
18
20
|
- 'miaklwalker/stagehand:src/script.ts'
|
|
21
|
+
- 'miaklwalker/stagehand:test/error-handling.test.ts'
|
|
19
22
|
---
|
|
20
23
|
|
|
21
24
|
# Stagehand — Handling Results and Errors
|
|
22
25
|
|
|
23
26
|
`run()` never throws for an ordinary step failure — it resolves to a discriminated union on `ok`. A handful of exported error classes exist for callers building their own reporting, but most of them never propagate through `run()` itself; knowing which ones do (and which don't) is the whole game.
|
|
24
27
|
|
|
28
|
+
## The failure contract (read this before reasoning about rollback)
|
|
29
|
+
|
|
30
|
+
- **Retries never roll back.** A failed attempt is not compensated; the handler simply re-runs against the same `input`/`ctx`. Rollback runs **once**, after the last attempt fails (or `retryIf` stops retrying).
|
|
31
|
+
- **The failed step is never rolled back**, and steps after it never run (`"pending"`). Only steps that *completed* are compensated, in reverse order. Skipped and cached steps are not.
|
|
32
|
+
- **Extent** is `ScriptOptions.rollback`: `"all"` (default) every completed step, `"phase"` only the failing step's phase, `"none"` nothing.
|
|
33
|
+
- A **failing rollback** is recorded in `result.rollbacks` (`status: "rollback-failed"`), the rest still run, and `result.error` stays the original error.
|
|
34
|
+
- A **timeout** (`StepTimeoutError`) is an ordinary failure: retried, `isAbort` false. A **cancellation** is never retried, gives `status: "aborted"`, and still compensates; a second signal abandons compensation.
|
|
35
|
+
- **Not step failures** (thrown out of `run()`, nothing rolled back): `SchemaValidationError`, flag errors, and an error thrown by a `when` predicate or a mount `input` mapper. Keep those total; put fallible logic in a step or `addBranch`.
|
|
36
|
+
- A step with `retry` must tolerate partial work: nothing compensates the failed attempts, so make it idempotent or clean up inside the handler before rethrowing.
|
|
37
|
+
|
|
38
|
+
Full tables and the step lifecycle: docs/guides/error-handling.md.
|
|
39
|
+
|
|
25
40
|
## Setup
|
|
26
41
|
|
|
27
42
|
```ts
|
|
@@ -89,7 +104,7 @@ if (!result.ok) {
|
|
|
89
104
|
}
|
|
90
105
|
```
|
|
91
106
|
|
|
92
|
-
`isAbort(error)` returns `true` for a `ScriptAbortedError` or any `Error` named `"AbortError"` — checking `result.status === "aborted"` alongside it confirms the abort was the script's own, not an unrelated `AbortError` a handler happened to throw.
|
|
107
|
+
`isAbort(error)` returns `true` for a `ScriptAbortedError`, a `PromptCancelledError` (Ctrl-C at a prompt), or any `Error` named `"AbortError"` — checking `result.status === "aborted"` alongside it confirms the abort was the script's own, not an unrelated `AbortError` a handler happened to throw.
|
|
93
108
|
|
|
94
109
|
### Use `throwOnError` when the script is one stage of a larger flow
|
|
95
110
|
|
|
@@ -157,7 +172,7 @@ try {
|
|
|
157
172
|
}
|
|
158
173
|
```
|
|
159
174
|
|
|
160
|
-
`SchemaValidationError` is always thrown directly by `run()`, before any phase executes, and is unaffected by `throwOnError` — there is no partial result to produce since nothing ran yet.
|
|
175
|
+
`SchemaValidationError` is always thrown directly by `run()`, before any phase executes, and is unaffected by `throwOnError` — there is no partial result to produce since nothing ran yet. `UnknownFlagError` and `MissingFlagValueError` (bad `defineFlag` argv) behave the same way. `PromptUnavailableError`, by contrast, is thrown from inside a handler, so it arrives as an ordinary failed step.
|
|
161
176
|
|
|
162
177
|
Source: docs/guides/typed-context.md; docs/reference/errors.md
|
|
163
178
|
|
|
@@ -5,7 +5,7 @@ description: >
|
|
|
5
5
|
metadata:
|
|
6
6
|
type: 'core'
|
|
7
7
|
library: 'stagehand'
|
|
8
|
-
library_version: '0.
|
|
8
|
+
library_version: '0.8.0'
|
|
9
9
|
sources:
|
|
10
10
|
- 'miaklwalker/stagehand:docs/guides/handler-surface.md'
|
|
11
11
|
- 'miaklwalker/stagehand:src/context.ts'
|
|
@@ -14,6 +14,8 @@ sources:
|
|
|
14
14
|
|
|
15
15
|
# Stagehand — Reporting Progress From a Step
|
|
16
16
|
|
|
17
|
+
The handler context also carries `prompt` (see skills/building-scripts/prompting-the-user/SKILL.md) and `flags` (see skills/building-scripts/command-line-flags/SKILL.md); this skill covers only the output side.
|
|
18
|
+
|
|
17
19
|
Every handler receives `status`, `note`, `progress`, `task`, `tasks`, and the five log methods as part of its single context object. `rollback` gets a smaller subset — `log` (no `info`/`warn`/`error`/`success`), `status`, `note`, and `progress`, but not `task`/`tasks`.
|
|
18
20
|
|
|
19
21
|
## Setup
|
|
@@ -7,7 +7,7 @@ description: >
|
|
|
7
7
|
metadata:
|
|
8
8
|
type: 'core'
|
|
9
9
|
library: 'stagehand'
|
|
10
|
-
library_version: '0.
|
|
10
|
+
library_version: '0.8.0'
|
|
11
11
|
sources:
|
|
12
12
|
- 'miaklwalker/stagehand:docs/guides/reusable-scripts.md'
|
|
13
13
|
- 'miaklwalker/stagehand:docs/guides/caching.md'
|
|
@@ -104,7 +104,7 @@ const result = await new Script<{ region: string }>({ name: "t" })
|
|
|
104
104
|
.run({ region: "eu" });
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
`input` takes a fixed value or an `{ input, ctx } => SubIn` mapper, may be async, and is resolved once per mount at the moment the mount is reached — the host no longer has to match the routine's input shape, only produce it.
|
|
107
|
+
`input` takes a fixed value or an `{ input, ctx, flags } => SubIn` mapper, may be async, and is resolved once per mount at the moment the mount is reached — the host no longer has to match the routine's input shape, only produce it. `flags` is how a routine, which cannot declare flags itself, is driven by one: `use(r, { input: ({ flags }) => ({ env: flags.environment }) })`.
|
|
108
108
|
|
|
109
109
|
## Common Mistakes
|
|
110
110
|
|
|
@@ -152,7 +152,7 @@ export const pullChannel = routineFor<{ channel: string; since: string }>()(
|
|
|
152
152
|
);
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
A mount's input is resolved once, when the mount is reached, from either a fixed value or an `{ input, ctx } => SubIn` mapper — every `when` inside that fragment (phase- or step-level) is evaluated against the mount's resolved input, never the host's own.
|
|
155
|
+
A mount's input is resolved once, when the mount is reached, from either a fixed value or an `{ input, ctx, flags } => SubIn` mapper — every `when` inside that fragment (phase- or step-level) is evaluated against the mount's resolved input, never the host's own.
|
|
156
156
|
|
|
157
157
|
Source: docs/guides/reusable-scripts.md ("Giving a mount its own input"); src/script.ts use()/run() mount input resolution
|
|
158
158
|
|