@tenderprompt/cli 0.1.2 → 0.1.4

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 +22 -17
  2. package/dist/index.js +1264 -234
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
- import { validateTenderApp, } from "@tenderprompt/tender-app-validator";
7
+ import { generateTenderAppEnvTypes, validateTenderApp, } from "@tenderprompt/tender-app-validator";
8
8
  import { collectTenderAppFiles } from "./local-files.js";
9
9
  class TenderCliUsageError extends Error {
10
10
  constructor(message) {
@@ -23,58 +23,73 @@ Commands:
23
23
  tender auth login --device
24
24
  Authorize this machine with a browser-approved device flow
25
25
  tender auth status Show whether a Tender API token is available
26
- tender artifacts list List artifacts visible to the current token
27
- tender artifacts create --name <name>
28
- Create a new artifact in the current account
29
- tender artifacts update <artifact-id> --name <name>
30
- Update artifact metadata
31
- tender artifacts init <artifact-id>
26
+ tender app list List Tender App records visible to the current token
27
+ tender app create --name <name>
28
+ Create a new Tender App in the current account
29
+ tender app update <app-id> --name <name>
30
+ Update app metadata
31
+ tender app init <app-id>
32
32
  Bootstrap a checkout for local agent work
33
- tender artifacts validate <artifact-id>
34
- Validate the server-side artifact workspace
35
- tender artifacts build <artifact-id>
36
- Build the current artifact workspace
37
- tender artifacts preview rebuild <artifact-id>
33
+ tender app validate <app-id>
34
+ Validate the server-side app workspace
35
+ tender app build <app-id>
36
+ Build the current app workspace
37
+ tender app preview <app-id>
38
38
  Rebuild the preview from the current workspace
39
- tender artifacts preview status <artifact-id>
39
+ tender app preview status <app-id>
40
40
  Show the latest or commit-pinned preview job
41
- tender artifacts preview watch <artifact-id>
41
+ tender app preview watch <app-id>
42
42
  Stream or print lifecycle events for a preview job
43
- tender artifacts publish <artifact-id>
43
+ tender app publish <app-id>
44
44
  Publish after explicit confirmation
45
- tender artifacts publish status <artifact-id>
45
+ tender app publish status <app-id>
46
46
  Show publish job status by job id
47
- tender artifacts publish watch <artifact-id>
47
+ tender app publish watch <app-id>
48
48
  Stream or print lifecycle events for a publish job
49
- tender artifacts context fetch <artifact-id>
49
+ tender app analytics summary <app-id>
50
+ Read artifact analytics totals and trend points
51
+ tender app analytics query <app-id> --spec <file|->
52
+ Run a server-validated chart spec
53
+ tender app analytics suggestions <app-id>
54
+ Generate useful starter chart suggestions
55
+ tender app context fetch <app-id>
50
56
  Fetch managed agent context into a checkout
51
- tender artifacts context status <artifact-id>
57
+ tender app context status <app-id>
52
58
  Report whether managed context is stale
53
- tender artifacts context refresh <artifact-id>
59
+ tender app context refresh <app-id>
54
60
  Refresh managed context files
55
- tender artifacts git setup <artifact-id>
56
- Configure a checkout to push to the artifact remote
57
- tender artifacts doctor Validate a local Tender App checkout
61
+ tender app git setup <app-id>
62
+ Configure a checkout to push to the app remote
63
+ tender app doctor Validate a local Tender App checkout
64
+ tender app generate-env-types
65
+ Regenerate src/env.d.ts from app.json and bindings
66
+
67
+ Compatibility:
68
+ tender artifacts ... Legacy alias for Tender App commands
58
69
 
59
70
  Examples:
60
71
  tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
61
72
  tender auth status --json
62
- tender artifacts list --json
63
- tender artifacts create --name "Exit Intent Widget" --json
64
- tender artifacts update artifact_123 --name "Sale Widget" --json
65
- tender artifacts init artifact_123 --dir ./widget --json
66
- tender artifacts validate artifact_123 --json
67
- tender artifacts build artifact_123 --commit $(git rev-parse HEAD) --json
68
- tender artifacts preview rebuild artifact_123 --commit $(git rev-parse HEAD) --stream --json
69
- tender artifacts preview status artifact_123 --commit $(git rev-parse HEAD) --json
70
- tender artifacts preview watch artifact_123 --job job_123 --stream --json
71
- tender artifacts publish artifact_123 --commit $(git rev-parse HEAD) --confirm publish --stream --json
72
- tender artifacts context fetch artifact_123 --dir ./widget --dry-run --json
73
- tender artifacts context status artifact_123 --dir ./widget --json
74
- tender artifacts context refresh artifact_123 --dir ./widget --dry-run --json
75
- tender artifacts git setup artifact_123 --dir ./widget --json
76
- tender artifacts doctor --dir ./widget
77
- tender artifacts doctor --dir ./widget --json`;
73
+ tender app list --json
74
+ tender app create --name "Exit Intent Widget" --json
75
+ tender app update artifact_123 --name "Sale Widget" --json
76
+ tender app init artifact_123 --dir ./widget --json
77
+ tender app validate artifact_123 --json
78
+ tender app build artifact_123 --commit $(git rev-parse HEAD) --json
79
+ tender app preview artifact_123 --commit $(git rev-parse HEAD) --stream --json
80
+ tender app preview status artifact_123 --commit $(git rev-parse HEAD) --json
81
+ tender app preview watch artifact_123 --job job_123 --stream --json
82
+ tender app publish artifact_123 --commit $(git rev-parse HEAD) --confirm publish --stream --json
83
+ tender app analytics summary artifact_123 --range 30d --json
84
+ tender app analytics query artifact_123 --spec chart.json --json
85
+ tender app analytics suggestions artifact_123 --range 30d --json
86
+ tender app context fetch artifact_123 --dir ./widget --dry-run --json
87
+ tender app context status artifact_123 --dir ./widget --json
88
+ tender app context refresh artifact_123 --dir ./widget --dry-run --json
89
+ tender app git setup artifact_123 --dir ./widget --json
90
+ tender app doctor --dir ./widget
91
+ tender app generate-env-types --dir ./widget --json
92
+ tender app doctor --dir ./widget --json`;
78
93
  }
79
94
  function authHelp() {
80
95
  return `Usage: tender auth <command> [options]
@@ -117,68 +132,187 @@ Examples:
117
132
  tender auth status
118
133
  tender auth status --profile publish --json`;
119
134
  }
120
- function artifactsHelp() {
121
- return `Usage: tender artifacts <command> [options]
135
+ function appHelp() {
136
+ return `Usage: tender app <command> [options]
122
137
 
123
138
  Commands:
124
- tender artifacts list List artifacts visible to the current token
125
- tender artifacts create --name <name>
126
- Create a new artifact in the current account
127
- tender artifacts update <artifact-id> --name <name>
128
- Update artifact metadata
129
- tender artifacts init <artifact-id>
139
+ tender app list List Tender App records visible to the current token
140
+ tender app create --name <name>
141
+ Create a new Tender App in the current account
142
+ tender app update <app-id> --name <name>
143
+ Update app metadata
144
+ tender app init <app-id>
130
145
  Bootstrap context files and the tender Git remote
131
- tender artifacts validate <artifact-id>
132
- Validate the server-side artifact workspace
133
- tender artifacts build <artifact-id>
134
- Build the current artifact workspace
135
- tender artifacts preview rebuild <artifact-id>
146
+ tender app validate <app-id>
147
+ Validate the server-side app workspace
148
+ tender app build <app-id>
149
+ Build the current app workspace
150
+ tender app preview <app-id>
136
151
  Rebuild the preview and optionally stream lifecycle events
137
- tender artifacts preview status <artifact-id>
152
+ tender app preview status <app-id>
138
153
  Show preview job status by latest, commit, or job id
139
- tender artifacts preview watch <artifact-id>
154
+ tender app preview watch <app-id>
140
155
  Replay lifecycle events by latest, commit, or job id
141
- tender artifacts publish <artifact-id>
156
+ tender app publish <app-id>
142
157
  Publish after dry-run or explicit confirmation
143
- tender artifacts publish status <artifact-id>
158
+ tender app publish status <app-id>
144
159
  Show publish job status by job id
145
- tender artifacts publish watch <artifact-id>
160
+ tender app publish watch <app-id>
146
161
  Replay lifecycle events for a publish job id
147
- tender artifacts context fetch <artifact-id>
162
+ tender app analytics summary <app-id>
163
+ Read artifact analytics totals and trend points
164
+ tender app analytics query <app-id> --spec <file|->
165
+ Run a server-validated chart spec
166
+ tender app analytics suggestions <app-id>
167
+ Generate useful starter chart suggestions
168
+ tender app analytics dashboards <app-id>
169
+ List or create saved dashboards
170
+ tender app analytics charts create <app-id>
171
+ Create a saved chart from a chart spec
172
+ tender app context fetch <app-id>
148
173
  Fetch AGENTS.md, skills, and Tender App scaffold files
149
- tender artifacts context status <artifact-id>
174
+ tender app context status <app-id>
150
175
  Show managed context freshness for a checkout
151
- tender artifacts context refresh <artifact-id>
176
+ tender app context refresh <app-id>
152
177
  Refresh managed context files in a checkout
153
- tender artifacts git setup <artifact-id>
178
+ tender app git setup <app-id>
154
179
  Configure the tender Git remote and credential helper
155
- tender artifacts doctor Validate local context, TypeScript scaffold, and Tender App rules
156
- tender artifacts git remote <artifact-id>
180
+ tender app doctor Validate local context, TypeScript scaffold, and Tender App rules
181
+ tender app generate-env-types
182
+ Regenerate src/env.d.ts from app.json and bindings
183
+ tender app git remote <app-id>
157
184
  Show Tender-hosted Git remote metadata
158
185
 
159
186
  Examples:
160
- tender artifacts list --json
161
- tender artifacts create --name "Exit Intent Widget" --json
162
- tender artifacts update artifact_123 --name "Sale Widget" --json
163
- tender artifacts init artifact_123 --dir ./widget --json
164
- tender artifacts validate artifact_123 --json
165
- tender artifacts build artifact_123 --commit $(git rev-parse HEAD) --json
166
- tender artifacts preview rebuild artifact_123 --commit $(git rev-parse HEAD) --stream --json
167
- tender artifacts preview status artifact_123 --commit $(git rev-parse HEAD) --json
168
- tender artifacts preview watch artifact_123 --job job_123 --stream --json
169
- tender artifacts publish artifact_123 --dry-run --json
170
- tender artifacts publish status artifact_123 --job job_123 --json
171
- tender artifacts publish watch artifact_123 --job job_123 --stream --json
172
- tender artifacts context fetch artifact_123 --dir ./widget --dry-run --json
173
- tender artifacts context status artifact_123 --dir ./widget --json
174
- tender artifacts context refresh artifact_123 --dir ./widget --dry-run --json
175
- tender artifacts git setup artifact_123 --dir ./widget --json
176
- tender artifacts doctor --dir ./widget
177
- tender artifacts doctor --json
178
- tender artifacts git remote artifact_123 --ttl 7d --json`;
187
+ tender app list --json
188
+ tender app create --name "Exit Intent Widget" --json
189
+ tender app update artifact_123 --name "Sale Widget" --json
190
+ tender app init artifact_123 --dir ./widget --json
191
+ tender app validate artifact_123 --json
192
+ tender app build artifact_123 --commit $(git rev-parse HEAD) --json
193
+ tender app preview artifact_123 --commit $(git rev-parse HEAD) --stream --json
194
+ tender app preview status artifact_123 --commit $(git rev-parse HEAD) --json
195
+ tender app preview watch artifact_123 --job job_123 --stream --json
196
+ tender app publish artifact_123 --dry-run --json
197
+ tender app publish status artifact_123 --job job_123 --json
198
+ tender app publish watch artifact_123 --job job_123 --stream --json
199
+ tender app analytics summary artifact_123 --range 30d --json
200
+ tender app analytics query artifact_123 --spec chart.json --json
201
+ tender app analytics suggestions artifact_123 --range 30d --json
202
+ tender app analytics dashboards artifact_123 --json
203
+ tender app analytics dashboards artifact_123 --create "Agent dashboard" --json
204
+ tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec funnel.json --json
205
+ tender app context fetch artifact_123 --dir ./widget --dry-run --json
206
+ tender app context status artifact_123 --dir ./widget --json
207
+ tender app context refresh artifact_123 --dir ./widget --dry-run --json
208
+ tender app git setup artifact_123 --dir ./widget --json
209
+ tender app doctor --dir ./widget
210
+ tender app generate-env-types --dir ./widget --json
211
+ tender app doctor --json
212
+ tender app git remote artifact_123 --ttl 7d --json`;
213
+ }
214
+ function artifactsHelp() {
215
+ return `${appHelp()}
216
+
217
+ Legacy alias:
218
+ tender artifacts ... continues to work for existing automation. Prefer tender app ... for new workflows.`;
219
+ }
220
+ function analyticsHelp() {
221
+ return `Usage: tender app analytics <command> <app-id> [options]
222
+
223
+ Start here for agents:
224
+ tender app analytics capabilities <app-id> --include-catalog --range 30d --json
225
+
226
+ Commands:
227
+ tender app analytics summary <app-id> Read totals and trend points
228
+ tender app analytics query <app-id> Run one chart spec
229
+ tender app analytics capabilities <app-id> Describe agent-safe analytics capabilities
230
+ tender app analytics suggestions <app-id> Generate starter chart suggestions
231
+ tender app analytics dashboards <app-id> List or create dashboards
232
+ tender app analytics export <kind> <app-id> Export catalog metadata or query rows
233
+ tender app analytics charts create <app-id> Create a saved chart
234
+
235
+ Examples:
236
+ tender app analytics summary artifact_123 --range 30d --json
237
+ tender app analytics capabilities artifact_123 --include-catalog --json
238
+ tender app analytics query artifact_123 --spec chart.json --json
239
+ tender app analytics query artifact_123 --spec - --json < chart.json
240
+ tender app analytics export catalog artifact_123 --range 30d --json
241
+ tender app analytics export query artifact_123 --spec chart.json --format csv
242
+ tender app analytics suggestions artifact_123 --range 2026-04-01..2026-04-30 --json
243
+ tender app analytics dashboards artifact_123 --create "Agent dashboard" --json
244
+ tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec funnel.json --json`;
245
+ }
246
+ function analyticsSummaryHelp() {
247
+ return `Usage: tender app analytics summary <app-id> [--range <7d|30d|90d|YYYY-MM-DD..YYYY-MM-DD>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
248
+
249
+ Examples:
250
+ tender app analytics summary artifact_123 --range 30d --json
251
+ tender app analytics summary artifact_123 --range 2026-04-01..2026-04-30 --json`;
252
+ }
253
+ function analyticsQueryHelp() {
254
+ return `Usage: tender app analytics query <app-id> --spec <file|-> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
255
+
256
+ Examples:
257
+ tender app analytics query artifact_123 --spec chart.json --json
258
+ tender app analytics query artifact_123 --spec - --json < chart.json`;
259
+ }
260
+ function analyticsCapabilitiesHelp() {
261
+ return `Usage: tender app analytics capabilities <app-id> [--include-catalog] [--range <7d|30d|90d|YYYY-MM-DD..YYYY-MM-DD>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
262
+
263
+ Use this as the self-documenting entrypoint for coding agents. With --include-catalog,
264
+ the response includes observed events, paths, rough property types, current saved
265
+ dashboards, supported chart spec shapes, retention limits, and safe next commands.
266
+
267
+ Examples:
268
+ tender app analytics capabilities artifact_123 --json
269
+ tender app analytics capabilities artifact_123 --include-catalog --range 30d --json`;
270
+ }
271
+ function analyticsExportHelp() {
272
+ return `Usage: tender app analytics export <catalog|query> <app-id> [options]
273
+
274
+ Examples:
275
+ tender app analytics export catalog artifact_123 --range 30d --json
276
+ tender app analytics export query artifact_123 --spec chart.json --format json
277
+ tender app analytics export query artifact_123 --spec chart.json --format csv`;
278
+ }
279
+ function analyticsExportCatalogHelp() {
280
+ return `Usage: tender app analytics export catalog <app-id> [--range <7d|30d|90d|YYYY-MM-DD..YYYY-MM-DD>] [--format json] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
281
+
282
+ Examples:
283
+ tender app analytics export catalog artifact_123 --range 30d --json`;
284
+ }
285
+ function analyticsExportQueryHelp() {
286
+ return `Usage: tender app analytics export query <app-id> --spec <file|-> [--format <json|csv>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
287
+
288
+ Examples:
289
+ tender app analytics export query artifact_123 --spec chart.json --format json
290
+ tender app analytics export query artifact_123 --spec chart.json --format csv
291
+ tender app analytics export query artifact_123 --spec - --format csv < chart.json`;
292
+ }
293
+ function analyticsSuggestionsHelp() {
294
+ return `Usage: tender app analytics suggestions <app-id> [--range <7d|30d|90d|YYYY-MM-DD..YYYY-MM-DD>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
295
+
296
+ Examples:
297
+ tender app analytics suggestions artifact_123 --range 30d --json`;
298
+ }
299
+ function analyticsDashboardsHelp() {
300
+ return `Usage: tender app analytics dashboards <app-id> [--create <name>] [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
301
+
302
+ Examples:
303
+ tender app analytics dashboards artifact_123 --json
304
+ tender app analytics dashboards artifact_123 --create "Agent dashboard" --dry-run --json
305
+ tender app analytics dashboards artifact_123 --create "Agent dashboard" --json`;
306
+ }
307
+ function analyticsChartsCreateHelp() {
308
+ return `Usage: tender app analytics charts create <app-id> --dashboard <dashboard-id> --title <title> --spec <file|-> [--dry-run] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
309
+
310
+ Examples:
311
+ tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec funnel.json --dry-run --json
312
+ tender app analytics charts create artifact_123 --dashboard analytics_dashboard_123 --title "Signup funnel" --spec funnel.json --json`;
179
313
  }
180
314
  function artifactsListHelp() {
181
- return `Usage: tender artifacts list [--base-url <url>] [--token <token>] [--profile <name>] [--json]
315
+ return `Usage: tender app list [--base-url <url>] [--token <token>] [--profile <name>] [--json]
182
316
 
183
317
  Options:
184
318
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
@@ -187,15 +321,15 @@ Options:
187
321
  --json Emit stable JSON for coding agents.
188
322
 
189
323
  Examples:
190
- tender artifacts list --json
191
- tender artifacts list --profile account --json
192
- TENDER_API_TOKEN=tpat_... tender artifacts list --base-url https://app.tenderprompt.com --json`;
324
+ tender app list --json
325
+ tender app list --profile account --json
326
+ TENDER_API_TOKEN=tpat_... tender app list --base-url https://app.tenderprompt.com --json`;
193
327
  }
194
328
  function artifactsCreateHelp() {
195
- return `Usage: tender artifacts create --name <name> [--target-pack <id>] [--target-pack-version <version>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
329
+ return `Usage: tender app create --name <name> [--target-pack <id>] [--target-pack-version <version>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
196
330
 
197
331
  Options:
198
- --name <name> Artifact name.
332
+ --name <name> App name.
199
333
  --target-pack <id> Target pack id. Defaults to the API default.
200
334
  --target-pack-version <value> Target pack version. Defaults to the API default.
201
335
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
@@ -204,24 +338,24 @@ Options:
204
338
  --json Emit stable JSON for coding agents.
205
339
 
206
340
  Examples:
207
- tender artifacts create --name "Exit Intent Widget" --json
208
- tender artifacts create --name "Exit Intent Widget" --profile account --json`;
341
+ tender app create --name "Exit Intent Widget" --json
342
+ tender app create --name "Exit Intent Widget" --profile account --json`;
209
343
  }
210
344
  function artifactsUpdateHelp() {
211
- return `Usage: tender artifacts update <artifact-id> --name <name> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
345
+ return `Usage: tender app update <app-id> --name <name> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
212
346
 
213
347
  Options:
214
- --name <name> New artifact name.
348
+ --name <name> New app name.
215
349
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
216
350
  --token <token> Tender API token. Defaults to TENDER_API_TOKEN or the saved profile token.
217
351
  --profile <name> Local config profile name. Defaults to the saved default profile.
218
352
  --json Emit stable JSON for coding agents.
219
353
 
220
354
  Examples:
221
- tender artifacts update artifact_123 --name "Sale Widget" --json`;
355
+ tender app update artifact_123 --name "Sale Widget" --json`;
222
356
  }
223
357
  function artifactsInitHelp() {
224
- return `Usage: tender artifacts init <artifact-id> [--dir <path>] [--remote <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--force] [--json]
358
+ return `Usage: tender app init <app-id> [--dir <path>] [--remote <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--force] [--json]
225
359
 
226
360
  Options:
227
361
  --dir <path> Local checkout directory to create/update. Defaults to current directory.
@@ -235,12 +369,12 @@ Options:
235
369
  --json Emit stable JSON for coding agents.
236
370
 
237
371
  Examples:
238
- tender artifacts init artifact_123 --dir ./widget --dry-run --json
239
- tender artifacts init artifact_123 --dir ./widget --json
240
- tender artifacts init artifact_123 --dir ./widget --force --json`;
372
+ tender app init artifact_123 --dir ./widget --dry-run --json
373
+ tender app init artifact_123 --dir ./widget --json
374
+ tender app init artifact_123 --dir ./widget --force --json`;
241
375
  }
242
376
  function artifactsContextFetchHelp() {
243
- return `Usage: tender artifacts context fetch <artifact-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--dry-run] [--force] [--json]
377
+ return `Usage: tender app context fetch <app-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--dry-run] [--force] [--json]
244
378
 
245
379
  Options:
246
380
  --dir <path> Local checkout to update. Defaults to current directory.
@@ -252,12 +386,12 @@ Options:
252
386
  --json Emit stable JSON for coding agents.
253
387
 
254
388
  Examples:
255
- tender artifacts context fetch artifact_123 --dir ./widget --dry-run --json
256
- tender artifacts context fetch artifact_123 --dir ./widget --force
257
- tender artifacts context fetch artifact_123 --profile agent --json`;
389
+ tender app context fetch artifact_123 --dir ./widget --dry-run --json
390
+ tender app context fetch artifact_123 --dir ./widget --force
391
+ tender app context fetch artifact_123 --profile agent --json`;
258
392
  }
259
393
  function artifactsContextStatusHelp() {
260
- return `Usage: tender artifacts context status <artifact-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
394
+ return `Usage: tender app context status <app-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
261
395
 
262
396
  Options:
263
397
  --dir <path> Local checkout to inspect. Defaults to current directory.
@@ -267,10 +401,10 @@ Options:
267
401
  --json Emit stable JSON for coding agents.
268
402
 
269
403
  Examples:
270
- tender artifacts context status artifact_123 --dir ./widget --json`;
404
+ tender app context status artifact_123 --dir ./widget --json`;
271
405
  }
272
406
  function artifactsContextRefreshHelp() {
273
- return `Usage: tender artifacts context refresh <artifact-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--dry-run] [--force] [--json]
407
+ return `Usage: tender app context refresh <app-id> [--dir <path>] [--base-url <url>] [--token <token>] [--profile <name>] [--dry-run] [--force] [--json]
274
408
 
275
409
  Options:
276
410
  --dir <path> Local checkout to update. Defaults to current directory.
@@ -282,22 +416,33 @@ Options:
282
416
  --json Emit stable JSON for coding agents.
283
417
 
284
418
  Examples:
285
- tender artifacts context refresh artifact_123 --dir ./widget --dry-run --json
286
- tender artifacts context refresh artifact_123 --dir ./widget --force`;
419
+ tender app context refresh artifact_123 --dir ./widget --dry-run --json
420
+ tender app context refresh artifact_123 --dir ./widget --force`;
287
421
  }
288
422
  function doctorHelp() {
289
- return `Usage: tender artifacts doctor [--dir <path>] [--json]
423
+ return `Usage: tender app doctor [--dir <path>] [--json]
290
424
 
291
425
  Options:
292
426
  --dir <path> Local Tender App checkout to inspect. Defaults to current directory.
293
427
  --json Emit stable JSON for coding agents.
294
428
 
295
429
  Examples:
296
- tender artifacts doctor --dir ./widget
297
- tender artifacts doctor --dir ./widget --json`;
430
+ tender app doctor --dir ./widget
431
+ tender app doctor --dir ./widget --json`;
432
+ }
433
+ function generateEnvTypesHelp() {
434
+ return `Usage: tender app generate-env-types [--dir <path>] [--json]
435
+
436
+ Options:
437
+ --dir <path> Local Tender App checkout to update. Defaults to current directory.
438
+ --json Emit stable JSON for coding agents.
439
+
440
+ Examples:
441
+ tender app generate-env-types --dir ./widget
442
+ tender app generate-env-types --dir ./widget --json`;
298
443
  }
299
444
  function gitRemoteHelp() {
300
- return `Usage: tender artifacts git remote <artifact-id> [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--json]
445
+ return `Usage: tender app git remote <app-id> [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--json]
301
446
 
302
447
  Options:
303
448
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
@@ -307,12 +452,12 @@ Options:
307
452
  --json Emit stable JSON for coding agents.
308
453
 
309
454
  Examples:
310
- tender artifacts git remote artifact_123 --ttl 7d --json
311
- tender artifacts git remote artifact_123 --profile publish --ttl 7d --json
312
- TENDER_API_TOKEN=tp_... tender artifacts git remote artifact_123 --base-url https://app.tenderprompt.com --json`;
455
+ tender app git remote artifact_123 --ttl 7d --json
456
+ tender app git remote artifact_123 --profile publish --ttl 7d --json
457
+ TENDER_API_TOKEN=tp_... tender app git remote artifact_123 --base-url https://app.tenderprompt.com --json`;
313
458
  }
314
459
  function gitSetupHelp() {
315
- return `Usage: tender artifacts git setup <artifact-id> [--dir <path>] [--remote <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--json]
460
+ return `Usage: tender app git setup <app-id> [--dir <path>] [--remote <name>] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--dry-run] [--json]
316
461
 
317
462
  Options:
318
463
  --dir <path> Local Git checkout to configure. Defaults to current directory.
@@ -325,26 +470,26 @@ Options:
325
470
  --json Emit stable JSON for coding agents.
326
471
 
327
472
  Examples:
328
- tender artifacts git setup artifact_123 --dir ./widget --json
329
- tender artifacts git setup artifact_123 --dir ./widget --remote tender --ttl 7d
330
- tender artifacts git setup artifact_123 --dir ./widget --dry-run --json`;
473
+ tender app git setup artifact_123 --dir ./widget --json
474
+ tender app git setup artifact_123 --dir ./widget --remote tender --ttl 7d
475
+ tender app git setup artifact_123 --dir ./widget --dry-run --json`;
331
476
  }
332
477
  function gitCredentialHelp() {
333
- return `Usage: tender artifacts git credential <artifact-id> [get|store|erase] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--remote-url <url>]
478
+ return `Usage: tender app git credential <app-id> [get|store|erase] [--base-url <url>] [--token <token>] [--profile <name>] [--ttl <7d|14d|30d>] [--remote-url <url>]
334
479
 
335
480
  This command is intended for Git's credential.helper protocol. It prints a
336
481
  Tender API-token username/password pair only for matching get requests. Do not
337
482
  run it manually unless you are debugging Git credential-helper behavior.
338
483
 
339
484
  Examples:
340
- tender artifacts git credential artifact_123 get
341
- tender artifacts git credential artifact_123 get --remote-url https://app.tenderprompt.com/git/artifacts/artifact_123.git`;
485
+ tender app git credential artifact_123 get
486
+ tender app git credential artifact_123 get --remote-url https://app.tenderprompt.com/git/artifacts/artifact_123.git`;
342
487
  }
343
488
  function previewRebuildHelp() {
344
- return `Usage: tender artifacts preview rebuild <artifact-id> [--commit <sha>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
489
+ return `Usage: tender app preview rebuild <app-id> [--commit <sha>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
345
490
 
346
491
  Options:
347
- --commit <sha> Rebuild preview only if the artifact workspace is at this Git commit.
492
+ --commit <sha> Rebuild preview only if the app workspace is at this Git commit.
348
493
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
349
494
  --token <token> Tender API token. Defaults to TENDER_API_TOKEN or the saved profile token.
350
495
  --profile <name> Local config profile name. Defaults to the saved default profile.
@@ -352,11 +497,11 @@ Options:
352
497
  --json Emit stable JSON for coding agents.
353
498
 
354
499
  Examples:
355
- tender artifacts preview rebuild artifact_123 --commit $(git rev-parse HEAD) --stream --json
356
- tender artifacts preview rebuild artifact_123 --json`;
500
+ tender app preview rebuild artifact_123 --commit $(git rev-parse HEAD) --stream --json
501
+ tender app preview rebuild artifact_123 --json`;
357
502
  }
358
503
  function validateHelp() {
359
- return `Usage: tender artifacts validate <artifact-id> [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
504
+ return `Usage: tender app validate <app-id> [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
360
505
 
361
506
  Options:
362
507
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
@@ -366,14 +511,14 @@ Options:
366
511
  --json Emit stable JSON for coding agents.
367
512
 
368
513
  Examples:
369
- tender artifacts validate artifact_123 --json
370
- tender artifacts validate artifact_123 --stream --json`;
514
+ tender app validate artifact_123 --json
515
+ tender app validate artifact_123 --stream --json`;
371
516
  }
372
517
  function buildHelp() {
373
- return `Usage: tender artifacts build <artifact-id> [--commit <sha>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
518
+ return `Usage: tender app build <app-id> [--commit <sha>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
374
519
 
375
520
  Options:
376
- --commit <sha> Build only if the artifact workspace is at this Git commit.
521
+ --commit <sha> Build only if the app workspace is at this Git commit.
377
522
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
378
523
  --token <token> Tender API token. Defaults to TENDER_API_TOKEN or the saved profile token.
379
524
  --profile <name> Local config profile name. Defaults to the saved default profile.
@@ -381,11 +526,11 @@ Options:
381
526
  --json Emit stable JSON for coding agents.
382
527
 
383
528
  Examples:
384
- tender artifacts build artifact_123 --commit $(git rev-parse HEAD) --json
385
- tender artifacts build artifact_123 --stream --json`;
529
+ tender app build artifact_123 --commit $(git rev-parse HEAD) --json
530
+ tender app build artifact_123 --stream --json`;
386
531
  }
387
532
  function previewStatusHelp() {
388
- return `Usage: tender artifacts preview status <artifact-id> [--commit <sha> | --job <job-id>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
533
+ return `Usage: tender app preview status <app-id> [--commit <sha> | --job <job-id>] [--base-url <url>] [--token <token>] [--profile <name>] [--json]
389
534
 
390
535
  Options:
391
536
  --commit <sha> Show the latest preview job for one artifact Git commit.
@@ -396,11 +541,11 @@ Options:
396
541
  --json Emit stable JSON for coding agents.
397
542
 
398
543
  Examples:
399
- tender artifacts preview status artifact_123 --commit $(git rev-parse HEAD) --json
400
- tender artifacts preview status artifact_123 --job job_123 --json`;
544
+ tender app preview status artifact_123 --commit $(git rev-parse HEAD) --json
545
+ tender app preview status artifact_123 --job job_123 --json`;
401
546
  }
402
547
  function previewWatchHelp() {
403
- return `Usage: tender artifacts preview watch <artifact-id> [--commit <sha> | --job <job-id>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
548
+ return `Usage: tender app preview watch <app-id> [--commit <sha> | --job <job-id>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
404
549
 
405
550
  Options:
406
551
  --commit <sha> Watch the latest preview job for one artifact Git commit.
@@ -412,16 +557,16 @@ Options:
412
557
  --json Emit lifecycle events as JSON lines.
413
558
 
414
559
  Examples:
415
- tender artifacts preview watch artifact_123 --commit $(git rev-parse HEAD) --stream --json
416
- tender artifacts preview watch artifact_123 --job job_123 --stream --json`;
560
+ tender app preview watch artifact_123 --commit $(git rev-parse HEAD) --stream --json
561
+ tender app preview watch artifact_123 --job job_123 --stream --json`;
417
562
  }
418
563
  function publishHelp() {
419
- return `Usage: tender artifacts publish <artifact-id> (--dry-run | --confirm publish) [--commit <sha>] [--message <text>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
564
+ return `Usage: tender app publish <app-id> (--dry-run | --confirm publish) [--commit <sha>] [--message <text>] [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
420
565
 
421
566
  Options:
422
567
  --dry-run Show the publish request without calling the API.
423
568
  --confirm publish Required to call the production-facing publish API.
424
- --commit <sha> Publish only if the artifact workspace is at this Git commit.
569
+ --commit <sha> Publish only if the app workspace is at this Git commit.
425
570
  --message <text> Human audit message returned in CLI output.
426
571
  --base-url <url> Tender base URL. Defaults to TENDER_BASE_URL, saved profile base URL, or https://app.tenderprompt.com.
427
572
  --token <token> Tender API token. Defaults to TENDER_API_TOKEN or the saved profile token.
@@ -430,11 +575,11 @@ Options:
430
575
  --json Emit stable JSON for coding agents.
431
576
 
432
577
  Examples:
433
- tender artifacts publish artifact_123 --dry-run --json
434
- tender artifacts publish artifact_123 --commit $(git rev-parse HEAD) --confirm publish --stream --json`;
578
+ tender app publish artifact_123 --dry-run --json
579
+ tender app publish artifact_123 --commit $(git rev-parse HEAD) --confirm publish --stream --json`;
435
580
  }
436
581
  function publishStatusHelp() {
437
- return `Usage: tender artifacts publish status <artifact-id> --job <job-id> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
582
+ return `Usage: tender app publish status <app-id> --job <job-id> [--base-url <url>] [--token <token>] [--profile <name>] [--json]
438
583
 
439
584
  Options:
440
585
  --job <job-id> Show one publish lifecycle job directly.
@@ -444,10 +589,10 @@ Options:
444
589
  --json Emit stable JSON for coding agents.
445
590
 
446
591
  Examples:
447
- tender artifacts publish status artifact_123 --job job_123 --json`;
592
+ tender app publish status artifact_123 --job job_123 --json`;
448
593
  }
449
594
  function publishWatchHelp() {
450
- return `Usage: tender artifacts publish watch <artifact-id> --job <job-id> [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
595
+ return `Usage: tender app publish watch <app-id> --job <job-id> [--base-url <url>] [--token <token>] [--profile <name>] [--stream] [--json]
451
596
 
452
597
  Options:
453
598
  --job <job-id> Watch one publish lifecycle job directly.
@@ -458,7 +603,7 @@ Options:
458
603
  --json Emit lifecycle events as JSON lines.
459
604
 
460
605
  Examples:
461
- tender artifacts publish watch artifact_123 --job job_123 --stream --json`;
606
+ tender app publish watch artifact_123 --job job_123 --stream --json`;
462
607
  }
463
608
  function normalizeBaseUrl(value) {
464
609
  return (value ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
@@ -605,7 +750,7 @@ function parseGitRemoteArgs(args) {
605
750
  }
606
751
  const artifactId = args[0];
607
752
  if (!artifactId || artifactId.startsWith("-")) {
608
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts git remote <artifact-id> --json");
753
+ throw new TenderCliUsageError("app id is required. Example: tender app git remote <app-id> --json");
609
754
  }
610
755
  let baseUrl = null;
611
756
  let flagToken = null;
@@ -665,7 +810,7 @@ function parseGitSetupArgs(args) {
665
810
  }
666
811
  const artifactId = args[0];
667
812
  if (!artifactId || artifactId.startsWith("-")) {
668
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts git setup <artifact-id> --dir ./widget --json");
813
+ throw new TenderCliUsageError("app id is required. Example: tender app git setup <app-id> --dir ./widget --json");
669
814
  }
670
815
  let dir = ".";
671
816
  let remoteName = "tender";
@@ -758,7 +903,7 @@ function parseGitCredentialArgs(args) {
758
903
  }
759
904
  const artifactId = args[0];
760
905
  if (!artifactId || artifactId.startsWith("-")) {
761
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts git credential <artifact-id> get");
906
+ throw new TenderCliUsageError("app id is required. Example: tender app git credential <app-id> get");
762
907
  }
763
908
  const parsedOperation = parseGitCredentialOperation(args[1]);
764
909
  let operation = parsedOperation.operation;
@@ -832,7 +977,7 @@ function parseValidateArgs(args) {
832
977
  }
833
978
  const artifactId = args[0];
834
979
  if (!artifactId || artifactId.startsWith("-")) {
835
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts validate <artifact-id> --json");
980
+ throw new TenderCliUsageError("app id is required. Example: tender app validate <app-id> --json");
836
981
  }
837
982
  let baseUrl = null;
838
983
  let flagToken = null;
@@ -882,7 +1027,7 @@ function parseBuildArgs(args) {
882
1027
  }
883
1028
  const artifactId = args[0];
884
1029
  if (!artifactId || artifactId.startsWith("-")) {
885
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts build <artifact-id> --json");
1030
+ throw new TenderCliUsageError("app id is required. Example: tender app build <app-id> --json");
886
1031
  }
887
1032
  let baseUrl = null;
888
1033
  let flagToken = null;
@@ -943,7 +1088,7 @@ function parsePreviewRebuildArgs(args) {
943
1088
  }
944
1089
  const artifactId = args[0];
945
1090
  if (!artifactId || artifactId.startsWith("-")) {
946
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts preview rebuild <artifact-id> --stream --json");
1091
+ throw new TenderCliUsageError("app id is required. Example: tender app preview rebuild <app-id> --stream --json");
947
1092
  }
948
1093
  let baseUrl = null;
949
1094
  let flagToken = null;
@@ -1070,7 +1215,7 @@ function parsePreviewStatusArgs(args) {
1070
1215
  }
1071
1216
  const artifactId = args[0];
1072
1217
  if (!artifactId || artifactId.startsWith("-")) {
1073
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts preview status <artifact-id> --commit <sha> --json");
1218
+ throw new TenderCliUsageError("app id is required. Example: tender app preview status <app-id> --commit <sha> --json");
1074
1219
  }
1075
1220
  const options = readPreviewLookupOptions({
1076
1221
  args,
@@ -1078,7 +1223,7 @@ function parsePreviewStatusArgs(args) {
1078
1223
  commandName: "preview status",
1079
1224
  });
1080
1225
  if (options.stream) {
1081
- throw new TenderCliUsageError("preview status does not support --stream. Use tender artifacts preview watch.");
1226
+ throw new TenderCliUsageError("preview status does not support --stream. Use tender app preview watch.");
1082
1227
  }
1083
1228
  return {
1084
1229
  command: "artifacts preview status",
@@ -1097,7 +1242,7 @@ function parsePreviewWatchArgs(args) {
1097
1242
  }
1098
1243
  const artifactId = args[0];
1099
1244
  if (!artifactId || artifactId.startsWith("-")) {
1100
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts preview watch <artifact-id> --job <job-id> --stream --json");
1245
+ throw new TenderCliUsageError("app id is required. Example: tender app preview watch <app-id> --job <job-id> --stream --json");
1101
1246
  }
1102
1247
  const options = readPreviewLookupOptions({
1103
1248
  args,
@@ -1122,7 +1267,7 @@ function parsePublishArgs(args) {
1122
1267
  }
1123
1268
  const artifactId = args[0];
1124
1269
  if (!artifactId || artifactId.startsWith("-")) {
1125
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts publish <artifact-id> --dry-run --json");
1270
+ throw new TenderCliUsageError("app id is required. Example: tender app publish <app-id> --dry-run --json");
1126
1271
  }
1127
1272
  let baseUrl = null;
1128
1273
  let flagToken = null;
@@ -1269,7 +1414,7 @@ function parsePublishStatusArgs(args) {
1269
1414
  }
1270
1415
  const artifactId = args[0];
1271
1416
  if (!artifactId || artifactId.startsWith("-")) {
1272
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts publish status <artifact-id> --job <job-id> --json");
1417
+ throw new TenderCliUsageError("app id is required. Example: tender app publish status <app-id> --job <job-id> --json");
1273
1418
  }
1274
1419
  const options = readPublishJobLookupOptions({
1275
1420
  args,
@@ -1277,7 +1422,7 @@ function parsePublishStatusArgs(args) {
1277
1422
  commandName: "publish status",
1278
1423
  });
1279
1424
  if (options.stream) {
1280
- throw new TenderCliUsageError("publish status does not support --stream. Use tender artifacts publish watch.");
1425
+ throw new TenderCliUsageError("publish status does not support --stream. Use tender app publish watch.");
1281
1426
  }
1282
1427
  return {
1283
1428
  command: "artifacts publish status",
@@ -1295,7 +1440,7 @@ function parsePublishWatchArgs(args) {
1295
1440
  }
1296
1441
  const artifactId = args[0];
1297
1442
  if (!artifactId || artifactId.startsWith("-")) {
1298
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts publish watch <artifact-id> --job <job-id> --stream --json");
1443
+ throw new TenderCliUsageError("app id is required. Example: tender app publish watch <app-id> --job <job-id> --stream --json");
1299
1444
  }
1300
1445
  const options = readPublishJobLookupOptions({
1301
1446
  args,
@@ -1342,7 +1487,7 @@ function parseArtifactsListArgs(args) {
1342
1487
  index += 1;
1343
1488
  continue;
1344
1489
  }
1345
- throw new TenderCliUsageError(`Unknown artifacts list option: ${arg}`);
1490
+ throw new TenderCliUsageError(`Unknown app list option: ${arg}`);
1346
1491
  }
1347
1492
  return {
1348
1493
  command: "artifacts list",
@@ -1372,7 +1517,7 @@ function parseArtifactsCreateArgs(args) {
1372
1517
  if (arg === "--name") {
1373
1518
  const value = args[index + 1];
1374
1519
  if (!value || value.startsWith("-")) {
1375
- throw new TenderCliUsageError("--name requires an artifact name.");
1520
+ throw new TenderCliUsageError("--name requires an app name.");
1376
1521
  }
1377
1522
  name = value;
1378
1523
  index += 1;
@@ -1411,10 +1556,10 @@ function parseArtifactsCreateArgs(args) {
1411
1556
  index += 1;
1412
1557
  continue;
1413
1558
  }
1414
- throw new TenderCliUsageError(`Unknown artifacts create option: ${arg}`);
1559
+ throw new TenderCliUsageError(`Unknown app create option: ${arg}`);
1415
1560
  }
1416
1561
  if (!name.trim()) {
1417
- throw new TenderCliUsageError("--name is required. Example: tender artifacts create --name \"Exit Intent Widget\" --json");
1562
+ throw new TenderCliUsageError("--name is required. Example: tender app create --name \"Exit Intent Widget\" --json");
1418
1563
  }
1419
1564
  return {
1420
1565
  command: "artifacts create",
@@ -1433,7 +1578,7 @@ function parseArtifactsUpdateArgs(args) {
1433
1578
  }
1434
1579
  const artifactId = args[0];
1435
1580
  if (!artifactId || artifactId.startsWith("-")) {
1436
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts update <artifact-id> --name \"Sale Widget\" --json");
1581
+ throw new TenderCliUsageError("app id is required. Example: tender app update <app-id> --name \"Sale Widget\" --json");
1437
1582
  }
1438
1583
  let name = "";
1439
1584
  let baseUrl = null;
@@ -1449,7 +1594,7 @@ function parseArtifactsUpdateArgs(args) {
1449
1594
  if (arg === "--name") {
1450
1595
  const value = args[index + 1];
1451
1596
  if (!value || value.startsWith("-")) {
1452
- throw new TenderCliUsageError("--name requires an artifact name.");
1597
+ throw new TenderCliUsageError("--name requires an app name.");
1453
1598
  }
1454
1599
  name = value;
1455
1600
  index += 1;
@@ -1470,10 +1615,10 @@ function parseArtifactsUpdateArgs(args) {
1470
1615
  index += 1;
1471
1616
  continue;
1472
1617
  }
1473
- throw new TenderCliUsageError(`Unknown artifacts update option: ${arg}`);
1618
+ throw new TenderCliUsageError(`Unknown app update option: ${arg}`);
1474
1619
  }
1475
1620
  if (!name.trim()) {
1476
- throw new TenderCliUsageError("--name is required. Example: tender artifacts update artifact_123 --name \"Sale Widget\" --json");
1621
+ throw new TenderCliUsageError("--name is required. Example: tender app update artifact_123 --name \"Sale Widget\" --json");
1477
1622
  }
1478
1623
  return {
1479
1624
  command: "artifacts update",
@@ -1491,7 +1636,7 @@ function parseArtifactsInitArgs(args) {
1491
1636
  }
1492
1637
  const artifactId = args[0];
1493
1638
  if (!artifactId || artifactId.startsWith("-")) {
1494
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts init <artifact-id> --dir ./widget --json");
1639
+ throw new TenderCliUsageError("app id is required. Example: tender app init <app-id> --dir ./widget --json");
1495
1640
  }
1496
1641
  let dir = ".";
1497
1642
  let remoteName = "tender";
@@ -1550,7 +1695,7 @@ function parseArtifactsInitArgs(args) {
1550
1695
  index += 1;
1551
1696
  continue;
1552
1697
  }
1553
- throw new TenderCliUsageError(`Unknown artifacts init option: ${arg}`);
1698
+ throw new TenderCliUsageError(`Unknown app init option: ${arg}`);
1554
1699
  }
1555
1700
  return {
1556
1701
  command: "artifacts init",
@@ -1572,7 +1717,7 @@ function parseContextFetchArgs(args) {
1572
1717
  }
1573
1718
  const artifactId = args[0];
1574
1719
  if (!artifactId || artifactId.startsWith("-")) {
1575
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts context fetch <artifact-id> --dir ./widget --json");
1720
+ throw new TenderCliUsageError("app id is required. Example: tender app context fetch <app-id> --dir ./widget --json");
1576
1721
  }
1577
1722
  let dir = ".";
1578
1723
  let baseUrl = null;
@@ -1639,7 +1784,7 @@ function parseContextStatusArgs(args) {
1639
1784
  }
1640
1785
  const artifactId = args[0];
1641
1786
  if (!artifactId || artifactId.startsWith("-")) {
1642
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts context status <artifact-id> --dir ./widget --json");
1787
+ throw new TenderCliUsageError("app id is required. Example: tender app context status <app-id> --dir ./widget --json");
1643
1788
  }
1644
1789
  let dir = ".";
1645
1790
  let baseUrl = null;
@@ -1694,7 +1839,7 @@ function parseContextRefreshArgs(args) {
1694
1839
  }
1695
1840
  const artifactId = args[0];
1696
1841
  if (!artifactId || artifactId.startsWith("-")) {
1697
- throw new TenderCliUsageError("artifact id is required. Example: tender artifacts context refresh <artifact-id> --dir ./widget --dry-run --json");
1842
+ throw new TenderCliUsageError("app id is required. Example: tender app context refresh <app-id> --dir ./widget --dry-run --json");
1698
1843
  }
1699
1844
  let dir = ".";
1700
1845
  let baseUrl = null;
@@ -1873,6 +2018,343 @@ function parseAuthStatusArgs(args) {
1873
2018
  json,
1874
2019
  };
1875
2020
  }
2021
+ function parseGenerateEnvTypesArgs(args) {
2022
+ if (args.includes("--help") || args.includes("-h")) {
2023
+ return { command: "help", topic: "artifacts generate-env-types" };
2024
+ }
2025
+ let dir = ".";
2026
+ let json = false;
2027
+ for (let index = 0; index < args.length; index += 1) {
2028
+ const arg = args[index];
2029
+ if (arg === "--json") {
2030
+ json = true;
2031
+ continue;
2032
+ }
2033
+ if (arg === "--dir") {
2034
+ const value = args[index + 1];
2035
+ if (!value) {
2036
+ throw new TenderCliUsageError("--dir requires a path.");
2037
+ }
2038
+ dir = value;
2039
+ index += 1;
2040
+ continue;
2041
+ }
2042
+ throw new TenderCliUsageError(`Unknown generate-env-types option: ${arg}`);
2043
+ }
2044
+ return {
2045
+ command: "artifacts generate-env-types",
2046
+ dir,
2047
+ json,
2048
+ };
2049
+ }
2050
+ function parseAnalyticsRange(value) {
2051
+ if (!value || value.startsWith("-")) {
2052
+ throw new TenderCliUsageError("--range requires 7d, 30d, 90d, or YYYY-MM-DD..YYYY-MM-DD.");
2053
+ }
2054
+ if (value === "7d" || value === "30d" || value === "90d") {
2055
+ return value;
2056
+ }
2057
+ if (/^\d{4}-\d{2}-\d{2}\.\.\d{4}-\d{2}-\d{2}$/.test(value)) {
2058
+ return value;
2059
+ }
2060
+ throw new TenderCliUsageError("--range must be 7d, 30d, 90d, or YYYY-MM-DD..YYYY-MM-DD.");
2061
+ }
2062
+ function parseSpecPath(value) {
2063
+ if (!value || (value !== "-" && value.startsWith("-"))) {
2064
+ throw new TenderCliUsageError("--spec requires a JSON file path or - for stdin.");
2065
+ }
2066
+ return value;
2067
+ }
2068
+ function parseRequiredFlagValue(value, flag) {
2069
+ if (!value || value.startsWith("-")) {
2070
+ throw new TenderCliUsageError(`${flag} requires a value.`);
2071
+ }
2072
+ return value;
2073
+ }
2074
+ function parseAnalyticsCommonArgs(args, startIndex) {
2075
+ let baseUrl = null;
2076
+ let flagToken = null;
2077
+ let profileName = null;
2078
+ let json = false;
2079
+ const remaining = [];
2080
+ for (let index = startIndex; index < args.length; index += 1) {
2081
+ const arg = args[index];
2082
+ if (arg === "--json") {
2083
+ json = true;
2084
+ continue;
2085
+ }
2086
+ if (arg === "--base-url") {
2087
+ baseUrl = parseBaseUrlFlag(args, index);
2088
+ index += 1;
2089
+ continue;
2090
+ }
2091
+ if (arg === "--token") {
2092
+ flagToken = parseTokenFlag(args, index);
2093
+ index += 1;
2094
+ continue;
2095
+ }
2096
+ if (arg === "--profile") {
2097
+ profileName = parseProfileName(args[index + 1], "--profile");
2098
+ index += 1;
2099
+ continue;
2100
+ }
2101
+ remaining.push(arg);
2102
+ }
2103
+ return { baseUrl, flagToken, profileName, json, remaining };
2104
+ }
2105
+ function parseAnalyticsSummaryArgs(args) {
2106
+ if (args.includes("--help") || args.includes("-h")) {
2107
+ return { command: "help", topic: "artifacts analytics summary" };
2108
+ }
2109
+ const artifactId = args[0];
2110
+ if (!artifactId || artifactId.startsWith("-")) {
2111
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics summary <app-id> --range 30d --json");
2112
+ }
2113
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2114
+ let range = "7d";
2115
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2116
+ const arg = parsed.remaining[index];
2117
+ if (arg === "--range") {
2118
+ range = parseAnalyticsRange(parsed.remaining[index + 1]);
2119
+ index += 1;
2120
+ continue;
2121
+ }
2122
+ throw new TenderCliUsageError(`Unknown analytics summary option: ${arg}`);
2123
+ }
2124
+ return { command: "artifacts analytics summary", artifactId, range, ...parsed };
2125
+ }
2126
+ function parseAnalyticsQueryArgs(args) {
2127
+ if (args.includes("--help") || args.includes("-h")) {
2128
+ return { command: "help", topic: "artifacts analytics query" };
2129
+ }
2130
+ const artifactId = args[0];
2131
+ if (!artifactId || artifactId.startsWith("-")) {
2132
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics query <app-id> --spec chart.json --json");
2133
+ }
2134
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2135
+ let specPath = null;
2136
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2137
+ const arg = parsed.remaining[index];
2138
+ if (arg === "--spec") {
2139
+ specPath = parseSpecPath(parsed.remaining[index + 1]);
2140
+ index += 1;
2141
+ continue;
2142
+ }
2143
+ throw new TenderCliUsageError(`Unknown analytics query option: ${arg}`);
2144
+ }
2145
+ if (!specPath) {
2146
+ throw new TenderCliUsageError("--spec is required. Example: tender app analytics query artifact_123 --spec chart.json --json");
2147
+ }
2148
+ return { command: "artifacts analytics query", artifactId, specPath, ...parsed };
2149
+ }
2150
+ function parseAnalyticsCapabilitiesArgs(args) {
2151
+ if (args.includes("--help") || args.includes("-h")) {
2152
+ return { command: "help", topic: "artifacts analytics capabilities" };
2153
+ }
2154
+ const artifactId = args[0];
2155
+ if (!artifactId || artifactId.startsWith("-")) {
2156
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics capabilities <app-id> --include-catalog --json");
2157
+ }
2158
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2159
+ let range = "7d";
2160
+ let includeCatalog = false;
2161
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2162
+ const arg = parsed.remaining[index];
2163
+ if (arg === "--include-catalog") {
2164
+ includeCatalog = true;
2165
+ continue;
2166
+ }
2167
+ if (arg === "--range") {
2168
+ range = parseAnalyticsRange(parsed.remaining[index + 1]);
2169
+ index += 1;
2170
+ continue;
2171
+ }
2172
+ throw new TenderCliUsageError(`Unknown analytics capabilities option: ${arg}`);
2173
+ }
2174
+ return {
2175
+ command: "artifacts analytics capabilities",
2176
+ artifactId,
2177
+ includeCatalog,
2178
+ range,
2179
+ ...parsed,
2180
+ };
2181
+ }
2182
+ function parseAnalyticsSuggestionsArgs(args) {
2183
+ if (args.includes("--help") || args.includes("-h")) {
2184
+ return { command: "help", topic: "artifacts analytics suggestions" };
2185
+ }
2186
+ const artifactId = args[0];
2187
+ if (!artifactId || artifactId.startsWith("-")) {
2188
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics suggestions <app-id> --range 30d --json");
2189
+ }
2190
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2191
+ let range = "7d";
2192
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2193
+ const arg = parsed.remaining[index];
2194
+ if (arg === "--range") {
2195
+ range = parseAnalyticsRange(parsed.remaining[index + 1]);
2196
+ index += 1;
2197
+ continue;
2198
+ }
2199
+ throw new TenderCliUsageError(`Unknown analytics suggestions option: ${arg}`);
2200
+ }
2201
+ return { command: "artifacts analytics suggestions", artifactId, range, ...parsed };
2202
+ }
2203
+ function parseAnalyticsDashboardsArgs(args) {
2204
+ if (args.includes("--help") || args.includes("-h")) {
2205
+ return { command: "help", topic: "artifacts analytics dashboards" };
2206
+ }
2207
+ const artifactId = args[0];
2208
+ if (!artifactId || artifactId.startsWith("-")) {
2209
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics dashboards <app-id> --json");
2210
+ }
2211
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2212
+ let name = null;
2213
+ let dryRun = false;
2214
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2215
+ const arg = parsed.remaining[index];
2216
+ if (arg === "--create") {
2217
+ name = parseRequiredFlagValue(parsed.remaining[index + 1], "--create");
2218
+ index += 1;
2219
+ continue;
2220
+ }
2221
+ if (arg === "--dry-run") {
2222
+ dryRun = true;
2223
+ continue;
2224
+ }
2225
+ throw new TenderCliUsageError(`Unknown analytics dashboards option: ${arg}`);
2226
+ }
2227
+ if (dryRun && !name) {
2228
+ throw new TenderCliUsageError("--dry-run is only valid with --create. Example: tender app analytics dashboards artifact_123 --create \"Agent dashboard\" --dry-run --json");
2229
+ }
2230
+ return { command: "artifacts analytics dashboards", artifactId, name, dryRun, ...parsed };
2231
+ }
2232
+ function parseAnalyticsExportCatalogArgs(args) {
2233
+ if (args.includes("--help") || args.includes("-h")) {
2234
+ return { command: "help", topic: "artifacts analytics export catalog" };
2235
+ }
2236
+ const artifactId = args[0];
2237
+ if (!artifactId || artifactId.startsWith("-")) {
2238
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics export catalog <app-id> --range 30d --json");
2239
+ }
2240
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2241
+ let range = "7d";
2242
+ let format = "json";
2243
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2244
+ const arg = parsed.remaining[index];
2245
+ if (arg === "--range") {
2246
+ range = parseAnalyticsRange(parsed.remaining[index + 1]);
2247
+ index += 1;
2248
+ continue;
2249
+ }
2250
+ if (arg === "--format") {
2251
+ const value = parseRequiredFlagValue(parsed.remaining[index + 1], "--format");
2252
+ if (value !== "json") {
2253
+ throw new TenderCliUsageError("--format for export catalog must be json.");
2254
+ }
2255
+ format = value;
2256
+ index += 1;
2257
+ continue;
2258
+ }
2259
+ throw new TenderCliUsageError(`Unknown analytics export catalog option: ${arg}`);
2260
+ }
2261
+ return {
2262
+ command: "artifacts analytics export catalog",
2263
+ artifactId,
2264
+ format,
2265
+ range,
2266
+ ...parsed,
2267
+ };
2268
+ }
2269
+ function parseAnalyticsExportQueryArgs(args) {
2270
+ if (args.includes("--help") || args.includes("-h")) {
2271
+ return { command: "help", topic: "artifacts analytics export query" };
2272
+ }
2273
+ const artifactId = args[0];
2274
+ if (!artifactId || artifactId.startsWith("-")) {
2275
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics export query <app-id> --spec chart.json --format csv");
2276
+ }
2277
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2278
+ let specPath = null;
2279
+ let format = "json";
2280
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2281
+ const arg = parsed.remaining[index];
2282
+ if (arg === "--spec") {
2283
+ specPath = parseSpecPath(parsed.remaining[index + 1]);
2284
+ index += 1;
2285
+ continue;
2286
+ }
2287
+ if (arg === "--format") {
2288
+ const value = parseRequiredFlagValue(parsed.remaining[index + 1], "--format");
2289
+ if (value !== "json" && value !== "csv") {
2290
+ throw new TenderCliUsageError("--format must be json or csv.");
2291
+ }
2292
+ format = value;
2293
+ index += 1;
2294
+ continue;
2295
+ }
2296
+ throw new TenderCliUsageError(`Unknown analytics export query option: ${arg}`);
2297
+ }
2298
+ if (!specPath) {
2299
+ throw new TenderCliUsageError("--spec is required. Example: tender app analytics export query artifact_123 --spec chart.json --format csv");
2300
+ }
2301
+ return {
2302
+ command: "artifacts analytics export query",
2303
+ artifactId,
2304
+ specPath,
2305
+ format,
2306
+ ...parsed,
2307
+ };
2308
+ }
2309
+ function parseAnalyticsChartsCreateArgs(args) {
2310
+ if (args.includes("--help") || args.includes("-h")) {
2311
+ return { command: "help", topic: "artifacts analytics charts create" };
2312
+ }
2313
+ const artifactId = args[0];
2314
+ if (!artifactId || artifactId.startsWith("-")) {
2315
+ throw new TenderCliUsageError("app id is required. Example: tender app analytics charts create <app-id> --dashboard <dashboard-id> --title <title> --spec chart.json --json");
2316
+ }
2317
+ const parsed = parseAnalyticsCommonArgs(args, 1);
2318
+ let dashboardId = null;
2319
+ let title = null;
2320
+ let specPath = null;
2321
+ let dryRun = false;
2322
+ for (let index = 0; index < parsed.remaining.length; index += 1) {
2323
+ const arg = parsed.remaining[index];
2324
+ if (arg === "--dashboard") {
2325
+ dashboardId = parseRequiredFlagValue(parsed.remaining[index + 1], "--dashboard");
2326
+ index += 1;
2327
+ continue;
2328
+ }
2329
+ if (arg === "--title") {
2330
+ title = parseRequiredFlagValue(parsed.remaining[index + 1], "--title");
2331
+ index += 1;
2332
+ continue;
2333
+ }
2334
+ if (arg === "--spec") {
2335
+ specPath = parseSpecPath(parsed.remaining[index + 1]);
2336
+ index += 1;
2337
+ continue;
2338
+ }
2339
+ if (arg === "--dry-run") {
2340
+ dryRun = true;
2341
+ continue;
2342
+ }
2343
+ throw new TenderCliUsageError(`Unknown analytics charts create option: ${arg}`);
2344
+ }
2345
+ if (!dashboardId || !title || !specPath) {
2346
+ 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
+ }
2348
+ return {
2349
+ command: "artifacts analytics charts create",
2350
+ artifactId,
2351
+ dashboardId,
2352
+ title,
2353
+ specPath,
2354
+ dryRun,
2355
+ ...parsed,
2356
+ };
2357
+ }
1876
2358
  function parseTenderArgs(args) {
1877
2359
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
1878
2360
  return { command: "help", topic: "root" };
@@ -1889,81 +2371,141 @@ function parseTenderArgs(args) {
1889
2371
  }
1890
2372
  throw new TenderCliUsageError(`Unknown auth command: ${args[1]}`);
1891
2373
  }
1892
- if (args[0] !== "artifacts") {
2374
+ if (args[0] === "apps") {
2375
+ throw new TenderCliUsageError("Unknown command: apps. Use `tender app ...` for Tender App workflows.");
2376
+ }
2377
+ if (args[0] !== "artifacts" && args[0] !== "app") {
1893
2378
  throw new TenderCliUsageError(`Unknown command: ${args[0]}`);
1894
2379
  }
1895
- if (args[1] === undefined || args[1] === "--help" || args[1] === "-h") {
2380
+ const resourceArgs = normalizeAppArgs(args);
2381
+ const resourceName = args[0] === "app" ? "app" : "artifacts";
2382
+ if (resourceArgs[1] === undefined ||
2383
+ resourceArgs[1] === "--help" ||
2384
+ resourceArgs[1] === "-h") {
1896
2385
  return { command: "help", topic: "artifacts" };
1897
2386
  }
1898
- if (args[1] !== "doctor") {
1899
- if (args[1] === "list") {
1900
- return parseArtifactsListArgs(args.slice(2));
2387
+ if (resourceArgs[1] !== "doctor") {
2388
+ if (resourceArgs[1] === "list") {
2389
+ return parseArtifactsListArgs(resourceArgs.slice(2));
2390
+ }
2391
+ if (resourceArgs[1] === "create") {
2392
+ return parseArtifactsCreateArgs(resourceArgs.slice(2));
2393
+ }
2394
+ if (resourceArgs[1] === "update") {
2395
+ return parseArtifactsUpdateArgs(resourceArgs.slice(2));
2396
+ }
2397
+ if (resourceArgs[1] === "init") {
2398
+ return parseArtifactsInitArgs(resourceArgs.slice(2));
1901
2399
  }
1902
- if (args[1] === "create") {
1903
- return parseArtifactsCreateArgs(args.slice(2));
2400
+ if (resourceArgs[1] === "context" && resourceArgs[2] === "fetch") {
2401
+ return parseContextFetchArgs(resourceArgs.slice(3));
1904
2402
  }
1905
- if (args[1] === "update") {
1906
- return parseArtifactsUpdateArgs(args.slice(2));
2403
+ if (resourceArgs[1] === "context" && resourceArgs[2] === "status") {
2404
+ return parseContextStatusArgs(resourceArgs.slice(3));
1907
2405
  }
1908
- if (args[1] === "init") {
1909
- return parseArtifactsInitArgs(args.slice(2));
2406
+ if (resourceArgs[1] === "context" && resourceArgs[2] === "refresh") {
2407
+ return parseContextRefreshArgs(resourceArgs.slice(3));
1910
2408
  }
1911
- if (args[1] === "context" && args[2] === "fetch") {
1912
- return parseContextFetchArgs(args.slice(3));
2409
+ if (resourceArgs[1] === "analytics" &&
2410
+ (resourceArgs[2] === undefined ||
2411
+ resourceArgs[2] === "--help" ||
2412
+ resourceArgs[2] === "-h")) {
2413
+ return { command: "help", topic: "artifacts analytics" };
1913
2414
  }
1914
- if (args[1] === "context" && args[2] === "status") {
1915
- return parseContextStatusArgs(args.slice(3));
2415
+ if (resourceArgs[1] === "analytics" && resourceArgs[2] === "summary") {
2416
+ return parseAnalyticsSummaryArgs(resourceArgs.slice(3));
1916
2417
  }
1917
- if (args[1] === "context" && args[2] === "refresh") {
1918
- return parseContextRefreshArgs(args.slice(3));
2418
+ if (resourceArgs[1] === "analytics" && resourceArgs[2] === "query") {
2419
+ return parseAnalyticsQueryArgs(resourceArgs.slice(3));
1919
2420
  }
1920
- if (args[1] === "context" &&
1921
- (args[2] === undefined || args[2] === "--help" || args[2] === "-h")) {
2421
+ if (resourceArgs[1] === "analytics" && resourceArgs[2] === "capabilities") {
2422
+ return parseAnalyticsCapabilitiesArgs(resourceArgs.slice(3));
2423
+ }
2424
+ if (resourceArgs[1] === "analytics" && resourceArgs[2] === "suggestions") {
2425
+ return parseAnalyticsSuggestionsArgs(resourceArgs.slice(3));
2426
+ }
2427
+ if (resourceArgs[1] === "analytics" && resourceArgs[2] === "dashboards") {
2428
+ return parseAnalyticsDashboardsArgs(resourceArgs.slice(3));
2429
+ }
2430
+ if (resourceArgs[1] === "analytics" &&
2431
+ resourceArgs[2] === "export" &&
2432
+ (resourceArgs[3] === undefined ||
2433
+ resourceArgs[3] === "--help" ||
2434
+ resourceArgs[3] === "-h")) {
2435
+ return { command: "help", topic: "artifacts analytics export" };
2436
+ }
2437
+ if (resourceArgs[1] === "analytics" &&
2438
+ resourceArgs[2] === "export" &&
2439
+ resourceArgs[3] === "catalog") {
2440
+ return parseAnalyticsExportCatalogArgs(resourceArgs.slice(4));
2441
+ }
2442
+ if (resourceArgs[1] === "analytics" &&
2443
+ resourceArgs[2] === "export" &&
2444
+ resourceArgs[3] === "query") {
2445
+ return parseAnalyticsExportQueryArgs(resourceArgs.slice(4));
2446
+ }
2447
+ if (resourceArgs[1] === "analytics" &&
2448
+ resourceArgs[2] === "charts" &&
2449
+ resourceArgs[3] === "create") {
2450
+ return parseAnalyticsChartsCreateArgs(resourceArgs.slice(4));
2451
+ }
2452
+ if (resourceArgs[1] === "context" &&
2453
+ (resourceArgs[2] === undefined ||
2454
+ resourceArgs[2] === "--help" ||
2455
+ resourceArgs[2] === "-h")) {
1922
2456
  return { command: "help", topic: "artifacts" };
1923
2457
  }
1924
- if (args[1] === "git" && args[2] === "remote") {
1925
- return parseGitRemoteArgs(args.slice(3));
2458
+ if (resourceArgs[1] === "git" && resourceArgs[2] === "remote") {
2459
+ return parseGitRemoteArgs(resourceArgs.slice(3));
1926
2460
  }
1927
- if (args[1] === "git" && args[2] === "setup") {
1928
- return parseGitSetupArgs(args.slice(3));
2461
+ if (resourceArgs[1] === "git" && resourceArgs[2] === "setup") {
2462
+ return parseGitSetupArgs(resourceArgs.slice(3));
1929
2463
  }
1930
- if (args[1] === "git" && args[2] === "credential") {
1931
- return parseGitCredentialArgs(args.slice(3));
2464
+ if (resourceArgs[1] === "git" && resourceArgs[2] === "credential") {
2465
+ return parseGitCredentialArgs(resourceArgs.slice(3));
1932
2466
  }
1933
- if (args[1] === "validate") {
1934
- return parseValidateArgs(args.slice(2));
2467
+ if (resourceArgs[1] === "generate-env-types") {
2468
+ return parseGenerateEnvTypesArgs(resourceArgs.slice(2));
1935
2469
  }
1936
- if (args[1] === "build") {
1937
- return parseBuildArgs(args.slice(2));
2470
+ if (resourceArgs[1] === "validate") {
2471
+ return parseValidateArgs(resourceArgs.slice(2));
1938
2472
  }
1939
- if (args[1] === "preview" && args[2] === "rebuild") {
1940
- return parsePreviewRebuildArgs(args.slice(3));
2473
+ if (resourceArgs[1] === "build") {
2474
+ return parseBuildArgs(resourceArgs.slice(2));
1941
2475
  }
1942
- if (args[1] === "preview" && args[2] === "status") {
1943
- return parsePreviewStatusArgs(args.slice(3));
2476
+ if (resourceArgs[1] === "preview" && resourceArgs[2] === "rebuild") {
2477
+ return parsePreviewRebuildArgs(resourceArgs.slice(3));
1944
2478
  }
1945
- if (args[1] === "preview" && args[2] === "watch") {
1946
- return parsePreviewWatchArgs(args.slice(3));
2479
+ if (resourceArgs[1] === "preview" && resourceArgs[2] === "status") {
2480
+ return parsePreviewStatusArgs(resourceArgs.slice(3));
1947
2481
  }
1948
- if (args[1] === "preview" &&
1949
- (args[2] === undefined || args[2] === "--help" || args[2] === "-h")) {
2482
+ if (resourceArgs[1] === "preview" && resourceArgs[2] === "watch") {
2483
+ return parsePreviewWatchArgs(resourceArgs.slice(3));
2484
+ }
2485
+ if (resourceArgs[1] === "preview" &&
2486
+ (resourceArgs[2] === undefined ||
2487
+ resourceArgs[2] === "--help" ||
2488
+ resourceArgs[2] === "-h")) {
1950
2489
  return { command: "help", topic: "artifacts" };
1951
2490
  }
1952
- if (args[1] === "publish" && args[2] === "status") {
1953
- return parsePublishStatusArgs(args.slice(3));
2491
+ if (resourceArgs[1] === "publish" && resourceArgs[2] === "status") {
2492
+ return parsePublishStatusArgs(resourceArgs.slice(3));
1954
2493
  }
1955
- if (args[1] === "publish" && args[2] === "watch") {
1956
- return parsePublishWatchArgs(args.slice(3));
2494
+ if (resourceArgs[1] === "publish" && resourceArgs[2] === "watch") {
2495
+ return parsePublishWatchArgs(resourceArgs.slice(3));
1957
2496
  }
1958
- if (args[1] === "publish") {
1959
- return parsePublishArgs(args.slice(2));
2497
+ if (resourceArgs[1] === "publish") {
2498
+ return parsePublishArgs(resourceArgs.slice(2));
1960
2499
  }
1961
- if (args[1] === "git" && (args[2] === undefined || args[2] === "--help" || args[2] === "-h")) {
2500
+ if (resourceArgs[1] === "git" &&
2501
+ (resourceArgs[2] === undefined ||
2502
+ resourceArgs[2] === "--help" ||
2503
+ resourceArgs[2] === "-h")) {
1962
2504
  return { command: "help", topic: "artifacts" };
1963
2505
  }
1964
- throw new TenderCliUsageError(`Unknown artifacts command: ${args[1]}`);
2506
+ throw new TenderCliUsageError(`Unknown ${resourceName} command: ${resourceArgs[1]}`);
1965
2507
  }
1966
- const rest = args.slice(2);
2508
+ const rest = resourceArgs.slice(2);
1967
2509
  if (rest.includes("--help") || rest.includes("-h")) {
1968
2510
  return { command: "help", topic: "artifacts doctor" };
1969
2511
  }
@@ -1992,11 +2534,26 @@ function parseTenderArgs(args) {
1992
2534
  json,
1993
2535
  };
1994
2536
  }
2537
+ function normalizeAppArgs(args) {
2538
+ if (args[0] !== "app") {
2539
+ return args;
2540
+ }
2541
+ if (args[1] === "preview" &&
2542
+ args[2] &&
2543
+ args[2] !== "rebuild" &&
2544
+ args[2] !== "status" &&
2545
+ args[2] !== "watch" &&
2546
+ args[2] !== "--help" &&
2547
+ args[2] !== "-h") {
2548
+ return ["artifacts", "preview", "rebuild", ...args.slice(2)];
2549
+ }
2550
+ return ["artifacts", ...args.slice(1)];
2551
+ }
1995
2552
  function formatDoctorHuman(result) {
1996
2553
  if (result.diagnostics.length === 0) {
1997
2554
  return result.ok
1998
- ? "Tender artifacts doctor passed."
1999
- : "Tender artifacts doctor failed.";
2555
+ ? "Tender app doctor passed."
2556
+ : "Tender app doctor failed.";
2000
2557
  }
2001
2558
  return result.diagnostics
2002
2559
  .map((diagnostic) => {
@@ -2039,6 +2596,69 @@ async function runDoctor(command, io) {
2039
2596
  }
2040
2597
  return result.ok ? 0 : 1;
2041
2598
  }
2599
+ function formatEnvTypesGenerationFailure(result) {
2600
+ if (result.ok || result.diagnostics.length === 0) {
2601
+ return "Could not generate src/env.d.ts.";
2602
+ }
2603
+ return formatDoctorHuman({
2604
+ ok: false,
2605
+ diagnostics: result.diagnostics,
2606
+ });
2607
+ }
2608
+ async function runGenerateEnvTypes(command, io) {
2609
+ const root = path.resolve(command.dir);
2610
+ const files = await collectTenderAppFiles({ root, current: root });
2611
+ const result = generateTenderAppEnvTypes({
2612
+ files,
2613
+ mode: "local",
2614
+ });
2615
+ if (!result.ok) {
2616
+ if (command.json) {
2617
+ io.stdout(JSON.stringify({
2618
+ ok: false,
2619
+ command: command.command,
2620
+ dir: root,
2621
+ path: result.path,
2622
+ diagnostics: result.diagnostics,
2623
+ }, null, 2));
2624
+ }
2625
+ else {
2626
+ io.stdout(formatEnvTypesGenerationFailure(result));
2627
+ }
2628
+ return 1;
2629
+ }
2630
+ const absolutePath = path.join(root, result.path);
2631
+ const previous = await readFile(absolutePath, "utf8").catch((error) => {
2632
+ if (error &&
2633
+ typeof error === "object" &&
2634
+ error.code === "ENOENT") {
2635
+ return null;
2636
+ }
2637
+ throw error;
2638
+ });
2639
+ const changed = previous !== result.content;
2640
+ await mkdir(path.dirname(absolutePath), { recursive: true });
2641
+ await writeFile(absolutePath, result.content);
2642
+ if (command.json) {
2643
+ io.stdout(JSON.stringify({
2644
+ ok: true,
2645
+ command: command.command,
2646
+ dir: root,
2647
+ path: result.path,
2648
+ absolutePath,
2649
+ changed,
2650
+ bytes: Buffer.byteLength(result.content),
2651
+ diagnostics: result.diagnostics,
2652
+ }, null, 2));
2653
+ }
2654
+ else {
2655
+ io.stdout([
2656
+ `generated: ${path.join(command.dir, result.path)}`,
2657
+ `changed: ${changed ? "yes" : "no"}`,
2658
+ ].join("\n"));
2659
+ }
2660
+ return 0;
2661
+ }
2042
2662
  async function parseJsonResponse(response) {
2043
2663
  return (await response.json().catch(() => null));
2044
2664
  }
@@ -2076,6 +2696,119 @@ function parseSseLifecycleBlock(block) {
2076
2696
  return { raw: dataLines.join("\n") };
2077
2697
  }
2078
2698
  }
2699
+ function appendAnalyticsRange(params, range) {
2700
+ if (range === "7d" || range === "30d" || range === "90d") {
2701
+ params.set("rangePreset", range);
2702
+ return;
2703
+ }
2704
+ const [startDate, endDate] = range.split("..");
2705
+ if (startDate && endDate) {
2706
+ params.set("startDate", startDate);
2707
+ params.set("endDate", endDate);
2708
+ }
2709
+ }
2710
+ async function readAnalyticsSpec(input) {
2711
+ const raw = input.specPath === "-"
2712
+ ? input.stdin
2713
+ : await readFile(path.resolve(input.specPath), "utf8");
2714
+ if (!raw) {
2715
+ throw new TenderCliUsageError("--spec - requires JSON on stdin.");
2716
+ }
2717
+ try {
2718
+ return JSON.parse(raw);
2719
+ }
2720
+ catch {
2721
+ throw new TenderCliUsageError("--spec must contain valid JSON.");
2722
+ }
2723
+ }
2724
+ async function requestAnalyticsApi(input) {
2725
+ const params = new URLSearchParams();
2726
+ if (input.range) {
2727
+ appendAnalyticsRange(params, input.range);
2728
+ }
2729
+ if (input.includeCatalog) {
2730
+ params.set("includeCatalog", "1");
2731
+ }
2732
+ const suffix = input.analyticsPath ? `/${input.analyticsPath}` : "";
2733
+ const query = params.size > 0 ? `?${params.toString()}` : "";
2734
+ const response = await input.fetcher(`${input.baseUrl}/api/v1/artifacts/${encodeURIComponent(input.artifactId)}/analytics${suffix}${query}`, {
2735
+ method: input.method,
2736
+ headers: {
2737
+ authorization: `Bearer ${input.token}`,
2738
+ accept: "application/json",
2739
+ ...(input.body === undefined ? {} : { "content-type": "application/json" }),
2740
+ },
2741
+ body: input.body === undefined ? undefined : JSON.stringify(input.body),
2742
+ });
2743
+ const payload = await parseJsonResponse(response);
2744
+ if (!response.ok || !payload?.ok) {
2745
+ const reasonCode = (typeof payload?.reasonCode === "string" && payload.reasonCode) ||
2746
+ `http_${response.status}`;
2747
+ const message = (typeof payload?.message === "string" && payload.message) ||
2748
+ (typeof payload?.reasonCode === "string" && payload.reasonCode) ||
2749
+ `Analytics request failed with HTTP ${response.status}.`;
2750
+ throw new Error([
2751
+ message,
2752
+ `Scope: artifact ${input.artifactId}, analytics/${input.analyticsPath || "summary"}.`,
2753
+ `Reason: ${reasonCode}.`,
2754
+ `Example: ${analyticsCorrectedExample(input.artifactId, input.analyticsPath)}.`,
2755
+ ].join("\n"));
2756
+ }
2757
+ return payload;
2758
+ }
2759
+ function analyticsCorrectedExample(artifactId, analyticsPath) {
2760
+ if (analyticsPath === "capabilities") {
2761
+ return `tender app analytics capabilities ${artifactId} --include-catalog --range 30d --json`;
2762
+ }
2763
+ if (analyticsPath === "query") {
2764
+ return `tender app analytics query ${artifactId} --spec chart.json --json`;
2765
+ }
2766
+ if (analyticsPath === "suggestions") {
2767
+ return `tender app analytics suggestions ${artifactId} --range 30d --json`;
2768
+ }
2769
+ if (analyticsPath === "dashboards") {
2770
+ return `tender app analytics dashboards ${artifactId} --json`;
2771
+ }
2772
+ if (analyticsPath === "charts") {
2773
+ return `tender app analytics charts create ${artifactId} --dashboard analytics_dashboard_123 --title "Signup funnel" --spec chart.json --json`;
2774
+ }
2775
+ return `tender app analytics summary ${artifactId} --range 30d --json`;
2776
+ }
2777
+ function printAnalyticsPayload(command, io, payload, fallbackLines) {
2778
+ if (command.json) {
2779
+ io.stdout(JSON.stringify(payload, null, 2));
2780
+ }
2781
+ else {
2782
+ io.stdout(fallbackLines.join("\n"));
2783
+ }
2784
+ }
2785
+ function csvCell(value) {
2786
+ if (value === null || value === undefined) {
2787
+ return "";
2788
+ }
2789
+ const json = JSON.stringify(value);
2790
+ const text = typeof value === "string" ? value : typeof json === "string" ? json : String(value);
2791
+ if (/[",\n\r]/.test(text)) {
2792
+ return `"${text.replaceAll("\"", "\"\"")}"`;
2793
+ }
2794
+ return text;
2795
+ }
2796
+ function rowsToCsv(rows) {
2797
+ const records = rows.filter((row) => Boolean(row) && typeof row === "object" && !Array.isArray(row));
2798
+ const headers = Array.from(records.reduce((set, row) => {
2799
+ for (const key of Object.keys(row)) {
2800
+ set.add(key);
2801
+ }
2802
+ return set;
2803
+ }, new Set()));
2804
+ if (headers.length === 0) {
2805
+ return "";
2806
+ }
2807
+ return [
2808
+ headers.map(csvCell).join(","),
2809
+ ...records.map((row) => headers.map((header) => csvCell(row[header])).join(",")),
2810
+ ].join("\n");
2811
+ }
2079
2812
  function findSseBlockSeparator(buffer) {
2080
2813
  const unixIndex = buffer.indexOf("\n\n");
2081
2814
  const windowsIndex = buffer.indexOf("\r\n\r\n");
@@ -2377,7 +3110,7 @@ async function runAuthStatus(command, io, runtime) {
2377
3110
  `base_url: ${profile.baseUrl}`,
2378
3111
  `token_prefix: ${profile.tokenPrefix ?? "(unknown)"}`,
2379
3112
  `tenant_id: ${profile.tenantId ?? "(unknown)"}`,
2380
- `artifact_id: ${profile.artifactId ?? "(account)"}`,
3113
+ `app_id: ${profile.artifactId ?? "(account)"}`,
2381
3114
  `permissions: ${(profile.permissions ?? []).join(" ") || "(unknown)"}`,
2382
3115
  `expires_at: ${formatExpiry(profile.expiresAt) ?? "(unknown)"}`,
2383
3116
  ].join("\n"));
@@ -2502,7 +3235,7 @@ async function runAuthLogin(command, io, runtime) {
2502
3235
  "authenticated: true",
2503
3236
  `profile: ${command.saveProfile}`,
2504
3237
  `tenant_id: ${result.tenantId ?? "(unknown)"}`,
2505
- `artifact_id: ${result.artifactId ?? "(account)"}`,
3238
+ `app_id: ${result.artifactId ?? "(account)"}`,
2506
3239
  `permissions: ${result.permissions.join(" ") || "(unknown)"}`,
2507
3240
  `expires_at: ${result.expiresAt ?? "(unknown)"}`,
2508
3241
  ].join("\n"));
@@ -2706,7 +3439,7 @@ async function runArtifactsList(command, io, runtime) {
2706
3439
  io.stdout(JSON.stringify(result, null, 2));
2707
3440
  }
2708
3441
  else if (payload.artifacts.length === 0) {
2709
- io.stdout("No artifacts found.");
3442
+ io.stdout("No Tender App records found.");
2710
3443
  }
2711
3444
  else {
2712
3445
  io.stdout(payload.artifacts
@@ -2758,10 +3491,11 @@ async function runArtifactsCreate(command, io, runtime) {
2758
3491
  authSource: credentials.source,
2759
3492
  profile: credentials.profileName,
2760
3493
  tenantId: payload.tenantId ?? null,
3494
+ appId: payload.artifact.artifactId,
2761
3495
  artifact: payload.artifact,
2762
3496
  next: {
2763
- contextFetch: `tender artifacts context fetch ${payload.artifact.artifactId} --dir .`,
2764
- gitSetup: `tender artifacts git setup ${payload.artifact.artifactId} --dir .`,
3497
+ contextFetch: `tender app context fetch ${payload.artifact.artifactId} --dir .`,
3498
+ gitSetup: `tender app git setup ${payload.artifact.artifactId} --dir .`,
2765
3499
  },
2766
3500
  };
2767
3501
  if (command.json) {
@@ -2769,7 +3503,7 @@ async function runArtifactsCreate(command, io, runtime) {
2769
3503
  }
2770
3504
  else {
2771
3505
  io.stdout([
2772
- `artifact_id: ${payload.artifact.artifactId}`,
3506
+ `app_id: ${payload.artifact.artifactId}`,
2773
3507
  `name: ${payload.artifact.name}`,
2774
3508
  `preview_url: ${payload.artifact.previewUrl ?? ""}`,
2775
3509
  `next: ${result.next.contextFetch}`,
@@ -2806,6 +3540,7 @@ async function runArtifactsUpdate(command, io, runtime) {
2806
3540
  authSource: credentials.source,
2807
3541
  profile: credentials.profileName,
2808
3542
  tenantId: payload.tenantId ?? null,
3543
+ appId: payload.artifact.artifactId,
2809
3544
  artifact: payload.artifact,
2810
3545
  };
2811
3546
  if (command.json) {
@@ -2813,7 +3548,7 @@ async function runArtifactsUpdate(command, io, runtime) {
2813
3548
  }
2814
3549
  else {
2815
3550
  io.stdout([
2816
- `artifact_id: ${payload.artifact.artifactId}`,
3551
+ `app_id: ${payload.artifact.artifactId}`,
2817
3552
  `name: ${payload.artifact.name}`,
2818
3553
  ].join("\n"));
2819
3554
  }
@@ -2903,6 +3638,8 @@ function createGitSetupCommandPlan(input) {
2903
3638
  input.credentialHelper,
2904
3639
  ],
2905
3640
  ["git", "config", "--local", "credential.useHttpPath", "true"],
3641
+ ["git", "config", "--local", "pack.window", "0"],
3642
+ ["git", "config", "--local", "pack.depth", "0"],
2906
3643
  ];
2907
3644
  }
2908
3645
  async function applyGitSetup(input) {
@@ -2958,6 +3695,16 @@ async function applyGitSetup(input) {
2958
3695
  cwd: input.root,
2959
3696
  args: ["config", "--local", "credential.useHttpPath", "true"],
2960
3697
  });
3698
+ await runGitCommand({
3699
+ runtime: input.runtime,
3700
+ cwd: input.root,
3701
+ args: ["config", "--local", "pack.window", "0"],
3702
+ });
3703
+ await runGitCommand({
3704
+ runtime: input.runtime,
3705
+ cwd: input.root,
3706
+ args: ["config", "--local", "pack.depth", "0"],
3707
+ });
2961
3708
  }
2962
3709
  async function maybeCheckoutInitialArtifactSource(input) {
2963
3710
  const localHead = await runGitCommand({
@@ -3508,6 +4255,7 @@ async function runArtifactsInit(command, io, runtime) {
3508
4255
  ok: true,
3509
4256
  command: command.command,
3510
4257
  artifactId: command.artifactId,
4258
+ appId: command.artifactId,
3511
4259
  revision: context.revision,
3512
4260
  dir: root,
3513
4261
  remoteName: command.remoteName,
@@ -3545,7 +4293,7 @@ async function runArtifactsInit(command, io, runtime) {
3545
4293
  }
3546
4294
  else {
3547
4295
  io.stdout([
3548
- `artifact_id: ${command.artifactId}`,
4296
+ `app_id: ${command.artifactId}`,
3549
4297
  `context_revision: ${context.revision}`,
3550
4298
  `dir: ${root}`,
3551
4299
  `remote: ${command.remoteName}`,
@@ -3608,6 +4356,7 @@ async function postLifecycle(input) {
3608
4356
  authSource: credentials.source,
3609
4357
  profile: credentials.profileName,
3610
4358
  artifactId: input.command.artifactId,
4359
+ appId: input.command.artifactId,
3611
4360
  operation: payload.operation ?? input.operation,
3612
4361
  job: payload.job ?? null,
3613
4362
  result: payload.result ?? null,
@@ -3617,7 +4366,7 @@ async function postLifecycle(input) {
3617
4366
  }
3618
4367
  else {
3619
4368
  input.io.stdout([
3620
- `artifact_id: ${input.command.artifactId}`,
4369
+ `app_id: ${input.command.artifactId}`,
3621
4370
  `operation: ${result.operation}`,
3622
4371
  "status: completed",
3623
4372
  ].join("\n"));
@@ -3731,7 +4480,7 @@ async function runPreviewStatus(command, io, runtime) {
3731
4480
  }
3732
4481
  else {
3733
4482
  io.stdout([
3734
- `artifact_id: ${command.artifactId}`,
4483
+ `app_id: ${command.artifactId}`,
3735
4484
  `job_id: ${job.jobId}`,
3736
4485
  `status: ${result.status ?? "unknown"}`,
3737
4486
  ...(result.previewUrl ? [`preview_url: ${result.previewUrl}`] : []),
@@ -3801,6 +4550,7 @@ async function runPublish(command, io, runtime) {
3801
4550
  ok: true,
3802
4551
  command: command.command,
3803
4552
  artifactId: command.artifactId,
4553
+ appId: command.artifactId,
3804
4554
  commitSha: command.commitSha,
3805
4555
  dryRun: true,
3806
4556
  confirmed: false,
@@ -3820,7 +4570,7 @@ async function runPublish(command, io, runtime) {
3820
4570
  }
3821
4571
  else {
3822
4572
  io.stdout([
3823
- `artifact_id: ${command.artifactId}`,
4573
+ `app_id: ${command.artifactId}`,
3824
4574
  "dry_run: true",
3825
4575
  "next: rerun with --confirm publish to publish.",
3826
4576
  ].join("\n"));
@@ -3880,7 +4630,7 @@ async function runPublishStatus(command, io, runtime) {
3880
4630
  }
3881
4631
  else {
3882
4632
  io.stdout([
3883
- `artifact_id: ${command.artifactId}`,
4633
+ `app_id: ${command.artifactId}`,
3884
4634
  `job_id: ${job.jobId}`,
3885
4635
  `status: ${result.status ?? "unknown"}`,
3886
4636
  ...(result.publishedUrl
@@ -3995,6 +4745,226 @@ async function runGitRemote(command, io, runtime) {
3995
4745
  }
3996
4746
  return 0;
3997
4747
  }
4748
+ async function resolveAnalyticsCredentials(command, runtime) {
4749
+ return await resolveApiCredentials({
4750
+ baseUrl: command.baseUrl,
4751
+ flagToken: command.flagToken,
4752
+ profileName: command.profileName,
4753
+ env: runtime.env ?? process.env,
4754
+ });
4755
+ }
4756
+ async function runAnalyticsSummary(command, io, runtime) {
4757
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4758
+ const payload = await requestAnalyticsApi({
4759
+ artifactId: command.artifactId,
4760
+ analyticsPath: "",
4761
+ method: "GET",
4762
+ baseUrl: credentials.baseUrl,
4763
+ token: credentials.token,
4764
+ fetcher: runtime.fetcher ?? fetch,
4765
+ range: command.range,
4766
+ });
4767
+ const points = Array.isArray(payload.points) ? payload.points : [];
4768
+ printAnalyticsPayload(command, io, payload, [
4769
+ `app_id: ${command.artifactId}`,
4770
+ `source: ${String(payload.source ?? "unknown")}`,
4771
+ `points: ${points.length}`,
4772
+ ]);
4773
+ return 0;
4774
+ }
4775
+ async function runAnalyticsQuery(command, io, runtime) {
4776
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4777
+ const spec = await readAnalyticsSpec({
4778
+ specPath: command.specPath,
4779
+ stdin: runtime.stdin,
4780
+ });
4781
+ const payload = await requestAnalyticsApi({
4782
+ artifactId: command.artifactId,
4783
+ analyticsPath: "query",
4784
+ method: "POST",
4785
+ baseUrl: credentials.baseUrl,
4786
+ token: credentials.token,
4787
+ fetcher: runtime.fetcher ?? fetch,
4788
+ body: { spec },
4789
+ });
4790
+ const rows = Array.isArray(payload.rows) ? payload.rows : [];
4791
+ printAnalyticsPayload(command, io, payload, [
4792
+ `app_id: ${command.artifactId}`,
4793
+ `source: ${String(payload.source ?? "unknown")}`,
4794
+ `rows: ${rows.length}`,
4795
+ ]);
4796
+ return 0;
4797
+ }
4798
+ async function runAnalyticsCapabilities(command, io, runtime) {
4799
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4800
+ const payload = await requestAnalyticsApi({
4801
+ artifactId: command.artifactId,
4802
+ analyticsPath: "capabilities",
4803
+ method: "GET",
4804
+ baseUrl: credentials.baseUrl,
4805
+ token: credentials.token,
4806
+ fetcher: runtime.fetcher ?? fetch,
4807
+ range: command.range,
4808
+ includeCatalog: command.includeCatalog,
4809
+ });
4810
+ const commands = Array.isArray(payload.commands) ? payload.commands : [];
4811
+ const catalog = payload.catalog && typeof payload.catalog === "object"
4812
+ ? payload.catalog
4813
+ : null;
4814
+ const observedEvents = Array.isArray(catalog?.observedEvents)
4815
+ ? catalog.observedEvents
4816
+ : [];
4817
+ printAnalyticsPayload(command, io, payload, [
4818
+ `app_id: ${command.artifactId}`,
4819
+ `commands: ${commands.length}`,
4820
+ `catalog_events: ${observedEvents.length}`,
4821
+ ]);
4822
+ return 0;
4823
+ }
4824
+ async function runAnalyticsSuggestions(command, io, runtime) {
4825
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4826
+ const payload = await requestAnalyticsApi({
4827
+ artifactId: command.artifactId,
4828
+ analyticsPath: "suggestions",
4829
+ method: "POST",
4830
+ baseUrl: credentials.baseUrl,
4831
+ token: credentials.token,
4832
+ fetcher: runtime.fetcher ?? fetch,
4833
+ range: command.range,
4834
+ body: {},
4835
+ });
4836
+ const suggestions = Array.isArray(payload.suggestions) ? payload.suggestions : [];
4837
+ printAnalyticsPayload(command, io, payload, [
4838
+ `app_id: ${command.artifactId}`,
4839
+ `suggestions: ${suggestions.length}`,
4840
+ ]);
4841
+ return 0;
4842
+ }
4843
+ async function runAnalyticsDashboards(command, io, runtime) {
4844
+ if (command.name && command.dryRun) {
4845
+ const payload = {
4846
+ ok: true,
4847
+ dryRun: true,
4848
+ artifactId: command.artifactId,
4849
+ request: {
4850
+ name: command.name,
4851
+ },
4852
+ };
4853
+ printAnalyticsPayload(command, io, payload, [
4854
+ `app_id: ${command.artifactId}`,
4855
+ `name: ${command.name}`,
4856
+ "dry_run: true",
4857
+ ]);
4858
+ return 0;
4859
+ }
4860
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4861
+ const payload = await requestAnalyticsApi({
4862
+ artifactId: command.artifactId,
4863
+ analyticsPath: "dashboards",
4864
+ method: command.name ? "POST" : "GET",
4865
+ baseUrl: credentials.baseUrl,
4866
+ token: credentials.token,
4867
+ fetcher: runtime.fetcher ?? fetch,
4868
+ body: command.name ? { name: command.name } : undefined,
4869
+ });
4870
+ const dashboards = Array.isArray(payload.dashboards) ? payload.dashboards : [];
4871
+ printAnalyticsPayload(command, io, payload, [
4872
+ `app_id: ${command.artifactId}`,
4873
+ command.name
4874
+ ? `dashboard_id: ${String(payload.dashboard?.id ?? "")}`
4875
+ : `dashboards: ${dashboards.length}`,
4876
+ ]);
4877
+ return 0;
4878
+ }
4879
+ async function runAnalyticsExportCatalog(command, io, runtime) {
4880
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4881
+ const payload = await requestAnalyticsApi({
4882
+ artifactId: command.artifactId,
4883
+ analyticsPath: "capabilities",
4884
+ method: "GET",
4885
+ baseUrl: credentials.baseUrl,
4886
+ token: credentials.token,
4887
+ fetcher: runtime.fetcher ?? fetch,
4888
+ range: command.range,
4889
+ includeCatalog: true,
4890
+ });
4891
+ const catalog = payload.catalog && typeof payload.catalog === "object"
4892
+ ? payload.catalog
4893
+ : null;
4894
+ const exportPayload = {
4895
+ ok: true,
4896
+ artifactId: command.artifactId,
4897
+ format: command.format,
4898
+ catalog,
4899
+ };
4900
+ io.stdout(JSON.stringify(exportPayload, null, 2));
4901
+ return 0;
4902
+ }
4903
+ async function runAnalyticsExportQuery(command, io, runtime) {
4904
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4905
+ const spec = await readAnalyticsSpec({
4906
+ specPath: command.specPath,
4907
+ stdin: runtime.stdin,
4908
+ });
4909
+ const payload = await requestAnalyticsApi({
4910
+ artifactId: command.artifactId,
4911
+ analyticsPath: "query",
4912
+ method: "POST",
4913
+ baseUrl: credentials.baseUrl,
4914
+ token: credentials.token,
4915
+ fetcher: runtime.fetcher ?? fetch,
4916
+ body: { spec },
4917
+ });
4918
+ const rows = Array.isArray(payload.rows) ? payload.rows : [];
4919
+ if (command.format === "csv") {
4920
+ io.stdout(rowsToCsv(rows));
4921
+ return 0;
4922
+ }
4923
+ io.stdout(JSON.stringify(payload, null, 2));
4924
+ return 0;
4925
+ }
4926
+ async function runAnalyticsChartsCreate(command, io, runtime) {
4927
+ const spec = await readAnalyticsSpec({
4928
+ specPath: command.specPath,
4929
+ stdin: runtime.stdin,
4930
+ });
4931
+ const body = {
4932
+ dashboardId: command.dashboardId,
4933
+ title: command.title,
4934
+ spec,
4935
+ layout: {},
4936
+ };
4937
+ if (command.dryRun) {
4938
+ const payload = {
4939
+ ok: true,
4940
+ dryRun: true,
4941
+ artifactId: command.artifactId,
4942
+ request: body,
4943
+ };
4944
+ printAnalyticsPayload(command, io, payload, [
4945
+ `app_id: ${command.artifactId}`,
4946
+ `dashboard_id: ${command.dashboardId}`,
4947
+ `title: ${command.title}`,
4948
+ "dry_run: true",
4949
+ ]);
4950
+ return 0;
4951
+ }
4952
+ const credentials = await resolveAnalyticsCredentials(command, runtime);
4953
+ const payload = await requestAnalyticsApi({
4954
+ artifactId: command.artifactId,
4955
+ analyticsPath: "charts",
4956
+ method: "POST",
4957
+ baseUrl: credentials.baseUrl,
4958
+ token: credentials.token,
4959
+ fetcher: runtime.fetcher ?? fetch,
4960
+ body,
4961
+ });
4962
+ printAnalyticsPayload(command, io, payload, [
4963
+ `app_id: ${command.artifactId}`,
4964
+ `chart_id: ${String(payload.chart?.id ?? "")}`,
4965
+ ]);
4966
+ return 0;
4967
+ }
3998
4968
  export async function runTenderCli(args, io = {
3999
4969
  stdout: (message) => console.log(message),
4000
4970
  stderr: (message) => console.error(message),
@@ -4023,6 +4993,9 @@ export async function runTenderCli(args, io = {
4023
4993
  else if (command.topic === "artifacts doctor") {
4024
4994
  io.stdout(doctorHelp());
4025
4995
  }
4996
+ else if (command.topic === "artifacts generate-env-types") {
4997
+ io.stdout(generateEnvTypesHelp());
4998
+ }
4026
4999
  else if (command.topic === "artifacts list") {
4027
5000
  io.stdout(artifactsListHelp());
4028
5001
  }
@@ -4068,6 +5041,36 @@ export async function runTenderCli(args, io = {
4068
5041
  else if (command.topic === "artifacts publish watch") {
4069
5042
  io.stdout(publishWatchHelp());
4070
5043
  }
5044
+ else if (command.topic === "artifacts analytics") {
5045
+ io.stdout(analyticsHelp());
5046
+ }
5047
+ else if (command.topic === "artifacts analytics summary") {
5048
+ io.stdout(analyticsSummaryHelp());
5049
+ }
5050
+ else if (command.topic === "artifacts analytics query") {
5051
+ io.stdout(analyticsQueryHelp());
5052
+ }
5053
+ else if (command.topic === "artifacts analytics capabilities") {
5054
+ io.stdout(analyticsCapabilitiesHelp());
5055
+ }
5056
+ else if (command.topic === "artifacts analytics suggestions") {
5057
+ io.stdout(analyticsSuggestionsHelp());
5058
+ }
5059
+ else if (command.topic === "artifacts analytics dashboards") {
5060
+ io.stdout(analyticsDashboardsHelp());
5061
+ }
5062
+ else if (command.topic === "artifacts analytics export") {
5063
+ io.stdout(analyticsExportHelp());
5064
+ }
5065
+ else if (command.topic === "artifacts analytics export catalog") {
5066
+ io.stdout(analyticsExportCatalogHelp());
5067
+ }
5068
+ else if (command.topic === "artifacts analytics export query") {
5069
+ io.stdout(analyticsExportQueryHelp());
5070
+ }
5071
+ else if (command.topic === "artifacts analytics charts create") {
5072
+ io.stdout(analyticsChartsCreateHelp());
5073
+ }
4071
5074
  else if (command.topic === "artifacts") {
4072
5075
  io.stdout(artifactsHelp());
4073
5076
  }
@@ -4094,6 +5097,9 @@ export async function runTenderCli(args, io = {
4094
5097
  if (command.command === "artifacts init") {
4095
5098
  return await runArtifactsInit(command, io, runtime);
4096
5099
  }
5100
+ if (command.command === "artifacts generate-env-types") {
5101
+ return await runGenerateEnvTypes(command, io);
5102
+ }
4097
5103
  if (command.command === "artifacts context fetch") {
4098
5104
  return await runContextFetch(command, io, runtime);
4099
5105
  }
@@ -4133,6 +5139,30 @@ export async function runTenderCli(args, io = {
4133
5139
  if (command.command === "artifacts publish watch") {
4134
5140
  return await runPublishWatch(command, io, runtime);
4135
5141
  }
5142
+ if (command.command === "artifacts analytics summary") {
5143
+ return await runAnalyticsSummary(command, io, runtime);
5144
+ }
5145
+ if (command.command === "artifacts analytics query") {
5146
+ return await runAnalyticsQuery(command, io, runtime);
5147
+ }
5148
+ if (command.command === "artifacts analytics capabilities") {
5149
+ return await runAnalyticsCapabilities(command, io, runtime);
5150
+ }
5151
+ if (command.command === "artifacts analytics suggestions") {
5152
+ return await runAnalyticsSuggestions(command, io, runtime);
5153
+ }
5154
+ if (command.command === "artifacts analytics dashboards") {
5155
+ return await runAnalyticsDashboards(command, io, runtime);
5156
+ }
5157
+ if (command.command === "artifacts analytics export catalog") {
5158
+ return await runAnalyticsExportCatalog(command, io, runtime);
5159
+ }
5160
+ if (command.command === "artifacts analytics export query") {
5161
+ return await runAnalyticsExportQuery(command, io, runtime);
5162
+ }
5163
+ if (command.command === "artifacts analytics charts create") {
5164
+ return await runAnalyticsChartsCreate(command, io, runtime);
5165
+ }
4136
5166
  if (command.command === "artifacts git remote") {
4137
5167
  return await runGitRemote(command, io, runtime);
4138
5168
  }
@@ -4146,9 +5176,9 @@ export async function runTenderCli(args, io = {
4146
5176
  }
4147
5177
  const currentFile = fileURLToPath(import.meta.url);
4148
5178
  function shouldReadEntrypointStdin(args) {
4149
- return (args[0] === "artifacts" &&
4150
- args[1] === "git" &&
4151
- args[2] === "credential");
5179
+ return ((args[0] === "artifacts" || args[0] === "app") &&
5180
+ ((args[1] === "git" && args[2] === "credential") ||
5181
+ (args[1] === "analytics" && args.includes("--spec") && args.includes("-"))));
4152
5182
  }
4153
5183
  async function readEntrypointStdin() {
4154
5184
  if (process.stdin.isTTY) {