inspeffct 1.0.3 → 1.0.5

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.
Files changed (2) hide show
  1. package/dist/bin.js +388 -210
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import * as NodeRuntime from '@effect/platform-node/NodeRuntime';
3
3
  import * as NodeServices from '@effect/platform-node/NodeServices';
4
- import * as Effect8 from 'effect/Effect';
5
- import * as Command5 from 'effect/unstable/cli/Command';
6
- import * as Argument2 from 'effect/unstable/cli/Argument';
7
- import * as Context3 from 'effect/Context';
4
+ import * as Effect10 from 'effect/Effect';
5
+ import * as Command6 from 'effect/unstable/cli/Command';
6
+ import * as Argument3 from 'effect/unstable/cli/Argument';
7
+ import * as Context4 from 'effect/Context';
8
8
  import * as Fiber from 'effect/Fiber';
9
9
  import * as FileSystem from 'effect/FileSystem';
10
- import * as Layer7 from 'effect/Layer';
10
+ import * as Layer8 from 'effect/Layer';
11
11
  import * as Schema from 'effect/Schema';
12
12
  import * as Stream from 'effect/Stream';
13
13
  import * as Formatter from 'effect/Formatter';
@@ -20,10 +20,11 @@ import * as Queue2 from 'effect/Queue';
20
20
  import * as Socket from 'effect/unstable/socket/Socket';
21
21
  import * as Chunk from 'effect/Chunk';
22
22
  import * as Ref from 'effect/Ref';
23
+ import * as Random from 'effect/Random';
23
24
  import * as SqliteClient from '@effect/sql-sqlite-node/SqliteClient';
24
25
  import * as Struct5 from 'effect/Struct';
25
26
  import * as Migrator from 'effect/unstable/sql/Migrator';
26
- import * as SqlClient3 from 'effect/unstable/sql/SqlClient';
27
+ import * as SqlClient5 from 'effect/unstable/sql/SqlClient';
27
28
  import * as SqlSchema from 'effect/unstable/sql/SqlSchema';
28
29
  import * as SchemaGetter from 'effect/SchemaGetter';
29
30
  import { flow } from 'effect/Function';
@@ -35,9 +36,9 @@ import * as crypto from 'crypto';
35
36
  import * as fs from 'fs';
36
37
  import * as os from 'os';
37
38
  import * as path from 'path';
39
+ import * as Console2 from 'effect/Console';
38
40
  import * as Option3 from 'effect/Option';
39
41
  import * as ChildProcess from 'effect/unstable/process/ChildProcess';
40
- import * as Console from 'effect/Console';
41
42
  import * as Duration from 'effect/Duration';
42
43
  import * as Graph from 'effect/Graph';
43
44
 
@@ -195,17 +196,17 @@ Schema.toCodecJson(
195
196
  CaptureCurrentFibersRequest
196
197
  ]).annotate({ identifier: "InMessage" })
197
198
  );
198
- var BootloaderPath = class extends Context3.Service()("inspeffct/BootloaderPath") {
199
+ var BootloaderPath = class extends Context4.Service()("inspeffct/BootloaderPath") {
199
200
  };
200
- var getPath = Effect8.map(BootloaderPath, (service) => service.path);
201
- var computeBootloaderPath = Effect8.gen(function* () {
201
+ var getPath = Effect10.map(BootloaderPath, (service) => service.path);
202
+ var computeBootloaderPath = Effect10.gen(function* () {
202
203
  const path2 = yield* Path.Path;
203
204
  const binDir = path2.dirname(import.meta.url.replace("file://", ""));
204
205
  return path2.join(binDir, "bootloader.cjs");
205
206
  });
206
- var layer = Layer7.effect(
207
+ var layer = Layer8.effect(
207
208
  BootloaderPath,
208
- Effect8.map(computeBootloaderPath, (path2) => BootloaderPath.of({ path: path2 }))
209
+ Effect10.map(computeBootloaderPath, (path2) => BootloaderPath.of({ path: path2 }))
209
210
  );
210
211
  var CdpRequest = Schema.Struct({
211
212
  id: Schema.Number,
@@ -236,13 +237,13 @@ var CdpError = class extends Schema.TaggedErrorClass()("CdpError", {
236
237
  code: Schema.optional(Schema.Number)
237
238
  }) {
238
239
  };
239
- var CdpClient = class extends Context3.Service()("inspeffct/CdpClient") {
240
+ var CdpClient = class extends Context4.Service()("inspeffct/CdpClient") {
240
241
  };
241
242
  var isCdpEvent = (msg) => typeof msg === "object" && msg !== null && "method" in msg && typeof msg.method === "string" && !("id" in msg);
242
243
  var isCdpResponse = (msg) => typeof msg === "object" && msg !== null && "id" in msg && typeof msg.id === "number";
243
- var makeConnection = (url) => Effect8.gen(function* () {
244
+ var makeConnection = (url) => Effect10.gen(function* () {
244
245
  const socket = yield* Socket.makeWebSocket(url).pipe(
245
- Effect8.mapError((e) => new CdpError({ message: `Failed to connect to ${url}: ${e}` }))
246
+ Effect10.mapError((e) => new CdpError({ message: `Failed to connect to ${url}: ${e}` }))
246
247
  );
247
248
  const outgoing = yield* Queue2.unbounded();
248
249
  const eventsPubSub = yield* PubSub2.unbounded();
@@ -256,14 +257,14 @@ var makeConnection = (url) => Effect8.gen(function* () {
256
257
  })
257
258
  ),
258
259
  Stream.runForEach(
259
- (msg) => Effect8.gen(function* () {
260
+ (msg) => Effect10.gen(function* () {
260
261
  if (isCdpResponse(msg)) {
261
262
  const resume = pendingRequests.get(msg.id);
262
263
  if (resume) {
263
264
  pendingRequests.delete(msg.id);
264
265
  if (msg.error) {
265
266
  resume(
266
- Effect8.fail(
267
+ Effect10.fail(
267
268
  new CdpError({
268
269
  message: msg.error.message,
269
270
  code: msg.error.code
@@ -271,28 +272,28 @@ var makeConnection = (url) => Effect8.gen(function* () {
271
272
  )
272
273
  );
273
274
  } else {
274
- resume(Effect8.succeed(msg.result));
275
+ resume(Effect10.succeed(msg.result));
275
276
  }
276
277
  }
277
278
  }
278
279
  if (isCdpEvent(msg)) {
279
280
  const decoded = yield* Schema.decodeUnknownEffect(CdpEvent)(msg).pipe(
280
- Effect8.mapError((error) => new CdpError({ message: String(error) }))
281
+ Effect10.mapError((error) => new CdpError({ message: String(error) }))
281
282
  );
282
283
  yield* PubSub2.publish(eventsPubSub, decoded);
283
284
  }
284
- }).pipe(Effect8.catchCause(Effect8.logDebug))
285
+ }).pipe(Effect10.catchCause(Effect10.logDebug))
285
286
  ),
286
- Effect8.ensuring(Queue2.shutdown(outgoing)),
287
- Effect8.catchCause(Effect8.logDebug),
288
- Effect8.forkScoped
287
+ Effect10.ensuring(Queue2.shutdown(outgoing)),
288
+ Effect10.catchCause(Effect10.logDebug),
289
+ Effect10.forkScoped
289
290
  );
290
291
  const request = (method, params) => {
291
292
  const id = nextId++;
292
- return Effect8.callback((resume) => {
293
+ return Effect10.callback((resume) => {
293
294
  pendingRequests.set(id, resume);
294
295
  Queue2.offerUnsafe(outgoing, { id, method, params });
295
- return Effect8.sync(() => {
296
+ return Effect10.sync(() => {
296
297
  pendingRequests.delete(id);
297
298
  });
298
299
  });
@@ -304,19 +305,36 @@ var makeConnection = (url) => Effect8.gen(function* () {
304
305
  events
305
306
  };
306
307
  });
307
- var layer2 = Layer7.effect(
308
+ var layer2 = Layer8.effect(
308
309
  CdpClient,
309
- Effect8.gen(function* () {
310
+ Effect10.gen(function* () {
310
311
  const wsConstructor = yield* Socket.WebSocketConstructor;
311
312
  return CdpClient.of({
312
313
  connect: (url) => makeConnection(url).pipe(
313
- Effect8.provideService(Socket.WebSocketConstructor, wsConstructor)
314
+ Effect10.provideService(Socket.WebSocketConstructor, wsConstructor)
314
315
  )
315
316
  });
316
317
  })
317
318
  ).pipe(
318
- Layer7.provide(NodeSocket.layerWebSocketConstructor)
319
+ Layer8.provide(NodeSocket.layerWebSocketConstructor)
319
320
  );
321
+ var randomByte = Random.nextIntBetween(0, 256, { halfOpen: true });
322
+ var randomUUID = Effect10.gen(function* () {
323
+ const bytes = yield* Effect10.all(Array.from({ length: 16 }, () => randomByte));
324
+ bytes[6] = bytes[6] & 15 | 64;
325
+ bytes[8] = bytes[8] & 63 | 128;
326
+ const hex = bytes.map((byte) => byte.toString(16).padStart(2, "0"));
327
+ return [
328
+ hex.slice(0, 4).join(""),
329
+ hex.slice(4, 6).join(""),
330
+ hex.slice(6, 8).join(""),
331
+ hex.slice(8, 10).join(""),
332
+ hex.slice(10, 16).join("")
333
+ ].join("-");
334
+ });
335
+ var RunId = class extends Context4.Service()("inspeffct/RunId") {
336
+ };
337
+ var layer3 = Layer8.effect(RunId, randomUUID);
320
338
  var isSchema = (u) => typeof u === "object" && u !== null && "ast" in u;
321
339
  var getMembers = (schema) => "members" in schema && Array.isArray(schema.members) ? schema.members : "cases" in schema ? Object.values(schema.cases) : [schema];
322
340
  var evolveNested = (schema, evolve2) => {
@@ -435,8 +453,8 @@ var encodeStruct = (config) => (self) => {
435
453
  })
436
454
  );
437
455
  };
438
- var create_otel_tables_default = Effect8.gen(function* () {
439
- const sql = yield* SqlClient3.SqlClient;
456
+ var create_otel_tables_default = Effect10.gen(function* () {
457
+ const sql = yield* SqlClient5.SqlClient;
440
458
  yield* sql`
441
459
  CREATE TABLE spans (
442
460
  span_id TEXT PRIMARY KEY,
@@ -457,15 +475,15 @@ var create_otel_tables_default = Effect8.gen(function* () {
457
475
  dropped_links_count INTEGER NOT NULL DEFAULT 0,
458
476
  is_external INTEGER NOT NULL DEFAULT 0
459
477
  )
460
- `.pipe(Effect8.withSpan("create_spans_table"));
461
- yield* sql`CREATE INDEX idx_spans_trace_id ON spans(trace_id)`.pipe(Effect8.withSpan("create_idx_spans_trace_id"));
478
+ `.pipe(Effect10.withSpan("create_spans_table"));
479
+ yield* sql`CREATE INDEX idx_spans_trace_id ON spans(trace_id)`.pipe(Effect10.withSpan("create_idx_spans_trace_id"));
462
480
  yield* sql`CREATE INDEX idx_spans_start_time ON spans(start_time)`.pipe(
463
- Effect8.withSpan("create_idx_spans_start_time")
481
+ Effect10.withSpan("create_idx_spans_start_time")
464
482
  );
465
- yield* sql`CREATE INDEX idx_spans_name ON spans(name)`.pipe(Effect8.withSpan("create_idx_spans_name"));
466
- yield* sql`CREATE INDEX idx_spans_parent ON spans(parent_span_id)`.pipe(Effect8.withSpan("create_idx_spans_parent"));
483
+ yield* sql`CREATE INDEX idx_spans_name ON spans(name)`.pipe(Effect10.withSpan("create_idx_spans_name"));
484
+ yield* sql`CREATE INDEX idx_spans_parent ON spans(parent_span_id)`.pipe(Effect10.withSpan("create_idx_spans_parent"));
467
485
  yield* sql`CREATE INDEX idx_spans_running ON spans(span_id) WHERE end_time IS NULL`.pipe(
468
- Effect8.withSpan("create_idx_spans_running")
486
+ Effect10.withSpan("create_idx_spans_running")
469
487
  );
470
488
  yield* sql`
471
489
  CREATE TABLE span_events (
@@ -477,9 +495,9 @@ var create_otel_tables_default = Effect8.gen(function* () {
477
495
  attributes TEXT NOT NULL DEFAULT '{}',
478
496
  dropped_attributes_count INTEGER NOT NULL DEFAULT 0
479
497
  )
480
- `.pipe(Effect8.withSpan("create_span_events_table"));
498
+ `.pipe(Effect10.withSpan("create_span_events_table"));
481
499
  yield* sql`CREATE INDEX idx_span_events_span ON span_events(span_id)`.pipe(
482
- Effect8.withSpan("create_idx_span_events_span")
500
+ Effect10.withSpan("create_idx_span_events_span")
483
501
  );
484
502
  yield* sql`
485
503
  CREATE TABLE span_links (
@@ -491,13 +509,22 @@ var create_otel_tables_default = Effect8.gen(function* () {
491
509
  attributes TEXT NOT NULL DEFAULT '{}',
492
510
  dropped_attributes_count INTEGER NOT NULL DEFAULT 0
493
511
  )
494
- `.pipe(Effect8.withSpan("create_span_links_table"));
512
+ `.pipe(Effect10.withSpan("create_span_links_table"));
495
513
  yield* sql`CREATE INDEX idx_span_links_span ON span_links(span_id)`.pipe(
496
- Effect8.withSpan("create_idx_span_links_span")
514
+ Effect10.withSpan("create_idx_span_links_span")
515
+ );
516
+ });
517
+ var create_span_exits_table_default = Effect10.void;
518
+ var simplify_span_exits_default = Effect10.void;
519
+ var add_run_id_default = Effect10.gen(function* () {
520
+ const sql = yield* SqlClient5.SqlClient;
521
+ yield* sql`ALTER TABLE spans ADD COLUMN run_id TEXT NOT NULL DEFAULT ''`.pipe(
522
+ Effect10.withSpan("add_spans_run_id")
523
+ );
524
+ yield* sql`CREATE INDEX idx_spans_run_id ON spans(run_id)`.pipe(
525
+ Effect10.withSpan("create_idx_spans_run_id")
497
526
  );
498
527
  });
499
- var create_span_exits_table_default = Effect8.void;
500
- var simplify_span_exits_default = Effect8.void;
501
528
 
502
529
  // src/services/Storage.ts
503
530
  var SpanExitJson = Schema.toCodecJson(SpanExit);
@@ -567,6 +594,7 @@ var DbExternalSpan = ExternalSpan.pipe(
567
594
  );
568
595
  var DbAnySpan = Schema.Union([DbSpan, DbExternalSpan]);
569
596
  var TraceSummary = Schema.Struct({
597
+ run_id: Schema.String,
570
598
  trace_id: Schema.String,
571
599
  span_count: NumberFromBigInt,
572
600
  root_span_name: Schema.NullOr(Schema.String),
@@ -586,40 +614,44 @@ var DbSpanLink = SpanLink.mapFields(
586
614
  linkedTraceId: "linked_trace_id"
587
615
  })
588
616
  );
589
- var Storage = class extends Context3.Service()("inspeffct/Storage") {
617
+ var Storage = class extends Context4.Service()("inspeffct/Storage") {
590
618
  };
591
619
  var MigrationsLoader = Migrator.fromRecord({
592
620
  "0001_create_otel_tables": create_otel_tables_default,
593
621
  "0002_create_span_exits_table": create_span_exits_table_default,
594
- "0003_simplify_span_exits": simplify_span_exits_default
622
+ "0003_simplify_span_exits": simplify_span_exits_default,
623
+ "0004_add_run_id": add_run_id_default
595
624
  });
596
625
  var runMigrations = Migrator.make({})({
597
626
  loader: MigrationsLoader
598
627
  });
599
- var layer4 = (config) => Layer7.effectContext(
600
- Effect8.gen(function* () {
628
+ var layer5 = (config) => Layer8.effectContext(
629
+ Effect10.gen(function* () {
601
630
  const sql = yield* SqliteClient.SqliteClient;
602
631
  yield* runMigrations;
603
632
  const storage = Storage.of({
604
- persistSpan: (span) => Effect8.gen(function* () {
633
+ persistSpan: (span, runId) => Effect10.gen(function* () {
605
634
  const changed = yield* (
606
635
  // @ts-ignore TS28 false positive from SqlSchema service inference
607
636
  SqlSchema.findOne({
608
637
  Request: DbAnySpan,
609
638
  Result: Schema.Struct({ span_id: Schema.String }),
610
- execute: (db) => sql`
611
- INSERT INTO spans ${sql.insert(db)}
639
+ execute: (db) => {
640
+ const row = { ...db, run_id: runId };
641
+ return sql`
642
+ INSERT INTO spans ${sql.insert(row)}
612
643
  ON CONFLICT(span_id) DO UPDATE SET
613
- ${sql.update(db, ["span_id"])}
644
+ ${sql.update(row, ["span_id"])}
614
645
  WHERE
615
646
  is_external = 1 OR
616
647
  (end_time IS NULL AND excluded.is_external = 0)
617
648
  RETURNING span_id
618
- `
649
+ `;
650
+ }
619
651
  })(span).pipe(
620
- Effect8.as(true),
621
- Effect8.catch(() => Effect8.succeed(false)),
622
- Effect8.provideService(SqlClient3.SafeIntegers, true)
652
+ Effect10.as(true),
653
+ Effect10.catch(() => Effect10.succeed(false)),
654
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
623
655
  )
624
656
  );
625
657
  return changed;
@@ -644,7 +676,7 @@ var layer4 = (config) => Layer7.effectContext(
644
676
  )
645
677
  `
646
678
  }),
647
- Effect8.provideService(SqlClient3.SafeIntegers, true)
679
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
648
680
  ),
649
681
  getSpansByTraceId: (traceId) => (
650
682
  // @ts-ignore TS28 false positive from SqlSchema service inference
@@ -658,7 +690,7 @@ var layer4 = (config) => Layer7.effectContext(
658
690
  ORDER BY s.start_time ASC
659
691
  `
660
692
  })(traceId).pipe(
661
- Effect8.provideService(SqlClient3.SafeIntegers, true)
693
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
662
694
  )
663
695
  ),
664
696
  getRecentSpans: (limit = 100) => (
@@ -673,7 +705,7 @@ var layer4 = (config) => Layer7.effectContext(
673
705
  LIMIT ${l}
674
706
  `
675
707
  })(limit).pipe(
676
- Effect8.provideService(SqlClient3.SafeIntegers, true)
708
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
677
709
  )
678
710
  ),
679
711
  getSpanEvents: flow(
@@ -696,7 +728,7 @@ var layer4 = (config) => Layer7.effectContext(
696
728
  ORDER BY time ASC
697
729
  `
698
730
  }),
699
- Effect8.provideService(SqlClient3.SafeIntegers, true)
731
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
700
732
  ),
701
733
  persistSpanLink: SqlSchema.void({
702
734
  Request: DbSpanLink,
@@ -725,15 +757,24 @@ var layer4 = (config) => Layer7.effectContext(
725
757
  getTraces: (filters = {}) => SqlSchema.findAll({
726
758
  Request: Schema.Struct({
727
759
  limit: Schema.optional(Schema.Number),
760
+ runId: Schema.optional(Schema.String),
728
761
  since: Schema.optional(Schema.BigInt),
729
762
  status: Schema.optional(Schema.Number)
730
763
  }),
731
764
  Result: TraceSummary,
732
765
  execute: (req) => sql`
733
766
  SELECT
767
+ s.run_id,
734
768
  s.trace_id,
735
769
  COUNT(*) as span_count,
736
- (SELECT name FROM spans WHERE trace_id = s.trace_id AND parent_span_id IS NULL LIMIT 1) as root_span_name,
770
+ (
771
+ SELECT name
772
+ FROM spans
773
+ WHERE trace_id = s.trace_id
774
+ AND run_id = s.run_id
775
+ AND parent_span_id IS NULL
776
+ LIMIT 1
777
+ ) as root_span_name,
737
778
  MIN(s.start_time) as start_time,
738
779
  MAX(s.end_time) as end_time,
739
780
  MAX(
@@ -745,6 +786,7 @@ var layer4 = (config) => Layer7.effectContext(
745
786
  ) as status
746
787
  FROM spans s
747
788
  WHERE ${sql.and([
789
+ req.runId !== void 0 ? sql`s.run_id = ${req.runId}` : sql`1=1`,
748
790
  req.since !== void 0 ? sql`s.start_time >= ${req.since}` : sql`1=1`,
749
791
  req.status !== void 0 ? sql`
750
792
  CASE
@@ -754,12 +796,12 @@ var layer4 = (config) => Layer7.effectContext(
754
796
  END = ${req.status}
755
797
  ` : sql`1=1`
756
798
  ])}
757
- GROUP BY s.trace_id
799
+ GROUP BY s.run_id, s.trace_id
758
800
  ORDER BY start_time DESC
759
801
  ${req.limit !== void 0 ? sql`LIMIT ${req.limit}` : sql``}
760
802
  `
761
803
  })(filters).pipe(
762
- Effect8.provideService(SqlClient3.SafeIntegers, true)
804
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
763
805
  ),
764
806
  getSpans: (filters = {}) => (
765
807
  // @ts-ignore TS28 false positive from SqlSchema service inference
@@ -768,6 +810,8 @@ var layer4 = (config) => Layer7.effectContext(
768
810
  limit: Schema.optional(Schema.Number),
769
811
  minDuration: Schema.optional(Schema.BigInt),
770
812
  name: Schema.optional(Schema.String),
813
+ runId: Schema.optional(Schema.String),
814
+ spanId: Schema.optional(Schema.String),
771
815
  status: Schema.optional(Schema.Number),
772
816
  traceId: Schema.optional(Schema.String)
773
817
  }),
@@ -776,6 +820,8 @@ var layer4 = (config) => Layer7.effectContext(
776
820
  SELECT s.*
777
821
  FROM spans s
778
822
  WHERE ${sql.and([
823
+ req.runId !== void 0 ? sql`s.run_id = ${req.runId}` : sql`1=1`,
824
+ req.spanId !== void 0 ? sql`s.span_id = ${req.spanId}` : sql`1=1`,
779
825
  req.traceId !== void 0 ? sql`s.trace_id = ${req.traceId}` : sql`1=1`,
780
826
  req.name !== void 0 ? req.name.includes("%") ? sql`s.name LIKE ${req.name}` : sql`s.name = ${req.name}` : sql`1=1`,
781
827
  req.minDuration !== void 0 ? sql`(s.end_time - s.start_time) >= ${req.minDuration}` : sql`1=1`,
@@ -791,44 +837,43 @@ var layer4 = (config) => Layer7.effectContext(
791
837
  ${req.limit !== void 0 ? sql`LIMIT ${req.limit}` : sql``}
792
838
  `
793
839
  })(filters).pipe(
794
- Effect8.provideService(SqlClient3.SafeIntegers, true)
840
+ Effect10.provideService(SqlClient5.SafeIntegers, true)
795
841
  )
796
842
  )
797
843
  });
798
- return Context3.make(Storage, storage);
844
+ return Context4.make(Storage, storage);
799
845
  })
800
- ).pipe(Layer7.provide(SqliteClient.layer(config)));
846
+ ).pipe(Layer8.provide(SqliteClient.layer(config)));
801
847
 
802
848
  // src/services/EventCollector.ts
803
- var EventCollector = class extends Context3.Service()("inspeffct/EventCollector") {
849
+ var EventCollector = class extends Context4.Service()("inspeffct/EventCollector") {
804
850
  };
805
- var layer5 = Layer7.effect(
851
+ var layer6 = Layer8.effect(
806
852
  EventCollector,
807
- Effect8.gen(function* () {
853
+ Effect10.gen(function* () {
854
+ const runId = yield* RunId;
808
855
  const storage = yield* Storage;
809
856
  return EventCollector.of({
810
- collect: (message) => Effect8.gen(function* () {
857
+ collect: (message) => Effect10.gen(function* () {
811
858
  switch (message._tag) {
812
859
  case "InitNotification": {
813
- yield* Effect8.logDebug(
860
+ yield* Effect10.logDebug(
814
861
  `${message._tag} from ${message.instrumentationId} (inspectorURL: ${message.inspectorURL ?? "none"}, waitingForDebugger: ${message.waitingForDebugger})`
815
862
  );
816
863
  break;
817
864
  }
818
865
  case "TracerSpanNotification": {
819
866
  const { instrumentationId, span } = message;
820
- yield* Effect8.logDebug(`${message._tag} from ${instrumentationId}`);
821
- if (span._tag === "Span" && span.status._tag === "Ended") {
822
- yield* storage.persistSpan(span);
823
- yield* Effect8.logDebug(
824
- `Persisted span ${span.name} (${span.spanId}) with exit ${span.status.exit._tag} to storage`
825
- );
826
- }
867
+ yield* Effect10.logDebug(`${message._tag} from ${instrumentationId}`);
868
+ yield* storage.persistSpan(span, runId);
869
+ yield* Effect10.logDebug(
870
+ `Persisted span (${span.traceId}, ${span.spanId}) to storage`
871
+ );
827
872
  break;
828
873
  }
829
874
  case "TracerSpanEventNotification": {
830
875
  const { event } = message;
831
- yield* Effect8.logDebug(`${message._tag} from ${message.instrumentationId}`);
876
+ yield* Effect10.logDebug(`${message._tag} from ${message.instrumentationId}`);
832
877
  yield* storage.persistSpanEvent({
833
878
  spanId: event.spanId,
834
879
  traceId: event.traceId,
@@ -836,14 +881,14 @@ var layer5 = Layer7.effect(
836
881
  time: event.time,
837
882
  attributes: event.attributes
838
883
  });
839
- yield* Effect8.logDebug(
884
+ yield* Effect10.logDebug(
840
885
  `Persisted span event ${event.name} for span ${event.spanId}`
841
886
  );
842
887
  break;
843
888
  }
844
889
  case "TracerSpanLinkNotification": {
845
890
  const { link } = message;
846
- yield* Effect8.logDebug(`${message._tag} from ${message.instrumentationId}`);
891
+ yield* Effect10.logDebug(`${message._tag} from ${message.instrumentationId}`);
847
892
  yield* storage.persistSpanLink({
848
893
  spanId: link.spanId,
849
894
  traceId: link.traceId,
@@ -851,7 +896,7 @@ var layer5 = Layer7.effect(
851
896
  linkedTraceId: link.linkedTraceId,
852
897
  attributes: link.attributes
853
898
  });
854
- yield* Effect8.logDebug(
899
+ yield* Effect10.logDebug(
855
900
  `Persisted span link from ${link.spanId} to ${link.linkedSpanId}`
856
901
  );
857
902
  break;
@@ -860,48 +905,48 @@ var layer5 = Layer7.effect(
860
905
  case "VariableReferenceInfo":
861
906
  case "ResourcesForRequestReleased":
862
907
  case "CurrentFibersInfo": {
863
- yield* Effect8.logDebug(`${message._tag} from ${message.instrumentationId}`);
908
+ yield* Effect10.logDebug(`${message._tag} from ${message.instrumentationId}`);
864
909
  break;
865
910
  }
866
911
  }
867
- }).pipe(Effect8.catch((error) => Effect8.logWarning(`Failed to persist event: ${error}`)))
912
+ }).pipe(Effect10.catch((error) => Effect10.logWarning(`Failed to persist event: ${error}`)))
868
913
  });
869
914
  })
870
915
  );
871
- Layer7.succeed(
916
+ Layer8.succeed(
872
917
  EventCollector,
873
918
  EventCollector.of({
874
919
  collect: (message) => {
875
920
  if (message._tag === "InitNotification") {
876
- return Effect8.logDebug(
921
+ return Effect10.logDebug(
877
922
  `${message._tag} from ${message.instrumentationId} (inspectorURL: ${message.inspectorURL ?? "none"}, waitingForDebugger: ${message.waitingForDebugger})`
878
923
  );
879
924
  }
880
- return Effect8.logDebug(`${message._tag} from ${message.instrumentationId}`);
925
+ return Effect10.logDebug(`${message._tag} from ${message.instrumentationId}`);
881
926
  }
882
927
  })
883
928
  );
884
- Layer7.effect(
929
+ Layer8.effect(
885
930
  EventCollector,
886
- Effect8.gen(function* () {
931
+ Effect10.gen(function* () {
887
932
  const messagesRef = yield* Ref.make(Chunk.empty());
888
933
  return EventCollector.of({
889
934
  collect: (message) => Ref.update(messagesRef, Chunk.append(message)),
890
- getMessages: Ref.get(messagesRef).pipe(Effect8.map(Chunk.toReadonlyArray))
935
+ getMessages: Ref.get(messagesRef).pipe(Effect10.map(Chunk.toReadonlyArray))
891
936
  });
892
937
  })
893
938
  );
894
939
 
895
940
  // src/services/CdpManager.ts
896
941
  var BINDING_NAME = "__inspeffct_bridge__";
897
- var CdpManager = class extends Context3.Service()("inspeffct/CdpManager") {
942
+ var CdpManager = class extends Context4.Service()("inspeffct/CdpManager") {
898
943
  };
899
- var getBootloaderScript = Effect8.gen(function* () {
944
+ var getBootloaderScript = Effect10.gen(function* () {
900
945
  const fs2 = yield* FileSystem.FileSystem;
901
946
  const bootloaderPath = yield* getPath;
902
947
  return yield* fs2.readFileString(bootloaderPath);
903
948
  });
904
- var connectAndListen = (url, bootloaderScript) => Effect8.gen(function* () {
949
+ var connectAndListen = (url, bootloaderScript) => Effect10.gen(function* () {
905
950
  const cdp = yield* CdpClient;
906
951
  const collector = yield* EventCollector;
907
952
  const connection = yield* cdp.connect(url);
@@ -909,21 +954,21 @@ var connectAndListen = (url, bootloaderScript) => Effect8.gen(function* () {
909
954
  expression: bootloaderScript,
910
955
  contextId,
911
956
  silent: true
912
- }).pipe(Effect8.ensuring(connection.request("Runtime.runIfWaitingForDebugger").pipe(Effect8.ignore({ log: true }))));
957
+ }).pipe(Effect10.ensuring(connection.request("Runtime.runIfWaitingForDebugger").pipe(Effect10.ignore({ log: true }))));
913
958
  const eventFiber = yield* connection.events.pipe(
914
959
  Stream.takeUntil(
915
960
  (event) => event.method === "Runtime.executionContextDestroyed" || event.method === "Runtime.executionContextsCleared" || event.method === "Inspector.detached"
916
961
  ),
917
962
  Stream.runForEach(
918
- (event) => Effect8.gen(function* () {
963
+ (event) => Effect10.gen(function* () {
919
964
  if (event.method === "Runtime.bindingCalled") {
920
965
  const params = event.params;
921
966
  if (params.name === BINDING_NAME) {
922
967
  yield* Schema.decodeUnknownEffect(Schema.fromJsonString(OutMessage))(
923
968
  params.payload
924
969
  ).pipe(
925
- Effect8.flatMap((decoded) => collector.collect(decoded)),
926
- Effect8.catch(() => Effect8.logError(`Failed to decode CDP message: ${params.payload}`))
970
+ Effect10.flatMap((decoded) => collector.collect(decoded)),
971
+ Effect10.catch(() => Effect10.logError(`Failed to decode CDP message: ${params.payload}`))
927
972
  );
928
973
  }
929
974
  }
@@ -933,44 +978,44 @@ var connectAndListen = (url, bootloaderScript) => Effect8.gen(function* () {
933
978
  }
934
979
  })
935
980
  ),
936
- Effect8.forkScoped
981
+ Effect10.forkScoped
937
982
  );
938
- yield* Effect8.yieldNow;
983
+ yield* Effect10.yieldNow;
939
984
  yield* connection.request("Runtime.addBinding", { name: BINDING_NAME });
940
985
  yield* connection.request("Runtime.enable");
941
986
  yield* connection.request("Runtime.runIfWaitingForDebugger");
942
- yield* Effect8.logDebug(`CDP connected: ${url}`);
987
+ yield* Effect10.logDebug(`CDP connected: ${url}`);
943
988
  yield* Fiber.join(eventFiber);
944
989
  });
945
- var layer6 = Layer7.effect(
990
+ var layer7 = Layer8.effect(
946
991
  CdpManager,
947
- Effect8.gen(function* () {
992
+ Effect10.gen(function* () {
948
993
  const bootloaderScript = yield* getBootloaderScript;
949
994
  const cdpClient = yield* CdpClient;
950
995
  const collector = yield* EventCollector;
951
- const managerScope = yield* Effect8.scope;
996
+ const managerScope = yield* Effect10.scope;
952
997
  const activeConnections = /* @__PURE__ */ new Map();
953
998
  return CdpManager.of({
954
- connect: (url) => Effect8.gen(function* () {
999
+ connect: (url) => Effect10.gen(function* () {
955
1000
  if (activeConnections.has(url)) {
956
1001
  return;
957
1002
  }
958
1003
  activeConnections.set(url, true);
959
- yield* Effect8.logDebug(`Connecting to CDP: ${url}`);
1004
+ yield* Effect10.logDebug(`Connecting to CDP: ${url}`);
960
1005
  yield* connectAndListen(url, bootloaderScript).pipe(
961
- Effect8.provideService(CdpClient, cdpClient),
962
- Effect8.provideService(EventCollector, collector),
963
- Effect8.scoped,
964
- Effect8.catchCause((cause) => Effect8.logError(`CDP connection failed for ${url}: ${cause}`)),
1006
+ Effect10.provideService(CdpClient, cdpClient),
1007
+ Effect10.provideService(EventCollector, collector),
1008
+ Effect10.scoped,
1009
+ Effect10.catchCause((cause) => Effect10.logError(`CDP connection failed for ${url}: ${cause}`)),
965
1010
  // Always remove from tracking when done (success, failure, or interruption)
966
- Effect8.ensuring(
967
- Effect8.sync(() => {
1011
+ Effect10.ensuring(
1012
+ Effect10.sync(() => {
968
1013
  activeConnections.delete(url);
969
1014
  }).pipe(
970
- Effect8.tap(() => Effect8.logDebug(`CDP disconnected: ${url}`))
1015
+ Effect10.tap(() => Effect10.logDebug(`CDP disconnected: ${url}`))
971
1016
  )
972
1017
  ),
973
- Effect8.forkIn(managerScope)
1018
+ Effect10.forkIn(managerScope)
974
1019
  );
975
1020
  })
976
1021
  });
@@ -978,12 +1023,12 @@ var layer6 = Layer7.effect(
978
1023
  );
979
1024
  var namedSocketDirectory = os.platform() === "win32" ? "\\\\.\\pipe\\" : os.tmpdir();
980
1025
  var pipeCounter = 0;
981
- var generateIpcPath = Effect8.sync(() => {
1026
+ var generateIpcPath = Effect10.sync(() => {
982
1027
  const randomHex = crypto.randomBytes(4).toString("hex");
983
1028
  const pipeName = `inspeffct.${process.pid}-${randomHex}-${pipeCounter++}.sock`;
984
1029
  return path.join(namedSocketDirectory, pipeName);
985
1030
  });
986
- var cleanupSocketFile = (socketPath) => Effect8.sync(() => {
1031
+ var cleanupSocketFile = (socketPath) => Effect10.sync(() => {
987
1032
  if (os.platform() !== "win32") {
988
1033
  try {
989
1034
  fs.unlinkSync(socketPath);
@@ -991,7 +1036,7 @@ var cleanupSocketFile = (socketPath) => Effect8.sync(() => {
991
1036
  }
992
1037
  }
993
1038
  });
994
- var IpcServer = class extends Context3.Service()("inspeffct/IpcServer") {
1039
+ var IpcServer = class extends Context4.Service()("inspeffct/IpcServer") {
995
1040
  };
996
1041
  var tryParseMessage = (message) => {
997
1042
  try {
@@ -1003,13 +1048,13 @@ var tryParseMessage = (message) => {
1003
1048
  };
1004
1049
  var ACK_SUCCESS = new Uint8Array([0]);
1005
1050
  var parseMessages = (socket) => Stream.unwrap(
1006
- Effect8.gen(function* () {
1051
+ Effect10.gen(function* () {
1007
1052
  const write = yield* socket.writer;
1008
1053
  const decoder = new TextDecoder();
1009
1054
  let buffer = "";
1010
1055
  return Stream.callback(
1011
1056
  (queue) => socket.run(
1012
- (data) => Effect8.gen(function* () {
1057
+ (data) => Effect10.gen(function* () {
1013
1058
  buffer += decoder.decode(data);
1014
1059
  let nullIndex;
1015
1060
  while ((nullIndex = buffer.indexOf("\0")) !== -1) {
@@ -1024,13 +1069,13 @@ var parseMessages = (socket) => Stream.unwrap(
1024
1069
  }
1025
1070
  }
1026
1071
  }),
1027
- { onOpen: Effect8.void }
1072
+ { onOpen: Effect10.void }
1028
1073
  ).pipe(
1029
- Effect8.andThen(() => {
1074
+ Effect10.andThen(() => {
1030
1075
  if (buffer.length > 0) {
1031
1076
  const decoded = tryParseMessage(buffer);
1032
1077
  if (decoded) {
1033
- return Queue2.offer(queue, decoded).pipe(Effect8.andThen(Queue2.end(queue)));
1078
+ return Queue2.offer(queue, decoded).pipe(Effect10.andThen(Queue2.end(queue)));
1034
1079
  }
1035
1080
  }
1036
1081
  return Queue2.end(queue);
@@ -1039,18 +1084,18 @@ var parseMessages = (socket) => Stream.unwrap(
1039
1084
  );
1040
1085
  })
1041
1086
  );
1042
- var layer7 = Layer7.effect(
1087
+ var layer8 = Layer8.effect(
1043
1088
  IpcServer,
1044
- Effect8.gen(function* () {
1089
+ Effect10.gen(function* () {
1045
1090
  const ipcPath = yield* generateIpcPath;
1046
- yield* Effect8.addFinalizer(() => cleanupSocketFile(ipcPath));
1091
+ yield* Effect10.addFinalizer(() => cleanupSocketFile(ipcPath));
1047
1092
  const server = yield* NodeSocketServer.make({ path: ipcPath });
1048
1093
  const pubsub = yield* PubSub2.unbounded();
1049
1094
  yield* server.run(
1050
1095
  (socket) => parseMessages(socket).pipe(
1051
1096
  Stream.runForEach((message) => PubSub2.publish(pubsub, message))
1052
1097
  )
1053
- ).pipe(Effect8.catchCause(Effect8.logDebug), Effect8.forkScoped);
1098
+ ).pipe(Effect10.catchCause(Effect10.logDebug), Effect10.forkScoped);
1054
1099
  const messages = Stream.fromPubSub(pubsub);
1055
1100
  const subscribe3 = PubSub2.subscribe(pubsub);
1056
1101
  return IpcServer.of({
@@ -1060,9 +1105,9 @@ var layer7 = Layer7.effect(
1060
1105
  });
1061
1106
  })
1062
1107
  );
1063
- Effect8.map(IpcServer, (server) => server.path);
1064
- Effect8.map(IpcServer, (server) => server.messages);
1065
- Effect8.flatMap(IpcServer, (server) => server.subscribe);
1108
+ Effect10.map(IpcServer, (server) => server.path);
1109
+ Effect10.map(IpcServer, (server) => server.messages);
1110
+ Effect10.flatMap(IpcServer, (server) => server.subscribe);
1066
1111
 
1067
1112
  // src/cli/options.ts
1068
1113
  var dataOption = Flag3.string("data").pipe(
@@ -1094,45 +1139,50 @@ var buildEnv = (bootloaderPath, ipcPath) => {
1094
1139
  };
1095
1140
  };
1096
1141
  var makeServicesLayer = (dataPath) => {
1097
- const storageLayer = layer4({ filename: dataPath });
1098
- const eventCollectorLayer = layer5.pipe(Layer7.provide(storageLayer));
1099
- const bootloaderPathLayer = layer.pipe(Layer7.provide(NodePath.layer));
1100
- return Layer7.mergeAll(
1101
- layer7,
1102
- eventCollectorLayer,
1142
+ const runIdLayer = layer3;
1143
+ const storageLayer = layer5({ filename: dataPath });
1144
+ const eventCollectorLayer = layer6.pipe(
1145
+ Layer8.provide(runIdLayer),
1146
+ Layer8.provide(storageLayer)
1147
+ );
1148
+ const bootloaderPathLayer = layer.pipe(Layer8.provide(NodePath.layer));
1149
+ return Layer8.mergeAll(
1150
+ layer8,
1151
+ runIdLayer,
1103
1152
  bootloaderPathLayer,
1104
- layer6.pipe(
1105
- Layer7.provide(eventCollectorLayer),
1106
- Layer7.provide(layer2),
1107
- Layer7.provide(bootloaderPathLayer),
1108
- Layer7.provide(NodeFileSystem.layer),
1109
- Layer7.provide(NodePath.layer)
1153
+ layer7.pipe(
1154
+ Layer8.provide(layer2),
1155
+ Layer8.provide(bootloaderPathLayer),
1156
+ Layer8.provide(NodeFileSystem.layer),
1157
+ Layer8.provide(NodePath.layer)
1110
1158
  )
1159
+ ).pipe(
1160
+ Layer8.provideMerge(eventCollectorLayer)
1111
1161
  );
1112
1162
  };
1113
- var makeReadOnlyLayer = (dataPath) => layer4({ filename: dataPath });
1163
+ var makeReadOnlyLayer = (dataPath) => layer5({ filename: dataPath });
1114
1164
 
1115
1165
  // src/cli/connect.ts
1116
- var command = Command5.make(
1166
+ var command = Command6.make(
1117
1167
  "connect",
1118
1168
  {
1119
1169
  data: dataOption,
1120
- url: Argument2.string("url").pipe(
1121
- Argument2.withDescription("WebSocket URL of the inspector (ws://...)")
1170
+ url: Argument3.string("url").pipe(
1171
+ Argument3.withDescription("WebSocket URL of the inspector (ws://...)")
1122
1172
  )
1123
1173
  },
1124
- ({ data, url }) => Effect8.gen(function* () {
1125
- yield* Effect8.logDebug(`Connecting to URL: ${url}`);
1126
- yield* Effect8.logDebug(`Data file: ${data}`);
1174
+ ({ data, url }) => Effect10.gen(function* () {
1175
+ yield* Effect10.logDebug(`Connecting to URL: ${url}`);
1176
+ yield* Effect10.logDebug(`Data file: ${data}`);
1127
1177
  const cdpManager = yield* CdpManager;
1128
1178
  yield* cdpManager.connect(url);
1129
- yield* Effect8.logInfo(`Connected to ${url}`);
1130
- return yield* Effect8.never;
1179
+ yield* Effect10.logInfo(`Connected to ${url}`);
1180
+ return yield* Effect10.never;
1131
1181
  }).pipe(
1132
- Effect8.scoped,
1133
- Effect8.provide(makeServicesLayer(data))
1182
+ Effect10.scoped,
1183
+ Effect10.provide(makeServicesLayer(data))
1134
1184
  )
1135
- ).pipe(Command5.withDescription("Connect to an existing inspector endpoint"));
1185
+ ).pipe(Command6.withDescription("Connect to an existing CDP inspector endpoint"));
1136
1186
  var NODE_INSPECTOR_REGEX = /Debugger listening on (ws:\/\/[^\s]+)/;
1137
1187
  var BUN_INSPECTOR_REGEX = /https:\/\/debug\.bun\.sh\/#([^\s]+)/;
1138
1188
  var parseInspectorUrl = (chunk, decoder) => {
@@ -1147,7 +1197,7 @@ var parseInspectorUrl = (chunk, decoder) => {
1147
1197
  }
1148
1198
  return void 0;
1149
1199
  };
1150
- var command2 = Command5.make(
1200
+ var command2 = Command6.make(
1151
1201
  "run",
1152
1202
  {
1153
1203
  data: dataOption,
@@ -1155,31 +1205,33 @@ var command2 = Command5.make(
1155
1205
  Flag3.optional,
1156
1206
  Flag3.withHidden
1157
1207
  ),
1158
- args: Argument2.string("command").pipe(
1159
- Argument2.withDescription("The command to run"),
1160
- Argument2.variadic({ min: 0 })
1208
+ args: Argument3.string("command").pipe(
1209
+ Argument3.withDescription("The command to run"),
1210
+ Argument3.variadic({ min: 0 })
1161
1211
  )
1162
1212
  },
1163
- ({ args, data, encodedCommand }) => Effect8.gen(function* () {
1213
+ ({ args, data, encodedCommand }) => Effect10.gen(function* () {
1164
1214
  const resolvedArgs = Option3.isSome(encodedCommand) ? JSON.parse(Buffer.from(encodedCommand.value, "base64url").toString("utf8")) : args;
1165
1215
  const [rawExecutable, ...commandArgs] = resolvedArgs;
1166
1216
  const executable = rawExecutable === "node" ? process.execPath : rawExecutable;
1167
- yield* Effect8.logDebug(`Running: ${executable} ${commandArgs.join(" ")}`);
1168
- yield* Effect8.logDebug(`Data file: ${data}`);
1217
+ const runId = yield* RunId;
1218
+ yield* Console2.log(`Run ID: ${runId}`);
1219
+ yield* Effect10.logDebug(`Running: ${executable} ${commandArgs.join(" ")}`);
1220
+ yield* Effect10.logDebug(`Data file: ${data}`);
1169
1221
  const bootloaderPath = yield* getPath;
1170
- yield* Effect8.logDebug(`Bootloader: ${bootloaderPath}`);
1222
+ yield* Effect10.logDebug(`Bootloader: ${bootloaderPath}`);
1171
1223
  const ipcServer = yield* IpcServer;
1172
- yield* Effect8.logDebug(`IPC socket: ${ipcServer.path}`);
1224
+ yield* Effect10.logDebug(`IPC socket: ${ipcServer.path}`);
1173
1225
  const collector = yield* EventCollector;
1174
1226
  const cdpManager = yield* CdpManager;
1175
1227
  const env = buildEnv(bootloaderPath, ipcServer.path);
1176
- yield* Effect8.logDebug(`NODE_OPTIONS: ${env.NODE_OPTIONS}`);
1177
- yield* Stream.runForEach(ipcServer.messages, (message) => Effect8.gen(function* () {
1228
+ yield* Effect10.logDebug(`NODE_OPTIONS: ${env.NODE_OPTIONS}`);
1229
+ yield* Stream.runForEach(ipcServer.messages, (message) => Effect10.gen(function* () {
1178
1230
  yield* collector.collect(message);
1179
1231
  if (message._tag === "InitNotification" && message.inspectorURL) {
1180
1232
  yield* cdpManager.connect(message.inspectorURL);
1181
1233
  }
1182
- })).pipe(Effect8.forkScoped);
1234
+ })).pipe(Effect10.forkScoped);
1183
1235
  const cmd = ChildProcess.make(executable, commandArgs, {
1184
1236
  env,
1185
1237
  extendEnv: true,
@@ -1188,35 +1240,35 @@ var command2 = Command5.make(
1188
1240
  stdout: "inherit"
1189
1241
  });
1190
1242
  const childProcess = yield* cmd;
1191
- yield* Effect8.logDebug(`Started process with PID: ${childProcess.pid}`);
1243
+ yield* Effect10.logDebug(`Started process with PID: ${childProcess.pid}`);
1192
1244
  const textDecoder = new TextDecoder();
1193
1245
  yield* Stream.runForEach(
1194
1246
  childProcess.stderr,
1195
- (chunk) => Effect8.gen(function* () {
1196
- yield* Effect8.sync(() => process.stderr.write(chunk));
1247
+ (chunk) => Effect10.gen(function* () {
1248
+ yield* Effect10.sync(() => process.stderr.write(chunk));
1197
1249
  const inspectorUrl = parseInspectorUrl(chunk, textDecoder);
1198
1250
  if (inspectorUrl) {
1199
- yield* Effect8.logDebug(`Detected inspector URL from stderr: ${inspectorUrl}`);
1251
+ yield* Effect10.logDebug(`Detected inspector URL from stderr: ${inspectorUrl}`);
1200
1252
  yield* cdpManager.connect(inspectorUrl);
1201
1253
  }
1202
1254
  })
1203
- ).pipe(Effect8.forkScoped);
1204
- const forwardSignal = (signal) => Effect8.sync(() => {
1255
+ ).pipe(Effect10.forkScoped);
1256
+ const forwardSignal = (signal) => Effect10.sync(() => {
1205
1257
  process.on(signal, () => {
1206
- Effect8.runPromise(childProcess.kill({ killSignal: signal }).pipe(Effect8.ignore));
1258
+ Effect10.runPromise(childProcess.kill({ killSignal: signal }).pipe(Effect10.ignore));
1207
1259
  });
1208
1260
  });
1209
1261
  yield* forwardSignal("SIGTERM");
1210
1262
  yield* forwardSignal("SIGINT");
1211
1263
  yield* forwardSignal("SIGHUP");
1212
1264
  const exitCode = yield* childProcess.exitCode;
1213
- yield* Effect8.logDebug(`Process exited with code: ${exitCode}`);
1214
- yield* Effect8.sync(() => process.exitCode = exitCode);
1265
+ yield* Effect10.logDebug(`Process exited with code: ${exitCode}`);
1266
+ yield* Effect10.sync(() => process.exitCode = exitCode);
1215
1267
  }).pipe(
1216
- Effect8.scoped,
1217
- Effect8.provide(makeServicesLayer(data))
1268
+ Effect10.scoped,
1269
+ Effect10.provide(makeServicesLayer(data))
1218
1270
  )
1219
- ).pipe(Command5.withDescription("Run a command with Effect instrumentation"));
1271
+ ).pipe(Command6.withDescription("Run a command with Effect instrumentation"));
1220
1272
  var getSpanId = (span) => span.spanId;
1221
1273
  var getTraceId = (span) => span.traceId;
1222
1274
  var getParentSpanId = (span) => span._tag === "Span" ? span.parentSpanId : null;
@@ -1341,11 +1393,123 @@ var renderSpanGraph = (graph) => {
1341
1393
  return rootDocs.filter((doc) => doc.length > 0).join("\n");
1342
1394
  };
1343
1395
 
1344
- // src/cli/spans.ts
1345
- var command3 = Command5.make(
1396
+ // src/cli/span.ts
1397
+ var attributesToObject = (attributes) => Object.fromEntries(attributes);
1398
+ var command3 = Command6.make(
1399
+ "span",
1400
+ {
1401
+ data: dataOption,
1402
+ json: jsonOption,
1403
+ traceId: Argument3.string("trace-id").pipe(
1404
+ Argument3.withDescription("The trace ID containing the span")
1405
+ ),
1406
+ spanId: Argument3.string("span-id").pipe(
1407
+ Argument3.withDescription("The span ID to display")
1408
+ )
1409
+ },
1410
+ ({ data, json, spanId, traceId }) => Effect10.gen(function* () {
1411
+ const storage = yield* Storage;
1412
+ const spans = yield* storage.getSpans({ spanId, traceId });
1413
+ const span = spans[0];
1414
+ if (span === void 0) {
1415
+ yield* Console2.log(`No span found for trace: ${traceId}, span: ${spanId}`);
1416
+ return;
1417
+ }
1418
+ const events = yield* storage.getSpanEvents({ traceId, spanId });
1419
+ const links = yield* storage.getSpanLinks({ traceId, spanId });
1420
+ const startTime = getStartTime(span);
1421
+ const endTime = getEndTime(span);
1422
+ const durationNanos = endTime !== null ? endTime - startTime : null;
1423
+ if (json) {
1424
+ const output = {
1425
+ span: {
1426
+ spanId: getSpanId(span),
1427
+ traceId: getTraceId(span),
1428
+ parentSpanId: getParentSpanId(span),
1429
+ name: getSpanName(span),
1430
+ kind: getSpanKind(span),
1431
+ statusCode: getStatusCode(span),
1432
+ statusMessage: getStatusMessage(span),
1433
+ startTime: formatTimestamp(startTime),
1434
+ endTime: endTime !== null ? formatTimestamp(endTime) : null,
1435
+ durationMs: durationNanos !== null ? Number(durationNanos / 1000000n) : null,
1436
+ attributes: getAttributes(span),
1437
+ isExternal: isExternalSpan(span)
1438
+ },
1439
+ events: events.map((event) => ({
1440
+ name: event.name,
1441
+ time: formatTimestamp(event.time),
1442
+ attributes: attributesToObject(event.attributes)
1443
+ })),
1444
+ links: links.map((link) => ({
1445
+ linkedSpanId: link.linkedSpanId,
1446
+ linkedTraceId: link.linkedTraceId,
1447
+ attributes: attributesToObject(link.attributes)
1448
+ }))
1449
+ };
1450
+ yield* Console2.log(JSON.stringify(output, null, 2));
1451
+ } else {
1452
+ const fields = [
1453
+ field("Span", getSpanId(span)),
1454
+ field("Name", getSpanName(span)),
1455
+ field("Trace", getTraceId(span)),
1456
+ field("Kind", String(getSpanKind(span))),
1457
+ field("Status", formatStatusDoc(getStatusCode(span))),
1458
+ field("Started", formatTimestamp(startTime)),
1459
+ field("Duration", durationNanos !== null ? formatDuration(durationNanos) : "running")
1460
+ ];
1461
+ const parentSpanId = getParentSpanId(span);
1462
+ if (parentSpanId !== null) {
1463
+ fields.push(field("Parent", parentSpanId));
1464
+ }
1465
+ if (endTime !== null) {
1466
+ fields.push(field("Ended", formatTimestamp(endTime)));
1467
+ }
1468
+ const statusMessage = getStatusMessage(span);
1469
+ if (statusMessage !== null) {
1470
+ fields.push(field("Status Message", statusMessage));
1471
+ }
1472
+ const attrs = getAttributes(span);
1473
+ if (Object.keys(attrs).length > 0) {
1474
+ fields.push(field("Attrs", JSON.stringify(attrs)));
1475
+ }
1476
+ const eventDocs = events.length === 0 ? ["Events: none"] : [
1477
+ `Events (${events.length}):`,
1478
+ ...events.map((event) => {
1479
+ const attrs2 = attributesToObject(event.attributes);
1480
+ const lines = [` ${event.name} @ ${formatTimestamp(event.time)}`];
1481
+ if (Object.keys(attrs2).length > 0) {
1482
+ lines.push(` ${field("Attrs", JSON.stringify(attrs2))}`);
1483
+ }
1484
+ return lines.join("\n");
1485
+ })
1486
+ ];
1487
+ const linkDocs = links.length === 0 ? ["Links: none"] : [
1488
+ `Links (${links.length}):`,
1489
+ ...links.map((link) => {
1490
+ const attrs2 = attributesToObject(link.attributes);
1491
+ const lines = [` ${link.linkedTraceId}/${link.linkedSpanId}`];
1492
+ if (Object.keys(attrs2).length > 0) {
1493
+ lines.push(` ${field("Attrs", JSON.stringify(attrs2))}`);
1494
+ }
1495
+ return lines.join("\n");
1496
+ })
1497
+ ];
1498
+ yield* Console2.log(renderDoc([...fields, "", ...eventDocs, "", ...linkDocs].join("\n")));
1499
+ }
1500
+ }).pipe(
1501
+ Effect10.scoped,
1502
+ Effect10.provide(makeReadOnlyLayer(data))
1503
+ )
1504
+ ).pipe(Command6.withDescription("Show detailed span information"));
1505
+ var command4 = Command6.make(
1346
1506
  "spans",
1347
1507
  {
1348
1508
  data: dataOption,
1509
+ runId: Flag3.string("run-id").pipe(
1510
+ Flag3.withDescription("Filter by run ID"),
1511
+ Flag3.optional
1512
+ ),
1349
1513
  json: jsonOption,
1350
1514
  limit: limitOption,
1351
1515
  minDuration: Flag3.string("min-duration").pipe(
@@ -1356,17 +1520,21 @@ var command3 = Command5.make(
1356
1520
  Flag3.withDescription("Filter by span name (use % for wildcards)"),
1357
1521
  Flag3.optional
1358
1522
  ),
1523
+ spanId: Flag3.string("span-id").pipe(
1524
+ Flag3.withDescription("Filter by span ID"),
1525
+ Flag3.optional
1526
+ ),
1359
1527
  status: Flag3.string("status").pipe(
1360
1528
  Flag3.withDescription("Filter by status: ok, error, unset"),
1361
1529
  Flag3.optional
1362
1530
  ),
1363
- trace: Flag3.string("trace").pipe(
1531
+ trace: Flag3.string("trace-id").pipe(
1364
1532
  Flag3.withAlias("t"),
1365
1533
  Flag3.withDescription("Filter by trace ID"),
1366
1534
  Flag3.optional
1367
1535
  )
1368
1536
  },
1369
- ({ data, json, limit, minDuration, name, status, trace }) => Effect8.gen(function* () {
1537
+ ({ data, json, limit, minDuration, name, runId, spanId, status, trace }) => Effect10.gen(function* () {
1370
1538
  const storage = yield* Storage;
1371
1539
  let statusCode;
1372
1540
  if (Option3.isSome(status)) {
@@ -1381,10 +1549,12 @@ var command3 = Command5.make(
1381
1549
  statusCode = 0;
1382
1550
  break;
1383
1551
  default:
1384
- yield* Effect8.logWarning(`Unknown status: ${status.value}, ignoring filter`);
1552
+ yield* Effect10.logWarning(`Unknown status: ${status.value}, ignoring filter`);
1385
1553
  }
1386
1554
  }
1387
1555
  const filters = {
1556
+ ...Option3.isSome(runId) ? { runId: runId.value } : {},
1557
+ ...Option3.isSome(spanId) ? { spanId: spanId.value } : {},
1388
1558
  ...Option3.isSome(trace) ? { traceId: trace.value } : {},
1389
1559
  ...Option3.isSome(name) ? { name: name.value } : {},
1390
1560
  ...statusCode !== void 0 ? { status: statusCode } : {},
@@ -1411,10 +1581,10 @@ var command3 = Command5.make(
1411
1581
  isExternal: isExternalSpan(s)
1412
1582
  };
1413
1583
  });
1414
- yield* Console.log(JSON.stringify(output, null, 2));
1584
+ yield* Console2.log(JSON.stringify(output, null, 2));
1415
1585
  } else {
1416
1586
  if (spans.length === 0) {
1417
- yield* Console.log("No spans found.");
1587
+ yield* Console2.log("No spans found.");
1418
1588
  } else {
1419
1589
  const spanItems = spans.map((s) => {
1420
1590
  const endTime = getEndTime(s);
@@ -1444,28 +1614,28 @@ var command3 = Command5.make(
1444
1614
  "",
1445
1615
  ...spanItems
1446
1616
  ].join("\n");
1447
- yield* Console.log(renderDoc(doc));
1617
+ yield* Console2.log(renderDoc(doc));
1448
1618
  }
1449
1619
  }
1450
1620
  }).pipe(
1451
- Effect8.scoped,
1452
- Effect8.provide(makeReadOnlyLayer(data))
1621
+ Effect10.scoped,
1622
+ Effect10.provide(makeReadOnlyLayer(data))
1453
1623
  )
1454
- ).pipe(Command5.withDescription("List spans with optional filters"));
1455
- var command4 = Command5.make(
1624
+ ).pipe(Command6.withDescription("List spans with optional filters"));
1625
+ var command5 = Command6.make(
1456
1626
  "trace",
1457
1627
  {
1458
1628
  data: dataOption,
1459
1629
  json: jsonOption,
1460
- traceId: Argument2.string("trace-id").pipe(
1461
- Argument2.withDescription("The trace ID to display")
1630
+ traceId: Argument3.string("trace-id").pipe(
1631
+ Argument3.withDescription("The trace ID to display")
1462
1632
  )
1463
1633
  },
1464
- ({ data, json, traceId }) => Effect8.gen(function* () {
1634
+ ({ data, json, traceId }) => Effect10.gen(function* () {
1465
1635
  const storage = yield* Storage;
1466
1636
  const spans = yield* storage.getSpans({ traceId });
1467
1637
  if (spans.length === 0) {
1468
- yield* Console.log(`No spans found for trace: ${traceId}`);
1638
+ yield* Console2.log(`No spans found for trace: ${traceId}`);
1469
1639
  return;
1470
1640
  }
1471
1641
  const traces = yield* storage.getTraces({ limit: 1 });
@@ -1507,7 +1677,7 @@ var command4 = Command5.make(
1507
1677
  spanCount: spans.length,
1508
1678
  spans: roots.map((r) => buildJsonTree(graph, r.index))
1509
1679
  };
1510
- yield* Console.log(JSON.stringify(output, null, 2));
1680
+ yield* Console2.log(JSON.stringify(output, null, 2));
1511
1681
  } else {
1512
1682
  const header = [
1513
1683
  field("Trace", traceId),
@@ -1515,18 +1685,22 @@ var command4 = Command5.make(
1515
1685
  ""
1516
1686
  ].join("\n");
1517
1687
  const treeDoc = renderSpanGraph(graph);
1518
- yield* Console.log(renderDoc([header, treeDoc].filter((line) => line.length > 0).join("\n")));
1688
+ yield* Console2.log(renderDoc([header, treeDoc].filter((line) => line.length > 0).join("\n")));
1519
1689
  }
1520
1690
  }).pipe(
1521
- Effect8.scoped,
1522
- Effect8.provide(makeReadOnlyLayer(data))
1691
+ Effect10.scoped,
1692
+ Effect10.provide(makeReadOnlyLayer(data))
1523
1693
  )
1524
- ).pipe(Command5.withDescription("Show a trace as a tree view"));
1525
- var command5 = Command5.make(
1694
+ ).pipe(Command6.withDescription("Show a trace as a tree view"));
1695
+ var command6 = Command6.make(
1526
1696
  "traces",
1527
1697
  {
1528
1698
  data: dataOption,
1529
1699
  json: jsonOption,
1700
+ runId: Flag3.string("run-id").pipe(
1701
+ Flag3.withDescription("Filter by run ID"),
1702
+ Flag3.optional
1703
+ ),
1530
1704
  limit: limitOption,
1531
1705
  since: Flag3.string("since").pipe(
1532
1706
  Flag3.withDescription("Filter by time range (e.g., '1h', '30m')"),
@@ -1537,7 +1711,7 @@ var command5 = Command5.make(
1537
1711
  Flag3.optional
1538
1712
  )
1539
1713
  },
1540
- ({ data, json, limit, since, status }) => Effect8.gen(function* () {
1714
+ ({ data, json, limit, runId, since, status }) => Effect10.gen(function* () {
1541
1715
  const storage = yield* Storage;
1542
1716
  let statusCode;
1543
1717
  if (Option3.isSome(status)) {
@@ -1552,7 +1726,7 @@ var command5 = Command5.make(
1552
1726
  statusCode = 0;
1553
1727
  break;
1554
1728
  default:
1555
- yield* Effect8.logWarning(`Unknown status: ${status.value}, ignoring filter`);
1729
+ yield* Effect10.logWarning(`Unknown status: ${status.value}, ignoring filter`);
1556
1730
  }
1557
1731
  }
1558
1732
  let sinceNanos;
@@ -1562,6 +1736,7 @@ var command5 = Command5.make(
1562
1736
  sinceNanos = nowNanos - durationNanos;
1563
1737
  }
1564
1738
  const filters = {
1739
+ ...Option3.isSome(runId) ? { runId: runId.value } : {},
1565
1740
  ...statusCode !== void 0 ? { status: statusCode } : {},
1566
1741
  ...sinceNanos !== void 0 ? { since: sinceNanos } : {},
1567
1742
  ...Option3.isSome(limit) ? { limit: limit.value } : {}
@@ -1577,10 +1752,10 @@ var command5 = Command5.make(
1577
1752
  endTime: t.end_time ? formatTimestamp(t.end_time) : null,
1578
1753
  durationMs: t.end_time ? Number((t.end_time - t.start_time) / 1000000n) : null
1579
1754
  }));
1580
- yield* Console.log(JSON.stringify(output, null, 2));
1755
+ yield* Console2.log(JSON.stringify(output, null, 2));
1581
1756
  } else {
1582
1757
  if (traces.length === 0) {
1583
- yield* Console.log("No traces found.");
1758
+ yield* Console2.log("No traces found.");
1584
1759
  } else {
1585
1760
  const traceItems = traces.map((t) => {
1586
1761
  const duration = t.end_time ? formatDuration(t.end_time - t.start_time) : "running";
@@ -1598,21 +1773,24 @@ var command5 = Command5.make(
1598
1773
  "",
1599
1774
  ...traceItems
1600
1775
  ].join("\n");
1601
- yield* Console.log(renderDoc(doc));
1776
+ yield* Console2.log(renderDoc(doc));
1602
1777
  }
1603
1778
  }
1604
1779
  }).pipe(
1605
- Effect8.scoped,
1606
- Effect8.provide(makeReadOnlyLayer(data))
1780
+ Effect10.scoped,
1781
+ Effect10.provide(makeReadOnlyLayer(data))
1607
1782
  )
1608
- ).pipe(Command5.withDescription("List traces with optional filters"));
1783
+ ).pipe(Command6.withDescription("List traces with optional filters"));
1609
1784
 
1610
1785
  // src/cli.ts
1611
- var command6 = Command5.make("inspeffct").pipe(
1612
- Command5.withDescription("Inspect Effect applications without code changes"),
1613
- Command5.withSubcommands([command2, command, command5, command4, command3])
1786
+ var command7 = Command6.make("inspeffct").pipe(
1787
+ Command6.withDescription("Inspect Effect applications without code changes"),
1788
+ Command6.withSubcommands([
1789
+ { group: "Capture", commands: [command2, command] },
1790
+ { group: "Inspect", commands: [command6, command5, command4, command3] }
1791
+ ])
1614
1792
  );
1615
- var cli = Command5.runWith(command6, {
1793
+ var cli = Command6.runWith(command7, {
1616
1794
  version: "0.0.1"
1617
1795
  });
1618
1796
  var encodeRunSeparator = (args) => {
@@ -1629,6 +1807,6 @@ var run = (args) => cli(encodeRunSeparator(args));
1629
1807
 
1630
1808
  // src/bin.ts
1631
1809
  run(process.argv.slice(2)).pipe(
1632
- Effect8.provide(NodeServices.layer),
1810
+ Effect10.provide(NodeServices.layer),
1633
1811
  NodeRuntime.runMain
1634
1812
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inspeffct",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "type": "module",
5
5
  "description": "A CLI to help agents and humans inspect Effect applications",
6
6
  "license": "MIT",