effective-progress 0.6.0 → 0.6.1

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 CHANGED
@@ -17,7 +17,7 @@
17
17
  - spinner support for “we have no idea how long this takes” work
18
18
  - keep using `Console.log` / `Effect.logInfo` while progress rendering is active
19
19
  - familiar `.all` and `.forEach` APIs — swap `Effect` for `Progress`, get progress bars basically for free
20
- - flicker-free rendering (in theory) by drawing everything in a single terminal frame
20
+ - flicker-free rendering with [Ink](https://github.com/vadimdemedes/ink)
21
21
 
22
22
  ## Install
23
23
 
@@ -27,7 +27,7 @@ bun add effective-progress
27
27
 
28
28
  ## Usage
29
29
 
30
- This shows the simplest usage: iterate items with a single progress bar.
30
+ Iterate items with a single progress bar.
31
31
 
32
32
  ```ts
33
33
  import { Console, Effect } from "effect";
@@ -50,13 +50,7 @@ Effect.runPromise(program);
50
50
 
51
51
  ### Nested example
52
52
 
53
- Run:
54
-
55
- ```bash
56
- bun examples/nesting.ts
57
- ```
58
-
59
- This demonstrates nested multibar behavior where parent tasks each run their own child progress bars.
53
+ Nested progress bars with tree-style rendering that highlights parent tasks and their subtasks
60
54
 
61
55
  ```ts
62
56
  import { Effect } from "effect";
@@ -81,10 +75,15 @@ Effect.runPromise(program);
81
75
 
82
76
  ### Effect.all modes
83
77
 
84
- We support the `either`/`validate` modes of `Effect.all` and render the amount of sucesses/failures.
78
+ Support for `either`/`validate` modes of `Effect.all` and render the amount of sucesses/failures.
85
79
 
86
80
  <img alt="Mixed outcomes modes output" src="docs/images/mixedOutcomes.gif" width="600" />
87
81
 
82
+ - `Progress.all` in default mode (`mode: "default"`) remains fail-fast.
83
+ - In fail-fast runs, unresolved units remain unprocessed.
84
+ - `mode: "either"` and `mode: "validate"` run all effects and keep mixed outcomes in the task counters.
85
+ - Mixed outcomes can still finalize as `done` when all units are accounted for.
86
+
88
87
  ### Other examples
89
88
 
90
89
  - `examples/simpleExample.ts` - low-boilerplate real-world flow
@@ -112,13 +111,6 @@ We support the `either`/`validate` modes of `Effect.all` and render the amount o
112
111
  - Layout uses a 100-column baseline and grows when content requires more space.
113
112
  - On narrow terminals, layout compacts to fit available width and tree prefixes are suppressed when description space is too tight.
114
113
 
115
- ### Mixed outcomes and `mode`
116
-
117
- - `Progress.all` in default mode (`mode: "default"`) remains fail-fast.
118
- - In fail-fast runs, unresolved units remain unprocessed.
119
- - `mode: "either"` and `mode: "validate"` run all effects and keep mixed outcomes in the task counters.
120
- - Mixed outcomes can still finalize as `done` when all units are accounted for.
121
-
122
114
  ## Manual task control
123
115
 
124
116
  For manual usage, `task` still provides the current `Task` context, while logs continue through your outer `Console`:
@@ -131,8 +123,8 @@ const program = Progress.task(
131
123
  yield* Console.log("This log is handled by the outer Console", { taskId: currentTask });
132
124
 
133
125
  // Manual determinate updates:
134
- yield* progress.advanceTask(currentTask, 3);
135
- yield* progress.advanceTaskFailed(currentTask, 1);
126
+ yield* progress.incrementSucceeded(currentTask, 3);
127
+ yield* progress.incrementFailed(currentTask, 1);
136
128
  yield* Effect.sleep("1 second");
137
129
  }),
138
130
  { description: "Manual task", total: 10 },
package/dist/index.d.mts CHANGED
@@ -66,8 +66,8 @@ interface TaskStore {
66
66
  interface ProgressService {
67
67
  readonly addTask: (options: AddTaskOptions) => Effect.Effect<TaskId>;
68
68
  readonly updateTask: (taskId: TaskId, options: UpdateTaskOptions) => Effect.Effect<void>;
69
- readonly advanceTask: (taskId: TaskId, amount?: number) => Effect.Effect<void>;
70
- readonly advanceTaskFailed: (taskId: TaskId, amount?: number) => Effect.Effect<void>;
69
+ readonly incrementSucceeded: (taskId: TaskId, amount?: number) => Effect.Effect<void>;
70
+ readonly incrementFailed: (taskId: TaskId, amount?: number) => Effect.Effect<void>;
71
71
  readonly completeTask: (taskId: TaskId) => Effect.Effect<void>;
72
72
  readonly failTask: (taskId: TaskId) => Effect.Effect<void>;
73
73
  readonly log: (...args: ReadonlyArray<unknown>) => Effect.Effect<void>;
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { Brand, Cause, Clock, Context, Effect, Exit, FiberRef, Layer, Option, Sc
2
2
  import { dual } from "effect/Function";
3
3
  import { Box, Text, render } from "ink";
4
4
  import { useEffect, useState, useSyncExternalStore } from "react";
5
- import stringWidth from "string-width";
5
+ import stringWidth from "fast-string-width";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
 
8
8
  //#region src/types.ts
@@ -327,7 +327,7 @@ const makeProgressRenderStore = () => {
327
327
  };
328
328
  });
329
329
  }),
330
- addSuccess: (taskId, amount = 1) => Effect.sync(() => {
330
+ incrementSucceeded: (taskId, amount = 1) => Effect.sync(() => {
331
331
  updateState((current) => {
332
332
  const currentTask = current.tasks.get(taskId);
333
333
  if (!currentTask || currentTask.units._tag !== "DeterminateTaskUnits") return current;
@@ -353,7 +353,7 @@ const makeProgressRenderStore = () => {
353
353
  };
354
354
  });
355
355
  }),
356
- addFailure: (taskId, amount = 1) => Effect.sync(() => {
356
+ incrementFailed: (taskId, amount = 1) => Effect.sync(() => {
357
357
  updateState((current) => {
358
358
  const currentTask = current.tasks.get(taskId);
359
359
  if (!currentTask || currentTask.units._tag !== "DeterminateTaskUnits") return current;
@@ -1466,8 +1466,8 @@ const makeProgressService = Effect.gen(function* () {
1466
1466
  });
1467
1467
  });
1468
1468
  const updateTask = store.updateTask;
1469
- const advanceTask = store.addSuccess;
1470
- const advanceTaskFailed = store.addFailure;
1469
+ const incrementSucceeded = store.incrementSucceeded;
1470
+ const incrementFailed = store.incrementFailed;
1471
1471
  const completeTask = store.completeTask;
1472
1472
  const failTask = store.failTask;
1473
1473
  const getTask = store.getTask;
@@ -1485,8 +1485,8 @@ const makeProgressService = Effect.gen(function* () {
1485
1485
  const service = {
1486
1486
  addTask,
1487
1487
  updateTask,
1488
- advanceTask,
1489
- advanceTaskFailed,
1488
+ incrementSucceeded,
1489
+ incrementFailed,
1490
1490
  completeTask,
1491
1491
  failTask,
1492
1492
  log,
@@ -1546,11 +1546,11 @@ const allCountDisplay = (mode) => isCollectAllMode(mode) ? "detailed" : "process
1546
1546
  const wrapTrackedEffect = (progress, taskId, effect) => Effect.gen(function* () {
1547
1547
  const exit = yield* Effect.exit(effect);
1548
1548
  if (Exit.isSuccess(exit)) {
1549
- yield* progress.advanceTask(taskId, 1);
1549
+ yield* progress.incrementSucceeded(taskId, 1);
1550
1550
  return exit.value;
1551
1551
  }
1552
1552
  if (Cause.isInterruptedOnly(exit.cause)) return yield* Effect.failCause(exit.cause);
1553
- yield* progress.advanceTaskFailed(taskId, 1);
1553
+ yield* progress.incrementFailed(taskId, 1);
1554
1554
  return yield* Effect.failCause(exit.cause);
1555
1555
  });
1556
1556
  const isTaskFullyProcessed = (progress, taskId) => Effect.gen(function* () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effective-progress",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Effect-first terminal progress bars with nested multibar support",
5
5
  "homepage": "https://github.com/stromseng/effective-progress#readme",
6
6
  "bugs": {
@@ -27,9 +27,6 @@
27
27
  "default": "./dist/index.mjs"
28
28
  }
29
29
  },
30
- "engines": {
31
- "node": ">=20.12.0"
32
- },
33
30
  "publishConfig": {
34
31
  "access": "public"
35
32
  },
@@ -43,9 +40,9 @@
43
40
  "format:check": "oxfmt --check ."
44
41
  },
45
42
  "dependencies": {
43
+ "fast-string-width": "^3.0.2",
46
44
  "ink": "^6.8.0",
47
- "react": "^19.2.4",
48
- "string-width": "^8.2.0"
45
+ "react": "^19.2.4"
49
46
  },
50
47
  "devDependencies": {
51
48
  "@effect/language-service": "^0.73.1",
@@ -59,5 +56,8 @@
59
56
  },
60
57
  "peerDependencies": {
61
58
  "effect": "^3.19.17"
59
+ },
60
+ "engines": {
61
+ "node": ">=20.12.0"
62
62
  }
63
63
  }