@bicharts/chart-mcp 0.6.126 → 0.6.128
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/check-chart.mjs +64 -64
- package/dist/index.mjs +140 -140
- package/package.json +3 -3
- package/skills/bic-charts/SKILL.md +37 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.128",
|
|
4
4
|
"description": "AI Data Components for Power BI, Excel, Fabric Apps and the web, over MCP: working what-if apps, interactive tables and bivariate maps first, plus about 90 everyday chart types, with selection and cross-filtering already wired. It profiles your table locally; the code it writes is yours and runs with no license.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
},
|
|
52
52
|
"// dependencies": "NONE, deliberately. dist/ bundles every module the server uses, so a runtime dependency installs nothing it needs - it only makes npx fetch that package (and its tree) before the first start. Everything the bundle carries is a devDependency; scripts/verify-package.mjs fails the release if a dependency appears or a shipped file imports anything but Node's built-ins.",
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@bicharts/chart-host": "^0.6.
|
|
55
|
-
"@bicharts/shape-core": "^0.6.
|
|
54
|
+
"@bicharts/chart-host": "^0.6.128",
|
|
55
|
+
"@bicharts/shape-core": "^0.6.128",
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
57
57
|
"@types/node": "^26.6.5",
|
|
58
58
|
"@types/papaparse": "^5.3.14",
|
|
@@ -793,7 +793,7 @@ as `projection`. The chart is drawn at that grain and says so.
|
|
|
793
793
|
|
|
794
794
|
The Interactive table and the Variance grid are preview types too, so either may be missing from the list. When the person asked for one and it isn't listed, say so and ask how to go on; don't build a table by hand in its place.
|
|
795
795
|
|
|
796
|
-
Retention curves, the Cohort retention triangle and the Churn risk list are preview types, so any of them may be missing from the list; when the person asked for one and it isn't listed, say so and ask how to go on. Query ONE row per customer: the start and end dates as dates (a blank end while still a customer), the as-of date if the model has one (a snapshot date or a `Data As Of` measure), the fields to compare,
|
|
796
|
+
Retention curves, the Cohort retention triangle and the Churn risk list are preview types, so any of them may be missing from the list; when the person asked for one and it isn't listed, say so and ask how to go on. Query ONE row per customer: the start and end dates as dates (a blank end while still a customer), the as-of date if the model has one (a snapshot date or a `Data As Of` measure), the fields to compare, the customer's key and name, and last activity as a measure; pass the customer key as the id even when a name reads better (two customers can share a name, and a repeated id counts once), and the list shows the name beside it. A headline figure beside these charts says what it is measured over and when: 12-month retention names its base (customers who joined at least 12 months before the as-of date), a "last 90 days" count names the day it ends, and a blank figure says why (no customer in the pick can be measured that long), never a bare n/a. Never join the activity rows into the customer query, and never compute retention, a curve, a cohort share or a risk score in the app: every number and word is the chart's.
|
|
797
797
|
|
|
798
798
|
The Selection explainer is a preview type: the server offers it only where it's switched on, so it may be missing from the
|
|
799
799
|
list even when the data fits. When `list_eligible_charts` doesn't list it for your data, tell the person it isn't available
|
|
@@ -983,6 +983,25 @@ whichever panel shows it clears it; and only the member holding it is active (on
|
|
|
983
983
|
group they are separate picks, ANDed: a country picked on the map and then in the table is held twice, and clicking it
|
|
984
984
|
again on the map leaves the page filtered by the table's. `check_app` flags filters on one key without a group.
|
|
985
985
|
|
|
986
|
+
**A group is for the SAME pick offered in two panels, never for a drill-in.** A pick that narrows INSIDE another - a
|
|
987
|
+
segment picked on a chart, then one customer in the table that segment narrowed - is its own filter with NO group, ANDed
|
|
988
|
+
with the outer pick: the table's query keeps taking the segment's filter (and passes it as `scopedBy`), and the segments
|
|
989
|
+
chart does not follow the table's. In one group the newest pick is the page's only pick, so a click on a row clears the
|
|
990
|
+
segment and the table refills with every customer, losing the drill-down at the moment the reader clicks into it.
|
|
991
|
+
`check_app` flags a drill-in held in a group (one panel follows the other one way only). Every other panel takes BOTH
|
|
992
|
+
filters, ANDed - `treatAs(segment, ...)` and `treatAs(customer, ...)`, `scopedBy={[segment, customer]}` - never one in
|
|
993
|
+
place of the other (`customer.active ? customer : segment`): the inner pick is inside the outer one anyway. And the inner
|
|
994
|
+
pick is cleared when the outer one changes, `useEffect(() => segment.onChange(() => customer.clear()), [segment,
|
|
995
|
+
customer])`, so a customer held from one segment never narrows the page after the reader picks another.
|
|
996
|
+
|
|
997
|
+
**A tag on a segment belongs on that segment's card.** When the person tags segments (a campaign, an owner), key each tag
|
|
998
|
+
by the segment's NAME - the Customer segments chart keeps names across a refresh and a filter - and store the tag, its
|
|
999
|
+
owner and when it was saved in the app's data. Pass them to the chart as `segmentTags: { "<segment name>": [{ tag,
|
|
1000
|
+
owner, at }] }` in its options: the newest tag shows on that segment's card, and a tag on a segment not drawn now is
|
|
1001
|
+
counted in its caption. A tag kept as a list of customer ids, or only in a list beside the chart, leaves a tagged segment
|
|
1002
|
+
looking untagged. "Gained or lost since the last tag" is the chart's too: put the three inputs as they stood on the
|
|
1003
|
+
last tag's day in the chart's query and name them in the request, so the chart reports each segment's gained and lost.
|
|
1004
|
+
|
|
986
1005
|
```tsx
|
|
987
1006
|
const fromMap = useBicFilter("CountryIso3", { label: "Country (map)", display: "CountryName", group: "country" });
|
|
988
1007
|
const fromTable = useBicFilter("CountryIso3", { label: "Country (table)", display: "CountryName", group: "country" });
|
|
@@ -1013,6 +1032,13 @@ everything it plots. A query that takes only part of a pick's key (`treatAs(cell
|
|
|
1013
1032
|
stage cell) names that part: `scopedBy={{ filter: cell, takes: ["Region"] }}` says "Europe", never "Europe · 3-Propose",
|
|
1014
1033
|
and a stage-only pick adds nothing to that chart's line.
|
|
1015
1034
|
|
|
1035
|
+
**A chart that rates every row shows the picked ones: give it every row and pass the picks as `viewedBy`.** A Churn risk
|
|
1036
|
+
list rates each customer against how long every customer has stayed. Narrow its query by a pick and it rates only what
|
|
1037
|
+
the pick left - one joining quarter's customers can't be rated at all, since none of them was watched longer than the
|
|
1038
|
+
others. So its query takes NONE of the page's picks, it carries each pick's key column (a quarter label column for a
|
|
1039
|
+
quarter pick), and the picks go in `viewedBy={[channel, quarter]}`: the chart rates against everyone and lists the picked
|
|
1040
|
+
customers, and its caption says both ("124 active customers in 2023 Q2 ...; each rated against all 3,600 customers").
|
|
1041
|
+
|
|
1016
1042
|
**A panel a pick cannot reach says so on its card.** When a pick can't reach a panel or one of its encodings (its query
|
|
1017
1043
|
takes only part of the pick's key, or none of it), or a figure's measure removes that pick's filter on purpose (a close
|
|
1018
1044
|
rate kept across every stage beside open pipeline that follows the stage), that card says so in one line: "Close rate
|
|
@@ -1231,6 +1257,12 @@ files do:
|
|
|
1231
1257
|
permission with no policy lets a second person mark a done item done again and overwrite who closed it. Key the row
|
|
1232
1258
|
by the item with a unique field, under the same who-check, so a second one fails at the database and the first
|
|
1233
1259
|
stays; an item is open while it has no such row, and only an open item offers the action.
|
|
1260
|
+
- **An open item stays closable after its subject leaves.** The form that records an outcome looks its subject up in
|
|
1261
|
+
every row the model has (every customer, every account), or reads the name saved on the item - never only the active
|
|
1262
|
+
list the page shows. An attempt filed on a customer who has since left is still open, the owner's open count still
|
|
1263
|
+
counts it, and its outcome must still be saveable: most often the outcome IS that they left. Open it from the owner's
|
|
1264
|
+
open list as well as from its badge, and offer its actions from the saved item, not from a lookup that can come back empty.
|
|
1265
|
+
A save that fails says so IN the dialog that made it, beside its buttons - never only in a panel the dialog covers.
|
|
1234
1266
|
|
|
1235
1267
|
```ts
|
|
1236
1268
|
// rayfin/data/TaskDone.ts
|
|
@@ -1406,6 +1438,10 @@ name, list, apply, and which one is applied now - `applied`, the saved scenario
|
|
|
1406
1438
|
save keeps what was typed), and, with Rayfin's functions on, the `addSavedScenario` function each save runs through, so
|
|
1407
1439
|
the server stamps its time.
|
|
1408
1440
|
|
|
1441
|
+
A chart's own segmented row (Retention curves' "Compare by Channel | Plan | Region") is a control too:
|
|
1442
|
+
`controls.values.compare` is the reader's choice, from the first draw, and the page re-renders when the reader switches
|
|
1443
|
+
it - so a page that filters by what the chart compares reads it there, never from the chart's source.
|
|
1444
|
+
|
|
1409
1445
|
**8. What stays the template's job - this is additive, never a replacement:** sign-in, the query hooks
|
|
1410
1446
|
(`useSemanticModelQuery`; a page filter feeds it through `filterQuery`), the theme (`useCssTheme`, which
|
|
1411
1447
|
`bic-chart-options.ts` builds on), the app's database (Rayfin's data service), `VisualContainer` headers, the template's
|