tomo-ai 0.8.10 → 0.8.12
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/CHANGELOG.md +24 -0
- package/README.md +15 -1
- package/contrib/observability/README.md +90 -0
- package/contrib/observability/alloy/config.alloy +53 -0
- package/contrib/observability/docker-compose.yml +70 -0
- package/contrib/observability/grafana/dashboards/tomo.json +328 -0
- package/contrib/observability/grafana/provisioning/dashboards/dashboards.yml +8 -0
- package/contrib/observability/grafana/provisioning/datasources/datasources.yml +16 -0
- package/contrib/observability/prometheus.yml +9 -0
- package/dist/agent/delivery-pipeline.d.ts.map +1 -1
- package/dist/agent/delivery-pipeline.js +8 -1
- package/dist/agent/delivery-pipeline.js.map +1 -1
- package/dist/agent/live-session.d.ts +3 -0
- package/dist/agent/live-session.d.ts.map +1 -1
- package/dist/agent/live-session.js +33 -0
- package/dist/agent/live-session.js.map +1 -1
- package/dist/agent/text-utils.d.ts +15 -10
- package/dist/agent/text-utils.d.ts.map +1 -1
- package/dist/agent/text-utils.js +17 -10
- package/dist/agent/text-utils.js.map +1 -1
- package/dist/agent/turn-runner.d.ts +3 -0
- package/dist/agent/turn-runner.d.ts.map +1 -1
- package/dist/agent/turn-runner.js +32 -12
- package/dist/agent/turn-runner.js.map +1 -1
- package/dist/agent.d.ts +13 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +68 -1
- package/dist/agent.js.map +1 -1
- package/dist/channels/heic.d.ts +21 -0
- package/dist/channels/heic.d.ts.map +1 -0
- package/dist/channels/heic.js +107 -0
- package/dist/channels/heic.js.map +1 -0
- package/dist/channels/imessage-dedupe.d.ts +9 -0
- package/dist/channels/imessage-dedupe.d.ts.map +1 -1
- package/dist/channels/imessage-dedupe.js +18 -0
- package/dist/channels/imessage-dedupe.js.map +1 -1
- package/dist/channels/imessage-imsg.d.ts +194 -0
- package/dist/channels/imessage-imsg.d.ts.map +1 -0
- package/dist/channels/imessage-imsg.js +1298 -0
- package/dist/channels/imessage-imsg.js.map +1 -0
- package/dist/channels/imessage.d.ts.map +1 -1
- package/dist/channels/imessage.js +8 -4
- package/dist/channels/imessage.js.map +1 -1
- package/dist/channels/imsg-satellite.d.ts +56 -0
- package/dist/channels/imsg-satellite.d.ts.map +1 -0
- package/dist/channels/imsg-satellite.js +107 -0
- package/dist/channels/imsg-satellite.js.map +1 -0
- package/dist/channels/index.d.ts +1 -0
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +1 -0
- package/dist/channels/index.js.map +1 -1
- package/dist/channels/telegram.d.ts +2 -0
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +73 -1
- package/dist/channels/telegram.js.map +1 -1
- package/dist/cli/config/channels.d.ts.map +1 -1
- package/dist/cli/config/channels.js +45 -4
- package/dist/cli/config/channels.js.map +1 -1
- package/dist/cli/config/identities.js +1 -1
- package/dist/cli/config/identities.js.map +1 -1
- package/dist/cli/start.js +62 -2
- package/dist/cli/start.js.map +1 -1
- package/dist/cli/status.js +2 -2
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/watch.d.ts +3 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +15 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +38 -1
- package/dist/config.js.map +1 -1
- package/dist/continuity.d.ts +4 -0
- package/dist/continuity.d.ts.map +1 -1
- package/dist/continuity.js +15 -1
- package/dist/continuity.js.map +1 -1
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/scheduler.js +3 -0
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +32 -0
- package/dist/logger.js.map +1 -1
- package/dist/metrics/activity-log.d.ts +46 -0
- package/dist/metrics/activity-log.d.ts.map +1 -0
- package/dist/metrics/activity-log.js +103 -0
- package/dist/metrics/activity-log.js.map +1 -0
- package/dist/metrics/exporter.d.ts +58 -0
- package/dist/metrics/exporter.d.ts.map +1 -0
- package/dist/metrics/exporter.js +255 -0
- package/dist/metrics/exporter.js.map +1 -0
- package/dist/runtime-paths.d.ts +1 -0
- package/dist/runtime-paths.d.ts.map +1 -1
- package/dist/runtime-paths.js +1 -0
- package/dist/runtime-paths.js.map +1 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +16 -0
- package/dist/sessions/store.js.map +1 -1
- package/dist/watch/bus.d.ts +36 -0
- package/dist/watch/bus.d.ts.map +1 -0
- package/dist/watch/bus.js +44 -0
- package/dist/watch/bus.js.map +1 -0
- package/dist/watch/client.d.ts +31 -0
- package/dist/watch/client.d.ts.map +1 -0
- package/dist/watch/client.js +101 -0
- package/dist/watch/client.js.map +1 -0
- package/dist/watch/protocol.d.ts +144 -0
- package/dist/watch/protocol.d.ts.map +1 -0
- package/dist/watch/protocol.js +20 -0
- package/dist/watch/protocol.js.map +1 -0
- package/dist/watch/server.d.ts +41 -0
- package/dist/watch/server.d.ts.map +1 -0
- package/dist/watch/server.js +161 -0
- package/dist/watch/server.js.map +1 -0
- package/dist/watch/snapshot.d.ts +22 -0
- package/dist/watch/snapshot.d.ts.map +1 -0
- package/dist/watch/snapshot.js +43 -0
- package/dist/watch/snapshot.js.map +1 -0
- package/dist/watch/tui/app.d.ts +7 -0
- package/dist/watch/tui/app.d.ts.map +1 -0
- package/dist/watch/tui/app.js +135 -0
- package/dist/watch/tui/app.js.map +1 -0
- package/dist/watch/tui/feed.d.ts +12 -0
- package/dist/watch/tui/feed.d.ts.map +1 -0
- package/dist/watch/tui/feed.js +58 -0
- package/dist/watch/tui/feed.js.map +1 -0
- package/dist/watch/tui/format.d.ts +12 -0
- package/dist/watch/tui/format.d.ts.map +1 -0
- package/dist/watch/tui/format.js +58 -0
- package/dist/watch/tui/format.js.map +1 -0
- package/dist/watch/tui/header.d.ts +7 -0
- package/dist/watch/tui/header.d.ts.map +1 -0
- package/dist/watch/tui/header.js +15 -0
- package/dist/watch/tui/header.js.map +1 -0
- package/dist/watch/tui/index.d.ts +3 -0
- package/dist/watch/tui/index.d.ts.map +1 -0
- package/dist/watch/tui/index.js +24 -0
- package/dist/watch/tui/index.js.map +1 -0
- package/dist/watch/tui/log-tail.d.ts +6 -0
- package/dist/watch/tui/log-tail.d.ts.map +1 -0
- package/dist/watch/tui/log-tail.js +73 -0
- package/dist/watch/tui/log-tail.js.map +1 -0
- package/dist/watch/tui/model.d.ts +69 -0
- package/dist/watch/tui/model.d.ts.map +1 -0
- package/dist/watch/tui/model.js +268 -0
- package/dist/watch/tui/model.js.map +1 -0
- package/dist/watch/tui/sidebar.d.ts +8 -0
- package/dist/watch/tui/sidebar.d.ts.map +1 -0
- package/dist/watch/tui/sidebar.js +31 -0
- package/dist/watch/tui/sidebar.js.map +1 -0
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.12 (2026-07-12)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **Prometheus metrics + activity log with Grafana stack** (#238). Two new `WatchBus` subscribers, gated by `config.metrics` (default off): a `prom-client` exporter on `127.0.0.1:9464` (turns, cost, per-session context, tool calls, cron, heartbeats, compactions) and an NDJSON activity log at `~/.tomo/logs/activity.ndjson` for Loki tailing (transcript text local-only, redactable via `metrics.includeMessageText=false`). `contrib/observability/` ships a docker-compose stack (Prometheus, Loki, Alloy, Grafana) with a provisioned Tomo dashboard.
|
|
8
|
+
|
|
9
|
+
### Dependencies
|
|
10
|
+
|
|
11
|
+
- Bump `@anthropic-ai/claude-agent-sdk` 0.3.201 → 0.3.207 (#237).
|
|
12
|
+
- Bump the dev-dependencies group (#236). The TypeScript ^6 → ^7 bump in that group was reverted — no `typescript-eslint` release yet supports TypeScript 7 (peer range caps at `<6.1.0`), so it broke `npm ci`.
|
|
13
|
+
|
|
14
|
+
## 0.8.11 (2026-07-09)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **`imsg`-backed iMessage channel (BlueBubbles successor)** (#230, #231, #232, #234). A new `ImsgChannel` (`src/channels/imessage-imsg.ts`) implements the `Channel` surface over a single long-lived `imsg rpc` child (newline-delimited JSON-RPC 2.0 on stdio), selectable via `channels.imessage.provider: "imsg"` without touching the BlueBubbles channel. Inbound uses the `watch.subscribe` all-chat stream with attachments (local file paths), reply context, inbound tapbacks, slash commands, and group/DM mapping; outbound covers chunked sends, threaded replies via `send.rich` (with plain-send fallback), attachments, targeted tapbacks, typing indicators, mark-read, and unsend. Message edit is gated on the `imsg status --json` bridge selector probe, so on macOS 26 (where the edit selectors are gone OS-wide) the channel refuses cleanly instead of crashing Messages. The child restarts on crash with escalating backoff and resumes the watch from a persisted rowid cursor, and persistent GUID dedupe is shared with the BlueBubbles store so a provider cutover never re-dispatches messages. Session keys stay compatible — chat.db chat GUIDs are used verbatim (identical to what BlueBubbles reported), so existing session mappings survive. Inbound HEIC/HEIF attachments that `imsg` doesn't pre-convert are normalized to JPEG channel-side via macOS `sips` (by mime, `.heic`/`.heif` extension, or `ftyp` magic-byte sniff), read-only-safe (converts into a temp JPEG that is read then unlinked) and never dropped on conversion failure.
|
|
19
|
+
- **`tomo watch` — live mission-control TUI** (#229). An always-on terminal dashboard for watching what Tomo is doing, backed by a daemon-side event bus. `src/watch/bus.ts` is an in-process `WatchBus` singleton with a ring buffer, fed by emit hooks in `SessionStore.append` (inbound/outbound messages), `LiveSession` (tool start/end with durations, compact boundaries), `TurnRunner` (turn start/end with ingress source), the per-turn cost/context stats closure, `CronScheduler`, `ContinuityRunner`, and a pino tap (warn/error → "issue" events). `server.ts` serves NDJSON over `~/.tomo/watch.sock` (0600) — a snapshot on connect (vitals, cron next-runs, cost 24h/7d, feed backfill), then live relay; inbound "send" frames route chat into the dm session. The Ink/React TUI renders an activity feed (messages, tools with status + duration, turn summaries with cost + ctx%, cron, heartbeats), a pinned in-flight turn line, a vitals sidebar (context gauge, cost, next-up, last warn/error), a chat line, a raw-log-tail toggle, a group-traffic filter, scroll with follow mode, and a help overlay. Auto-reconnects with an offline header state and drops to a 15s idle render tick so it can stay open 24/7. The daemon never depends on clients.
|
|
20
|
+
|
|
21
|
+
### Bug fixes
|
|
22
|
+
|
|
23
|
+
- **Trailing `NO_REPLY` suppresses the whole block/turn** (#233). A reply whose final line(s) are a bare `NO_REPLY` is now suppressed entirely instead of delivering the stripped remainder — the agent narrates housekeeping turns and ends them with `NO_REPLY`, and that narration (sometimes including the literal `NO_REPLY` text) previously leaked to the channel (owner decision 2026-07-08: trailing `NO_REPLY` marks the whole response as not-for-the-channel). `agent/text-utils` gains `endsWithTrailingNoReply()` (`stripTrailingNoReply` stays exported for the watch TUI, which still shows the visible text); `TurnRunner.runSendTurn` (cron/continuity) silences the entire turn; imsg and BlueBubbles streaming drop a block whose trailing line is bare `NO_REPLY`; and Telegram streaming retracts the already-streamed message before the multi-part delivery path. Follow-up rounds close the Telegram over-4096 rollover gaps: finalized rollover head chunks are now deleted and un-recorded (new `forgetOwnMessage`) on every block-abandoning path (`finalFlush` suppression, multi-part re-delivery, `discardBlock`, `cancel`), suppression is judged on the full block buffer rather than the post-rollover slice, and attachment blocks (`MEDIA:`/`STICKER:`) are suppressed as a whole.
|
|
24
|
+
- **iMessage inbound reply context only for genuine threaded replies** (#234). Since the imsg cutover, nearly every inbound iMessage arrived tagged `[replying to: "..."]` even when the sender never used long-press → Reply, because the channel fell back to `reply_to_guid` — a chat.db column populated on almost every row (it points at the preceding message, usually our own last outbound; verified 186/186 inbound DM rows over 3 days carried it, vs. 7 with a genuine thread originator). The reply marker is now gated on `thread_originator_guid` only, with fallback to the recent-message ring and then a quote-less marker. Outbound threading and tapback handling are untouched.
|
|
25
|
+
- **imsg channel post-merge review fixes** (#232). `stop()` no longer leaves in-flight requests hanging forever — `killChild()` now rejects pending requests before nulling the child. A failed row with no numeric rowid (parsed as `0`) no longer wedges the cursor floor permanently — it is logged and skipped. A write parked on `drain` now settles when its response arrives (the response proves the child consumed the line), so a healthy answering child is never killed by the drain backstop. A temp JPEG from a failed HEIC conversion is unlinked instead of leaking.
|
|
26
|
+
|
|
3
27
|
## 0.8.10 (2026-07-06)
|
|
4
28
|
|
|
5
29
|
### Features
|
package/README.md
CHANGED
|
@@ -108,11 +108,12 @@ Tomo keeps person records at `~/.tomo/workspace/memory/people/*.md` — canonica
|
|
|
108
108
|
- Image/photo support (sends to Claude as vision input)
|
|
109
109
|
- Group chat: defaults to mention-required (only responds when @mentioned or replied to); per-group passive listen mode opt-in via `channels.telegram.passiveGroups`
|
|
110
110
|
- Markdown rendering with plain-text fallback
|
|
111
|
-
- **iMessage** — via [BlueBubbles](https://bluebubbles.app)
|
|
111
|
+
- **iMessage** — via [BlueBubbles](https://bluebubbles.app) (default) or the [imsg CLI](https://github.com/openclaw/imsg) (`channels.imessage.provider: "imsg"`)
|
|
112
112
|
- DM and group chat support
|
|
113
113
|
- Image attachment support
|
|
114
114
|
- Contact name resolution from Mac contacts
|
|
115
115
|
- Group chat: observes all messages, only responds when relevant (replies `NO_REPLY` to stay silent)
|
|
116
|
+
- imsg provider: no external server — Tomo spawns one `imsg rpc` child (needs Full Disk Access); adds inbound tapbacks and built-in reply context, and gates message editing on a live macOS selector probe
|
|
116
117
|
|
|
117
118
|
### Multi-Channel Sessions
|
|
118
119
|
|
|
@@ -291,6 +292,16 @@ Run `tomo config` for interactive setup, or edit `~/.tomo/config.json` directly:
|
|
|
291
292
|
}
|
|
292
293
|
```
|
|
293
294
|
|
|
295
|
+
To run iMessage through the local [imsg CLI](https://github.com/openclaw/imsg) instead of a BlueBubbles server (the Tomo process needs Full Disk Access; advanced features additionally need `imsg launch`):
|
|
296
|
+
|
|
297
|
+
```json
|
|
298
|
+
{
|
|
299
|
+
"channels": {
|
|
300
|
+
"imessage": { "provider": "imsg", "cliPath": "/opt/homebrew/bin/imsg", "allowlist": ["+15551234567"] }
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
294
305
|
Environment variables override config file values:
|
|
295
306
|
|
|
296
307
|
| Variable | Description |
|
|
@@ -298,6 +309,9 @@ Environment variables override config file values:
|
|
|
298
309
|
| `ANTHROPIC_API_KEY` | Use Anthropic API-key authentication; overrides the authentication stored in `config.json` |
|
|
299
310
|
| `TELEGRAM_BOT_TOKEN` | Override Telegram token |
|
|
300
311
|
| `IMESSAGE_URL` | Override BlueBubbles URL |
|
|
312
|
+
| `IMESSAGE_PROVIDER` | iMessage backend: `bluebubbles` (default) or `imsg` |
|
|
313
|
+
| `IMSG_CLI_PATH` | Path to the `imsg` binary (default: `imsg` on PATH) |
|
|
314
|
+
| `IMSG_DB_PATH` | Override chat.db path passed to `imsg rpc --db` |
|
|
301
315
|
| `IMESSAGE_TYPING_START_DELAY_MS` | Delay before showing iMessage typing for ordinary turns (default: `1200`) |
|
|
302
316
|
| `IMESSAGE_PASSIVE_TYPING_START_DELAY_MS` | Delay before showing iMessage typing for passive iMessage group turns (default: `4000`) |
|
|
303
317
|
| `CLAUDE_MODEL` | Override model |
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Tomo observability stack
|
|
2
|
+
|
|
3
|
+
A self-contained Grafana + Prometheus + Loki + Alloy stack for watching Tomo
|
|
4
|
+
from a dashboard. Data never leaves the machine: Prometheus, Loki, and Alloy
|
|
5
|
+
bind to `127.0.0.1` only. Grafana is reachable from the local network (login
|
|
6
|
+
required) so you can open the dashboard from another computer.
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
Tomo daemon ──/metrics (127.0.0.1:9464)──▶ Prometheus ──┐
|
|
10
|
+
│ ├──▶ Grafana (127.0.0.1:3000)
|
|
11
|
+
└──~/.tomo/logs/activity.ndjson──▶ Alloy ──▶ Loki ─┘
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
1. Enable metrics in `~/.tomo/config.json`:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"metrics": { "enabled": true }
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Then restart the daemon (`tomo restart`) and verify:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
curl -s localhost:9464/metrics | grep tomo_
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. Copy the stack somewhere you own, then start it (requires Docker Desktop).
|
|
31
|
+
Copying matters: run it in place and an `npm upgrade` will overwrite any
|
|
32
|
+
compose/dashboard customizations.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# from a git clone:
|
|
36
|
+
cp -r contrib/observability ~/tomo-observability
|
|
37
|
+
# or from a global npm install:
|
|
38
|
+
cp -r "$(npm root -g)/tomo-ai/contrib/observability" ~/tomo-observability
|
|
39
|
+
|
|
40
|
+
cd ~/tomo-observability
|
|
41
|
+
docker compose up -d
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Open <http://localhost:3000> — or from another computer on your network,
|
|
45
|
+
`http://<hostname>.local:3000` (e.g. `http://mac-mini.local:3000`). Sign in
|
|
46
|
+
with `admin` / `admin`; Grafana forces a password change on first login.
|
|
47
|
+
The **Tomo** dashboard is pre-provisioned.
|
|
48
|
+
|
|
49
|
+
To restrict Grafana to this machine only, change its port mapping back to
|
|
50
|
+
`"127.0.0.1:3000:3000"` in `docker-compose.yml`. For access from *outside*
|
|
51
|
+
your home network, don't port-forward — use Tailscale or similar.
|
|
52
|
+
|
|
53
|
+
## Config reference
|
|
54
|
+
|
|
55
|
+
`~/.tomo/config.json` → `metrics` (env overrides in parens):
|
|
56
|
+
|
|
57
|
+
| Key | Default | Meaning |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `enabled` (`TOMO_METRICS`) | `false` | Serve `/metrics` and write the activity log |
|
|
60
|
+
| `port` (`TOMO_METRICS_PORT`) | `9464` | Prometheus exporter port, loopback-only |
|
|
61
|
+
| `activityLog` | `true` | Write `~/.tomo/logs/activity.ndjson` for Loki |
|
|
62
|
+
| `includeMessageText` | `true` | Include transcript text in the activity log. Disable if you ever ship the log off this machine. |
|
|
63
|
+
|
|
64
|
+
## What's collected
|
|
65
|
+
|
|
66
|
+
**Prometheus** (`tomo_*`, plus standard `process_*`/`nodejs_*`): turns by
|
|
67
|
+
source/outcome, turn duration histogram, cumulative cost (USD), per-session
|
|
68
|
+
context usage, tool calls, cron runs + upcoming cron schedule, compactions,
|
|
69
|
+
heartbeats (count, last, next), warn/error issues.
|
|
70
|
+
|
|
71
|
+
**Loki** (`{job="tomo-activity"}`): every watch-bus event as structured JSON —
|
|
72
|
+
the same feed `tomo watch` renders. Labels: `type`, `session`, `level`.
|
|
73
|
+
Example queries:
|
|
74
|
+
|
|
75
|
+
```logql
|
|
76
|
+
{job="tomo-activity", type="tool.start"} # every tool call
|
|
77
|
+
{job="tomo-activity", type="transcript", session="dm:merlin"}
|
|
78
|
+
{job="tomo-activity"} | json | costUsd > 0.10 # expensive turns
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Notes
|
|
82
|
+
|
|
83
|
+
- Prometheus keeps 90 days of metrics; Loki uses its default retention.
|
|
84
|
+
Volumes (`prometheus-data`, `loki-data`, `grafana-data`) survive
|
|
85
|
+
`docker compose down`; add `-v` to wipe them.
|
|
86
|
+
- Counters reset when the daemon restarts — dashboard queries use
|
|
87
|
+
`increase()`/`rate()`, which handle resets.
|
|
88
|
+
- If `TOMO_HOME` is not `~/.tomo`, fix the Alloy volume mount in
|
|
89
|
+
`docker-compose.yml`.
|
|
90
|
+
- History starts when you enable the stack; nothing is backfilled.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Tail Tomo's NDJSON activity feed into Loki. The glob also matches rotated
|
|
2
|
+
// files (activity.ndjson.1, …) so lines written just before a rotation are
|
|
3
|
+
// still picked up if the shipper lags.
|
|
4
|
+
|
|
5
|
+
local.file_match "tomo_activity" {
|
|
6
|
+
path_targets = [{ __path__ = "/var/log/tomo/activity.ndjson*" }]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
loki.source.file "tomo_activity" {
|
|
10
|
+
targets = local.file_match.tomo_activity.targets
|
|
11
|
+
forward_to = [loki.process.tomo.receiver]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
loki.process "tomo" {
|
|
15
|
+
stage.json {
|
|
16
|
+
expressions = {
|
|
17
|
+
type = "type",
|
|
18
|
+
session = "sessionKey",
|
|
19
|
+
level = "level",
|
|
20
|
+
ts = "ts",
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Low-cardinality labels only: event type, session key, issue level.
|
|
25
|
+
// Everything else stays in the JSON body and is queryable via `| json`.
|
|
26
|
+
stage.labels {
|
|
27
|
+
values = {
|
|
28
|
+
type = "",
|
|
29
|
+
session = "",
|
|
30
|
+
level = "",
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
stage.static_labels {
|
|
35
|
+
values = {
|
|
36
|
+
job = "tomo-activity",
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Use the event's own millisecond timestamp, not ingestion time.
|
|
41
|
+
stage.timestamp {
|
|
42
|
+
source = "ts"
|
|
43
|
+
format = "UnixMs"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
forward_to = [loki.write.local.receiver]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
loki.write "local" {
|
|
50
|
+
endpoint {
|
|
51
|
+
url = "http://loki:3100/loki/api/v1/push"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Local observability stack for Tomo: Prometheus (metrics), Loki (activity
|
|
2
|
+
# feed), Alloy (log shipper), Grafana (dashboard). See README.md.
|
|
3
|
+
#
|
|
4
|
+
# Grafana listens on the LAN (with login required); everything else binds to
|
|
5
|
+
# 127.0.0.1 — Prometheus/Loki have no auth of their own, and Grafana reaches
|
|
6
|
+
# them over the internal Docker network, so they never need outside exposure.
|
|
7
|
+
services:
|
|
8
|
+
prometheus:
|
|
9
|
+
image: prom/prometheus:v3.4.1
|
|
10
|
+
ports:
|
|
11
|
+
- "127.0.0.1:9090:9090"
|
|
12
|
+
volumes:
|
|
13
|
+
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
|
14
|
+
- prometheus-data:/prometheus
|
|
15
|
+
command:
|
|
16
|
+
- --config.file=/etc/prometheus/prometheus.yml
|
|
17
|
+
- --storage.tsdb.retention.time=90d
|
|
18
|
+
extra_hosts:
|
|
19
|
+
# Docker Desktop for Mac provides host.docker.internal natively; this
|
|
20
|
+
# line makes the same name work if the stack ever runs on Linux.
|
|
21
|
+
- "host.docker.internal:host-gateway"
|
|
22
|
+
restart: unless-stopped
|
|
23
|
+
|
|
24
|
+
loki:
|
|
25
|
+
image: grafana/loki:3.5.1
|
|
26
|
+
# No host port: Grafana and Alloy reach Loki over the internal Docker
|
|
27
|
+
# network, and host 3100 is BlueBubbles' default webhook port — publishing
|
|
28
|
+
# it would collide with a default iMessage setup. To poke Loki directly:
|
|
29
|
+
# docker compose exec loki wget -qO- localhost:3100/ready
|
|
30
|
+
volumes:
|
|
31
|
+
- loki-data:/loki
|
|
32
|
+
restart: unless-stopped
|
|
33
|
+
|
|
34
|
+
alloy:
|
|
35
|
+
image: grafana/alloy:v1.9.1
|
|
36
|
+
volumes:
|
|
37
|
+
- ./alloy/config.alloy:/etc/alloy/config.alloy:ro
|
|
38
|
+
- alloy-data:/var/lib/alloy/data
|
|
39
|
+
# Tomo's activity log (metrics.activityLog). Adjust if TOMO_HOME moved.
|
|
40
|
+
- ~/.tomo/logs:/var/log/tomo:ro
|
|
41
|
+
command:
|
|
42
|
+
- run
|
|
43
|
+
- /etc/alloy/config.alloy
|
|
44
|
+
- --storage.path=/var/lib/alloy/data
|
|
45
|
+
depends_on:
|
|
46
|
+
- loki
|
|
47
|
+
restart: unless-stopped
|
|
48
|
+
|
|
49
|
+
grafana:
|
|
50
|
+
image: grafana/grafana:12.0.2
|
|
51
|
+
ports:
|
|
52
|
+
# LAN-reachable so other machines can open the dashboard. Because the
|
|
53
|
+
# activity feed can contain message text, login stays REQUIRED — first
|
|
54
|
+
# sign-in is admin/admin and Grafana forces a password change. To lock
|
|
55
|
+
# it back down to this machine only, prefix with 127.0.0.1: again.
|
|
56
|
+
- "3000:3000"
|
|
57
|
+
volumes:
|
|
58
|
+
- ./grafana/provisioning:/etc/grafana/provisioning:ro
|
|
59
|
+
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
|
|
60
|
+
- grafana-data:/var/lib/grafana
|
|
61
|
+
depends_on:
|
|
62
|
+
- prometheus
|
|
63
|
+
- loki
|
|
64
|
+
restart: unless-stopped
|
|
65
|
+
|
|
66
|
+
volumes:
|
|
67
|
+
prometheus-data:
|
|
68
|
+
loki-data:
|
|
69
|
+
alloy-data:
|
|
70
|
+
grafana-data:
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
{
|
|
2
|
+
"uid": "tomo-overview",
|
|
3
|
+
"title": "Tomo",
|
|
4
|
+
"tags": ["tomo"],
|
|
5
|
+
"schemaVersion": 39,
|
|
6
|
+
"editable": true,
|
|
7
|
+
"time": { "from": "now-24h", "to": "now" },
|
|
8
|
+
"refresh": "30s",
|
|
9
|
+
"panels": [
|
|
10
|
+
{
|
|
11
|
+
"id": 1,
|
|
12
|
+
"type": "stat",
|
|
13
|
+
"title": "Daemon",
|
|
14
|
+
"gridPos": { "h": 4, "w": 3, "x": 0, "y": 0 },
|
|
15
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
16
|
+
"targets": [{ "refId": "A", "expr": "up{job=\"tomo\"}" }],
|
|
17
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background" },
|
|
18
|
+
"fieldConfig": {
|
|
19
|
+
"defaults": {
|
|
20
|
+
"mappings": [
|
|
21
|
+
{
|
|
22
|
+
"type": "value",
|
|
23
|
+
"options": {
|
|
24
|
+
"0": { "text": "DOWN", "color": "red" },
|
|
25
|
+
"1": { "text": "UP", "color": "green" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"overrides": []
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": 2,
|
|
35
|
+
"type": "stat",
|
|
36
|
+
"title": "Cost (24h)",
|
|
37
|
+
"gridPos": { "h": 4, "w": 3, "x": 3, "y": 0 },
|
|
38
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
39
|
+
"targets": [{ "refId": "A", "expr": "sum(increase(tomo_cost_usd_total[24h]))" }],
|
|
40
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
41
|
+
"fieldConfig": { "defaults": { "unit": "currencyUSD", "decimals": 2 }, "overrides": [] }
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": 3,
|
|
45
|
+
"type": "stat",
|
|
46
|
+
"title": "Turns (24h)",
|
|
47
|
+
"gridPos": { "h": 4, "w": 3, "x": 6, "y": 0 },
|
|
48
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
49
|
+
"targets": [{ "refId": "A", "expr": "sum(increase(tomo_turns_total[24h]))" }],
|
|
50
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
51
|
+
"fieldConfig": { "defaults": { "unit": "short", "decimals": 0 }, "overrides": [] }
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": 4,
|
|
55
|
+
"type": "stat",
|
|
56
|
+
"title": "Errors (24h)",
|
|
57
|
+
"gridPos": { "h": 4, "w": 3, "x": 9, "y": 0 },
|
|
58
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
59
|
+
"targets": [
|
|
60
|
+
{ "refId": "A", "expr": "sum(increase(tomo_issues_total{level=\"error\"}[24h])) or vector(0)" }
|
|
61
|
+
],
|
|
62
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
63
|
+
"fieldConfig": {
|
|
64
|
+
"defaults": {
|
|
65
|
+
"unit": "short",
|
|
66
|
+
"decimals": 0,
|
|
67
|
+
"thresholds": {
|
|
68
|
+
"mode": "absolute",
|
|
69
|
+
"steps": [
|
|
70
|
+
{ "color": "green", "value": null },
|
|
71
|
+
{ "color": "red", "value": 1 }
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"overrides": []
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": 5,
|
|
80
|
+
"type": "stat",
|
|
81
|
+
"title": "In flight",
|
|
82
|
+
"gridPos": { "h": 4, "w": 3, "x": 12, "y": 0 },
|
|
83
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
84
|
+
"targets": [{ "refId": "A", "expr": "tomo_turns_active" }],
|
|
85
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
86
|
+
"fieldConfig": { "defaults": { "unit": "short", "decimals": 0 }, "overrides": [] }
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": 6,
|
|
90
|
+
"type": "stat",
|
|
91
|
+
"title": "Memory (RSS)",
|
|
92
|
+
"gridPos": { "h": 4, "w": 3, "x": 15, "y": 0 },
|
|
93
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
94
|
+
"targets": [{ "refId": "A", "expr": "process_resident_memory_bytes{job=\"tomo\"}" }],
|
|
95
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
96
|
+
"fieldConfig": { "defaults": { "unit": "bytes" }, "overrides": [] }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": 7,
|
|
100
|
+
"type": "stat",
|
|
101
|
+
"title": "Next heartbeat",
|
|
102
|
+
"gridPos": { "h": 4, "w": 3, "x": 18, "y": 0 },
|
|
103
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
104
|
+
"targets": [{ "refId": "A", "expr": "tomo_heartbeat_next_timestamp_seconds * 1000" }],
|
|
105
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
106
|
+
"fieldConfig": {
|
|
107
|
+
"defaults": {
|
|
108
|
+
"unit": "dateTimeFromNow",
|
|
109
|
+
"noValue": "n/a",
|
|
110
|
+
"mappings": [
|
|
111
|
+
{
|
|
112
|
+
"type": "value",
|
|
113
|
+
"options": { "0": { "text": "continuity off", "color": "text" } }
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"overrides": []
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"id": 8,
|
|
122
|
+
"type": "stat",
|
|
123
|
+
"title": "Next cron job",
|
|
124
|
+
"gridPos": { "h": 4, "w": 3, "x": 21, "y": 0 },
|
|
125
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
126
|
+
"targets": [{ "refId": "A", "expr": "min(tomo_cron_next_run_timestamp_seconds) * 1000" }],
|
|
127
|
+
"options": { "reduceOptions": { "calcs": ["lastNotNull"] } },
|
|
128
|
+
"fieldConfig": { "defaults": { "unit": "dateTimeFromNow", "noValue": "none" }, "overrides": [] }
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": 21,
|
|
132
|
+
"type": "table",
|
|
133
|
+
"title": "Upcoming cron jobs",
|
|
134
|
+
"gridPos": { "h": 9, "w": 8, "x": 0, "y": 4 },
|
|
135
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
136
|
+
"targets": [
|
|
137
|
+
{
|
|
138
|
+
"refId": "A",
|
|
139
|
+
"expr": "tomo_cron_next_run_timestamp_seconds * 1000",
|
|
140
|
+
"format": "table",
|
|
141
|
+
"instant": true
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"transformations": [
|
|
145
|
+
{
|
|
146
|
+
"id": "organize",
|
|
147
|
+
"options": {
|
|
148
|
+
"excludeByName": { "Time": true, "__name__": true, "instance": true, "job": true },
|
|
149
|
+
"renameByName": { "cron_job": "Job", "Value": "Next run" }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"options": { "sortBy": [{ "displayName": "Next run", "desc": false }] },
|
|
154
|
+
"fieldConfig": {
|
|
155
|
+
"defaults": { "unit": "dateTimeFromNow" },
|
|
156
|
+
"overrides": [
|
|
157
|
+
{
|
|
158
|
+
"matcher": { "id": "byName", "options": "Job" },
|
|
159
|
+
"properties": [{ "id": "unit", "value": "string" }]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": 22,
|
|
166
|
+
"type": "logs",
|
|
167
|
+
"title": "Tool calls",
|
|
168
|
+
"gridPos": { "h": 9, "w": 16, "x": 8, "y": 4 },
|
|
169
|
+
"datasource": { "type": "loki", "uid": "loki" },
|
|
170
|
+
"targets": [
|
|
171
|
+
{
|
|
172
|
+
"refId": "A",
|
|
173
|
+
"expr": "{job=\"tomo-activity\", type=\"tool.start\"} | json | line_format \"{{.tool}}{{if .agent}} [{{.agent}}]{{end}}{{if .detail}} — {{.detail}}{{end}}\""
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"refId": "B",
|
|
177
|
+
"expr": "{job=\"tomo-activity\", type=\"tool.end\"} | json | ok=\"false\" | line_format \"{{.tool}} FAILED{{if .durationMs}} after {{.durationMs}}ms{{end}}\""
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"options": {
|
|
181
|
+
"showTime": true,
|
|
182
|
+
"sortOrder": "Descending",
|
|
183
|
+
"wrapLogMessage": true,
|
|
184
|
+
"enableLogDetails": true,
|
|
185
|
+
"dedupStrategy": "none"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"id": 10,
|
|
190
|
+
"type": "timeseries",
|
|
191
|
+
"title": "Cost per hour",
|
|
192
|
+
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 13 },
|
|
193
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
194
|
+
"targets": [
|
|
195
|
+
{ "refId": "A", "expr": "sum(increase(tomo_cost_usd_total[1h]))", "legendFormat": "USD/h" }
|
|
196
|
+
],
|
|
197
|
+
"fieldConfig": { "defaults": { "unit": "currencyUSD" }, "overrides": [] }
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"id": 11,
|
|
201
|
+
"type": "timeseries",
|
|
202
|
+
"title": "Turns per hour by source",
|
|
203
|
+
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 13 },
|
|
204
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
205
|
+
"targets": [
|
|
206
|
+
{
|
|
207
|
+
"refId": "A",
|
|
208
|
+
"expr": "sum by (source) (increase(tomo_turns_total[1h]))",
|
|
209
|
+
"legendFormat": "{{source}}"
|
|
210
|
+
}
|
|
211
|
+
],
|
|
212
|
+
"fieldConfig": {
|
|
213
|
+
"defaults": { "unit": "short", "custom": { "stacking": { "mode": "normal" } } },
|
|
214
|
+
"overrides": []
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": 12,
|
|
219
|
+
"type": "timeseries",
|
|
220
|
+
"title": "Turn duration (p50 / p95)",
|
|
221
|
+
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 21 },
|
|
222
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
223
|
+
"targets": [
|
|
224
|
+
{
|
|
225
|
+
"refId": "A",
|
|
226
|
+
"expr": "histogram_quantile(0.5, sum by (le) (rate(tomo_turn_duration_seconds_bucket[$__rate_interval])))",
|
|
227
|
+
"legendFormat": "p50"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"refId": "B",
|
|
231
|
+
"expr": "histogram_quantile(0.95, sum by (le) (rate(tomo_turn_duration_seconds_bucket[$__rate_interval])))",
|
|
232
|
+
"legendFormat": "p95"
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"fieldConfig": { "defaults": { "unit": "s" }, "overrides": [] }
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"id": 13,
|
|
239
|
+
"type": "timeseries",
|
|
240
|
+
"title": "Context usage by session",
|
|
241
|
+
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 21 },
|
|
242
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
243
|
+
"targets": [
|
|
244
|
+
{
|
|
245
|
+
"refId": "A",
|
|
246
|
+
"expr": "tomo_context_used_tokens / on(session) tomo_context_max_tokens",
|
|
247
|
+
"legendFormat": "{{session}}"
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
"fieldConfig": {
|
|
251
|
+
"defaults": { "unit": "percentunit", "min": 0, "max": 1 },
|
|
252
|
+
"overrides": []
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"id": 14,
|
|
257
|
+
"type": "timeseries",
|
|
258
|
+
"title": "Tool calls per hour",
|
|
259
|
+
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 29 },
|
|
260
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
261
|
+
"targets": [
|
|
262
|
+
{
|
|
263
|
+
"refId": "A",
|
|
264
|
+
"expr": "sum by (tool) (increase(tomo_tool_calls_total[1h]))",
|
|
265
|
+
"legendFormat": "{{tool}}"
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
"fieldConfig": {
|
|
269
|
+
"defaults": { "unit": "short", "custom": { "stacking": { "mode": "normal" } } },
|
|
270
|
+
"overrides": []
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"id": 15,
|
|
275
|
+
"type": "timeseries",
|
|
276
|
+
"title": "Messages per hour by channel",
|
|
277
|
+
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 29 },
|
|
278
|
+
"datasource": { "type": "prometheus", "uid": "prometheus" },
|
|
279
|
+
"targets": [
|
|
280
|
+
{
|
|
281
|
+
"refId": "A",
|
|
282
|
+
"expr": "sum by (channel, role) (increase(tomo_messages_total[1h]))",
|
|
283
|
+
"legendFormat": "{{channel}} / {{role}}"
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
"fieldConfig": { "defaults": { "unit": "short" }, "overrides": [] }
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"id": 20,
|
|
290
|
+
"type": "logs",
|
|
291
|
+
"title": "Activity feed",
|
|
292
|
+
"gridPos": { "h": 12, "w": 24, "x": 0, "y": 37 },
|
|
293
|
+
"datasource": { "type": "loki", "uid": "loki" },
|
|
294
|
+
"targets": [{ "refId": "A", "expr": "{job=\"tomo-activity\"}" }],
|
|
295
|
+
"options": {
|
|
296
|
+
"showTime": true,
|
|
297
|
+
"sortOrder": "Descending",
|
|
298
|
+
"wrapLogMessage": true,
|
|
299
|
+
"enableLogDetails": true
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
],
|
|
303
|
+
"annotations": {
|
|
304
|
+
"list": [
|
|
305
|
+
{
|
|
306
|
+
"name": "Compactions",
|
|
307
|
+
"datasource": { "type": "loki", "uid": "loki" },
|
|
308
|
+
"enable": true,
|
|
309
|
+
"expr": "{job=\"tomo-activity\", type=\"compact\"}",
|
|
310
|
+
"iconColor": "orange"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"name": "Heartbeats",
|
|
314
|
+
"datasource": { "type": "loki", "uid": "loki" },
|
|
315
|
+
"enable": true,
|
|
316
|
+
"expr": "{job=\"tomo-activity\", type=\"heartbeat\"}",
|
|
317
|
+
"iconColor": "blue"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"name": "Issues",
|
|
321
|
+
"datasource": { "type": "loki", "uid": "loki" },
|
|
322
|
+
"enable": false,
|
|
323
|
+
"expr": "{job=\"tomo-activity\", type=\"issue\"}",
|
|
324
|
+
"iconColor": "red"
|
|
325
|
+
}
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
apiVersion: 1
|
|
2
|
+
|
|
3
|
+
datasources:
|
|
4
|
+
- name: Prometheus
|
|
5
|
+
uid: prometheus
|
|
6
|
+
type: prometheus
|
|
7
|
+
access: proxy
|
|
8
|
+
url: http://prometheus:9090
|
|
9
|
+
isDefault: true
|
|
10
|
+
editable: false
|
|
11
|
+
- name: Loki
|
|
12
|
+
uid: loki
|
|
13
|
+
type: loki
|
|
14
|
+
access: proxy
|
|
15
|
+
url: http://loki:3100
|
|
16
|
+
editable: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery-pipeline.d.ts","sourceRoot":"","sources":["../../src/agent/delivery-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,OAAO,
|
|
1
|
+
{"version":3,"file":"delivery-pipeline.d.ts","sourceRoot":"","sources":["../../src/agent/delivery-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,OAAO,EAA2B,kBAAkB,EAAiB,MAAM,iBAAiB,CAAC;AAG7F,UAAU,oBAAoB;IAC5B,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACvE;AAED,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE/D,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAM9D;AAED,qBAAa,gBAAgB;IACf,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,oBAAoB;IAE9C;;;;;;OAMG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,EACrB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAuB,GACtD,OAAO,CAAC,IAAI,CAAC;IAoBhB;;;OAGG;IACG,uBAAuB,CAC3B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,iBAA4C,GACnD,OAAO,CAAC,IAAI,CAAC;IAoBhB;;;;OAIG;IACH,gBAAgB,CACd,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,gBAAgB,GACvB,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC;CA4BnC"}
|