devsess 0.1.0 → 0.2.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 CHANGED
@@ -7,12 +7,13 @@ Scaffold dev scripts with reusable **dev sessions** and a per-session **PGlite +
7
7
  - **Dev sessions** — each run reuses (or creates) a named, slug-based working directory under `.data/sessions`. Sticky dev-server ports, managed subprocesses that die with your script, and cross-service "running" signal files come built in.
8
8
  - **A PGlite adapter** (`devsess/pglite`) — prepare a local Postgres-compatible database from your Drizzle migrations, scoped to the current dev session. Perfect for a `--lite` offline dev mode.
9
9
 
10
- It targets **Node** (`@effect/platform-node`). The examples below use the [Effect](https://effect.website) API (`devsess`); if you'd rather not deal with Effect directly, `devsess/async` exposes the same dev-session scaffolding as a plain, Promise-based API — see [API](#api).
10
+ It runs on **Node or Bun** — devsess depends on neither directly, you supply whichever platform package's layer you use (`NodeServices.layer`/`BunServices.layer`, or the equivalent `platform` object for `devsess/async`). The examples below use the [Effect](https://effect.website) API (`devsess`); if you'd rather not deal with Effect directly, `devsess/async` exposes the same dev-session scaffolding as a plain, Promise-based API — see [API](#api).
11
11
 
12
12
  ## Install
13
13
 
14
14
  ```bash
15
15
  bun add devsess effect @effect/platform-node
16
+ # or, on Bun: bun add devsess effect @effect/platform-bun
16
17
  ```
17
18
 
18
19
  For the PGlite adapter (`devsess/pglite`), also add:
@@ -25,24 +26,24 @@ bun add @electric-sql/pglite drizzle-orm
25
26
 
26
27
  ```ts
27
28
  // scripts/dev.ts
28
- import { join } from 'node:path';
29
- import { cli, defineDevCli } from 'devsess';
29
+ import { CurrentSession, DevSessions, getStickyPort, runManagedSubprocess } from 'devsess';
30
+ import { NodeRuntime, NodeServices } from '@effect/platform-node';
30
31
  import { Effect } from 'effect';
32
+ import { Command, Flag } from 'effect/unstable/cli';
31
33
 
32
- const main = defineDevCli({
33
- name: 'web',
34
- dir: join(import.meta.dirname, '..'),
35
- options: {
36
- lite: cli.Flag.boolean('lite').pipe(
37
- cli.Flag.withDescription('Use a per-session PGlite database'),
34
+ const web = Command.make(
35
+ 'web',
36
+ {
37
+ lite: Flag.boolean('lite').pipe(
38
+ Flag.withDescription('Use a per-session PGlite database'),
38
39
  ),
39
40
  },
40
- run: (ctx, opts) =>
41
+ (opts) =>
41
42
  Effect.gen(function* () {
42
- const session = yield* ctx.session;
43
+ const session = yield* CurrentSession;
43
44
  yield* Effect.logInfo(`[dev] session: ${session.name}`);
44
45
 
45
- const port = yield* ctx.getStickyPort();
46
+ const port = yield* getStickyPort(session);
46
47
  const env: Record<string, string> = { PORT: String(port) };
47
48
 
48
49
  if (opts.lite) {
@@ -51,29 +52,38 @@ const main = defineDevCli({
51
52
  env.DATABASE_LITE_PATH = litePath;
52
53
  }
53
54
 
54
- yield* ctx.runManagedSubprocess('bunx', ['vite'], { env });
55
- }),
56
- });
55
+ yield* runManagedSubprocess('bunx', ['vite'], { env });
56
+ }).pipe(Effect.provide(CurrentSession.layer)),
57
+ );
57
58
 
58
- main(process.argv);
59
+ Command.run(web, { version: '0.1.0' }).pipe(
60
+ Effect.provide(DevSessions.layer),
61
+ Effect.provide(NodeServices.layer),
62
+ Effect.scoped,
63
+ NodeRuntime.runMain,
64
+ );
59
65
  ```
60
66
 
61
67
  ```bash
62
68
  bun scripts/dev.ts --lite
63
69
  ```
64
70
 
71
+ `DevSessions.layer` auto-detects your project root (the nearest ancestor with a `package.json`) — no `dir` to pass. `CurrentSession.layer` sits on the handler, not around `Command.run`, so a `--help`/`--version` invocation never resolves (or creates) a session.
72
+
65
73
  ## Per-session PGlite
66
74
 
67
75
  `prepareSessionPglite` builds a migration dump (if missing), hydrates a PGlite
68
76
  client, validates and applies migrations — all scoped to the active dev session:
69
77
 
70
78
  ```ts
79
+ import { DevSessions, CurrentSession } from 'devsess';
71
80
  import { prepareSessionPglite } from 'devsess/pglite';
72
81
 
73
- // inside run():
74
- const session = yield* ctx.session;
82
+ // inside a handler, with CurrentSession.layer provided:
83
+ const sessions = yield* DevSessions;
84
+ const session = yield* CurrentSession;
75
85
  const db = yield* prepareSessionPglite(session, {
76
- migrationsFolder: join(import.meta.dirname, '../drizzle'),
86
+ migrationsFolder: sessions.path('drizzle'),
77
87
  });
78
88
  // db.client — a ready PGlite client
79
89
  // db.dataDir — its on-disk path (e.g. pass as DATABASE_LITE_PATH)
@@ -83,11 +93,14 @@ const db = yield* prepareSessionPglite(session, {
83
93
 
84
94
  From `devsess` (the Effect API):
85
95
 
86
- - `defineDevCli({ name, dir, options?, run })` → `(argv) => void`
87
- - `cli` — re-export of `effect/unstable/cli`
88
- - `DevSessions`, `makeDevSessionsLayer(rootDir)`, `DevSession`
96
+ - `DevSessions` — session-store service. `.layer` auto-detects the project root; `.layerAt(rootDir)` overrides it
97
+ - `CurrentSession` — resolved-session service for the current run. `.layer` resolves via `DevSessions`; `.layerOf(session)` pins one
98
+ - `ProjectRootNotFoundError` — raised by `DevSessions.layer` when no ancestor of `process.cwd()` has a `package.json`
99
+ - `getStickyPort(session)`, `runManagedSubprocess(cmd, args, opts?)`, `publishRunning(data)`, `awaitRunning(pkg)` — free functions; only `getStickyPort` takes a `DevSession`
89
100
  - `SessionState.slot(schema)` — typed per-session JSON state
90
101
 
102
+ Build your CLI with a stock `Command.make(...)` from `effect/unstable/cli` — devsess no longer wraps it.
103
+
91
104
  From `devsess/pglite`:
92
105
 
93
106
  - `prepareSessionPglite(session, { migrationsFolder })`
@@ -98,8 +111,8 @@ From `devsess/pglite`:
98
111
 
99
112
  From `devsess/async` (a plain, Promise-based mirror of the Effect API — no `effect` imports required):
100
113
 
101
- - `defineDevCli({ name, dir, options?, run })` — `run` is `async (ctx, opts) => void`, and `ctx`'s helpers return Promises instead of Effects
102
- - `createDevSessions(rootDir)` — async session manager (`getSessions`, `createSession`, `getLatestOrCreate`)
114
+ - `defineDevCli({ name, dir, platform, options?, run })` — `run` is `async (ctx, opts) => void`, and `ctx`'s helpers return Promises instead of Effects
115
+ - `createDevSessions(rootDir, services)` — async session manager (`getSessions`, `createSession`, `getLatestOrCreate`)
103
116
  - `SessionState`, `DevSession`, plus `cli` and `Schema` re-exports
104
117
 
105
118
  See the [full documentation](https://github.com/fdarian/devsess/tree/main/apps/docs) for details.
@@ -1,8 +1,9 @@
1
1
  import { Effect } from 'effect';
2
- import { type CommandConfig } from '../dev/run-dev-cli';
3
2
  import { runManagedSubprocess } from '../dev/subprocess';
3
+ import type { DevPlatform } from './platform';
4
+ import { type CommandConfig } from './run-dev-cli';
4
5
  import { type DevSession } from './session';
5
- /** Promise-returning mirror of the Effect core's `RunContext` (see `src/dev/define-cli.ts`). */
6
+ /** Promise-returning mirror of the Effect core's free functions (`getStickyPort`, `runManagedSubprocess`, `publishRunning`, `awaitRunning`), bundled into a single per-run context. */
6
7
  type AsyncRunContext = {
7
8
  session: () => Promise<DevSession>;
8
9
  getStickyPort: () => Promise<number>;
@@ -14,6 +15,7 @@ export declare const defineDevCli: (config: {
14
15
  name: string;
15
16
  dir: string;
16
17
  options?: CommandConfig;
18
+ platform: DevPlatform;
17
19
  run: (ctx: AsyncRunContext, opts: Record<string, unknown>) => Promise<void> | void;
18
20
  }) => ((argv: string[]) => void);
19
21
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"define-cli.d.ts","sourceRoot":"","sources":["../../src/async/define-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,QAAQ,CAAC;AAI5C,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,oBAAoB,CAAC;AAQnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,KAAK,UAAU,EAAkB,MAAM,WAAW,CAAC;AAE5D,gGAAgG;AAChG,KAAK,eAAe,GAAG;IACtB,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,oBAAoB,EAAE,CACrB,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,KAC5C,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACtE,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7C,CAAC;AAEF,eAAO,MAAM,YAAY,WAAY;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,EAAE,CACJ,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1B,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CA4C1B,CAAC"}
1
+ {"version":3,"file":"define-cli.d.ts","sourceRoot":"","sources":["../../src/async/define-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAc,MAAM,QAAQ,CAAC;AAW5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,KAAK,UAAU,EAAkB,MAAM,WAAW,CAAC;AAE5D,uLAAuL;AACvL,KAAK,eAAe,GAAG;IACtB,OAAO,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,oBAAoB,EAAE,CACrB,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,KAC5C,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC;IACtE,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7C,CAAC;AAEF,eAAO,MAAM,YAAY,WAAY;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,GAAG,EAAE,CACJ,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1B,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CA6C1B,CAAC"}
@@ -1,3 +1,5 @@
1
+ import { Layer } from 'effect';
2
+ import type { DevServices } from './platform';
1
3
  import { type DevSession } from './session';
2
4
  export type DevSessionManager = {
3
5
  readonly dir: string;
@@ -6,11 +8,14 @@ export type DevSessionManager = {
6
8
  getLatestOrCreate(): Promise<DevSession>;
7
9
  };
8
10
  /**
9
- * Creates a manager for slug-named dev session directories under `rootDir`.
11
+ * Creates a manager for slug-named dev session directories under
12
+ * `<rootDir>/.data/sessions`, using the caller-supplied platform `services` layer
13
+ * (e.g. `NodeServices.layer`). Same `rootDir` convention as `DevSessions.layerAt` — the
14
+ * CLI facade and this one agree on where sessions live given the same root.
10
15
  *
11
- * `makeDevSessionsLayer` only wires lazy service methods when built (no directory
12
- * IO happens at build time — see `src/dev-sessions.ts`), so it's cheap to re-provide
13
- * the same `layer` value on every call rather than resolving a shared runtime once.
16
+ * `DevSessions.layerAt` only wires lazy service methods when built (no directory IO
17
+ * happens at build time — see `src/dev-sessions.ts`), so it's cheap to re-provide the
18
+ * same `layer` value on every call rather than resolving a shared runtime once.
14
19
  */
15
- export declare const createDevSessions: (rootDir: string) => DevSessionManager;
20
+ export declare const createDevSessions: (rootDir: string, services: Layer.Layer<DevServices>) => DevSessionManager;
16
21
  //# sourceMappingURL=dev-sessions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dev-sessions.d.ts","sourceRoot":"","sources":["../../src/async/dev-sessions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAkB,MAAM,WAAW,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1C,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,iBAAiB,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,YAAa,MAAM,KAAG,iBAwBnD,CAAC"}
1
+ {"version":3,"file":"dev-sessions.d.ts","sourceRoot":"","sources":["../../src/async/dev-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,KAAK,UAAU,EAAkB,MAAM,WAAW,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC;IAC1C,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,iBAAiB,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,YACpB,MAAM,YACL,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,KAChC,iBAsBF,CAAC"}
@@ -3,6 +3,7 @@ export * as cli from 'effect/unstable/cli';
3
3
  export { SessionStateError } from '../dev/session-state';
4
4
  export { defineDevCli } from './define-cli';
5
5
  export { createDevSessions, type DevSessionManager } from './dev-sessions';
6
+ export type { DevPlatform, DevServices } from './platform';
6
7
  export type { DevSession } from './session';
7
8
  export { SessionState } from './session-state';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/async/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/async/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC3E,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -4,30 +4,48 @@ import {
4
4
  SessionStateError,
5
5
  awaitRunningSignal,
6
6
  getStickyPort,
7
- makeDevSessionsLayer,
8
7
  publishRunningSignal,
9
8
  resolveSiblingDir,
10
- runDevCli,
11
9
  runManagedSubprocess,
12
10
  runningSignalPath
13
- } from "../chunk-IEQZ3AJH.js";
11
+ } from "../chunk-AQGYVNYU.js";
14
12
 
15
13
  // src/async/index.ts
16
14
  import { Schema } from "effect";
17
- import * as cli from "effect/unstable/cli";
15
+ import * as cli2 from "effect/unstable/cli";
18
16
 
19
17
  // src/async/define-cli.ts
20
- import { Effect as Effect2 } from "effect";
18
+ import { Effect as Effect3 } from "effect";
19
+
20
+ // src/async/run-dev-cli.ts
21
+ import { Effect, Layer } from "effect";
22
+ import * as cli from "effect/unstable/cli";
23
+ var runDevCli = (config) => {
24
+ const command = cli.Command.make(
25
+ config.name,
26
+ config.options ?? {},
27
+ (opts) => config.makeHandler(opts)
28
+ );
29
+ return (argv) => {
30
+ const layer = DevSessions.layerAt(config.dir).pipe(
31
+ Layer.provideMerge(config.platform.services)
32
+ );
33
+ const program = cli.Command.runWith(command, {
34
+ version: "0.0.0"
35
+ })(argv);
36
+ config.platform.runMain(Effect.scoped(Effect.provide(program, layer)));
37
+ };
38
+ };
21
39
 
22
40
  // src/async/session.ts
23
- import { Effect } from "effect";
41
+ import { Effect as Effect2 } from "effect";
24
42
  var EFFECT_SESSION = /* @__PURE__ */ Symbol("devsess/async/DevSession#effectSession");
25
43
  var toAsyncSession = (session) => {
26
44
  const asyncSession = {
27
45
  name: session.name,
28
46
  lastModifiedAt: session.lastModifiedAt,
29
47
  // Safe to run synchronously: the core `path` is `Effect.succeed(pathJoin(rel))`, pure.
30
- path: (relativePath) => Effect.runSync(session.path(relativePath)),
48
+ path: (relativePath) => Effect2.runSync(session.path(relativePath)),
31
49
  toString: () => session.toString()
32
50
  };
33
51
  Object.defineProperty(asyncSession, EFFECT_SESSION, {
@@ -51,67 +69,63 @@ var defineDevCli = (config) => runDevCli({
51
69
  name: config.name,
52
70
  dir: config.dir,
53
71
  options: config.options,
54
- makeHandler: (opts) => Effect2.gen(function* () {
72
+ platform: config.platform,
73
+ makeHandler: (opts) => Effect3.gen(function* () {
55
74
  const sessions = yield* DevSessions;
56
- const session = yield* Effect2.cached(sessions.getLatestOrCreate);
57
- const services = yield* Effect2.context();
75
+ const session = yield* Effect3.cached(sessions.getLatestOrCreate);
76
+ const services = yield* Effect3.context();
58
77
  const ctx = {
59
- session: () => Effect2.runPromiseWith(services)(session).then(toAsyncSession),
60
- getStickyPort: () => Effect2.runPromiseWith(services)(
61
- Effect2.flatMap(session, getStickyPort)
78
+ session: () => Effect3.runPromiseWith(services)(session).then(toAsyncSession),
79
+ getStickyPort: () => Effect3.runPromiseWith(services)(
80
+ Effect3.flatMap(session, getStickyPort)
62
81
  ),
63
- runManagedSubprocess: (...args) => Effect2.runPromiseWith(services)(runManagedSubprocess(...args)),
64
- publishRunning: (data) => Effect2.runPromiseWith(services)(
82
+ runManagedSubprocess: (...args) => Effect3.runPromiseWith(services)(runManagedSubprocess(...args)),
83
+ publishRunning: (data) => Effect3.runPromiseWith(services)(
65
84
  publishRunningSignal(runningSignalPath(config.dir), data)
66
85
  ),
67
- awaitRunning: (pkg) => Effect2.runPromiseWith(services)(
86
+ awaitRunning: (pkg) => Effect3.runPromiseWith(services)(
68
87
  awaitRunningSignal(
69
88
  runningSignalPath(resolveSiblingDir(pkg, config.dir)),
70
89
  { parse: (raw) => JSON.parse(raw) }
71
90
  )
72
91
  )
73
92
  };
74
- yield* Effect2.promise(() => Promise.resolve(config.run(ctx, opts)));
93
+ yield* Effect3.promise(() => Promise.resolve(config.run(ctx, opts)));
75
94
  })
76
95
  });
77
96
 
78
97
  // src/async/dev-sessions.ts
79
- import { NodeServices } from "@effect/platform-node";
80
- import { Effect as Effect3, Layer } from "effect";
81
- var createDevSessions = (rootDir) => {
82
- const layer = makeDevSessionsLayer(rootDir).pipe(
83
- Layer.provide(NodeServices.layer)
84
- );
85
- const run = (effect) => Effect3.runPromise(Effect3.provide(effect, layer));
98
+ import { Effect as Effect4, Layer as Layer2 } from "effect";
99
+ var createDevSessions = (rootDir, services) => {
100
+ const layer = DevSessions.layerAt(rootDir).pipe(Layer2.provide(services));
101
+ const run2 = (effect) => Effect4.runPromise(Effect4.provide(effect, layer));
86
102
  return {
87
103
  // Matches the service's own `dir`, which is `rootDir` verbatim — safe to read synchronously.
88
104
  dir: rootDir,
89
- getSessions: () => run(DevSessions.use((sessions) => sessions.getSessions)).then(
105
+ getSessions: () => run2(DevSessions.use((sessions) => sessions.getSessions)).then(
90
106
  (sessions) => sessions.map(toAsyncSession)
91
107
  ),
92
- createSession: () => run(DevSessions.use((sessions) => sessions.createSession)).then(
108
+ createSession: () => run2(DevSessions.use((sessions) => sessions.createSession)).then(
93
109
  toAsyncSession
94
110
  ),
95
- getLatestOrCreate: () => run(DevSessions.use((sessions) => sessions.getLatestOrCreate)).then(
111
+ getLatestOrCreate: () => run2(DevSessions.use((sessions) => sessions.getLatestOrCreate)).then(
96
112
  toAsyncSession
97
113
  )
98
114
  };
99
115
  };
100
116
 
101
117
  // src/async/run.ts
102
- import { NodeServices as NodeServices2 } from "@effect/platform-node";
103
- import { Effect as Effect4 } from "effect";
104
- var nodeLayer = NodeServices2.layer;
105
- var runNode = (effect) => Effect4.runPromise(Effect4.scoped(Effect4.provide(effect, nodeLayer)));
118
+ import { Effect as Effect5 } from "effect";
119
+ var run = (effect, services) => Effect5.runPromise(Effect5.scoped(Effect5.provide(effect, services)));
106
120
 
107
121
  // src/async/session-state.ts
108
122
  var SessionState2;
109
123
  ((SessionState3) => {
110
- function slot(schema) {
124
+ function slot(schema, services) {
111
125
  const effectSlot = SessionState.slot(schema);
112
126
  return {
113
- read: (session) => runNode(effectSlot.read(unwrapSession(session))),
114
- write: (session, data) => runNode(effectSlot.write(unwrapSession(session), data))
127
+ read: (session) => run(effectSlot.read(unwrapSession(session)), services),
128
+ write: (session, data) => run(effectSlot.write(unwrapSession(session), data), services)
115
129
  };
116
130
  }
117
131
  SessionState3.slot = slot;
@@ -120,7 +134,7 @@ export {
120
134
  Schema,
121
135
  SessionState2 as SessionState,
122
136
  SessionStateError,
123
- cli,
137
+ cli2 as cli,
124
138
  createDevSessions,
125
139
  defineDevCli
126
140
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/async/index.ts","../../src/async/define-cli.ts","../../src/async/session.ts","../../src/async/dev-sessions.ts","../../src/async/run.ts","../../src/async/session-state.ts"],"sourcesContent":["// Re-exported so consumers can declare CLI flags/arguments without a direct\n// dependency on `effect/unstable/cli`, e.g. `cli.Flag.string('local')`.\n\nexport { Schema } from 'effect';\nexport * as cli from 'effect/unstable/cli';\n\nexport { SessionStateError } from '../dev/session-state';\nexport { defineDevCli } from './define-cli';\nexport { createDevSessions, type DevSessionManager } from './dev-sessions';\nexport type { DevSession } from './session';\nexport { SessionState } from './session-state';\n","import { Effect, type Scope } from 'effect';\nimport type { FileSystem } from 'effect/FileSystem';\nimport type { Path } from 'effect/Path';\nimport type { ChildProcessSpawner } from 'effect/unstable/process/ChildProcessSpawner';\nimport { type CommandConfig, runDevCli } from '../dev/run-dev-cli';\nimport {\n\tawaitRunningSignal,\n\tpublishRunningSignal,\n\tresolveSiblingDir,\n\trunningSignalPath,\n} from '../dev/running-signal';\nimport { getStickyPort } from '../dev/sticky-port';\nimport { runManagedSubprocess } from '../dev/subprocess';\nimport { DevSessions } from '../dev-sessions';\nimport { type DevSession, toAsyncSession } from './session';\n\n/** Promise-returning mirror of the Effect core's `RunContext` (see `src/dev/define-cli.ts`). */\ntype AsyncRunContext = {\n\tsession: () => Promise<DevSession>;\n\tgetStickyPort: () => Promise<number>;\n\trunManagedSubprocess: (\n\t\t...args: Parameters<typeof runManagedSubprocess>\n\t) => Promise<Effect.Success<ReturnType<typeof runManagedSubprocess>>>;\n\tpublishRunning: (data: unknown) => Promise<void>;\n\tawaitRunning: <T>(pkg: string) => Promise<T>;\n};\n\nexport const defineDevCli = (config: {\n\tname: string;\n\tdir: string;\n\toptions?: CommandConfig;\n\trun: (\n\t\tctx: AsyncRunContext,\n\t\topts: Record<string, unknown>,\n\t) => Promise<void> | void;\n}): ((argv: string[]) => void) =>\n\trunDevCli({\n\t\tname: config.name,\n\t\tdir: config.dir,\n\t\toptions: config.options,\n\t\tmakeHandler: (opts) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst sessions = yield* DevSessions;\n\t\t\t\tconst session = yield* Effect.cached(sessions.getLatestOrCreate);\n\n\t\t\t\t// Capture the process-lifetime context (the Scope opened by `runDevCli`'s\n\t\t\t\t// outer `Effect.scoped`, plus DevSessions | FileSystem | Path | ChildProcessSpawner).\n\t\t\t\t// Running each ctx helper with this captured context — instead of a fresh,\n\t\t\t\t// transient `Effect.runPromise` per call — attaches its scoped resources\n\t\t\t\t// (managed subprocess, running-signal file) to that process-lifetime scope,\n\t\t\t\t// so they only release when the CLI process ends, not right after the Promise settles.\n\t\t\t\tconst services = yield* Effect.context<\n\t\t\t\t\tDevSessions | FileSystem | Path | ChildProcessSpawner | Scope.Scope\n\t\t\t\t>();\n\n\t\t\t\tconst ctx: AsyncRunContext = {\n\t\t\t\t\tsession: () =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(session).then(toAsyncSession),\n\t\t\t\t\tgetStickyPort: () =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tEffect.flatMap(session, getStickyPort),\n\t\t\t\t\t\t),\n\t\t\t\t\trunManagedSubprocess: (...args) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(runManagedSubprocess(...args)),\n\t\t\t\t\tpublishRunning: (data) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tpublishRunningSignal(runningSignalPath(config.dir), data),\n\t\t\t\t\t\t),\n\t\t\t\t\tawaitRunning: <T>(pkg: string) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tawaitRunningSignal<T>(\n\t\t\t\t\t\t\t\trunningSignalPath(resolveSiblingDir(pkg, config.dir)),\n\t\t\t\t\t\t\t\t{ parse: (raw) => JSON.parse(raw) as T },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t};\n\n\t\t\t\tyield* Effect.promise(() => Promise.resolve(config.run(ctx, opts)));\n\t\t\t}),\n\t});\n","import { Effect } from 'effect';\nimport type { DevSession as EffectDevSession } from '../dev-sessions';\n\n/** Non-enumerable, module-private key used to stash the Effect session on its async wrapper. */\nconst EFFECT_SESSION = Symbol('devsess/async/DevSession#effectSession');\n\nexport type DevSession = {\n\treadonly name: string;\n\treadonly lastModifiedAt: Date | null;\n\tpath(relativePath: string): string;\n\ttoString(): string;\n};\n\n/**\n * Wraps an Effect `DevSession` as a plain-async `DevSession`. The original Effect\n * session is stashed under `EFFECT_SESSION` so other async ops (e.g. `SessionState`)\n * can reuse the Effect core via `unwrapSession`.\n */\nexport const toAsyncSession = (session: EffectDevSession): DevSession => {\n\tconst asyncSession: DevSession = {\n\t\tname: session.name,\n\t\tlastModifiedAt: session.lastModifiedAt,\n\t\t// Safe to run synchronously: the core `path` is `Effect.succeed(pathJoin(rel))`, pure.\n\t\tpath: (relativePath) => Effect.runSync(session.path(relativePath)),\n\t\ttoString: () => session.toString(),\n\t};\n\n\tObject.defineProperty(asyncSession, EFFECT_SESSION, {\n\t\tvalue: session,\n\t\tenumerable: false,\n\t});\n\n\treturn asyncSession;\n};\n\n/** Recovers the Effect `DevSession` stashed by `toAsyncSession`. */\nexport const unwrapSession = (session: DevSession): EffectDevSession => {\n\tconst effectSession = (\n\t\tsession as unknown as Record<\n\t\t\ttypeof EFFECT_SESSION,\n\t\t\tEffectDevSession | undefined\n\t\t>\n\t)[EFFECT_SESSION];\n\tif (effectSession === undefined) {\n\t\tthrow new Error(\n\t\t\t'devsess/async: expected a DevSession created by this package, but the internal Effect session handle is missing',\n\t\t);\n\t}\n\treturn effectSession;\n};\n","import { NodeServices } from '@effect/platform-node';\nimport { Effect, Layer } from 'effect';\nimport { DevSessions, makeDevSessionsLayer } from '../dev-sessions';\nimport { type DevSession, toAsyncSession } from './session';\n\nexport type DevSessionManager = {\n\treadonly dir: string;\n\tgetSessions(): Promise<Array<DevSession>>;\n\tcreateSession(): Promise<DevSession>;\n\tgetLatestOrCreate(): Promise<DevSession>;\n};\n\n/**\n * Creates a manager for slug-named dev session directories under `rootDir`.\n *\n * `makeDevSessionsLayer` only wires lazy service methods when built (no directory\n * IO happens at build time — see `src/dev-sessions.ts`), so it's cheap to re-provide\n * the same `layer` value on every call rather than resolving a shared runtime once.\n */\nexport const createDevSessions = (rootDir: string): DevSessionManager => {\n\tconst layer = makeDevSessionsLayer(rootDir).pipe(\n\t\tLayer.provide(NodeServices.layer),\n\t);\n\n\tconst run = <A, E>(effect: Effect.Effect<A, E, DevSessions>): Promise<A> =>\n\t\tEffect.runPromise(Effect.provide(effect, layer));\n\n\treturn {\n\t\t// Matches the service's own `dir`, which is `rootDir` verbatim — safe to read synchronously.\n\t\tdir: rootDir,\n\t\tgetSessions: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.getSessions)).then(\n\t\t\t\t(sessions) => sessions.map(toAsyncSession),\n\t\t\t),\n\t\tcreateSession: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.createSession)).then(\n\t\t\t\ttoAsyncSession,\n\t\t\t),\n\t\tgetLatestOrCreate: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.getLatestOrCreate)).then(\n\t\t\t\ttoAsyncSession,\n\t\t\t),\n\t};\n};\n","import { NodeServices } from '@effect/platform-node';\nimport { Effect, type Scope } from 'effect';\n\nconst nodeLayer = NodeServices.layer;\n\n/** Runs an Effect that only needs the shared Node platform services (+ an optional Scope) as a Promise. */\nexport const runNode = <A, E>(\n\teffect: Effect.Effect<A, E, NodeServices.NodeServices | Scope.Scope>,\n): Promise<A> =>\n\tEffect.runPromise(Effect.scoped(Effect.provide(effect, nodeLayer)));\n","import type * as S from 'effect/Schema';\nimport { SessionState as EffectSessionState } from '../dev/session-state';\nimport { runNode } from './run';\nimport { type DevSession, unwrapSession } from './session';\n\nexport namespace SessionState {\n\t// Decoding must run without extra context (only `NodeServices | Scope` are\n\t// available via `runNode`), so schemas cannot require decoding services.\n\ttype Shape = S.Codec<unknown, unknown, never>;\n\n\texport function slot<T extends Shape>(schema: T) {\n\t\tconst effectSlot = EffectSessionState.slot(schema);\n\t\treturn {\n\t\t\tread: (session: DevSession): Promise<T['Type'] | null> =>\n\t\t\t\trunNode(effectSlot.read(unwrapSession(session))),\n\t\t\twrite: (session: DevSession, data: T['Type']): Promise<void> =>\n\t\t\t\trunNode(effectSlot.write(unwrapSession(session), data)),\n\t\t};\n\t}\n}\n"],"mappings":"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","names":["Effect","Effect","Effect","Effect","NodeServices","Effect","SessionState"]}
1
+ {"version":3,"sources":["../../src/async/index.ts","../../src/async/define-cli.ts","../../src/async/run-dev-cli.ts","../../src/async/session.ts","../../src/async/dev-sessions.ts","../../src/async/run.ts","../../src/async/session-state.ts"],"sourcesContent":["// Re-exported so consumers can declare CLI flags/arguments without a direct\n// dependency on `effect/unstable/cli`, e.g. `cli.Flag.string('local')`.\n\nexport { Schema } from 'effect';\nexport * as cli from 'effect/unstable/cli';\n\nexport { SessionStateError } from '../dev/session-state';\nexport { defineDevCli } from './define-cli';\nexport { createDevSessions, type DevSessionManager } from './dev-sessions';\nexport type { DevPlatform, DevServices } from './platform';\nexport type { DevSession } from './session';\nexport { SessionState } from './session-state';\n","import { Effect, type Scope } from 'effect';\nimport type { FileSystem } from 'effect/FileSystem';\nimport type { Path } from 'effect/Path';\nimport type { ChildProcessSpawner } from 'effect/unstable/process/ChildProcessSpawner';\nimport {\n\tawaitRunningSignal,\n\tpublishRunningSignal,\n\tresolveSiblingDir,\n\trunningSignalPath,\n} from '../dev/running-signal';\nimport { getStickyPort } from '../dev/sticky-port';\nimport { runManagedSubprocess } from '../dev/subprocess';\nimport { DevSessions } from '../dev-sessions';\nimport type { DevPlatform } from './platform';\nimport { type CommandConfig, runDevCli } from './run-dev-cli';\nimport { type DevSession, toAsyncSession } from './session';\n\n/** Promise-returning mirror of the Effect core's free functions (`getStickyPort`, `runManagedSubprocess`, `publishRunning`, `awaitRunning`), bundled into a single per-run context. */\ntype AsyncRunContext = {\n\tsession: () => Promise<DevSession>;\n\tgetStickyPort: () => Promise<number>;\n\trunManagedSubprocess: (\n\t\t...args: Parameters<typeof runManagedSubprocess>\n\t) => Promise<Effect.Success<ReturnType<typeof runManagedSubprocess>>>;\n\tpublishRunning: (data: unknown) => Promise<void>;\n\tawaitRunning: <T>(pkg: string) => Promise<T>;\n};\n\nexport const defineDevCli = (config: {\n\tname: string;\n\tdir: string;\n\toptions?: CommandConfig;\n\tplatform: DevPlatform;\n\trun: (\n\t\tctx: AsyncRunContext,\n\t\topts: Record<string, unknown>,\n\t) => Promise<void> | void;\n}): ((argv: string[]) => void) =>\n\trunDevCli({\n\t\tname: config.name,\n\t\tdir: config.dir,\n\t\toptions: config.options,\n\t\tplatform: config.platform,\n\t\tmakeHandler: (opts) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst sessions = yield* DevSessions;\n\t\t\t\tconst session = yield* Effect.cached(sessions.getLatestOrCreate);\n\n\t\t\t\t// Capture the process-lifetime context (the Scope opened by `runDevCli`'s\n\t\t\t\t// outer `Effect.scoped`, plus DevSessions | FileSystem | Path | ChildProcessSpawner).\n\t\t\t\t// Running each ctx helper with this captured context — instead of a fresh,\n\t\t\t\t// transient `Effect.runPromise` per call — attaches its scoped resources\n\t\t\t\t// (managed subprocess, running-signal file) to that process-lifetime scope,\n\t\t\t\t// so they only release when the CLI process ends, not right after the Promise settles.\n\t\t\t\tconst services = yield* Effect.context<\n\t\t\t\t\tDevSessions | FileSystem | Path | ChildProcessSpawner | Scope.Scope\n\t\t\t\t>();\n\n\t\t\t\tconst ctx: AsyncRunContext = {\n\t\t\t\t\tsession: () =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(session).then(toAsyncSession),\n\t\t\t\t\tgetStickyPort: () =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tEffect.flatMap(session, getStickyPort),\n\t\t\t\t\t\t),\n\t\t\t\t\trunManagedSubprocess: (...args) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(runManagedSubprocess(...args)),\n\t\t\t\t\tpublishRunning: (data) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tpublishRunningSignal(runningSignalPath(config.dir), data),\n\t\t\t\t\t\t),\n\t\t\t\t\tawaitRunning: <T>(pkg: string) =>\n\t\t\t\t\t\tEffect.runPromiseWith(services)(\n\t\t\t\t\t\t\tawaitRunningSignal<T>(\n\t\t\t\t\t\t\t\trunningSignalPath(resolveSiblingDir(pkg, config.dir)),\n\t\t\t\t\t\t\t\t{ parse: (raw) => JSON.parse(raw) as T },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t};\n\n\t\t\t\tyield* Effect.promise(() => Promise.resolve(config.run(ctx, opts)));\n\t\t\t}),\n\t});\n","import { Effect, Layer, type Scope } from 'effect';\nimport * as cli from 'effect/unstable/cli';\nimport { DevSessions } from '../dev-sessions';\nimport type { DevPlatform, DevServices } from './platform';\n\nexport type CommandConfig = typeof cli.Command.make extends (\n\tname: string,\n\tconfig: infer C,\n\t...rest: Array<unknown>\n) => unknown\n\t? C\n\t: never;\n\ntype CliHandler = (\n\topts: Record<string, unknown>,\n) => Effect.Effect<void, unknown, DevSessions | DevServices | Scope.Scope>;\n\n/**\n * CLI scaffolding for the plain-async `defineDevCli` facade (`src/async/define-cli.ts`):\n * builds the `cli.Command`, wires the per-project `DevSessions` + caller-supplied\n * platform services layer, and runs it via `platform.runMain`.\n */\nexport const runDevCli = (config: {\n\tname: string;\n\tdir: string;\n\toptions?: CommandConfig;\n\tplatform: DevPlatform;\n\tmakeHandler: CliHandler;\n}): ((argv: string[]) => void) => {\n\tconst command = cli.Command.make(config.name, config.options ?? {}, (opts) =>\n\t\tconfig.makeHandler(opts as Record<string, unknown>),\n\t);\n\n\treturn (argv) => {\n\t\tconst layer = DevSessions.layerAt(config.dir).pipe(\n\t\t\tLayer.provideMerge(config.platform.services),\n\t\t);\n\n\t\tconst program = cli.Command.runWith(command, {\n\t\t\tversion: '0.0.0',\n\t\t})(argv);\n\n\t\tconfig.platform.runMain(Effect.scoped(Effect.provide(program, layer)));\n\t};\n};\n","import { Effect } from 'effect';\nimport type { DevSession as EffectDevSession } from '../dev-sessions';\n\n/** Non-enumerable, module-private key used to stash the Effect session on its async wrapper. */\nconst EFFECT_SESSION = Symbol('devsess/async/DevSession#effectSession');\n\nexport type DevSession = {\n\treadonly name: string;\n\treadonly lastModifiedAt: Date | null;\n\tpath(relativePath: string): string;\n\ttoString(): string;\n};\n\n/**\n * Wraps an Effect `DevSession` as a plain-async `DevSession`. The original Effect\n * session is stashed under `EFFECT_SESSION` so other async ops (e.g. `SessionState`)\n * can reuse the Effect core via `unwrapSession`.\n */\nexport const toAsyncSession = (session: EffectDevSession): DevSession => {\n\tconst asyncSession: DevSession = {\n\t\tname: session.name,\n\t\tlastModifiedAt: session.lastModifiedAt,\n\t\t// Safe to run synchronously: the core `path` is `Effect.succeed(pathJoin(rel))`, pure.\n\t\tpath: (relativePath) => Effect.runSync(session.path(relativePath)),\n\t\ttoString: () => session.toString(),\n\t};\n\n\tObject.defineProperty(asyncSession, EFFECT_SESSION, {\n\t\tvalue: session,\n\t\tenumerable: false,\n\t});\n\n\treturn asyncSession;\n};\n\n/** Recovers the Effect `DevSession` stashed by `toAsyncSession`. */\nexport const unwrapSession = (session: DevSession): EffectDevSession => {\n\tconst effectSession = (\n\t\tsession as unknown as Record<\n\t\t\ttypeof EFFECT_SESSION,\n\t\t\tEffectDevSession | undefined\n\t\t>\n\t)[EFFECT_SESSION];\n\tif (effectSession === undefined) {\n\t\tthrow new Error(\n\t\t\t'devsess/async: expected a DevSession created by this package, but the internal Effect session handle is missing',\n\t\t);\n\t}\n\treturn effectSession;\n};\n","import { Effect, Layer } from 'effect';\nimport { DevSessions } from '../dev-sessions';\nimport type { DevServices } from './platform';\nimport { type DevSession, toAsyncSession } from './session';\n\nexport type DevSessionManager = {\n\treadonly dir: string;\n\tgetSessions(): Promise<Array<DevSession>>;\n\tcreateSession(): Promise<DevSession>;\n\tgetLatestOrCreate(): Promise<DevSession>;\n};\n\n/**\n * Creates a manager for slug-named dev session directories under\n * `<rootDir>/.data/sessions`, using the caller-supplied platform `services` layer\n * (e.g. `NodeServices.layer`). Same `rootDir` convention as `DevSessions.layerAt` — the\n * CLI facade and this one agree on where sessions live given the same root.\n *\n * `DevSessions.layerAt` only wires lazy service methods when built (no directory IO\n * happens at build time — see `src/dev-sessions.ts`), so it's cheap to re-provide the\n * same `layer` value on every call rather than resolving a shared runtime once.\n */\nexport const createDevSessions = (\n\trootDir: string,\n\tservices: Layer.Layer<DevServices>,\n): DevSessionManager => {\n\tconst layer = DevSessions.layerAt(rootDir).pipe(Layer.provide(services));\n\n\tconst run = <A, E>(effect: Effect.Effect<A, E, DevSessions>): Promise<A> =>\n\t\tEffect.runPromise(Effect.provide(effect, layer));\n\n\treturn {\n\t\t// Matches the service's own `dir`, which is `rootDir` verbatim — safe to read synchronously.\n\t\tdir: rootDir,\n\t\tgetSessions: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.getSessions)).then(\n\t\t\t\t(sessions) => sessions.map(toAsyncSession),\n\t\t\t),\n\t\tcreateSession: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.createSession)).then(\n\t\t\t\ttoAsyncSession,\n\t\t\t),\n\t\tgetLatestOrCreate: () =>\n\t\t\trun(DevSessions.use((sessions) => sessions.getLatestOrCreate)).then(\n\t\t\t\ttoAsyncSession,\n\t\t\t),\n\t};\n};\n","import { Effect, type Layer, type Scope } from 'effect';\nimport type { DevServices } from './platform';\n\n/** Runs an Effect that only needs the caller-supplied platform services (+ an optional Scope) as a Promise. */\nexport const run = <A, E>(\n\teffect: Effect.Effect<A, E, DevServices | Scope.Scope>,\n\tservices: Layer.Layer<DevServices>,\n): Promise<A> =>\n\tEffect.runPromise(Effect.scoped(Effect.provide(effect, services)));\n","import type { Layer } from 'effect';\nimport type * as S from 'effect/Schema';\nimport { SessionState as EffectSessionState } from '../dev/session-state';\nimport type { DevServices } from './platform';\nimport { run } from './run';\nimport { type DevSession, unwrapSession } from './session';\n\nexport namespace SessionState {\n\t// Decoding must run without extra context beyond the platform `services` layer, so\n\t// schemas cannot require decoding services of their own.\n\ttype Shape = S.Codec<unknown, unknown, never>;\n\n\texport function slot<T extends Shape>(\n\t\tschema: T,\n\t\tservices: Layer.Layer<DevServices>,\n\t) {\n\t\tconst effectSlot = EffectSessionState.slot(schema);\n\t\treturn {\n\t\t\tread: (session: DevSession): Promise<T['Type'] | null> =>\n\t\t\t\trun(effectSlot.read(unwrapSession(session)), services),\n\t\t\twrite: (session: DevSession, data: T['Type']): Promise<void> =>\n\t\t\t\trun(effectSlot.write(unwrapSession(session), data), services),\n\t\t};\n\t}\n}\n"],"mappings":"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","names":["cli","Effect","Effect","Effect","Effect","Layer","Layer","run","Effect","Effect","SessionState"]}
@@ -0,0 +1,41 @@
1
+ import type { Effect, Layer } from 'effect';
2
+ import type { FileSystem } from 'effect/FileSystem';
3
+ import type { Path } from 'effect/Path';
4
+ import type * as Runtime from 'effect/Runtime';
5
+ import type { Stdio } from 'effect/Stdio';
6
+ import type { Terminal } from 'effect/Terminal';
7
+ import type { ChildProcessSpawner } from 'effect/unstable/process/ChildProcessSpawner';
8
+ /**
9
+ * Core `effect` service tags this library needs from the caller-supplied platform.
10
+ * `effect/unstable/cli`'s `Command.runWith` pulls in `Stdio`/`Terminal` alongside the
11
+ * `FileSystem`/`Path`/`ChildProcessSpawner` the library's own code depends on directly.
12
+ *
13
+ * Both `@effect/platform-node`'s `NodeServices.NodeServices` and `@effect/platform-bun`'s
14
+ * `BunServices.BunServices` are unions of these same core tags (plus `Crypto`, which this
15
+ * library never uses), so either `.layer` satisfies this narrower requirement.
16
+ */
17
+ export type DevServices = ChildProcessSpawner | FileSystem | Path | Stdio | Terminal;
18
+ type RunMainOptions = {
19
+ readonly disableErrorReporting?: boolean | undefined;
20
+ readonly teardown?: Runtime.Teardown | undefined;
21
+ };
22
+ /**
23
+ * Structurally identical to `NodeRuntime.runMain` and `BunRuntime.runMain` (both are the
24
+ * same function, re-exported from `@effect/platform-node-shared`), so either is assignable
25
+ * here with no cast.
26
+ */
27
+ type RunMain = {
28
+ (options?: RunMainOptions): <E, A>(effect: Effect.Effect<A, E>) => void;
29
+ <E, A>(effect: Effect.Effect<A, E>, options?: RunMainOptions): void;
30
+ };
31
+ /**
32
+ * The platform a caller supplies so the library depends on no platform package of its
33
+ * own, e.g. `{ services: NodeServices.layer, runMain: NodeRuntime.runMain }` or the `Bun`
34
+ * equivalents.
35
+ */
36
+ export type DevPlatform = {
37
+ readonly services: Layer.Layer<DevServices>;
38
+ readonly runMain: RunMain;
39
+ };
40
+ export {};
41
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/async/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAEvF;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GACpB,mBAAmB,GACnB,UAAU,GACV,IAAI,GACJ,KAAK,GACL,QAAQ,CAAC;AAEZ,KAAK,cAAc,GAAG;IACrB,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;CACjD,CAAC;AAEF;;;;GAIG;AACH,KAAK,OAAO,GAAG;IACd,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;IACxE,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACpE,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { Effect, type Scope } from 'effect';
2
+ import * as cli from 'effect/unstable/cli';
3
+ import { DevSessions } from '../dev-sessions';
4
+ import type { DevPlatform, DevServices } from './platform';
5
+ export type CommandConfig = typeof cli.Command.make extends (name: string, config: infer C, ...rest: Array<unknown>) => unknown ? C : never;
6
+ type CliHandler = (opts: Record<string, unknown>) => Effect.Effect<void, unknown, DevSessions | DevServices | Scope.Scope>;
7
+ /**
8
+ * CLI scaffolding for the plain-async `defineDevCli` facade (`src/async/define-cli.ts`):
9
+ * builds the `cli.Command`, wires the per-project `DevSessions` + caller-supplied
10
+ * platform services layer, and runs it via `platform.runMain`.
11
+ */
12
+ export declare const runDevCli: (config: {
13
+ name: string;
14
+ dir: string;
15
+ options?: CommandConfig;
16
+ platform: DevPlatform;
17
+ makeHandler: CliHandler;
18
+ }) => ((argv: string[]) => void);
19
+ export {};
20
+ //# sourceMappingURL=run-dev-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-dev-cli.d.ts","sourceRoot":"","sources":["../../src/async/run-dev-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAS,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAC3D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,EACf,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KACnB,OAAO,GACT,CAAC,GACD,KAAK,CAAC;AAET,KAAK,UAAU,GAAG,CACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;AAE3E;;;;GAIG;AACH,eAAO,MAAM,SAAS,WAAY;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,WAAW,EAAE,UAAU,CAAC;CACxB,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAgB5B,CAAC"}
@@ -1,5 +1,5 @@
1
- import { NodeServices } from '@effect/platform-node';
2
- import { Effect, type Scope } from 'effect';
3
- /** Runs an Effect that only needs the shared Node platform services (+ an optional Scope) as a Promise. */
4
- export declare const runNode: <A, E>(effect: Effect.Effect<A, E, NodeServices.NodeServices | Scope.Scope>) => Promise<A>;
1
+ import { Effect, type Layer, type Scope } from 'effect';
2
+ import type { DevServices } from './platform';
3
+ /** Runs an Effect that only needs the caller-supplied platform services (+ an optional Scope) as a Promise. */
4
+ export declare const run: <A, E>(effect: Effect.Effect<A, E, DevServices | Scope.Scope>, services: Layer.Layer<DevServices>) => Promise<A>;
5
5
  //# sourceMappingURL=run.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/async/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAI5C,2GAA2G;AAC3G,eAAO,MAAM,OAAO,GAAI,CAAC,EAAE,CAAC,UACnB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,KAClE,OAAO,CAAC,CAAC,CACwD,CAAC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/async/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,+GAA+G;AAC/G,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC,UACf,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,YAC5C,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,KAChC,OAAO,CAAC,CAAC,CACuD,CAAC"}
@@ -1,8 +1,10 @@
1
+ import type { Layer } from 'effect';
1
2
  import type * as S from 'effect/Schema';
3
+ import type { DevServices } from './platform';
2
4
  import { type DevSession } from './session';
3
5
  export declare namespace SessionState {
4
6
  type Shape = S.Codec<unknown, unknown, never>;
5
- export function slot<T extends Shape>(schema: T): {
7
+ export function slot<T extends Shape>(schema: T, services: Layer.Layer<DevServices>): {
6
8
  read: (session: DevSession) => Promise<T['Type'] | null>;
7
9
  write: (session: DevSession, data: T['Type']) => Promise<void>;
8
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../src/async/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,CAAC,MAAM,eAAe,CAAC;AAGxC,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,WAAW,CAAC;AAE3D,yBAAiB,YAAY,CAAC;IAG7B,KAAK,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAE9C,MAAM,UAAU,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,MAAM,EAAE,CAAC;QAG7C,IAAI,YAAY,UAAU,KAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;QAEtD,KAAK,YAAY,UAAU,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC;MAG7D;;CACD"}
1
+ {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../src/async/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,KAAK,CAAC,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,WAAW,CAAC;AAE3D,yBAAiB,YAAY,CAAC;IAG7B,KAAK,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAE9C,MAAM,UAAU,IAAI,CAAC,CAAC,SAAS,KAAK,EACnC,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;QAIjC,IAAI,YAAY,UAAU,KAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;QAEtD,KAAK,YAAY,UAAU,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC;MAG7D;;CACD"}