@growthub/cli 0.9.9 → 0.9.10

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.
@@ -40,7 +40,12 @@ const GRID_COLUMNS = 12;
40
40
  const GRID_ROWS = 16;
41
41
  const KNOWN_WIDGET_KINDS = ["chart", "view", "iframe", "rich-text"];
42
42
  const KNOWN_FIELDS = ["dashboards", "widgetTypes", "canvas"];
43
- const KNOWN_DATA_BINDING_MODES = ["manual", "json", "csv"];
43
+ const KNOWN_DATA_BINDING_MODES = ["manual", "json", "csv", "integration"];
44
+ const KNOWN_CHART_TYPES = ["bar-vertical", "bar-horizontal", "line", "pie", "sum", "gauge"];
45
+ const KNOWN_FILTER_OPERATORS = ["eq", "ne", "contains", "gt", "lt", "isEmpty", "isNotEmpty"];
46
+ const KNOWN_FILTER_CONJUNCTIONS = ["and", "or"];
47
+ const KNOWN_SORT_DIRECTIONS = ["asc", "desc"];
48
+ const KNOWN_AGGREGATIONS = ["sum", "avg", "count", "min", "max"];
44
49
  const WORKSPACE_TEMPLATE_KIND = "growthub-workspace-template";
45
50
  const WORKSPACE_TEMPLATE_VERSION = 1;
46
51
  const WORKSPACE_TEMPLATE_SOURCE = "growthub-custom-workspace-starter-v1";
@@ -61,7 +66,12 @@ const WIDGET_SCHEMA_CONTRACTS = {
61
66
  config: "kind-specific config object"
62
67
  },
63
68
  ChartWidgetConfig: {
64
- values: "number[]",
69
+ values: "number[] (legacy preserved)",
70
+ chartType: `${KNOWN_CHART_TYPES.join(" | ")} optional, defaults to bar-vertical`,
71
+ xAxis: "ChartAxisConfig optional",
72
+ yAxis: "ChartAxisConfig optional",
73
+ style: "ChartStyleConfig optional",
74
+ filter: "FilterConfig optional",
65
75
  binding: "StaticDataBinding optional"
66
76
  },
67
77
  ViewWidgetConfig: {
@@ -69,8 +79,42 @@ const WIDGET_SCHEMA_CONTRACTS = {
69
79
  layout: "Table",
70
80
  columns: "string[]",
71
81
  rows: "record[]",
82
+ fieldSettings: "FieldSettingsConfig optional (hidden[], order[])",
83
+ sort: "SortClause[] optional ({ fieldId, direction })",
84
+ filter: "FilterConfig optional ({ op, clauses[] })",
72
85
  binding: "StaticDataBinding optional"
73
86
  },
87
+ ChartAxisConfig: {
88
+ field: "string optional",
89
+ sort: "string optional (asc | desc | position)",
90
+ aggregation: `${KNOWN_AGGREGATIONS.join(" | ")} optional`,
91
+ groupBy: "string optional",
92
+ omitZero: "boolean optional",
93
+ min: "string | number optional",
94
+ max: "string | number optional"
95
+ },
96
+ ChartStyleConfig: {
97
+ colors: "string optional (auto | manual swatch label)",
98
+ axisName: "string optional",
99
+ dataLabels: "boolean optional"
100
+ },
101
+ FieldSettingsConfig: {
102
+ hidden: "string[] of column names hidden from preview",
103
+ order: "string[] of column names defining custom order"
104
+ },
105
+ SortClause: {
106
+ fieldId: "non-empty string (column name)",
107
+ direction: KNOWN_SORT_DIRECTIONS.join(" | ")
108
+ },
109
+ FilterConfig: {
110
+ op: KNOWN_FILTER_CONJUNCTIONS.join(" | "),
111
+ clauses: "FilterClause[]"
112
+ },
113
+ FilterClause: {
114
+ fieldId: "non-empty string (column name)",
115
+ operator: KNOWN_FILTER_OPERATORS.join(" | "),
116
+ value: "string | number | boolean optional"
117
+ },
74
118
  IframeWidgetConfig: {
75
119
  url: "string"
76
120
  },
@@ -333,6 +377,127 @@ function validateStaticDataBinding(binding, path, errors) {
333
377
  if (binding.csv !== undefined && typeof binding.csv !== "string") {
334
378
  errors.push(`${path}.csv must be a string`);
335
379
  }
380
+ if (binding.integrationId !== undefined && typeof binding.integrationId !== "string") {
381
+ errors.push(`${path}.integrationId must be a string`);
382
+ }
383
+ if (binding.lane !== undefined && typeof binding.lane !== "string") {
384
+ errors.push(`${path}.lane must be a string`);
385
+ }
386
+ }
387
+
388
+ function validateFieldSettings(fieldSettings, path, errors) {
389
+ if (fieldSettings === undefined) return;
390
+ if (!isPlainObject(fieldSettings)) {
391
+ errors.push(`${path} must be a plain object`);
392
+ return;
393
+ }
394
+ if (fieldSettings.hidden !== undefined) validateStringArray(fieldSettings.hidden, `${path}.hidden`, errors);
395
+ if (fieldSettings.order !== undefined) validateStringArray(fieldSettings.order, `${path}.order`, errors);
396
+ }
397
+
398
+ function validateSortClauses(sort, path, errors) {
399
+ if (sort === undefined) return;
400
+ if (!Array.isArray(sort)) {
401
+ errors.push(`${path} must be an array`);
402
+ return;
403
+ }
404
+ sort.forEach((clause, index) => {
405
+ const prefix = `${path}[${index}]`;
406
+ if (!isPlainObject(clause)) {
407
+ errors.push(`${prefix} must be a plain object`);
408
+ return;
409
+ }
410
+ if (typeof clause.fieldId !== "string" || !clause.fieldId) {
411
+ errors.push(`${prefix}.fieldId must be a non-empty string`);
412
+ }
413
+ if (clause.direction !== undefined && !KNOWN_SORT_DIRECTIONS.includes(clause.direction)) {
414
+ errors.push(`${prefix}.direction must be one of ${KNOWN_SORT_DIRECTIONS.join(", ")}`);
415
+ }
416
+ });
417
+ }
418
+
419
+ function validateFilterClauses(filter, path, errors) {
420
+ if (filter === undefined) return;
421
+ if (!isPlainObject(filter)) {
422
+ errors.push(`${path} must be a plain object`);
423
+ return;
424
+ }
425
+ if (filter.op !== undefined && !KNOWN_FILTER_CONJUNCTIONS.includes(filter.op)) {
426
+ errors.push(`${path}.op must be one of ${KNOWN_FILTER_CONJUNCTIONS.join(", ")}`);
427
+ }
428
+ if (filter.clauses !== undefined) {
429
+ if (!Array.isArray(filter.clauses)) {
430
+ errors.push(`${path}.clauses must be an array`);
431
+ } else {
432
+ filter.clauses.forEach((clause, index) => {
433
+ const prefix = `${path}.clauses[${index}]`;
434
+ if (!isPlainObject(clause)) {
435
+ errors.push(`${prefix} must be a plain object`);
436
+ return;
437
+ }
438
+ if (typeof clause.fieldId !== "string" || !clause.fieldId) {
439
+ errors.push(`${prefix}.fieldId must be a non-empty string`);
440
+ }
441
+ if (clause.operator !== undefined && !KNOWN_FILTER_OPERATORS.includes(clause.operator)) {
442
+ errors.push(`${prefix}.operator must be one of ${KNOWN_FILTER_OPERATORS.join(", ")}`);
443
+ }
444
+ if (
445
+ clause.value !== undefined &&
446
+ typeof clause.value !== "string" &&
447
+ typeof clause.value !== "number" &&
448
+ typeof clause.value !== "boolean"
449
+ ) {
450
+ errors.push(`${prefix}.value must be a string, number, or boolean`);
451
+ }
452
+ });
453
+ }
454
+ }
455
+ }
456
+
457
+ function validateChartAxis(axis, path, errors) {
458
+ if (axis === undefined) return;
459
+ if (!isPlainObject(axis)) {
460
+ errors.push(`${path} must be a plain object`);
461
+ return;
462
+ }
463
+ if (axis.field !== undefined && typeof axis.field !== "string") {
464
+ errors.push(`${path}.field must be a string`);
465
+ }
466
+ if (axis.sort !== undefined && typeof axis.sort !== "string") {
467
+ errors.push(`${path}.sort must be a string`);
468
+ }
469
+ if (axis.aggregation !== undefined && !KNOWN_AGGREGATIONS.includes(axis.aggregation)) {
470
+ errors.push(`${path}.aggregation must be one of ${KNOWN_AGGREGATIONS.join(", ")}`);
471
+ }
472
+ if (axis.groupBy !== undefined && typeof axis.groupBy !== "string") {
473
+ errors.push(`${path}.groupBy must be a string`);
474
+ }
475
+ if (axis.omitZero !== undefined && typeof axis.omitZero !== "boolean") {
476
+ errors.push(`${path}.omitZero must be a boolean`);
477
+ }
478
+ if (axis.min !== undefined && typeof axis.min !== "string" && typeof axis.min !== "number") {
479
+ errors.push(`${path}.min must be a string or number`);
480
+ }
481
+ if (axis.max !== undefined && typeof axis.max !== "string" && typeof axis.max !== "number") {
482
+ errors.push(`${path}.max must be a string or number`);
483
+ }
484
+ }
485
+
486
+ function validateChartStyle(style, path, errors) {
487
+ if (style === undefined) return;
488
+ if (!isPlainObject(style)) {
489
+ errors.push(`${path} must be a plain object`);
490
+ return;
491
+ }
492
+ if (style.colors !== undefined && typeof style.colors !== "string") {
493
+ errors.push(`${path}.colors must be a string`);
494
+ }
495
+ if (style.axisName !== undefined && typeof style.axisName !== "string") {
496
+ errors.push(`${path}.axisName must be a string`);
497
+ }
498
+ if (style.dataLabels !== undefined && typeof style.dataLabels !== "boolean") {
499
+ errors.push(`${path}.dataLabels must be a boolean`);
500
+ }
336
501
  }
337
502
 
338
503
  function validateWidgetConfig(kind, config, path, errors) {
@@ -353,6 +518,13 @@ function validateWidgetConfig(kind, config, path, errors) {
353
518
  });
354
519
  }
355
520
  }
521
+ if (config.chartType !== undefined && !KNOWN_CHART_TYPES.includes(config.chartType)) {
522
+ errors.push(`${path}.chartType must be one of ${KNOWN_CHART_TYPES.join(", ")}`);
523
+ }
524
+ validateChartAxis(config.xAxis, `${path}.xAxis`, errors);
525
+ validateChartAxis(config.yAxis, `${path}.yAxis`, errors);
526
+ validateChartStyle(config.style, `${path}.style`, errors);
527
+ validateFilterClauses(config.filter, `${path}.filter`, errors);
356
528
  validateStaticDataBinding(config.binding, `${path}.binding`, errors);
357
529
  }
358
530
  if (kind === "view") {
@@ -360,6 +532,9 @@ function validateWidgetConfig(kind, config, path, errors) {
360
532
  if (config.layout !== undefined && config.layout !== "Table") errors.push(`${path}.layout must be Table`);
361
533
  if (config.columns !== undefined) validateStringArray(config.columns, `${path}.columns`, errors);
362
534
  if (config.rows !== undefined && !Array.isArray(config.rows)) errors.push(`${path}.rows must be an array`);
535
+ validateFieldSettings(config.fieldSettings, `${path}.fieldSettings`, errors);
536
+ validateSortClauses(config.sort, `${path}.sort`, errors);
537
+ validateFilterClauses(config.filter, `${path}.filter`, errors);
363
538
  validateStaticDataBinding(config.binding, `${path}.binding`, errors);
364
539
  }
365
540
  if (kind === "iframe" && config.url !== undefined && typeof config.url !== "string") {
@@ -787,8 +962,13 @@ export {
787
962
  DASHBOARD_TEMPLATES,
788
963
  GRID_COLUMNS,
789
964
  GRID_ROWS,
965
+ KNOWN_AGGREGATIONS,
966
+ KNOWN_CHART_TYPES,
790
967
  KNOWN_DATA_BINDING_MODES,
791
968
  KNOWN_FIELDS,
969
+ KNOWN_FILTER_CONJUNCTIONS,
970
+ KNOWN_FILTER_OPERATORS,
971
+ KNOWN_SORT_DIRECTIONS,
792
972
  KNOWN_WIDGET_KINDS,
793
973
  SAMPLE_DATA_BINDINGS,
794
974
  SAMPLE_VIEW_ROWS,
@@ -8,15 +8,10 @@
8
8
  "name": "growthub-workspace-app",
9
9
  "version": "1.0.0",
10
10
  "dependencies": {
11
+ "lucide-react": "^0.468.0",
11
12
  "next": "16.2.4",
12
13
  "react": "19.2.4",
13
14
  "react-dom": "19.2.4"
14
- },
15
- "devDependencies": {
16
- "@types/node": "^20",
17
- "@types/react": "^19",
18
- "@types/react-dom": "^19",
19
- "typescript": "^5"
20
15
  }
21
16
  },
22
17
  "node_modules/@emnapi/runtime": {
@@ -638,36 +633,6 @@
638
633
  "tslib": "^2.8.0"
639
634
  }
640
635
  },
641
- "node_modules/@types/node": {
642
- "version": "20.19.39",
643
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
644
- "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
645
- "dev": true,
646
- "license": "MIT",
647
- "dependencies": {
648
- "undici-types": "~6.21.0"
649
- }
650
- },
651
- "node_modules/@types/react": {
652
- "version": "19.2.14",
653
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
654
- "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
655
- "dev": true,
656
- "license": "MIT",
657
- "dependencies": {
658
- "csstype": "^3.2.2"
659
- }
660
- },
661
- "node_modules/@types/react-dom": {
662
- "version": "19.2.3",
663
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
664
- "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
665
- "dev": true,
666
- "license": "MIT",
667
- "peerDependencies": {
668
- "@types/react": "^19.2.0"
669
- }
670
- },
671
636
  "node_modules/baseline-browser-mapping": {
672
637
  "version": "2.10.21",
673
638
  "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz",
@@ -706,13 +671,6 @@
706
671
  "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
707
672
  "license": "MIT"
708
673
  },
709
- "node_modules/csstype": {
710
- "version": "3.2.3",
711
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
712
- "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
713
- "dev": true,
714
- "license": "MIT"
715
- },
716
674
  "node_modules/detect-libc": {
717
675
  "version": "2.1.2",
718
676
  "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -723,6 +681,15 @@
723
681
  "node": ">=8"
724
682
  }
725
683
  },
684
+ "node_modules/lucide-react": {
685
+ "version": "0.468.0",
686
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz",
687
+ "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==",
688
+ "license": "ISC",
689
+ "peerDependencies": {
690
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
691
+ }
692
+ },
726
693
  "node_modules/nanoid": {
727
694
  "version": "3.3.11",
728
695
  "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
@@ -950,27 +917,6 @@
950
917
  "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
951
918
  "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
952
919
  "license": "0BSD"
953
- },
954
- "node_modules/typescript": {
955
- "version": "5.9.3",
956
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
957
- "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
958
- "dev": true,
959
- "license": "Apache-2.0",
960
- "bin": {
961
- "tsc": "bin/tsc",
962
- "tsserver": "bin/tsserver"
963
- },
964
- "engines": {
965
- "node": ">=14.17"
966
- }
967
- },
968
- "node_modules/undici-types": {
969
- "version": "6.21.0",
970
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
971
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
972
- "dev": true,
973
- "license": "MIT"
974
920
  }
975
921
  }
976
922
  }
@@ -10,6 +10,7 @@
10
10
  "lint": "next lint"
11
11
  },
12
12
  "dependencies": {
13
+ "lucide-react": "^0.468.0",
13
14
  "next": "16.2.4",
14
15
  "react": "19.2.4",
15
16
  "react-dom": "19.2.4"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growthub/cli",
3
- "version": "0.9.9",
3
+ "version": "0.9.10",
4
4
  "description": "Growthub Local is a control plane for forked worker kits. The CLI is the executor, the hosted app is the identity authority, the worker kit is the unit of portable agent infrastructure, and the fork is the operator's personal branch of that infrastructure — policy-governed, trace-backed, and self-healing.",
5
5
  "type": "module",
6
6
  "bin": {