@tenderprompt/cli 0.1.9 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +290 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -157,6 +157,8 @@ tender app analytics export catalog artifact_123 --range 30d --json
157
157
  tender app analytics export query artifact_123 --spec chart.json --format csv
158
158
 
159
159
  tender app analytics suggestions artifact_123 --range 30d --json
160
+
161
+ tender app analytics charts templates --json
160
162
  ```
161
163
 
162
164
  Safe write previews:
@@ -178,6 +180,8 @@ Agents should combine `capabilities --include-catalog` with local source-code
178
180
  inspection. For example, inspect where the app calls
179
181
  `__TP_ANALYTICS.invoke(...)`, propose a chart spec, validate it with
180
182
  `analytics query`, and only then create a saved chart.
183
+ Use `charts templates --json` for reusable chart shapes; adapt any placeholders
184
+ to observed events, paths, or promoted property keys before querying or saving.
181
185
 
182
186
  ## Safety Model
183
187
 
package/dist/index.js CHANGED
@@ -266,6 +266,7 @@ Commands:
266
266
  tender app analytics suggestions <app-id> Generate starter chart suggestions
267
267
  tender app analytics dashboards <app-id> List or create dashboards
268
268
  tender app analytics export <kind> <app-id> Export catalog metadata or query rows
269
+ tender app analytics charts templates Print reusable chart spec templates
269
270
  tender app analytics charts create <app-id> Create a saved chart
270
271
 
271
272
  Examples:
@@ -277,6 +278,7 @@ Examples:
277
278
  tender app analytics export query artifact_123 --spec chart.json --format csv
278
279
  tender app analytics suggestions artifact_123 --range 2026-04-01..2026-04-30 --json
279
280
  tender app analytics dashboards artifact_123 --create "Agent dashboard" --json
281
+ tender app analytics charts templates --json
280
282
  tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec funnel.json --json`;
281
283
  }
282
284
  function analyticsSummaryHelp() {
@@ -340,6 +342,16 @@ Examples:
340
342
  tender app analytics dashboards artifact_123 --create "Agent dashboard" --dry-run --json
341
343
  tender app analytics dashboards artifact_123 --create "Agent dashboard" --json`;
342
344
  }
345
+ function analyticsChartsTemplatesHelp() {
346
+ return `Usage: tender app analytics charts templates [--json]
347
+
348
+ Print reusable chart spec templates for agents. Adapt templates to observed
349
+ events, paths, and property keys from analytics capabilities before querying or
350
+ saving.
351
+
352
+ Examples:
353
+ tender app analytics charts templates --json`;
354
+ }
343
355
  function analyticsChartsCreateHelp() {
344
356
  return `Usage: tender app analytics charts create <app-id> --dashboard <dashboard-id> --title <title> --spec <file|-> [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
345
357
 
@@ -725,6 +737,7 @@ function tenderCliCapabilities() {
725
737
  when: "When understanding app analytics or creating saved charts.",
726
738
  commands: [
727
739
  "tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json",
740
+ "tender app analytics charts templates --json",
728
741
  "tender app analytics query <artifact-id> --spec chart.json --json",
729
742
  "tender app analytics export query <artifact-id> --spec chart.json --format csv",
730
743
  "tender app analytics dashboards <artifact-id> --create \"Agent dashboard\" --dry-run --json",
@@ -782,6 +795,12 @@ function tenderCliCapabilities() {
782
795
  requiresAuth: true,
783
796
  writes: false,
784
797
  },
798
+ {
799
+ command: "tender app analytics charts templates --json",
800
+ purpose: "Print reusable chart spec templates for agents to adapt to observed analytics data.",
801
+ requiresAuth: false,
802
+ writes: false,
803
+ },
785
804
  ],
786
805
  security: [
787
806
  "Prefer artifact-scoped device tokens.",
@@ -2555,6 +2574,21 @@ function parseAnalyticsDashboardsArgs(args) {
2555
2574
  }
2556
2575
  return { command: "app analytics dashboards", artifactId, name, dryRun, ...parsed };
2557
2576
  }
2577
+ function parseAnalyticsChartsTemplatesArgs(args) {
2578
+ if (args.includes("--help") || args.includes("-h")) {
2579
+ return { command: "help", topic: "app analytics charts templates" };
2580
+ }
2581
+ let json = false;
2582
+ for (let index = 0; index < args.length; index += 1) {
2583
+ const arg = args[index];
2584
+ if (arg === "--json") {
2585
+ json = true;
2586
+ continue;
2587
+ }
2588
+ throw new TenderCliUsageError(`Unknown analytics charts templates option: ${arg}`);
2589
+ }
2590
+ return { command: "app analytics charts templates", json };
2591
+ }
2558
2592
  function parseAnalyticsExportCatalogArgs(args) {
2559
2593
  if (args.includes("--help") || args.includes("-h")) {
2560
2594
  return { command: "help", topic: "app analytics export catalog" };
@@ -2632,6 +2666,244 @@ function parseAnalyticsExportQueryArgs(args) {
2632
2666
  ...parsed,
2633
2667
  };
2634
2668
  }
2669
+ function analyticsChartTemplates() {
2670
+ return [
2671
+ {
2672
+ id: "daily_custom_events",
2673
+ title: "Daily custom events",
2674
+ visualization: "line",
2675
+ purpose: "Track app-owned business events over time.",
2676
+ usableAsIs: true,
2677
+ adaptWith: [
2678
+ "Use when the catalog has observed custom events.",
2679
+ "Switch the range preset to 7d or 90d when the user's question asks for that window.",
2680
+ ],
2681
+ spec: {
2682
+ version: 1,
2683
+ dataset: "events",
2684
+ visualization: "line",
2685
+ metric: { name: "custom_event_count" },
2686
+ groupBy: [{ field: "day" }],
2687
+ filters: [],
2688
+ range: { preset: "30d" },
2689
+ sort: [{ field: "label", direction: "asc" }],
2690
+ limit: 30,
2691
+ },
2692
+ },
2693
+ {
2694
+ id: "top_custom_events",
2695
+ title: "Top custom events",
2696
+ visualization: "bar",
2697
+ purpose: "Show which app-owned events happen most often.",
2698
+ usableAsIs: true,
2699
+ adaptWith: [
2700
+ "Use this before proposing deeper charts so the agent can see the dominant event shape.",
2701
+ ],
2702
+ spec: {
2703
+ version: 1,
2704
+ dataset: "events",
2705
+ visualization: "bar",
2706
+ metric: { name: "custom_event_count" },
2707
+ groupBy: [{ field: "event_name" }],
2708
+ filters: [],
2709
+ range: { preset: "30d" },
2710
+ sort: [{ field: "value", direction: "desc" }],
2711
+ limit: 10,
2712
+ },
2713
+ },
2714
+ {
2715
+ id: "top_request_paths",
2716
+ title: "Top request paths",
2717
+ visualization: "bar",
2718
+ purpose: "Find the generated app routes receiving the most traffic.",
2719
+ usableAsIs: true,
2720
+ adaptWith: [
2721
+ "Use only when the capabilities catalog reports request paths.",
2722
+ "Inspect the local source to understand what the busiest routes represent.",
2723
+ ],
2724
+ spec: {
2725
+ version: 1,
2726
+ dataset: "events",
2727
+ visualization: "bar",
2728
+ metric: { name: "request_count" },
2729
+ groupBy: [{ field: "path" }],
2730
+ filters: [],
2731
+ range: { preset: "30d" },
2732
+ sort: [{ field: "value", direction: "desc" }],
2733
+ limit: 10,
2734
+ },
2735
+ },
2736
+ {
2737
+ id: "event_funnel_by_name",
2738
+ title: "Event funnel",
2739
+ visualization: "funnel",
2740
+ purpose: "Measure ordered conversion through observed custom event names.",
2741
+ usableAsIs: false,
2742
+ placeholders: {
2743
+ eventNames: ["<start_event>", "<middle_event>", "<conversion_event>"],
2744
+ },
2745
+ adaptWith: [
2746
+ "Replace placeholders with ordered event names from catalog classification or observed events.",
2747
+ "Use only event names observed for the selected app.",
2748
+ "Validate with analytics query before saving because funnel order changes the meaning.",
2749
+ ],
2750
+ spec: {
2751
+ version: 1,
2752
+ dataset: "events",
2753
+ visualization: "funnel",
2754
+ metric: { name: "custom_event_count" },
2755
+ groupBy: [{ field: "event_name" }],
2756
+ filters: [
2757
+ {
2758
+ field: "event_name",
2759
+ op: "in",
2760
+ value: ["<start_event>", "<middle_event>", "<conversion_event>"],
2761
+ },
2762
+ ],
2763
+ range: { preset: "30d" },
2764
+ sort: [{ field: "label", direction: "asc" }],
2765
+ limit: 3,
2766
+ },
2767
+ },
2768
+ {
2769
+ id: "request_path_funnel",
2770
+ title: "Request path funnel",
2771
+ visualization: "funnel",
2772
+ purpose: "Measure ordered conversion through observed request paths.",
2773
+ usableAsIs: false,
2774
+ placeholders: {
2775
+ paths: ["/<start_path>", "/<middle_path>", "/<conversion_path>"],
2776
+ },
2777
+ adaptWith: [
2778
+ "Use when catalog classification includes a path-based funnel or the source code shows ordered route milestones.",
2779
+ "Replace placeholders with exact observed paths from the selected app.",
2780
+ "Do not include repeated activity routes unless source context says they are milestones.",
2781
+ ],
2782
+ spec: {
2783
+ version: 1,
2784
+ dataset: "events",
2785
+ visualization: "funnel",
2786
+ metric: { name: "request_count" },
2787
+ groupBy: [{ field: "path" }],
2788
+ filters: [
2789
+ {
2790
+ field: "path",
2791
+ op: "in",
2792
+ value: ["/<start_path>", "/<middle_path>", "/<conversion_path>"],
2793
+ },
2794
+ ],
2795
+ range: { preset: "30d" },
2796
+ sort: [{ field: "label", direction: "asc" }],
2797
+ limit: 3,
2798
+ },
2799
+ },
2800
+ {
2801
+ id: "property_breakdown",
2802
+ title: "Property breakdown",
2803
+ visualization: "bar",
2804
+ purpose: "Compare a promoted dimension property observed in events.",
2805
+ usableAsIs: false,
2806
+ placeholders: {
2807
+ property: "<promoted_dimension_property>",
2808
+ },
2809
+ adaptWith: [
2810
+ "Use a property key promoted by capabilities chartSpec.groupBy, such as property:plan.",
2811
+ "Choose stable categorical properties with enough observations to compare.",
2812
+ ],
2813
+ spec: {
2814
+ version: 1,
2815
+ dataset: "events",
2816
+ visualization: "bar",
2817
+ metric: { name: "custom_event_count" },
2818
+ groupBy: [{ field: "property:<promoted_dimension_property>" }],
2819
+ filters: [],
2820
+ range: { preset: "30d" },
2821
+ sort: [{ field: "value", direction: "desc" }],
2822
+ limit: 10,
2823
+ },
2824
+ },
2825
+ {
2826
+ id: "average_metric_property",
2827
+ title: "Average metric property",
2828
+ visualization: "line",
2829
+ purpose: "Track an observed numeric event property over time.",
2830
+ usableAsIs: false,
2831
+ placeholders: {
2832
+ metric: "avg:<promoted_metric_property>",
2833
+ },
2834
+ adaptWith: [
2835
+ "Use a numeric property key promoted by capabilities chartSpec.metrics.",
2836
+ "Prefer averages for scores, durations, quantities, or ordinal values.",
2837
+ ],
2838
+ spec: {
2839
+ version: 1,
2840
+ dataset: "events",
2841
+ visualization: "line",
2842
+ metric: { name: "avg:<promoted_metric_property>" },
2843
+ groupBy: [{ field: "day" }],
2844
+ filters: [],
2845
+ range: { preset: "30d" },
2846
+ sort: [{ field: "label", direction: "asc" }],
2847
+ limit: 30,
2848
+ },
2849
+ },
2850
+ {
2851
+ id: "single_number_total",
2852
+ title: "Single number total",
2853
+ visualization: "number",
2854
+ purpose: "Show one headline count for a selected event or request segment.",
2855
+ usableAsIs: false,
2856
+ placeholders: {
2857
+ eventName: "<event_name>",
2858
+ },
2859
+ adaptWith: [
2860
+ "Use when a dashboard needs a compact KPI card.",
2861
+ "Replace the event filter with an observed conversion or outcome event.",
2862
+ ],
2863
+ spec: {
2864
+ version: 1,
2865
+ dataset: "events",
2866
+ visualization: "number",
2867
+ metric: { name: "custom_event_count" },
2868
+ groupBy: [],
2869
+ filters: [{ field: "event_name", op: "=", value: "<event_name>" }],
2870
+ range: { preset: "30d" },
2871
+ sort: [],
2872
+ limit: 1,
2873
+ },
2874
+ },
2875
+ ];
2876
+ }
2877
+ function runAnalyticsChartsTemplates(command, io) {
2878
+ const templates = analyticsChartTemplates();
2879
+ const payload = {
2880
+ ok: true,
2881
+ command: command.command,
2882
+ templates,
2883
+ next: [
2884
+ "Run tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json.",
2885
+ "Choose a template and replace placeholders with observed events, paths, or promoted property keys.",
2886
+ "Validate with tender app analytics query <artifact-id> --spec chart.json --json.",
2887
+ "Preview saved writes with tender app analytics dashboards ... --dry-run and charts create ... --dry-run.",
2888
+ ],
2889
+ };
2890
+ if (command.json) {
2891
+ io.stdout(JSON.stringify(payload, null, 2));
2892
+ }
2893
+ else {
2894
+ io.stdout([
2895
+ "Analytics chart templates",
2896
+ "",
2897
+ ...templates.map((template) => {
2898
+ const marker = template.usableAsIs ? "usable as-is" : "adapt before use";
2899
+ return `- ${template.id}: ${template.title} (${marker})`;
2900
+ }),
2901
+ "",
2902
+ "Use --json to copy full chart specs.",
2903
+ ].join("\n"));
2904
+ }
2905
+ return 0;
2906
+ }
2635
2907
  function parseAnalyticsChartsCreateArgs(args) {
2636
2908
  if (args.includes("--help") || args.includes("-h")) {
2637
2909
  return { command: "help", topic: "app analytics charts create" };
@@ -2781,6 +3053,18 @@ function parseTenderArgs(args) {
2781
3053
  resourceArgs[3] === "query") {
2782
3054
  return parseAnalyticsExportQueryArgs(resourceArgs.slice(4));
2783
3055
  }
3056
+ if (resourceArgs[1] === "analytics" &&
3057
+ resourceArgs[2] === "charts" &&
3058
+ resourceArgs[3] === "templates") {
3059
+ return parseAnalyticsChartsTemplatesArgs(resourceArgs.slice(4));
3060
+ }
3061
+ if (resourceArgs[1] === "analytics" &&
3062
+ resourceArgs[2] === "charts" &&
3063
+ (resourceArgs[3] === undefined ||
3064
+ resourceArgs[3] === "--help" ||
3065
+ resourceArgs[3] === "-h")) {
3066
+ return { command: "help", topic: "app analytics charts templates" };
3067
+ }
2784
3068
  if (resourceArgs[1] === "analytics" &&
2785
3069
  resourceArgs[2] === "charts" &&
2786
3070
  resourceArgs[3] === "create") {
@@ -5503,6 +5787,9 @@ export async function runTenderCli(args, io = {
5503
5787
  else if (command.topic === "app analytics export query") {
5504
5788
  io.stdout(analyticsExportQueryHelp());
5505
5789
  }
5790
+ else if (command.topic === "app analytics charts templates") {
5791
+ io.stdout(analyticsChartsTemplatesHelp());
5792
+ }
5506
5793
  else if (command.topic === "app analytics charts create") {
5507
5794
  io.stdout(analyticsChartsCreateHelp());
5508
5795
  }
@@ -5601,6 +5888,9 @@ export async function runTenderCli(args, io = {
5601
5888
  if (command.command === "app analytics export query") {
5602
5889
  return await runAnalyticsExportQuery(command, io, runtime);
5603
5890
  }
5891
+ if (command.command === "app analytics charts templates") {
5892
+ return runAnalyticsChartsTemplates(command, io);
5893
+ }
5604
5894
  if (command.command === "app analytics charts create") {
5605
5895
  return await runAnalyticsChartsCreate(command, io, runtime);
5606
5896
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenderprompt/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tender": "bin/tender.js"