bdy 1.23.13-dev-target-commands → 1.23.13-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.
- package/distTs/README.md +181 -0
- package/distTs/package.json +3 -5
- package/distTs/src/agent/manager.js +9 -2
- package/distTs/src/api/client.js +12 -222
- package/distTs/src/cliIndex.js +0 -4
- package/distTs/src/command/artifact/list.js +6 -2
- package/distTs/src/command/distro/list.js +0 -1
- package/distTs/src/command/distro/route/update.js +1 -1
- package/distTs/src/command/distro/update.js +9 -9
- package/distTs/src/command/pre.js +9 -8
- package/distTs/src/command/project/get.js +18 -0
- package/distTs/src/command/project/set.js +31 -0
- package/distTs/src/command/sandbox/get/yaml.js +30 -0
- package/distTs/src/command/version.js +1 -1
- package/distTs/src/command/vt/scrape.js +193 -0
- package/distTs/src/input.js +0 -65
- package/distTs/src/logger.js +7 -1
- package/distTs/src/output.js +2 -21
- package/distTs/src/texts.js +27 -252
- package/distTs/src/tunnel/server/sftp.js +24 -5
- package/distTs/src/tunnel/ssh/client.js +35 -4
- package/distTs/src/utils.js +50 -31
- package/package.json +3 -5
- package/distTs/detect-rules.json +0 -351
- package/distTs/src/command/environment/create.js +0 -70
- package/distTs/src/command/environment/delete.js +0 -29
- package/distTs/src/command/environment/get.js +0 -48
- package/distTs/src/command/environment/list.js +0 -45
- package/distTs/src/command/environment/resolve.js +0 -22
- package/distTs/src/command/environment/update.js +0 -59
- package/distTs/src/command/environment.js +0 -20
- package/distTs/src/command/pipeline/run/apply.js +0 -62
- package/distTs/src/command/target/create.js +0 -33
- package/distTs/src/command/target/delete.js +0 -30
- package/distTs/src/command/target/exec/command.js +0 -103
- package/distTs/src/command/target/exec/kill.js +0 -31
- package/distTs/src/command/target/exec/list.js +0 -53
- package/distTs/src/command/target/exec/logs.js +0 -27
- package/distTs/src/command/target/exec/status.js +0 -44
- package/distTs/src/command/target/exec.js +0 -24
- package/distTs/src/command/target/get.js +0 -63
- package/distTs/src/command/target/list.js +0 -49
- package/distTs/src/command/target/scope.js +0 -108
- package/distTs/src/command/target/update.js +0 -31
- package/distTs/src/command/target.js +0 -22
- package/distTs/src/command/yaml/actions/detect.js +0 -268
- package/distTs/src/command/yaml/actions/info.js +0 -56
- package/distTs/src/command/yaml/actions/list.js +0 -70
- package/distTs/src/command/yaml/actions/schema.js +0 -104
- package/distTs/src/command/yaml/actions.js +0 -13
- package/distTs/src/command/yaml/agents.js +0 -88
- package/distTs/src/command/yaml/cache.js +0 -98
- package/distTs/src/command/yaml/init.js +0 -110
- package/distTs/src/command/yaml/pipeline.js +0 -42
- package/distTs/src/command/yaml/render.js +0 -83
- package/distTs/src/command/yaml/schemaUtils.js +0 -139
- package/distTs/src/command/yaml/validate.js +0 -259
- package/distTs/src/command/yaml.js +0 -18
- package/distTs/src/diskCache.js +0 -82
package/distTs/README.md
ADDED
|
@@ -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).
|
package/distTs/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.23.13-dev
|
|
4
|
+
"version": "1.23.13-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": [
|
|
@@ -53,7 +51,7 @@
|
|
|
53
51
|
"@fastify/cors": "11.2.0",
|
|
54
52
|
"@inquirer/prompts": "8.5.2",
|
|
55
53
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
56
|
-
"@puppeteer/browsers": "2.
|
|
54
|
+
"@puppeteer/browsers": "3.2.0",
|
|
57
55
|
"@scalar/json-magic": "0.12.16",
|
|
58
56
|
"@scalar/openapi-parser": "0.28.7",
|
|
59
57
|
"@scalar/openapi-types": "0.9.1",
|
|
@@ -81,7 +79,7 @@
|
|
|
81
79
|
"picomatch": "4.0.4",
|
|
82
80
|
"pino": "10.3.1",
|
|
83
81
|
"punycode": "2.3.1",
|
|
84
|
-
"puppeteer-core": "
|
|
82
|
+
"puppeteer-core": "25.6.0",
|
|
85
83
|
"range-parser": "1.2.1",
|
|
86
84
|
"socket.io-client": "4.8.3",
|
|
87
85
|
"ssh2": "1.17.0",
|
|
@@ -161,6 +161,10 @@ class AgentManagerClass {
|
|
|
161
161
|
}
|
|
162
162
|
const current = (0, utils_1.getVersion)();
|
|
163
163
|
const latest = await (0, utils_1.getLatestVersion)();
|
|
164
|
+
// Equality only, deliberately not "is latest newer": this runs on an explicit remote
|
|
165
|
+
// update action, whose meaning is "match what the channel publishes". Refusing an
|
|
166
|
+
// older latest would take away the only rollback the fleet has - moving the channel
|
|
167
|
+
// pointer back after a bad release.
|
|
164
168
|
if (!latest || latest === '0.0.0' || latest === current) {
|
|
165
169
|
logger_1.default.info((0, texts_1.LOG_AGENT_UPDATE_NOT_NEEDED)(current));
|
|
166
170
|
// Nothing to do is not a failure, and showing it as one would make an update of
|
|
@@ -174,12 +178,15 @@ class AgentManagerClass {
|
|
|
174
178
|
// - this is the value that stays behind if the restart never lands.
|
|
175
179
|
this.agent?.reportUpdateStatus(tunnel_1.TUNNEL_AGENT_UPDATE_STATUS.STARTED);
|
|
176
180
|
this.agent?.flushUpdateStatus();
|
|
177
|
-
|
|
181
|
+
// getLatestVersion already refuses a version it cannot parse, so this is belt and
|
|
182
|
+
// braces - kept because the download url is built from the triple, and shipping a
|
|
183
|
+
// malformed one would fail much further away from the cause.
|
|
184
|
+
const target = (0, utils_1.parseVersion)(latest);
|
|
178
185
|
if (!target) {
|
|
179
186
|
logger_1.default.error(texts_1.LOG_AGENT_UPDATE_FAILED);
|
|
180
187
|
return report(tunnel_1.TUNNEL_AGENT_UPDATE_STATUS.FAILED);
|
|
181
188
|
}
|
|
182
|
-
const swapped = await this.system.swapBinaryToVersion(target
|
|
189
|
+
const swapped = await this.system.swapBinaryToVersion(target.version);
|
|
183
190
|
if (!swapped) {
|
|
184
191
|
logger_1.default.error((0, texts_1.LOG_AGENT_UPDATE_BINARY_INVALID)(latest));
|
|
185
192
|
return report(tunnel_1.TUNNEL_AGENT_UPDATE_STATUS.FAILED);
|
package/distTs/src/api/client.js
CHANGED
|
@@ -16,25 +16,6 @@ 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;
|
|
38
19
|
const formDataFileName = (name) => name.replace(/["\r\n]/g, (c) => ({ '"': '%22', '\r': '%0D', '\n': '%0A' })[c]);
|
|
39
20
|
exports.formDataFileName = formDataFileName;
|
|
40
21
|
class ApiClient {
|
|
@@ -131,41 +112,20 @@ class ApiClient {
|
|
|
131
112
|
logger_1.default.debug(headers);
|
|
132
113
|
logger_1.default.debug('BODY');
|
|
133
114
|
logger_1.default.debug(bodyParsed);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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']);
|
|
115
|
+
try {
|
|
116
|
+
response = await this.client.request(opts);
|
|
117
|
+
rateLimitReset = response.headers['x-rate-limit-reset'];
|
|
153
118
|
status = response.statusCode;
|
|
154
119
|
responseBody = response.body;
|
|
155
120
|
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);
|
|
164
121
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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 });
|
|
169
129
|
}
|
|
170
130
|
if (status === 401) {
|
|
171
131
|
await responseBody.dump();
|
|
@@ -225,7 +185,7 @@ class ApiClient {
|
|
|
225
185
|
if (status === 404)
|
|
226
186
|
throw new Error(texts_1.ERR_REST_API_RESOURCE_NOT_FOUND);
|
|
227
187
|
else
|
|
228
|
-
throw new Error(
|
|
188
|
+
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
229
189
|
}
|
|
230
190
|
if ([200, 201].includes(status)) {
|
|
231
191
|
if (parseResponseBody) {
|
|
@@ -261,23 +221,9 @@ class ApiClient {
|
|
|
261
221
|
}
|
|
262
222
|
else {
|
|
263
223
|
await responseBody.dump();
|
|
264
|
-
throw new Error(
|
|
224
|
+
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
265
225
|
}
|
|
266
226
|
}
|
|
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
|
-
}
|
|
281
227
|
async getPipelineRunActionLogs(workspace, project, pipelineId, executionId, actionExecutionId, offset, limit) {
|
|
282
228
|
const query = {
|
|
283
229
|
offset: String(offset),
|
|
@@ -617,162 +563,6 @@ class ApiClient {
|
|
|
617
563
|
q.project = project;
|
|
618
564
|
return await this.getResourceByIdentifier(workspace, q);
|
|
619
565
|
}
|
|
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
|
-
}
|
|
776
566
|
// Sandbox methods
|
|
777
567
|
async createSandbox(workspace, project, body) {
|
|
778
568
|
return await this.request({
|
package/distTs/src/cliIndex.js
CHANGED
|
@@ -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);
|
|
@@ -18,12 +18,14 @@ 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');
|
|
22
21
|
const client = input_1.default.restApiTokenClient();
|
|
23
22
|
const response = await client.getArtifacts(workspace, scope === distro_1.SCOPE.PROJECT ? project : null);
|
|
24
23
|
const artifacts = response.artifacts || [];
|
|
25
24
|
if (options.format === 'json') {
|
|
26
|
-
|
|
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);
|
|
27
29
|
}
|
|
28
30
|
else {
|
|
29
31
|
if (artifacts.length === 0) {
|
|
@@ -31,6 +33,8 @@ commandArtifactList.action(async (options) => {
|
|
|
31
33
|
}
|
|
32
34
|
const data = [['NAME', 'IDENTIFIER', 'TYPE', 'URL']];
|
|
33
35
|
for (const artifact of artifacts) {
|
|
36
|
+
if (scope === distro_1.SCOPE.PROJECT && artifact.scope === distro_1.SCOPE.WORKSPACE)
|
|
37
|
+
continue;
|
|
34
38
|
data.push([
|
|
35
39
|
artifact.name,
|
|
36
40
|
artifact.identifier,
|
|
@@ -19,7 +19,6 @@ commandDistroList.action(async (options) => {
|
|
|
19
19
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
20
20
|
const project = input_1.default.restApiProject(options.project, true);
|
|
21
21
|
const scope = input_1.default.scope(project, options.scope);
|
|
22
|
-
input_1.default.projectScopeNote(options, project, scope, 'distributions');
|
|
23
22
|
const client = input_1.default.restApiTokenClient();
|
|
24
23
|
const r = await client.getDistributions(workspace, scope === distro_1.SCOPE.PROJECT ? project : null);
|
|
25
24
|
const distributions = r.distributions || [];
|
|
@@ -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.
|
|
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.
|
|
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);
|
|
@@ -46,14 +46,15 @@ const commandPre = async (_, command) => {
|
|
|
46
46
|
if (!output_1.default.isTTY() || command.hideVersionUpdate || ['json', 'jsonl'].includes(command.opts()?.format)) {
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
// No truthiness guards on the versions: an empty or unparsable one is never newer
|
|
50
|
+
const latest = command.latestVersion || '';
|
|
51
|
+
const newCli = (0, utils_1.isVersionNewer)(latest, command.currentVersion || '');
|
|
52
|
+
const newAgent = !!command.agentStatus && (0, utils_1.isVersionNewer)(latest, command.agentStatus.version);
|
|
53
|
+
if ((0, utils_1.isDocker)() && newCli) {
|
|
54
|
+
output_1.default.newCliDockerVersion(latest);
|
|
55
|
+
}
|
|
56
|
+
else if (newCli) {
|
|
57
|
+
output_1.default.newCliVersion(latest);
|
|
57
58
|
}
|
|
58
59
|
else if (newAgent) {
|
|
59
60
|
output_1.default.newAgentVersion();
|
|
@@ -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;
|