bdy 1.25.20 → 1.25.22-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/package.json +1 -1
- package/distTs/src/agent/manager.js +22 -1
- package/distTs/src/api/client.js +6 -6
- package/distTs/src/command/target/exec/command.js +10 -9
- package/distTs/src/command/target/exec/kill.js +9 -3
- package/distTs/src/command/target/exec/logs.js +8 -3
- package/distTs/src/command/target/exec/status.js +8 -2
- package/distTs/src/command/target/scope.js +26 -7
- package/distTs/src/texts.js +18 -18
- package/distTs/src/tunnel/api/agent.js +2 -2
- package/package.json +1 -1
package/distTs/package.json
CHANGED
|
@@ -305,6 +305,17 @@ class AgentManagerClass {
|
|
|
305
305
|
res.statusCode = 404;
|
|
306
306
|
res.end('Not found');
|
|
307
307
|
}
|
|
308
|
+
// The server is bound to loopback, but a web page open on this machine can still
|
|
309
|
+
// reach it: a no-cors POST or an <img> fires without a preflight, a WebSocket is
|
|
310
|
+
// never subject to CORS, and DNS rebinding lets a page read the responses. bdy
|
|
311
|
+
// sends no Origin and always targets 127.0.0.1, browsers always send Origin on
|
|
312
|
+
// those requests and keep the rebound name in Host - so refuse either.
|
|
313
|
+
isLocalRequest(req) {
|
|
314
|
+
if (req.headers.origin !== undefined)
|
|
315
|
+
return false;
|
|
316
|
+
const host = req.headers.host;
|
|
317
|
+
return (host === `127.0.0.1:${this.port}` || host === `localhost:${this.port}`);
|
|
318
|
+
}
|
|
308
319
|
serverError(res, message) {
|
|
309
320
|
res.statusCode = 400;
|
|
310
321
|
res.end(JSON.stringify({
|
|
@@ -709,6 +720,11 @@ class AgentManagerClass {
|
|
|
709
720
|
}
|
|
710
721
|
async processRequest(req, res) {
|
|
711
722
|
logger_1.default.debug(`MANAGER REQUEST: ${req.url}`);
|
|
723
|
+
if (!this.isLocalRequest(req)) {
|
|
724
|
+
res.statusCode = 403;
|
|
725
|
+
res.end('Forbidden');
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
712
728
|
if (req.url === '/status')
|
|
713
729
|
return this.processStatus(res);
|
|
714
730
|
if (req.url === '/target')
|
|
@@ -751,6 +767,10 @@ class AgentManagerClass {
|
|
|
751
767
|
}
|
|
752
768
|
processUpgrade(req, socket, head) {
|
|
753
769
|
logger_1.default.debug(`MANAGER REQUEST: ${req.url}`);
|
|
770
|
+
if (!this.isLocalRequest(req)) {
|
|
771
|
+
socket.destroy();
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
754
774
|
const url = new URL(req.url || '', 'http://localhost');
|
|
755
775
|
const id = url.searchParams.get('id');
|
|
756
776
|
if (url.pathname === '/tunnel' && id && this.ws) {
|
|
@@ -801,7 +821,8 @@ class AgentManagerClass {
|
|
|
801
821
|
logger_1.default.error(err);
|
|
802
822
|
}
|
|
803
823
|
});
|
|
804
|
-
|
|
824
|
+
// Loopback only: the API has no credentials, every caller is a local bdy.
|
|
825
|
+
this.server.listen(this.port ?? 0, '127.0.0.1', () => {
|
|
805
826
|
logger_1.default.info(texts_1.LOG_AGENT_SERVER_STARTED);
|
|
806
827
|
});
|
|
807
828
|
}
|
package/distTs/src/api/client.js
CHANGED
|
@@ -704,25 +704,25 @@ class ApiClient {
|
|
|
704
704
|
parseResponseBody: true,
|
|
705
705
|
});
|
|
706
706
|
}
|
|
707
|
-
async getTargetExec(workspace, execId, wait) {
|
|
707
|
+
async getTargetExec(workspace, targetId, execId, wait) {
|
|
708
708
|
const query = {};
|
|
709
709
|
if (wait)
|
|
710
710
|
query.wait = wait.toString();
|
|
711
711
|
return await this.request({
|
|
712
712
|
method: 'GET',
|
|
713
|
-
path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
|
|
713
|
+
path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs/${encodeURIComponent(execId)}`,
|
|
714
714
|
query,
|
|
715
715
|
parseResponseBody: true,
|
|
716
716
|
});
|
|
717
717
|
}
|
|
718
|
-
async cancelTargetExec(workspace, execId) {
|
|
718
|
+
async cancelTargetExec(workspace, targetId, execId) {
|
|
719
719
|
return await this.request({
|
|
720
720
|
method: 'DELETE',
|
|
721
|
-
path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}`,
|
|
721
|
+
path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs/${encodeURIComponent(execId)}`,
|
|
722
722
|
parseResponseBody: false,
|
|
723
723
|
});
|
|
724
724
|
}
|
|
725
|
-
async getTargetExecLog(workspace, execId, offset, limit) {
|
|
725
|
+
async getTargetExecLog(workspace, targetId, execId, offset, limit) {
|
|
726
726
|
const query = {};
|
|
727
727
|
if (offset)
|
|
728
728
|
query.offset = offset.toString();
|
|
@@ -730,7 +730,7 @@ class ApiClient {
|
|
|
730
730
|
query.limit = limit.toString();
|
|
731
731
|
return await this.request({
|
|
732
732
|
method: 'GET',
|
|
733
|
-
path: `/workspaces/${encodeURIComponent(workspace)}/targets/execs/${encodeURIComponent(execId)}/log`,
|
|
733
|
+
path: `/workspaces/${encodeURIComponent(workspace)}/targets/${encodeURIComponent(targetId)}/execs/${encodeURIComponent(execId)}/log`,
|
|
734
734
|
query,
|
|
735
735
|
parseResponseBody: true,
|
|
736
736
|
});
|
|
@@ -47,18 +47,19 @@ commandTargetExecCommand.action(async (identifier, command, options) => {
|
|
|
47
47
|
command: cmd,
|
|
48
48
|
});
|
|
49
49
|
const execId = exec.execution_id;
|
|
50
|
+
const target = (0, scope_1.targetExecRef)(identifier, options);
|
|
50
51
|
const json = options.format === 'json';
|
|
51
52
|
// Preserve the execution id before status validation can fail.
|
|
52
53
|
if (!json) {
|
|
53
54
|
if (options.async) {
|
|
54
|
-
output_1.default.note((0, texts_1.TXT_TARGET_EXEC_BACKGROUND)(execId));
|
|
55
|
+
output_1.default.note((0, texts_1.TXT_TARGET_EXEC_BACKGROUND)(target, execId));
|
|
55
56
|
output_1.default.data(execId);
|
|
56
57
|
}
|
|
57
58
|
else {
|
|
58
59
|
output_1.default.note((0, texts_1.TXT_TARGET_EXEC_ID)(execId));
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
const recoveryHint = (0, texts_1.TXT_TARGET_EXEC_RECOVERY)(execId);
|
|
62
|
+
const recoveryHint = (0, texts_1.TXT_TARGET_EXEC_RECOVERY)(target, execId);
|
|
62
63
|
let code = options.exitCode
|
|
63
64
|
? (0, utils_1.executionExitCode)(exec.status, recoveryHint)
|
|
64
65
|
: undefined;
|
|
@@ -71,12 +72,12 @@ commandTargetExecCommand.action(async (identifier, command, options) => {
|
|
|
71
72
|
}
|
|
72
73
|
if (json) {
|
|
73
74
|
while (exec.status === utils_1.TARGET_EXEC_STATUS.INPROGRESS) {
|
|
74
|
-
exec = await client.getTargetExec(workspace, execId, EXEC_WAIT_MS);
|
|
75
|
+
exec = await client.getTargetExec(workspace, target_id, execId, EXEC_WAIT_MS);
|
|
75
76
|
if (options.exitCode)
|
|
76
77
|
code = (0, utils_1.executionExitCode)(exec.status, recoveryHint);
|
|
77
78
|
}
|
|
78
79
|
const log = [];
|
|
79
|
-
await (0, scope_1.forwardExecLog)(client, workspace, execId, 0, (lines) => log.push(...lines));
|
|
80
|
+
await (0, scope_1.forwardExecLog)(client, workspace, target_id, execId, 0, (lines) => log.push(...lines));
|
|
80
81
|
output_1.default.json({ ...exec, log });
|
|
81
82
|
output_1.default.exitCode(code ?? (exec.status === utils_1.TARGET_EXEC_STATUS.SUCCESSFUL ? 0 : 1));
|
|
82
83
|
}
|
|
@@ -87,12 +88,12 @@ commandTargetExecCommand.action(async (identifier, command, options) => {
|
|
|
87
88
|
let loggedBytes;
|
|
88
89
|
const drainLog = async () => {
|
|
89
90
|
loggedBytes = exec.bytes_out;
|
|
90
|
-
const log = await (0, scope_1.forwardExecLog)(client, workspace, execId, offset);
|
|
91
|
+
const log = await (0, scope_1.forwardExecLog)(client, workspace, target_id, execId, offset);
|
|
91
92
|
offset = log.offset;
|
|
92
93
|
truncated = truncated || log.truncated;
|
|
93
94
|
};
|
|
94
95
|
while (exec.status === utils_1.TARGET_EXEC_STATUS.INPROGRESS) {
|
|
95
|
-
exec = await client.getTargetExec(workspace, execId, EXEC_WAIT_MS);
|
|
96
|
+
exec = await client.getTargetExec(workspace, target_id, execId, EXEC_WAIT_MS);
|
|
96
97
|
if (options.exitCode)
|
|
97
98
|
(0, utils_1.executionExitCode)(exec.status, recoveryHint);
|
|
98
99
|
if (exec.bytes_out !== loggedBytes)
|
|
@@ -105,11 +106,11 @@ commandTargetExecCommand.action(async (identifier, command, options) => {
|
|
|
105
106
|
output_1.default.noteWarning(texts_1.WARN_TARGET_EXEC_TRUNCATED);
|
|
106
107
|
}
|
|
107
108
|
if (exec.status === utils_1.TARGET_EXEC_STATUS.SUCCESSFUL) {
|
|
108
|
-
output_1.default.note((0, texts_1.TXT_TARGET_EXEC_SUCCESS)(execId));
|
|
109
|
+
output_1.default.note((0, texts_1.TXT_TARGET_EXEC_SUCCESS)(target, execId));
|
|
109
110
|
output_1.default.exitNormal();
|
|
110
111
|
}
|
|
111
112
|
output_1.default.exitError(exec.status === utils_1.TARGET_EXEC_STATUS.CANCELLED
|
|
112
|
-
? (0, texts_1.TXT_TARGET_EXEC_CANCELLED)(execId)
|
|
113
|
-
: (0, texts_1.TXT_TARGET_EXEC_FAILED)(execId, exec.failure_reason), 1);
|
|
113
|
+
? (0, texts_1.TXT_TARGET_EXEC_CANCELLED)(target, execId)
|
|
114
|
+
: (0, texts_1.TXT_TARGET_EXEC_FAILED)(target, execId, exec.failure_reason), 1);
|
|
114
115
|
});
|
|
115
116
|
exports.default = commandTargetExecCommand;
|
|
@@ -7,25 +7,31 @@ const utils_1 = require("../../../utils");
|
|
|
7
7
|
const texts_1 = require("../../../texts");
|
|
8
8
|
const input_1 = __importDefault(require("../../../input"));
|
|
9
9
|
const output_1 = __importDefault(require("../../../output"));
|
|
10
|
+
const scope_1 = require("../scope");
|
|
10
11
|
const commandTargetExecKill = (0, utils_1.newCommand)('kill', texts_1.DESC_COMMAND_TARGET_EXEC_KILL, { requiredScopes: [utils_1.REST_API_SCOPE.TARGET_USE], examples: texts_1.EXAMPLE_TARGET_EXEC_KILL });
|
|
11
12
|
commandTargetExecKill.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
13
|
+
commandTargetExecKill.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
14
|
+
commandTargetExecKill.option('--pipeline <identifier>', texts_1.OPTION_TARGET_PIPELINE);
|
|
15
|
+
commandTargetExecKill.option('--environment <identifier>', texts_1.OPTION_TARGET_ENVIRONMENT);
|
|
12
16
|
commandTargetExecKill.option('-f, --force', texts_1.OPTION_CONFIRM_FORCE);
|
|
13
17
|
commandTargetExecKill.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
18
|
+
commandTargetExecKill.argument('<identifier>', texts_1.OPTION_TARGET_IDENTIFIER);
|
|
14
19
|
commandTargetExecKill.argument('<exec-id>', texts_1.OPTION_TARGET_EXEC_ID);
|
|
15
|
-
commandTargetExecKill.action(async (execId, options) => {
|
|
20
|
+
commandTargetExecKill.action(async (identifier, execId, options) => {
|
|
16
21
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
17
22
|
const client = input_1.default.restApiTokenClient();
|
|
23
|
+
const target_id = await (0, scope_1.resolveTargetId)(client, workspace, identifier, options);
|
|
18
24
|
// Resolve the exec before the prompt so a bad id fails the same way
|
|
19
25
|
// (Resource not found, exit 1) with and without --force - otherwise the
|
|
20
26
|
// confirmation error would hide the invalid id. With --force
|
|
21
27
|
// the DELETE itself surfaces the 404, so the extra request is skipped.
|
|
22
28
|
if (!options.force)
|
|
23
|
-
await client.getTargetExec(workspace, execId);
|
|
29
|
+
await client.getTargetExec(workspace, target_id, execId);
|
|
24
30
|
const json = options.format === 'json';
|
|
25
31
|
const confirmed = await output_1.default.confirmDestructive(options.force, (0, texts_1.TXT_TARGET_EXEC_KILL_CONFIRM)(execId), json);
|
|
26
32
|
if (!confirmed)
|
|
27
33
|
output_1.default.exitResult(json, { killed: null });
|
|
28
|
-
await client.cancelTargetExec(workspace, execId);
|
|
34
|
+
await client.cancelTargetExec(workspace, target_id, execId);
|
|
29
35
|
output_1.default.exitResult(json, { killed: execId }, (0, texts_1.TXT_TARGET_EXEC_KILLED)(execId));
|
|
30
36
|
});
|
|
31
37
|
exports.default = commandTargetExecKill;
|
|
@@ -10,23 +10,28 @@ const output_1 = __importDefault(require("../../../output"));
|
|
|
10
10
|
const scope_1 = require("../scope");
|
|
11
11
|
const commandTargetExecLogs = (0, utils_1.newCommand)('logs', texts_1.DESC_COMMAND_TARGET_EXEC_LOGS, { requiredScopes: [utils_1.REST_API_SCOPE.TARGET_READ], helpText: texts_1.HELP_TARGET_EXEC_LOGS_JSONL, examples: texts_1.EXAMPLE_TARGET_EXEC_LOGS });
|
|
12
12
|
commandTargetExecLogs.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
13
|
+
commandTargetExecLogs.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
14
|
+
commandTargetExecLogs.option('--pipeline <identifier>', texts_1.OPTION_TARGET_PIPELINE);
|
|
15
|
+
commandTargetExecLogs.option('--environment <identifier>', texts_1.OPTION_TARGET_ENVIRONMENT);
|
|
13
16
|
commandTargetExecLogs.option('--offset <n>', texts_1.OPTION_TARGET_EXEC_LOG_OFFSET);
|
|
14
17
|
commandTargetExecLogs.option('--limit <n>', texts_1.OPTION_TARGET_EXEC_LOG_LIMIT);
|
|
18
|
+
commandTargetExecLogs.argument('<identifier>', texts_1.OPTION_TARGET_IDENTIFIER);
|
|
15
19
|
commandTargetExecLogs.argument('<exec-id>', texts_1.OPTION_TARGET_EXEC_ID);
|
|
16
20
|
commandTargetExecLogs.option('--format <text|jsonl>', texts_1.OPTION_EXEC_FORMAT_JSONL);
|
|
17
21
|
commandTargetExecLogs.option('--exit-code', texts_1.OPTION_EXEC_EXIT_CODE);
|
|
18
|
-
commandTargetExecLogs.action(async (execId, options) => {
|
|
22
|
+
commandTargetExecLogs.action(async (identifier, execId, options) => {
|
|
19
23
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
20
24
|
const client = input_1.default.restApiTokenClient();
|
|
25
|
+
const target_id = await (0, scope_1.resolveTargetId)(client, workspace, identifier, options);
|
|
21
26
|
const offset = options.offset ? parseInt(options.offset, 10) : 0;
|
|
22
27
|
const limit = options.limit ? parseInt(options.limit, 10) : undefined;
|
|
23
|
-
const { truncated } = await (0, scope_1.forwardExecLog)(client, workspace, execId, offset, options.format === 'jsonl'
|
|
28
|
+
const { truncated } = await (0, scope_1.forwardExecLog)(client, workspace, target_id, execId, offset, options.format === 'jsonl'
|
|
24
29
|
? (lines) => lines.forEach((data) => output_1.default.json({ type: 'log', data }))
|
|
25
30
|
: undefined, limit);
|
|
26
31
|
if (truncated)
|
|
27
32
|
output_1.default.noteWarning(texts_1.WARN_TARGET_EXEC_TRUNCATED);
|
|
28
33
|
if (options.format === 'jsonl' || options.exitCode) {
|
|
29
|
-
const exec = await client.getTargetExec(workspace, execId);
|
|
34
|
+
const exec = await client.getTargetExec(workspace, target_id, execId);
|
|
30
35
|
const code = options.exitCode ? (0, utils_1.executionExitCode)(exec.status) : undefined;
|
|
31
36
|
if (options.format === 'jsonl')
|
|
32
37
|
output_1.default.json({
|
|
@@ -7,15 +7,21 @@ const utils_1 = require("../../../utils");
|
|
|
7
7
|
const texts_1 = require("../../../texts");
|
|
8
8
|
const input_1 = __importDefault(require("../../../input"));
|
|
9
9
|
const output_1 = __importDefault(require("../../../output"));
|
|
10
|
+
const scope_1 = require("../scope");
|
|
10
11
|
const commandTargetExecStatus = (0, utils_1.newCommand)('status', texts_1.DESC_COMMAND_TARGET_EXEC_STATUS, { requiredScopes: [utils_1.REST_API_SCOPE.TARGET_READ], examples: texts_1.EXAMPLE_TARGET_EXEC_STATUS, helpText: texts_1.HELP_TARGET_EXEC_STATUS });
|
|
11
12
|
commandTargetExecStatus.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
13
|
+
commandTargetExecStatus.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
14
|
+
commandTargetExecStatus.option('--pipeline <identifier>', texts_1.OPTION_TARGET_PIPELINE);
|
|
15
|
+
commandTargetExecStatus.option('--environment <identifier>', texts_1.OPTION_TARGET_ENVIRONMENT);
|
|
12
16
|
commandTargetExecStatus.option('--format <text|json>', texts_1.OPTION_EXEC_FORMAT_JSON);
|
|
17
|
+
commandTargetExecStatus.argument('<identifier>', texts_1.OPTION_TARGET_IDENTIFIER);
|
|
13
18
|
commandTargetExecStatus.argument('<exec-id>', texts_1.OPTION_TARGET_EXEC_ID);
|
|
14
19
|
commandTargetExecStatus.option('--exit-code', texts_1.OPTION_EXEC_EXIT_CODE);
|
|
15
|
-
commandTargetExecStatus.action(async (execId, options) => {
|
|
20
|
+
commandTargetExecStatus.action(async (identifier, execId, options) => {
|
|
16
21
|
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
17
22
|
const client = input_1.default.restApiTokenClient();
|
|
18
|
-
const
|
|
23
|
+
const target_id = await (0, scope_1.resolveTargetId)(client, workspace, identifier, options);
|
|
24
|
+
const exec = await client.getTargetExec(workspace, target_id, execId);
|
|
19
25
|
const code = options.exitCode ? (0, utils_1.executionExitCode)(exec.status) : undefined;
|
|
20
26
|
if (options.format === 'json') {
|
|
21
27
|
output_1.default.json(exec);
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.resolveTargetScope = exports.targetScopeOf = exports.targetAddressOf = exports.forwardExecLog = exports.resolveTargetId = void 0;
|
|
6
|
+
exports.resolveTargetScope = exports.targetScopeOf = exports.targetAddressOf = exports.forwardExecLog = exports.targetExecRef = exports.resolveTargetId = void 0;
|
|
7
7
|
const utils_1 = require("../../utils");
|
|
8
8
|
const texts_1 = require("../../texts");
|
|
9
9
|
const output_1 = __importDefault(require("../../output"));
|
|
@@ -18,10 +18,11 @@ const input_1 = __importDefault(require("../../input"));
|
|
|
18
18
|
// line - that is how workspace targets stay addressable from a line context,
|
|
19
19
|
// which the CLI enters on its own from BUDDY_PROJECT or a linked project.
|
|
20
20
|
//
|
|
21
|
-
// strictLine is for
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
21
|
+
// strictLine is for commands that act on the target itself (update/delete/
|
|
22
|
+
// exec command): the requested line - from a flag, BUDDY_PROJECT or a linked
|
|
23
|
+
// project alike - is a statement "the target of this project/pipeline/
|
|
24
|
+
// environment", so no fallback. An explicit flag additionally gets the scope
|
|
25
|
+
// verified once more in case the API resolves loosely again.
|
|
25
26
|
const resolveTargetId = async (client, workspace, identifier, options, strictLine = false) => {
|
|
26
27
|
const project = input_1.default.restApiProject(options.project, true);
|
|
27
28
|
const line = input_1.default.targetLine(project, options.pipeline, options.environment);
|
|
@@ -57,6 +58,24 @@ const resolveTargetId = async (client, workspace, identifier, options, strictLin
|
|
|
57
58
|
return resolved.target_id;
|
|
58
59
|
};
|
|
59
60
|
exports.resolveTargetId = resolveTargetId;
|
|
61
|
+
// Executions live under their target, so follow-up commands printed in hints
|
|
62
|
+
// need the target again - with the line it was resolved through, or a
|
|
63
|
+
// project/pipeline/environment target would not resolve on the next call.
|
|
64
|
+
// The project is the one resolveTargetId used, so one implied by
|
|
65
|
+
// BUDDY_PROJECT or a linked directory is spelled out: the hint has to work
|
|
66
|
+
// from another shell or directory too.
|
|
67
|
+
const targetExecRef = (identifier, options) => {
|
|
68
|
+
let ref = identifier;
|
|
69
|
+
const project = input_1.default.restApiProject(options.project, true);
|
|
70
|
+
if (project)
|
|
71
|
+
ref += ` -p ${project}`;
|
|
72
|
+
if (options.pipeline)
|
|
73
|
+
ref += ` --pipeline ${options.pipeline}`;
|
|
74
|
+
if (options.environment)
|
|
75
|
+
ref += ` --environment ${options.environment}`;
|
|
76
|
+
return ref;
|
|
77
|
+
};
|
|
78
|
+
exports.targetExecRef = targetExecRef;
|
|
60
79
|
// Lines the CLI requests per log fetch.
|
|
61
80
|
const EXEC_LOG_PAGE = 1000;
|
|
62
81
|
// The exec log endpoint pages by line offset; its `truncated` field
|
|
@@ -66,7 +85,7 @@ const EXEC_LOG_PAGE = 1000;
|
|
|
66
85
|
// next_offset - offset lines are emitted to avoid re-printing the partial
|
|
67
86
|
// line on the next pass. A page shorter than requested means the committed
|
|
68
87
|
// log is drained, so the common case costs a single request.
|
|
69
|
-
const forwardExecLog = async (client, workspace, execId, startOffset, emitPage = (lines) => output_1.default.data(lines.join('\n')), maxLines) => {
|
|
88
|
+
const forwardExecLog = async (client, workspace, targetId, execId, startOffset, emitPage = (lines) => output_1.default.data(lines.join('\n')), maxLines) => {
|
|
70
89
|
let offset = startOffset;
|
|
71
90
|
let emitted = 0;
|
|
72
91
|
let truncated = false;
|
|
@@ -76,7 +95,7 @@ const forwardExecLog = async (client, workspace, execId, startOffset, emitPage =
|
|
|
76
95
|
: Math.min(EXEC_LOG_PAGE, maxLines - emitted);
|
|
77
96
|
if (pageLimit <= 0)
|
|
78
97
|
break;
|
|
79
|
-
const log = await client.getTargetExecLog(workspace, execId, offset, pageLimit);
|
|
98
|
+
const log = await client.getTargetExecLog(workspace, targetId, execId, offset, pageLimit);
|
|
80
99
|
truncated = truncated || !!log.truncated;
|
|
81
100
|
const next = log.next_offset ?? offset;
|
|
82
101
|
if (next <= offset)
|
package/distTs/src/texts.js
CHANGED
|
@@ -502,7 +502,7 @@ exports.OPTION_EXEC_FORMAT_JSONL = 'Output format: jsonl, text. JSONL CLI errors
|
|
|
502
502
|
exports.OPTION_EXEC_FORMAT_JSON = 'Output format: json, text. JSON CLI errors: {error:{code,message,hint}}, exit 1 (2 or 3 with --exit-code). Default: text';
|
|
503
503
|
const ERR_EXEC_STATUS_UNKNOWN = (status) => `Unknown execution status: ${status ?? '(missing)'}`;
|
|
504
504
|
exports.ERR_EXEC_STATUS_UNKNOWN = ERR_EXEC_STATUS_UNKNOWN;
|
|
505
|
-
const TXT_TARGET_EXEC_RECOVERY = (id) => `Execution ID: ${id}. Run 'bdy target exec logs ${id}' to read logs.`;
|
|
505
|
+
const TXT_TARGET_EXEC_RECOVERY = (target, id) => `Execution ID: ${id}. Run 'bdy target exec logs ${target} ${id}' to read logs.`;
|
|
506
506
|
exports.TXT_TARGET_EXEC_RECOVERY = TXT_TARGET_EXEC_RECOVERY;
|
|
507
507
|
const ERR_PIPELINE_RUN_STATUS_UNKNOWN = (status) => `Unknown pipeline run status: ${status ?? '(missing)'}`;
|
|
508
508
|
exports.ERR_PIPELINE_RUN_STATUS_UNKNOWN = ERR_PIPELINE_RUN_STATUS_UNKNOWN;
|
|
@@ -1124,18 +1124,18 @@ exports.TXT_TARGET_DELETED = TXT_TARGET_DELETED;
|
|
|
1124
1124
|
// Target exec messages
|
|
1125
1125
|
const TXT_TARGET_EXEC_ID = (id) => `Execution id: ${id}`;
|
|
1126
1126
|
exports.TXT_TARGET_EXEC_ID = TXT_TARGET_EXEC_ID;
|
|
1127
|
-
const TXT_TARGET_EXEC_BACKGROUND = (execId) => `Command started in background: ${execId}. To view status or logs of the execution run:
|
|
1128
|
-
bdy tg exec status ${execId}
|
|
1129
|
-
bdy tg exec logs ${execId}`;
|
|
1127
|
+
const TXT_TARGET_EXEC_BACKGROUND = (target, execId) => `Command started in background: ${execId}. To view status or logs of the execution run:
|
|
1128
|
+
bdy tg exec status ${target} ${execId}
|
|
1129
|
+
bdy tg exec logs ${target} ${execId}`;
|
|
1130
1130
|
exports.TXT_TARGET_EXEC_BACKGROUND = TXT_TARGET_EXEC_BACKGROUND;
|
|
1131
|
-
const TXT_TARGET_EXEC_SUCCESS = (execId) => `Command finished successfully: ${execId}. To view logs of the execution run:
|
|
1132
|
-
bdy tg exec logs ${execId}`;
|
|
1131
|
+
const TXT_TARGET_EXEC_SUCCESS = (target, execId) => `Command finished successfully: ${execId}. To view logs of the execution run:
|
|
1132
|
+
bdy tg exec logs ${target} ${execId}`;
|
|
1133
1133
|
exports.TXT_TARGET_EXEC_SUCCESS = TXT_TARGET_EXEC_SUCCESS;
|
|
1134
|
-
const TXT_TARGET_EXEC_FAILED = (execId, reason) => `Command failed${reason ? ` (${reason})` : ''}: ${execId}. To view logs of the execution run:
|
|
1135
|
-
bdy tg exec logs ${execId}`;
|
|
1134
|
+
const TXT_TARGET_EXEC_FAILED = (target, execId, reason) => `Command failed${reason ? ` (${reason})` : ''}: ${execId}. To view logs of the execution run:
|
|
1135
|
+
bdy tg exec logs ${target} ${execId}`;
|
|
1136
1136
|
exports.TXT_TARGET_EXEC_FAILED = TXT_TARGET_EXEC_FAILED;
|
|
1137
|
-
const TXT_TARGET_EXEC_CANCELLED = (execId) => `Command cancelled: ${execId}. To view logs of the execution run:
|
|
1138
|
-
bdy tg exec logs ${execId}`;
|
|
1137
|
+
const TXT_TARGET_EXEC_CANCELLED = (target, execId) => `Command cancelled: ${execId}. To view logs of the execution run:
|
|
1138
|
+
bdy tg exec logs ${target} ${execId}`;
|
|
1139
1139
|
exports.TXT_TARGET_EXEC_CANCELLED = TXT_TARGET_EXEC_CANCELLED;
|
|
1140
1140
|
exports.WARN_TARGET_EXEC_TRUNCATED = 'Command output was truncated by the server';
|
|
1141
1141
|
const TXT_TARGET_EXEC_KILL_CONFIRM = (execId) => `Are you sure you want to cancel execution '${execId}'?`;
|
|
@@ -2166,21 +2166,21 @@ exports.EXAMPLE_TARGET_EXEC_COMMAND = [
|
|
|
2166
2166
|
exports.EXAMPLE_TARGET_EXEC_STATUS = [
|
|
2167
2167
|
{
|
|
2168
2168
|
description: 'return the execution state using semantic exit codes',
|
|
2169
|
-
command: 'bdy target exec status exec-id --exit-code',
|
|
2169
|
+
command: 'bdy target exec status target-identifier exec-id --exit-code',
|
|
2170
2170
|
},
|
|
2171
2171
|
{
|
|
2172
2172
|
description: 'show status of execution:',
|
|
2173
|
-
command: 'bdy tg exec status exec-id',
|
|
2173
|
+
command: 'bdy tg exec status target-identifier exec-id',
|
|
2174
2174
|
},
|
|
2175
2175
|
];
|
|
2176
2176
|
exports.EXAMPLE_TARGET_EXEC_KILL = [
|
|
2177
2177
|
{
|
|
2178
2178
|
description: 'cancel running execution:',
|
|
2179
|
-
command: 'bdy tg exec kill exec-id',
|
|
2179
|
+
command: 'bdy tg exec kill target-identifier exec-id',
|
|
2180
2180
|
},
|
|
2181
2181
|
{
|
|
2182
2182
|
description: 'cancel running execution and automatically confirm:',
|
|
2183
|
-
command: 'bdy tg exec kill exec-id -f',
|
|
2183
|
+
command: 'bdy tg exec kill target-identifier exec-id -f',
|
|
2184
2184
|
},
|
|
2185
2185
|
];
|
|
2186
2186
|
exports.EXAMPLE_TARGET_EXEC_LIST = [
|
|
@@ -2196,19 +2196,19 @@ exports.EXAMPLE_TARGET_EXEC_LIST = [
|
|
|
2196
2196
|
exports.EXAMPLE_TARGET_EXEC_LOGS = [
|
|
2197
2197
|
{
|
|
2198
2198
|
description: 'return the execution state using semantic exit codes',
|
|
2199
|
-
command: 'bdy target exec logs exec-id --exit-code',
|
|
2199
|
+
command: 'bdy target exec logs target-identifier exec-id --exit-code',
|
|
2200
2200
|
},
|
|
2201
2201
|
{
|
|
2202
2202
|
description: 'show logs of execution:',
|
|
2203
|
-
command: 'bdy tg exec logs exec-id',
|
|
2203
|
+
command: 'bdy tg exec logs target-identifier exec-id',
|
|
2204
2204
|
},
|
|
2205
2205
|
{
|
|
2206
2206
|
description: 'show logs of execution starting from line 100:',
|
|
2207
|
-
command: 'bdy tg exec logs exec-id --offset 100',
|
|
2207
|
+
command: 'bdy tg exec logs target-identifier exec-id --offset 100',
|
|
2208
2208
|
},
|
|
2209
2209
|
{
|
|
2210
2210
|
description: 'Return log records as JSONL',
|
|
2211
|
-
command: 'bdy target exec logs execution-id --format jsonl',
|
|
2211
|
+
command: 'bdy target exec logs target-identifier execution-id --format jsonl',
|
|
2212
2212
|
},
|
|
2213
2213
|
];
|
|
2214
2214
|
exports.EXAMPLE_ENVIRONMENT_LIST = [
|
|
@@ -10,7 +10,7 @@ const undici_1 = __importDefault(require("undici"));
|
|
|
10
10
|
const TIMEOUT = 120000;
|
|
11
11
|
const openSocket = (port, path) => {
|
|
12
12
|
return new Promise((resolve, reject) => {
|
|
13
|
-
const ws = new ws_1.WebSocket(`ws://
|
|
13
|
+
const ws = new ws_1.WebSocket(`ws://127.0.0.1:${port}${path}`);
|
|
14
14
|
ws.on('error', () => {
|
|
15
15
|
reject(new Error(texts_1.ERR_FAILED_TO_CONNECT_TO_AGENT));
|
|
16
16
|
});
|
|
@@ -26,7 +26,7 @@ const makeRequest = async (port, path, body) => {
|
|
|
26
26
|
}, TIMEOUT);
|
|
27
27
|
logger_1.default.debug(`TUNNEL API AGENT REQUEST: :${port}${path}`);
|
|
28
28
|
logger_1.default.debug(body);
|
|
29
|
-
const response = await undici_1.default.fetch(`http://
|
|
29
|
+
const response = await undici_1.default.fetch(`http://127.0.0.1:${port}${path}`, {
|
|
30
30
|
body: body ? JSON.stringify(body) : null,
|
|
31
31
|
headers: { 'Content-Type': 'application/json' },
|
|
32
32
|
method: 'POST',
|