bdy 1.23.4-dev-target-commands → 1.23.5-dev

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 (54) hide show
  1. package/distTs/README.md +181 -0
  2. package/distTs/package.json +1 -3
  3. package/distTs/src/agent/agent.js +35 -2
  4. package/distTs/src/agent/manager.js +11 -0
  5. package/distTs/src/agent/system.js +6 -1
  6. package/distTs/src/api/client.js +0 -156
  7. package/distTs/src/cliIndex.js +0 -4
  8. package/distTs/src/command/artifact/list.js +6 -1
  9. package/distTs/src/command/distro/route/update.js +1 -1
  10. package/distTs/src/command/distro/update.js +9 -9
  11. package/distTs/src/command/project/get.js +18 -0
  12. package/distTs/src/command/project/set.js +31 -0
  13. package/distTs/src/command/sandbox/get/yaml.js +30 -0
  14. package/distTs/src/command/vt/scrape.js +193 -0
  15. package/distTs/src/input.js +0 -54
  16. package/distTs/src/texts.js +8 -196
  17. package/distTs/src/utils.js +7 -16
  18. package/package.json +1 -3
  19. package/distTs/detect-rules.json +0 -351
  20. package/distTs/src/command/environment/create.js +0 -70
  21. package/distTs/src/command/environment/delete.js +0 -29
  22. package/distTs/src/command/environment/get.js +0 -48
  23. package/distTs/src/command/environment/list.js +0 -44
  24. package/distTs/src/command/environment/resolve.js +0 -22
  25. package/distTs/src/command/environment/update.js +0 -59
  26. package/distTs/src/command/environment.js +0 -20
  27. package/distTs/src/command/pipeline/run/apply.js +0 -62
  28. package/distTs/src/command/target/create.js +0 -33
  29. package/distTs/src/command/target/delete.js +0 -30
  30. package/distTs/src/command/target/exec/command.js +0 -65
  31. package/distTs/src/command/target/exec/kill.js +0 -25
  32. package/distTs/src/command/target/exec/list.js +0 -54
  33. package/distTs/src/command/target/exec/logs.js +0 -25
  34. package/distTs/src/command/target/exec/status.js +0 -41
  35. package/distTs/src/command/target/exec.js +0 -24
  36. package/distTs/src/command/target/get.js +0 -62
  37. package/distTs/src/command/target/list.js +0 -48
  38. package/distTs/src/command/target/scope.js +0 -60
  39. package/distTs/src/command/target/update.js +0 -31
  40. package/distTs/src/command/target.js +0 -22
  41. package/distTs/src/command/yaml/actions/detect.js +0 -268
  42. package/distTs/src/command/yaml/actions/info.js +0 -56
  43. package/distTs/src/command/yaml/actions/list.js +0 -70
  44. package/distTs/src/command/yaml/actions/schema.js +0 -104
  45. package/distTs/src/command/yaml/actions.js +0 -13
  46. package/distTs/src/command/yaml/agents.js +0 -88
  47. package/distTs/src/command/yaml/cache.js +0 -98
  48. package/distTs/src/command/yaml/init.js +0 -110
  49. package/distTs/src/command/yaml/pipeline.js +0 -42
  50. package/distTs/src/command/yaml/render.js +0 -83
  51. package/distTs/src/command/yaml/schemaUtils.js +0 -139
  52. package/distTs/src/command/yaml/validate.js +0 -259
  53. package/distTs/src/command/yaml.js +0 -18
  54. package/distTs/src/diskCache.js +0 -82
@@ -0,0 +1,181 @@
1
+ # Buddy CLI (`bdy`)
2
+
3
+ Work seamlessly with [Buddy](https://buddy.works) from the command line.
4
+
5
+ `bdy` is Buddy's official command-line interface for managing CI/CD pipelines, agents, tests, artifacts, sandboxes, distributions, and more — straight from your terminal.
6
+
7
+ 📚 Full documentation: https://buddy.works/docs/cli/getting-started
8
+
9
+ ## Installation
10
+
11
+ ### npm (recommended)
12
+
13
+ Requires Node.js 14+.
14
+
15
+ ```bash
16
+ # macOS / Linux
17
+ sudo npm i -g bdy
18
+
19
+ # Windows
20
+ npm i -g bdy
21
+ ```
22
+
23
+ ### Homebrew (macOS)
24
+
25
+ ```bash
26
+ brew tap buddy/bdy
27
+ brew install bdy
28
+ ```
29
+
30
+ ### APT (Linux x64 / ARM64)
31
+
32
+ ```bash
33
+ sudo apt-get update && sudo apt-get install -y software-properties-common
34
+ sudo gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/buddy.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys eb39332e766364ca6220e8dc631c5a16310cc0ad
35
+ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/buddy.gpg] https://es.buddy.works/bdy/apt-repo prod main" | sudo tee /etc/apt/sources.list.d/buddy.list > /dev/null
36
+ sudo apt-get update && sudo apt-get install -y bdy
37
+ ```
38
+
39
+ > On ARM64, replace `arch=amd64` with `arch=arm64` in the `echo` command above.
40
+
41
+ ### Chocolatey (Windows)
42
+
43
+ ```powershell
44
+ choco install bdy --pre
45
+ ```
46
+
47
+ ### Direct download
48
+
49
+ Prebuilt binaries are available for macOS (Apple Silicon), Linux (x64/ARM64), and Windows (x64) on the [installation page](https://buddy.works/docs/cli/getting-started).
50
+
51
+ ### Verify & update
52
+
53
+ ```bash
54
+ bdy version # show current and latest version
55
+ sudo npm i -g bdy # update (or use your package manager's upgrade command)
56
+ ```
57
+
58
+ ## Authentication
59
+
60
+ A [Buddy account](https://buddy.works) is required to use the CLI.
61
+
62
+ Log in interactively:
63
+
64
+ ```bash
65
+ bdy login
66
+ ```
67
+
68
+ New to Buddy? Create an account from the CLI:
69
+
70
+ ```bash
71
+ bdy register
72
+ ```
73
+
74
+ ### Linking a project
75
+
76
+ Once logged in, link a directory to a Buddy project:
77
+
78
+ ```bash
79
+ mkdir my-proj
80
+ cd my-proj
81
+ bdy proj link
82
+ ```
83
+
84
+ After linking, every `bdy` command run from this directory is executed against the linked project — no need to pass the project name each time.
85
+
86
+ Check who you're logged in as, or log out:
87
+
88
+ ```bash
89
+ bdy whoami
90
+ bdy logout
91
+ ```
92
+
93
+ ### Tokens & non-interactive login
94
+
95
+ For CI/CD pipelines and non-browser environments, authenticate with a [personal access token](https://buddy.works/docs/api/getting-started/oauth2/personal-access-token):
96
+
97
+ ```bash
98
+ bdy login --token <token>
99
+ ```
100
+
101
+ The login command accepts the following options:
102
+
103
+ | Option | Description | Environment variable |
104
+ | --- | --- | --- |
105
+ | `--token <token>` | Personal access token | `BUDDY_TOKEN` |
106
+ | `--api <url>` | API URL for On-Premises installations | `BUDDY_API_ENDPOINT` |
107
+ | `--region <region>` | Region: `us`, `eu`, or `as` | `BUDDY_REGION` |
108
+ | `-w, --workspace <domain>` | Workspace URL handle | `BUDDY_WORKSPACE` |
109
+
110
+ Each option can be supplied as a flag or via its environment variable — handy for pipelines and headless setups:
111
+
112
+ ```bash
113
+ export BUDDY_TOKEN=<token>
114
+ export BUDDY_WORKSPACE=<your-workspace>
115
+ bdy login
116
+ ```
117
+
118
+ ## Agent integration (plugin & skills)
119
+
120
+ The [Buddy Plugin](https://github.com/buddy/buddy-plugin) lets coding agents deploy applications, expose local services, and manage infrastructure on Buddy. It bundles a consolidated skill covering sandboxes, artifacts, tunnels, domains, distributions, and pipelines, plus two commands:
121
+
122
+ - `/deploy [name] [path]` — deploy a static site or server application
123
+ - `/expose [port]` — open a tunnel to a locally running service
124
+
125
+ Make sure the CLI is installed first (`sudo npm install -g bdy`), then:
126
+
127
+ **Claude Code** — install the plugin (commands + skills):
128
+
129
+ ```bash
130
+ claude plugin marketplace add buddy/buddy-plugin
131
+ claude plugin install buddy@buddy-plugin
132
+ ```
133
+
134
+ **Other agents** — install the skills only:
135
+
136
+ ```bash
137
+ npx skills add buddy/buddy-plugin
138
+ ```
139
+
140
+ Then authenticate and link your project:
141
+
142
+ ```bash
143
+ bdy login
144
+ cd your-project
145
+ bdy proj link
146
+ ```
147
+
148
+ The plugin auto-detects your project type: static sites generate versioned artifacts with public URLs, while server applications deploy to sandboxes with HTTPS endpoints. Monorepos can deploy multiple applications, each getting its own URL and endpoint.
149
+
150
+ ## Commands
151
+
152
+ | Command | Description |
153
+ | --- | --- |
154
+ | `bdy login` / `sign-in` | Log in to Buddy |
155
+ | `bdy register` / `sign-up` | Register a new Buddy account |
156
+ | `bdy whoami` | Check login information |
157
+ | `bdy logout` | Log out from Buddy |
158
+ | `bdy workspace` / `ws` | Manage workspaces |
159
+ | `bdy project` / `proj` | Manage projects |
160
+ | `bdy pipeline` / `pip` | Interact with the pipeline service |
161
+ | `bdy artifact` / `art` | Interact with the artifact service |
162
+ | `bdy sandbox` / `sb` | Interact with sandboxes |
163
+ | `bdy agent` | Install and run `bdy` as an OS service (Windows, macOS, Linux) |
164
+ | `bdy tunnel` | Manage tunnel configuration |
165
+ | `bdy crawl` | Manage web crawls (Markdown, HTML, PNG/JPEG screenshots; suite linking) |
166
+ | `bdy tests` | Manage unit tests and visual regression (Storybook, URL captures, runners) |
167
+ | `bdy domain` | Manage zones used in distribution routes |
168
+ | `bdy distro` | Manage distributions |
169
+ | `bdy api` | Contact the Buddy API directly |
170
+ | `bdy update` / `version` | Show version and update the CLI |
171
+
172
+ Run any command with `-h` / `--help` for detailed usage:
173
+
174
+ ```bash
175
+ bdy --help
176
+ bdy pipeline --help
177
+ ```
178
+
179
+ ## Feedback
180
+
181
+ Found a bug or have a feature request? Let us know through [Buddy support](https://buddy.works/support) or the [documentation](https://buddy.works/docs/cli/getting-started).
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bdy",
3
3
  "preferGlobal": false,
4
- "version": "1.23.4-dev-target-commands",
4
+ "version": "1.23.5-dev",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "homepage": "https://buddy.works/docs/cli",
@@ -27,8 +27,6 @@
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/",
32
30
  "unit": "vitest run --config vitest.config.ts"
33
31
  },
34
32
  "files": [
@@ -25,6 +25,7 @@ class Agent extends events_1.default {
25
25
  api;
26
26
  socket;
27
27
  manager;
28
+ updateStatusExpiry;
28
29
  onRefresh;
29
30
  constructor(id, host, token, service, target, tunneling, proxy, tags, api, disabled) {
30
31
  super();
@@ -41,6 +42,7 @@ class Agent extends events_1.default {
41
42
  this.tunnelsUpdating = false;
42
43
  this.api = api;
43
44
  this.manager = null;
45
+ this.updateStatusExpiry = null;
44
46
  this.onRefresh = null;
45
47
  this.socket = new client_1.default(host, id, token);
46
48
  this.socket.on(tunnel_1.TUNNEL_SOCKET_EVENT.FETCH_SUCCESS, (data) => this._onSocketFetch(data));
@@ -56,6 +58,10 @@ class Agent extends events_1.default {
56
58
  this.socket.destroy();
57
59
  this.socket = null;
58
60
  }
61
+ // Would fire on a socket that is already gone
62
+ if (this.updateStatusExpiry)
63
+ clearTimeout(this.updateStatusExpiry);
64
+ this.updateStatusExpiry = null;
59
65
  this.manager = null;
60
66
  this.onRefresh = null;
61
67
  this.api = null;
@@ -260,8 +266,35 @@ class Agent extends events_1.default {
260
266
  // previous value in place, which is why the front reads STARTED on an offline agent as
261
267
  // an unknown outcome rather than as an update still running.
262
268
  reportUpdateStatus(status) {
263
- if (this.socket)
264
- this.socket.setPendingAction(status);
269
+ if (!this.socket)
270
+ return;
271
+ this.socket.setPendingAction(status);
272
+ this.expireUpdateStatusIn(status);
273
+ }
274
+ // Takes the outcome back off the record after a while, so it reads as the confirmation
275
+ // it is rather than as a standing fact about the agent. Done here rather than by hiding
276
+ // it in the front because nothing on the record dates the write: the only timestamps a
277
+ // front could compare against are the agent's boot time and its heartbeat, and neither
278
+ // is when this happened.
279
+ //
280
+ // A timer is sound for this where it would not be for the update itself: the process
281
+ // that reports an outcome is the one still running, so nothing has to survive a restart
282
+ // - and if it dies first, the next start() sends an empty action anyway.
283
+ expireUpdateStatusIn(status) {
284
+ if (this.updateStatusExpiry)
285
+ clearTimeout(this.updateStatusExpiry);
286
+ this.updateStatusExpiry = null;
287
+ // STARTED is not an outcome. It is what stays behind when a restart never lands, and
288
+ // clearing it would turn the one state the front can flag as unknown into silence.
289
+ if (status === tunnel_1.TUNNEL_AGENT_UPDATE_STATUS.STARTED)
290
+ return;
291
+ this.updateStatusExpiry = setTimeout(() => {
292
+ this.updateStatusExpiry = null;
293
+ this.ackAction();
294
+ }, utils_1.AGENT_UPDATE_STATUS_TTL_MS);
295
+ // A foreground tunnel reporting UNSUPPORTED exits as soon as it has acked, and must
296
+ // not be held open for the rest of the window just to tidy up after itself
297
+ this.updateStatusExpiry.unref();
265
298
  }
266
299
  // For a status with no ack to ride on - STARTED, reported while the download is still
267
300
  // running. Passes null so that if the status has somehow already gone out, this does
@@ -141,6 +141,11 @@ class AgentManagerClass {
141
141
  // Every path that gives up reports why as well as acking: the ack alone clears the
142
142
  // request, which on the front is indistinguishable from an update that never ran.
143
143
  const report = (status) => {
144
+ // Except when the agent is going away. There is nothing left to tell, and the write
145
+ // would land on top of the DELETE this process has not finished acting on - which
146
+ // is also how the swap below reports being cut short by one.
147
+ if (this.exiting)
148
+ return;
144
149
  this.agent?.reportUpdateStatus(status);
145
150
  return this.agent?.ackAction();
146
151
  };
@@ -540,6 +545,12 @@ class AgentManagerClass {
540
545
  }
541
546
  async disableAgentAndExit(txt) {
542
547
  logger_1.default.error(txt);
548
+ // Set before the first await, not just before the exit: uninstalling and unregistering
549
+ // both take a while, and a remote update arriving in that window would otherwise start
550
+ // downloading a release for an agent that is being taken apart - and could rename the
551
+ // new binary into place after the files it lives among have been removed. The update
552
+ // path already refuses to start while this is set.
553
+ this.exiting = true;
543
554
  try {
544
555
  await this.system.uninstall();
545
556
  }
@@ -407,7 +407,12 @@ class AgentSystem {
407
407
  // Last check before touching the live binary. The download and the smoke test take
408
408
  // long enough for an uninstall to have run in the meantime, and finishing the swap
409
409
  // then would put a binary back for an agent that is deliberately gone.
410
- if (!(0, node_fs_1.existsSync)(this.getSystemConfigPath())) {
410
+ //
411
+ // The config file alone is not enough to tell: an uninstall removes it only after
412
+ // stopping the service and unregistering, so a delete that is under way still looks
413
+ // like a live install from here for as long as those take. The flag is set before
414
+ // any of that starts.
415
+ if (!(0, node_fs_1.existsSync)(this.getSystemConfigPath()) || manager_1.default.exiting) {
411
416
  throw new Error(texts_1.LOG_AGENT_UPDATE_UNINSTALLED);
412
417
  }
413
418
  (0, node_fs_1.rmSync)(backup, { force: true });
@@ -563,162 +563,6 @@ class ApiClient {
563
563
  q.project = project;
564
564
  return await this.getResourceByIdentifier(workspace, q);
565
565
  }
566
- // Target methods
567
- targetScopeQuery(scope) {
568
- const query = {};
569
- if (scope.project)
570
- query.project_name = scope.project;
571
- if (scope.pipelineId)
572
- query.pipeline_id = scope.pipelineId.toString();
573
- if (scope.environmentId)
574
- query.environment_id = scope.environmentId;
575
- return query;
576
- }
577
- async getTargets(workspace, filters = {}) {
578
- return await this.request({
579
- method: 'GET',
580
- path: `/workspaces/${encodeURIComponent(workspace)}/targets`,
581
- query: this.targetScopeQuery(filters),
582
- parseResponseBody: true,
583
- });
584
- }
585
- async getTarget(workspace, targetId) {
586
- return await this.request({
587
- method: 'GET',
588
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}`,
589
- parseResponseBody: true,
590
- });
591
- }
592
- async createTargetByYaml(workspace, scope, body) {
593
- return await this.request({
594
- method: 'POST',
595
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/yaml`,
596
- query: this.targetScopeQuery(scope),
597
- body,
598
- parseResponseBody: true,
599
- });
600
- }
601
- async updateTargetByYaml(workspace, targetId, body) {
602
- return await this.request({
603
- method: 'PATCH',
604
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/yaml`,
605
- body,
606
- parseResponseBody: true,
607
- });
608
- }
609
- async deleteTarget(workspace, targetId) {
610
- return await this.request({
611
- method: 'DELETE',
612
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}`,
613
- parseResponseBody: false,
614
- });
615
- }
616
- async executeTargetCommand(workspace, targetId, body) {
617
- return await this.request({
618
- method: 'POST',
619
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs`,
620
- body,
621
- parseResponseBody: true,
622
- });
623
- }
624
- async getTargetExecs(workspace, targetId, limit) {
625
- const query = {};
626
- if (limit)
627
- query.limit = limit.toString();
628
- return await this.request({
629
- method: 'GET',
630
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs`,
631
- query,
632
- parseResponseBody: true,
633
- });
634
- }
635
- async getTargetExec(workspace, execId, wait) {
636
- const query = {};
637
- if (wait)
638
- query.wait = wait.toString();
639
- return await this.request({
640
- method: 'GET',
641
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
642
- query,
643
- parseResponseBody: true,
644
- });
645
- }
646
- async cancelTargetExec(workspace, execId) {
647
- return await this.request({
648
- method: 'DELETE',
649
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
650
- parseResponseBody: false,
651
- });
652
- }
653
- async getTargetExecLog(workspace, execId, offset, limit) {
654
- const query = {};
655
- if (offset)
656
- query.offset = offset.toString();
657
- if (limit)
658
- query.limit = limit.toString();
659
- return await this.request({
660
- method: 'GET',
661
- path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}/log`,
662
- query,
663
- parseResponseBody: true,
664
- });
665
- }
666
- async getTargetByIdentifier(workspace, identifier, line = {}) {
667
- return await this.getResourceByIdentifier(workspace, {
668
- target: identifier,
669
- ...line,
670
- });
671
- }
672
- // Environment methods
673
- async getEnvironments(workspace, project) {
674
- const query = {};
675
- if (project)
676
- query.project_name = project;
677
- return await this.request({
678
- method: 'GET',
679
- path: `/workspaces/${encodeURIComponent(workspace)}/environments`,
680
- query,
681
- parseResponseBody: true,
682
- });
683
- }
684
- async getEnvironment(workspace, environmentId) {
685
- return await this.request({
686
- method: 'GET',
687
- path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
688
- parseResponseBody: true,
689
- });
690
- }
691
- async createEnvironment(workspace, body) {
692
- return await this.request({
693
- method: 'POST',
694
- path: `/workspaces/${encodeURIComponent(workspace)}/environments`,
695
- body,
696
- parseResponseBody: true,
697
- });
698
- }
699
- async updateEnvironment(workspace, environmentId, body) {
700
- return await this.request({
701
- method: 'PATCH',
702
- path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
703
- body,
704
- parseResponseBody: true,
705
- });
706
- }
707
- async deleteEnvironment(workspace, environmentId) {
708
- return await this.request({
709
- method: 'DELETE',
710
- path: `/workspaces/${encodeURIComponent(workspace)}/environments/${encodeURIComponent(environmentId)}`,
711
- parseResponseBody: false,
712
- });
713
- }
714
- async getEnvironmentByIdentifier(workspace, identifier, project) {
715
- const q = {
716
- environment: identifier,
717
- };
718
- if (project)
719
- q.project = project;
720
- return await this.getResourceByIdentifier(workspace, q);
721
- }
722
566
  // Sandbox methods
723
567
  async createSandbox(workspace, project, body) {
724
568
  return await this.request({
@@ -24,8 +24,6 @@ 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"));
29
27
  const register_1 = __importDefault(require("./command/register"));
30
28
  const mcp_1 = __importDefault(require("./command/mcp"));
31
29
  function cliIndex() {
@@ -49,8 +47,6 @@ function cliIndex() {
49
47
  program.addCommand(sandbox_1.default);
50
48
  program.addCommand(domain_1.default);
51
49
  program.addCommand(distro_1.default);
52
- program.addCommand(target_1.default);
53
- program.addCommand(environment_1.default);
54
50
  program.addCommand(login_1.default);
55
51
  program.addCommand(register_1.default);
56
52
  program.addCommand(whoami_1.default);
@@ -22,7 +22,10 @@ commandArtifactList.action(async (options) => {
22
22
  const response = await client.getArtifacts(workspace, scope === distro_1.SCOPE.PROJECT ? project : null);
23
23
  const artifacts = response.artifacts || [];
24
24
  if (options.format === 'json') {
25
- output_1.default.json(artifacts);
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
29
  }
27
30
  else {
28
31
  if (artifacts.length === 0) {
@@ -30,6 +33,8 @@ commandArtifactList.action(async (options) => {
30
33
  }
31
34
  const data = [['NAME', 'IDENTIFIER', 'TYPE', 'URL']];
32
35
  for (const artifact of artifacts) {
36
+ if (scope === distro_1.SCOPE.PROJECT && artifact.scope === distro_1.SCOPE.WORKSPACE)
37
+ continue;
33
38
  data.push([
34
39
  artifact.name,
35
40
  artifact.identifier,
@@ -77,7 +77,7 @@ commandDistroRouteUpdate.action(async (identifier, routeId, options) => {
77
77
  changed = true;
78
78
  }
79
79
  if (!changed) {
80
- output_1.default.exitError(texts_1.ERR_COMMAND_NO_UPDATE);
80
+ output_1.default.exitError(texts_1.ERR_COMMAND_ROUTE_NO_UPDATE);
81
81
  }
82
82
  const result = await client.updateRoute(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, data.distribution_id, routeId, body);
83
83
  output_1.default.id(result.id);
@@ -27,6 +27,14 @@ commandDistroUpdate.action(async (identifier, options) => {
27
27
  const workspace = input_1.default.restApiWorkspace(options.workspace);
28
28
  const project = input_1.default.restApiProject(options.project, true);
29
29
  const scope = input_1.default.scope(project, options.scope);
30
+ const client = input_1.default.restApiTokenClient();
31
+ const data = await client.getDistributionByIdentifier(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, identifier);
32
+ if (!data || !data.domain) {
33
+ output_1.default.exitError(texts_1.ERR_WORKSPACE_NOT_FOUND);
34
+ }
35
+ if (!data || !data.distribution_id) {
36
+ output_1.default.exitError(texts_1.ERR_COMMAND_DISTRO_NOT_FOUND);
37
+ }
30
38
  const body = {};
31
39
  let changed = false;
32
40
  if (options.name) {
@@ -46,15 +54,7 @@ commandDistroUpdate.action(async (identifier, options) => {
46
54
  changed = true;
47
55
  }
48
56
  if (!changed) {
49
- output_1.default.exitError(texts_1.ERR_COMMAND_NO_UPDATE);
50
- }
51
- const client = input_1.default.restApiTokenClient();
52
- const data = await client.getDistributionByIdentifier(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, identifier);
53
- if (!data || !data.domain) {
54
- output_1.default.exitError(texts_1.ERR_WORKSPACE_NOT_FOUND);
55
- }
56
- if (!data || !data.distribution_id) {
57
- output_1.default.exitError(texts_1.ERR_COMMAND_DISTRO_NOT_FOUND);
57
+ output_1.default.exitError(texts_1.ERR_COMMAND_DISTRO_NO_UPDATE);
58
58
  }
59
59
  const result = await client.updateDistribution(workspace, scope === distro_1.SCOPE.PROJECT ? project : null, data.distribution_id, body);
60
60
  output_1.default.identifier(result.identifier);
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
7
+ const output_1 = __importDefault(require("../../output"));
8
+ const texts_1 = require("../../texts");
9
+ const utils_1 = require("../../utils");
10
+ const commandProjectGet = (0, utils_1.newCommand)('get', texts_1.DESC_COMMAND_PROJECT_GET);
11
+ commandProjectGet.action(async () => {
12
+ const project = cfg_1.default.getProject();
13
+ if (!project) {
14
+ output_1.default.exitError(texts_1.TXT_PROJECT_NONE);
15
+ }
16
+ output_1.default.exitNormal(project);
17
+ });
18
+ exports.default = commandProjectGet;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const cfg_1 = __importDefault(require("../../tunnel/cfg"));
7
+ const output_1 = __importDefault(require("../../output"));
8
+ const texts_1 = require("../../texts");
9
+ const utils_1 = require("../../utils");
10
+ const input_1 = __importDefault(require("../../input"));
11
+ const commandProjectSet = (0, utils_1.newCommand)('set', texts_1.DESC_COMMAND_PROJECT_SET);
12
+ commandProjectSet.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
13
+ commandProjectSet.argument('[project]', texts_1.ARG_COMMAND_PROJECT_NAME);
14
+ commandProjectSet.action(async (project, options) => {
15
+ output_1.default.handleSignals();
16
+ const workspace = input_1.default.restApiWorkspace(options.workspace);
17
+ const client = input_1.default.restApiTokenClient();
18
+ if (project) {
19
+ await client.getProject(workspace, project);
20
+ }
21
+ else {
22
+ const response = await client.getProjects(workspace);
23
+ project = await output_1.default.selectProject(response.projects);
24
+ }
25
+ cfg_1.default.setProject(project);
26
+ if (!project)
27
+ output_1.default.exitSuccess(texts_1.TXT_PROJECT_SET_CLEARED);
28
+ else
29
+ output_1.default.exitSuccess((0, texts_1.TXT_PROJECT_SET_SUCCESS)(project));
30
+ });
31
+ exports.default = commandProjectSet;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const utils_1 = require("../../../utils");
7
+ const texts_1 = require("../../../texts");
8
+ const input_1 = __importDefault(require("../../../input"));
9
+ const output_1 = __importDefault(require("../../../output"));
10
+ const commandSandboxGetYaml = (0, utils_1.newCommand)('yaml', texts_1.DESC_COMMAND_SANDBOX_GET_YAML);
11
+ commandSandboxGetYaml.hideVersionUpdate = true;
12
+ commandSandboxGetYaml.alias('yml');
13
+ commandSandboxGetYaml.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
14
+ commandSandboxGetYaml.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
15
+ commandSandboxGetYaml.argument('<identifier>', texts_1.OPTION_SANDBOX_IDENTIFIER);
16
+ commandSandboxGetYaml.action(async (identifier, options) => {
17
+ const workspace = input_1.default.restApiWorkspace(options.workspace);
18
+ const project = input_1.default.restApiProject(options.project);
19
+ const client = input_1.default.restApiTokenClient();
20
+ let result = await client.listSandboxes(workspace, project);
21
+ const sandboxes = result.sandboxes || [];
22
+ const found = sandboxes.find((s) => s.identifier === identifier);
23
+ if (!found) {
24
+ output_1.default.exitError(texts_1.ERR_SANDBOX_NOT_FOUND);
25
+ }
26
+ const sandboxId = found.id;
27
+ result = await client.getSandboxYaml(workspace, sandboxId);
28
+ output_1.default.exitNormal(Buffer.from(result.yaml, 'base64').toString('utf8'));
29
+ });
30
+ exports.default = commandSandboxGetYaml;