@docyrus/docyrus 0.0.13 → 0.0.15

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/main.js +282 -33
  2. package/main.js.map +3 -3
  3. package/package.json +1 -1
package/main.js CHANGED
@@ -124678,7 +124678,7 @@ function buildInputSchema(args, env2, options2) {
124678
124678
  // package.json
124679
124679
  var package_default = {
124680
124680
  name: "@docyrus/docyrus",
124681
- version: "0.0.13",
124681
+ version: "0.0.15",
124682
124682
  private: false,
124683
124683
  description: "Docyrus API CLI",
124684
124684
  main: "./main.js",
@@ -125009,6 +125009,54 @@ function createAiCli(dependencies) {
125009
125009
  }
125010
125010
 
125011
125011
  // src/commands/appsCommands.ts
125012
+ function normalizeOptional(value) {
125013
+ const trimmed = value?.trim();
125014
+ return trimmed && trimmed.length > 0 ? trimmed : void 0;
125015
+ }
125016
+ function extractAppRecords(payload) {
125017
+ if (Array.isArray(payload)) {
125018
+ return payload.filter((item) => typeof item === "object" && item !== null);
125019
+ }
125020
+ if (typeof payload === "object" && payload !== null && Array.isArray(payload.data)) {
125021
+ return payload.data.filter((item) => typeof item === "object" && item !== null);
125022
+ }
125023
+ return [];
125024
+ }
125025
+ function extractString(record2, key) {
125026
+ const value = record2[key];
125027
+ return typeof value === "string" && value.length > 0 ? value : void 0;
125028
+ }
125029
+ async function resolveAppId(params) {
125030
+ const appId = normalizeOptional(params.appId);
125031
+ const appSlug = normalizeOptional(params.appSlug);
125032
+ if (appId && appSlug) {
125033
+ throw new UserInputError("Provide either --appId or --appSlug, not both.");
125034
+ }
125035
+ if (!appId && !appSlug) {
125036
+ throw new UserInputError("Provide --appId or --appSlug.");
125037
+ }
125038
+ if (appId) {
125039
+ return appId;
125040
+ }
125041
+ const response = await params.apiClient.request({
125042
+ method: "GET",
125043
+ path: "/apps"
125044
+ });
125045
+ const apps = extractAppRecords(response.data);
125046
+ const matches = apps.filter((item) => extractString(item, "slug") === appSlug);
125047
+ if (matches.length === 0) {
125048
+ throw new UserInputError(`App slug '${appSlug}' was not found.`);
125049
+ }
125050
+ if (matches.length > 1) {
125051
+ const matchingIds = matches.map((item) => extractString(item, "id")).filter((value) => Boolean(value));
125052
+ throw new UserInputError(`App slug '${appSlug}' is ambiguous. Matching IDs: ${matchingIds.join(", ")}`);
125053
+ }
125054
+ const resolvedId = extractString(matches[0], "id");
125055
+ if (!resolvedId) {
125056
+ throw new UserInputError(`App slug '${appSlug}' resolved to an invalid item without id.`);
125057
+ }
125058
+ return resolvedId;
125059
+ }
125012
125060
  function createAppsCli(dependencies) {
125013
125061
  const appsCli = Cli_exports.create("apps", {
125014
125062
  description: "App commands",
@@ -125036,6 +125084,81 @@ function createAppsCli(dependencies) {
125036
125084
  });
125037
125085
  }
125038
125086
  });
125087
+ appsCli.command("delete", {
125088
+ description: "Archive an app",
125089
+ options: external_exports.object({
125090
+ appId: external_exports.string().optional().describe("App ID"),
125091
+ appSlug: external_exports.string().optional().describe("App slug")
125092
+ }),
125093
+ run: async (context) => {
125094
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125095
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125096
+ const appId = await resolveAppId({
125097
+ apiClient,
125098
+ appId: context.options.appId,
125099
+ appSlug: context.options.appSlug
125100
+ });
125101
+ const response = await apiClient.request({
125102
+ method: "DELETE",
125103
+ path: `/dev/apps/${appId}`
125104
+ });
125105
+ return await injectContext({
125106
+ apiBaseUrl,
125107
+ authStore: dependencies.authStore,
125108
+ payload: response.data
125109
+ });
125110
+ }
125111
+ });
125112
+ appsCli.command("restore", {
125113
+ description: "Restore an archived app",
125114
+ options: external_exports.object({
125115
+ appId: external_exports.string().optional().describe("App ID"),
125116
+ appSlug: external_exports.string().optional().describe("App slug")
125117
+ }),
125118
+ run: async (context) => {
125119
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125120
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125121
+ const appId = await resolveAppId({
125122
+ apiClient,
125123
+ appId: context.options.appId,
125124
+ appSlug: context.options.appSlug
125125
+ });
125126
+ const response = await apiClient.request({
125127
+ method: "POST",
125128
+ path: `/dev/apps/${appId}/restore`
125129
+ });
125130
+ return await injectContext({
125131
+ apiBaseUrl,
125132
+ authStore: dependencies.authStore,
125133
+ payload: response.data
125134
+ });
125135
+ }
125136
+ });
125137
+ appsCli.command("permanent-delete", {
125138
+ description: "Permanently delete an app",
125139
+ options: external_exports.object({
125140
+ appId: external_exports.string().optional().describe("App ID"),
125141
+ appSlug: external_exports.string().optional().describe("App slug")
125142
+ }),
125143
+ run: async (context) => {
125144
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125145
+ const apiClient = dependencies.createApiClient(apiBaseUrl);
125146
+ const appId = await resolveAppId({
125147
+ apiClient,
125148
+ appId: context.options.appId,
125149
+ appSlug: context.options.appSlug
125150
+ });
125151
+ const response = await apiClient.request({
125152
+ method: "DELETE",
125153
+ path: `/dev/apps/${appId}/permanent`
125154
+ });
125155
+ return await injectContext({
125156
+ apiBaseUrl,
125157
+ authStore: dependencies.authStore,
125158
+ payload: response.data
125159
+ });
125160
+ }
125161
+ });
125039
125162
  return appsCli;
125040
125163
  }
125041
125164
 
@@ -125214,6 +125337,49 @@ async function resolveTenantIdSelector(params) {
125214
125337
  }
125215
125338
  return selector;
125216
125339
  }
125340
+ async function resolveClientId(params) {
125341
+ const envClientId = getOptionalEnvValue(params.env, "DOCYRUS_API_CLIENT_ID");
125342
+ const configuredClientId = await params.environmentConfigService.getDefaultClientId();
125343
+ const globalConfiguredClientId = configuredClientId ? void 0 : await params.globalEnvironmentConfigService?.getDefaultClientId();
125344
+ const resolvedClientId = params.requestedClientId || envClientId || configuredClientId || globalConfiguredClientId;
125345
+ return {
125346
+ configuredClientId,
125347
+ globalConfiguredClientId,
125348
+ resolvedClientId,
125349
+ clientId: resolvedClientId || (params.allowManualFallback ? "manual-token" : void 0)
125350
+ };
125351
+ }
125352
+ async function loginWithManualTokens(params) {
125353
+ const manualAccessToken = params.accessToken.trim();
125354
+ const manualRefreshToken = params.refreshToken?.trim();
125355
+ if (!manualAccessToken) {
125356
+ throw new UserInputError("accessToken is required.");
125357
+ }
125358
+ const resolvedClient = await resolveClientId({
125359
+ requestedClientId: params.clientId,
125360
+ env: params.env,
125361
+ environmentConfigService: params.dependencies.environmentConfigService,
125362
+ globalEnvironmentConfigService: params.dependencies.globalEnvironmentConfigService,
125363
+ allowManualFallback: true
125364
+ });
125365
+ if (!resolvedClient.clientId) {
125366
+ throw new UserInputError(
125367
+ "Client ID is required. Pass --clientId, set DOCYRUS_API_CLIENT_ID, or login once with --clientId to save it."
125368
+ );
125369
+ }
125370
+ const authSessionService = params.dependencies.createAuthSessionService(params.apiBaseUrl);
125371
+ const profile = await authSessionService.loginWithManualTokens({
125372
+ clientId: resolvedClient.clientId,
125373
+ accessToken: manualAccessToken,
125374
+ refreshToken: manualRefreshToken || void 0,
125375
+ scope: params.scope,
125376
+ tokenType: "Bearer"
125377
+ });
125378
+ if (resolvedClient.resolvedClientId) {
125379
+ await params.dependencies.environmentConfigService.setDefaultClientId(resolvedClient.resolvedClientId);
125380
+ }
125381
+ return profile;
125382
+ }
125217
125383
  function createAuthCli(dependencies) {
125218
125384
  const authCli = Cli_exports.create("auth", {
125219
125385
  description: "Authentication commands",
@@ -125234,32 +125400,36 @@ function createAuthCli(dependencies) {
125234
125400
  if (manualRefreshToken && !manualAccessToken) {
125235
125401
  throw new UserInputError("refreshToken requires accessToken. Pass --accessToken when using --refreshToken.");
125236
125402
  }
125237
- const envClientId = getOptionalEnvValue(context.env, "DOCYRUS_API_CLIENT_ID");
125238
- const configuredClientId = await dependencies.environmentConfigService.getDefaultClientId();
125239
- const globalConfiguredClientId = configuredClientId ? void 0 : await dependencies.globalEnvironmentConfigService?.getDefaultClientId();
125240
- const resolvedClientId = context.options.clientId || envClientId || configuredClientId || globalConfiguredClientId;
125241
- const clientId = resolvedClientId || (manualAccessToken ? "manual-token" : void 0);
125403
+ const resolvedClient = await resolveClientId({
125404
+ requestedClientId: context.options.clientId,
125405
+ env: context.env,
125406
+ environmentConfigService: dependencies.environmentConfigService,
125407
+ globalEnvironmentConfigService: dependencies.globalEnvironmentConfigService,
125408
+ allowManualFallback: Boolean(manualAccessToken)
125409
+ });
125410
+ const clientId = resolvedClient.clientId;
125242
125411
  if (!clientId) {
125243
125412
  throw new UserInputError(
125244
125413
  "Client ID is required. Pass --clientId, set DOCYRUS_API_CLIENT_ID, or login once with --clientId to save it."
125245
125414
  );
125246
125415
  }
125247
- const authSessionService = dependencies.createAuthSessionService(apiBaseUrl);
125248
- const profile = manualAccessToken ? await authSessionService.loginWithManualTokens({
125249
- clientId,
125416
+ const profile = manualAccessToken ? await loginWithManualTokens({
125417
+ apiBaseUrl,
125250
125418
  accessToken: manualAccessToken,
125251
- refreshToken: manualRefreshToken || void 0,
125419
+ refreshToken: manualRefreshToken,
125420
+ clientId: context.options.clientId,
125252
125421
  scope: context.options.scope,
125253
- tokenType: "Bearer"
125254
- }) : await authSessionService.loginWithDeviceFlow({
125422
+ dependencies,
125423
+ env: context.env
125424
+ }) : await dependencies.createAuthSessionService(apiBaseUrl).loginWithDeviceFlow({
125255
125425
  clientId,
125256
125426
  scope: context.options.scope,
125257
125427
  onVerification: (verification) => {
125258
125428
  logVerificationHint(verification, context.agent, dependencies.onMessage);
125259
125429
  }
125260
125430
  });
125261
- if (resolvedClientId) {
125262
- await dependencies.environmentConfigService.setDefaultClientId(resolvedClientId);
125431
+ if (!manualAccessToken && resolvedClient.resolvedClientId) {
125432
+ await dependencies.environmentConfigService.setDefaultClientId(resolvedClient.resolvedClientId);
125263
125433
  }
125264
125434
  return await injectContext({
125265
125435
  apiBaseUrl,
@@ -125279,6 +125449,43 @@ function createAuthCli(dependencies) {
125279
125449
  });
125280
125450
  }
125281
125451
  });
125452
+ authCli.command("set-tokens", {
125453
+ description: "Set custom access and refresh tokens for the active environment",
125454
+ options: external_exports.object({
125455
+ clientId: external_exports.string().optional().describe("OAuth2 client id"),
125456
+ scope: external_exports.string().default(DEFAULT_LOGIN_SCOPES).describe("OAuth2 scopes"),
125457
+ accessToken: external_exports.string().min(1).describe("Custom access token"),
125458
+ refreshToken: external_exports.string().optional().describe("Custom refresh token")
125459
+ }),
125460
+ run: async (context) => {
125461
+ const apiBaseUrl = await dependencies.environmentConfigService.getActiveApiBaseUrl();
125462
+ const profile = await loginWithManualTokens({
125463
+ apiBaseUrl,
125464
+ accessToken: context.options.accessToken,
125465
+ refreshToken: context.options.refreshToken,
125466
+ clientId: context.options.clientId,
125467
+ scope: context.options.scope,
125468
+ dependencies,
125469
+ env: context.env
125470
+ });
125471
+ return await injectContext({
125472
+ apiBaseUrl,
125473
+ authStore: dependencies.authStore,
125474
+ payload: {
125475
+ authenticated: true,
125476
+ apiBaseUrl,
125477
+ userId: profile.userId,
125478
+ email: profile.email,
125479
+ tenantId: profile.tenantId,
125480
+ tenantName: profile.tenantName,
125481
+ tenantNo: profile.tenantNo,
125482
+ clientId: profile.clientId,
125483
+ scope: profile.scope,
125484
+ expiresAt: profile.expiresAt
125485
+ }
125486
+ });
125487
+ }
125488
+ });
125282
125489
  const accountsCli = Cli_exports.create("accounts", {
125283
125490
  description: "Account management",
125284
125491
  env: EnvSchema
@@ -126370,7 +126577,7 @@ function normalizeBatchPayload(payload, key) {
126370
126577
  function isRecord4(value) {
126371
126578
  return typeof value === "object" && value !== null;
126372
126579
  }
126373
- function extractString(record2, key) {
126580
+ function extractString2(record2, key) {
126374
126581
  const value = record2[key];
126375
126582
  return typeof value === "string" && value.length > 0 ? value : void 0;
126376
126583
  }
@@ -126391,20 +126598,20 @@ function ensureExclusiveSelector(label, idValue, slugValue) {
126391
126598
  throw new UserInputError(`Provide --${label}Id or --${label}Slug.`);
126392
126599
  }
126393
126600
  }
126394
- function normalizeOptional(value) {
126601
+ function normalizeOptional2(value) {
126395
126602
  const trimmed = value?.trim();
126396
126603
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
126397
126604
  }
126398
126605
  function resolveBySlug(label, items, slug) {
126399
- const matches = items.filter((item) => extractString(item, "slug") === slug);
126606
+ const matches = items.filter((item) => extractString2(item, "slug") === slug);
126400
126607
  if (matches.length === 0) {
126401
126608
  throw new UserInputError(`${label} slug '${slug}' was not found.`);
126402
126609
  }
126403
126610
  if (matches.length > 1) {
126404
- const matchingIds = matches.map((item) => extractString(item, "id")).filter((id) => Boolean(id));
126611
+ const matchingIds = matches.map((item) => extractString2(item, "id")).filter((id) => Boolean(id));
126405
126612
  throw new UserInputError(`${label} slug '${slug}' is ambiguous. Matching IDs: ${matchingIds.join(", ")}`);
126406
126613
  }
126407
- const matchId = extractString(matches[0], "id");
126614
+ const matchId = extractString2(matches[0], "id");
126408
126615
  if (!matchId) {
126409
126616
  throw new UserInputError(`${label} slug '${slug}' resolved to an invalid item without id.`);
126410
126617
  }
@@ -126418,8 +126625,8 @@ var StudioResolver = class {
126418
126625
  #dataSourcesByAppId = /* @__PURE__ */ new Map();
126419
126626
  #fieldsByAppAndDataSource = /* @__PURE__ */ new Map();
126420
126627
  async resolveAppId(options2) {
126421
- const appId = normalizeOptional(options2.appId);
126422
- const appSlug = normalizeOptional(options2.appSlug);
126628
+ const appId = normalizeOptional2(options2.appId);
126629
+ const appSlug = normalizeOptional2(options2.appSlug);
126423
126630
  ensureExclusiveSelector("app", appId, appSlug);
126424
126631
  if (appId) {
126425
126632
  return appId;
@@ -126428,8 +126635,8 @@ var StudioResolver = class {
126428
126635
  return resolveBySlug("App", apps, appSlug);
126429
126636
  }
126430
126637
  async resolveDataSourceId(options2) {
126431
- const dataSourceId = normalizeOptional(options2.dataSourceId);
126432
- const dataSourceSlug = normalizeOptional(options2.dataSourceSlug);
126638
+ const dataSourceId = normalizeOptional2(options2.dataSourceId);
126639
+ const dataSourceSlug = normalizeOptional2(options2.dataSourceSlug);
126433
126640
  ensureExclusiveSelector("dataSource", dataSourceId, dataSourceSlug);
126434
126641
  if (dataSourceId) {
126435
126642
  return dataSourceId;
@@ -126438,8 +126645,8 @@ var StudioResolver = class {
126438
126645
  return resolveBySlug("Data source", dataSources, dataSourceSlug);
126439
126646
  }
126440
126647
  async resolveFieldId(options2) {
126441
- const fieldId = normalizeOptional(options2.fieldId);
126442
- const fieldSlug = normalizeOptional(options2.fieldSlug);
126648
+ const fieldId = normalizeOptional2(options2.fieldId);
126649
+ const fieldSlug = normalizeOptional2(options2.fieldSlug);
126443
126650
  ensureExclusiveSelector("field", fieldId, fieldSlug);
126444
126651
  if (fieldId) {
126445
126652
  return fieldId;
@@ -126684,7 +126891,7 @@ function createStudioCli(dependencies) {
126684
126891
  }
126685
126892
  });
126686
126893
  studioCli.command("delete-data-source", {
126687
- description: "Delete a data source",
126894
+ description: "Archive a data source",
126688
126895
  options: external_exports.object({
126689
126896
  appId: external_exports.string().optional().describe("App ID"),
126690
126897
  appSlug: external_exports.string().optional().describe("App slug"),
@@ -126709,6 +126916,46 @@ function createStudioCli(dependencies) {
126709
126916
  return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
126710
126917
  }
126711
126918
  });
126919
+ studioCli.command("restore-data-source", {
126920
+ description: "Restore an archived data source",
126921
+ options: external_exports.object({
126922
+ appId: external_exports.string().optional().describe("App ID"),
126923
+ appSlug: external_exports.string().optional().describe("App slug"),
126924
+ dataSourceId: external_exports.string().min(1).describe("Data source ID")
126925
+ }),
126926
+ run: async (context) => {
126927
+ const studio = await getStudioRunContext(dependencies);
126928
+ const appId = await studio.resolver.resolveAppId({
126929
+ appId: context.options.appId,
126930
+ appSlug: context.options.appSlug
126931
+ });
126932
+ const response = await studio.apiClient.request({
126933
+ method: "POST",
126934
+ path: `/dev/apps/${appId}/data-sources/${context.options.dataSourceId}/restore`
126935
+ });
126936
+ return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
126937
+ }
126938
+ });
126939
+ studioCli.command("permanent-delete-data-source", {
126940
+ description: "Permanently delete a data source",
126941
+ options: external_exports.object({
126942
+ appId: external_exports.string().optional().describe("App ID"),
126943
+ appSlug: external_exports.string().optional().describe("App slug"),
126944
+ dataSourceId: external_exports.string().min(1).describe("Data source ID")
126945
+ }),
126946
+ run: async (context) => {
126947
+ const studio = await getStudioRunContext(dependencies);
126948
+ const appId = await studio.resolver.resolveAppId({
126949
+ appId: context.options.appId,
126950
+ appSlug: context.options.appSlug
126951
+ });
126952
+ const response = await studio.apiClient.request({
126953
+ method: "DELETE",
126954
+ path: `/dev/apps/${appId}/data-sources/${context.options.dataSourceId}/permanent`
126955
+ });
126956
+ return await wrapStudioPayload(studio.apiBaseUrl, dependencies, response.data);
126957
+ }
126958
+ });
126712
126959
  studioCli.command("bulk-create-data-sources", {
126713
126960
  description: "Bulk create data sources",
126714
126961
  options: external_exports.object({
@@ -127514,7 +127761,7 @@ function extractRecordValue(record2, keys) {
127514
127761
  }
127515
127762
  return void 0;
127516
127763
  }
127517
- function extractString2(record2, keys) {
127764
+ function extractString3(record2, keys) {
127518
127765
  const value = extractRecordValue(record2, keys);
127519
127766
  return typeof value === "string" && value.length > 0 ? value : void 0;
127520
127767
  }
@@ -127821,10 +128068,10 @@ var AuthSessionService = class {
127821
128068
  throw new AuthSessionError("Unable to parse /users/me response.");
127822
128069
  }
127823
128070
  const tenantCandidate = isRecord5(dataCandidate.tenant) ? dataCandidate.tenant : void 0;
127824
- const userId = extractString2(dataCandidate, ["id", "user_id"]);
127825
- const email3 = extractString2(dataCandidate, ["email"]);
127826
- const tenantId = tenantCandidate ? extractString2(tenantCandidate, ["id"]) : extractString2(dataCandidate, ["tenant_id", "tenantId"]);
127827
- const tenantName = tenantCandidate ? extractString2(tenantCandidate, ["name"]) : extractString2(dataCandidate, ["tenant_name", "tenantName"]);
128071
+ const userId = extractString3(dataCandidate, ["id", "user_id"]);
128072
+ const email3 = extractString3(dataCandidate, ["email"]);
128073
+ const tenantId = tenantCandidate ? extractString3(tenantCandidate, ["id"]) : extractString3(dataCandidate, ["tenant_id", "tenantId"]);
128074
+ const tenantName = tenantCandidate ? extractString3(tenantCandidate, ["name"]) : extractString3(dataCandidate, ["tenant_name", "tenantName"]);
127828
128075
  const tenantNo = tenantCandidate ? extractNumber(tenantCandidate, ["no", "tenant_no"]) : extractNumber(dataCandidate, ["tenant_no", "tenantNo"]);
127829
128076
  if (!userId || !email3 || !tenantId || !tenantName || !tenantNo) {
127830
128077
  throw new AuthSessionError("Incomplete identity data returned from /users/me.");
@@ -127855,8 +128102,8 @@ var AuthSessionService = class {
127855
128102
  if (!isRecord5(item)) {
127856
128103
  continue;
127857
128104
  }
127858
- const tenantId = extractString2(item, ["id", "tenant_id"]);
127859
- const tenantName = extractString2(item, ["name"]);
128105
+ const tenantId = extractString3(item, ["id", "tenant_id"]);
128106
+ const tenantName = extractString3(item, ["name"]);
127860
128107
  const tenantNo = extractNumber(item, ["tenant_no", "tenantNo", "no"]);
127861
128108
  const logoValue = extractRecordValue(item, ["logo"]);
127862
128109
  const logo = typeof logoValue === "string" || logoValue === null ? logoValue : void 0;
@@ -128602,6 +128849,7 @@ var ROOT_HELP_COMMANDS = [
128602
128849
  { command: "env", description: "Show active environment and list environments" },
128603
128850
  { command: "env use <id|name>", description: "Switch active environment" },
128604
128851
  { command: "auth login", description: "Authenticate with OAuth2 device flow" },
128852
+ { command: "auth set-tokens --accessToken <token>", description: "Save custom access and refresh tokens" },
128605
128853
  { command: "auth accounts list", description: "List saved user accounts" },
128606
128854
  { command: "auth tenants use <uuid|tenantNo>", description: "Switch active tenant for selected user" },
128607
128855
  { command: 'ai "<prompt>"', description: "Send a prompt to the default Docyrus CLI agent" },
@@ -128613,6 +128861,7 @@ var ROOT_HELP_COMMANDS = [
128613
128861
  { command: "discover search <terms>", description: "Search in endpoint paths and entity names" },
128614
128862
  { command: "ds list <appSlug> <dataSourceSlug>", description: "List data source items" },
128615
128863
  { command: "apps list", description: "List apps" },
128864
+ { command: "apps delete --appId <id>", description: "Archive an app" },
128616
128865
  { command: "studio list-data-sources --appSlug <slug>", description: "List studio data sources" },
128617
128866
  { command: "tui", description: "Launch terminal UI (OpenTUI, requires Bun)" },
128618
128867
  { command: "curl <path>", description: "Send arbitrary API requests" }