kimaki 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bash-tool-schema-plugin.js +18 -0
- package/dist/bash-tool-schema-plugin.test.js +20 -1
- package/dist/channel-management.js +113 -51
- package/dist/cli-commands/misc.js +4 -1
- package/dist/cli-commands/project.js +7 -4
- package/dist/cli-commands/session.js +84 -33
- package/dist/cli-commands/thread.js +63 -0
- package/dist/cli.js +2 -0
- package/dist/commands/queue.js +79 -31
- package/dist/commands/queue.test.js +15 -0
- package/dist/commands/restart-opencode-server.js +7 -1
- package/dist/commands/session-id.js +5 -5
- package/dist/database.js +76 -0
- package/dist/db.js +34 -0
- package/dist/db.test.js +96 -1
- package/dist/default-channel-provisioning.test.js +2 -1
- package/dist/discord-bot.js +9 -3
- package/dist/discord-command-registration.js +1 -1
- package/dist/guild-categories.test.js +225 -0
- package/dist/interaction-handler.js +5 -1
- package/dist/kimaki-opencode-plugin.js +2 -0
- package/dist/kimaki-opencode-plugin.test.js +28 -0
- package/dist/list-channel-threads.js +163 -0
- package/dist/list-channel-threads.test.js +80 -0
- package/dist/message-formatting.js +9 -16
- package/dist/message-formatting.test.js +91 -2
- package/dist/schema.js +21 -0
- package/dist/session-handler/event-stream-state.js +53 -5
- package/dist/session-handler/event-stream-state.test.js +223 -0
- package/dist/session-handler/thread-runtime-state.js +4 -0
- package/dist/session-handler/thread-session-runtime.js +314 -73
- package/dist/system-message.js +55 -13
- package/dist/system-message.test.js +50 -13
- package/dist/task-id-plugin.js +16 -0
- package/package.json +5 -5
- package/skills/strada/SKILL.md +61 -232
- package/src/bash-tool-schema-plugin.test.ts +29 -0
- package/src/bash-tool-schema-plugin.ts +31 -0
- package/src/channel-management.ts +144 -65
- package/src/cli-commands/misc.ts +4 -1
- package/src/cli-commands/project.ts +9 -4
- package/src/cli-commands/session.ts +123 -34
- package/src/cli-commands/thread.ts +86 -0
- package/src/cli.ts +2 -0
- package/src/commands/queue.test.ts +19 -0
- package/src/commands/queue.ts +106 -40
- package/src/commands/restart-opencode-server.ts +12 -1
- package/src/commands/session-id.ts +5 -5
- package/src/database.ts +114 -0
- package/src/db.test.ts +112 -0
- package/src/db.ts +38 -0
- package/src/default-channel-provisioning.test.ts +2 -1
- package/src/discord-bot.ts +11 -2
- package/src/discord-command-registration.ts +3 -1
- package/src/guild-categories.test.ts +260 -0
- package/src/interaction-handler.ts +7 -0
- package/src/kimaki-opencode-plugin.test.ts +34 -0
- package/src/kimaki-opencode-plugin.ts +2 -0
- package/src/list-channel-threads.test.ts +90 -0
- package/src/list-channel-threads.ts +252 -0
- package/src/message-formatting.test.ts +105 -1
- package/src/message-formatting.ts +7 -12
- package/src/schema.sql +16 -0
- package/src/schema.ts +23 -0
- package/src/session-handler/event-stream-state.test.ts +226 -0
- package/src/session-handler/event-stream-state.ts +57 -5
- package/src/session-handler/thread-runtime-state.ts +5 -0
- package/src/session-handler/thread-session-runtime.ts +380 -81
- package/src/system-message.test.ts +50 -13
- package/src/system-message.ts +58 -12
- package/src/task-id-plugin.ts +17 -0
package/skills/strada/SKILL.md
CHANGED
|
@@ -1,275 +1,104 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: strada
|
|
3
|
+
repo: remorses/strada
|
|
3
4
|
description: >
|
|
4
5
|
Strada is an open-source OpenTelemetry observability platform (error tracking, tracing, logs,
|
|
5
|
-
metrics, browser analytics, health checks) that stores data in ClickHouse/Tinybird.
|
|
6
|
-
when you need to interface with the Strada CLI, read or debug a project
|
|
7
|
-
OpenTelemetry data collected by Strada,
|
|
8
|
-
for OpenTelemetry data ingestion.
|
|
6
|
+
metrics, browser analytics, product events, health checks) that stores data in ClickHouse/Tinybird.
|
|
7
|
+
ALWAYS load this skill when you need to interface with the Strada CLI, read or debug a project
|
|
8
|
+
issue via OpenTelemetry data collected by Strada, set up and configure a project that uses Strada
|
|
9
|
+
for OpenTelemetry data ingestion, or add product analytics with track().
|
|
9
10
|
---
|
|
10
11
|
|
|
11
12
|
# Strada
|
|
12
13
|
|
|
13
|
-
Open-source Sentry/Datadog alternative built on
|
|
14
|
+
Open-source Sentry/Datadog alternative built on OpenTelemetry. Apps send OTel data with `@strada.sh/sdk`, Strada stores it in the user's own ClickHouse database (Tinybird as first-class backend), and everything is queried with SQL from the `strada` CLI.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
This skill is deliberately thin. The documentation lives in the repo and in the CLI, and it changes often, so **fetch the canonical source instead of trusting anything you remember about this SDK.**
|
|
16
17
|
|
|
17
|
-
Read the
|
|
18
|
+
## Read the docs before writing code
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
cat README.md # read the full output, NEVER pipe to head/tail
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## CLI reference
|
|
24
|
-
|
|
25
|
-
The `strada` CLI is the main interface for managing projects, querying data, listing errors, and viewing analytics. Always run help first to see all available commands before using the CLI:
|
|
20
|
+
Fetch the page that matches the task. Read each one **in full**. Never pipe these to `head`, `tail`, `sed`, or `less`: the rules that matter are spread throughout, not at the top.
|
|
26
21
|
|
|
27
22
|
```bash
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Project management
|
|
23
|
+
# What Strada is, how it compares, CLI-first workflows
|
|
24
|
+
curl -s https://raw.githubusercontent.com/remorses/strada/main/README.md
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
strada projects create my-app
|
|
26
|
+
# Setting up a project: server + browser, env vars, RSC pattern, verification
|
|
27
|
+
curl -s https://raw.githubusercontent.com/remorses/strada/main/website/src/docs/quickstart.mdx
|
|
36
28
|
|
|
37
|
-
#
|
|
38
|
-
|
|
29
|
+
# SDK API reference: every option and helper, per-runtime details
|
|
30
|
+
curl -s https://raw.githubusercontent.com/remorses/strada/main/website/src/docs/sdk.mdx
|
|
39
31
|
|
|
40
|
-
#
|
|
41
|
-
|
|
32
|
+
# SQL: tables, ClickHouse gotchas, ready-made queries
|
|
33
|
+
curl -s https://raw.githubusercontent.com/remorses/strada/main/website/src/docs/querying.mdx
|
|
42
34
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# List recent errors
|
|
47
|
-
strada issues list -p my-app --since 24h
|
|
35
|
+
# Browser analytics: pageviews, sessions, custom event attribute shape
|
|
36
|
+
curl -s https://raw.githubusercontent.com/remorses/strada/main/website/src/docs/browser-analytics.mdx
|
|
48
37
|
```
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
All queries use **ClickHouse SQL**. You can use any ClickHouse SQL syntax, functions, and operators. The query runs against the project's Tinybird/ClickHouse database with automatic project-scoped filtering via JWT.
|
|
39
|
+
Inside the strada repo itself, read the local files instead (`README.md`, `website/src/docs/*.mdx`, `website/src/docs/sdk.mdx`) so you see uncommitted changes.
|
|
53
40
|
|
|
54
|
-
##
|
|
55
|
-
|
|
56
|
-
For the full task-oriented walkthrough (create project, server + browser, env var rules, RSC pattern, verify), read the quickstart:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
cat website/src/docs/quickstart.mdx # read the full output, NEVER pipe to head/tail
|
|
60
|
-
```
|
|
41
|
+
## Read the CLI help before running commands
|
|
61
42
|
|
|
62
|
-
|
|
43
|
+
The CLI is the main interface: projects, tokens, issues, logs, traces, analytics, alerts, health checks. Command descriptions are the documentation.
|
|
63
44
|
|
|
64
45
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
The SDK package is `@strada.sh/sdk`. The import path auto-resolves by runtime: browsers get the browser entry, Workers get the Workers entry, Node.js gets the server entry. **One import path works everywhere.** Get the project ID and first server-side token from `strada projects create <slug>`; create more org-wide ingest tokens later with `strada tokens create --scope ingest <name>`.
|
|
69
|
-
|
|
70
|
-
When a project has both a frontend and a backend, set up **both** runtimes against the **same project ID**.
|
|
71
|
-
|
|
72
|
-
**Server** (Node, Bun, Workers). Pass the `token`:
|
|
73
|
-
|
|
74
|
-
```ts
|
|
75
|
-
import { initStrada, captureException } from "@strada.sh/sdk"
|
|
76
|
-
|
|
77
|
-
initStrada({
|
|
78
|
-
projectId: process.env.STRADA_PROJECT_ID,
|
|
79
|
-
token: process.env.STRADA_TOKEN, // server only
|
|
80
|
-
service: "my-app",
|
|
81
|
-
})
|
|
46
|
+
strada --help # full command list, read all of it
|
|
47
|
+
strada issues list --help # per-command options and examples
|
|
82
48
|
```
|
|
83
49
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
```ts
|
|
87
|
-
import { initStrada } from "@strada.sh/sdk"
|
|
88
|
-
|
|
89
|
-
initStrada({
|
|
90
|
-
projectId: process.env.PUBLIC_STRADA_PROJECT_ID,
|
|
91
|
-
service: "my-app-browser",
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Rules to never break:
|
|
96
|
-
|
|
97
|
-
- **Never ship `STRADA_TOKEN` to the browser.** It is a server secret.
|
|
98
|
-
- **Browser project id needs a public prefix** or the bundler will strip it.
|
|
99
|
-
- In **RSC / server-rendered** apps, run browser `initStrada()` from a side-effect-only `"use client"` module rendered once in the root layout (a component that returns `null`). A bare `import` runs on the server and gets tree-shaken from the client bundle. See `website/src/docs/quickstart.mdx` for the pattern.
|
|
100
|
-
- If the framework exposes an OTel tracer hook (e.g. Spiceflow `new Spiceflow({ tracer })`), pass `trace.getTracer("my-app")` from the SDK so request spans flow to the same project.
|
|
101
|
-
- In **Cloudflare Workers**, import `env` from `cloudflare:workers` and call
|
|
102
|
-
`initStrada()` at module scope. Never initialize in per-request middleware.
|
|
103
|
-
See the Cloudflare Workers section of `website/src/sdk/README.mdx`.
|
|
104
|
-
- **Email and user id belong on errors, logs, and product events.** That is how
|
|
105
|
-
you open an issue and see who hit it. Use `strataBetterAuth()` (default
|
|
106
|
-
`includeUserDetails: true`), `identifyUser()`, or `tags` / event properties
|
|
107
|
-
with `user.id` and `user.email`. Do not strip them.
|
|
108
|
-
- Never attach API keys, prompts, or raw user content (the text they typed)
|
|
109
|
-
to tags or events. Use stable route, handler, service, and environment
|
|
110
|
-
identifiers for those.
|
|
111
|
-
|
|
112
|
-
## Terminal UI
|
|
50
|
+
Do not guess flags. Two that are guessed wrong constantly:
|
|
113
51
|
|
|
114
|
-
|
|
52
|
+
- `-p` takes a **project slug** from `strada projects list`, usually with an environment suffix (`my-app-prod`, not `my-app`)
|
|
53
|
+
- multi-value options repeat the flag: `-p frontend -p api`, never `-p frontend,api`
|
|
115
54
|
|
|
116
|
-
|
|
55
|
+
## Debugging a production error
|
|
117
56
|
|
|
118
|
-
|
|
57
|
+
Start here before writing any SQL. This flow answers most questions without a query.
|
|
119
58
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
import { getLogger } from "@strada.sh/sdk"
|
|
124
|
-
|
|
125
|
-
const logger = getLogger("api")
|
|
126
|
-
|
|
127
|
-
logger.info({ message: "checkout started", checkoutId: "chk_123" })
|
|
128
|
-
logger.error({ message: "payment failed", error: String(err) })
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
If you need both console output and Strada logs during development, create a wrapper that calls both. See the SDK README for the full pattern.
|
|
132
|
-
|
|
133
|
-
## captureException in leaf functions
|
|
134
|
-
|
|
135
|
-
When a function handles an error inline (returning early, responding with a status code, logging and continuing), it **must** call `captureException` explicitly. The framework's top-level `.onError` handler only catches uncaught exceptions; errors that are caught and swallowed never reach it.
|
|
59
|
+
```bash
|
|
60
|
+
# 1. top error groups in the window
|
|
61
|
+
strada issues list -p my-app --since 24h
|
|
136
62
|
|
|
137
|
-
|
|
63
|
+
# 2. full details for one fingerprint: stack trace, mechanism, services, releases
|
|
64
|
+
strada issues view <fingerprint> -p my-app --events 3
|
|
138
65
|
|
|
139
|
-
|
|
140
|
-
|
|
66
|
+
# 3. the whole request that failed, using a TraceId from step 2
|
|
67
|
+
strada traces view <traceId> -p my-app
|
|
141
68
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
captureException(result, {
|
|
145
|
-
tags: { route: 'stripe-webhook', eventType: event.type },
|
|
146
|
-
})
|
|
147
|
-
return new Response('Webhook handler failed', { status: 500 })
|
|
148
|
-
}
|
|
69
|
+
# 4. logs correlated to that same request
|
|
70
|
+
strada logs -p my-app --trace-id <traceId>
|
|
149
71
|
```
|
|
150
72
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
**AGENTS.md notice.** If a project uses strada, its `AGENTS.md` (or `*_AGENTS.md`) should include a section stating that all inline-handled errors must call `captureException` from `@strada.sh/sdk` instead of being swallowed with `console.error`/`console.warn`. If that section is missing, add it when you touch error handling code.
|
|
73
|
+
`issues list` hides resolved and muted issues by default. Use `--status all` when an issue seems to have vanished.
|
|
154
74
|
|
|
155
|
-
|
|
75
|
+
Running `strada` with no arguments opens a TUI (Issues, Logs, Traces, Analytics) that uses the same queries. Suggest it when the user wants to browse rather than run one-off commands.
|
|
156
76
|
|
|
157
|
-
|
|
77
|
+
## Rules for instrumenting an app
|
|
158
78
|
|
|
159
|
-
|
|
160
|
-
# 1. Find the top error groups in the last 24 hours
|
|
161
|
-
strada issues list -p my-app --since 24h
|
|
79
|
+
These are the mistakes models make in this SDK. The reasoning behind each one is in the quickstart and the SDK reference.
|
|
162
80
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
81
|
+
- **Never ship `STRADA_TOKEN` to the browser.** It is a server secret. Browser ingest is anonymous and rate limited, so the browser `initStrada()` takes no token.
|
|
82
|
+
- **The browser project id needs a public env prefix** (`VITE_`, `NEXT_PUBLIC_`, ...) or the bundler strips it.
|
|
83
|
+
- **Frontend and backend of the same app use the same `projectId`** with different `service` names.
|
|
84
|
+
- **In Cloudflare Workers**, import `env` from `cloudflare:workers` and call `initStrada()` at **module scope**. Never inside per-request middleware.
|
|
85
|
+
- **In RSC / server-rendered apps**, call browser `initStrada()` from a side-effect-only `"use client"` module rendered once in the root layout. A bare import runs on the server and is tree-shaken out of the client bundle.
|
|
86
|
+
- **Never skip `initStrada()` to disable telemetry**, and never wrap SDK calls in your own `if (enabled)` guard. Pass `enabled` to `initStrada()`, or leave `projectId` empty; both make every call a silent no-op.
|
|
87
|
+
- **Pass the framework's tracer hook** when one exists (e.g. Spiceflow `new Spiceflow({ tracer })`) using `trace.getTracer("my-app")` from the SDK, so request spans reach the same project.
|
|
88
|
+
- **Use `getLogger()`, not `console.*`.** Console output never reaches Strada; it only shows in platform logs (Cloudflare dashboard, Node stdout).
|
|
89
|
+
- **Use `track()` for product events, not `getLogger()`.** A log with an `event` field is still an ordinary log: `strada analytics events` and SQL on `event.name` will miss it.
|
|
90
|
+
- **Errors handled inline still need `captureException()`.** Top-level error handlers only see errors thrown out of the request. Anything caught and turned into a `500`, a retry, or an error-as-value return is invisible unless you capture it explicitly, with `tags` carrying at least a `route` or `handler`.
|
|
91
|
+
- **Keep user identity on telemetry.** `user.id` and email are how an issue becomes actionable. Use `strataBetterAuth()`, or put `user.id` into baggage yourself and call `identifyUser()` at login (see "Server-side user identification without Better Auth" in the SDK reference).
|
|
92
|
+
- **Never attach prompts, API keys, session tokens, or raw user content** to tags or event properties. Ids, counts, model names, durations, booleans, route names: yes.
|
|
93
|
+
- **Type your events.** `track()` takes a plain `string`, so a typo compiles and is only noticed when a query returns nothing. Declare the catalog once and wrap `track()`; see "Type-safe event catalog" in the SDK reference.
|
|
166
94
|
|
|
167
|
-
|
|
95
|
+
## Writing SQL
|
|
168
96
|
|
|
169
|
-
|
|
97
|
+
Read `website/src/docs/querying.mdx` (curl URL above) before composing a query. The two rules that silently corrupt results if ignored:
|
|
170
98
|
|
|
171
|
-
|
|
99
|
+
- **Never add `WHERE ProjectId`.** The JWT injects project scoping already.
|
|
100
|
+
- **Materialized views need merge combinators.** `uniqMerge(Visits)`, `countMerge(Hits)` on `otel_analytics_*`, never plain `count()`.
|
|
172
101
|
|
|
173
|
-
|
|
174
|
-
# 3. View the distributed trace for a specific error event
|
|
175
|
-
strada traces view <traceId> -p my-app
|
|
176
|
-
```
|
|
102
|
+
## AGENTS.md notice
|
|
177
103
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
# 4. Show logs correlated to the same trace
|
|
182
|
-
strada logs -p my-app --trace-id <traceId>
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## Common mistakes
|
|
186
|
-
|
|
187
|
-
**Never reference ProjectId in SQL queries.** The Tinybird JWT injects `WHERE ProjectId = '...'` automatically on every query. Adding it manually is redundant and error-prone.
|
|
188
|
-
|
|
189
|
-
**Always add LIMIT to every query.** Unbounded queries scan the entire table. Even aggregations that expect one row should use `LIMIT 1`.
|
|
190
|
-
|
|
191
|
-
**Column names are PascalCase.** The OTel ClickHouse schema uses PascalCase: `TraceId`, `SpanName`, `ServiceName`, `ExceptionType`, not `trace_id` or `span_name`. This is the standard OTel ClickHouse exporter convention.
|
|
192
|
-
|
|
193
|
-
**Use repeatable -p flags, not comma-separated.** Pass multiple projects as `-p frontend -p api`, never `-p frontend,api`.
|
|
194
|
-
|
|
195
|
-
**No CTEs in Tinybird SQL.** Tinybird does not optimize `WITH ... AS` well. Use subqueries instead.
|
|
196
|
-
|
|
197
|
-
**Filter in WHERE, not HAVING.** `WHERE` filters skip data at the storage level. `HAVING` filters after ClickHouse already read and grouped everything.
|
|
198
|
-
|
|
199
|
-
**Map column access.** Use `mapContains(LogAttributes, 'event.name')` to check key existence and `LogAttributes['key']` to read values.
|
|
200
|
-
|
|
201
|
-
**Time filtering.** Use ClickHouse interval syntax: `WHERE Timestamp >= now() - INTERVAL 1 HOUR`, not string comparisons.
|
|
202
|
-
|
|
203
|
-
**Aggregation on MV tables.** Analytics tables (`otel_analytics_pages`, `otel_analytics_sessions`) use `AggregatingMergeTree`. Read with `-Merge` combinators: `uniqMerge(Visits)`, `countMerge(Hits)`, never plain `count()` or `uniq()` on those columns.
|
|
204
|
-
|
|
205
|
-
## Tables
|
|
206
|
-
|
|
207
|
-
The main tables you can query:
|
|
208
|
-
|
|
209
|
-
| Table | Contains |
|
|
210
|
-
|-------|----------|
|
|
211
|
-
| `otel_traces` | Spans (HTTP requests, DB queries, function calls) |
|
|
212
|
-
| `otel_logs` | Log records and custom events |
|
|
213
|
-
| `otel_errors` | Extracted exceptions grouped by fingerprint |
|
|
214
|
-
| `otel_analytics_pages` | Pre-aggregated pageview data (MV) |
|
|
215
|
-
| `otel_analytics_sessions` | Pre-aggregated session data (MV) |
|
|
216
|
-
| `otel_metrics_gauge` | Gauge metric snapshots |
|
|
217
|
-
| `otel_metrics_sum` | Cumulative counter metrics |
|
|
218
|
-
| `otel_metrics_histogram` | Distribution metrics |
|
|
219
|
-
|
|
220
|
-
## Useful query patterns
|
|
221
|
-
|
|
222
|
-
```sql
|
|
223
|
-
-- Recent errors grouped by type
|
|
224
|
-
SELECT FingerprintHash, anyLast(ExceptionType) AS type,
|
|
225
|
-
anyLast(ExceptionMessage) AS message, count() AS events
|
|
226
|
-
FROM otel_errors
|
|
227
|
-
WHERE Timestamp >= now() - INTERVAL 24 HOUR
|
|
228
|
-
GROUP BY FingerprintHash
|
|
229
|
-
ORDER BY events DESC
|
|
230
|
-
LIMIT 20
|
|
231
|
-
|
|
232
|
-
-- Custom events from browser
|
|
233
|
-
SELECT Timestamp, LogAttributes['event.name'] AS event,
|
|
234
|
-
LogAttributes['user.id'] AS user_id
|
|
235
|
-
FROM otel_logs
|
|
236
|
-
WHERE mapContains(LogAttributes, 'event.name')
|
|
237
|
-
ORDER BY Timestamp DESC
|
|
238
|
-
LIMIT 100
|
|
239
|
-
|
|
240
|
-
-- Slow spans
|
|
241
|
-
SELECT SpanName, ServiceName, Duration / 1e6 AS duration_ms
|
|
242
|
-
FROM otel_traces
|
|
243
|
-
WHERE Duration > 1000000000
|
|
244
|
-
ORDER BY Duration DESC
|
|
245
|
-
LIMIT 20
|
|
246
|
-
|
|
247
|
-
-- HTTP route performance: top routes by RPS and latency
|
|
248
|
-
-- ParentSpanId = '' filters to root spans (one per HTTP request)
|
|
249
|
-
-- Duration is nanoseconds, divide by 1e6 for milliseconds
|
|
250
|
-
SELECT
|
|
251
|
-
SpanName AS path,
|
|
252
|
-
count() AS total_requests,
|
|
253
|
-
round(count() / 3600, 2) AS rps,
|
|
254
|
-
round(avg(Duration) / 1e6, 1) AS avg_ms,
|
|
255
|
-
round(quantile(0.95)(Duration) / 1e6, 1) AS p95_ms,
|
|
256
|
-
round(max(Duration) / 1e6, 1) AS max_ms
|
|
257
|
-
FROM otel_traces
|
|
258
|
-
WHERE Timestamp >= now() - INTERVAL 1 HOUR
|
|
259
|
-
AND ParentSpanId = ''
|
|
260
|
-
GROUP BY path
|
|
261
|
-
ORDER BY total_requests DESC
|
|
262
|
-
LIMIT 30
|
|
263
|
-
|
|
264
|
-
-- Per-minute traffic pattern for a specific route
|
|
265
|
-
SELECT
|
|
266
|
-
toStartOfMinute(Timestamp) AS minute,
|
|
267
|
-
count() AS requests
|
|
268
|
-
FROM otel_traces
|
|
269
|
-
WHERE Timestamp >= now() - INTERVAL 1 HOUR
|
|
270
|
-
AND ParentSpanId = ''
|
|
271
|
-
AND SpanName = 'POST /api/my-route'
|
|
272
|
-
GROUP BY minute
|
|
273
|
-
ORDER BY minute DESC
|
|
274
|
-
LIMIT 60
|
|
275
|
-
```
|
|
104
|
+
When a project uses Strada, its `AGENTS.md` (or `*_AGENTS.md`) should tell agents that inline-handled errors must call `captureException` instead of being swallowed with `console.error`, and that product events go through a typed `trackEvent` wrapper. If that section is missing, add it while you are touching the relevant code.
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest'
|
|
2
2
|
import {
|
|
3
3
|
extendBashToolDefinition,
|
|
4
|
+
injectKimakiSessionEnv,
|
|
5
|
+
KIMAKI_SESSION_ID_ENV,
|
|
6
|
+
resolveUploadToDiscordSessionId,
|
|
4
7
|
type ToolDefinitionOutput,
|
|
5
8
|
} from './bash-tool-schema-plugin.js'
|
|
6
9
|
|
|
@@ -53,3 +56,29 @@ describe('extendBashToolDefinition', () => {
|
|
|
53
56
|
`)
|
|
54
57
|
})
|
|
55
58
|
})
|
|
59
|
+
|
|
60
|
+
describe('upload-to-discord session targeting', () => {
|
|
61
|
+
test('bash env uses the live OpenCode session, not a copied --session flag', () => {
|
|
62
|
+
const env: Record<string, string> = {}
|
|
63
|
+
injectKimakiSessionEnv({ sessionID: 'ses_child', env })
|
|
64
|
+
expect(env).toEqual({ [KIMAKI_SESSION_ID_ENV]: 'ses_child' })
|
|
65
|
+
expect(
|
|
66
|
+
resolveUploadToDiscordSessionId({
|
|
67
|
+
flagSessionId: 'ses_parent',
|
|
68
|
+
envSessionId: env[KIMAKI_SESSION_ID_ENV],
|
|
69
|
+
}),
|
|
70
|
+
).toBe('ses_child')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('falls back to --session when bash is not inside an OpenCode session', () => {
|
|
74
|
+
expect(
|
|
75
|
+
resolveUploadToDiscordSessionId({
|
|
76
|
+
flagSessionId: 'ses_parent',
|
|
77
|
+
}),
|
|
78
|
+
).toBe('ses_parent')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
test('returns undefined when neither live session nor flag is set', () => {
|
|
82
|
+
expect(resolveUploadToDiscordSessionId({})).toBeUndefined()
|
|
83
|
+
})
|
|
84
|
+
})
|
|
@@ -3,10 +3,38 @@
|
|
|
3
3
|
// Assign jsonSchema only. Leave parameters as the Effect Schema used to decode
|
|
4
4
|
// args before execute. Extra fields stay in the model-facing schema and in
|
|
5
5
|
// Discord input; they never reach the shell.
|
|
6
|
+
//
|
|
7
|
+
// Also injects KIMAKI_SESSION_ID into bash env. /btw and /fork clone parent
|
|
8
|
+
// history, so the copied system prompt still says --session <parent>. Upload
|
|
9
|
+
// then prefers this live env over that stale flag.
|
|
6
10
|
|
|
7
11
|
import type { Plugin } from '@opencode-ai/plugin'
|
|
8
12
|
import { z } from 'zod'
|
|
9
13
|
|
|
14
|
+
export const KIMAKI_SESSION_ID_ENV = 'KIMAKI_SESSION_ID'
|
|
15
|
+
|
|
16
|
+
export function injectKimakiSessionEnv({
|
|
17
|
+
sessionID,
|
|
18
|
+
env,
|
|
19
|
+
}: {
|
|
20
|
+
sessionID?: string
|
|
21
|
+
env: Record<string, string>
|
|
22
|
+
}) {
|
|
23
|
+
if (!sessionID) return
|
|
24
|
+
env[KIMAKI_SESSION_ID_ENV] = sessionID
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function resolveUploadToDiscordSessionId({
|
|
28
|
+
flagSessionId,
|
|
29
|
+
envSessionId = process.env[KIMAKI_SESSION_ID_ENV],
|
|
30
|
+
}: {
|
|
31
|
+
flagSessionId?: string
|
|
32
|
+
envSessionId?: string
|
|
33
|
+
} = {}) {
|
|
34
|
+
if (envSessionId) return envSessionId
|
|
35
|
+
return flagSessionId
|
|
36
|
+
}
|
|
37
|
+
|
|
10
38
|
export const bashParameters = z.object({
|
|
11
39
|
command: z.string().describe('The command to execute'),
|
|
12
40
|
description: z
|
|
@@ -42,5 +70,8 @@ export const bashToolSchemaPlugin: Plugin = async () => {
|
|
|
42
70
|
if (input.toolID !== 'bash') return
|
|
43
71
|
extendBashToolDefinition(output)
|
|
44
72
|
},
|
|
73
|
+
'shell.env': async (input, output) => {
|
|
74
|
+
injectKimakiSessionEnv({ sessionID: input.sessionID, env: output.env })
|
|
75
|
+
},
|
|
45
76
|
}
|
|
46
77
|
}
|