@cimplify/sdk 0.44.32 → 0.44.34

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.
@@ -15,15 +15,47 @@ var CLI_ERROR_CODE = {
15
15
  INVALID_INPUT: "INVALID_INPUT",
16
16
  ALREADY_LINKED: "ALREADY_LINKED",
17
17
  SERVER_ERROR: "SERVER_ERROR",
18
- ABORTED: "ABORTED"};
18
+ ABORTED: "ABORTED",
19
+ /** Operation needs interactive confirmation and the shell is non-interactive. */
20
+ INTERACTIVE_REQUIRED: "INTERACTIVE_REQUIRED"
21
+ };
19
22
  var EXIT_CODE = {
20
- ERROR: 1};
23
+ ABORTED: 3,
24
+ NOT_LINKED: 4,
25
+ ALREADY_LINKED: 5,
26
+ GIT_ERROR: 6,
27
+ INTERACTIVE_REQUIRED: 7,
28
+ PROJECT_NOT_FOUND: 8,
29
+ NETWORK_ERROR: 10,
30
+ SERVER_ERROR: 11,
31
+ TIMEOUT: 12,
32
+ NOT_LOGGED_IN: 20,
33
+ AUTH_FAILED: 21,
34
+ UNAUTHORIZED: 22,
35
+ INVALID_INPUT: 30
36
+ };
37
+ var EXIT_CODE_FOR = {
38
+ NOT_LOGGED_IN: EXIT_CODE.NOT_LOGGED_IN,
39
+ NOT_LINKED: EXIT_CODE.NOT_LINKED,
40
+ NETWORK_ERROR: EXIT_CODE.NETWORK_ERROR,
41
+ AUTH_FAILED: EXIT_CODE.AUTH_FAILED,
42
+ PROJECT_NOT_FOUND: EXIT_CODE.PROJECT_NOT_FOUND,
43
+ GIT_ERROR: EXIT_CODE.GIT_ERROR,
44
+ INVALID_INPUT: EXIT_CODE.INVALID_INPUT,
45
+ ALREADY_LINKED: EXIT_CODE.ALREADY_LINKED,
46
+ SERVER_ERROR: EXIT_CODE.SERVER_ERROR,
47
+ ABORTED: EXIT_CODE.ABORTED,
48
+ UNAUTHORIZED: EXIT_CODE.UNAUTHORIZED,
49
+ TIMEOUT: EXIT_CODE.TIMEOUT,
50
+ INTERACTIVE_REQUIRED: EXIT_CODE.INTERACTIVE_REQUIRED
51
+ };
21
52
  var CliError = class extends Error {
22
- constructor(code, message, exitCode = EXIT_CODE.ERROR) {
53
+ constructor(code, message, options = {}) {
23
54
  super(message);
24
55
  this.name = "CliError";
25
56
  this.code = code;
26
- this.exitCode = exitCode;
57
+ this.exitCode = options.exitCode ?? EXIT_CODE_FOR[code];
58
+ this.remediation = options.remediation;
27
59
  }
28
60
  };
29
61
 
@@ -321,25 +353,57 @@ var BOLD_OPEN = "\x1B[1m";
321
353
  var DIM_OPEN = "\x1B[2m";
322
354
  var GREEN_OPEN = "\x1B[32m";
323
355
  var PREFIX_SUCCESS = "\u2713";
356
+ var ENV_JSON = "CIMPLIFY_JSON";
357
+ var ENV_YES = "CIMPLIFY_YES";
358
+ function envFlag(name) {
359
+ const v = process.env[name];
360
+ return v === "1" || v === "true";
361
+ }
362
+ function isJsonMode() {
363
+ return envFlag(ENV_JSON);
364
+ }
365
+ function isAutoYes() {
366
+ return envFlag(ENV_YES);
367
+ }
368
+ function isInteractive() {
369
+ return Boolean(process.stdout.isTTY) && Boolean(process.stdin.isTTY);
370
+ }
324
371
  function wrap(open, value) {
325
372
  return `${open}${value}${RESET}`;
326
373
  }
327
374
  function bold(value) {
328
- return wrap(BOLD_OPEN, value);
375
+ return isJsonMode() ? value : wrap(BOLD_OPEN, value);
329
376
  }
330
377
  function dim(value) {
331
- return wrap(DIM_OPEN, value);
378
+ return isJsonMode() ? value : wrap(DIM_OPEN, value);
332
379
  }
333
380
  function green(value) {
334
- return wrap(GREEN_OPEN, value);
381
+ return isJsonMode() ? value : wrap(GREEN_OPEN, value);
335
382
  }
336
383
  function success(message) {
384
+ if (isJsonMode()) return;
337
385
  console.log(`${green(PREFIX_SUCCESS)} ${message}`);
338
386
  }
339
387
  function info(message) {
388
+ if (isJsonMode()) return;
340
389
  console.log(message);
341
390
  }
391
+ var ENV_EMITTED = "__CIMPLIFY_RESULT_EMITTED";
392
+ function result(data) {
393
+ if (!isJsonMode()) return;
394
+ if (process.env[ENV_EMITTED] === "1") return;
395
+ process.env[ENV_EMITTED] = "1";
396
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}
397
+ `);
398
+ }
342
399
  async function promptLine(question) {
400
+ if (!isInteractive()) {
401
+ throw new CliError(
402
+ CLI_ERROR_CODE.INTERACTIVE_REQUIRED,
403
+ "this operation needs interactive input but stdin is not a TTY",
404
+ { remediation: "run interactively, or supply the value via a flag" }
405
+ );
406
+ }
343
407
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
344
408
  try {
345
409
  return await new Promise((resolve) => {
@@ -350,6 +414,14 @@ async function promptLine(question) {
350
414
  }
351
415
  }
352
416
  async function promptYesNo(question, defaultNo = true) {
417
+ if (isAutoYes()) return true;
418
+ if (!isInteractive()) {
419
+ throw new CliError(
420
+ CLI_ERROR_CODE.INTERACTIVE_REQUIRED,
421
+ `this operation needs confirmation: ${question}`,
422
+ { remediation: "re-run with --yes to accept, or run interactively" }
423
+ );
424
+ }
353
425
  const suffix = defaultNo ? " [y/N] " : " [Y/n] ";
354
426
  const answer = (await promptLine(`${question}${suffix}`)).trim().toLowerCase();
355
427
  if (answer === "") return !defaultNo;
@@ -365,6 +437,13 @@ var ENV_SCOPE = {
365
437
  };
366
438
  var SECRET_MASK = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
367
439
  var PUBLIC_ENV_PREFIX = "NEXT_PUBLIC_";
440
+ var REPO_PROVIDER = {
441
+ FREESTYLE: "freestyle",
442
+ GITHUB: "github",
443
+ GITEA: "gitea",
444
+ EXTERNAL: "external"
445
+ };
446
+ new Set(Object.values(REPO_PROVIDER));
368
447
 
369
448
  // src/cli/commands/env.ts
370
449
  var SUB_LS = "ls";
@@ -462,6 +541,7 @@ async function listEnv(client, businessId, projectId, args) {
462
541
  });
463
542
  if (records.length === 0) {
464
543
  info(dim(`No env vars in scope "${scope}". Add one: cimplify env add KEY=VALUE`));
544
+ result({ scope, vars: [] });
465
545
  return;
466
546
  }
467
547
  const keyWidth = Math.max(COL_KEY.length, ...records.map((r) => r.key.length));
@@ -488,6 +568,15 @@ async function listEnv(client, businessId, projectId, args) {
488
568
  ].join(COL_GAP)
489
569
  );
490
570
  }
571
+ result({
572
+ scope,
573
+ vars: records.map((r) => ({
574
+ key: r.key,
575
+ scope: r.scope,
576
+ is_secret: r.is_secret,
577
+ value: r.is_secret ? null : r.value ?? null
578
+ }))
579
+ });
491
580
  }
492
581
  function renderValue(r, show) {
493
582
  if (r.is_secret) return SECRET_MASK;
@@ -514,6 +603,7 @@ Secrets are never returned in plaintext to the CLI; use the dashboard to copy th
514
603
  await promises.mkdir(path.dirname(outPath), { recursive: true });
515
604
  await promises.writeFile(outPath, formatEnvFile(entries), "utf8");
516
605
  success(`Pulled ${entries.length} var${entries.length === 1 ? "" : "s"} to ${path.relative(process.cwd(), outPath) || outPath}`);
606
+ result({ scope, count: entries.length, file: outPath });
517
607
  }
518
608
  async function backupIfExists(target) {
519
609
  try {
@@ -559,6 +649,7 @@ Use --file to point at a different path.`
559
649
  };
560
650
  await client.post(bulkSetEndpoint(businessId, projectId), body);
561
651
  success(`Pushed ${entries.length} var${entries.length === 1 ? "" : "s"} to ${scope}${overwrite ? " (overwrite)" : ""}`);
652
+ result({ scope, count: entries.length, overwrite });
562
653
  }
563
654
  async function addEnv(client, businessId, projectId, args) {
564
655
  const positional = args.positional[1];
@@ -577,6 +668,9 @@ async function addEnv(client, businessId, projectId, args) {
577
668
  const body = { key, value, scope, is_secret: isSecret };
578
669
  const created = await client.post(envEndpoint(businessId, projectId), body);
579
670
  success(`Added ${created.key} (${scope}, ${isSecret ? "secret" : "public"})`);
671
+ result({
672
+ var: { key: created.key, scope: created.scope, is_secret: created.is_secret }
673
+ });
580
674
  }
581
675
  async function removeEnv(client, businessId, projectId, args) {
582
676
  const key = args.positional[1];
@@ -605,6 +699,7 @@ async function removeEnv(client, businessId, projectId, args) {
605
699
  }
606
700
  await client.delete(envItemEndpoint(businessId, projectId, target.id));
607
701
  success(`Removed ${key} from ${scope}`);
702
+ result({ removed: true, key, scope });
608
703
  }
609
704
 
610
705
  export { classifyIsSecret, run as default };
@@ -12,13 +12,42 @@ var CLI_ERROR_CODE = {
12
12
  ALREADY_LINKED: "ALREADY_LINKED",
13
13
  SERVER_ERROR: "SERVER_ERROR"};
14
14
  var EXIT_CODE = {
15
- ERROR: 1};
15
+ ABORTED: 3,
16
+ NOT_LINKED: 4,
17
+ ALREADY_LINKED: 5,
18
+ GIT_ERROR: 6,
19
+ INTERACTIVE_REQUIRED: 7,
20
+ PROJECT_NOT_FOUND: 8,
21
+ NETWORK_ERROR: 10,
22
+ SERVER_ERROR: 11,
23
+ TIMEOUT: 12,
24
+ NOT_LOGGED_IN: 20,
25
+ AUTH_FAILED: 21,
26
+ UNAUTHORIZED: 22,
27
+ INVALID_INPUT: 30
28
+ };
29
+ var EXIT_CODE_FOR = {
30
+ NOT_LOGGED_IN: EXIT_CODE.NOT_LOGGED_IN,
31
+ NOT_LINKED: EXIT_CODE.NOT_LINKED,
32
+ NETWORK_ERROR: EXIT_CODE.NETWORK_ERROR,
33
+ AUTH_FAILED: EXIT_CODE.AUTH_FAILED,
34
+ PROJECT_NOT_FOUND: EXIT_CODE.PROJECT_NOT_FOUND,
35
+ GIT_ERROR: EXIT_CODE.GIT_ERROR,
36
+ INVALID_INPUT: EXIT_CODE.INVALID_INPUT,
37
+ ALREADY_LINKED: EXIT_CODE.ALREADY_LINKED,
38
+ SERVER_ERROR: EXIT_CODE.SERVER_ERROR,
39
+ ABORTED: EXIT_CODE.ABORTED,
40
+ UNAUTHORIZED: EXIT_CODE.UNAUTHORIZED,
41
+ TIMEOUT: EXIT_CODE.TIMEOUT,
42
+ INTERACTIVE_REQUIRED: EXIT_CODE.INTERACTIVE_REQUIRED
43
+ };
16
44
  var CliError = class extends Error {
17
- constructor(code, message, exitCode = EXIT_CODE.ERROR) {
45
+ constructor(code, message, options = {}) {
18
46
  super(message);
19
47
  this.name = "CliError";
20
48
  this.code = code;
21
- this.exitCode = exitCode;
49
+ this.exitCode = options.exitCode ?? EXIT_CODE_FOR[code];
50
+ this.remediation = options.remediation;
22
51
  }
23
52
  };
24
53
 
@@ -274,21 +303,39 @@ var RESET = "\x1B[0m";
274
303
  var DIM_OPEN = "\x1B[2m";
275
304
  var GREEN_OPEN = "\x1B[32m";
276
305
  var PREFIX_SUCCESS = "\u2713";
306
+ var ENV_JSON = "CIMPLIFY_JSON";
307
+ function envFlag(name) {
308
+ const v = process.env[name];
309
+ return v === "1" || v === "true";
310
+ }
311
+ function isJsonMode() {
312
+ return envFlag(ENV_JSON);
313
+ }
277
314
  function wrap(open, value) {
278
315
  return `${open}${value}${RESET}`;
279
316
  }
280
317
  function dim(value) {
281
- return wrap(DIM_OPEN, value);
318
+ return isJsonMode() ? value : wrap(DIM_OPEN, value);
282
319
  }
283
320
  function green(value) {
284
- return wrap(GREEN_OPEN, value);
321
+ return isJsonMode() ? value : wrap(GREEN_OPEN, value);
285
322
  }
286
323
  function success(message) {
324
+ if (isJsonMode()) return;
287
325
  console.log(`${green(PREFIX_SUCCESS)} ${message}`);
288
326
  }
289
327
  function info(message) {
328
+ if (isJsonMode()) return;
290
329
  console.log(message);
291
330
  }
331
+ var ENV_EMITTED = "__CIMPLIFY_RESULT_EMITTED";
332
+ function result(data) {
333
+ if (!isJsonMode()) return;
334
+ if (process.env[ENV_EMITTED] === "1") return;
335
+ process.env[ENV_EMITTED] = "1";
336
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}
337
+ `);
338
+ }
292
339
 
293
340
  // src/cli/commands/link.ts
294
341
  function projectEndpoint(businessId, projectId) {
@@ -320,6 +367,12 @@ async function run(argv) {
320
367
  await writeProjectLink(link);
321
368
  success(`Linked to ${project.name} (${project.id})`);
322
369
  if (link.remoteUrl) info(dim(`remote: ${link.remoteUrl}`));
370
+ result({
371
+ project: { id: project.id, name: project.name },
372
+ business: { id: project.business_id },
373
+ remote_url: link.remoteUrl ?? null,
374
+ default_branch: link.defaultBranch ?? null
375
+ });
323
376
  }
324
377
 
325
378
  export { run as default };
@@ -16,16 +16,47 @@ var CLI_ERROR_CODE = {
16
16
  ALREADY_LINKED: "ALREADY_LINKED",
17
17
  SERVER_ERROR: "SERVER_ERROR",
18
18
  UNAUTHORIZED: "UNAUTHORIZED",
19
- TIMEOUT: "TIMEOUT"
19
+ TIMEOUT: "TIMEOUT",
20
+ /** Operation needs interactive confirmation and the shell is non-interactive. */
21
+ INTERACTIVE_REQUIRED: "INTERACTIVE_REQUIRED"
20
22
  };
21
23
  var EXIT_CODE = {
22
- ERROR: 1};
24
+ ABORTED: 3,
25
+ NOT_LINKED: 4,
26
+ ALREADY_LINKED: 5,
27
+ GIT_ERROR: 6,
28
+ INTERACTIVE_REQUIRED: 7,
29
+ PROJECT_NOT_FOUND: 8,
30
+ NETWORK_ERROR: 10,
31
+ SERVER_ERROR: 11,
32
+ TIMEOUT: 12,
33
+ NOT_LOGGED_IN: 20,
34
+ AUTH_FAILED: 21,
35
+ UNAUTHORIZED: 22,
36
+ INVALID_INPUT: 30
37
+ };
38
+ var EXIT_CODE_FOR = {
39
+ NOT_LOGGED_IN: EXIT_CODE.NOT_LOGGED_IN,
40
+ NOT_LINKED: EXIT_CODE.NOT_LINKED,
41
+ NETWORK_ERROR: EXIT_CODE.NETWORK_ERROR,
42
+ AUTH_FAILED: EXIT_CODE.AUTH_FAILED,
43
+ PROJECT_NOT_FOUND: EXIT_CODE.PROJECT_NOT_FOUND,
44
+ GIT_ERROR: EXIT_CODE.GIT_ERROR,
45
+ INVALID_INPUT: EXIT_CODE.INVALID_INPUT,
46
+ ALREADY_LINKED: EXIT_CODE.ALREADY_LINKED,
47
+ SERVER_ERROR: EXIT_CODE.SERVER_ERROR,
48
+ ABORTED: EXIT_CODE.ABORTED,
49
+ UNAUTHORIZED: EXIT_CODE.UNAUTHORIZED,
50
+ TIMEOUT: EXIT_CODE.TIMEOUT,
51
+ INTERACTIVE_REQUIRED: EXIT_CODE.INTERACTIVE_REQUIRED
52
+ };
23
53
  var CliError = class extends Error {
24
- constructor(code, message, exitCode = EXIT_CODE.ERROR) {
54
+ constructor(code, message, options = {}) {
25
55
  super(message);
26
56
  this.name = "CliError";
27
57
  this.code = code;
28
- this.exitCode = exitCode;
58
+ this.exitCode = options.exitCode ?? EXIT_CODE_FOR[code];
59
+ this.remediation = options.remediation;
29
60
  }
30
61
  };
31
62
 
@@ -386,27 +417,46 @@ var GREEN_OPEN = "\x1B[32m";
386
417
  var CYAN_OPEN = "\x1B[36m";
387
418
  var PREFIX_STEP = "\u25B8";
388
419
  var PREFIX_SUCCESS = "\u2713";
420
+ var ENV_JSON = "CIMPLIFY_JSON";
421
+ function envFlag(name) {
422
+ const v = process.env[name];
423
+ return v === "1" || v === "true";
424
+ }
425
+ function isJsonMode() {
426
+ return envFlag(ENV_JSON);
427
+ }
389
428
  function wrap(open, value) {
390
429
  return `${open}${value}${RESET}`;
391
430
  }
392
431
  function dim(value) {
393
- return wrap(DIM_OPEN, value);
432
+ return isJsonMode() ? value : wrap(DIM_OPEN, value);
394
433
  }
395
434
  function green(value) {
396
- return wrap(GREEN_OPEN, value);
435
+ return isJsonMode() ? value : wrap(GREEN_OPEN, value);
397
436
  }
398
437
  function cyan(value) {
399
- return wrap(CYAN_OPEN, value);
438
+ return isJsonMode() ? value : wrap(CYAN_OPEN, value);
400
439
  }
401
440
  function step(message) {
441
+ if (isJsonMode()) return;
402
442
  console.log(`${cyan(PREFIX_STEP)} ${message}`);
403
443
  }
404
444
  function success(message) {
445
+ if (isJsonMode()) return;
405
446
  console.log(`${green(PREFIX_SUCCESS)} ${message}`);
406
447
  }
407
448
  function info(message) {
449
+ if (isJsonMode()) return;
408
450
  console.log(message);
409
451
  }
452
+ var ENV_EMITTED = "__CIMPLIFY_RESULT_EMITTED";
453
+ function result(data) {
454
+ if (!isJsonMode()) return;
455
+ if (process.env[ENV_EMITTED] === "1") return;
456
+ process.env[ENV_EMITTED] = "1";
457
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}
458
+ `);
459
+ }
410
460
 
411
461
  // src/cli/commands/login.ts
412
462
  var FLAG_API_KEY = "api-key";
@@ -447,8 +497,21 @@ async function loginWithKey(baseUrl, apiKey) {
447
497
  savedAt: (/* @__PURE__ */ new Date()).toISOString()
448
498
  });
449
499
  success(`Logged in as ${me.email ?? me.name ?? me.id} (business ${me.business_id})`);
500
+ result({
501
+ logged_in: true,
502
+ account: { id: me.id, email: me.email ?? null, name: me.name ?? null },
503
+ business: { id: me.business_id },
504
+ method: "api_key"
505
+ });
450
506
  }
451
507
  async function loginWithBrowser(baseUrl, noBrowser) {
508
+ if (isJsonMode()) {
509
+ throw new CliError(
510
+ CLI_ERROR_CODE.INTERACTIVE_REQUIRED,
511
+ "browser login is not supported in --json mode",
512
+ { remediation: "pass --api-key dk_\u2026 (create one in the dashboard or via `cimplify auth keys create`)" }
513
+ );
514
+ }
452
515
  const pkce = generatePkcePair();
453
516
  const state = generateState();
454
517
  const loopback = await startLoopbackServer(baseUrl);
@@ -510,6 +573,12 @@ async function loginWithBrowser(baseUrl, noBrowser) {
510
573
  success(
511
574
  `Logged in as ${me.email ?? me.name ?? me.id} (business ${me.business_id})`
512
575
  );
576
+ result({
577
+ logged_in: true,
578
+ account: { id: me.id, email: me.email ?? null, name: me.name ?? null },
579
+ business: { id: me.business_id },
580
+ method: "oauth_pkce"
581
+ });
513
582
  }
514
583
 
515
584
  export { run as default };
@@ -2,6 +2,8 @@ import { promises } from 'fs';
2
2
  import os from 'os';
3
3
  import path from 'path';
4
4
 
5
+ // src/cli/config.ts
6
+
5
7
  // src/cli/config.ts
6
8
  var AUTH_FILE_NAME = "auth.json";
7
9
  var ENV_XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
@@ -28,18 +30,36 @@ async function clearAuth() {
28
30
  var RESET = "\x1B[0m";
29
31
  var GREEN_OPEN = "\x1B[32m";
30
32
  var PREFIX_SUCCESS = "\u2713";
33
+ var ENV_JSON = "CIMPLIFY_JSON";
34
+ function envFlag(name) {
35
+ const v = process.env[name];
36
+ return v === "1" || v === "true";
37
+ }
38
+ function isJsonMode() {
39
+ return envFlag(ENV_JSON);
40
+ }
31
41
  function wrap(open, value) {
32
42
  return `${open}${value}${RESET}`;
33
43
  }
34
44
  function green(value) {
35
- return wrap(GREEN_OPEN, value);
45
+ return isJsonMode() ? value : wrap(GREEN_OPEN, value);
36
46
  }
37
47
  function success(message) {
48
+ if (isJsonMode()) return;
38
49
  console.log(`${green(PREFIX_SUCCESS)} ${message}`);
39
50
  }
40
51
  function info(message) {
52
+ if (isJsonMode()) return;
41
53
  console.log(message);
42
54
  }
55
+ var ENV_EMITTED = "__CIMPLIFY_RESULT_EMITTED";
56
+ function result(data) {
57
+ if (!isJsonMode()) return;
58
+ if (process.env[ENV_EMITTED] === "1") return;
59
+ process.env[ENV_EMITTED] = "1";
60
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}
61
+ `);
62
+ }
43
63
 
44
64
  // src/cli/commands/logout.ts
45
65
  async function run(_argv) {
@@ -49,6 +69,7 @@ async function run(_argv) {
49
69
  } else {
50
70
  info("Not logged in.");
51
71
  }
72
+ result({ logged_out: removed });
52
73
  }
53
74
 
54
75
  export { run as default };
@@ -13,13 +13,42 @@ var CLI_ERROR_CODE = {
13
13
  ALREADY_LINKED: "ALREADY_LINKED",
14
14
  SERVER_ERROR: "SERVER_ERROR"};
15
15
  var EXIT_CODE = {
16
- ERROR: 1};
16
+ ABORTED: 3,
17
+ NOT_LINKED: 4,
18
+ ALREADY_LINKED: 5,
19
+ GIT_ERROR: 6,
20
+ INTERACTIVE_REQUIRED: 7,
21
+ PROJECT_NOT_FOUND: 8,
22
+ NETWORK_ERROR: 10,
23
+ SERVER_ERROR: 11,
24
+ TIMEOUT: 12,
25
+ NOT_LOGGED_IN: 20,
26
+ AUTH_FAILED: 21,
27
+ UNAUTHORIZED: 22,
28
+ INVALID_INPUT: 30
29
+ };
30
+ var EXIT_CODE_FOR = {
31
+ NOT_LOGGED_IN: EXIT_CODE.NOT_LOGGED_IN,
32
+ NOT_LINKED: EXIT_CODE.NOT_LINKED,
33
+ NETWORK_ERROR: EXIT_CODE.NETWORK_ERROR,
34
+ AUTH_FAILED: EXIT_CODE.AUTH_FAILED,
35
+ PROJECT_NOT_FOUND: EXIT_CODE.PROJECT_NOT_FOUND,
36
+ GIT_ERROR: EXIT_CODE.GIT_ERROR,
37
+ INVALID_INPUT: EXIT_CODE.INVALID_INPUT,
38
+ ALREADY_LINKED: EXIT_CODE.ALREADY_LINKED,
39
+ SERVER_ERROR: EXIT_CODE.SERVER_ERROR,
40
+ ABORTED: EXIT_CODE.ABORTED,
41
+ UNAUTHORIZED: EXIT_CODE.UNAUTHORIZED,
42
+ TIMEOUT: EXIT_CODE.TIMEOUT,
43
+ INTERACTIVE_REQUIRED: EXIT_CODE.INTERACTIVE_REQUIRED
44
+ };
17
45
  var CliError = class extends Error {
18
- constructor(code, message, exitCode = EXIT_CODE.ERROR) {
46
+ constructor(code, message, options = {}) {
19
47
  super(message);
20
48
  this.name = "CliError";
21
49
  this.code = code;
22
- this.exitCode = exitCode;
50
+ this.exitCode = options.exitCode ?? EXIT_CODE_FOR[code];
51
+ this.remediation = options.remediation;
23
52
  }
24
53
  };
25
54
 
@@ -265,15 +294,32 @@ async function readProjectState(cwd = process.cwd()) {
265
294
  var RESET = "\x1B[0m";
266
295
  var RED_OPEN = "\x1B[31m";
267
296
  var PREFIX_FAILURE = "\u2717";
297
+ var ENV_JSON = "CIMPLIFY_JSON";
298
+ function envFlag(name) {
299
+ const v = process.env[name];
300
+ return v === "1" || v === "true";
301
+ }
302
+ function isJsonMode() {
303
+ return envFlag(ENV_JSON);
304
+ }
268
305
  function wrap(open, value) {
269
306
  return `${open}${value}${RESET}`;
270
307
  }
271
308
  function red(value) {
272
- return wrap(RED_OPEN, value);
309
+ return isJsonMode() ? value : wrap(RED_OPEN, value);
273
310
  }
274
311
  function failure(message) {
312
+ if (isJsonMode()) return;
275
313
  console.error(`${red(PREFIX_FAILURE)} ${message}`);
276
314
  }
315
+ var ENV_EMITTED = "__CIMPLIFY_RESULT_EMITTED";
316
+ function result(data) {
317
+ if (!isJsonMode()) return;
318
+ if (process.env[ENV_EMITTED] === "1") return;
319
+ process.env[ENV_EMITTED] = "1";
320
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}
321
+ `);
322
+ }
277
323
 
278
324
  // src/cli/types.ts
279
325
  var DEPLOYMENT_STATUS = {
@@ -288,6 +334,13 @@ var TERMINAL_DEPLOYMENT_STATUSES = /* @__PURE__ */ new Set([
288
334
  DEPLOYMENT_STATUS.CANCELLED,
289
335
  DEPLOYMENT_STATUS.SUPERSEDED
290
336
  ]);
337
+ var REPO_PROVIDER = {
338
+ FREESTYLE: "freestyle",
339
+ GITHUB: "github",
340
+ GITEA: "gitea",
341
+ EXTERNAL: "external"
342
+ };
343
+ new Set(Object.values(REPO_PROVIDER));
291
344
 
292
345
  // src/cli/commands/logs.ts
293
346
  var FLAG_DEPLOYMENT = "deployment";
@@ -325,26 +378,41 @@ async function run(argv) {
325
378
  }
326
379
  const endpoint = progressEndpoint(link.businessId, link.projectId, deploymentId);
327
380
  const follow = flagBool(args, FLAG_FOLLOW);
381
+ const json = isJsonMode();
328
382
  if (!follow) {
329
383
  const progress = await client.get(endpoint);
330
- if (progress.build_logs) process.stdout.write(progress.build_logs);
331
- if (progress.error_message) failure(progress.error_message);
384
+ if (!json) {
385
+ if (progress.build_logs) process.stdout.write(progress.build_logs);
386
+ if (progress.error_message) failure(progress.error_message);
387
+ }
388
+ result({
389
+ deployment_id: deploymentId,
390
+ status: progress.status,
391
+ build_logs: progress.build_logs ?? null,
392
+ error_message: progress.error_message ?? null
393
+ });
332
394
  return;
333
395
  }
334
396
  const cursor = { printed: 0 };
335
397
  const startedAt = Date.now();
336
398
  let lastErrorMessage;
399
+ let finalProgress = null;
337
400
  while (true) {
338
401
  const progress = await client.get(endpoint);
339
- const chunk = nextChunk(cursor, progress.build_logs);
340
- if (chunk.length > 0) process.stdout.write(chunk);
341
- if (progress.error_message && progress.error_message !== lastErrorMessage) {
342
- process.stdout.write(`
402
+ if (!json) {
403
+ const chunk = nextChunk(cursor, progress.build_logs);
404
+ if (chunk.length > 0) process.stdout.write(chunk);
405
+ if (progress.error_message && progress.error_message !== lastErrorMessage) {
406
+ process.stdout.write(`
343
407
  ${red(progress.error_message)}
344
408
  `);
345
- lastErrorMessage = progress.error_message;
409
+ lastErrorMessage = progress.error_message;
410
+ }
411
+ }
412
+ if (TERMINAL_DEPLOYMENT_STATUSES.has(progress.status)) {
413
+ finalProgress = progress;
414
+ break;
346
415
  }
347
- if (TERMINAL_DEPLOYMENT_STATUSES.has(progress.status)) return;
348
416
  if (Date.now() - startedAt > POLL_MAX_MS) {
349
417
  throw new CliError(
350
418
  CLI_ERROR_CODE.NETWORK_ERROR,
@@ -353,6 +421,12 @@ ${red(progress.error_message)}
353
421
  }
354
422
  await sleep(POLL_INTERVAL_MS);
355
423
  }
424
+ result({
425
+ deployment_id: deploymentId,
426
+ status: finalProgress.status,
427
+ build_logs: finalProgress.build_logs ?? null,
428
+ error_message: finalProgress.error_message ?? null
429
+ });
356
430
  }
357
431
 
358
432
  export { run as default, nextChunk };