Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.git
.reference
.local
node_modules
dist
web/dist
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
branches:
- main
pull_request:

permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Typecheck
run: bun run typecheck

- name: Typecheck web
run: bun run web:typecheck

- name: Test
run: bun run test
15 changes: 12 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ on:
workflow_dispatch:

permissions:
contents: read
contents: write
id-token: write # required for npm Trusted Publishing (OIDC)

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

# npm Trusted Publishing requires npm >= 11.5.1 and Node >= 22.14.
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
Expand All @@ -35,7 +35,16 @@ jobs:
- name: Test
run: bun run test

- name: Validate package
run: bun run release:validate

# npm publish runs `prepublishOnly` (bun run web:build) automatically,
# so we don't need an explicit build step.
- name: Publish (OIDC, no token)
run: npm publish --provenance

- name: Create GitHub release
if: github.ref_type == 'tag'
env:
GH_TOKEN: ${{ github.token }}
run: gh release create "${GITHUB_REF_NAME}" --generate-notes --latest
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ node_modules/
.otel-data/
.motel-data/
web/dist/
.local/
dist/
.reference/
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ The repo is wired up with `@effect/language-service` as a `tsconfig.json` `plugi

## Env Vars
- `MOTEL_OTEL_ENABLED`: defaults to `false` (set to `true` to emit self-traces for debugging motel itself)
- `MOTEL_OTEL_SERVICE_NAME`: defaults to `motel-otel-tui`
- `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)
- `MOTEL_OTEL_BASE_URL`: defaults to `http://127.0.0.1:27686`
- `MOTEL_OTEL_HOST`: defaults to `127.0.0.1`
- `MOTEL_OTEL_PORT`: defaults to `27686`
Expand Down
583 changes: 271 additions & 312 deletions bun.lock

Large diffs are not rendered by default.

216 changes: 117 additions & 99 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,101 +1,119 @@
{
"name": "@executor-js/motel",
"version": "0.2.5-executor.1",
"description": "A local OpenTelemetry ingest + TUI viewer for development, backed by SQLite. (Executor fork of @kitlangton/motel)",
"type": "module",
"license": "MIT",
"author": "Kit Langton",
"repository": {
"type": "git",
"url": "https://github.com/UsefulSoftwareCo/motel.git"
},
"homepage": "https://github.com/kitlangton/motel#readme",
"bugs": {
"url": "https://github.com/kitlangton/motel/issues"
},
"keywords": [
"opentelemetry",
"otel",
"tracing",
"observability",
"tui",
"sqlite",
"effect",
"opentui"
],
"workspaces": [
"web"
],
"engines": {
"bun": ">=1.1.0"
},
"publishConfig": {
"access": "public"
},
"files": [
"src",
"web/dist",
"LICENSE",
"README.md",
"AGENTS.md"
],
"bin": {
"motel": "src/motel.ts",
"motel-mcp": "src/mcp.ts"
},
"scripts": {
"clear-motel-debug": "bun run skills/motel-debug/scripts/clear-motel-debug.ts",
"dev": "MOTEL_OTEL_ENABLED=true bun run src/motel.ts tui",
"start": "bun run src/motel.ts tui",
"daemon": "bun run src/motel.ts daemon",
"status": "bun run src/motel.ts status",
"stop": "bun run src/motel.ts stop",
"restart": "bun run src/motel.ts restart",
"server": "bun run src/motel.ts server",
"mcp": "bun run src/mcp.ts",
"test": "bun test",
"cli": "bun run src/cli.ts",
"instructions": "bun run src/cli.ts instructions",
"services": "bun run src/cli.ts services",
"logs": "bun run src/cli.ts logs",
"trace-logs": "bun run src/cli.ts trace-logs",
"span-logs": "bun run src/cli.ts span-logs",
"span": "bun run src/cli.ts span",
"trace-spans": "bun run src/cli.ts trace-spans",
"search-spans": "bun run src/cli.ts search-spans",
"trace-stats": "bun run src/cli.ts trace-stats",
"log-stats": "bun run src/cli.ts log-stats",
"web:dev": "bun run --cwd web dev",
"web:build": "bun run --cwd web build",
"story:chat": "bun run src/storybook/aiChatStory.tsx",
"bench:motel-cold-start": "bun run scripts/bench-motel-cold-start.ts",
"bench:ingest-logs": "bun run scripts/bench-ingest-logs.ts",
"bench:ingest-traces": "bun run scripts/bench-ingest-traces.ts",
"bench:search-spans": "bun run scripts/bench-search-spans.ts",
"typecheck": "tsc --noEmit",
"prepublishOnly": "bun run web:build"
},
"devDependencies": {
"@effect/language-service": "^0.85.1",
"@types/bun": "^1.3.12",
"@types/react": "^19.2.14",
"typescript": "^6.0.2"
},
"dependencies": {
"@effect/atom-react": "^4.0.0-beta.49",
"@effect/opentelemetry": "^4.0.0-beta.49",
"@effect/platform-bun": "^4.0.0-beta.50",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.214.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.211.0",
"@opentelemetry/sdk-logs": "^0.214.0",
"@opentelemetry/sdk-node": "^0.214.0",
"@opentelemetry/sdk-trace-base": "^2.5.0",
"@opentelemetry/sdk-trace-node": "^2.6.1",
"@opentui/core": "^0.1.99",
"@opentui/react": "^0.1.99",
"effect": "^4.0.0-beta.49",
"react": "^19.2.5",
"scheduler": "^0.27.0"
}
"name": "@executor-js/motel",
"version": "0.2.8-executor.1",
"description": "A local OpenTelemetry collector and viewer, with Bun and workerd runtimes.",
"type": "module",
"license": "MIT",
"author": "Kit Langton",
"repository": {
"type": "git",
"url": "https://github.com/UsefulSoftwareCo/motel.git"
},
"homepage": "https://github.com/kitlangton/motel#readme",
"bugs": {
"url": "https://github.com/kitlangton/motel/issues"
},
"keywords": [
"opentelemetry",
"otel",
"tracing",
"observability",
"tui",
"sqlite",
"effect",
"opentui"
],
"workspaces": [
"web"
],
"engines": {
"bun": ">=1.3.0"
},
"publishConfig": {
"access": "public"
},
"overrides": {
"@grpc/grpc-js": "1.14.4",
"protobufjs": "7.6.4",
"shell-quote": "1.9.0",
"ws": "8.21.0"
},
"files": [
"src",
"web/dist",
"skills/motel-debug/SKILL.md",
"skills/motel-debug/references/effect.md",
"LICENSE",
"README.md",
"AGENTS.md"
],
"bin": {
"motel": "src/motel.ts",
"motel-mcp": "src/mcp.ts"
},
"scripts": {
"clear-motel-debug": "bun run skills/motel-debug/scripts/clear-motel-debug.ts",
"dev": "MOTEL_OTEL_ENABLED=true bun run src/motel.ts tui",
"start": "bun run src/motel.ts tui",
"daemon": "bun run src/motel.ts daemon",
"status": "bun run src/motel.ts status",
"stop": "bun run src/motel.ts stop",
"restart": "bun run src/motel.ts restart",
"server": "bun run src/motel.ts server",
"mcp": "bun run src/mcp.ts",
"test": "bun run web:build && bun run workerd:build && bun test",
"cli": "bun run src/cli.ts",
"instructions": "bun run src/cli.ts instructions",
"services": "bun run src/cli.ts services",
"logs": "bun run src/cli.ts logs",
"trace-logs": "bun run src/cli.ts trace-logs",
"span-logs": "bun run src/cli.ts span-logs",
"span": "bun run src/cli.ts span",
"trace-spans": "bun run src/cli.ts trace-spans",
"search-spans": "bun run src/cli.ts search-spans",
"trace-stats": "bun run src/cli.ts trace-stats",
"log-stats": "bun run src/cli.ts log-stats",
"web:dev": "bun run --cwd web dev",
"web:build": "bun run --cwd web build",
"story:chat": "bun run src/storybook/aiChatStory.tsx",
"bench:motel-cold-start": "bun run scripts/bench-motel-cold-start.ts",
"bench:ingest-logs": "bun run scripts/bench-ingest-logs.ts",
"bench:ingest-traces": "bun run scripts/bench-ingest-traces.ts",
"bench:search-spans": "bun run scripts/bench-search-spans.ts",
"release:validate": "bun run scripts/validate-release.ts",
"typecheck": "tsc --noEmit",
"web:typecheck": "tsc --noEmit -p web/tsconfig.json",
"prepublishOnly": "bun run web:build",
"workerd:build": "bun run scripts/build-workerd.ts",
"workerd:serve": "workerd serve workerd/motel.capnp --experimental",
"workerd:test": "bun run web:build && bun run workerd:build && bun test src/workerd.integration.test.ts"
},
"devDependencies": {
"@cloudflare/workers-types": "5.20260923.1",
"@effect/language-service": "^0.86.2",
"@types/bun": "^1.3.14",
"@types/react": "^19.2.17",
"esbuild": "0.28.2",
"typescript": "^6.0.3",
"workerd": "1.20260901.1"
},
"dependencies": {
"@effect/atom-react": "4.0.0-beta.90",
"@effect/opentelemetry": "4.0.0-beta.90",
"@effect/platform-bun": "4.0.0-beta.90",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
"@opentelemetry/otlp-transformer": "0.214.0",
"@opentelemetry/sdk-logs": "^0.219.0",
"@opentelemetry/sdk-node": "^0.219.0",
"@opentelemetry/sdk-trace-base": "^2.8.0",
"@opentelemetry/sdk-trace-node": "^2.8.0",
"@opentui/core": "0.4.2",
"@opentui/react": "0.4.2",
"effect": "4.0.0-beta.90",
"protobufjs": "7.6.4",
"react": "^19.2.7",
"scheduler": "^0.27.0"
}
}
2 changes: 1 addition & 1 deletion scripts/bench-ingest-logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const runOne = async (seed: number): Promise<Sample> => {
const payload = makePayload(seed)
const startedAt = performance.now()
const result = await loaded.storeRuntime.runPromise(
Effect.flatMap(loaded.TelemetryStore.asEffect(), (store) => store.ingestLogs(payload)).pipe(
Effect.flatMap(loaded.TelemetryStore, (store) => store.ingestLogs(payload)).pipe(
Effect.provideService(References.MinimumLogLevel, "None"),
),
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/bench-ingest-traces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ const runOne = async (seed: number): Promise<Sample> => {
const payload = makePayload(seed)
const startedAt = performance.now()
const result = await loaded.storeRuntime.runPromise(
Effect.flatMap(loaded.TelemetryStore.asEffect(), (store) => store.ingestTraces(payload)).pipe(
Effect.flatMap(loaded.TelemetryStore, (store) => store.ingestTraces(payload)).pipe(
Effect.provideService(References.MinimumLogLevel, "None"),
),
)
Expand Down
4 changes: 2 additions & 2 deletions scripts/bench-search-spans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const seedStore = async (
const traceCount = Math.min(batchSize, traces - start)
const payload = makeTraceBatch(start, traceCount, startedAtNanos)
await storeRuntime.runPromise(
Effect.flatMap(TelemetryStore.asEffect(), (store) => store.ingestTraces(payload)).pipe(
Effect.flatMap(TelemetryStore, (store) => store.ingestTraces(payload)).pipe(
Effect.provideService(References.MinimumLogLevel, "None"),
),
)
Expand All @@ -134,7 +134,7 @@ const seedStore = async (
const runOne = async (loaded: LoadedRuntime): Promise<Sample> => {
const startedAt = performance.now()
const result = await loaded.queryRuntime.runPromise(
Effect.flatMap(loaded.TelemetryStoreReadonly.asEffect(), (store) =>
Effect.flatMap(loaded.TelemetryStoreReadonly, (store) =>
store.searchSpans({
serviceName: "bench-api",
operation: "search.target",
Expand Down
33 changes: 33 additions & 0 deletions scripts/build-workerd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { build } from "esbuild"
import { mkdir, readFile } from "node:fs/promises"
import { fileURLToPath } from "node:url"
const root = fileURLToPath(new URL("../", import.meta.url))
const docs = {
debug: await readFile(`${root}skills/motel-debug/SKILL.md`, "utf8"),
effect: await readFile(`${root}skills/motel-debug/references/effect.md`, "utf8"),
}
await mkdir(`${root}.local/workerd-data`, { recursive: true })
await build({
absWorkingDir: root,
entryPoints: ["src/workerd.ts"],
outfile: "dist/workerd/motel.mjs",
bundle: true,
format: "esm",
platform: "browser",
target: "es2022",
conditions: ["workerd"],
external: ["node:*", "cloudflare:*"],
minify: true,
sourcemap: "external",
sourcesContent: false,
legalComments: "external",
plugins: [
{
name: "motel-documents",
setup(builder) {
builder.onResolve({ filter: /^motel:documents$/ }, () => ({ path: "documents", namespace: "motel" }))
builder.onLoad({ filter: /.*/, namespace: "motel" }, () => ({ contents: `export default ${JSON.stringify(docs)}`, loader: "js" }))
},
},
],
})
Loading
Loading