@michaelrwalker/stagehand 0.1.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.
@@ -0,0 +1,176 @@
1
+ export type Awaitable<T> = T | Promise<T>;
2
+ /** Flattens intersections so hover tooltips show a real object shape. */
3
+ export type Prettify<T> = {
4
+ [K in keyof T]: T[K];
5
+ } & {};
6
+ /**
7
+ * Context after a step contributes `Out`. A step that returns nothing leaves
8
+ * the context untouched; later keys win over earlier ones.
9
+ */
10
+ export type Merge<Ctx, Out> = [Out] extends [void] ? Ctx : [Out] extends [undefined] ? Ctx : Prettify<Omit<Ctx, keyof Out> & Out>;
11
+ export type StepStatus = "pending" | "running" | "success" | "failed" | "skipped" | "rolling-back" | "rolled-back" | "rollback-failed";
12
+ export type PhaseStatus = "pending" | "running" | "success" | "failed" | "skipped";
13
+ export type RunStatus = "pending" | "running" | "success" | "failed" | "aborted";
14
+ export interface ProgressHandle {
15
+ /** Set the absolute value, optionally relabelling the bar. */
16
+ update(value: number, label?: string): void;
17
+ /** Advance by `by` (default 1). */
18
+ increment(by?: number): void;
19
+ setTotal(total: number): void;
20
+ setLabel(label: string): void;
21
+ /** Fill the bar and stop showing it as in-flight. */
22
+ done(): void;
23
+ readonly value: number;
24
+ readonly total: number;
25
+ }
26
+ export interface TaskHandle {
27
+ /** Move a pending task into the running state (spinner). */
28
+ start(text?: string): void;
29
+ /** Rename the task in place. */
30
+ label(text: string): void;
31
+ succeed(text?: string): void;
32
+ fail(text?: string): void;
33
+ skip(text?: string): void;
34
+ }
35
+ export interface TaskListHandle<K extends string> {
36
+ readonly tasks: Record<K, TaskHandle>;
37
+ get(key: K): TaskHandle;
38
+ }
39
+ /** Everything a handler gets: accumulated data plus the live terminal. */
40
+ export interface StepContext<In, Ctx> {
41
+ /** The input the script was run with. */
42
+ readonly input: In;
43
+ /** Data produced by every step that has already succeeded. */
44
+ readonly ctx: Ctx;
45
+ /** Aborts on timeout, on Ctrl-C, or when `run` is cancelled. */
46
+ readonly signal: AbortSignal;
47
+ /** 1 on the first try, 2 on the first retry, and so on. */
48
+ readonly attempt: number;
49
+ readonly phase: string;
50
+ readonly step: string;
51
+ /** Permanent line, printed above the live frame and kept in scrollback. */
52
+ log(message: string): void;
53
+ info(message: string): void;
54
+ warn(message: string): void;
55
+ error(message: string): void;
56
+ success(message: string): void;
57
+ /** Transient one-liner shown beside the step. Replaced on each call. */
58
+ status(message: string): void;
59
+ /** Attach a progress bar to this step. */
60
+ progress(options: {
61
+ total: number;
62
+ label?: string;
63
+ value?: number;
64
+ }): ProgressHandle;
65
+ /** Attach a single checklist item nested under this step. */
66
+ task(label: string): TaskHandle;
67
+ /** Attach a whole checklist at once, keyed for typed lookup. */
68
+ tasks<const K extends readonly string[]>(labels: K): TaskListHandle<K[number]>;
69
+ }
70
+ export interface RollbackContext<In, Ctx, Out> {
71
+ readonly input: In;
72
+ /** Context as it stood when the failure happened. */
73
+ readonly ctx: Ctx;
74
+ /** Exactly what this step's handler returned. */
75
+ readonly output: Out;
76
+ /** The error that triggered the unwind. */
77
+ readonly error: unknown;
78
+ readonly signal: AbortSignal;
79
+ readonly phase: string;
80
+ readonly step: string;
81
+ log(message: string): void;
82
+ status(message: string): void;
83
+ progress(options: {
84
+ total: number;
85
+ label?: string;
86
+ value?: number;
87
+ }): ProgressHandle;
88
+ }
89
+ export interface RetryPolicy {
90
+ attempts: number;
91
+ /** Fixed delay in ms, or a function of the attempt just failed (1-based). */
92
+ delayMs?: number | ((attempt: number) => number);
93
+ /** Return false to stop retrying this particular error. */
94
+ retryIf?: (error: unknown, attempt: number) => boolean;
95
+ }
96
+ export interface StepDef<In, Ctx, Out> {
97
+ name: string;
98
+ description?: string;
99
+ /**
100
+ * The work. Whatever object it resolves to is merged into `ctx` and becomes
101
+ * visible — and typed — for every later step.
102
+ */
103
+ handler: (context: StepContext<In, Ctx>) => Awaitable<Out>;
104
+ /**
105
+ * Compensation. Runs when a *later* step fails, in reverse order, after this
106
+ * step has already succeeded.
107
+ */
108
+ rollback?: (context: RollbackContext<In, Ctx, Out>) => Awaitable<void>;
109
+ /** Skip the step (and its rollback) when this resolves falsy. */
110
+ when?: (context: {
111
+ input: In;
112
+ ctx: Ctx;
113
+ }) => Awaitable<boolean>;
114
+ retry?: RetryPolicy;
115
+ timeoutMs?: number;
116
+ }
117
+ export interface PhaseOptions<In = unknown, Ctx = unknown> {
118
+ description?: string;
119
+ /** Skip every step in the phase when this resolves falsy. */
120
+ when?: (context: {
121
+ input: In;
122
+ ctx: Ctx;
123
+ }) => Awaitable<boolean>;
124
+ }
125
+ export interface ScriptOptions {
126
+ name?: string;
127
+ description?: string;
128
+ /**
129
+ * `all` (default) unwinds every completed step across the whole script.
130
+ * `phase` unwinds only the phase that failed. `none` leaves state as-is.
131
+ */
132
+ rollback?: "all" | "phase" | "none";
133
+ /** Throw instead of returning a failed result. Default false. */
134
+ throwOnError?: boolean;
135
+ /** Force the plain, non-animated renderer (useful in CI). Default: auto. */
136
+ plain?: boolean;
137
+ /** Suppress all output. */
138
+ silent?: boolean;
139
+ /** Rollback on SIGINT/SIGTERM. Default true. */
140
+ handleSignals?: boolean;
141
+ }
142
+ export interface StepReport {
143
+ phase: string;
144
+ name: string;
145
+ status: StepStatus;
146
+ durationMs: number;
147
+ attempts: number;
148
+ error?: unknown;
149
+ }
150
+ export interface RollbackReport {
151
+ phase: string;
152
+ step: string;
153
+ ok: boolean;
154
+ error?: unknown;
155
+ }
156
+ export type RunResult<Ctx> = {
157
+ ok: true;
158
+ status: "success";
159
+ ctx: Prettify<Ctx>;
160
+ durationMs: number;
161
+ steps: StepReport[];
162
+ } | {
163
+ ok: false;
164
+ status: "failed" | "aborted";
165
+ error: unknown;
166
+ failedAt: {
167
+ phase: string;
168
+ step: string;
169
+ } | null;
170
+ /** Partial context: everything the steps that did succeed produced. */
171
+ ctx: Partial<Prettify<Ctx>>;
172
+ durationMs: number;
173
+ steps: StepReport[];
174
+ rollbacks: RollbackReport[];
175
+ };
176
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Minimal ANSI toolkit. No dependencies, no global mutation of the stream.
3
+ */
4
+ export declare function isColorEnabled(): boolean;
5
+ export declare function setColorEnabled(value: boolean): void;
6
+ export type Styler = (input: string) => string;
7
+ export declare const bold: Styler;
8
+ export declare const dim: Styler;
9
+ export declare const italic: Styler;
10
+ export declare const underline: Styler;
11
+ export declare const inverse: Styler;
12
+ /** 256-colour foreground. Degrades to plain text when colour is off. */
13
+ export declare function fg(code: number): Styler;
14
+ /** 256-colour background. */
15
+ export declare function bg(code: number): Styler;
16
+ export declare const cursor: {
17
+ hide: string;
18
+ show: string;
19
+ up: (n: number) => string;
20
+ toStart: string;
21
+ eraseDown: string;
22
+ };
23
+ export declare function stripAnsi(input: string): string;
24
+ /**
25
+ * Terminal cell width. Handles the wide-character ranges that actually turn up
26
+ * in CLI output (CJK, emoji) and treats combining marks as zero-width.
27
+ */
28
+ export declare function stringWidth(input: string): number;
29
+ /**
30
+ * Truncate to a visible width while keeping escape sequences intact, so a
31
+ * clipped line never leaks colour into the rest of the frame.
32
+ */
33
+ export declare function truncate(input: string, max: number): string;
34
+ /**
35
+ * Word-wrap to a visible width, returning plain lines.
36
+ *
37
+ * Errors must never be clipped — the useful half of a message like npm's 403
38
+ * lives at the end of the line. Callers style each returned line themselves,
39
+ * which sidesteps splitting an escape sequence across a break.
40
+ */
41
+ export declare function wrapText(input: string, width: number): string[];
42
+ export declare function padEnd(input: string, target: number): string;
43
+ //# sourceMappingURL=ansi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../../src/ui/ansi.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEpD;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;AAM/C,eAAO,MAAM,IAAI,QAAiC,CAAC;AACnD,eAAO,MAAM,GAAG,QAAiC,CAAC;AAClD,eAAO,MAAM,MAAM,QAAiC,CAAC;AACrD,eAAO,MAAM,SAAS,QAAiC,CAAC;AACxD,eAAO,MAAM,OAAO,QAAiC,CAAC;AAEtD,wEAAwE;AACxE,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,6BAA6B;AAC7B,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,eAAO,MAAM,MAAM;;;YAGT,MAAM,KAAG,MAAM;;;CAGxB,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWjD;AAiBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B3D;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwC/D;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG5D"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Minimal ANSI toolkit. No dependencies, no global mutation of the stream.
3
+ */
4
+ const ESC = "[";
5
+ const ANSI_PATTERN = /\[[0-9;]*m/g;
6
+ function detectColor() {
7
+ const env = process.env;
8
+ if (env.NO_COLOR !== undefined && env.NO_COLOR !== "")
9
+ return false;
10
+ if (env.FORCE_COLOR !== undefined)
11
+ return env.FORCE_COLOR !== "0";
12
+ if (env.TERM === "dumb")
13
+ return false;
14
+ return Boolean(process.stdout.isTTY);
15
+ }
16
+ let colorEnabled = detectColor();
17
+ export function isColorEnabled() {
18
+ return colorEnabled;
19
+ }
20
+ export function setColorEnabled(value) {
21
+ colorEnabled = value;
22
+ }
23
+ function style(open, close) {
24
+ return (input) => (colorEnabled ? open + input + close : input);
25
+ }
26
+ export const bold = style(`${ESC}1m`, `${ESC}22m`);
27
+ export const dim = style(`${ESC}2m`, `${ESC}22m`);
28
+ export const italic = style(`${ESC}3m`, `${ESC}23m`);
29
+ export const underline = style(`${ESC}4m`, `${ESC}24m`);
30
+ export const inverse = style(`${ESC}7m`, `${ESC}27m`);
31
+ /** 256-colour foreground. Degrades to plain text when colour is off. */
32
+ export function fg(code) {
33
+ return style(`${ESC}38;5;${code}m`, `${ESC}39m`);
34
+ }
35
+ /** 256-colour background. */
36
+ export function bg(code) {
37
+ return style(`${ESC}48;5;${code}m`, `${ESC}49m`);
38
+ }
39
+ export const cursor = {
40
+ hide: `${ESC}?25l`,
41
+ show: `${ESC}?25h`,
42
+ up: (n) => (n > 0 ? `${ESC}${n}A` : ""),
43
+ toStart: `${ESC}G`,
44
+ eraseDown: `${ESC}0J`,
45
+ };
46
+ export function stripAnsi(input) {
47
+ return input.replace(ANSI_PATTERN, "");
48
+ }
49
+ /**
50
+ * Terminal cell width. Handles the wide-character ranges that actually turn up
51
+ * in CLI output (CJK, emoji) and treats combining marks as zero-width.
52
+ */
53
+ export function stringWidth(input) {
54
+ let total = 0;
55
+ for (const char of stripAnsi(input)) {
56
+ const cp = char.codePointAt(0);
57
+ if (cp === undefined)
58
+ continue;
59
+ if (cp === 0x200d)
60
+ continue; // zero-width joiner
61
+ if (cp >= 0x0300 && cp <= 0x036f)
62
+ continue; // combining diacriticals
63
+ if (cp >= 0xfe00 && cp <= 0xfe0f)
64
+ continue; // variation selectors
65
+ total += isWide(cp) ? 2 : 1;
66
+ }
67
+ return total;
68
+ }
69
+ function isWide(cp) {
70
+ return ((cp >= 0x1100 && cp <= 0x115f) ||
71
+ (cp >= 0x2e80 && cp <= 0xa4cf && cp !== 0x303f) ||
72
+ (cp >= 0xac00 && cp <= 0xd7a3) ||
73
+ (cp >= 0xf900 && cp <= 0xfaff) ||
74
+ (cp >= 0xfe30 && cp <= 0xfe6f) ||
75
+ (cp >= 0xff00 && cp <= 0xff60) ||
76
+ (cp >= 0xffe0 && cp <= 0xffe6) ||
77
+ (cp >= 0x1f300 && cp <= 0x1f64f) ||
78
+ (cp >= 0x1f900 && cp <= 0x1f9ff) ||
79
+ (cp >= 0x20000 && cp <= 0x3fffd));
80
+ }
81
+ /**
82
+ * Truncate to a visible width while keeping escape sequences intact, so a
83
+ * clipped line never leaks colour into the rest of the frame.
84
+ */
85
+ export function truncate(input, max) {
86
+ if (max <= 0)
87
+ return "";
88
+ if (stringWidth(input) <= max)
89
+ return input;
90
+ let out = "";
91
+ let visible = 0;
92
+ let sawEscape = false;
93
+ let index = 0;
94
+ while (index < input.length) {
95
+ if (input.startsWith("[", index)) {
96
+ const end = input.indexOf("m", index);
97
+ if (end !== -1) {
98
+ out += input.slice(index, end + 1);
99
+ sawEscape = true;
100
+ index = end + 1;
101
+ continue;
102
+ }
103
+ }
104
+ const char = String.fromCodePoint(input.codePointAt(index));
105
+ const w = stringWidth(char);
106
+ if (visible + w > max - 1)
107
+ break;
108
+ out += char;
109
+ visible += w;
110
+ index += char.length;
111
+ }
112
+ return out + "…" + (sawEscape && colorEnabled ? `${ESC}0m` : "");
113
+ }
114
+ /**
115
+ * Word-wrap to a visible width, returning plain lines.
116
+ *
117
+ * Errors must never be clipped — the useful half of a message like npm's 403
118
+ * lives at the end of the line. Callers style each returned line themselves,
119
+ * which sidesteps splitting an escape sequence across a break.
120
+ */
121
+ export function wrapText(input, width) {
122
+ if (width <= 1)
123
+ return [stripAnsi(input)];
124
+ const lines = [];
125
+ let current = "";
126
+ const push = () => {
127
+ if (current !== "")
128
+ lines.push(current);
129
+ current = "";
130
+ };
131
+ for (const word of stripAnsi(input).split(/\s+/).filter(Boolean)) {
132
+ let token = word;
133
+ // A single token wider than the line (a URL, a stack frame) is hard-broken.
134
+ while (stringWidth(token) > width) {
135
+ push();
136
+ let head = "";
137
+ let index = 0;
138
+ while (index < token.length && stringWidth(head) < width) {
139
+ const char = String.fromCodePoint(token.codePointAt(index));
140
+ if (stringWidth(head) + stringWidth(char) > width)
141
+ break;
142
+ head += char;
143
+ index += char.length;
144
+ }
145
+ lines.push(head);
146
+ token = token.slice(index);
147
+ }
148
+ if (token === "")
149
+ continue;
150
+ if (current === "")
151
+ current = token;
152
+ else if (stringWidth(current) + 1 + stringWidth(token) <= width)
153
+ current += ` ${token}`;
154
+ else {
155
+ push();
156
+ current = token;
157
+ }
158
+ }
159
+ push();
160
+ return lines.length > 0 ? lines : [""];
161
+ }
162
+ export function padEnd(input, target) {
163
+ const gap = target - stringWidth(input);
164
+ return gap > 0 ? input + " ".repeat(gap) : input;
165
+ }
166
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../src/ui/ansi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type ProgressState, type RunState } from "../state.js";
2
+ export type LogLevel = "log" | "info" | "warn" | "error" | "success";
3
+ export interface LogEntry {
4
+ level: LogLevel;
5
+ message: string;
6
+ }
7
+ export declare function renderBar(progress: ProgressState, width?: number): string;
8
+ export declare function renderHeader(state: RunState): string[];
9
+ /**
10
+ * Lines the live region may occupy without the terminal scrolling under it.
11
+ *
12
+ * The hard limit is the viewport height; the margin covers the one extra line
13
+ * a permanent log write costs when the region is already at full height.
14
+ */
15
+ export declare function bodyBudget(): number;
16
+ /**
17
+ * The live body, guaranteed to fit `bodyBudget()`.
18
+ *
19
+ * This guarantee is load-bearing, not cosmetic: the renderer repaints by moving
20
+ * the cursor up N lines, so a frame taller than the viewport scrolls its own
21
+ * top off screen and every repaint appends a copy instead of overwriting. Four
22
+ * progressively stronger reductions are tried, and the result is clamped.
23
+ */
24
+ export declare function renderBody(state: RunState, tick: number, now: number, fit?: boolean): string[];
25
+ export declare function renderSummary(state: RunState, now: number): string[];
26
+ export declare function renderLogEntry(entry: LogEntry): string;
27
+ //# sourceMappingURL=frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/ui/frame.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,QAAQ,EAGd,MAAM,aAAa,CAAC;AAOrB,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA8DD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,SAAK,GAAG,MAAM,CAoBrE;AAwHD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,EAAE,CAOtD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,UAAO,GAAG,MAAM,EAAE,CA2C3F;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAgDpE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAkBtD"}