@graphit/cli 0.2.322 → 0.2.323

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.
Files changed (62) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/bin/graphit +1 -1
  5. package/bin/graphit.ps1 +1 -1
  6. package/dist/api/client.js +15 -0
  7. package/dist/api/client.js.map +1 -1
  8. package/dist/commands/ds-config.js +2 -2
  9. package/dist/commands/ds-config.js.map +1 -1
  10. package/dist/commands/ds.js +2 -2
  11. package/dist/commands/ds.js.map +1 -1
  12. package/dist/commands/kb.js +347 -15
  13. package/dist/commands/kb.js.map +1 -1
  14. package/dist/commands/query.js +3 -3
  15. package/dist/commands/query.js.map +1 -1
  16. package/dist/index.js +0 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/skill-guard.js +2 -1
  19. package/dist/skill-guard.js.map +1 -1
  20. package/package.json +1 -1
  21. package/scripts/verb-policy-source.json +30 -102
  22. package/skills/graphit/SKILL.md +31 -39
  23. package/skills/graphit/VERSION.json +1 -1
  24. package/skills/graphit/references/data-source-refresh.md +27 -0
  25. package/skills/graphit/references/data-sources.md +27 -122
  26. package/skills/graphit/references/filters-advanced.md +2 -2
  27. package/skills/graphit/references/governance-explained.md +18 -29
  28. package/skills/graphit/references/governance.md +20 -83
  29. package/skills/graphit/references/kb-actions.md +28 -81
  30. package/skills/graphit/references/kb-discovery.md +35 -64
  31. package/skills/graphit/references/kb-scope.md +17 -15
  32. package/skills/graphit/references/kb-structure.md +28 -54
  33. package/skills/graphit/references/kb-traversal.md +24 -96
  34. package/skills/graphit/references/metric-families.md +19 -0
  35. package/skills/graphit/references/migration.md +2 -2
  36. package/skills/graphit/references/onboarding.md +5 -4
  37. package/skills/graphit/references/presentations.md +1 -1
  38. package/skills/graphit/references/runtime.md +6 -6
  39. package/skills/graphit/references/semantic-authoring.md +65 -0
  40. package/skills/graphit/references/sql-reference.md +10 -20
  41. package/dist/commands/kb-constraints.d.ts +0 -14
  42. package/dist/commands/kb-constraints.js +0 -53
  43. package/dist/commands/kb-constraints.js.map +0 -1
  44. package/dist/commands/kb-create.d.ts +0 -2
  45. package/dist/commands/kb-create.js +0 -296
  46. package/dist/commands/kb-create.js.map +0 -1
  47. package/dist/commands/kb-delete.d.ts +0 -2
  48. package/dist/commands/kb-delete.js +0 -37
  49. package/dist/commands/kb-delete.js.map +0 -1
  50. package/dist/commands/kb-read.d.ts +0 -2
  51. package/dist/commands/kb-read.js +0 -223
  52. package/dist/commands/kb-read.js.map +0 -1
  53. package/dist/commands/kb-shared.d.ts +0 -43
  54. package/dist/commands/kb-shared.js +0 -81
  55. package/dist/commands/kb-shared.js.map +0 -1
  56. package/dist/commands/kb-update.d.ts +0 -2
  57. package/dist/commands/kb-update.js +0 -240
  58. package/dist/commands/kb-update.js.map +0 -1
  59. package/dist/commands/sl/index.d.ts +0 -2
  60. package/dist/commands/sl/index.js +0 -263
  61. package/dist/commands/sl/index.js.map +0 -1
  62. package/skills/graphit/references/parameterized-metrics.md +0 -77
@@ -77,7 +77,7 @@ deck.slide({
77
77
  html: `
78
78
  <h2>Live Data</h2>
79
79
  <div data-graphit-id="spend-chart" data-graphit-label="Ad Spend"
80
- data-graphit-sql="SELECT {{dim:MEDIA_SOURCE_DIMENSION}} AS source, {{metric:TOTAL_AD_SPEND}} AS spend FROM MARKETING_UA_DS GROUP BY 1 ORDER BY spend DESC LIMIT 6"
80
+ data-graphit-sql="SELECT {{ Dimension('campaign__media_source') }} AS source, {{ Metric('total_ad_spend') }} AS spend FROM MARKETING_UA_DS GROUP BY 1 ORDER BY spend DESC LIMIT 6"
81
81
  data-graphit-ds="MARKETING_UA_DS">
82
82
  <div id="chart1" class="gh-loading">
83
83
  <div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="#e5e5e5" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="#4DB6AC" stroke-width="2.5" stroke-linecap="round"/></svg></div>
@@ -30,7 +30,7 @@ const result = await graphit.resolve({
30
30
 
31
31
  MUST: every resolve feeding a rendered graph, KPI, or table carries attribution - `target` (the entity wrapper or an element inside it), or `sourceEntityId` plus `targetEntityIds` when one result feeds several graphs. Attribution records the live filtered query behind that entity's details panel; unattributed, the panel shows `data-graphit-sql` as an unrun example, so a user changing a filter sees the SQL never move. Saving a page with filters or params and zero attributed resolves returns an `unattributed_resolves` warning. Queries feeding page chrome need no attribution and no entity, but belong on the primitives - `graphit.cascade` for option lists, `graphit.dataBounds` for a column's min/max, `graphit.rank` for top-N (`filters-advanced.md`) - never hand-written entity-less SQL.
32
32
 
33
- CRITICAL: use KB reference syntax (`{{metric:NAME}}`, `{{dim:NAME}}`) inside the entity's `data-graphit-sql` whenever a KB asset exists - the server expands it at query time, producing the governed trust tier. Syntax and trust tiers: `governance.md`.
33
+ CRITICAL: use `{{ Metric('name') }}`, `{{ Dimension('entity__name') }}`, or Graphit's `{{ Measure('name') }}` extension inside `data-graphit-sql` whenever the semantic asset exists. The server expands it into the governed tier. See `governance.md`.
34
34
 
35
35
  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.
36
36
 
@@ -41,7 +41,7 @@ Every visible element - chart, KPI card, table, text section - must be wrapped s
41
41
  ```html
42
42
  <div data-graphit-id="revenue-trend"
43
43
  data-graphit-label="Revenue Trend"
44
- data-graphit-sql="SELECT {{dim:REGION}} AS region, {{metric:REVENUE}} AS revenue FROM ORDERS_DS GROUP BY region"
44
+ data-graphit-sql="SELECT {{ Dimension('order__region') }} AS region, {{ Metric('revenue') }} AS revenue FROM ORDERS_DS GROUP BY region"
45
45
  data-graphit-ds="ORDERS_DS">
46
46
  <!-- chart, KPI, or table content here -->
47
47
  </div>
@@ -55,7 +55,7 @@ Every visible element - chart, KPI card, table, text section - must be wrapped s
55
55
  | `data-graphit-ds` | Data source name (same as the FROM table) or id | `"ORDERS_DS"` |
56
56
  | `data-graphit-state` | Not an entity attribute - a SIBLING wrapper around a user-changeable control, naming the state key saved views capture (`filters.md`) | `"country"` |
57
57
 
58
- KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` in the SQL; the governance compiler resolves these and shows KB asset chips in the details panel. Missing any one attribute breaks the entity; missing the wrapper makes the element invisible to the platform.
58
+ Semantic references are derived automatically from the final grammar; the compiler resolves them and shows asset chips in the details panel. Missing any one attribute breaks the entity; missing the wrapper makes the element invisible to the platform.
59
59
 
60
60
  **JavaScript may populate an entity, never create one.** Every entity - including on hidden tabs, collapsed panels, and lazily-shown views - exists as static markup in the HTML you save; JavaScript fills its chart host, wires listeners, and toggles visibility. Nothing server-side runs your JavaScript, so a card built at render time (`host.innerHTML = charts.map(...)`) does not exist for governance, lineage, the KB graph, `list-entities`, or a later `get-entity`. A save whose `data-graphit-id`s are reachable only by running your JavaScript is REFUSED and the error names them. A dynamic **query** is supported - the attribute carries the canonical template; a dynamic **entity** is not.
61
61
 
@@ -74,14 +74,14 @@ A filtered entity uses `graphit.bind(el, { params, deps, render })` (`filters.md
74
74
 
75
75
  ```html
76
76
  <div data-graphit-id="explorer" data-graphit-label="Metric Explorer" data-graphit-ds="UA_DS"
77
- data-graphit-sql="SELECT day, {{metric:ROAS}} AS roas FROM UA_DS GROUP BY 1"
78
- data-graphit-vocab="metric:REV*,metric:ROAS,dim:COUNTRY"></div>
77
+ data-graphit-sql="SELECT day, {{ Metric('roas') }} AS roas FROM UA_DS GROUP BY 1"
78
+ data-graphit-vocab="metric:revenue,metric:roas,dimension:campaign__country"></div>
79
79
  ```
80
80
  ```js
81
81
  graphit.resolve({ sql: buildSql(picked), dataSourceId: "UA_DS", runtimeComposed: true, sourceEntityId: "explorer" });
82
82
  ```
83
83
 
84
- `metric:NAME` / `dim:NAME`, UPPER_SNAKE_CASE, one optional trailing `*` per family; a space instead of a comma is one malformed entry. Declare the family, not today's SQL - but every name must exist (an unknown name, a wildcard matching nothing, or a bare `metric:*` refuses), and wildcards alone add no lineage. Undeclared inline SQL is invisible to lineage and governance; a save that ADDS one is refused, and existing ones are not a defect to fix - move a query onto its entity only when asked (`migration.md`).
84
+ Use comma-separated lowercase declarations such as `metric:revenue`, `dimension:order__region`, and `measure:order_total`. Every declared name must exist; unknown names and wildcards refuse. Undeclared inline SQL is invisible to lineage and governance. Existing runtime-composed queries are first-class, not debt; migrate query ownership only when asked (`migration.md`).
85
85
 
86
86
  **Label equals the visible title.** `data-graphit-label` MUST match the card's visible heading exactly - users find their chart by that label in @ mention dropdowns and entity panels, and a mismatch means they cannot find it.
87
87
 
@@ -0,0 +1,65 @@
1
+ # Semantic Authoring
2
+
3
+ Load when creating or changing semantic models or metrics.
4
+
5
+ ## Syntax boundary
6
+
7
+ Graphit accepts the MetricFlow 0.211 execution shape: semantic models contain
8
+ entities, dimensions, and measures; metrics are top-level objects with `type`
9
+ and `type_params`. Do not emit newer measureless/Fusion authoring syntax, dbt
10
+ project YAML, Jinja, `ref()` expressions, or source declarations on this
11
+ surface. Those belong to dbt project import/export, not Graphit authoring.
12
+
13
+ Public dbt/MetricFlow concepts:
14
+
15
+ - semantic model, entity, dimension, measure, metric, and group
16
+ - simple, ratio, and derived metric composition
17
+ - entity-qualified dimension paths
18
+
19
+ Graphit extensions and assets:
20
+
21
+ - `meta.graphit.family` and `axes` group concrete metric variants
22
+ - topics are curated Graphit metadata, deliberately not dbt `tags`
23
+ - rules are separate Graphit objects targeting semantic identities by name;
24
+ never embed them in dbt metadata
25
+ - verification attribution, provenance, and data-source bindings are
26
+ server-owned; use dedicated actions instead of hand-authoring them
27
+
28
+ Do not expose or depend on storage collection names, revision fields, feature
29
+ flags, cache keys, or compiler implementation details.
30
+
31
+ ## Semantic model
32
+
33
+ A semantic model owns:
34
+
35
+ - lowercase name and physical model/binding
36
+ - group placement
37
+ - primary grain/entity
38
+ - entities for joins
39
+ - dimensions for grouping/filtering
40
+ - measures for aggregation input
41
+ - defaults such as aggregation time dimension
42
+
43
+ Measure-bearing models need a valid aggregation time dimension. Primary/unique entity claims require grain evidence; never guess uniqueness. Time-aware shapes require the platform time-spine prerequisite.
44
+
45
+ Nested lists replace whole lists on update. Read the model and preserve every sibling.
46
+
47
+ ## Metrics
48
+
49
+ Only these shapes are served by the shipping fragment path:
50
+
51
+ - **simple:** one measure object
52
+ - **ratio:** numerator and denominator metric objects
53
+ - **derived:** expression over declared metric inputs or aliases
54
+
55
+ Metric-level and per-input filters must resolve through declared semantic identities. Bare strings where an input object is required are refused.
56
+
57
+ Cumulative, conversion, shifted inputs, time-spine joins, and null-fill are unavailable until Project #289. Use a supported decomposition or clearly labeled free SQL; do not create an unusable governed definition.
58
+
59
+ ## Verification
60
+
61
+ Create defaults to verified on human-driven CLI paths; `--unverified` creates a draft. Promote or demote with dedicated verify/unverify actions. Never replace `meta` only to toggle verification.
62
+
63
+ ## Final check
64
+
65
+ Re-read the root, verify nested completeness, inspect group/binding, and use the returned receipt. A degraded freshness result may mean the write landed; do not retry blindly.
@@ -1,6 +1,6 @@
1
1
  # SQL Reference
2
2
 
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).
3
+ Consult when writing queries. Data-source queries run DuckDB. Warehouse queries run the connected Snowflake or BigQuery dialect. Governance parses the same dialect. Read physical columns through metadata discovery or semantic-model physical detail; never use DDL through the SELECT-only query surface.
4
4
 
5
5
  ## DuckDB vs Snowflake Translation
6
6
 
@@ -138,22 +138,20 @@ The canvas `percent` format only appends `%` (it does not multiply by 100), so m
138
138
 
139
139
  ## Presenting Query Results
140
140
 
141
- After every `graphit query`, present results grounded in the KB. Always show which KB assets were used - this is what makes governed queries valuable.
142
-
143
- **When using KB reference syntax** (`{{metric:X}}`, `{{dim:X}}`), show all five sections:
141
+ After every query, show all five sections below. Use `--verbose` to obtain the resolved SQL. Executable SQL uses semantic references; narration uses backticked exact asset names so Graphit can render clickable KB pills.
144
142
 
145
143
  ~~~
146
- **KB Assets:** dimension **CAMPAIGN_CATEGORY**, metric **TOTAL_INSTALLS**, metric **CPI**, table **MARKETING_UA_DS**
144
+ **KB Assets:** dimension `campaign__category`, metrics `total_installs` and `cpi`, semantic model `marketing_ua`
147
145
 
148
146
  **Query:**
149
147
  ```sql
150
148
  SELECT
151
- {{dim:CAMPAIGN_CATEGORY}} AS category,
152
- {{metric:TOTAL_INSTALLS}} AS installs,
153
- {{metric:CPI}} AS cpi
149
+ {{ Dimension('campaign__category') }} AS category,
150
+ {{ Metric('total_installs') }} AS installs,
151
+ {{ Metric('cpi') }} AS cpi
154
152
  FROM MARKETING_UA_DS
155
153
  WHERE ACTIVITY_TIME >= '2026-01-01'
156
- GROUP BY {{dim:CAMPAIGN_CATEGORY}}
154
+ GROUP BY {{ Dimension('campaign__category') }}
157
155
  ORDER BY installs DESC
158
156
  ```
159
157
 
@@ -179,17 +177,9 @@ ORDER BY installs DESC
179
177
  | Retargeting | 12,300 | $1.24 |
180
178
  | Connected TV | 3,100 | $2.80 |
181
179
 
182
- **Governance:** governed - 3 KB refs, 2 rules enforced (**EXCLUDE_ORGANIC**, **MIN_SPEND**). Max rows: 1,000.
183
- ~~~
184
-
185
- **When using inline SQL** (no `{{metric:X}}`), present it the same way (query + results + governance), but the footer states the ad-hoc tier and offers the governed rewrite:
186
-
187
- ~~~
188
- **Governance:** ad-hoc - 0 KB refs. Consider using `{{metric:TOTAL_SPEND}}` for governed tier.
180
+ **Governance:** governed - 3 semantic refs; 2 rules enforced (`exclude_organic`, `min_spend`). Max rows: 1,000.
189
181
  ~~~
190
182
 
191
- Any ad-hoc query on the CLI is withheld until you justify it (full rules in governance.md): prefer a `{{metric:X}}` / `{{dim:X}}` rewrite, creating the metric or dimension first if it is missing, and pass `--adhoc-reason` only when nothing governed fits.
192
-
193
- **Always use `--verbose`** to get the resolved SQL; if the user didn't pass it, re-run with it.
183
+ For inline SQL, use the same sections but state the ad-hoc tier and offer a governed rewrite, for example: **Governance:** ad-hoc - 0 semantic refs. Consider `{{ Metric('total_spend') }}`. Author a supported root definition first when needed; provide an ad-hoc reason only when nothing governed fits.
194
184
 
195
- Zero rows: explain what you checked and hypothesize why (wrong date range, filter too strict, table empty).
185
+ For zero rows, explain the checks performed and likely cause, such as date range, filter, or empty source.
@@ -1,14 +0,0 @@
1
- /**
2
- * Pure parsers for `graphit kb create/update rule` --constraint / --apply-on flags.
3
- *
4
- * Extracted from kb.ts so they are unit-testable without Commander or the API
5
- * client (mirrors query-timeout.ts). Issue #548: the required_where quote
6
- * stripper used to remove ANY leading/trailing quote, so a predicate ending in
7
- * a SQL string literal lost its closing quote
8
- * (`MEDIA_SOURCE != 'organic'` -> `MEDIA_SOURCE != 'organic`), producing
9
- * unparseable SQL that the backend rejected - the constraint never persisted.
10
- */
11
- /** Strip wrapping quotes only when the value is wrapped in a matched pair. */
12
- export declare function unwrapQuotes(value: string): string;
13
- export declare function parseConstraintFlags(specs: string[]): Record<string, unknown>[];
14
- export declare function parseApplyOnFlags(specs: string[]): Record<string, string>[];
@@ -1,53 +0,0 @@
1
- /**
2
- * Pure parsers for `graphit kb create/update rule` --constraint / --apply-on flags.
3
- *
4
- * Extracted from kb.ts so they are unit-testable without Commander or the API
5
- * client (mirrors query-timeout.ts). Issue #548: the required_where quote
6
- * stripper used to remove ANY leading/trailing quote, so a predicate ending in
7
- * a SQL string literal lost its closing quote
8
- * (`MEDIA_SOURCE != 'organic'` -> `MEDIA_SOURCE != 'organic`), producing
9
- * unparseable SQL that the backend rejected - the constraint never persisted.
10
- */
11
- /** Strip wrapping quotes only when the value is wrapped in a matched pair. */
12
- export function unwrapQuotes(value) {
13
- const first = value[0];
14
- if (value.length >= 2 &&
15
- (first === '"' || first === "'") &&
16
- value[value.length - 1] === first) {
17
- return value.slice(1, -1);
18
- }
19
- return value;
20
- }
21
- export function parseConstraintFlags(specs) {
22
- return specs.map((spec) => {
23
- const colonIdx = spec.indexOf(":");
24
- if (colonIdx < 0)
25
- throw new Error(`Invalid constraint: "${spec}". Use type:value (e.g., forbidden_column:email)`);
26
- const type = spec.slice(0, colonIdx);
27
- const value = spec.slice(colonIdx + 1);
28
- switch (type) {
29
- case "required_where":
30
- return { type, predicate: unwrapQuotes(value) };
31
- case "forbidden_column":
32
- case "required_filter":
33
- case "required_aggregation":
34
- return { type, column: value };
35
- case "value_restriction": {
36
- const [col, op, ...valueParts] = value.split(":");
37
- const operator = op === "not_in" ? "not_in" : "in";
38
- return { type, column: col, values: valueParts.join(":").split(","), operator };
39
- }
40
- default:
41
- throw new Error(`Unknown constraint type: "${type}"`);
42
- }
43
- });
44
- }
45
- export function parseApplyOnFlags(specs) {
46
- return specs.map((spec) => {
47
- const colonIdx = spec.indexOf(":");
48
- if (colonIdx < 0)
49
- throw new Error(`Invalid apply-on: "${spec}". Use type:NAME (e.g., table:USERS)`);
50
- return { type: spec.slice(0, colonIdx), name: spec.slice(colonIdx + 1) };
51
- });
52
- }
53
- //# sourceMappingURL=kb-constraints.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kb-constraints.js","sourceRoot":"","sources":["../../src/commands/kb-constraints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;QACjB,CAAC,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;QAChC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK,EACjC,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,kDAAkD,CAAC,CAAC;QAClH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QACvC,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,gBAAgB;gBACnB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,KAAK,kBAAkB,CAAC;YACxB,KAAK,iBAAiB,CAAC;YACvB,KAAK,sBAAsB;gBACzB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YACjC,KAAK,mBAAmB,CAAC,CAAC,CAAC;gBACzB,MAAM,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,UAAU,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClD,MAAM,QAAQ,GAAG,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;gBACnD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC;YAClF,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,GAAG,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAe;IAC/C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,sCAAsC,CAAC,CAAC;QACpG,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1,2 +0,0 @@
1
- import { Command } from "commander";
2
- export declare function addKBCreateCommands(kb: Command): void;
@@ -1,296 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { apiClient } from "../api/client.js";
3
- import { output, errorOutput, getOutputFormat } from "../output/format.js";
4
- import { writeStderr } from "../stderr.js";
5
- import { styledIntro, styledOutro, styledSuccess, formatBold, } from "../output/styled.js";
6
- import { parseConstraintFlags, parseApplyOnFlags } from "./kb-constraints.js";
7
- import { renderValidation, renderVisibility, withVisibility, } from "./kb-shared.js";
8
- // Project #254 Phase 1: kb create verbs (metric/dimension/rule/domain/synonym/
9
- // relationship/topic/template). Tables are created from data sources.
10
- export function addKBCreateCommands(kb) {
11
- const create = kb
12
- .command("create")
13
- .description("Create KB entities. Tables are created from data sources - use 'graphit ds create'.");
14
- create
15
- .command("metric")
16
- .description("Create a new metric")
17
- .requiredOption("--name <name>", "Metric name (UPPER_SNAKE_CASE)")
18
- .requiredOption("--sql <expr>", "SQL calculation expression")
19
- .requiredOption("--table <table>", "Primary table")
20
- .option("--description <desc>", "Business meaning of the metric - what it counts and when to use it", "")
21
- .option("--topics <topics>", "Comma-separated topic names")
22
- .option("--default-dimensions <dims>", "Comma-separated dimension names this metric naturally groups by")
23
- .option("--parameters <json>", "JSON array of parameter definitions")
24
- .option("--parameters-file <path>", "Read parameters JSON from file")
25
- .option("--skip-validate", "Skip pre-creation data validation")
26
- .option("--unverified", "Create as a draft instead of verified (default: verified)")
27
- .action(async function () {
28
- try {
29
- const opts = this.opts();
30
- const fmt = getOutputFormat(this);
31
- const topics = opts.topics ? opts.topics.split(",").map((s) => s.trim()).filter(Boolean) : [];
32
- const defaultDimensions = opts.defaultDimensions ? opts.defaultDimensions.split(",").map((s) => s.trim()).filter(Boolean) : [];
33
- let parameters = [];
34
- if (opts.parametersFile) {
35
- parameters = JSON.parse(await readFile(opts.parametersFile, "utf-8"));
36
- }
37
- else if (opts.parameters) {
38
- parameters = JSON.parse(opts.parameters);
39
- }
40
- const skipValidate = opts.skipValidate ? "true" : "false";
41
- const resp = await apiClient.post(`/api/v1/cli/kb/metric?skip_validate=${skipValidate}`, {
42
- name: opts.name,
43
- calculation: opts.sql,
44
- table: opts.table,
45
- description: opts.description,
46
- topics,
47
- default_dimensions: defaultDimensions,
48
- parameters,
49
- unverified: Boolean(opts.unverified),
50
- });
51
- if (fmt === "styled") {
52
- styledIntro(`graphit kb create metric`);
53
- styledSuccess(`Metric ${formatBold(String(resp.entity.name))} created`);
54
- renderValidation(this, resp);
55
- renderVisibility(this, resp);
56
- styledOutro();
57
- }
58
- else {
59
- const out = withVisibility(this, { ...resp.entity }, resp);
60
- if (resp.validation)
61
- out.validation = resp.validation;
62
- output(this, out, { keyValue: true });
63
- }
64
- }
65
- catch (err) {
66
- errorOutput(err);
67
- }
68
- });
69
- create
70
- .command("dimension")
71
- .description("Create a new dimension")
72
- .requiredOption("--name <name>", "Dimension name (UPPER_SNAKE_CASE)")
73
- .requiredOption("--expr <expr>", "SQL expression")
74
- .requiredOption("--table <table>", "Primary table")
75
- .option("--type <type>", "Semantic type: categorical, temporal, quantitative, boolean, geographic (auto-inferred if omitted)")
76
- .option("--output-type <outputType>", "SQL output type: VARCHAR, NUMBER, BOOLEAN, DATE, TIMESTAMP (auto-inferred if omitted)")
77
- .option("--description <desc>", "Business meaning of the dimension - what it slices and when to use it", "")
78
- .option("--topics <topics>", "Comma-separated topic names")
79
- .option("--skip-validate", "Skip pre-creation data validation")
80
- .option("--unverified", "Create as a draft instead of verified (default: verified)")
81
- .action(async function () {
82
- try {
83
- const opts = this.opts();
84
- const fmt = getOutputFormat(this);
85
- const topics = opts.topics ? opts.topics.split(",").map((s) => s.trim()).filter(Boolean) : [];
86
- const body = {
87
- name: opts.name,
88
- expression: opts.expr,
89
- table: opts.table,
90
- description: opts.description,
91
- topics,
92
- unverified: Boolean(opts.unverified),
93
- };
94
- if (opts.type)
95
- body.semantic_type = opts.type;
96
- if (opts.outputType)
97
- body.output_type = opts.outputType;
98
- const skipValidate = opts.skipValidate ? "true" : "false";
99
- const resp = await apiClient.post(`/api/v1/cli/kb/dimension?skip_validate=${skipValidate}`, body);
100
- if (fmt === "styled") {
101
- styledIntro(`graphit kb create dimension`);
102
- styledSuccess(`Dimension ${formatBold(String(resp.entity.name))} created`);
103
- renderValidation(this, resp);
104
- renderVisibility(this, resp);
105
- styledOutro();
106
- }
107
- else {
108
- const out = withVisibility(this, { ...resp.entity }, resp);
109
- if (resp.validation)
110
- out.validation = resp.validation;
111
- output(this, out, { keyValue: true });
112
- }
113
- }
114
- catch (err) {
115
- errorOutput(err);
116
- }
117
- });
118
- create
119
- .command("rule")
120
- .description("Create a new rule. Without --apply-on the rule governs the whole --table, which cascades to every metric and dimension on it. Use --apply-on metric:NAME / dimension:NAME to govern only specific assets instead. A rule must apply to at least one asset (targetless rules are rejected).")
121
- .requiredOption("--name <name>", "Rule name (UPPER_SNAKE_CASE)")
122
- .requiredOption("--sql <expr>", "Rule content/SQL")
123
- .requiredOption("--table <table>", "Table the rule is about (validation context, and the whole-table target unless --apply-on narrows it)")
124
- .option("--description <desc>", "What the rule enforces and why it exists", "")
125
- .option("--topics <topics>", "Comma-separated topic names")
126
- .option("--constraint <spec...>", "Enforceable constraints (e.g., required_where:\"x=1\" forbidden_column:email)")
127
- .option("--enforcement-mode <mode>", "Rule enforcement: advisory|always|conditional")
128
- .option("--apply-on <targets...>", "What the rule governs. Omit to govern the whole --table (cascades to every metric/dimension on it). Use metric:NAME / dimension:NAME to govern only those assets. Cannot mix a table target with metric/dimension targets.")
129
- .option("--skip-validate", "Skip pre-creation data validation")
130
- .option("--unverified", "Create as a draft instead of verified (default: verified)")
131
- .action(async function () {
132
- try {
133
- const opts = this.opts();
134
- const fmt = getOutputFormat(this);
135
- const topics = opts.topics ? opts.topics.split(",").map((s) => s.trim()).filter(Boolean) : [];
136
- const constraints = opts.constraint ? parseConstraintFlags(opts.constraint) : undefined;
137
- const applyOn = opts.applyOn ? parseApplyOnFlags(opts.applyOn) : undefined;
138
- const skipValidate = opts.skipValidate ? "true" : "false";
139
- const resp = await apiClient.post(`/api/v1/cli/kb/rule?skip_validate=${skipValidate}`, {
140
- name: opts.name,
141
- content: opts.sql,
142
- table: opts.table,
143
- description: opts.description,
144
- topics,
145
- constraints,
146
- enforcement_mode: opts.enforcementMode,
147
- apply_on: applyOn,
148
- unverified: Boolean(opts.unverified),
149
- });
150
- if (fmt === "styled") {
151
- styledIntro(`graphit kb create rule`);
152
- styledSuccess(`Rule ${formatBold(String(resp.entity.name))} created`);
153
- renderValidation(this, resp);
154
- renderVisibility(this, resp);
155
- styledOutro();
156
- }
157
- else {
158
- const out = withVisibility(this, { ...resp.entity }, resp);
159
- if (resp.validation)
160
- out.validation = resp.validation;
161
- output(this, out, { keyValue: true });
162
- }
163
- }
164
- catch (err) {
165
- errorOutput(err);
166
- }
167
- });
168
- create
169
- .command("domain")
170
- .description("Create a new domain")
171
- .requiredOption("--name <name>", "Domain name (UPPER_SNAKE_CASE)")
172
- .option("--description <desc>", "What this domain covers - the business area its tables and assets belong to", "")
173
- .option("--color <hex>", "Hex color for UI", "#4DB6AC")
174
- .action(async function () {
175
- try {
176
- const opts = this.opts();
177
- const resp = await apiClient.post("/api/v1/cli/kb/domain", {
178
- name: opts.name,
179
- description: opts.description,
180
- color: opts.color,
181
- });
182
- output(this, resp.entity, { keyValue: true });
183
- }
184
- catch (err) {
185
- errorOutput(err);
186
- }
187
- });
188
- create
189
- .command("synonym")
190
- .description("Create a new synonym")
191
- .requiredOption("--term <term>", "Synonym term (e.g., GMV)")
192
- .requiredOption("--canonical <name>", "Canonical asset name (e.g., TOTAL_REVENUE)")
193
- .requiredOption("--type <type>", "Canonical type: metric, column, or table")
194
- .option("--description <desc>", "When this synonym applies - the phrasing users say for the canonical asset", "")
195
- .option("--unverified", "Create as a draft instead of verified (default: verified)")
196
- .action(async function () {
197
- try {
198
- const opts = this.opts();
199
- const resp = await apiClient.post("/api/v1/cli/kb/synonym", {
200
- term: opts.term,
201
- canonical: opts.canonical,
202
- canonical_type: opts.type,
203
- description: opts.description,
204
- unverified: Boolean(opts.unverified),
205
- });
206
- renderVisibility(this, resp);
207
- output(this, withVisibility(this, { ...resp.entity }, resp), { keyValue: true });
208
- }
209
- catch (err) {
210
- errorOutput(err);
211
- }
212
- });
213
- create
214
- .command("relationship")
215
- .description("Create a new relationship (JOIN between tables)")
216
- .requiredOption("--name <name>", "Relationship name (e.g., ORDERS_TO_CUSTOMERS)")
217
- .requiredOption("--primary-table <table>", "Primary table")
218
- .requiredOption("--primary-column <col>", "Primary column")
219
- .requiredOption("--related-table <table>", "Related table")
220
- .requiredOption("--related-column <col>", "Related column")
221
- .option("--description <desc>", "What this join represents in the business", "")
222
- .action(async function () {
223
- try {
224
- const opts = this.opts();
225
- const resp = await apiClient.post("/api/v1/cli/kb/relationship", {
226
- name: opts.name,
227
- primary_table: opts.primaryTable,
228
- primary_column: opts.primaryColumn,
229
- related_table: opts.relatedTable,
230
- related_column: opts.relatedColumn,
231
- description: opts.description,
232
- });
233
- renderVisibility(this, resp);
234
- output(this, withVisibility(this, { ...resp.entity }, resp), { keyValue: true });
235
- }
236
- catch (err) {
237
- errorOutput(err);
238
- }
239
- });
240
- create
241
- .command("topic")
242
- .description("Create a new topic (business-concept tag)")
243
- .requiredOption("--name <name>", "Topic name (UPPER_SNAKE_CASE)")
244
- .option("--description <desc>", "What this topic tags - the business concept its assets share", "")
245
- .action(async function () {
246
- try {
247
- const opts = this.opts();
248
- const resp = await apiClient.post("/api/v1/cli/kb/topic", {
249
- name: opts.name,
250
- description: opts.description,
251
- });
252
- output(this, resp.entity, { keyValue: true });
253
- }
254
- catch (err) {
255
- errorOutput(err);
256
- }
257
- });
258
- create
259
- .command("template")
260
- .description("Create a reusable template (chart, KPI, or filter control)")
261
- .requiredOption("--name <name>", "Template name (UPPER_SNAKE_CASE)")
262
- .option("--render-code <code>", "JS function body for rendering")
263
- .option("--file <path>", "Read render code from a local file")
264
- .option("--description <desc>", "What the template renders and when to reach for it", "")
265
- .option("--chart-types <types>", "Related chart types (comma-separated)", "")
266
- .action(async function () {
267
- try {
268
- const opts = this.opts();
269
- let renderCode;
270
- if (opts.file) {
271
- renderCode = await readFile(opts.file, "utf-8");
272
- }
273
- else if (opts.renderCode) {
274
- renderCode = opts.renderCode;
275
- }
276
- else {
277
- writeStderr(JSON.stringify({ error: "Provide --render-code or --file" }));
278
- process.exit(1);
279
- }
280
- const chartTypes = opts.chartTypes
281
- ? opts.chartTypes.split(",").map((s) => s.trim()).filter(Boolean)
282
- : [];
283
- const resp = await apiClient.post("/api/v1/cli/kb/template", {
284
- name: opts.name,
285
- render_code: renderCode,
286
- description: opts.description,
287
- chart_types: chartTypes,
288
- });
289
- output(this, resp.entity, { keyValue: true });
290
- }
291
- catch (err) {
292
- errorOutput(err);
293
- }
294
- });
295
- }
296
- //# sourceMappingURL=kb-create.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kb-create.js","sourceRoot":"","sources":["../../src/commands/kb-create.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { Command } from "commander";
2
- export declare function addKBDeleteCommands(kb: Command): void;
@@ -1,37 +0,0 @@
1
- import { apiClient } from "../api/client.js";
2
- import { errorOutput } from "../output/format.js";
3
- import { writeStderr } from "../stderr.js";
4
- import { KB_ARG_TYPE, KB_ARG_NAME } from "./kb-shared.js";
5
- // Project #254 Phase 1: kb delete verb.
6
- export function addKBDeleteCommands(kb) {
7
- kb.command("delete")
8
- .argument("<type>", KB_ARG_TYPE)
9
- .argument("<name>", KB_ARG_NAME)
10
- .description("Delete a KB entity (requires --yes flag)")
11
- .requiredOption("--yes", "Confirm deletion")
12
- // Project #272 F-6: a private asset belonging to another member can block a
13
- // shared asset's delete, and the refusal names who to ask. --force is the
14
- // other half of that: it proceeds anyway, and the backend notifies them.
15
- // Deliberately NOT a second confirmation prompt (founder decision 4) - --yes
16
- // already covers the destructive action, and a second gate teaches people to
17
- // click through gates.
18
- .option("--force", "Delete even though another member's private asset blocks it")
19
- .action(async function (type, name) {
20
- try {
21
- const validTypes = ["metric", "dimension", "rule", "template", "synonym", "domain", "relationship", "topic"];
22
- if (!validTypes.includes(type)) {
23
- writeStderr(JSON.stringify({
24
- error: `Delete not supported for '${type}'. Supported: ${validTypes.join(", ")}`,
25
- }));
26
- process.exit(1);
27
- }
28
- const force = this.opts().force === true;
29
- await apiClient.delete(`/api/v1/cli/kb/${type}/${encodeURIComponent(name)}${force ? "?force=true" : ""}`);
30
- console.log(JSON.stringify({ status: "deleted", type, name: name.toUpperCase(), ...(force ? { forced: true } : {}) }));
31
- }
32
- catch (err) {
33
- errorOutput(err);
34
- }
35
- });
36
- }
37
- //# sourceMappingURL=kb-delete.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kb-delete.js","sourceRoot":"","sources":["../../src/commands/kb-delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wCAAwC;AAExC,MAAM,UAAU,mBAAmB,CAAC,EAAW;IAC7C,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;SACjB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;SAC/B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;SAC/B,WAAW,CAAC,0CAA0C,CAAC;SACvD,cAAc,CAAC,OAAO,EAAE,kBAAkB,CAAC;QAC5C,4EAA4E;QAC5E,0EAA0E;QAC1E,yEAAyE;QACzE,6EAA6E;QAC7E,6EAA6E;QAC7E,uBAAuB;SACtB,MAAM,CAAC,SAAS,EAAE,6DAA6D,CAAC;SAChF,MAAM,CAAC,KAAK,WAA0B,IAAY,EAAE,IAAY;QAC/D,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;YAC7G,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;oBACzB,KAAK,EAAE,6BAA6B,IAAI,iBAAiB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBACjF,CAAC,CAAC,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC;YACzC,MAAM,SAAS,CAAC,MAAM,CACpB,kBAAkB,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAClF,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACzH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -1,2 +0,0 @@
1
- import { Command } from "commander";
2
- export declare function addKBReadCommands(kb: Command): void;