@tanstack/cli 0.63.0 → 0.64.0

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/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import { resolve } from 'node:path';
3
- import { Command, InvalidArgumentError } from 'commander';
3
+ import { Command, InvalidArgumentError, Option } from 'commander';
4
4
  import { cancel, confirm, intro, isCancel, log } from '@clack/prompts';
5
5
  import chalk from 'chalk';
6
6
  import semver from 'semver';
@@ -37,6 +37,19 @@ function sanitizeIdList(values) {
37
37
  .map((value) => sanitizeId(value))
38
38
  .filter((value) => Boolean(value))));
39
39
  }
40
+ const AGENT_FLAG = '--agent';
41
+ function addHiddenAgentFlag(cmd) {
42
+ if (cmd.options.some((option) => option.long === AGENT_FLAG)) {
43
+ return cmd;
44
+ }
45
+ cmd.addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp());
46
+ return cmd;
47
+ }
48
+ function getInvocationTelemetryProperties() {
49
+ return {
50
+ invoked_by_agent: process.argv.includes(AGENT_FLAG),
51
+ };
52
+ }
40
53
  function getStarterTelemetryProperties(value) {
41
54
  if (!value) {
42
55
  return {};
@@ -275,6 +288,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
275
288
  const startedAt = Date.now();
276
289
  currentTelemetry = telemetry;
277
290
  telemetry.captureCommandStarted(command, {
291
+ ...getInvocationTelemetryProperties(),
278
292
  ...opts.properties,
279
293
  cli_version: VERSION,
280
294
  });
@@ -295,6 +309,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
295
309
  .name(name)
296
310
  .description(`${appName} CLI`)
297
311
  .version(VERSION, '-v, --version', 'output the current version');
312
+ addHiddenAgentFlag(program);
298
313
  // Helper to create the create command action handler
299
314
  async function handleCreate(projectName, options) {
300
315
  try {
@@ -507,6 +522,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
507
522
  }
508
523
  // Helper to configure create command options
509
524
  function configureCreateCommand(cmd) {
525
+ addHiddenAgentFlag(cmd);
510
526
  cmd.argument('[project-name]', 'name of the project');
511
527
  if (!defaultFramework) {
512
528
  cmd.option('--framework <type>', `project framework (${availableFrameworks.join(', ')})`, (value) => {
@@ -624,6 +640,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
624
640
  program
625
641
  .command('libraries')
626
642
  .description('List TanStack libraries')
643
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
627
644
  .option('--group <group>', `filter by group (${LIBRARY_GROUPS.join(', ')})`)
628
645
  .option('--json', 'output JSON for automation', false)
629
646
  .action(async (options) => {
@@ -681,6 +698,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
681
698
  program
682
699
  .command('doc')
683
700
  .description('Fetch a TanStack documentation page')
701
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
684
702
  .argument('<library>', 'library ID (eg. query, router, table)')
685
703
  .argument('<path>', 'documentation path (eg. framework/react/overview)')
686
704
  .option('--docs-version <version>', 'docs version (default: latest)', 'latest')
@@ -757,6 +775,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
757
775
  program
758
776
  .command('search-docs')
759
777
  .description('Search TanStack documentation')
778
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
760
779
  .argument('<query>', 'search query')
761
780
  .option('--library <id>', 'filter to specific library')
762
781
  .option('--framework <name>', 'filter to specific framework')
@@ -804,6 +823,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
804
823
  program
805
824
  .command('ecosystem')
806
825
  .description('List TanStack ecosystem partners')
826
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
807
827
  .option('--category <category>', 'filter by category')
808
828
  .option('--library <id>', 'filter by TanStack library')
809
829
  .option('--json', 'output JSON for automation', false)
@@ -873,6 +893,7 @@ export function cli({ name, appName, forcedAddOns = [], forcedDeployment, defaul
873
893
  program
874
894
  .command('pin-versions')
875
895
  .description('Pin versions of the TanStack libraries')
896
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
876
897
  .action(async () => {
877
898
  try {
878
899
  await runWithTelemetry('pin-versions', {}, async (telemetry) => {
@@ -943,6 +964,7 @@ Remove your node_modules directory and package lock file and re-install.`);
943
964
  telemetryCommand
944
965
  .command('status')
945
966
  .description('Show anonymous telemetry status')
967
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
946
968
  .option('--json', 'output JSON for automation', false)
947
969
  .action(async (options) => {
948
970
  const status = await getTelemetryStatus({ createIfMissing: true });
@@ -966,6 +988,7 @@ Remove your node_modules directory and package lock file and re-install.`);
966
988
  telemetryCommand
967
989
  .command('enable')
968
990
  .description('Enable anonymous telemetry')
991
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
969
992
  .action(async () => {
970
993
  await setTelemetryEnabled(true);
971
994
  console.log('Anonymous telemetry enabled');
@@ -973,6 +996,7 @@ Remove your node_modules directory and package lock file and re-install.`);
973
996
  telemetryCommand
974
997
  .command('disable')
975
998
  .description('Disable anonymous telemetry')
999
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
976
1000
  .action(async () => {
977
1001
  await setTelemetryEnabled(false);
978
1002
  console.log('Anonymous telemetry disabled');
@@ -980,6 +1004,7 @@ Remove your node_modules directory and package lock file and re-install.`);
980
1004
  // === ADD SUBCOMMAND ===
981
1005
  program
982
1006
  .command('add')
1007
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
983
1008
  .argument('[add-on...]', 'Name of the add-ons (or add-ons separated by spaces or commas)')
984
1009
  .option('--forced', 'Force the add-on to be added', false)
985
1010
  .action(async (addOns, options) => {
@@ -1032,6 +1057,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1032
1057
  addOnCommand
1033
1058
  .command('init')
1034
1059
  .description('Initialize an add-on from the current project')
1060
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1035
1061
  .action(async () => {
1036
1062
  try {
1037
1063
  await runWithTelemetry('add-on:init', {}, async () => {
@@ -1046,6 +1072,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1046
1072
  addOnCommand
1047
1073
  .command('compile')
1048
1074
  .description('Update add-on from the current project')
1075
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1049
1076
  .action(async () => {
1050
1077
  try {
1051
1078
  await runWithTelemetry('add-on:compile', {}, async () => {
@@ -1060,6 +1087,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1060
1087
  addOnCommand
1061
1088
  .command('dev')
1062
1089
  .description('Watch project files and continuously refresh .add-on and add-on.json')
1090
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1063
1091
  .action(async () => {
1064
1092
  try {
1065
1093
  await runWithTelemetry('add-on:dev', {}, async () => {
@@ -1076,6 +1104,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1076
1104
  templateCommand
1077
1105
  .command('init')
1078
1106
  .description('Initialize a project template from the current project')
1107
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1079
1108
  .action(async () => {
1080
1109
  try {
1081
1110
  await runWithTelemetry('template:init', {}, async () => {
@@ -1090,6 +1119,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1090
1119
  templateCommand
1091
1120
  .command('compile')
1092
1121
  .description('Compile the template JSON file for the current project')
1122
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1093
1123
  .action(async () => {
1094
1124
  try {
1095
1125
  await runWithTelemetry('template:compile', {}, async () => {
@@ -1106,6 +1136,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1106
1136
  starterCommand
1107
1137
  .command('init')
1108
1138
  .description('Deprecated alias: initialize a project template')
1139
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1109
1140
  .action(async () => {
1110
1141
  try {
1111
1142
  await runWithTelemetry('starter:init', {}, async () => {
@@ -1120,6 +1151,7 @@ Remove your node_modules directory and package lock file and re-install.`);
1120
1151
  starterCommand
1121
1152
  .command('compile')
1122
1153
  .description('Deprecated alias: compile the template JSON file')
1154
+ .addOption(new Option(AGENT_FLAG, 'internal: invocation originated from an agent').hideHelp())
1123
1155
  .action(async () => {
1124
1156
  try {
1125
1157
  await runWithTelemetry('starter:compile', {}, async () => {
package/dist/telemetry.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { version as nodeVersion } from 'node:process';
2
2
  import { getTelemetryStatus, markTelemetryNoticeSeen, TELEMETRY_NOTICE_VERSION, } from './telemetry-config.js';
3
- const POSTHOG_API_HOST = 'https://us.i.posthog.com';
4
- const POSTHOG_CAPTURE_ENDPOINT = `${POSTHOG_API_HOST}/capture/`;
5
- const POSTHOG_PROJECT_TOKEN = 'phc_xJ2VBahJBzy3BShLhuGpw7EyoSuQtgwXXvhE9BYtHuKQ';
3
+ const TELEMETRY_TRANSPORT_ENDPOINT = 'https://www.google-analytics.com/g/collect';
4
+ const TELEMETRY_PROPERTY_ID = 'G-JMT1Z50SPS';
6
5
  const TELEMETRY_NOTICE = 'TanStack CLI sends anonymous usage telemetry by default. It never sends project names, paths, raw search text, template URLs, add-on config values, or raw error messages. Disable it with `tanstack telemetry disable` or `TANSTACK_CLI_TELEMETRY_DISABLED=1`.';
7
6
  const TELEMETRY_TIMEOUT_MS = 1200;
7
+ const TELEMETRY_VALUE_MAX_LENGTH = 500;
8
+ const TELEMETRY_NUMERIC_PREFIX = 'epn.';
9
+ const TELEMETRY_STRING_PREFIX = 'ep.';
8
10
  let telemetryStatusPromise;
9
11
  function getNodeMajorVersion() {
10
12
  return Number.parseInt(nodeVersion.replace(/^v/, '').split('.')[0] || '0', 10);
@@ -26,6 +28,57 @@ function cleanProperties(value) {
26
28
  }
27
29
  return value;
28
30
  }
31
+ function truncateValue(value) {
32
+ return value.length > TELEMETRY_VALUE_MAX_LENGTH
33
+ ? `${value.slice(0, TELEMETRY_VALUE_MAX_LENGTH - 1)}…`
34
+ : value;
35
+ }
36
+ function normalizeParamKey(key) {
37
+ const normalized = key.replace(/[^a-zA-Z0-9_]/g, '_').replace(/^_+/, '');
38
+ const prefixed = /^[a-zA-Z]/.test(normalized)
39
+ ? normalized
40
+ : `p_${normalized || 'value'}`;
41
+ return prefixed.slice(0, 40);
42
+ }
43
+ function normalizeParamValue(value) {
44
+ if (value === undefined || value === null) {
45
+ return undefined;
46
+ }
47
+ if (typeof value === 'boolean') {
48
+ return value ? 1 : 0;
49
+ }
50
+ if (typeof value === 'number') {
51
+ return Number.isFinite(value) ? value : undefined;
52
+ }
53
+ if (typeof value === 'string') {
54
+ return truncateValue(value);
55
+ }
56
+ const cleaned = cleanProperties(value);
57
+ if (cleaned === undefined) {
58
+ return undefined;
59
+ }
60
+ return truncateValue(JSON.stringify(cleaned));
61
+ }
62
+ function createTelemetryRequestBody(event, distinctId, properties) {
63
+ const params = new URLSearchParams({
64
+ cid: distinctId,
65
+ en: event,
66
+ tid: TELEMETRY_PROPERTY_ID,
67
+ v: '2',
68
+ });
69
+ for (const [key, value] of Object.entries(properties)) {
70
+ const normalizedValue = normalizeParamValue(value);
71
+ if (normalizedValue === undefined) {
72
+ continue;
73
+ }
74
+ const normalizedKey = normalizeParamKey(key);
75
+ const paramName = typeof normalizedValue === 'number'
76
+ ? `${TELEMETRY_NUMERIC_PREFIX}${normalizedKey}`
77
+ : `${TELEMETRY_STRING_PREFIX}${normalizedKey}`;
78
+ params.append(paramName, String(normalizedValue));
79
+ }
80
+ return params.toString();
81
+ }
29
82
  function getErrorCode(error) {
30
83
  if (!error || typeof error !== 'object') {
31
84
  return 'unknown_error';
@@ -63,17 +116,12 @@ async function postEvent(event, distinctId, properties) {
63
116
  controller.abort();
64
117
  }, TELEMETRY_TIMEOUT_MS);
65
118
  try {
66
- await fetch(POSTHOG_CAPTURE_ENDPOINT, {
119
+ await fetch(TELEMETRY_TRANSPORT_ENDPOINT, {
67
120
  method: 'POST',
68
121
  headers: {
69
- 'Content-Type': 'application/json',
122
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
70
123
  },
71
- body: JSON.stringify({
72
- api_key: POSTHOG_PROJECT_TOKEN,
73
- distinct_id: distinctId,
74
- event,
75
- properties,
76
- }),
124
+ body: createTelemetryRequestBody(event, distinctId, properties),
77
125
  signal: controller.signal,
78
126
  });
79
127
  }
@@ -171,7 +219,7 @@ export class TelemetryClient {
171
219
  }
172
220
  baseProperties() {
173
221
  return {
174
- $lib: 'tanstack-cli',
222
+ client_lib: 'tanstack-cli',
175
223
  disabled_by: this.disabledBy,
176
224
  node_major: getNodeMajorVersion(),
177
225
  os_arch: process.arch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cli",
3
- "version": "0.63.0",
3
+ "version": "0.64.0",
4
4
  "description": "TanStack CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -41,7 +41,7 @@
41
41
  "tempy": "^3.1.0",
42
42
  "validate-npm-package-name": "^7.0.0",
43
43
  "zod": "^3.24.2",
44
- "@tanstack/create": "0.63.2"
44
+ "@tanstack/create": "0.63.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@playwright/test": "^1.58.2",