@kitlangton/motel 0.2.6 → 0.2.7

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/AGENTS.md CHANGED
@@ -132,7 +132,7 @@ The repo is wired up with `@effect/language-service` as a `tsconfig.json` `plugi
132
132
 
133
133
  ## Env Vars
134
134
  - `MOTEL_OTEL_ENABLED`: defaults to `false` (set to `true` to emit self-traces for debugging motel itself)
135
- - `MOTEL_OTEL_SERVICE_NAME`: defaults to `motel-otel-tui`
135
+ - `MOTEL_OTEL_SERVICE_NAME`: defaults to `motel-otel-tui`; a nonblank explicit value also selects the initial TUI service, overriding the remembered selection (unset or blank values keep the remembered selection)
136
136
  - `MOTEL_OTEL_BASE_URL`: defaults to `http://127.0.0.1:27686`
137
137
  - `MOTEL_OTEL_HOST`: defaults to `127.0.0.1`
138
138
  - `MOTEL_OTEL_PORT`: defaults to `27686`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitlangton/motel",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "A local OpenTelemetry ingest + TUI viewer for development, backed by SQLite.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/config.ts CHANGED
@@ -22,10 +22,13 @@ const parsedBaseUrl = new URL(baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`)
22
22
  export const resolveOtelUrl = (path: string) => new URL(path.startsWith("/") ? path.slice(1) : path, parsedBaseUrl).toString()
23
23
  const serverPort = parsePositiveInt(process.env.MOTEL_OTEL_PORT, Number.parseInt(parsedBaseUrl.port || "80", 10))
24
24
 
25
+ // Preserve whether a service was requested so the TUI can override remembered state.
26
+ export const explicitServiceName = process.env.MOTEL_OTEL_SERVICE_NAME?.trim() || null
27
+
25
28
  export const config = {
26
29
  otel: {
27
30
  enabled: parseBoolean(process.env.MOTEL_OTEL_ENABLED, false),
28
- serviceName: process.env.MOTEL_OTEL_SERVICE_NAME?.trim() || "motel-otel-tui",
31
+ serviceName: explicitServiceName ?? "motel-otel-tui",
29
32
  baseUrl,
30
33
  host: process.env.MOTEL_OTEL_HOST?.trim() || parsedBaseUrl.hostname,
31
34
  port: serverPort,
package/src/ui/atoms.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as Atom from "effect/unstable/reactivity/Atom"
2
- import { config } from "../config.ts"
2
+ import { config, explicitServiceName } from "../config.ts"
3
3
  import type { LogItem, TraceItem, TraceSummaryItem } from "../domain.ts"
4
4
  import type { ThemeName } from "./theme.ts"
5
5
  import { readLastService, readLastTheme } from "./persistence.ts"
@@ -77,7 +77,7 @@ export const logStateAtom = Atom.make(initialLogState).pipe(Atom.keepAlive)
77
77
  export const serviceLogStateAtom = Atom.make(initialServiceLogState).pipe(Atom.keepAlive)
78
78
  export const selectedServiceLogIndexAtom = Atom.make(0).pipe(Atom.keepAlive)
79
79
  export const selectedTraceIndexAtom = Atom.make(0).pipe(Atom.keepAlive)
80
- export const selectedTraceServiceAtom = Atom.make<string | null>(readLastService() ?? config.otel.serviceName).pipe(Atom.keepAlive)
80
+ export const selectedTraceServiceAtom = Atom.make<string | null>(explicitServiceName ?? readLastService() ?? config.otel.serviceName).pipe(Atom.keepAlive)
81
81
  export const refreshNonceAtom = Atom.make(0).pipe(Atom.keepAlive)
82
82
  export const noticeAtom = Atom.make<string | null>(null).pipe(Atom.keepAlive)
83
83
  export const selectedSpanIndexAtom = Atom.make<number | null>(null).pipe(Atom.keepAlive)
@@ -0,0 +1,50 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs"
3
+ import { tmpdir } from "node:os"
4
+ import { join } from "node:path"
5
+
6
+ describe("initial TUI service selection", () => {
7
+ for (const remembered of [undefined, "svc-b", " \n"]) {
8
+ for (const explicit of [undefined, "", " \t ", "svc-a", " svc-a ", "motel-otel-tui"]) {
9
+ test(`env=${JSON.stringify(explicit)}, remembered=${JSON.stringify(remembered)}`, () => {
10
+ const dir = mkdtempSync(join(tmpdir(), "motel-service-selection-"))
11
+ try {
12
+ if (remembered !== undefined) writeFileSync(join(dir, "last-service.txt"), remembered)
13
+ const env = { ...process.env }
14
+ for (const key of Object.keys(env)) {
15
+ if (key.startsWith("MOTEL_")) delete env[key]
16
+ }
17
+ env.MOTEL_RUNTIME_DIR = dir
18
+ env.MOTEL_OTEL_DB_PATH = join(dir, "telemetry.sqlite")
19
+ if (explicit !== undefined) env.MOTEL_OTEL_SERVICE_NAME = explicit
20
+
21
+ // Fresh processes exercise import-time config and persistence without module-cache leakage.
22
+ const result = Bun.spawnSync([process.execPath, "--no-env-file", "--eval", `
23
+ import * as AtomRegistry from "effect/unstable/reactivity/AtomRegistry"
24
+ import { config } from "./src/config.ts"
25
+ import { selectedTraceServiceAtom } from "./src/ui/atoms.ts"
26
+ const registry = AtomRegistry.make()
27
+ const initial = registry.get(selectedTraceServiceAtom)
28
+ registry.set(selectedTraceServiceAtom, "switched-service")
29
+ console.log(JSON.stringify({
30
+ initial,
31
+ serviceName: config.otel.serviceName,
32
+ switched: registry.get(selectedTraceServiceAtom),
33
+ }))
34
+ registry.dispose()
35
+ `], { cwd: join(import.meta.dir, "../.."), env, timeout: 5_000 })
36
+
37
+ expect(result.exitCode).toBe(0)
38
+ expect(result.stderr.toString()).toBe("")
39
+ expect(JSON.parse(result.stdout.toString())).toEqual({
40
+ initial: explicit?.trim() || remembered?.trim() || "motel-otel-tui",
41
+ serviceName: explicit?.trim() || "motel-otel-tui",
42
+ switched: "switched-service",
43
+ })
44
+ } finally {
45
+ rmSync(dir, { recursive: true, force: true })
46
+ }
47
+ })
48
+ }
49
+ }
50
+ })