@carllee1983/dbcli 1.52.1 → 1.54.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/.cursor/rules/dbcli.mdc +8 -4
- package/.cursor/skills/dbcli/reference.md +132 -9
- package/.github/skills/dbcli/SKILL.md +8 -4
- package/.github/skills/dbcli/reference.md +132 -9
- package/CHANGELOG.md +39 -0
- package/assets/SKILL.md +8 -4
- package/assets/SKILL.zh-TW.md +6 -3
- package/assets/reference.md +132 -9
- package/assets/ui-template.html +2 -2
- package/dist/cli-runtime.mjs +38407 -96799
- package/dist/cli.mjs +6 -5
- package/dist/core.d.ts +361 -274
- package/dist/core.mjs +9350 -22209
- package/dist/ui-style.css +2 -2
- package/package.json +6 -5
- package/plugins/dbcli-agent/skills/dbcli/SKILL.md +8 -4
- package/plugins/dbcli-agent/skills/dbcli/reference.md +132 -9
- package/skills/dbcli/SKILL.md +8 -4
- package/skills/dbcli/reference.md +132 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@ All notable changes to dbcli are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.54.0] - 2026-08-13 - Query engine hardening: timeout semantics, load-on-demand, deterministic builds
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Separate connection and statement timeouts.** `--timeout` previously did two jobs at once: PostgreSQL fed it to both `connectionTimeoutMillis` and `statement_timeout`, so the 5000ms connection default silently became a global query ceiling, while MySQL consumed neither and ignored `--timeout` entirely. Connection timeout keeps its 5000ms built-in default, statement timeout now has none (the server decides) unless you ask for one, and the new root-level `--statement-timeout <ms>` plus the `statementTimeout` connection field (0–3600000, `0` removes the ceiling) adjust it on its own. MySQL now consumes both, mapping the statement limit onto session-level `max_execution_time` / `max_statement_time` where the server supports it.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- **The CLI loads what a command actually needs.** Subcommands register lazily, SQL drivers load at connection time rather than at import, and `node-sql-parser` is both deferred and externalized from the bundle — measured at roughly 8ms off startup for the lazy registration alone.
|
|
17
|
+
- **Full-schema scans cost less.** Per-table queries are merged, row estimates replace `COUNT(*)`, and remaining work runs with bounded parallelism. The query path no longer loads the layered schema in full — it fetches the single table it needs.
|
|
18
|
+
- **Repeated lookups are cached within a process.** Config binding files are read and validated once per process, and the skill update check keeps a TTL cache instead of re-checking on every invocation. Redis and Elasticsearch list operations were narrowed to what the caller asked for.
|
|
19
|
+
- **Identifier quoting and error classification each have one implementation.** Quote/encode helpers were consolidated into a shared utility, and driver errors are now classified by error code first rather than by matching message text.
|
|
20
|
+
- **Server-side script protection lives in the adapter layer**, so every caller is covered by the same guard rather than each command re-implementing it.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **`bun run build` was non-deterministic.** Consecutive builds of identical sources alternated between two `dist/cli-runtime.mjs` outputs about 690KB apart, depending on whether the bundler pulled in 48 `@inquirer/*` modules. `@inquirer/prompts` is now external, which also removes a silent degradation path where the prompt implementation quietly changed between builds. `bun run build:determinism` checks this in CI.
|
|
25
|
+
- **One CLI query writes exactly one audit entry.** Some paths recorded the same query more than once.
|
|
26
|
+
- **Windows CI is green again.** Path separator assumptions, CRLF handling in test fixtures, and CRLF frontmatter stripping in skill sources were all Unix-only.
|
|
27
|
+
- **The startup benchmark measures the noise floor rather than the median**, which is what actually distinguishes a regression from scheduler jitter, and a guide test no longer flakes on a random UUID colliding with `'5432'`.
|
|
28
|
+
|
|
29
|
+
## [1.53.0] - 2026-08-09 - Offline evidence, semantic contracts, and impact assessment
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Offline evidence packs.** `dbcli evidence compose`, `validate`, and `render` create, verify, and render workspace-contained evidence packs from safe claim text plus existing verification artifacts, audit entries, and optional assert receipts. Packs omit SQL, rows, targets, credentials, audit metadata, and verification summaries; source retention loss remains visible without preventing historical rendering.
|
|
34
|
+
- **Evidence receipts for post-write assertions.** `assert --evidence-receipt <path>` atomically records safe provenance only after the verdict, audit attempt, and optional verification artifact are authoritative. Receipts are workspace-contained, contain no SQL or returned data, cannot be used as execution approval, and may be composed into an evidence pack.
|
|
35
|
+
- **Reviewable semantic contracts.** `dbcli contract validate|context|search|drift` governs optional `dbcli.contracts.json` evidence expectations for canonical semantic terms. The commands are offline and read-only; only valid approved contracts enter ordinary agent context.
|
|
36
|
+
- **Offline impact assessment.** `dbcli impact assess` creates a declared-coverage report for a design change against exactly one local schema-cache or ORM baseline, optionally incorporating reviewed data-access metadata and redaction-first proxy workload evidence. It never connects, executes SQL, or claims complete coverage.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **Shared execution and adapter boundaries.** Query execution now uses an injectable command runtime, SQL adapters share readiness and driver-error handling, and doctor accepts a non-SQL collector runtime. These internal changes keep the CLI behavior stable while making offline evidence and impact workflows testable.
|
|
41
|
+
- **Documentation and agent skills cover the new surfaces.** English and Traditional Chinese Markdown and HTML guides, installed skill copies, and reference material document evidence packs, assert receipts, semantic contracts, and impact assessment.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **Release audit no longer resolves a vulnerable `nanoid`.** The build-only PostCSS and Tailwind dependencies now resolve `nanoid@3.3.18`, satisfying the security advisory without adding a runtime dependency.
|
|
46
|
+
|
|
8
47
|
## [1.52.1] - 2026-08-08 - Skill audit: correct claims, per-platform install, drift gate
|
|
9
48
|
|
|
10
49
|
### Fixed
|
package/assets/SKILL.md
CHANGED
|
@@ -110,8 +110,8 @@ still stop where those gates require human confirmation.
|
|
|
110
110
|
term, or relationship/join intent instead of a physical table or field name, first run
|
|
111
111
|
`dbcli skill context --format json`. If it includes `semantic`, treat that reviewed
|
|
112
112
|
section as the governed vocabulary; use `dbcli semantic search <terms> --format json`
|
|
113
|
-
to look up a specific term. If
|
|
114
|
-
fall back to `blacklist` → `schema` mapping and tell the user that optional
|
|
113
|
+
to look up a specific term. If `contracts` is present, use only its approved terms and
|
|
114
|
+
their descriptive evidence policy; it never authorizes an assertion or query. If no semantic section exists or search returns no result, fall back to `blacklist` → `schema` mapping and tell the user that optional
|
|
115
115
|
`dbcli.semantic.json` can make future requests consistent. Never create, update, or
|
|
116
116
|
migrate that file without an explicit human request; semantic vocabulary never replaces
|
|
117
117
|
schema confirmation or the normal query/write safety gates.
|
|
@@ -159,6 +159,7 @@ in **How to use dbcli** still applies.
|
|
|
159
159
|
| ORM or migration work | `schema --format json` → `diff --against-orm <orm-schema>` → review error-level drift → proposals via `migrate` (dry-run) → `migration-review` task pack → `diff --against <snapshot>` after applying. |
|
|
160
160
|
| Schema design, no database yet | `design init --output ./dbcli.design.json` → edit → `design validate` → `design render --format mermaid`. With existing ORM models, reconcile via `design diff --against-orm <path>` first. |
|
|
161
161
|
| Design drift on a live database | `blacklist list` → `schema --format json` → `design diff --against-cache` → `design propose --against-cache`, then hand the plan to a human before any migration. |
|
|
162
|
+
| PR schema-change review | `blacklist list` → `impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn`; optionally add explicit `--events ./.dbcli/proxy/events.jsonl` for advisory redacted workload table evidence (never SQL/log rendering or a blocker), then review declared findings, coverage gaps, and the optional reviewed `dbcli.data-access.json` (declared operations only; never source parsing). |
|
|
162
163
|
| PR database review | Review changed persistence paths, then propose concrete `schema` / `plan` / `dry-run` / `report` / `guide` commands per material claim. |
|
|
163
164
|
| Slow endpoint or query | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`; use `proxy analyze` when logs exist. |
|
|
164
165
|
| Safe data backfill | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back or snippet `--verify`. |
|
|
@@ -201,7 +202,9 @@ Guardrails:
|
|
|
201
202
|
- Durable evidence: `assert … --write-verification-artifact --verification-subject <kind:name>`;
|
|
202
203
|
inspect with `verification summary` / `list` / `show <id>`. The `verify safe-backfill` /
|
|
203
204
|
`migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>`
|
|
204
|
-
family runs preflight + `--after-write` checks and **never executes the write**.
|
|
205
|
+
family runs preflight + `--after-write` checks and **never executes the write**. Add
|
|
206
|
+
`--evidence-receipt <workspace-relative-path>` only after after-write for a safe provenance
|
|
207
|
+
receipt; it is never approval to execute a write. Full flags
|
|
205
208
|
and the per-command blocks are in [reference.md](reference.md#commands).
|
|
206
209
|
|
|
207
210
|
## Audit log
|
|
@@ -415,6 +418,7 @@ Full flags and edge cases: see [reference.md](reference.md#init).
|
|
|
415
418
|
| `shell` | (same as query+) | Interactive REPL. SQL engines, MongoDB, and Redis (single-line; `.no-limit on/off`). Elasticsearch opens a Kibana Dev Tools-style REPL (`<METHOD> /<path>` + optional JSON body, blank line submits). |
|
|
416
419
|
| `skill` | n/a | Generate / install AI skill docs (`--install <claude\|gemini\|antigravity\|copilot\|cursor\|codex\|windsurf>`); `skill tasks list/show/plan` for Agent Task Packs; `skill context` for an LLM prompt-context payload (for injecting into another LLM, not needed for normal operation). |
|
|
417
420
|
| `semantic` | n/a | Validate, search, inspect drift, migrate to v2, or print the optional project-root `dbcli.semantic.json`. Give its reviewed context to an external agent, but keep provider credentials, prompts, and agent context outside dbcli. `semantic draft validate --input <file|-> [--format text\|json]` validates only the explicit untrusted `QueryDraft` offline against local semantic/schema/saved-query metadata; it returns safe hashes/references/violation codes, never executes or echoes candidate SQL. Review the original draft, then invoke `explain` or `query` separately if intended. |
|
|
421
|
+
| `contract` | n/a | Validate, inspect approved context, search, or inspect drift for optional project-root `dbcli.contracts.json`. Contracts add ownership and a descriptive evidence policy to canonical semantic references; they are offline, never execute SQL, and cannot create verification or query authority. `skill context` includes only valid approved contracts. |
|
|
418
422
|
| `migrate` | admin | SQL only. **DDL; dry-run by default** — needs `--execute`. |
|
|
419
423
|
|
|
420
424
|
Use root-level `dbcli --use <name> <command>` for any command; `query`, `schema`, `list`,
|
|
@@ -601,4 +605,4 @@ schema. Raw `query` / `export` invocations render a sortable table only.
|
|
|
601
605
|
- Blacklisted tables and columns are redacted from query output.
|
|
602
606
|
- `schema` reports `estimatedRowCount` and `sizeCategory` (small / medium / large / huge). For large/huge tables add `WHERE` or `LIMIT` — bands in [reference.md](reference.md#schema).
|
|
603
607
|
- `doctor` on `mongodb+srv://` reports whether SRV resolves natively or through the DoH fallback — useful when the runtime restricts DNS.
|
|
604
|
-
- **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
|
|
608
|
+
- **Global flags:** `--version`, `--config <path>`, `--global`, `--use <name>`, `--timeout <ms>`, `--statement-timeout <ms>`, `-v` / `--verbose` / `-vv`, `-q` / `--quiet`, `--no-color` (also honours `NO_COLOR`). Root-level flags must precede the command unless the command explicitly declares a command-level option.
|
package/assets/SKILL.zh-TW.md
CHANGED
|
@@ -84,7 +84,8 @@ blacklist、schema、permission、dry-run、production 選取或寫入確認閘
|
|
|
84
84
|
**業務語言探索:** 當使用者以業務別名、metric、反覆出現的術語或 relationship/join 意圖,
|
|
85
85
|
而非實體 table 或 field 名稱提出需求時,先執行 `dbcli skill context --format json`。若輸出含有
|
|
86
86
|
`semantic`,將該已檢閱的區塊視為受治理詞彙;需查找特定術語時,用
|
|
87
|
-
`dbcli semantic search <terms> --format json
|
|
87
|
+
`dbcli semantic search <terms> --format json`。若有 `contracts` 區塊,只能使用其中 approved 術語
|
|
88
|
+
及描述性的 evidence policy;它絕不授權 assertion 或 query。若沒有 semantic 區塊,或搜尋沒有結果,就退回
|
|
88
89
|
`blacklist` → `schema` 對照,並告知使用者可選用的 `dbcli.semantic.json` 能讓後續需求保持一致。
|
|
89
90
|
除非人類明確要求,絕不可建立、更新或 migrate 此檔案;語意詞彙不能取代 schema 確認或正常的
|
|
90
91
|
query/write 安全閘門。
|
|
@@ -117,6 +118,7 @@ dbcli skill tasks plan <task> --param key=value --format json # generate pla
|
|
|
117
118
|
| ORM 或 migration | `schema --format json` → `diff --against-orm <orm-schema>` → 審查 error-level drift → 透過 `migrate` 取得提案(dry-run)→ `migration-review` task pack → 套用後執行 `diff --against <snapshot>`。 |
|
|
118
119
|
| 資料庫設計(尚未有 DB) | `design init --output ./dbcli.design.json` → 編輯 → `design validate` → `design render --format mermaid`。已有 ORM 模型時,先用 `design diff --against-orm <path>` 對齊。 |
|
|
119
120
|
| 既有資料庫的設計漂移 | `blacklist list` → `schema --format json` → `design diff --against-cache` → `design propose --against-cache`,計畫交人類審查後才執行 migration。 |
|
|
121
|
+
| PR schema 變更審查 | `blacklist list` → `impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn`;可選擇加入明確的 `--events ./.dbcli/proxy/events.jsonl` 取得 advisory、已 redaction 的 workload table evidence(不輸出 SQL/log,也不作為 blocker),再檢閱已宣告 findings、coverage gaps 與可選且已審閱的 `dbcli.data-access.json`(僅 declared operations;絕不解析 source)。 |
|
|
120
122
|
| PR 資料庫風險審查 | 審查變更的 persistence path,並針對每個重要主張提出具體 `schema`、`plan`、`dry-run`、`report` 或 `guide` 指令。 |
|
|
121
123
|
| 慢 endpoint 或查詢 | `report --section perf` → task pack `analyze-table-perf` → `lint "<query>"` → `guide missing-index-for "<query>"`;有 proxy log 時使用 `proxy analyze`。 |
|
|
122
124
|
| 安全資料回填 | `blacklist list` → `schema <object>` → count/scope query → `update … --dry-run` → read-back 或 snippet `--verify`。 |
|
|
@@ -153,7 +155,7 @@ dbcli inspect --for-agent --no-connect --format json
|
|
|
153
155
|
- 不要直接從 performance suggestion 建 index;應轉成經過 review 的 migration。
|
|
154
156
|
- 不要執行 `design propose` 計畫裡的 `commands`;未經人類要求,也不要建立或改寫 `dbcli.design.json`。
|
|
155
157
|
- 不要列印 credentials、複製的連線字串或 blacklisted 值。
|
|
156
|
-
- 持久化佐證:`assert … --write-verification-artifact --verification-subject <kind:name>`;以 `verification summary` / `list` / `show <id>` 檢視。`verify safe-backfill` / `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>` 系列執行 preflight + `--after-write`
|
|
158
|
+
- 持久化佐證:`assert … --write-verification-artifact --verification-subject <kind:name>`;以 `verification summary` / `list` / `show <id>` 檢視。`verify safe-backfill` / `migration` / `rollback --kind <ddl|dml>` / `constraint --check <fk|not-null|unique|custom>` 系列執行 preflight + `--after-write` 驗證,**永不執行寫入**。僅可在 after-write 後加入 `--evidence-receipt <工作區相對路徑>` 寫入安全 provenance receipt;它不代表核准執行寫入。完整旗標與每個指令的區塊詳見 [reference.md](reference.md#commands)。
|
|
157
159
|
|
|
158
160
|
## Audit Log 使用
|
|
159
161
|
|
|
@@ -329,6 +331,7 @@ dbcli init --conn-name prod --env-file .env.production --use-env-refs --skip-tes
|
|
|
329
331
|
| `shell` | (與 query 同) | 互動式 REPL。SQL 引擎、MongoDB 與 Redis(單行;`.no-limit on/off`)。Elasticsearch 開啟 Kibana Dev Tools 風格的 REPL(`<METHOD> /<path>` + 可選 JSON body,空白行送出)。 |
|
|
330
332
|
| `skill` | n/a | 產出 / 安裝 AI skill 文件(`--install <claude\|gemini\|antigravity\|copilot\|cursor\|codex\|windsurf>`);`skill tasks list/show/plan` 提供 Agent Task Packs;`skill context` 提供 LLM 提示詞脈絡載荷(用於注入其他 LLM,正常操作不需要)。 |
|
|
331
333
|
| `semantic` | n/a | 驗證、搜尋、檢查漂移、遷移至 v2 或輸出可選的專案根目錄 `dbcli.semantic.json`。把已檢閱的 context 交給外部 agent,但 provider 憑證、prompt 與 agent context 都留在 dbcli 外。`semantic draft validate --input <file|-> [--format text\|json]` 只會以本機 semantic/schema/saved-query metadata 離線驗證明確提交、不受信任的 `QueryDraft`;只回傳安全的 hash/reference/violation code,絕不執行或回顯 candidate SQL。先檢閱原始 draft,若要執行再另行呼叫 `explain` 或 `query`。 |
|
|
334
|
+
| `contract` | n/a | 驗證、檢視 approved context、搜尋或檢查可選專案根目錄 `dbcli.contracts.json` 的漂移。契約為 canonical semantic reference 加上 owner 與描述性的 evidence policy;完全離線、絕不執行 SQL,也不能建立 verification 或 query 權限。`skill context` 只納入有效且 approved 的契約。 |
|
|
332
335
|
| `migrate` | admin | 僅 SQL。**DDL;預設 dry-run** — 需 `--execute`。 |
|
|
333
336
|
|
|
334
337
|
任何指令都可使用 root 層級的 `dbcli --use <name> <command>`;`query`、`schema`、`list`、`export`、`check` 也接受指令層級的 `--use`。兩種寫法都只把本次目標切到 v2 連線,不改變預設值。`--recovery` 被 `query`、`q`、`insert`、`update`、`delete`、`export`、`schema`、`inspect`、`lint` 與 `diff --against-orm` 支援(見上方**失敗時**)。
|
|
@@ -469,4 +472,4 @@ dbcli export "SELECT * FROM orders" --format html --output orders.html
|
|
|
469
472
|
- 被 blacklist 的 table / column 會從查詢輸出中遮蔽。
|
|
470
473
|
- `schema` 回報 `estimatedRowCount` 與 `sizeCategory`(small / medium / large / huge)。大 / 巨大表要加 `WHERE` 或 `LIMIT` — 分界值見 [reference.md](reference.md#schema)。
|
|
471
474
|
- 對 `mongodb+srv://` 連線,`doctor` 會回報 SRV 是用原生解析或走 DoH fallback — 在執行環境限制 DNS 時很有用。
|
|
472
|
-
- **全域旗標:** `--version`、`--config <path>`、`--global`、`--use <name>`、`--timeout <ms>`、`-v` / `--verbose` / `-vv`、`-q` / `--quiet`、`--no-color`(也尊重 `NO_COLOR`)。除非指令明確宣告 command-level 選項,否則 root-level 旗標必須放在指令之前。
|
|
475
|
+
- **全域旗標:** `--version`、`--config <path>`、`--global`、`--use <name>`、`--timeout <ms>`、`--statement-timeout <ms>`、`-v` / `--verbose` / `-vv`、`-q` / `--quiet`、`--no-color`(也尊重 `NO_COLOR`)。除非指令明確宣告 command-level 選項,否則 root-level 旗標必須放在指令之前。
|
package/assets/reference.md
CHANGED
|
@@ -38,6 +38,7 @@ never the right move.
|
|
|
38
38
|
[check](#check) ·
|
|
39
39
|
[diff](#diff) ·
|
|
40
40
|
[design](#design) ·
|
|
41
|
+
[impact assess](#impact-assess) ·
|
|
41
42
|
[snapshot](#snapshot) ·
|
|
42
43
|
[assert](#assert) ·
|
|
43
44
|
[proxy](#proxy) ·
|
|
@@ -51,12 +52,14 @@ never the right move.
|
|
|
51
52
|
[verify](#verify) ·
|
|
52
53
|
[verification](#verification) ·
|
|
53
54
|
[backfill](#backfill) ·
|
|
55
|
+
[evidence](#evidence) ·
|
|
54
56
|
[doctor](#doctor) ·
|
|
55
57
|
[completion](#completion) ·
|
|
56
58
|
[upgrade](#upgrade) ·
|
|
57
59
|
[shell](#dbcli-shell) ·
|
|
58
60
|
[migrate](#migrate) ·
|
|
59
61
|
[semantic](#semantic) ·
|
|
62
|
+
[contract](#contract) ·
|
|
60
63
|
[skill](#skill) ·
|
|
61
64
|
[skill context](#skill-context) ·
|
|
62
65
|
[skill tasks](#skill-tasks-agent-task-packs)
|
|
@@ -80,13 +83,16 @@ command-level option is only valid after the command that declares it.
|
|
|
80
83
|
| `--global` | Select the user-global registry at `~/.config/dbcli/config.json` instead of the current project's `.dbcli` config. Place it before the command path. |
|
|
81
84
|
| `--use <connection>` | Select a named connection for this invocation; place it before the command path unless that command explicitly lists a command-level `--use`. |
|
|
82
85
|
| `--timeout <ms>` | Connection timeout in milliseconds (integer, 100–600000), overriding the connection config's `timeout` field for this invocation. Applies to every engine adapter. Without either the flag or the config field, adapters fall back to their built-in 5000ms default. |
|
|
86
|
+
| `--statement-timeout <ms>` | How long a single statement may run, in milliseconds (integer, 0–3600000; `0` removes the limit), overriding the connection config's `statementTimeout` field. Independent of the connection timeout — raising it does not slow down detection of an unreachable host. Falls back to `--timeout` when unset, and to the server's own setting when neither is given. |
|
|
83
87
|
|
|
84
88
|
`--timeout` is applied only when the adapter is constructed for this invocation — it is
|
|
85
89
|
never written back to `config.json`. Set the connection's `timeout` field instead for a
|
|
86
|
-
value that persists across runs.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
value that persists across runs. `--timeout` caps statement time as well as connection time, so a
|
|
91
|
+
low value cuts off a long-running query with an error that reads like a connection
|
|
92
|
+
problem; the 100ms floor exists specifically to keep that failure mode from being too
|
|
93
|
+
easy to trigger. Use `--statement-timeout` when only the statement limit should change.
|
|
94
|
+
With neither flag, dbcli sets no statement limit at all — the server's setting decides,
|
|
95
|
+
so a query that runs longer than the connection timeout is no longer cut off.
|
|
90
96
|
Elasticsearch applies its timeout per request rather than once for the whole connection.
|
|
91
97
|
The `timeout` field itself always takes a literal number — unlike other connection
|
|
92
98
|
fields, it does not accept an `{"$env": "..."}` reference.
|
|
@@ -217,8 +223,8 @@ dbcli list --include-system # Elasticsearch: include `.system` indices
|
|
|
217
223
|
**Permission:** query-only+
|
|
218
224
|
|
|
219
225
|
> **MongoDB:** Lists collections with estimated document count.
|
|
220
|
-
> **Redis:**
|
|
221
|
-
> **Elasticsearch:** Returns indices with `documentCount` from `/
|
|
226
|
+
> **Redis:** Samples the first 1 000 keys scanned via `SCAN MATCH * COUNT 1000`, applying the blacklist during the scan. When the keyspace is larger, table output adds a `Sampled the first 1000 keys scanned` line and JSON output carries `sampled: true` with `sampleLimit`. The header reads `Keys in db <n> (redis):` where `<n>` is the logical DB index.
|
|
227
|
+
> **Elasticsearch:** Returns indices with `documentCount` from one `/_cat/indices?h=index,docs.count&expand_wildcards=all` request (open and closed indices alike). The count is primaries-only, so a replicated index no longer reports its replica copies as extra documents. Aliases are tagged separately. System indices (names starting with `.`) are hidden unless `--include-system` is passed.
|
|
222
228
|
|
|
223
229
|
### schema
|
|
224
230
|
|
|
@@ -240,6 +246,13 @@ dbcli schema --use prod # Scan prod DB; saves to .dbcli/schemas/prod
|
|
|
240
246
|
**Options:** `--format <table|json>`, `--refresh`, `--reset`, `--force`, `--use <connection>`, `--sample-size <n>` (mongo only), `--sample-method <random|natural>` (mongo only)
|
|
241
247
|
**Permission:** query-only+
|
|
242
248
|
|
|
249
|
+
> **Row counts on a full scan:** scanning every table records
|
|
250
|
+
> `rowCountIsEstimate: true` and reports the engine's row *estimate* (`information_schema.TABLES.TABLE_ROWS` on MySQL/MariaDB,
|
|
251
|
+
> `pg_class.reltuples` on PostgreSQL) rather than running `COUNT(*)` per table —
|
|
252
|
+
> a hundred full-table counts is what made scanning a large database unusable.
|
|
253
|
+
> `dbcli schema <table>` on a single table still reports the exact count. Tables
|
|
254
|
+
> are scanned with bounded parallelism (4 at a time).
|
|
255
|
+
|
|
243
256
|
**Schema storage (v1.4+):** Schema is persisted as layered files under `.dbcli/schemas/`. With v2 multi-connection config each connection gets its own subdirectory (`.dbcli/schemas/<connection>/`). Run `dbcli schema --use <connection>` once per connection before querying it — otherwise `schema <table>` may return data from the wrong connection's cache.
|
|
244
257
|
|
|
245
258
|
> **PostgreSQL:** Introspection uses the exact `public` catalog identity throughout. Full catalog/schema/table joins prevent a reused constraint name from contaminating another table; enum lookup includes its namespace; composite primary-key order comes from the exact table OID and index ordinality; and row estimates are scoped to the exact `public` relation. Row-count SQL qualifies and quotes both `"public"` and the exact table identifier, escaping embedded quotes so mixed-case or punctuation-bearing names remain distinct and safe.
|
|
@@ -283,6 +296,12 @@ dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdou
|
|
|
283
296
|
**Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--fields <list>`, `--truncate <number>` / `--no-truncate`, `-f, --query-file <path>`, `--use <name[,name]>`, `--slow-ms <number>`, `--recovery`
|
|
284
297
|
**Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
|
|
285
298
|
|
|
299
|
+
> **Server-side scripts are rejected on every path.** MongoDB `$where`,
|
|
300
|
+
> `$function`, and `$accumulator`, and Elasticsearch `script` / `script_fields`,
|
|
301
|
+
> execute code on the database server. The adapters reject them anywhere in a
|
|
302
|
+
> filter, pipeline, or DSL body — before the request is sent — so `query`, `q`,
|
|
303
|
+
> saved snippets, and DML planning all behave the same way.
|
|
304
|
+
|
|
286
305
|
#### Passive slow-query hint (`--slow-ms`)
|
|
287
306
|
|
|
288
307
|
`query` and `q` read the execution time they already measured for a finished
|
|
@@ -1189,6 +1208,7 @@ dbcli design validate [--file <path>] [--format <format>]
|
|
|
1189
1208
|
dbcli design render [--file <path>] [--format <format>]
|
|
1190
1209
|
dbcli design diff (--against-cache | --against-orm <paths>) [options]
|
|
1191
1210
|
dbcli design propose (--against-cache | --against-orm <paths>) [options]
|
|
1211
|
+
dbcli impact assess --design <path> (--against-cache | --against-orm <paths>) --output <path> [options]
|
|
1192
1212
|
```
|
|
1193
1213
|
|
|
1194
1214
|
```bash
|
|
@@ -1200,6 +1220,7 @@ dbcli design render --format mermaid
|
|
|
1200
1220
|
dbcli design diff --against-cache --format markdown
|
|
1201
1221
|
dbcli design diff --against-orm ./prisma/schema.prisma --format markdown
|
|
1202
1222
|
dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
|
|
1223
|
+
dbcli impact assess --design ./dbcli.design.json --against-cache --output ./impact.json --fail-on warn
|
|
1203
1224
|
```
|
|
1204
1225
|
|
|
1205
1226
|
| Option | Applies to | Default | Meaning |
|
|
@@ -1216,6 +1237,10 @@ dbcli design propose --against-orm ./prisma/schema.prisma --format markdown
|
|
|
1216
1237
|
`diff` and `propose` require **exactly one** comparison target; passing both or
|
|
1217
1238
|
neither is an error.
|
|
1218
1239
|
|
|
1240
|
+
### impact assess
|
|
1241
|
+
|
|
1242
|
+
Writes an offline JSON or Markdown report for the known declared impact of a design change. It requires `--design`, exactly one baseline (`--against-cache` or `--against-orm`), and an explicit workspace-contained `--output`. `--format` is `json` (default) or `markdown`; `--fail-on` is `error`, `warn`, or `never` (default). The threshold changes only the successful command exit code after the report is written. The report is limited to declared/partial coverage and never claims complete coverage. It may join the optional reviewed `dbcli.data-access.json` manifest only after validating its canonical semantic references and existing workspace-relative source paths; it never reads those sources. An optional explicit `--events <path>` is bounded and streamed through a redaction-first projection that retains recent safe table metadata only. It never starts a proxy, reads a rotated log, renders SQL/literals/errors/sessions/paths, or makes the command fail solely because workload evidence is absent or advisory. It reads no database, executes no SQL, and never reads saved-query bodies.
|
|
1243
|
+
|
|
1219
1244
|
#### Artifact shape
|
|
1220
1245
|
|
|
1221
1246
|
This example validates clean (0 errors, 0 warnings):
|
|
@@ -1939,7 +1964,7 @@ Output reports: writer enabled/disabled, last write result, file-lock state, rot
|
|
|
1939
1964
|
### verify
|
|
1940
1965
|
|
|
1941
1966
|
Run a verification scenario. `verify` **runs** verification scenarios (safe-backfill,
|
|
1942
|
-
migration, rollback) and never executes writes/DDL. `verification` **inspects and manages**
|
|
1967
|
+
migration, rollback, constraint) and never executes writes/DDL. `verification` **inspects and manages**
|
|
1943
1968
|
the local result artifacts those scenarios produce under `.dbcli/verification/`.
|
|
1944
1969
|
|
|
1945
1970
|
```bash
|
|
@@ -1951,7 +1976,8 @@ dbcli verify safe-backfill \
|
|
|
1951
1976
|
--expect "value == 0"
|
|
1952
1977
|
|
|
1953
1978
|
# After-write: re-run guards, run the read-back assertion, write a v1 artifact.
|
|
1954
|
-
|
|
1979
|
+
# An optional receipt is provenance only, never approval to execute a write.
|
|
1980
|
+
dbcli verify safe-backfill ... --after-write --evidence-receipt .dbcli/evidence/verify-receipt.json
|
|
1955
1981
|
|
|
1956
1982
|
# JSON for agents.
|
|
1957
1983
|
dbcli verify safe-backfill ... --format json
|
|
@@ -1959,7 +1985,11 @@ dbcli verify safe-backfill ... --format json
|
|
|
1959
1985
|
|
|
1960
1986
|
Options: `--table` (req), `--query` (req, analyzed not executed), `--verify-query`
|
|
1961
1987
|
(req, **plain SELECT only**), `--expect` (req), `--after-write`, `--format <table|json>`,
|
|
1962
|
-
`--subject-name <name>`, `--summary <text
|
|
1988
|
+
`--subject-name <name>`, `--summary <text>`, `--evidence-receipt <workspace-relative-path>`
|
|
1989
|
+
(after-write only). A receipt is safe provenance for the already-executed verification,
|
|
1990
|
+
not approval to execute a write. Its `succeeded`/`failed` outcome remains distinct from
|
|
1991
|
+
the artifact status (`verified`, `not_verified`, `indeterminate`, or `blocked`); task-pack
|
|
1992
|
+
`planned` evidence stays plan-only.
|
|
1963
1993
|
|
|
1964
1994
|
Guard constraints (fail closed): `--verify-query` must be a **plain `SELECT`** —
|
|
1965
1995
|
`EXPLAIN`/`EXPLAIN ANALYZE`, `SHOW`, `DESCRIBE`, and data-modifying CTEs are rejected
|
|
@@ -2464,6 +2494,66 @@ dbcli migrate drop-enum status --execute --force
|
|
|
2464
2494
|
|
|
2465
2495
|
**AI agent note:** Always use dry-run first (no `--execute`) to preview generated SQL. Only add `--execute` after confirming the SQL is correct. For DROP operations, both `--execute` and `--force` are required.
|
|
2466
2496
|
|
|
2497
|
+
### evidence
|
|
2498
|
+
|
|
2499
|
+
Compose a canonical, offline **Evidence Pack** from existing verification artifacts
|
|
2500
|
+
and audit entries. This command never opens a database connection. A pack retains only
|
|
2501
|
+
safe pointers and outcome fields: it excludes SQL, targets, audit metadata, verification
|
|
2502
|
+
summaries, result data, and credentials. Claims are external statements, never dbcli
|
|
2503
|
+
verification verdicts.
|
|
2504
|
+
|
|
2505
|
+
#### `evidence compose`
|
|
2506
|
+
|
|
2507
|
+
```bash
|
|
2508
|
+
dbcli evidence compose --claims ./claims.json --verification ver_abcd --audit 1a2b \
|
|
2509
|
+
--receipt .dbcli/evidence/verify-receipt.json \
|
|
2510
|
+
--output .dbcli/evidence/review.json --format json
|
|
2511
|
+
```
|
|
2512
|
+
|
|
2513
|
+
| Flag | Purpose | Default |
|
|
2514
|
+
|---|---|---|
|
|
2515
|
+
| `--claims <file>` | Required JSON file with exactly `subject` and `claims`; every claim has an `id` and plain-language `text`. SQL-shaped text, credentials, error content, and blacklisted identifiers are rejected. | — |
|
|
2516
|
+
| `--verification <selector...>` | One or more verification artifact ids, unique prefixes, filenames, or in-bounds paths. | none |
|
|
2517
|
+
| `--audit <selector...>` | One or more audit ids or unique prefixes (minimum four characters) from the active connection. | none |
|
|
2518
|
+
| `--receipt <path...>` | Explicit workspace-relative receipt path(s). Receipts contribute safe provenance only; they are not execution approval. | none |
|
|
2519
|
+
| `--output <path>` | Required new JSON path under the current workspace. Existing files and paths outside the workspace are refused. | — |
|
|
2520
|
+
| `--format <json\|markdown>` | Compose receipt format printed to stdout. | `json` |
|
|
2521
|
+
|
|
2522
|
+
At least one `--verification`, `--audit`, or `--receipt` reference is required. The resulting pack
|
|
2523
|
+
contains a canonical SHA-256 integrity digest and `coverage.completeForDeclaredEvidence:
|
|
2524
|
+
true` for its explicitly selected references.
|
|
2525
|
+
|
|
2526
|
+
#### `evidence validate`
|
|
2527
|
+
|
|
2528
|
+
```bash
|
|
2529
|
+
dbcli evidence validate --file .dbcli/evidence/review.json --format json
|
|
2530
|
+
```
|
|
2531
|
+
|
|
2532
|
+
| Flag | Purpose | Default |
|
|
2533
|
+
|---|---|---|
|
|
2534
|
+
| `--file <path>` | Required evidence-pack JSON file. | — |
|
|
2535
|
+
| `--format <json\|markdown>` | Validation report format. | `json` |
|
|
2536
|
+
|
|
2537
|
+
Exit `0` when digest and all selected sources are valid. If a referenced audit or
|
|
2538
|
+
verification artifact later rotates, is cleared, disappears, or belongs to a different
|
|
2539
|
+
active connection, output stays parseable with `integrity: "valid"` and
|
|
2540
|
+
`references: "source-expired"`, then exits `1`.
|
|
2541
|
+
|
|
2542
|
+
#### `evidence render`
|
|
2543
|
+
|
|
2544
|
+
```bash
|
|
2545
|
+
dbcli evidence render --file .dbcli/evidence/review.json --format markdown
|
|
2546
|
+
```
|
|
2547
|
+
|
|
2548
|
+
| Flag | Purpose | Default |
|
|
2549
|
+
|---|---|---|
|
|
2550
|
+
| `--file <path>` | Required evidence-pack JSON file. | — |
|
|
2551
|
+
| `--format <json\|markdown>` | Render format. | `markdown` |
|
|
2552
|
+
|
|
2553
|
+
`render` validates the pack digest and active blacklist policy but does not resolve its
|
|
2554
|
+
original references. It is therefore available for historical review after `validate`
|
|
2555
|
+
reports `source-expired`, unless an exposed pack field is now blacklisted.
|
|
2556
|
+
|
|
2467
2557
|
### semantic
|
|
2468
2558
|
|
|
2469
2559
|
Validate or print the optional, version-controlled `dbcli.semantic.json` in the
|
|
@@ -2590,6 +2680,39 @@ limits, audit, and recovery safeguards remain in force.
|
|
|
2590
2680
|
|
|
2591
2681
|
**Permission:** n/a (local files only; no database connection).
|
|
2592
2682
|
|
|
2683
|
+
### contract
|
|
2684
|
+
|
|
2685
|
+
Inspect the optional, version-controlled `dbcli.contracts.json` without opening a
|
|
2686
|
+
database connection. A contract adds a reviewed owner and descriptive evidence policy
|
|
2687
|
+
to canonical semantic references; it is not an executable data contract, assertion,
|
|
2688
|
+
query, or verification scenario.
|
|
2689
|
+
|
|
2690
|
+
```bash
|
|
2691
|
+
dbcli contract validate --format json
|
|
2692
|
+
dbcli contract context --format json
|
|
2693
|
+
dbcli contract context --format markdown
|
|
2694
|
+
dbcli contract search customer --format json
|
|
2695
|
+
dbcli contract drift --format json
|
|
2696
|
+
```
|
|
2697
|
+
|
|
2698
|
+
The strict v1 artifact contains `version` and `contracts`. Each contract has a unique
|
|
2699
|
+
canonical `name`, `status` (`draft`, `approved`, or `deprecated`), bounded plain-text
|
|
2700
|
+
`description` and `owner`, one or more canonical semantic `subjects`, optional aliases,
|
|
2701
|
+
and an `evidencePolicy` of `none`, `receipt-required`, or `verification-required`.
|
|
2702
|
+
Subjects must remain in the existing visible semantic registry; protected identifiers,
|
|
2703
|
+
unknown keys, duplicate names or subjects, SQL-like text, credentials, and stale
|
|
2704
|
+
references fail closed without exposing protected names.
|
|
2705
|
+
|
|
2706
|
+
`contract validate` requires an explicit valid artifact. `contract context` and
|
|
2707
|
+
`contract search` return only valid approved contracts; draft and deprecated contracts
|
|
2708
|
+
remain local review artifacts. `contract drift` reports `valid`, `stale`, `invalid`, or
|
|
2709
|
+
`unavailable` evidence offline and exits non-zero except for `valid`. A missing default
|
|
2710
|
+
file is allowed by `skill context` and leaves ordinary semantic context unchanged; a
|
|
2711
|
+
present invalid file fails closed. No contract command writes a file, opens a database
|
|
2712
|
+
connection, widens a `QueryDraft`, or changes permission/blacklist behavior.
|
|
2713
|
+
|
|
2714
|
+
**Permission:** n/a (local files only; no database connection).
|
|
2715
|
+
|
|
2593
2716
|
### skill
|
|
2594
2717
|
|
|
2595
2718
|
Emit `SKILL.md` (and the companion `reference.md`) to stdout, a file, or an
|
package/assets/ui-template.html
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>dbcli Interactive Report</title>
|
|
7
7
|
<style id="dbcli-style">
|
|
8
|
-
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap")
|
|
8
|
+
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap");*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
|
|
9
9
|
|
|
10
|
-
/*! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}body{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity));font-family:Inter,system-ui,sans-serif;--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.card{overflow:hidden;border-radius:.75rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));--tw-shadow:0 2px 15px -3px #00000012,0 4px 6px -2px #0000000d;--tw-shadow-colored:0 2px 15px -3px var(--tw-shadow-color),0 4px 6px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.sticky{position:sticky}.top-0{top:0}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-8{margin-bottom:2rem}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[450px\]{height:450px}.h-full{height:100%}.min-h-0{min-height:0}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.max-w-7xl{max-width:80rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-slate-50>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(248 250 252/var(--tw-divide-opacity))}.overflow-x-auto{overflow-x:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-amber-300{--tw-border-opacity:1;border-color:rgb(252 211 77/var(--tw-border-opacity))}.border-primary-100{--tw-border-opacity:1;border-color:rgb(219 234 254/var(--tw-border-opacity))}.border-sky-200{--tw-border-opacity:1;border-color:rgb(186 230 253/var(--tw-border-opacity))}.border-slate-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity))}.border-l-primary-500{--tw-border-opacity:1;border-left-color:rgb(59 130 246/var(--tw-border-opacity))}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity))}.bg-primary-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity))}.bg-sky-50{--tw-bg-opacity:1;background-color:rgb(240 249 255/var(--tw-bg-opacity))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity))}.bg-slate-50\/30{background-color:#f8fafc4d}.bg-slate-50\/50{background-color:#f8fafc80}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/80{background-color:#fffc}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-1{padding-bottom:.25rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity))}.text-amber-950{--tw-text-opacity:1;color:rgb(69 26 3/var(--tw-text-opacity))}.text-emerald-600{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.text-primary-900{--tw-text-opacity:1;color:rgb(30 58 138/var(--tw-text-opacity))}.text-sky-600{--tw-text-opacity:1;color:rgb(2 132 199/var(--tw-text-opacity))}.text-sky-950{--tw-text-opacity:1;color:rgb(8 47 73/var(--tw-text-opacity))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow-lg{--tw-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:bg-primary-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity))}.hover\:bg-primary-50\/30:hover{background-color:#eff6ff4d}.hover\:text-primary-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:text-primary-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity))}@media (min-width:640px){.sm\:flex{display:flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:p-8{padding:2rem}}
|
|
10
|
+
/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}body{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1));font-family:Inter,system-ui,sans-serif;--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.card{overflow:hidden;border-radius:.75rem;border-width:1px;--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1));--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));--tw-shadow:0 2px 15px -3px rgba(0,0,0,.07),0 4px 6px -2px rgba(0,0,0,.05);--tw-shadow-colored:0 2px 15px -3px var(--tw-shadow-color),0 4px 6px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.sticky{position:sticky}.top-0{top:0}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-8{margin-bottom:2rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[450px\]{height:450px}.h-full{height:100%}.min-h-0{min-height:0}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.max-w-7xl{max-width:80rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-slate-50>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(248 250 252/var(--tw-divide-opacity,1))}.overflow-x-auto{overflow-x:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-amber-300{--tw-border-opacity:1;border-color:rgb(252 211 77/var(--tw-border-opacity,1))}.border-primary-100{--tw-border-opacity:1;border-color:rgb(219 234 254/var(--tw-border-opacity,1))}.border-sky-200{--tw-border-opacity:1;border-color:rgb(186 230 253/var(--tw-border-opacity,1))}.border-slate-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-l-primary-500{--tw-border-opacity:1;border-left-color:rgb(59 130 246/var(--tw-border-opacity,1))}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.bg-emerald-500{--tw-bg-opacity:1;background-color:rgb(16 185 129/var(--tw-bg-opacity,1))}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-primary-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-primary-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-sky-50{--tw-bg-opacity:1;background-color:rgb(240 249 255/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-200{--tw-bg-opacity:1;background-color:rgb(226 232 240/var(--tw-bg-opacity,1))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-slate-50\/30{background-color:rgba(248,250,252,.3)}.bg-slate-50\/50{background-color:rgba(248,250,252,.5)}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/80{background-color:hsla(0,0%,100%,.8)}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-1{padding-bottom:.25rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-amber-950{--tw-text-opacity:1;color:rgb(69 26 3/var(--tw-text-opacity,1))}.text-emerald-600{--tw-text-opacity:1;color:rgb(5 150 105/var(--tw-text-opacity,1))}.text-primary-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-primary-900{--tw-text-opacity:1;color:rgb(30 58 138/var(--tw-text-opacity,1))}.text-sky-600{--tw-text-opacity:1;color:rgb(2 132 199/var(--tw-text-opacity,1))}.text-sky-950{--tw-text-opacity:1;color:rgb(8 47 73/var(--tw-text-opacity,1))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:bg-primary-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-primary-50\/30:hover{background-color:rgba(239,246,255,.3)}.hover\:text-primary-600:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:text-primary-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:flex{display:flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:p-8{padding:2rem}}
|
|
11
11
|
</style>
|
|
12
12
|
</head>
|
|
13
13
|
<body class="bg-slate-50">
|