@markjaquith/agency 1.9.1 → 1.9.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markjaquith/agency",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "Manages personal agents files",
5
5
  "keywords": [
6
6
  "agents",
@@ -0,0 +1,45 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { Effect } from "effect"
3
+ import { withSpinner } from "./spinner"
4
+
5
+ describe("withSpinner", () => {
6
+ test("clears and stops the spinner when an Effect failure has no fail text", async () => {
7
+ const originalNodeEnv = process.env.NODE_ENV
8
+ const originalBunEnv = process.env.BUN_ENV
9
+ delete process.env.NODE_ENV
10
+ delete process.env.BUN_ENV
11
+
12
+ const calls: string[] = []
13
+ const error = new Error("boom")
14
+
15
+ try {
16
+ await expect(
17
+ Effect.runPromise(
18
+ withSpinner(Effect.fail(error), {
19
+ text: "Working",
20
+ createSpinner: () => ({
21
+ succeed: () => calls.push("succeed"),
22
+ fail: () => calls.push("fail"),
23
+ clear: () => calls.push("clear"),
24
+ stop: () => calls.push("stop"),
25
+ }),
26
+ }),
27
+ ),
28
+ ).rejects.toThrow("boom")
29
+
30
+ expect(calls).toEqual(["clear", "stop"])
31
+ } finally {
32
+ if (originalNodeEnv === undefined) {
33
+ delete process.env.NODE_ENV
34
+ } else {
35
+ process.env.NODE_ENV = originalNodeEnv
36
+ }
37
+
38
+ if (originalBunEnv === undefined) {
39
+ delete process.env.BUN_ENV
40
+ } else {
41
+ process.env.BUN_ENV = originalBunEnv
42
+ }
43
+ }
44
+ })
45
+ })
@@ -1,5 +1,12 @@
1
1
  import ora from "ora"
2
- import { Effect } from "effect"
2
+ import { Effect, Exit } from "effect"
3
+
4
+ interface Spinner {
5
+ succeed: (text?: string) => unknown
6
+ fail: (text?: string) => unknown
7
+ clear: () => unknown
8
+ stop: () => unknown
9
+ }
3
10
 
4
11
  /**
5
12
  * Check if we're running in a test environment
@@ -20,6 +27,8 @@ interface SpinnerConfig {
20
27
  failText?: string
21
28
  /** Whether the spinner is enabled (defaults to true) */
22
29
  enabled?: boolean
30
+ /** Creates the spinner instance. Intended for tests. */
31
+ createSpinner?: (text: string) => Spinner
23
32
  }
24
33
 
25
34
  /**
@@ -53,31 +62,35 @@ export const withSpinner = <A, E, R>(
53
62
  return effect
54
63
  }
55
64
 
56
- return Effect.gen(function* () {
57
- const spinner = ora({
58
- text,
59
- spinner: "dots",
60
- color: "cyan",
61
- }).start()
62
-
63
- try {
64
- const result = yield* effect
65
+ const createSpinner =
66
+ config.createSpinner ??
67
+ ((text: string) =>
68
+ ora({
69
+ text,
70
+ spinner: "dots",
71
+ color: "cyan",
72
+ }).start())
65
73
 
66
- if (successText) {
67
- spinner.succeed(successText)
68
- } else {
69
- spinner.stop()
70
- }
74
+ return Effect.acquireUseRelease(
75
+ Effect.sync(() => createSpinner(text)),
76
+ () => effect,
77
+ (spinner, exit) =>
78
+ Effect.sync(() => {
79
+ if (Exit.isSuccess(exit)) {
80
+ if (successText) {
81
+ spinner.succeed(successText)
82
+ } else {
83
+ spinner.stop()
84
+ }
85
+ return
86
+ }
71
87
 
72
- return result
73
- } catch (error) {
74
- if (failText) {
75
- spinner.fail(failText)
76
- } else {
77
- spinner.clear()
78
- spinner.stop()
79
- }
80
- throw error
81
- }
82
- })
88
+ if (failText) {
89
+ spinner.fail(failText)
90
+ } else {
91
+ spinner.clear()
92
+ spinner.stop()
93
+ }
94
+ }),
95
+ )
83
96
  }