bdy 1.23.11-dev → 1.23.13-dev-target-commands

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 (53) hide show
  1. package/distTs/detect-rules.json +351 -0
  2. package/distTs/package.json +3 -1
  3. package/distTs/src/api/client.js +222 -12
  4. package/distTs/src/cliIndex.js +4 -0
  5. package/distTs/src/command/artifact/list.js +2 -6
  6. package/distTs/src/command/distro/list.js +1 -0
  7. package/distTs/src/command/distro/route/update.js +1 -1
  8. package/distTs/src/command/distro/update.js +9 -9
  9. package/distTs/src/command/environment/create.js +70 -0
  10. package/distTs/src/command/environment/delete.js +29 -0
  11. package/distTs/src/command/environment/get.js +48 -0
  12. package/distTs/src/command/environment/list.js +45 -0
  13. package/distTs/src/command/environment/resolve.js +22 -0
  14. package/distTs/src/command/environment/update.js +59 -0
  15. package/distTs/src/command/environment.js +20 -0
  16. package/distTs/src/command/pipeline/run/apply.js +62 -0
  17. package/distTs/src/command/target/create.js +33 -0
  18. package/distTs/src/command/target/delete.js +30 -0
  19. package/distTs/src/command/target/exec/command.js +103 -0
  20. package/distTs/src/command/target/exec/kill.js +31 -0
  21. package/distTs/src/command/target/exec/list.js +53 -0
  22. package/distTs/src/command/target/exec/logs.js +27 -0
  23. package/distTs/src/command/target/exec/status.js +44 -0
  24. package/distTs/src/command/target/exec.js +24 -0
  25. package/distTs/src/command/target/get.js +63 -0
  26. package/distTs/src/command/target/list.js +49 -0
  27. package/distTs/src/command/target/scope.js +108 -0
  28. package/distTs/src/command/target/update.js +31 -0
  29. package/distTs/src/command/target.js +22 -0
  30. package/distTs/src/command/yaml/actions/detect.js +268 -0
  31. package/distTs/src/command/yaml/actions/info.js +56 -0
  32. package/distTs/src/command/yaml/actions/list.js +70 -0
  33. package/distTs/src/command/yaml/actions/schema.js +104 -0
  34. package/distTs/src/command/yaml/actions.js +13 -0
  35. package/distTs/src/command/yaml/agents.js +88 -0
  36. package/distTs/src/command/yaml/cache.js +98 -0
  37. package/distTs/src/command/yaml/init.js +110 -0
  38. package/distTs/src/command/yaml/pipeline.js +42 -0
  39. package/distTs/src/command/yaml/render.js +83 -0
  40. package/distTs/src/command/yaml/schemaUtils.js +139 -0
  41. package/distTs/src/command/yaml/validate.js +259 -0
  42. package/distTs/src/command/yaml.js +18 -0
  43. package/distTs/src/diskCache.js +82 -0
  44. package/distTs/src/input.js +65 -0
  45. package/distTs/src/output.js +21 -2
  46. package/distTs/src/texts.js +252 -27
  47. package/distTs/src/utils.js +18 -2
  48. package/package.json +3 -1
  49. package/distTs/README.md +0 -181
  50. package/distTs/src/command/project/get.js +0 -18
  51. package/distTs/src/command/project/set.js +0 -31
  52. package/distTs/src/command/sandbox/get/yaml.js +0 -30
  53. package/distTs/src/command/vt/scrape.js +0 -193
@@ -0,0 +1,351 @@
1
+ {
2
+ "BUILD": {
3
+ "files": ["package.json", "requirements.txt", "pyproject.toml", "go.mod", "Gemfile", "pom.xml", "build.gradle", "build.gradle.kts", "Cargo.toml", "composer.json", "pubspec.yaml", "Makefile", "CMakeLists.txt"],
4
+ "packages": ["eslint", "oxlint", "@oxlint/cli", "@biomejs/biome", "prettier", "stylelint", "xo", "standard", "typescript"]
5
+ },
6
+ "DOCKERFILE": {
7
+ "files": ["Dockerfile", "Containerfile", "compose.yaml", "compose.yml", "docker-compose.yml", "docker-compose.yaml"]
8
+ },
9
+ "DOCKER_PUSH": {
10
+ "files": ["Dockerfile", "Containerfile"]
11
+ },
12
+ "RUN_DOCKER_CONTAINER": {
13
+ "files": ["Dockerfile", "Containerfile", "compose.yaml", "compose.yml", "docker-compose.yml"]
14
+ },
15
+ "DOCKERFILE_LINTER": {
16
+ "files": ["Dockerfile", "Containerfile"]
17
+ },
18
+ "DOCKER": {
19
+ "files": ["Dockerfile", "Containerfile", "compose.yaml", "compose.yml", "docker-compose.yml"]
20
+ },
21
+ "DOCKER_BUILD_MULTI_ARCH": {
22
+ "files": ["Dockerfile", "Containerfile"]
23
+ },
24
+ "NATIVE_BUILD_DOCKER_CLI": {
25
+ "files": ["Dockerfile", "Containerfile"]
26
+ },
27
+ "PROMOTE_IMAGE": {
28
+ "files": ["Dockerfile", "Containerfile"]
29
+ },
30
+ "KUBERNETES_APPLY": {
31
+ "files": ["k8s/", "kubernetes/", "kustomization.yaml", "kustomization.yml", "Kustomization"],
32
+ "packages": ["@aws-sdk/client-eks", "@google-cloud/container", "@azure/arm-containerservice"]
33
+ },
34
+ "KUBERNETES_SET_IMAGE": {
35
+ "files": ["k8s/", "kubernetes/"]
36
+ },
37
+ "KUBERNETES_RUN_POD": {
38
+ "files": ["k8s/", "kubernetes/"]
39
+ },
40
+ "KUBERNETES_RUN_JOB": {
41
+ "files": ["k8s/", "kubernetes/"]
42
+ },
43
+ "KUBERNETES_CLI": {
44
+ "files": ["k8s/", "kubernetes/", "kustomization.yaml", "kustomization.yml", "Kustomization"],
45
+ "packages": ["@kubernetes/client-node", "@aws-sdk/client-eks", "@google-cloud/container", "@azure/arm-containerservice"]
46
+ },
47
+ "HELM": {
48
+ "files": ["Chart.yaml", "helm/", "charts/"]
49
+ },
50
+ "WAIT_FOR_APPLY": {
51
+ "files": ["k8s/", "kubernetes/"]
52
+ },
53
+ "AMAZON_S3": {
54
+ "packages": ["aws-sdk", "@aws-sdk/client-s3"]
55
+ },
56
+ "AWS_CLI": {
57
+ "files": ["buildspec.yml"],
58
+ "packages": ["aws-sdk", "@aws-sdk/*"]
59
+ },
60
+ "AWS_CLI_2": {
61
+ "files": ["buildspec.yml"],
62
+ "packages": ["aws-sdk", "@aws-sdk/*"]
63
+ },
64
+ "AWS_LAMBDA_DEPLOY": {
65
+ "files": ["serverless.yml", "serverless.yaml", "samconfig.toml", "sam-template.yaml"],
66
+ "packages": ["aws-sdk", "@aws-sdk/client-lambda"]
67
+ },
68
+ "LAMBDA": {
69
+ "files": ["serverless.yml", "samconfig.toml"],
70
+ "packages": ["@aws-sdk/client-lambda"]
71
+ },
72
+ "AWS_ECS": {
73
+ "files": ["ecs-task-definition.json", "task-definition.json"],
74
+ "packages": ["@aws-sdk/client-ecs"]
75
+ },
76
+ "CODE_DEPLOY": {
77
+ "files": ["appspec.yml", "appspec.yaml"]
78
+ },
79
+ "ELASTIC_BEANSTALK": {
80
+ "files": [".elasticbeanstalk/"]
81
+ },
82
+ "MONITOR": {
83
+ "files": [".elasticbeanstalk/"]
84
+ },
85
+ "AWS_CLOUD_FORMATION": {
86
+ "files": ["cloudformation/"]
87
+ },
88
+ "CLOUD_FRONT": {
89
+ "packages": ["aws-sdk", "@aws-sdk/client-cloudfront"]
90
+ },
91
+ "CODE_PIPELINE": {
92
+ "files": ["buildspec.yml"]
93
+ },
94
+ "AWS_APP_RUNNER_DEPLOY": {
95
+ "packages": ["@aws-sdk/client-apprunner"]
96
+ },
97
+ "AWS_APP_RUNNER_MONITOR": {
98
+ "packages": ["@aws-sdk/client-apprunner"]
99
+ },
100
+ "AWS_CDK_CLI": {
101
+ "files": ["cdk.json"],
102
+ "packages": ["aws-cdk-lib", "aws-cdk"]
103
+ },
104
+ "DOWNLOAD_S3": {
105
+ "packages": ["aws-sdk", "@aws-sdk/client-s3"]
106
+ },
107
+ "GOOGLE_CLOUD_STORAGE": {
108
+ "packages": ["@google-cloud/storage"]
109
+ },
110
+ "GOOGLE_CLOUD_CLI": {
111
+ "packages": ["@google-cloud/*"]
112
+ },
113
+ "GOOGLE_APP_DEPLOY": {
114
+ "files": ["app.yaml"]
115
+ },
116
+ "GOOGLE_FUNCTION_DEPLOY": {
117
+ "files": ["firebase.json"],
118
+ "packages": ["@google-cloud/functions-framework"]
119
+ },
120
+ "GOOGLE_FUNCTION_INVOKE": {
121
+ "packages": ["@google-cloud/functions-framework"]
122
+ },
123
+ "GOOGLE_CLOUD_RUN_DEPLOY": {
124
+ "files": ["Dockerfile", "Containerfile"]
125
+ },
126
+ "GOOGLE_CDN_INVALIDATE": {
127
+ "packages": ["@google-cloud/compute"]
128
+ },
129
+ "FIREBASE": {
130
+ "files": ["firebase.json", ".firebaserc"],
131
+ "packages": ["firebase", "firebase-admin"]
132
+ },
133
+ "DOWNLOAD_GCS": {
134
+ "packages": ["@google-cloud/storage"]
135
+ },
136
+ "AZURE": {
137
+ "files": ["azure-pipelines.yml"]
138
+ },
139
+ "AZURE_CLI": {
140
+ "files": ["azure-pipelines.yml"],
141
+ "packages": ["@azure/*"]
142
+ },
143
+ "AZURE_STORAGE": {
144
+ "packages": ["@azure/storage-blob"]
145
+ },
146
+ "HEROKU": {
147
+ "files": ["Procfile"]
148
+ },
149
+ "HEROKU_CLI": {
150
+ "files": ["Procfile"]
151
+ },
152
+ "NETLIFY": {
153
+ "files": ["netlify.toml"]
154
+ },
155
+ "TERRAFORM": {
156
+ "files": ["*.tf", "*.tofu", "terraform/", ".terraform/"]
157
+ },
158
+ "ANDROID_SIGN": {
159
+ "files": ["android/", "app/src/main/AndroidManifest.xml"]
160
+ },
161
+ "ANDROID_SIGN_BUNDLE": {
162
+ "files": ["android/", "app/src/main/AndroidManifest.xml"]
163
+ },
164
+ "ANDROID_PUBLISH_APK": {
165
+ "files": ["android/", "app/src/main/AndroidManifest.xml"]
166
+ },
167
+ "ANDROID_PUBLISH_APP_BUNDLE": {
168
+ "files": ["android/", "app/src/main/AndroidManifest.xml"]
169
+ },
170
+ "FASTLANE_ANDROID": {
171
+ "files": ["fastlane/", "android/"]
172
+ },
173
+ "NATIVE_BUILD_MAC": {
174
+ "files": ["*.xcodeproj", "*.xcworkspace"]
175
+ },
176
+ "NATIVE_BUILD_MAC_VM": {
177
+ "files": ["*.xcodeproj", "*.xcworkspace"]
178
+ },
179
+ "NATIVE_BUILD_MAC_SIGN": {
180
+ "files": ["*.xcodeproj", "*.xcworkspace"]
181
+ },
182
+ "NATIVE_BUILD_MAC_DEPLOY": {
183
+ "files": ["*.xcodeproj", "*.xcworkspace"]
184
+ },
185
+ "NATIVE_BUILD_MAC_REACT": {
186
+ "files": ["ios/"],
187
+ "packages": ["react-native"]
188
+ },
189
+ "NATIVE_BUILD_MAC_CORDOVA": {
190
+ "packages": ["cordova"]
191
+ },
192
+ "NATIVE_BUILD_MAC_FASTLANE": {
193
+ "files": ["fastlane/Fastfile"]
194
+ },
195
+ "NATIVE_BUILD_MAC_FLUTTER": {
196
+ "files": ["pubspec.yaml", "ios/"]
197
+ },
198
+ "PLAYWRIGHT": {
199
+ "files": ["playwright.config.*"],
200
+ "packages": ["@playwright/test", "playwright"]
201
+ },
202
+ "CYPRESS": {
203
+ "files": ["cypress.config.*", "cypress/"],
204
+ "packages": ["cypress"]
205
+ },
206
+ "STORYBOOK": {
207
+ "files": [".storybook/"],
208
+ "packages": ["storybook", "@storybook/react"]
209
+ },
210
+ "LIGHTHOUSE": {
211
+ "packages": ["lighthouse"]
212
+ },
213
+ "JMETER_CLI": {
214
+ "files": ["*.jmx"]
215
+ },
216
+ "SNYK_CLI": {
217
+ "files": [".snyk"],
218
+ "packages": ["snyk"]
219
+ },
220
+ "STACK_HAWK_CLI": {
221
+ "files": ["stackhawk.yml"]
222
+ },
223
+ "BLACKFIRE_PHP": {
224
+ "packages": ["blackfire/php-sdk"]
225
+ },
226
+ "BLACKFIRE_PYTHON": {
227
+ "packages": ["blackfire"]
228
+ },
229
+ "BLACKFIRE_GO": {
230
+ "packages": ["github.com/blackfireio/go-blackfire"]
231
+ },
232
+ "SENTRY": {
233
+ "packages": ["@sentry/node", "@sentry/browser", "@sentry/react"]
234
+ },
235
+ "SENTRY_ENTERPRISE": {
236
+ "packages": ["@sentry/node", "@sentry/browser"]
237
+ },
238
+ "NEW_RELIC": {
239
+ "packages": ["newrelic"]
240
+ },
241
+ "NEW_RELIC_CLI": {
242
+ "packages": ["newrelic"]
243
+ },
244
+ "DATADOG": {
245
+ "packages": ["dd-trace", "datadog-metrics"]
246
+ },
247
+ "DATADOG_STATUS_CHECK": {
248
+ "packages": ["dd-trace"]
249
+ },
250
+ "ROLLBAR": {
251
+ "packages": ["rollbar"]
252
+ },
253
+ "HONEYBADGER": {
254
+ "packages": ["@honeybadger-io/js"]
255
+ },
256
+ "BUGSNAG": {
257
+ "packages": ["@bugsnag/js", "@bugsnag/node"]
258
+ },
259
+ "RAYGUN": {
260
+ "packages": ["raygun"]
261
+ },
262
+ "LOGGLY": {
263
+ "packages": ["node-loggly-bulk", "winston-loggly-bulk"]
264
+ },
265
+ "DO_SPACES": {
266
+ "packages": ["aws-sdk", "@aws-sdk/client-s3"]
267
+ },
268
+ "GIT_HUB_RELEASE": {
269
+ "files": [".github/workflows/"]
270
+ },
271
+ "GIT_HUB_CLI": {
272
+ "files": [".github/workflows/"]
273
+ },
274
+ "GIT_LAB_CLI": {
275
+ "files": [".gitlab-ci.yml"]
276
+ },
277
+ "SHOPIFY": {
278
+ "files": ["shopify.app.toml"],
279
+ "packages": ["@shopify/shopify-api"]
280
+ },
281
+ "SHOPIFY_CLI": {
282
+ "files": ["shopify.app.toml"],
283
+ "packages": ["@shopify/cli"]
284
+ },
285
+ "SHOPIFY_THEMEKIT_CLI": {
286
+ "files": ["shopify.app.toml"]
287
+ },
288
+ "WP_CLI": {
289
+ "files": ["wp-config.php", "wp-content/"]
290
+ },
291
+ "CONTENTFUL_CLI": {
292
+ "packages": ["contentful", "contentful-management"]
293
+ },
294
+ "MYSQL_CLI": {
295
+ "packages": ["mysql", "mysql2", "sequelize", "typeorm", "prisma", "drizzle-orm"]
296
+ },
297
+ "CLOUDFLARE": {
298
+ "files": ["wrangler.toml", "wrangler.json", "wrangler.jsonc"],
299
+ "packages": ["wrangler"]
300
+ },
301
+ "NATIVE_BUILD_WINDOWS": {
302
+ "files": ["*.sln", "*.slnx", "*.csproj"]
303
+ },
304
+ "GIT_CRYPT_UNLOCK": {
305
+ "files": [".git-crypt/"]
306
+ },
307
+ "GIT_CRYPT_LOCK": {
308
+ "files": [".git-crypt/"]
309
+ },
310
+ "JIRA_BUILD": {
311
+ "files": [".jira/"]
312
+ },
313
+ "JIRA_DEPLOYMENT": {
314
+ "files": [".jira/"]
315
+ },
316
+ "NPM_PUBLISH": {
317
+ "files": ["package.json"]
318
+ },
319
+ "DOCTL": {
320
+ "files": [".do/"],
321
+ "packages": ["digitalocean", "do-wrapper"]
322
+ },
323
+ "DIGITAL_OCEAN_CDN": {
324
+ "files": [".do/"],
325
+ "packages": ["digitalocean", "do-wrapper"]
326
+ },
327
+ "SLACK": {
328
+ "packages": ["@slack/web-api", "@slack/bolt", "@slack/webhook"]
329
+ },
330
+ "DISCORD2": {
331
+ "packages": ["discord.js", "discord-webhook-node"]
332
+ },
333
+ "MICROSOFT_TEAMS": {
334
+ "packages": ["botbuilder", "@microsoft/teams-js"]
335
+ },
336
+ "TELEGRAM": {
337
+ "packages": ["telegraf", "node-telegram-bot-api", "grammy"]
338
+ },
339
+ "EMAIL": {
340
+ "packages": ["nodemailer", "@sendgrid/mail", "postmark", "mailgun-js"]
341
+ },
342
+ "POWERSHELL": {
343
+ "files": ["*.ps1", "*.psm1"]
344
+ },
345
+ "GHOST_INSPECTOR_CLI": {
346
+ "packages": ["ghost-inspector"]
347
+ },
348
+ "BACKBLAZE_B2": {
349
+ "packages": ["backblaze-b2"]
350
+ }
351
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.23.11-dev",
4
+ "version": "1.23.13-dev-target-commands",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -27,6 +27,8 @@
27
27
  "e2e:tunnel": "vitest run --config e2e/vitest.config.ts e2e/modules/tunnel/",
28
28
  "e2e:agent": "vitest run --config e2e/vitest.config.ts e2e/modules/agent/",
29
29
  "e2e:distro": "vitest run --config e2e/vitest.config.ts e2e/modules/distro/",
30
+ "e2e:target": "vitest run --config e2e/vitest.config.ts e2e/modules/target/",
31
+ "e2e:environment": "vitest run --config e2e/vitest.config.ts e2e/modules/environment/",
30
32
  "unit": "vitest run --config vitest.config.ts"
31
33
  },
32
34
  "files": [
@@ -16,6 +16,25 @@ const cfg_1 = __importDefault(require("../tunnel/cfg"));
16
16
  * echo back the escaped form - callers comparing a response against the names
17
17
  * they passed in must apply the same mapping.
18
18
  */
19
+ const RETRIABLE_NETWORK_ERROR = /ECONNREFUSED|ECONNRESET|ETIMEDOUT/;
20
+ // undici headers can be string | string[]; callers want the first value.
21
+ const headerValue = (h) => Array.isArray(h) ? h[0] : h;
22
+ // How long to wait before retrying a transient status on an idempotent
23
+ // request, or null when a retry makes no sense (non-retriable status, or a
24
+ // rate limit window that resets too far in the future to wait for).
25
+ const retryDelay = (status, attempt, rateLimitReset) => {
26
+ if (status === 429) {
27
+ if (!rateLimitReset)
28
+ return null;
29
+ const ms = parseInt(rateLimitReset, 10) * 1000 - Date.now();
30
+ if (ms <= 0)
31
+ return 1000;
32
+ return ms > 15000 ? null : ms + 500;
33
+ }
34
+ return [502, 503, 504].includes(status) ? attempt * 1000 : null;
35
+ };
36
+ const RATE_LIMIT_WARN_THRESHOLD = 25;
37
+ let rateLimitWarned = false;
19
38
  const formDataFileName = (name) => name.replace(/["\r\n]/g, (c) => ({ '"': '%22', '\r': '%0D', '\n': '%0A' })[c]);
20
39
  exports.formDataFileName = formDataFileName;
21
40
  class ApiClient {
@@ -112,20 +131,41 @@ class ApiClient {
112
131
  logger_1.default.debug(headers);
113
132
  logger_1.default.debug('BODY');
114
133
  logger_1.default.debug(bodyParsed);
115
- try {
116
- response = await this.client.request(opts);
117
- rateLimitReset = response.headers['x-rate-limit-reset'];
134
+ // Transient failures (rate limit with a nearby reset, 5xx, connection
135
+ // resets) are retried with a backoff, but only for idempotent requests -
136
+ // retrying a POST could duplicate the operation.
137
+ const maxAttempts = method === 'GET' ? 3 : 1;
138
+ for (let attempt = 1;; attempt += 1) {
139
+ try {
140
+ response = await this.client.request(opts);
141
+ }
142
+ catch (err) {
143
+ logger_1.default.debug('API CLIENT RESPONSE ERROR');
144
+ logger_1.default.debug(err);
145
+ const retriable = RETRIABLE_NETWORK_ERROR.test(err.message);
146
+ if (retriable && attempt < maxAttempts) {
147
+ await (0, utils_1.sleep)(attempt * 1000);
148
+ continue;
149
+ }
150
+ throw new Error(retriable ? texts_1.ERR_REST_API_CONNECT_ERROR : texts_1.ERR_REST_API_GENERAL_ERROR, { cause: err });
151
+ }
152
+ rateLimitReset = headerValue(response.headers['x-rate-limit-reset']);
118
153
  status = response.statusCode;
119
154
  responseBody = response.body;
120
155
  logger_1.default.debug(`API CLIENT RESPONSE STATUS: ${status}`);
156
+ const delay = attempt < maxAttempts
157
+ ? retryDelay(status, attempt, rateLimitReset)
158
+ : null;
159
+ if (delay === null)
160
+ break;
161
+ await responseBody.dump();
162
+ logger_1.default.debug(`API CLIENT RETRY IN ${delay}ms`);
163
+ await (0, utils_1.sleep)(delay);
121
164
  }
122
- catch (err) {
123
- logger_1.default.debug('API CLIENT RESPONSE ERROR');
124
- logger_1.default.debug(err);
125
- if (/ECONNREFUSED|ECONNRESET|ETIMEDOUT/.test(err.message)) {
126
- throw new Error(texts_1.ERR_REST_API_CONNECT_ERROR, { cause: err });
127
- }
128
- throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR, { cause: err });
165
+ this.warnRateLimitLow(headerValue(response.headers['x-rate-limit-remaining']), rateLimitReset);
166
+ if (status === 429) {
167
+ await responseBody.dump();
168
+ throw new Error((0, texts_1.ERR_REST_API_RATE_LIMIT)(rateLimitReset));
129
169
  }
130
170
  if (status === 401) {
131
171
  await responseBody.dump();
@@ -185,7 +225,7 @@ class ApiClient {
185
225
  if (status === 404)
186
226
  throw new Error(texts_1.ERR_REST_API_RESOURCE_NOT_FOUND);
187
227
  else
188
- throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
228
+ throw new Error((0, texts_1.ERR_REST_API_HTTP_ERROR)(status));
189
229
  }
190
230
  if ([200, 201].includes(status)) {
191
231
  if (parseResponseBody) {
@@ -221,9 +261,23 @@ class ApiClient {
221
261
  }
222
262
  else {
223
263
  await responseBody.dump();
224
- throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
264
+ throw new Error((0, texts_1.ERR_REST_API_HTTP_ERROR)(status));
225
265
  }
226
266
  }
267
+ // Set by the CLI bootstrap (Input.restApiTokenClient); the transport layer
268
+ // only detects the condition and leaves rendering to the caller, so
269
+ // non-interactive consumers (MCP proxy) stay silent.
270
+ static onRateLimitLow;
271
+ // One-time notification when the rate limit window is nearly exhausted.
272
+ warnRateLimitLow(remaining, reset) {
273
+ if (rateLimitWarned || !remaining || !ApiClient.onRateLimitLow)
274
+ return;
275
+ const left = parseInt(remaining, 10);
276
+ if (Number.isNaN(left) || left > RATE_LIMIT_WARN_THRESHOLD)
277
+ return;
278
+ rateLimitWarned = true;
279
+ ApiClient.onRateLimitLow(remaining, reset);
280
+ }
227
281
  async getPipelineRunActionLogs(workspace, project, pipelineId, executionId, actionExecutionId, offset, limit) {
228
282
  const query = {
229
283
  offset: String(offset),
@@ -563,6 +617,162 @@ class ApiClient {
563
617
  q.project = project;
564
618
  return await this.getResourceByIdentifier(workspace, q);
565
619
  }
620
+ // Target methods
621
+ targetScopeQuery(scope) {
622
+ const query = {};
623
+ if (scope.project)
624
+ query.project_name = scope.project;
625
+ if (scope.pipelineId)
626
+ query.pipeline_id = scope.pipelineId.toString();
627
+ if (scope.environmentId)
628
+ query.environment_id = scope.environmentId;
629
+ return query;
630
+ }
631
+ async getTargets(workspace, filters = {}) {
632
+ return await this.request({
633
+ method: 'GET',
634
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets`,
635
+ query: this.targetScopeQuery(filters),
636
+ parseResponseBody: true,
637
+ });
638
+ }
639
+ async getTarget(workspace, targetId) {
640
+ return await this.request({
641
+ method: 'GET',
642
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}`,
643
+ parseResponseBody: true,
644
+ });
645
+ }
646
+ async createTargetByYaml(workspace, scope, body) {
647
+ return await this.request({
648
+ method: 'POST',
649
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/yaml`,
650
+ query: this.targetScopeQuery(scope),
651
+ body,
652
+ parseResponseBody: true,
653
+ });
654
+ }
655
+ async updateTargetByYaml(workspace, targetId, body) {
656
+ return await this.request({
657
+ method: 'PATCH',
658
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/yaml`,
659
+ body,
660
+ parseResponseBody: true,
661
+ });
662
+ }
663
+ async deleteTarget(workspace, targetId) {
664
+ return await this.request({
665
+ method: 'DELETE',
666
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}`,
667
+ parseResponseBody: false,
668
+ });
669
+ }
670
+ async executeTargetCommand(workspace, targetId, body) {
671
+ return await this.request({
672
+ method: 'POST',
673
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs`,
674
+ body,
675
+ parseResponseBody: true,
676
+ });
677
+ }
678
+ async getTargetExecs(workspace, targetId, limit) {
679
+ const query = {};
680
+ if (limit)
681
+ query.limit = limit.toString();
682
+ return await this.request({
683
+ method: 'GET',
684
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs`,
685
+ query,
686
+ parseResponseBody: true,
687
+ });
688
+ }
689
+ async getTargetExec(workspace, execId, wait) {
690
+ const query = {};
691
+ if (wait)
692
+ query.wait = wait.toString();
693
+ return await this.request({
694
+ method: 'GET',
695
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
696
+ query,
697
+ parseResponseBody: true,
698
+ });
699
+ }
700
+ async cancelTargetExec(workspace, execId) {
701
+ return await this.request({
702
+ method: 'DELETE',
703
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
704
+ parseResponseBody: false,
705
+ });
706
+ }
707
+ async getTargetExecLog(workspace, execId, offset, limit) {
708
+ const query = {};
709
+ if (offset)
710
+ query.offset = offset.toString();
711
+ if (limit)
712
+ query.limit = limit.toString();
713
+ return await this.request({
714
+ method: 'GET',
715
+ path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}/log`,
716
+ query,
717
+ parseResponseBody: true,
718
+ });
719
+ }
720
+ async getTargetByIdentifier(workspace, identifier, line = {}) {
721
+ return await this.getResourceByIdentifier(workspace, {
722
+ target: identifier,
723
+ ...line,
724
+ });
725
+ }
726
+ // Environment methods
727
+ async getEnvironments(workspace, project) {
728
+ const query = {};
729
+ if (project)
730
+ query.project_name = project;
731
+ return await this.request({
732
+ method: 'GET',
733
+ path: `/workspaces/${encodeURIComponent(workspace)}/environments`,
734
+ query,
735
+ parseResponseBody: true,
736
+ });
737
+ }
738
+ async getEnvironment(workspace, environmentId) {
739
+ return await this.request({
740
+ method: 'GET',
741
+ path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
742
+ parseResponseBody: true,
743
+ });
744
+ }
745
+ async createEnvironment(workspace, body) {
746
+ return await this.request({
747
+ method: 'POST',
748
+ path: `/workspaces/${encodeURIComponent(workspace)}/environments`,
749
+ body,
750
+ parseResponseBody: true,
751
+ });
752
+ }
753
+ async updateEnvironment(workspace, environmentId, body) {
754
+ return await this.request({
755
+ method: 'PATCH',
756
+ path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
757
+ body,
758
+ parseResponseBody: true,
759
+ });
760
+ }
761
+ async deleteEnvironment(workspace, environmentId) {
762
+ return await this.request({
763
+ method: 'DELETE',
764
+ path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
765
+ parseResponseBody: false,
766
+ });
767
+ }
768
+ async getEnvironmentByIdentifier(workspace, identifier, project) {
769
+ const q = {
770
+ environment: identifier,
771
+ };
772
+ if (project)
773
+ q.project = project;
774
+ return await this.getResourceByIdentifier(workspace, q);
775
+ }
566
776
  // Sandbox methods
567
777
  async createSandbox(workspace, project, body) {
568
778
  return await this.request({
@@ -24,6 +24,8 @@ const artifact_1 = __importDefault(require("./command/artifact"));
24
24
  const api_1 = __importDefault(require("./command/api"));
25
25
  const domain_1 = __importDefault(require("./command/domain"));
26
26
  const distro_1 = __importDefault(require("./command/distro"));
27
+ const target_1 = __importDefault(require("./command/target"));
28
+ const environment_1 = __importDefault(require("./command/environment"));
27
29
  const register_1 = __importDefault(require("./command/register"));
28
30
  const mcp_1 = __importDefault(require("./command/mcp"));
29
31
  function cliIndex() {
@@ -47,6 +49,8 @@ function cliIndex() {
47
49
  program.addCommand(sandbox_1.default);
48
50
  program.addCommand(domain_1.default);
49
51
  program.addCommand(distro_1.default);
52
+ program.addCommand(target_1.default);
53
+ program.addCommand(environment_1.default);
50
54
  program.addCommand(login_1.default);
51
55
  program.addCommand(register_1.default);
52
56
  program.addCommand(whoami_1.default);
@@ -18,14 +18,12 @@ commandArtifactList.action(async (options) => {
18
18
  const workspace = input_1.default.restApiWorkspace(options.workspace);
19
19
  const project = input_1.default.restApiProject(options.project, true);
20
20
  const scope = input_1.default.scope(project, options.scope);
21
+ input_1.default.projectScopeNote(options, project, scope, 'artifacts');
21
22
  const client = input_1.default.restApiTokenClient();
22
23
  const response = await client.getArtifacts(workspace, scope === distro_1.SCOPE.PROJECT ? project : null);
23
24
  const artifacts = response.artifacts || [];
24
25
  if (options.format === 'json') {
25
- const filtered = scope === distro_1.SCOPE.PROJECT
26
- ? artifacts.filter((a) => a.scope !== distro_1.SCOPE.WORKSPACE)
27
- : artifacts;
28
- output_1.default.json(filtered);
26
+ output_1.default.json(artifacts);
29
27
  }
30
28
  else {
31
29
  if (artifacts.length === 0) {
@@ -33,8 +31,6 @@ commandArtifactList.action(async (options) => {
33
31
  }
34
32
  const data = [['NAME', 'IDENTIFIER', 'TYPE', 'URL']];
35
33
  for (const artifact of artifacts) {
36
- if (scope === distro_1.SCOPE.PROJECT && artifact.scope === distro_1.SCOPE.WORKSPACE)
37
- continue;
38
34
  data.push([
39
35
  artifact.name,
40
36
  artifact.identifier,