@graphit/cli 0.2.113 → 0.2.136
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +2 -0
- package/bin/graphit +1 -1
- package/bin/graphit.ps1 +1 -1
- package/dist/commands/connector.js +66 -2
- package/dist/commands/connector.js.map +1 -1
- package/dist/commands/ds-config.d.ts +45 -0
- package/dist/commands/ds-config.js +122 -0
- package/dist/commands/ds-config.js.map +1 -0
- package/dist/commands/ds.d.ts +0 -45
- package/dist/commands/ds.js +4 -128
- package/dist/commands/ds.js.map +1 -1
- package/dist/commands/governance.js +1 -17
- package/dist/commands/governance.js.map +1 -1
- package/dist/commands/kb-create.js +2 -2
- package/dist/commands/kb-create.js.map +1 -1
- package/dist/commands/kb-update.js +2 -2
- package/dist/commands/kb-update.js.map +1 -1
- package/dist/commands/query.d.ts +38 -0
- package/dist/commands/query.js +145 -18
- package/dist/commands/query.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/skill-guard.d.ts +4 -0
- package/dist/skill-guard.js +75 -0
- package/dist/skill-guard.js.map +1 -0
- package/package.json +1 -1
- package/scripts/plugin-status.mjs +48 -0
- package/skills/graphit/SKILL.md +15 -14
- package/skills/graphit/VERSION.json +1 -1
- package/skills/graphit/cursor/graphit-sql-reference.mdc +2 -2
- package/skills/graphit/graphit.mdc +6 -9
- package/skills/graphit/references/data-sources.md +7 -3
- package/skills/graphit/references/governance-explained.md +2 -2
- package/skills/graphit/references/governance.md +22 -17
- package/skills/graphit/references/kb-actions.md +2 -3
- package/skills/graphit/references/kb-traversal.md +1 -1
- package/skills/graphit/references/runtime.md +5 -1
- package/skills/graphit/references/sql-reference.md +15 -2
|
@@ -31,6 +31,8 @@ const result = await graphit.resolve({
|
|
|
31
31
|
- `maxRows` (optional) defaults to **10,000**, capped at **50,000**. Aggregate to a chartable grain well under the default; raise it only for a genuine row-level export, never above the cap.
|
|
32
32
|
- `result.data` is an array of row objects you render however you want.
|
|
33
33
|
|
|
34
|
+
MUST: every resolve that feeds a rendered graph, KPI, or table carries attribution - `target` (an element inside the entity wrapper), or `sourceEntityId` plus `targetEntityIds` when one result feeds several graphs. Attribution is what records the live filtered query behind each entity's details panel; an unattributed resolve leaves that panel showing the static `data-graphit-sql` example with its baked default filters, so a user who changes a filter sees the SQL never move. Saving a page that has filters or params and zero attributed resolves returns an `unattributed_resolves` warning. Queries that feed no visual (filter option lists, freshness probes) stay unattributed.
|
|
35
|
+
|
|
34
36
|
CRITICAL: use KB reference syntax (`{{metric:NAME}}`, `{{dim:NAME}}`) inside the resolve `sql` whenever a KB asset exists - the server expands it at query time, which produces the governed trust tier. See `governance.md` for the syntax and trust tiers.
|
|
35
37
|
|
|
36
38
|
Error handling: `graphit.resolve()` rejects on timeout (120s), bad SQL, or an invalid data source ID. Wrap calls in try/catch and show a user-visible error in the target element on failure. Verify the SQL returns data via the CLI before embedding it.
|
|
@@ -113,13 +115,15 @@ A resolve query that follows these shapes serves from a semantic cache in roughl
|
|
|
113
115
|
- `CURRENT_DATE`-relative predicates.
|
|
114
116
|
- Top-N with the aggregate only in ORDER BY (`... GROUP BY dim ORDER BY SUM(metric) DESC LIMIT N` with no decomposable aggregate in SELECT).
|
|
115
117
|
|
|
118
|
+
**Fresh anchors.** When a query needs a data-driven anchor - the latest install date, a "days since" reference, a MAX(date) - never fetch it once at page load into a JS variable and reuse it across refreshes. A long-open tab silently goes stale and every maturity gate or rolling window computed against it drifts. Re-resolve the anchor inside each refresh cycle, or derive it in a subquery so the query always anchors to the current data.
|
|
119
|
+
|
|
116
120
|
## Rate-limit budget
|
|
117
121
|
|
|
118
122
|
`graphit.resolve()` is rate-limited to 120 requests per minute per user per dashboard. Each call counts as one request. Design for that budget:
|
|
119
123
|
|
|
120
124
|
- **Single refresh function.** Put all queries in ONE `Promise.all` inside one `refresh()` function so they share the same time window. NEVER scatter `graphit.resolve()` across independent event handlers or timeouts - that turns one user action into several bursts.
|
|
121
125
|
- **Count queries per interaction.** 6 charts is 6 requests per filter change, about 20 changes per minute of budget; 12 charts is about 10 changes per minute. With 10 or more charts and 3 or more filters, debounce filter changes (300ms) so rapid clicks do not each trigger a full refresh.
|
|
122
|
-
- **Reuse trend data for KPIs.** If you already fetch a weekly time series, derive the KPI total and its sparkline from that result in JS instead of running a separate aggregate query - one query serves both.
|
|
126
|
+
- **Reuse trend data for KPIs.** If you already fetch a weekly time series, derive the KPI total and its sparkline from that result in JS instead of running a separate aggregate query - one query serves both. Anchor the extra graphs it feeds with `targetEntityIds` per the resolve attribution rule above. Canonical KPI-row example: `kpi.md`.
|
|
123
127
|
- **Avoid redundant refreshes.** If a filter affects only some charts, split into targeted refresh functions (`refreshKPIs()`, `refreshCharts()`) so unchanged sections do not re-query.
|
|
124
128
|
- **No polling.** NEVER use `setInterval(refresh, ...)`. Data sources update on their own schedule; a polling dashboard burns the entire budget.
|
|
125
129
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SQL Reference
|
|
2
2
|
|
|
3
|
-
Consult when writing queries. Data source queries (`graphit query --ds`) run DuckDB. Warehouse queries (`graphit query --warehouse`) run Snowflake. You MUST use the correct dialect. To read a table's columns, use `graphit kb explore table <NAME>` - never `DESCRIBE`/DDL (`graphit query` runs SELECT only).
|
|
3
|
+
Consult when writing queries. Data source queries (`graphit query --ds`) always run DuckDB. Warehouse queries (`graphit query --warehouse`) run the connected warehouse - Snowflake or BigQuery - and the dialect follows the connection type; governance parses your SQL in that dialect. You MUST use the correct dialect. To read a table's columns, use `graphit kb explore table <NAME>` - never `DESCRIBE`/DDL (`graphit query` runs SELECT only).
|
|
4
4
|
|
|
5
5
|
## DuckDB vs Snowflake Translation
|
|
6
6
|
|
|
@@ -50,6 +50,19 @@ NEVER use `->>` in Snowflake or `:field::STRING` in DuckDB.
|
|
|
50
50
|
- `COUNT_IF` MUST receive a boolean expression, not a raw INT column. Use `COUNT_IF(is_active = 1)`, not `COUNT_IF(is_active)`
|
|
51
51
|
- String matching: prefer `ILIKE` (case-insensitive) over `LIKE`
|
|
52
52
|
|
|
53
|
+
## BigQuery Standard SQL Notes
|
|
54
|
+
|
|
55
|
+
Applies only to `--warehouse` queries on a BigQuery connection. Key differences from Snowflake:
|
|
56
|
+
|
|
57
|
+
- Date math is `DATE_ADD(date, INTERVAL N DAY)` and `DATE_DIFF(a, b, DAY)` - the unit is a bare keyword and `DATE_DIFF` arg order is `(later, earlier, unit)`
|
|
58
|
+
- Null/branch: `IFNULL(a, b)` or `COALESCE(a, b)`; `IF(cond, a, b)` (not `IFF`); `NULLIF` as usual
|
|
59
|
+
- Error-tolerant: `SAFE_CAST(x AS INT64)`, `SAFE_DIVIDE(a, b)`, and the `SAFE.` prefix on most functions (`SAFE.PARSE_DATE(...)`) return NULL instead of erroring
|
|
60
|
+
- Dates/strings: `FORMAT_DATE('%Y-%m', d)`, `PARSE_DATE('%Y-%m-%d', s)`, `EXTRACT(MONTH FROM d)`, `DATE_TRUNC(d, MONTH)` (unit is a keyword, date-arg first)
|
|
61
|
+
- Approx: `APPROX_COUNT_DISTINCT(x)` (not `APPROX_COUNT_DISTINCT` colon syntax); `COUNTIF(cond)` is one word
|
|
62
|
+
- Like DuckDB and unlike Snowflake, BigQuery has `GROUP BY ALL` and `SELECT * EXCEPT(col)`
|
|
63
|
+
- Identifiers: back-tick fully-qualified names `` `project.dataset.table` ``; strings use single quotes
|
|
64
|
+
- JSON: `JSON_VALUE(col, '$.field')` (scalar) / `JSON_QUERY(col, '$.field')` (subtree) - not Snowflake colon syntax or DuckDB arrows
|
|
65
|
+
|
|
53
66
|
## SQL Formatting Standards (Both Engines)
|
|
54
67
|
|
|
55
68
|
- Keywords UPPERCASE: `SELECT`, `FROM`, `WHERE`, `JOIN`, `GROUP BY`, `ORDER BY`
|
|
@@ -117,7 +130,7 @@ When the query feeds a canvas `graphit.resolve()` call, write it in the cache-fr
|
|
|
117
130
|
|
|
118
131
|
## Data source routing
|
|
119
132
|
|
|
120
|
-
Always prefer a cached data source (`graphit query "SQL" --ds <NAME>`, roughly 100ms via DuckDB) over a live warehouse query (`graphit query "SQL" --warehouse --connection <id>`, roughly 10s via
|
|
133
|
+
Always prefer a cached data source (`graphit query "SQL" --ds <NAME>`, roughly 100ms via DuckDB) over a live warehouse query (`graphit query "SQL" --warehouse --connection <id>`, roughly 10s via the connected warehouse). Pass the data source name to `--ds` - the same name you SELECT FROM (a full id or unique id-prefix also works). The full routing table, the `ds list` output template, and the source-shape guidance live in `data-sources.md`.
|
|
121
134
|
|
|
122
135
|
## Percent scaling
|
|
123
136
|
|