@tenderprompt/cli 0.1.6 → 0.1.8

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 +14 -7
  2. package/dist/index.js +543 -135
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,6 +20,8 @@ function rootHelp() {
20
20
  return `Usage: tender <command> [options]
21
21
 
22
22
  Commands:
23
+ tender capabilities --json
24
+ Describe the CLI command surface for coding agents
23
25
  tender auth login --device
24
26
  Authorize this machine with a browser-approved device flow
25
27
  tender auth status Show whether a Tender API token is available
@@ -58,16 +60,16 @@ Commands:
58
60
  Report whether managed context is stale
59
61
  tender app context refresh <app-id>
60
62
  Refresh managed context files
63
+ tender app bindings outbound --id <id> --host <host> --dry-run
64
+ Preview files for an outbound HTTP binding
61
65
  tender app git setup <app-id>
62
66
  Configure a checkout to push to the app remote
63
67
  tender app doctor Validate a local Tender App checkout
64
68
  tender app generate-env-types
65
69
  Regenerate src/env.d.ts from app.json and bindings
66
70
 
67
- Compatibility:
68
- tender artifacts ... Legacy alias for Tender App commands
69
-
70
71
  Examples:
72
+ tender capabilities --json
71
73
  tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
72
74
  tender auth status --json
73
75
  tender app list --json
@@ -86,6 +88,7 @@ Examples:
86
88
  tender app context fetch artifact_123 --dir ./widget --dry-run --json
87
89
  tender app context status artifact_123 --dir ./widget --json
88
90
  tender app context refresh artifact_123 --dir ./widget --dry-run --json
91
+ tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json
89
92
  tender app git setup artifact_123 --dir ./widget --json
90
93
  tender app doctor --dir ./widget
91
94
  tender app generate-env-types --dir ./widget --json
@@ -175,6 +178,8 @@ Commands:
175
178
  Show managed context freshness for a checkout
176
179
  tender app context refresh <app-id>
177
180
  Refresh managed context files in a checkout
181
+ tender app bindings outbound --id <id> --host <host> --dry-run
182
+ Preview files for an outbound HTTP binding
178
183
  tender app git setup <app-id>
179
184
  Configure the tender Git remote and credential helper
180
185
  tender app doctor Validate local context, TypeScript scaffold, and Tender App rules
@@ -205,17 +210,21 @@ Examples:
205
210
  tender app context fetch artifact_123 --dir ./widget --dry-run --json
206
211
  tender app context status artifact_123 --dir ./widget --json
207
212
  tender app context refresh artifact_123 --dir ./widget --dry-run --json
213
+ tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json
208
214
  tender app git setup artifact_123 --dir ./widget --json
209
215
  tender app doctor --dir ./widget
210
216
  tender app generate-env-types --dir ./widget --json
211
217
  tender app doctor --json
212
218
  tender app git remote artifact_123 --ttl 7d --json`;
213
219
  }
214
- function artifactsHelp() {
215
- return `${appHelp()}
220
+ function capabilitiesHelp() {
221
+ return `Usage: tender capabilities [--json]
222
+
223
+ Describes the Tender CLI surface for coding agents. Use this first instead of
224
+ copying long command lists into skill prompts.
216
225
 
217
- Legacy alias:
218
- tender artifacts ... continues to work for existing automation. Prefer tender app ... for new workflows.`;
226
+ Examples:
227
+ tender capabilities --json`;
219
228
  }
220
229
  function analyticsHelp() {
221
230
  return `Usage: tender app analytics <command> <app-id> [options]
@@ -441,6 +450,26 @@ Examples:
441
450
  tender app generate-env-types --dir ./widget
442
451
  tender app generate-env-types --dir ./widget --json`;
443
452
  }
453
+ function bindingsOutboundHelp() {
454
+ return `Usage: tender app bindings outbound --id <id> --host <host> --dry-run [--name <ENV_NAME>] [--label <label>] [--interface <TypeName>] [--json]
455
+
456
+ Preview the file shape for an outbound HTTP binding. App server code cannot call
457
+ third-party internet URLs directly; external APIs, OAuth/token exchanges,
458
+ webhooks, and secrets must go through bindings.
459
+
460
+ Options:
461
+ --id <id> Binding id and directory name, for example shopify-api.
462
+ --host <host> Explicit lowercase host without protocol, wildcard, path, query, or port.
463
+ --name <ENV_NAME> App env binding name. Defaults to the id converted to UPPER_SNAKE.
464
+ --label <label> Human label for app.json. Defaults to a title-cased id.
465
+ --interface <TypeName> TypeScript interface and worker class name. Defaults to a PascalCase id plus Binding.
466
+ --dry-run Required. Prints files and app.json binding entry without writing.
467
+ --json Emit stable JSON for coding agents.
468
+
469
+ Examples:
470
+ tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json
471
+ tender app bindings outbound --id yotpo-api --host api.yotpo.com --name YOTPO --label "Yotpo API" --dry-run --json`;
472
+ }
444
473
  function gitRemoteHelp() {
445
474
  return `Usage: tender app git remote <app-id> [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--json]
446
475
 
@@ -605,6 +634,149 @@ Options:
605
634
  Examples:
606
635
  tender app publish watch artifact_123 --job job_123 --stream --json`;
607
636
  }
637
+ function tenderCliCapabilities() {
638
+ return {
639
+ ok: true,
640
+ surface: "tender_cli",
641
+ description: "Agent-safe Tender App source, lifecycle, analytics, and local scaffold controls.",
642
+ discovery: {
643
+ primary: "tender capabilities --json",
644
+ layeredHelp: [
645
+ "tender --help",
646
+ "tender auth --help",
647
+ "tender app --help",
648
+ "tender app analytics --help",
649
+ "tender app bindings outbound --help",
650
+ ],
651
+ },
652
+ workflows: [
653
+ {
654
+ name: "authenticate",
655
+ when: "Before reading or changing remote Tender App records.",
656
+ commands: [
657
+ "tender auth status --json",
658
+ "tender auth login --device --profile edit-preview --artifact <artifact-id> --ttl 7d --json",
659
+ ],
660
+ },
661
+ {
662
+ name: "clone_or_bootstrap_existing_app",
663
+ when: "When the user wants to download or work on an existing app locally.",
664
+ commands: [
665
+ "tender app init <artifact-id> --dir <dir> --dry-run --json",
666
+ "tender app init <artifact-id> --dir <dir> --json",
667
+ ],
668
+ notes: [
669
+ "init is the normal clone/bootstrap command.",
670
+ "If the app already has artifact Git source, init fetches it and configures the tender remote.",
671
+ "If no artifact Git source exists yet, init writes managed context/scaffold files and configures the tender remote.",
672
+ "Use context fetch only when you already have a checkout and only need AGENTS.md, skills, or Tender context refreshed.",
673
+ ],
674
+ },
675
+ {
676
+ name: "local_edit_preview_publish",
677
+ when: "When editing app source from a local checkout.",
678
+ commands: [
679
+ "tender app doctor --dir <dir> --json",
680
+ "tender app git setup <artifact-id> --dir <dir> --dry-run --json",
681
+ "git push tender main",
682
+ "tender app preview <artifact-id> --commit $(git rev-parse HEAD) --stream --json",
683
+ "tender app publish <artifact-id> --dry-run --json",
684
+ "tender app publish <artifact-id> --commit $(git rev-parse HEAD) --confirm publish --stream --json",
685
+ ],
686
+ notes: [
687
+ "Publishing is production-facing and requires explicit user intent.",
688
+ ],
689
+ },
690
+ {
691
+ name: "analytics_agent_loop",
692
+ when: "When understanding app analytics or creating saved charts.",
693
+ commands: [
694
+ "tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json",
695
+ "tender app analytics query <artifact-id> --spec chart.json --json",
696
+ "tender app analytics export query <artifact-id> --spec chart.json --format csv",
697
+ "tender app analytics dashboards <artifact-id> --create \"Agent dashboard\" --dry-run --json",
698
+ "tender app analytics charts create <artifact-id> --dashboard <dashboard-id> --title <title> --spec chart.json --dry-run --json",
699
+ ],
700
+ notes: [
701
+ "Combine CLI capabilities with local source inspection of analytics calls.",
702
+ "Validate chart specs with query before saving charts.",
703
+ ],
704
+ },
705
+ {
706
+ name: "outbound_http_binding",
707
+ when: "When app code needs external APIs, OAuth/token exchange, webhooks, provider SDKs, or secrets.",
708
+ commands: [
709
+ "tender app bindings outbound --id <id> --host <host> --dry-run --json",
710
+ "tender app generate-env-types --dir <dir> --json",
711
+ "tender app doctor --dir <dir> --json",
712
+ ],
713
+ notes: [
714
+ "src/server.ts cannot call third-party internet URLs directly.",
715
+ "Outbound calls are blocked unless they go through a binding with outbound:http and explicit allowedHosts.",
716
+ ],
717
+ },
718
+ ],
719
+ commands: [
720
+ {
721
+ command: "tender capabilities --json",
722
+ purpose: "Discover this CLI surface in a machine-readable shape.",
723
+ requiresAuth: false,
724
+ writes: false,
725
+ },
726
+ {
727
+ command: "tender app init <artifact-id> --dir <dir> --json",
728
+ purpose: "Clone/bootstrap an existing Tender App checkout and configure context plus the tender Git remote.",
729
+ requiresAuth: true,
730
+ writes: true,
731
+ dryRun: true,
732
+ },
733
+ {
734
+ command: "tender app context fetch <artifact-id> --dir <dir> --json",
735
+ purpose: "Fetch managed AGENTS.md, skills, and Tender context into an existing checkout.",
736
+ requiresAuth: true,
737
+ writes: true,
738
+ dryRun: true,
739
+ },
740
+ {
741
+ command: "tender app bindings outbound --id <id> --host <host> --dry-run --json",
742
+ purpose: "Preview app.json and binding files for an outbound HTTP integration.",
743
+ requiresAuth: false,
744
+ writes: false,
745
+ },
746
+ {
747
+ command: "tender app analytics capabilities <artifact-id> --include-catalog --range 30d --json",
748
+ purpose: "Discover artifact-scoped analytics commands, chart specs, saved dashboards, and bounded observed catalog.",
749
+ requiresAuth: true,
750
+ writes: false,
751
+ },
752
+ ],
753
+ security: [
754
+ "Prefer artifact-scoped device tokens.",
755
+ "Do not write Tender tokens into the project checkout.",
756
+ "Do not call Tender HTTP APIs directly from agent workflows.",
757
+ "Do not put third-party fetch calls in src/server.ts; use outbound bindings.",
758
+ "Do not request direct query credentials or raw SQL for analytics.",
759
+ ],
760
+ };
761
+ }
762
+ function runCapabilities(command, io) {
763
+ const payload = tenderCliCapabilities();
764
+ if (command.json) {
765
+ io.stdout(JSON.stringify(payload, null, 2));
766
+ }
767
+ else {
768
+ io.stdout([
769
+ "Tender CLI capabilities",
770
+ "",
771
+ "Start with:",
772
+ " tender capabilities --json",
773
+ "",
774
+ "Useful next help topics:",
775
+ ...payload.discovery.layeredHelp.map((topic) => ` ${topic}`),
776
+ ].join("\n"));
777
+ }
778
+ return 0;
779
+ }
608
780
  function normalizeBaseUrl(value) {
609
781
  return (value ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
610
782
  }
@@ -746,7 +918,7 @@ function parseTtl(value) {
746
918
  }
747
919
  function parseGitRemoteArgs(args) {
748
920
  if (args.includes("--help") || args.includes("-h")) {
749
- return { command: "help", topic: "artifacts git remote" };
921
+ return { command: "help", topic: "app git remote" };
750
922
  }
751
923
  const artifactId = args[0];
752
924
  if (!artifactId || artifactId.startsWith("-")) {
@@ -786,7 +958,7 @@ function parseGitRemoteArgs(args) {
786
958
  throw new TenderCliUsageError(`Unknown git remote option: ${arg}`);
787
959
  }
788
960
  return {
789
- command: "artifacts git remote",
961
+ command: "app git remote",
790
962
  artifactId,
791
963
  baseUrl,
792
964
  flagToken,
@@ -806,7 +978,7 @@ function parseRemoteName(value) {
806
978
  }
807
979
  function parseGitSetupArgs(args) {
808
980
  if (args.includes("--help") || args.includes("-h")) {
809
- return { command: "help", topic: "artifacts git setup" };
981
+ return { command: "help", topic: "app git setup" };
810
982
  }
811
983
  const artifactId = args[0];
812
984
  if (!artifactId || artifactId.startsWith("-")) {
@@ -867,7 +1039,7 @@ function parseGitSetupArgs(args) {
867
1039
  throw new TenderCliUsageError(`Unknown git setup option: ${arg}`);
868
1040
  }
869
1041
  return {
870
- command: "artifacts git setup",
1042
+ command: "app git setup",
871
1043
  artifactId,
872
1044
  dir,
873
1045
  remoteName,
@@ -899,7 +1071,7 @@ function isGitCredentialOperation(value) {
899
1071
  }
900
1072
  function parseGitCredentialArgs(args) {
901
1073
  if (args.includes("--help") || args.includes("-h")) {
902
- return { command: "help", topic: "artifacts git credential" };
1074
+ return { command: "help", topic: "app git credential" };
903
1075
  }
904
1076
  const artifactId = args[0];
905
1077
  if (!artifactId || artifactId.startsWith("-")) {
@@ -960,7 +1132,7 @@ function parseGitCredentialArgs(args) {
960
1132
  throw new TenderCliUsageError(`Unknown git credential option: ${arg}`);
961
1133
  }
962
1134
  return {
963
- command: "artifacts git credential",
1135
+ command: "app git credential",
964
1136
  artifactId,
965
1137
  operation,
966
1138
  baseUrl,
@@ -973,7 +1145,7 @@ function parseGitCredentialArgs(args) {
973
1145
  }
974
1146
  function parseValidateArgs(args) {
975
1147
  if (args.includes("--help") || args.includes("-h")) {
976
- return { command: "help", topic: "artifacts validate" };
1148
+ return { command: "help", topic: "app validate" };
977
1149
  }
978
1150
  const artifactId = args[0];
979
1151
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1012,7 +1184,7 @@ function parseValidateArgs(args) {
1012
1184
  throw new TenderCliUsageError(`Unknown validate option: ${arg}`);
1013
1185
  }
1014
1186
  return {
1015
- command: "artifacts validate",
1187
+ command: "app validate",
1016
1188
  artifactId,
1017
1189
  baseUrl,
1018
1190
  flagToken,
@@ -1023,7 +1195,7 @@ function parseValidateArgs(args) {
1023
1195
  }
1024
1196
  function parseBuildArgs(args) {
1025
1197
  if (args.includes("--help") || args.includes("-h")) {
1026
- return { command: "help", topic: "artifacts build" };
1198
+ return { command: "help", topic: "app build" };
1027
1199
  }
1028
1200
  const artifactId = args[0];
1029
1201
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1072,7 +1244,7 @@ function parseBuildArgs(args) {
1072
1244
  throw new TenderCliUsageError(`Unknown build option: ${arg}`);
1073
1245
  }
1074
1246
  return {
1075
- command: "artifacts build",
1247
+ command: "app build",
1076
1248
  artifactId,
1077
1249
  commitSha,
1078
1250
  baseUrl,
@@ -1084,7 +1256,7 @@ function parseBuildArgs(args) {
1084
1256
  }
1085
1257
  function parsePreviewRebuildArgs(args) {
1086
1258
  if (args.includes("--help") || args.includes("-h")) {
1087
- return { command: "help", topic: "artifacts preview rebuild" };
1259
+ return { command: "help", topic: "app preview rebuild" };
1088
1260
  }
1089
1261
  const artifactId = args[0];
1090
1262
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1133,7 +1305,7 @@ function parsePreviewRebuildArgs(args) {
1133
1305
  throw new TenderCliUsageError(`Unknown preview rebuild option: ${arg}`);
1134
1306
  }
1135
1307
  return {
1136
- command: "artifacts preview rebuild",
1308
+ command: "app preview rebuild",
1137
1309
  artifactId,
1138
1310
  commitSha,
1139
1311
  baseUrl,
@@ -1211,7 +1383,7 @@ function readPreviewLookupOptions(input) {
1211
1383
  }
1212
1384
  function parsePreviewStatusArgs(args) {
1213
1385
  if (args.includes("--help") || args.includes("-h")) {
1214
- return { command: "help", topic: "artifacts preview status" };
1386
+ return { command: "help", topic: "app preview status" };
1215
1387
  }
1216
1388
  const artifactId = args[0];
1217
1389
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1226,7 +1398,7 @@ function parsePreviewStatusArgs(args) {
1226
1398
  throw new TenderCliUsageError("preview status does not support --stream. Use tender app preview watch.");
1227
1399
  }
1228
1400
  return {
1229
- command: "artifacts preview status",
1401
+ command: "app preview status",
1230
1402
  artifactId,
1231
1403
  commitSha: options.commitSha,
1232
1404
  jobId: options.jobId,
@@ -1238,7 +1410,7 @@ function parsePreviewStatusArgs(args) {
1238
1410
  }
1239
1411
  function parsePreviewWatchArgs(args) {
1240
1412
  if (args.includes("--help") || args.includes("-h")) {
1241
- return { command: "help", topic: "artifacts preview watch" };
1413
+ return { command: "help", topic: "app preview watch" };
1242
1414
  }
1243
1415
  const artifactId = args[0];
1244
1416
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1250,7 +1422,7 @@ function parsePreviewWatchArgs(args) {
1250
1422
  commandName: "preview watch",
1251
1423
  });
1252
1424
  return {
1253
- command: "artifacts preview watch",
1425
+ command: "app preview watch",
1254
1426
  artifactId,
1255
1427
  commitSha: options.commitSha,
1256
1428
  jobId: options.jobId,
@@ -1263,7 +1435,7 @@ function parsePreviewWatchArgs(args) {
1263
1435
  }
1264
1436
  function parsePublishArgs(args) {
1265
1437
  if (args.includes("--help") || args.includes("-h")) {
1266
- return { command: "help", topic: "artifacts publish" };
1438
+ return { command: "help", topic: "app publish" };
1267
1439
  }
1268
1440
  const artifactId = args[0];
1269
1441
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1340,7 +1512,7 @@ function parsePublishArgs(args) {
1340
1512
  throw new TenderCliUsageError("publish requires --dry-run or --confirm publish.");
1341
1513
  }
1342
1514
  return {
1343
- command: "artifacts publish",
1515
+ command: "app publish",
1344
1516
  artifactId,
1345
1517
  commitSha,
1346
1518
  baseUrl,
@@ -1410,7 +1582,7 @@ function readPublishJobLookupOptions(input) {
1410
1582
  }
1411
1583
  function parsePublishStatusArgs(args) {
1412
1584
  if (args.includes("--help") || args.includes("-h")) {
1413
- return { command: "help", topic: "artifacts publish status" };
1585
+ return { command: "help", topic: "app publish status" };
1414
1586
  }
1415
1587
  const artifactId = args[0];
1416
1588
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1425,7 +1597,7 @@ function parsePublishStatusArgs(args) {
1425
1597
  throw new TenderCliUsageError("publish status does not support --stream. Use tender app publish watch.");
1426
1598
  }
1427
1599
  return {
1428
- command: "artifacts publish status",
1600
+ command: "app publish status",
1429
1601
  artifactId,
1430
1602
  jobId: options.jobId,
1431
1603
  baseUrl: options.baseUrl,
@@ -1436,7 +1608,7 @@ function parsePublishStatusArgs(args) {
1436
1608
  }
1437
1609
  function parsePublishWatchArgs(args) {
1438
1610
  if (args.includes("--help") || args.includes("-h")) {
1439
- return { command: "help", topic: "artifacts publish watch" };
1611
+ return { command: "help", topic: "app publish watch" };
1440
1612
  }
1441
1613
  const artifactId = args[0];
1442
1614
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1448,7 +1620,7 @@ function parsePublishWatchArgs(args) {
1448
1620
  commandName: "publish watch",
1449
1621
  });
1450
1622
  return {
1451
- command: "artifacts publish watch",
1623
+ command: "app publish watch",
1452
1624
  artifactId,
1453
1625
  jobId: options.jobId,
1454
1626
  baseUrl: options.baseUrl,
@@ -1460,7 +1632,7 @@ function parsePublishWatchArgs(args) {
1460
1632
  }
1461
1633
  function parseArtifactsListArgs(args) {
1462
1634
  if (args.includes("--help") || args.includes("-h")) {
1463
- return { command: "help", topic: "artifacts list" };
1635
+ return { command: "help", topic: "app list" };
1464
1636
  }
1465
1637
  let baseUrl = null;
1466
1638
  let flagToken = null;
@@ -1490,7 +1662,7 @@ function parseArtifactsListArgs(args) {
1490
1662
  throw new TenderCliUsageError(`Unknown app list option: ${arg}`);
1491
1663
  }
1492
1664
  return {
1493
- command: "artifacts list",
1665
+ command: "app list",
1494
1666
  baseUrl,
1495
1667
  flagToken,
1496
1668
  profileName,
@@ -1499,7 +1671,7 @@ function parseArtifactsListArgs(args) {
1499
1671
  }
1500
1672
  function parseArtifactsCreateArgs(args) {
1501
1673
  if (args.includes("--help") || args.includes("-h")) {
1502
- return { command: "help", topic: "artifacts create" };
1674
+ return { command: "help", topic: "app create" };
1503
1675
  }
1504
1676
  let name = "";
1505
1677
  let targetPackId = null;
@@ -1562,7 +1734,7 @@ function parseArtifactsCreateArgs(args) {
1562
1734
  throw new TenderCliUsageError("--name is required. Example: tender app create --name \"Exit Intent Widget\" --json");
1563
1735
  }
1564
1736
  return {
1565
- command: "artifacts create",
1737
+ command: "app create",
1566
1738
  name: name.trim(),
1567
1739
  targetPackId,
1568
1740
  targetPackVersion,
@@ -1574,7 +1746,7 @@ function parseArtifactsCreateArgs(args) {
1574
1746
  }
1575
1747
  function parseArtifactsUpdateArgs(args) {
1576
1748
  if (args.includes("--help") || args.includes("-h")) {
1577
- return { command: "help", topic: "artifacts update" };
1749
+ return { command: "help", topic: "app update" };
1578
1750
  }
1579
1751
  const artifactId = args[0];
1580
1752
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1621,7 +1793,7 @@ function parseArtifactsUpdateArgs(args) {
1621
1793
  throw new TenderCliUsageError("--name is required. Example: tender app update artifact_123 --name \"Sale Widget\" --json");
1622
1794
  }
1623
1795
  return {
1624
- command: "artifacts update",
1796
+ command: "app update",
1625
1797
  artifactId,
1626
1798
  name: name.trim(),
1627
1799
  baseUrl,
@@ -1632,7 +1804,7 @@ function parseArtifactsUpdateArgs(args) {
1632
1804
  }
1633
1805
  function parseArtifactsInitArgs(args) {
1634
1806
  if (args.includes("--help") || args.includes("-h")) {
1635
- return { command: "help", topic: "artifacts init" };
1807
+ return { command: "help", topic: "app init" };
1636
1808
  }
1637
1809
  const artifactId = args[0];
1638
1810
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1698,7 +1870,7 @@ function parseArtifactsInitArgs(args) {
1698
1870
  throw new TenderCliUsageError(`Unknown app init option: ${arg}`);
1699
1871
  }
1700
1872
  return {
1701
- command: "artifacts init",
1873
+ command: "app init",
1702
1874
  artifactId,
1703
1875
  dir,
1704
1876
  remoteName,
@@ -1713,7 +1885,7 @@ function parseArtifactsInitArgs(args) {
1713
1885
  }
1714
1886
  function parseContextFetchArgs(args) {
1715
1887
  if (args.includes("--help") || args.includes("-h")) {
1716
- return { command: "help", topic: "artifacts context fetch" };
1888
+ return { command: "help", topic: "app context fetch" };
1717
1889
  }
1718
1890
  const artifactId = args[0];
1719
1891
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1767,7 +1939,7 @@ function parseContextFetchArgs(args) {
1767
1939
  throw new TenderCliUsageError(`Unknown context fetch option: ${arg}`);
1768
1940
  }
1769
1941
  return {
1770
- command: "artifacts context fetch",
1942
+ command: "app context fetch",
1771
1943
  artifactId,
1772
1944
  dir,
1773
1945
  baseUrl,
@@ -1780,7 +1952,7 @@ function parseContextFetchArgs(args) {
1780
1952
  }
1781
1953
  function parseContextStatusArgs(args) {
1782
1954
  if (args.includes("--help") || args.includes("-h")) {
1783
- return { command: "help", topic: "artifacts context status" };
1955
+ return { command: "help", topic: "app context status" };
1784
1956
  }
1785
1957
  const artifactId = args[0];
1786
1958
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1824,7 +1996,7 @@ function parseContextStatusArgs(args) {
1824
1996
  throw new TenderCliUsageError(`Unknown context status option: ${arg}`);
1825
1997
  }
1826
1998
  return {
1827
- command: "artifacts context status",
1999
+ command: "app context status",
1828
2000
  artifactId,
1829
2001
  dir,
1830
2002
  baseUrl,
@@ -1835,7 +2007,7 @@ function parseContextStatusArgs(args) {
1835
2007
  }
1836
2008
  function parseContextRefreshArgs(args) {
1837
2009
  if (args.includes("--help") || args.includes("-h")) {
1838
- return { command: "help", topic: "artifacts context refresh" };
2010
+ return { command: "help", topic: "app context refresh" };
1839
2011
  }
1840
2012
  const artifactId = args[0];
1841
2013
  if (!artifactId || artifactId.startsWith("-")) {
@@ -1889,7 +2061,7 @@ function parseContextRefreshArgs(args) {
1889
2061
  throw new TenderCliUsageError(`Unknown context refresh option: ${arg}`);
1890
2062
  }
1891
2063
  return {
1892
- command: "artifacts context refresh",
2064
+ command: "app context refresh",
1893
2065
  artifactId,
1894
2066
  dir,
1895
2067
  baseUrl,
@@ -2020,7 +2192,7 @@ function parseAuthStatusArgs(args) {
2020
2192
  }
2021
2193
  function parseGenerateEnvTypesArgs(args) {
2022
2194
  if (args.includes("--help") || args.includes("-h")) {
2023
- return { command: "help", topic: "artifacts generate-env-types" };
2195
+ return { command: "help", topic: "app generate-env-types" };
2024
2196
  }
2025
2197
  let dir = ".";
2026
2198
  let json = false;
@@ -2042,7 +2214,7 @@ function parseGenerateEnvTypesArgs(args) {
2042
2214
  throw new TenderCliUsageError(`Unknown generate-env-types option: ${arg}`);
2043
2215
  }
2044
2216
  return {
2045
- command: "artifacts generate-env-types",
2217
+ command: "app generate-env-types",
2046
2218
  dir,
2047
2219
  json,
2048
2220
  };
@@ -2071,6 +2243,127 @@ function parseRequiredFlagValue(value, flag) {
2071
2243
  }
2072
2244
  return value;
2073
2245
  }
2246
+ function parseCapabilitiesArgs(args) {
2247
+ if (args.includes("--help") || args.includes("-h")) {
2248
+ return { command: "help", topic: "capabilities" };
2249
+ }
2250
+ let json = false;
2251
+ for (const arg of args) {
2252
+ if (arg === "--json") {
2253
+ json = true;
2254
+ continue;
2255
+ }
2256
+ throw new TenderCliUsageError(`Unknown capabilities option: ${arg}`);
2257
+ }
2258
+ return { command: "capabilities", json };
2259
+ }
2260
+ function parseBindingId(value) {
2261
+ if (!value || value.startsWith("-")) {
2262
+ throw new TenderCliUsageError("--id requires a binding id.");
2263
+ }
2264
+ if (!/^[a-z][a-z0-9-]*$/.test(value)) {
2265
+ throw new TenderCliUsageError("--id must start with a lowercase letter and contain only lowercase letters, numbers, and dashes. Example: shopify-api");
2266
+ }
2267
+ return value;
2268
+ }
2269
+ function parseAllowedHost(value) {
2270
+ if (!value || value.startsWith("-")) {
2271
+ throw new TenderCliUsageError("--host requires a hostname.");
2272
+ }
2273
+ if (value.length === 0 ||
2274
+ value.includes("/") ||
2275
+ value.includes(":") ||
2276
+ value.includes("?") ||
2277
+ value.includes("#") ||
2278
+ value.includes("*") ||
2279
+ value !== value.toLowerCase()) {
2280
+ throw new TenderCliUsageError("--host must be an explicit lowercase hostname without protocol, wildcard, path, query, or port. Example: api.example.com");
2281
+ }
2282
+ return value;
2283
+ }
2284
+ function parseEnvBindingName(value) {
2285
+ if (!value || value.startsWith("-")) {
2286
+ throw new TenderCliUsageError("--name requires an env binding name.");
2287
+ }
2288
+ if (!/^[A-Z][A-Z0-9_]*$/.test(value)) {
2289
+ throw new TenderCliUsageError("--name must be UPPER_SNAKE_CASE. Example: SHOPIFY_API");
2290
+ }
2291
+ return value;
2292
+ }
2293
+ function parseTypeName(value, flag) {
2294
+ if (!value || value.startsWith("-")) {
2295
+ throw new TenderCliUsageError(`${flag} requires a TypeScript type name.`);
2296
+ }
2297
+ if (!/^[A-Z][A-Za-z0-9]*$/.test(value)) {
2298
+ throw new TenderCliUsageError(`${flag} must be a PascalCase TypeScript type name. Example: ShopifyApiBinding`);
2299
+ }
2300
+ return value;
2301
+ }
2302
+ function parseBindingsOutboundArgs(args) {
2303
+ if (args.includes("--help") || args.includes("-h")) {
2304
+ return { command: "help", topic: "app bindings outbound" };
2305
+ }
2306
+ let id = null;
2307
+ let host = null;
2308
+ let name = null;
2309
+ let label = null;
2310
+ let interfaceName = null;
2311
+ let dryRun = false;
2312
+ let json = false;
2313
+ for (let index = 0; index < args.length; index += 1) {
2314
+ const arg = args[index];
2315
+ if (arg === "--json") {
2316
+ json = true;
2317
+ continue;
2318
+ }
2319
+ if (arg === "--dry-run") {
2320
+ dryRun = true;
2321
+ continue;
2322
+ }
2323
+ if (arg === "--id") {
2324
+ id = parseBindingId(args[index + 1]);
2325
+ index += 1;
2326
+ continue;
2327
+ }
2328
+ if (arg === "--host") {
2329
+ host = parseAllowedHost(args[index + 1]);
2330
+ index += 1;
2331
+ continue;
2332
+ }
2333
+ if (arg === "--name") {
2334
+ name = parseEnvBindingName(args[index + 1]);
2335
+ index += 1;
2336
+ continue;
2337
+ }
2338
+ if (arg === "--label") {
2339
+ label = parseRequiredFlagValue(args[index + 1], "--label");
2340
+ index += 1;
2341
+ continue;
2342
+ }
2343
+ if (arg === "--interface") {
2344
+ interfaceName = parseTypeName(args[index + 1], "--interface");
2345
+ index += 1;
2346
+ continue;
2347
+ }
2348
+ throw new TenderCliUsageError(`Unknown bindings outbound option: ${arg}`);
2349
+ }
2350
+ if (!id || !host) {
2351
+ throw new TenderCliUsageError("--id and --host are required. Example: tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json");
2352
+ }
2353
+ if (!dryRun) {
2354
+ throw new TenderCliUsageError("bindings outbound currently requires --dry-run. Example: tender app bindings outbound --id shopify --host admin.shopify.com --dry-run --json");
2355
+ }
2356
+ return {
2357
+ command: "app bindings outbound",
2358
+ id,
2359
+ host,
2360
+ name,
2361
+ label,
2362
+ interfaceName,
2363
+ dryRun,
2364
+ json,
2365
+ };
2366
+ }
2074
2367
  function parseAnalyticsCommonArgs(args, startIndex) {
2075
2368
  let baseUrl = null;
2076
2369
  let flagToken = null;
@@ -2104,7 +2397,7 @@ function parseAnalyticsCommonArgs(args, startIndex) {
2104
2397
  }
2105
2398
  function parseAnalyticsSummaryArgs(args) {
2106
2399
  if (args.includes("--help") || args.includes("-h")) {
2107
- return { command: "help", topic: "artifacts analytics summary" };
2400
+ return { command: "help", topic: "app analytics summary" };
2108
2401
  }
2109
2402
  const artifactId = args[0];
2110
2403
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2121,11 +2414,11 @@ function parseAnalyticsSummaryArgs(args) {
2121
2414
  }
2122
2415
  throw new TenderCliUsageError(`Unknown analytics summary option: ${arg}`);
2123
2416
  }
2124
- return { command: "artifacts analytics summary", artifactId, range, ...parsed };
2417
+ return { command: "app analytics summary", artifactId, range, ...parsed };
2125
2418
  }
2126
2419
  function parseAnalyticsQueryArgs(args) {
2127
2420
  if (args.includes("--help") || args.includes("-h")) {
2128
- return { command: "help", topic: "artifacts analytics query" };
2421
+ return { command: "help", topic: "app analytics query" };
2129
2422
  }
2130
2423
  const artifactId = args[0];
2131
2424
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2145,11 +2438,11 @@ function parseAnalyticsQueryArgs(args) {
2145
2438
  if (!specPath) {
2146
2439
  throw new TenderCliUsageError("--spec is required. Example: tender app analytics query artifact_123 --spec chart.json --json");
2147
2440
  }
2148
- return { command: "artifacts analytics query", artifactId, specPath, ...parsed };
2441
+ return { command: "app analytics query", artifactId, specPath, ...parsed };
2149
2442
  }
2150
2443
  function parseAnalyticsCapabilitiesArgs(args) {
2151
2444
  if (args.includes("--help") || args.includes("-h")) {
2152
- return { command: "help", topic: "artifacts analytics capabilities" };
2445
+ return { command: "help", topic: "app analytics capabilities" };
2153
2446
  }
2154
2447
  const artifactId = args[0];
2155
2448
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2172,7 +2465,7 @@ function parseAnalyticsCapabilitiesArgs(args) {
2172
2465
  throw new TenderCliUsageError(`Unknown analytics capabilities option: ${arg}`);
2173
2466
  }
2174
2467
  return {
2175
- command: "artifacts analytics capabilities",
2468
+ command: "app analytics capabilities",
2176
2469
  artifactId,
2177
2470
  includeCatalog,
2178
2471
  range,
@@ -2181,7 +2474,7 @@ function parseAnalyticsCapabilitiesArgs(args) {
2181
2474
  }
2182
2475
  function parseAnalyticsSuggestionsArgs(args) {
2183
2476
  if (args.includes("--help") || args.includes("-h")) {
2184
- return { command: "help", topic: "artifacts analytics suggestions" };
2477
+ return { command: "help", topic: "app analytics suggestions" };
2185
2478
  }
2186
2479
  const artifactId = args[0];
2187
2480
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2198,11 +2491,11 @@ function parseAnalyticsSuggestionsArgs(args) {
2198
2491
  }
2199
2492
  throw new TenderCliUsageError(`Unknown analytics suggestions option: ${arg}`);
2200
2493
  }
2201
- return { command: "artifacts analytics suggestions", artifactId, range, ...parsed };
2494
+ return { command: "app analytics suggestions", artifactId, range, ...parsed };
2202
2495
  }
2203
2496
  function parseAnalyticsDashboardsArgs(args) {
2204
2497
  if (args.includes("--help") || args.includes("-h")) {
2205
- return { command: "help", topic: "artifacts analytics dashboards" };
2498
+ return { command: "help", topic: "app analytics dashboards" };
2206
2499
  }
2207
2500
  const artifactId = args[0];
2208
2501
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2227,11 +2520,11 @@ function parseAnalyticsDashboardsArgs(args) {
2227
2520
  if (dryRun && !name) {
2228
2521
  throw new TenderCliUsageError("--dry-run is only valid with --create. Example: tender app analytics dashboards artifact_123 --create \"Agent dashboard\" --dry-run --json");
2229
2522
  }
2230
- return { command: "artifacts analytics dashboards", artifactId, name, dryRun, ...parsed };
2523
+ return { command: "app analytics dashboards", artifactId, name, dryRun, ...parsed };
2231
2524
  }
2232
2525
  function parseAnalyticsExportCatalogArgs(args) {
2233
2526
  if (args.includes("--help") || args.includes("-h")) {
2234
- return { command: "help", topic: "artifacts analytics export catalog" };
2527
+ return { command: "help", topic: "app analytics export catalog" };
2235
2528
  }
2236
2529
  const artifactId = args[0];
2237
2530
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2259,7 +2552,7 @@ function parseAnalyticsExportCatalogArgs(args) {
2259
2552
  throw new TenderCliUsageError(`Unknown analytics export catalog option: ${arg}`);
2260
2553
  }
2261
2554
  return {
2262
- command: "artifacts analytics export catalog",
2555
+ command: "app analytics export catalog",
2263
2556
  artifactId,
2264
2557
  format,
2265
2558
  range,
@@ -2268,7 +2561,7 @@ function parseAnalyticsExportCatalogArgs(args) {
2268
2561
  }
2269
2562
  function parseAnalyticsExportQueryArgs(args) {
2270
2563
  if (args.includes("--help") || args.includes("-h")) {
2271
- return { command: "help", topic: "artifacts analytics export query" };
2564
+ return { command: "help", topic: "app analytics export query" };
2272
2565
  }
2273
2566
  const artifactId = args[0];
2274
2567
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2299,7 +2592,7 @@ function parseAnalyticsExportQueryArgs(args) {
2299
2592
  throw new TenderCliUsageError("--spec is required. Example: tender app analytics export query artifact_123 --spec chart.json --format csv");
2300
2593
  }
2301
2594
  return {
2302
- command: "artifacts analytics export query",
2595
+ command: "app analytics export query",
2303
2596
  artifactId,
2304
2597
  specPath,
2305
2598
  format,
@@ -2308,7 +2601,7 @@ function parseAnalyticsExportQueryArgs(args) {
2308
2601
  }
2309
2602
  function parseAnalyticsChartsCreateArgs(args) {
2310
2603
  if (args.includes("--help") || args.includes("-h")) {
2311
- return { command: "help", topic: "artifacts analytics charts create" };
2604
+ return { command: "help", topic: "app analytics charts create" };
2312
2605
  }
2313
2606
  const artifactId = args[0];
2314
2607
  if (!artifactId || artifactId.startsWith("-")) {
@@ -2346,7 +2639,7 @@ function parseAnalyticsChartsCreateArgs(args) {
2346
2639
  throw new TenderCliUsageError("--dashboard, --title, and --spec are required. Example: tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title \"Signup funnel\" --spec chart.json --json");
2347
2640
  }
2348
2641
  return {
2349
- command: "artifacts analytics charts create",
2642
+ command: "app analytics charts create",
2350
2643
  artifactId,
2351
2644
  dashboardId,
2352
2645
  title,
@@ -2359,6 +2652,9 @@ function parseTenderArgs(args) {
2359
2652
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
2360
2653
  return { command: "help", topic: "root" };
2361
2654
  }
2655
+ if (args[0] === "capabilities") {
2656
+ return parseCapabilitiesArgs(args.slice(1));
2657
+ }
2362
2658
  if (args[0] === "auth") {
2363
2659
  if (args[1] === undefined || args[1] === "--help" || args[1] === "-h") {
2364
2660
  return { command: "help", topic: "auth" };
@@ -2374,15 +2670,14 @@ function parseTenderArgs(args) {
2374
2670
  if (args[0] === "apps") {
2375
2671
  throw new TenderCliUsageError("Unknown command: apps. Use `tender app ...` for Tender App workflows.");
2376
2672
  }
2377
- if (args[0] !== "artifacts" && args[0] !== "app") {
2673
+ if (args[0] !== "app") {
2378
2674
  throw new TenderCliUsageError(`Unknown command: ${args[0]}`);
2379
2675
  }
2380
2676
  const resourceArgs = normalizeAppArgs(args);
2381
- const resourceName = args[0] === "app" ? "app" : "artifacts";
2382
2677
  if (resourceArgs[1] === undefined ||
2383
2678
  resourceArgs[1] === "--help" ||
2384
2679
  resourceArgs[1] === "-h") {
2385
- return { command: "help", topic: "artifacts" };
2680
+ return { command: "help", topic: "app" };
2386
2681
  }
2387
2682
  if (resourceArgs[1] !== "doctor") {
2388
2683
  if (resourceArgs[1] === "list") {
@@ -2406,11 +2701,20 @@ function parseTenderArgs(args) {
2406
2701
  if (resourceArgs[1] === "context" && resourceArgs[2] === "refresh") {
2407
2702
  return parseContextRefreshArgs(resourceArgs.slice(3));
2408
2703
  }
2704
+ if (resourceArgs[1] === "bindings" && resourceArgs[2] === "outbound") {
2705
+ return parseBindingsOutboundArgs(resourceArgs.slice(3));
2706
+ }
2707
+ if (resourceArgs[1] === "bindings" &&
2708
+ (resourceArgs[2] === undefined ||
2709
+ resourceArgs[2] === "--help" ||
2710
+ resourceArgs[2] === "-h")) {
2711
+ return { command: "help", topic: "app bindings outbound" };
2712
+ }
2409
2713
  if (resourceArgs[1] === "analytics" &&
2410
2714
  (resourceArgs[2] === undefined ||
2411
2715
  resourceArgs[2] === "--help" ||
2412
2716
  resourceArgs[2] === "-h")) {
2413
- return { command: "help", topic: "artifacts analytics" };
2717
+ return { command: "help", topic: "app analytics" };
2414
2718
  }
2415
2719
  if (resourceArgs[1] === "analytics" && resourceArgs[2] === "summary") {
2416
2720
  return parseAnalyticsSummaryArgs(resourceArgs.slice(3));
@@ -2432,7 +2736,7 @@ function parseTenderArgs(args) {
2432
2736
  (resourceArgs[3] === undefined ||
2433
2737
  resourceArgs[3] === "--help" ||
2434
2738
  resourceArgs[3] === "-h")) {
2435
- return { command: "help", topic: "artifacts analytics export" };
2739
+ return { command: "help", topic: "app analytics export" };
2436
2740
  }
2437
2741
  if (resourceArgs[1] === "analytics" &&
2438
2742
  resourceArgs[2] === "export" &&
@@ -2453,7 +2757,7 @@ function parseTenderArgs(args) {
2453
2757
  (resourceArgs[2] === undefined ||
2454
2758
  resourceArgs[2] === "--help" ||
2455
2759
  resourceArgs[2] === "-h")) {
2456
- return { command: "help", topic: "artifacts" };
2760
+ return { command: "help", topic: "app" };
2457
2761
  }
2458
2762
  if (resourceArgs[1] === "git" && resourceArgs[2] === "remote") {
2459
2763
  return parseGitRemoteArgs(resourceArgs.slice(3));
@@ -2486,7 +2790,7 @@ function parseTenderArgs(args) {
2486
2790
  (resourceArgs[2] === undefined ||
2487
2791
  resourceArgs[2] === "--help" ||
2488
2792
  resourceArgs[2] === "-h")) {
2489
- return { command: "help", topic: "artifacts" };
2793
+ return { command: "help", topic: "app" };
2490
2794
  }
2491
2795
  if (resourceArgs[1] === "publish" && resourceArgs[2] === "status") {
2492
2796
  return parsePublishStatusArgs(resourceArgs.slice(3));
@@ -2501,13 +2805,13 @@ function parseTenderArgs(args) {
2501
2805
  (resourceArgs[2] === undefined ||
2502
2806
  resourceArgs[2] === "--help" ||
2503
2807
  resourceArgs[2] === "-h")) {
2504
- return { command: "help", topic: "artifacts" };
2808
+ return { command: "help", topic: "app" };
2505
2809
  }
2506
- throw new TenderCliUsageError(`Unknown ${resourceName} command: ${resourceArgs[1]}`);
2810
+ throw new TenderCliUsageError(`Unknown app command: ${resourceArgs[1]}`);
2507
2811
  }
2508
2812
  const rest = resourceArgs.slice(2);
2509
2813
  if (rest.includes("--help") || rest.includes("-h")) {
2510
- return { command: "help", topic: "artifacts doctor" };
2814
+ return { command: "help", topic: "app doctor" };
2511
2815
  }
2512
2816
  let dir = ".";
2513
2817
  let json = false;
@@ -2529,7 +2833,7 @@ function parseTenderArgs(args) {
2529
2833
  throw new TenderCliUsageError(`Unknown doctor option: ${arg}`);
2530
2834
  }
2531
2835
  return {
2532
- command: "artifacts doctor",
2836
+ command: "app doctor",
2533
2837
  dir,
2534
2838
  json,
2535
2839
  };
@@ -2545,9 +2849,9 @@ function normalizeAppArgs(args) {
2545
2849
  args[2] !== "watch" &&
2546
2850
  args[2] !== "--help" &&
2547
2851
  args[2] !== "-h") {
2548
- return ["artifacts", "preview", "rebuild", ...args.slice(2)];
2852
+ return ["app", "preview", "rebuild", ...args.slice(2)];
2549
2853
  }
2550
- return ["artifacts", ...args.slice(1)];
2854
+ return args;
2551
2855
  }
2552
2856
  function formatDoctorHuman(result) {
2553
2857
  if (result.diagnostics.length === 0) {
@@ -2659,6 +2963,98 @@ async function runGenerateEnvTypes(command, io) {
2659
2963
  }
2660
2964
  return 0;
2661
2965
  }
2966
+ function titleCaseBindingId(id) {
2967
+ return id
2968
+ .split("-")
2969
+ .filter(Boolean)
2970
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
2971
+ .join(" ");
2972
+ }
2973
+ function pascalCaseBindingId(id) {
2974
+ return id
2975
+ .split("-")
2976
+ .filter(Boolean)
2977
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
2978
+ .join("");
2979
+ }
2980
+ function envNameFromBindingId(id) {
2981
+ return id.toUpperCase().replaceAll("-", "_");
2982
+ }
2983
+ function createOutboundBindingShape(command) {
2984
+ const interfaceName = command.interfaceName ?? `${pascalCaseBindingId(command.id)}Binding`;
2985
+ const label = command.label ?? titleCaseBindingId(command.id);
2986
+ const name = command.name ?? envNameFromBindingId(command.id);
2987
+ const bindingDirectory = `bindings/${command.id}`;
2988
+ const bindingJson = {
2989
+ id: command.id,
2990
+ entry: "src/worker.ts",
2991
+ entrypoint: interfaceName,
2992
+ interface: interfaceName,
2993
+ permissions: ["outbound:http"],
2994
+ allowedHosts: [command.host],
2995
+ };
2996
+ const appJsonBinding = {
2997
+ id: command.id,
2998
+ label,
2999
+ name,
3000
+ source: bindingDirectory,
3001
+ interface: interfaceName,
3002
+ };
3003
+ const interfaceSource = `export interface ${interfaceName} {\n request(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n}\n`;
3004
+ const workerSource = `import { WorkerEntrypoint } from "cloudflare:workers";\n\nexport class ${interfaceName} extends WorkerEntrypoint {\n async request(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = typeof input === "string" || input instanceof URL ? new URL(input) : new URL(input.url);\n if (url.hostname !== "${command.host}") {\n throw new Error("Host is not allowed for this binding.");\n }\n return fetch(url, init);\n }\n}\n`;
3005
+ return {
3006
+ ok: true,
3007
+ command: command.command,
3008
+ dryRun: command.dryRun,
3009
+ binding: {
3010
+ id: command.id,
3011
+ name,
3012
+ label,
3013
+ interface: interfaceName,
3014
+ allowedHosts: [command.host],
3015
+ permissions: ["outbound:http"],
3016
+ },
3017
+ appJsonBinding,
3018
+ files: [
3019
+ {
3020
+ path: `${bindingDirectory}/binding.json`,
3021
+ content: `${JSON.stringify(bindingJson, null, 2)}\n`,
3022
+ },
3023
+ {
3024
+ path: `${bindingDirectory}/interface.d.ts`,
3025
+ content: interfaceSource,
3026
+ },
3027
+ {
3028
+ path: `${bindingDirectory}/src/worker.ts`,
3029
+ content: workerSource,
3030
+ },
3031
+ ],
3032
+ next: [
3033
+ "Add appJsonBinding to app.json bindings[].",
3034
+ `Call this binding from src/server.ts through env.${name}; do not fetch third-party URLs directly from src/server.ts.`,
3035
+ "Run tender app generate-env-types --dir . --json.",
3036
+ "Run tender app doctor --dir . --json.",
3037
+ ],
3038
+ };
3039
+ }
3040
+ function runBindingsOutbound(command, io) {
3041
+ const payload = createOutboundBindingShape(command);
3042
+ if (command.json) {
3043
+ io.stdout(JSON.stringify(payload, null, 2));
3044
+ }
3045
+ else {
3046
+ io.stdout([
3047
+ `Outbound binding dry run: ${payload.binding.id}`,
3048
+ `app.json binding name: ${payload.binding.name}`,
3049
+ `allowed host: ${payload.binding.allowedHosts.join(", ")}`,
3050
+ "files:",
3051
+ ...payload.files.map((file) => ` ${file.path}`),
3052
+ "next:",
3053
+ ...payload.next.map((step) => ` ${step}`),
3054
+ ].join("\n"));
3055
+ }
3056
+ return 0;
3057
+ }
2662
3058
  async function parseJsonResponse(response) {
2663
3059
  return (await response.json().catch(() => null));
2664
3060
  }
@@ -4972,7 +5368,10 @@ export async function runTenderCli(args, io = {
4972
5368
  try {
4973
5369
  const command = parseTenderArgs(args);
4974
5370
  if (command.command === "help") {
4975
- if (command.topic === "auth login") {
5371
+ if (command.topic === "capabilities") {
5372
+ io.stdout(capabilitiesHelp());
5373
+ }
5374
+ else if (command.topic === "auth login") {
4976
5375
  io.stdout(authLoginHelp());
4977
5376
  }
4978
5377
  else if (command.topic === "auth status") {
@@ -4981,189 +5380,198 @@ export async function runTenderCli(args, io = {
4981
5380
  else if (command.topic === "auth") {
4982
5381
  io.stdout(authHelp());
4983
5382
  }
4984
- else if (command.topic === "artifacts create") {
5383
+ else if (command.topic === "app create") {
4985
5384
  io.stdout(artifactsCreateHelp());
4986
5385
  }
4987
- else if (command.topic === "artifacts update") {
5386
+ else if (command.topic === "app update") {
4988
5387
  io.stdout(artifactsUpdateHelp());
4989
5388
  }
4990
- else if (command.topic === "artifacts init") {
5389
+ else if (command.topic === "app init") {
4991
5390
  io.stdout(artifactsInitHelp());
4992
5391
  }
4993
- else if (command.topic === "artifacts doctor") {
5392
+ else if (command.topic === "app doctor") {
4994
5393
  io.stdout(doctorHelp());
4995
5394
  }
4996
- else if (command.topic === "artifacts generate-env-types") {
5395
+ else if (command.topic === "app generate-env-types") {
4997
5396
  io.stdout(generateEnvTypesHelp());
4998
5397
  }
4999
- else if (command.topic === "artifacts list") {
5398
+ else if (command.topic === "app list") {
5000
5399
  io.stdout(artifactsListHelp());
5001
5400
  }
5002
- else if (command.topic === "artifacts context fetch") {
5401
+ else if (command.topic === "app context fetch") {
5003
5402
  io.stdout(artifactsContextFetchHelp());
5004
5403
  }
5005
- else if (command.topic === "artifacts context status") {
5404
+ else if (command.topic === "app context status") {
5006
5405
  io.stdout(artifactsContextStatusHelp());
5007
5406
  }
5008
- else if (command.topic === "artifacts context refresh") {
5407
+ else if (command.topic === "app context refresh") {
5009
5408
  io.stdout(artifactsContextRefreshHelp());
5010
5409
  }
5011
- else if (command.topic === "artifacts git setup") {
5410
+ else if (command.topic === "app bindings outbound") {
5411
+ io.stdout(bindingsOutboundHelp());
5412
+ }
5413
+ else if (command.topic === "app git setup") {
5012
5414
  io.stdout(gitSetupHelp());
5013
5415
  }
5014
- else if (command.topic === "artifacts git credential") {
5416
+ else if (command.topic === "app git credential") {
5015
5417
  io.stdout(gitCredentialHelp());
5016
5418
  }
5017
- else if (command.topic === "artifacts git remote") {
5419
+ else if (command.topic === "app git remote") {
5018
5420
  io.stdout(gitRemoteHelp());
5019
5421
  }
5020
- else if (command.topic === "artifacts validate") {
5422
+ else if (command.topic === "app validate") {
5021
5423
  io.stdout(validateHelp());
5022
5424
  }
5023
- else if (command.topic === "artifacts build") {
5425
+ else if (command.topic === "app build") {
5024
5426
  io.stdout(buildHelp());
5025
5427
  }
5026
- else if (command.topic === "artifacts preview rebuild") {
5428
+ else if (command.topic === "app preview rebuild") {
5027
5429
  io.stdout(previewRebuildHelp());
5028
5430
  }
5029
- else if (command.topic === "artifacts preview status") {
5431
+ else if (command.topic === "app preview status") {
5030
5432
  io.stdout(previewStatusHelp());
5031
5433
  }
5032
- else if (command.topic === "artifacts preview watch") {
5434
+ else if (command.topic === "app preview watch") {
5033
5435
  io.stdout(previewWatchHelp());
5034
5436
  }
5035
- else if (command.topic === "artifacts publish") {
5437
+ else if (command.topic === "app publish") {
5036
5438
  io.stdout(publishHelp());
5037
5439
  }
5038
- else if (command.topic === "artifacts publish status") {
5440
+ else if (command.topic === "app publish status") {
5039
5441
  io.stdout(publishStatusHelp());
5040
5442
  }
5041
- else if (command.topic === "artifacts publish watch") {
5443
+ else if (command.topic === "app publish watch") {
5042
5444
  io.stdout(publishWatchHelp());
5043
5445
  }
5044
- else if (command.topic === "artifacts analytics") {
5446
+ else if (command.topic === "app analytics") {
5045
5447
  io.stdout(analyticsHelp());
5046
5448
  }
5047
- else if (command.topic === "artifacts analytics summary") {
5449
+ else if (command.topic === "app analytics summary") {
5048
5450
  io.stdout(analyticsSummaryHelp());
5049
5451
  }
5050
- else if (command.topic === "artifacts analytics query") {
5452
+ else if (command.topic === "app analytics query") {
5051
5453
  io.stdout(analyticsQueryHelp());
5052
5454
  }
5053
- else if (command.topic === "artifacts analytics capabilities") {
5455
+ else if (command.topic === "app analytics capabilities") {
5054
5456
  io.stdout(analyticsCapabilitiesHelp());
5055
5457
  }
5056
- else if (command.topic === "artifacts analytics suggestions") {
5458
+ else if (command.topic === "app analytics suggestions") {
5057
5459
  io.stdout(analyticsSuggestionsHelp());
5058
5460
  }
5059
- else if (command.topic === "artifacts analytics dashboards") {
5461
+ else if (command.topic === "app analytics dashboards") {
5060
5462
  io.stdout(analyticsDashboardsHelp());
5061
5463
  }
5062
- else if (command.topic === "artifacts analytics export") {
5464
+ else if (command.topic === "app analytics export") {
5063
5465
  io.stdout(analyticsExportHelp());
5064
5466
  }
5065
- else if (command.topic === "artifacts analytics export catalog") {
5467
+ else if (command.topic === "app analytics export catalog") {
5066
5468
  io.stdout(analyticsExportCatalogHelp());
5067
5469
  }
5068
- else if (command.topic === "artifacts analytics export query") {
5470
+ else if (command.topic === "app analytics export query") {
5069
5471
  io.stdout(analyticsExportQueryHelp());
5070
5472
  }
5071
- else if (command.topic === "artifacts analytics charts create") {
5473
+ else if (command.topic === "app analytics charts create") {
5072
5474
  io.stdout(analyticsChartsCreateHelp());
5073
5475
  }
5074
- else if (command.topic === "artifacts") {
5075
- io.stdout(artifactsHelp());
5476
+ else if (command.topic === "app") {
5477
+ io.stdout(appHelp());
5076
5478
  }
5077
5479
  else {
5078
5480
  io.stdout(rootHelp());
5079
5481
  }
5080
5482
  return 0;
5081
5483
  }
5484
+ if (command.command === "capabilities") {
5485
+ return runCapabilities(command, io);
5486
+ }
5082
5487
  if (command.command === "auth login") {
5083
5488
  return await runAuthLogin(command, io, runtime);
5084
5489
  }
5085
5490
  if (command.command === "auth status") {
5086
5491
  return await runAuthStatus(command, io, runtime);
5087
5492
  }
5088
- if (command.command === "artifacts list") {
5493
+ if (command.command === "app list") {
5089
5494
  return await runArtifactsList(command, io, runtime);
5090
5495
  }
5091
- if (command.command === "artifacts create") {
5496
+ if (command.command === "app create") {
5092
5497
  return await runArtifactsCreate(command, io, runtime);
5093
5498
  }
5094
- if (command.command === "artifacts update") {
5499
+ if (command.command === "app update") {
5095
5500
  return await runArtifactsUpdate(command, io, runtime);
5096
5501
  }
5097
- if (command.command === "artifacts init") {
5502
+ if (command.command === "app init") {
5098
5503
  return await runArtifactsInit(command, io, runtime);
5099
5504
  }
5100
- if (command.command === "artifacts generate-env-types") {
5505
+ if (command.command === "app generate-env-types") {
5101
5506
  return await runGenerateEnvTypes(command, io);
5102
5507
  }
5103
- if (command.command === "artifacts context fetch") {
5508
+ if (command.command === "app context fetch") {
5104
5509
  return await runContextFetch(command, io, runtime);
5105
5510
  }
5106
- if (command.command === "artifacts context status") {
5511
+ if (command.command === "app context status") {
5107
5512
  return await runContextStatus(command, io, runtime);
5108
5513
  }
5109
- if (command.command === "artifacts context refresh") {
5514
+ if (command.command === "app context refresh") {
5110
5515
  return await runContextFetch(command, io, runtime);
5111
5516
  }
5112
- if (command.command === "artifacts git setup") {
5517
+ if (command.command === "app bindings outbound") {
5518
+ return runBindingsOutbound(command, io);
5519
+ }
5520
+ if (command.command === "app git setup") {
5113
5521
  return await runGitSetup(command, io, runtime);
5114
5522
  }
5115
- if (command.command === "artifacts git credential") {
5523
+ if (command.command === "app git credential") {
5116
5524
  return await runGitCredential(command, io, runtime);
5117
5525
  }
5118
- if (command.command === "artifacts validate") {
5526
+ if (command.command === "app validate") {
5119
5527
  return await runValidate(command, io, runtime);
5120
5528
  }
5121
- if (command.command === "artifacts build") {
5529
+ if (command.command === "app build") {
5122
5530
  return await runBuild(command, io, runtime);
5123
5531
  }
5124
- if (command.command === "artifacts preview rebuild") {
5532
+ if (command.command === "app preview rebuild") {
5125
5533
  return await runPreviewRebuild(command, io, runtime);
5126
5534
  }
5127
- if (command.command === "artifacts preview status") {
5535
+ if (command.command === "app preview status") {
5128
5536
  return await runPreviewStatus(command, io, runtime);
5129
5537
  }
5130
- if (command.command === "artifacts preview watch") {
5538
+ if (command.command === "app preview watch") {
5131
5539
  return await runPreviewWatch(command, io, runtime);
5132
5540
  }
5133
- if (command.command === "artifacts publish") {
5541
+ if (command.command === "app publish") {
5134
5542
  return await runPublish(command, io, runtime);
5135
5543
  }
5136
- if (command.command === "artifacts publish status") {
5544
+ if (command.command === "app publish status") {
5137
5545
  return await runPublishStatus(command, io, runtime);
5138
5546
  }
5139
- if (command.command === "artifacts publish watch") {
5547
+ if (command.command === "app publish watch") {
5140
5548
  return await runPublishWatch(command, io, runtime);
5141
5549
  }
5142
- if (command.command === "artifacts analytics summary") {
5550
+ if (command.command === "app analytics summary") {
5143
5551
  return await runAnalyticsSummary(command, io, runtime);
5144
5552
  }
5145
- if (command.command === "artifacts analytics query") {
5553
+ if (command.command === "app analytics query") {
5146
5554
  return await runAnalyticsQuery(command, io, runtime);
5147
5555
  }
5148
- if (command.command === "artifacts analytics capabilities") {
5556
+ if (command.command === "app analytics capabilities") {
5149
5557
  return await runAnalyticsCapabilities(command, io, runtime);
5150
5558
  }
5151
- if (command.command === "artifacts analytics suggestions") {
5559
+ if (command.command === "app analytics suggestions") {
5152
5560
  return await runAnalyticsSuggestions(command, io, runtime);
5153
5561
  }
5154
- if (command.command === "artifacts analytics dashboards") {
5562
+ if (command.command === "app analytics dashboards") {
5155
5563
  return await runAnalyticsDashboards(command, io, runtime);
5156
5564
  }
5157
- if (command.command === "artifacts analytics export catalog") {
5565
+ if (command.command === "app analytics export catalog") {
5158
5566
  return await runAnalyticsExportCatalog(command, io, runtime);
5159
5567
  }
5160
- if (command.command === "artifacts analytics export query") {
5568
+ if (command.command === "app analytics export query") {
5161
5569
  return await runAnalyticsExportQuery(command, io, runtime);
5162
5570
  }
5163
- if (command.command === "artifacts analytics charts create") {
5571
+ if (command.command === "app analytics charts create") {
5164
5572
  return await runAnalyticsChartsCreate(command, io, runtime);
5165
5573
  }
5166
- if (command.command === "artifacts git remote") {
5574
+ if (command.command === "app git remote") {
5167
5575
  return await runGitRemote(command, io, runtime);
5168
5576
  }
5169
5577
  return await runDoctor(command, io);
@@ -5176,7 +5584,7 @@ export async function runTenderCli(args, io = {
5176
5584
  }
5177
5585
  const currentFile = fileURLToPath(import.meta.url);
5178
5586
  function shouldReadEntrypointStdin(args) {
5179
- return ((args[0] === "artifacts" || args[0] === "app") &&
5587
+ return (args[0] === "app" &&
5180
5588
  ((args[1] === "git" && args[2] === "credential") ||
5181
5589
  (args[1] === "analytics" && args.includes("--spec") && args.includes("-"))));
5182
5590
  }