bdy 1.25.6-dev → 1.25.7-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/cliCommand.js +2 -0
- package/distTs/src/cliIndex.js +10 -0
- package/distTs/src/command/context/add.js +38 -0
- package/distTs/src/command/context/list.js +33 -0
- package/distTs/src/command/context/remove.js +36 -0
- package/distTs/src/command/context/show.js +35 -0
- package/distTs/src/command/context/use.js +25 -0
- package/distTs/src/command/context.js +22 -0
- package/distTs/src/command/login.js +1 -0
- package/distTs/src/command/logout.js +1 -0
- package/distTs/src/command/project/link.js +1 -0
- package/distTs/src/command/register.js +1 -0
- package/distTs/src/command/whoami.js +7 -10
- package/distTs/src/command/workspace/get.js +2 -2
- package/distTs/src/command/workspace/set.js +1 -0
- package/distTs/src/input.js +204 -26
- package/distTs/src/output.js +7 -5
- package/distTs/src/project/context.js +97 -0
- package/distTs/src/texts.js +128 -3
- package/distTs/src/tunnel/cfg.js +43 -4
- package/distTs/src/types/context.js +2 -0
- package/package.json +1 -1
package/distTs/package.json
CHANGED
package/distTs/src/cliCommand.js
CHANGED
|
@@ -52,11 +52,13 @@ class CliCommand extends commander_1.Command {
|
|
|
52
52
|
hideVersionUpdate;
|
|
53
53
|
agentPort;
|
|
54
54
|
skipPre = false;
|
|
55
|
+
usesDefaultContext = false;
|
|
55
56
|
defaultErrorFormat = 'text';
|
|
56
57
|
metadata;
|
|
57
58
|
constructor(name, metadata = {}) {
|
|
58
59
|
super(name);
|
|
59
60
|
this.metadata = metadata;
|
|
61
|
+
this.option('--context <name>', texts_1.OPTION_CONTEXT);
|
|
60
62
|
}
|
|
61
63
|
addOption(option) {
|
|
62
64
|
if (option.long === '--format' && !option.argChoices) {
|
package/distTs/src/cliIndex.js
CHANGED
|
@@ -30,10 +30,19 @@ const environment_1 = __importDefault(require("./command/environment"));
|
|
|
30
30
|
const register_1 = __importDefault(require("./command/register"));
|
|
31
31
|
const mcp_1 = __importDefault(require("./command/mcp"));
|
|
32
32
|
const discover_1 = __importDefault(require("./command/discover"));
|
|
33
|
+
const context_1 = __importDefault(require("./command/context"));
|
|
34
|
+
const input_1 = __importDefault(require("./input"));
|
|
33
35
|
const cliError_1 = __importDefault(require("./cliError"));
|
|
36
|
+
const cliCommand_1 = __importDefault(require("./cliCommand"));
|
|
34
37
|
const texts_2 = require("./texts");
|
|
35
38
|
function cliIndex() {
|
|
36
39
|
const program = (0, utils_1.newCommand)('bdy', texts_1.DESC_PROGRAM);
|
|
40
|
+
program.hook('preAction', (_, command) => {
|
|
41
|
+
const options = command.optsWithGlobals();
|
|
42
|
+
input_1.default.configureContext(command instanceof cliCommand_1.default && command.usesDefaultContext
|
|
43
|
+
? { ...options, context: 'default' }
|
|
44
|
+
: options);
|
|
45
|
+
});
|
|
37
46
|
program.hook('preAction', pre_1.default);
|
|
38
47
|
program.configureHelp({
|
|
39
48
|
formatHelp: utils_1.formatHelp,
|
|
@@ -65,6 +74,7 @@ function cliIndex() {
|
|
|
65
74
|
program.addCommand(api_1.default);
|
|
66
75
|
program.addCommand(mcp_1.default);
|
|
67
76
|
program.addCommand(discover_1.default);
|
|
77
|
+
program.addCommand(context_1.default);
|
|
68
78
|
program.action((_, cmd) => {
|
|
69
79
|
if (cmd.args.length > 0) {
|
|
70
80
|
output_1.default.exitError(new cliError_1.default('unknown_command', (0, texts_1.ERR_COMMAND_NOT_FOUND)(cmd.args[0]), (0, texts_2.TXT_CLI_USAGE_HINT)('bdy')));
|
|
@@ -0,0 +1,38 @@
|
|
|
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 input_1 = __importDefault(require("../../input"));
|
|
8
|
+
const output_1 = __importDefault(require("../../output"));
|
|
9
|
+
const cfg_1 = __importDefault(require("../../tunnel/cfg"));
|
|
10
|
+
const cliError_1 = __importDefault(require("../../cliError"));
|
|
11
|
+
const texts_1 = require("../../texts");
|
|
12
|
+
const command = (0, utils_1.newCommand)('add', texts_1.DESC_CONTEXT_ADD, {
|
|
13
|
+
requiredScopes: [],
|
|
14
|
+
examples: texts_1.EXAMPLE_CONTEXT_ADD,
|
|
15
|
+
helpText: texts_1.HELP_CONTEXT_ADD,
|
|
16
|
+
});
|
|
17
|
+
command.skipPre = true;
|
|
18
|
+
command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
|
|
19
|
+
command.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
20
|
+
command.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
21
|
+
command.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
22
|
+
command.option('--token <token>', texts_1.OPTION_CONTEXT_TOKEN);
|
|
23
|
+
command.option('--api <endpoint>', texts_1.OPTION_CONTEXT_API);
|
|
24
|
+
command.option('--from-link', texts_1.OPTION_CONTEXT_LINK);
|
|
25
|
+
command.option('--from-git', texts_1.OPTION_CONTEXT_GIT);
|
|
26
|
+
command.option('--remote <name>', texts_1.OPTION_CONTEXT_REMOTE);
|
|
27
|
+
command.action((name, options) => {
|
|
28
|
+
input_1.default.contextEditableName(name);
|
|
29
|
+
if (Object.hasOwn(cfg_1.default.getContexts(), name))
|
|
30
|
+
throw new cliError_1.default('usage_error', (0, texts_1.ERR_CONTEXT_EXISTS)(name));
|
|
31
|
+
const context = input_1.default.contextDefinition(options);
|
|
32
|
+
cfg_1.default.setContext(name, context);
|
|
33
|
+
if (options.format === 'json')
|
|
34
|
+
output_1.default.json({ name, source: context.source });
|
|
35
|
+
else
|
|
36
|
+
output_1.default.normal((0, texts_1.TXT_CONTEXT_SAVED)(name));
|
|
37
|
+
});
|
|
38
|
+
exports.default = command;
|
|
@@ -0,0 +1,33 @@
|
|
|
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 output_1 = __importDefault(require("../../output"));
|
|
8
|
+
const cfg_1 = __importDefault(require("../../tunnel/cfg"));
|
|
9
|
+
const texts_1 = require("../../texts");
|
|
10
|
+
const command = (0, utils_1.newCommand)('list', texts_1.DESC_CONTEXT_LIST, {
|
|
11
|
+
requiredScopes: [],
|
|
12
|
+
examples: texts_1.EXAMPLE_CONTEXT_LIST,
|
|
13
|
+
helpText: texts_1.HELP_CONTEXT_LIST,
|
|
14
|
+
});
|
|
15
|
+
command.skipPre = true;
|
|
16
|
+
command.alias('ls');
|
|
17
|
+
command.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
18
|
+
command.action((options) => {
|
|
19
|
+
const builtins = ['default', 'git', 'link'];
|
|
20
|
+
const active = cfg_1.default.getActiveContext();
|
|
21
|
+
const values = [...builtins, ...Object.keys(cfg_1.default.getContexts()).sort()].map((name) => ({
|
|
22
|
+
name,
|
|
23
|
+
active: name === active,
|
|
24
|
+
builtin: builtins.includes(name),
|
|
25
|
+
source: cfg_1.default.getContext(name)?.source || 'default',
|
|
26
|
+
}));
|
|
27
|
+
if (options.format === 'json')
|
|
28
|
+
output_1.default.json(values);
|
|
29
|
+
else
|
|
30
|
+
for (const item of values)
|
|
31
|
+
output_1.default.normal(`${item.active ? '*' : ' '} ${item.name}`);
|
|
32
|
+
});
|
|
33
|
+
exports.default = command;
|
|
@@ -0,0 +1,36 @@
|
|
|
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 input_1 = __importDefault(require("../../input"));
|
|
8
|
+
const output_1 = __importDefault(require("../../output"));
|
|
9
|
+
const cfg_1 = __importDefault(require("../../tunnel/cfg"));
|
|
10
|
+
const texts_1 = require("../../texts");
|
|
11
|
+
const command = (0, utils_1.newCommand)('remove', texts_1.DESC_CONTEXT_REMOVE, {
|
|
12
|
+
requiredScopes: [],
|
|
13
|
+
examples: texts_1.EXAMPLE_CONTEXT_REMOVE,
|
|
14
|
+
helpText: texts_1.HELP_CONTEXT_REMOVE,
|
|
15
|
+
});
|
|
16
|
+
command.skipPre = true;
|
|
17
|
+
command.alias('rm');
|
|
18
|
+
command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
|
|
19
|
+
command.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
20
|
+
command.option('-f, --force', texts_1.OPTION_CONFIRM_FORCE);
|
|
21
|
+
command.action(async (name, options) => {
|
|
22
|
+
input_1.default.contextEditableName(name);
|
|
23
|
+
cfg_1.default.getContext(name);
|
|
24
|
+
const confirmed = options.force ||
|
|
25
|
+
(await output_1.default.confirm((0, texts_1.TXT_CONTEXT_REMOVE_CONFIRM)(name), options.format === 'json'));
|
|
26
|
+
if (confirmed)
|
|
27
|
+
cfg_1.default.removeContext(name);
|
|
28
|
+
if (options.format === 'json')
|
|
29
|
+
output_1.default.json({
|
|
30
|
+
removed: confirmed ? name : null,
|
|
31
|
+
active: cfg_1.default.getActiveContext(),
|
|
32
|
+
});
|
|
33
|
+
else if (confirmed)
|
|
34
|
+
output_1.default.normal((0, texts_1.TXT_CONTEXT_REMOVED)(name));
|
|
35
|
+
});
|
|
36
|
+
exports.default = command;
|
|
@@ -0,0 +1,35 @@
|
|
|
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 input_1 = __importDefault(require("../../input"));
|
|
8
|
+
const output_1 = __importDefault(require("../../output"));
|
|
9
|
+
const texts_1 = require("../../texts");
|
|
10
|
+
const command = (0, utils_1.newCommand)('show', texts_1.DESC_CONTEXT_SHOW, {
|
|
11
|
+
requiredScopes: [],
|
|
12
|
+
examples: texts_1.EXAMPLE_CONTEXT_SHOW,
|
|
13
|
+
helpText: texts_1.HELP_CONTEXT_SHOW,
|
|
14
|
+
});
|
|
15
|
+
command.skipPre = true;
|
|
16
|
+
command.argument('[name]', texts_1.OPTION_CONTEXT_NAME);
|
|
17
|
+
command.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
18
|
+
command.action((name, options, cmd) => {
|
|
19
|
+
if (name)
|
|
20
|
+
input_1.default.configureContext({ ...cmd.optsWithGlobals(), context: name });
|
|
21
|
+
const result = input_1.default.showContext();
|
|
22
|
+
if (options.format === 'json')
|
|
23
|
+
output_1.default.json(result);
|
|
24
|
+
else
|
|
25
|
+
output_1.default.object({
|
|
26
|
+
[texts_1.TXT_CONTEXT_LABEL]: result.name,
|
|
27
|
+
[texts_1.TXT_CONTEXT_SOURCE_LABEL]: result.source,
|
|
28
|
+
[texts_1.TXT_CONTEXT_WORKSPACE_LABEL]: `${result.workspace || '-'} (${result.sources.workspace || '-'})`,
|
|
29
|
+
[texts_1.TXT_CONTEXT_PROJECT_LABEL]: `${result.project || '-'} (${result.sources.project || '-'})`,
|
|
30
|
+
[texts_1.TXT_CONTEXT_API_LABEL]: `${result.api} (${result.sources.api})`,
|
|
31
|
+
[texts_1.TXT_CONTEXT_REMOTE_LABEL]: result.remote || '-',
|
|
32
|
+
[texts_1.TXT_CONTEXT_TOKEN_LABEL]: `${result.token.available ? texts_1.TXT_CONTEXT_TOKEN_AVAILABLE : texts_1.TXT_CONTEXT_TOKEN_MISSING} (${result.token.source || '-'})`,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
exports.default = command;
|
|
@@ -0,0 +1,25 @@
|
|
|
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 output_1 = __importDefault(require("../../output"));
|
|
8
|
+
const cfg_1 = __importDefault(require("../../tunnel/cfg"));
|
|
9
|
+
const texts_1 = require("../../texts");
|
|
10
|
+
const command = (0, utils_1.newCommand)('use', texts_1.DESC_CONTEXT_USE, {
|
|
11
|
+
requiredScopes: [],
|
|
12
|
+
examples: texts_1.EXAMPLE_CONTEXT_USE,
|
|
13
|
+
helpText: texts_1.HELP_CONTEXT_USE,
|
|
14
|
+
});
|
|
15
|
+
command.skipPre = true;
|
|
16
|
+
command.argument('<name>', texts_1.OPTION_CONTEXT_NAME);
|
|
17
|
+
command.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
18
|
+
command.action((name, options) => {
|
|
19
|
+
cfg_1.default.setActiveContext(name);
|
|
20
|
+
if (options.format === 'json')
|
|
21
|
+
output_1.default.json({ active: name });
|
|
22
|
+
else
|
|
23
|
+
output_1.default.normal((0, texts_1.TXT_CONTEXT_ACTIVE)(name));
|
|
24
|
+
});
|
|
25
|
+
exports.default = command;
|
|
@@ -0,0 +1,22 @@
|
|
|
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 add_1 = __importDefault(require("./context/add"));
|
|
9
|
+
const list_1 = __importDefault(require("./context/list"));
|
|
10
|
+
const show_1 = __importDefault(require("./context/show"));
|
|
11
|
+
const use_1 = __importDefault(require("./context/use"));
|
|
12
|
+
const remove_1 = __importDefault(require("./context/remove"));
|
|
13
|
+
const commandContext = (0, utils_1.newCommand)('context', texts_1.DESC_CONTEXT, {
|
|
14
|
+
requiredScopes: [],
|
|
15
|
+
helpText: texts_1.HELP_CONTEXT,
|
|
16
|
+
});
|
|
17
|
+
commandContext.addCommand(add_1.default);
|
|
18
|
+
commandContext.addCommand(list_1.default);
|
|
19
|
+
commandContext.addCommand(show_1.default);
|
|
20
|
+
commandContext.addCommand(use_1.default);
|
|
21
|
+
commandContext.addCommand(remove_1.default);
|
|
22
|
+
exports.default = commandContext;
|
|
@@ -293,6 +293,7 @@ async function authorize(options, forceRegisterEmail, forceRegisterName) {
|
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
|
|
296
|
+
commandLogin.usesDefaultContext = true;
|
|
296
297
|
commandLogin.alias('sign-in');
|
|
297
298
|
commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
298
299
|
commandLogin.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
|
|
@@ -9,6 +9,7 @@ const texts_1 = require("../texts");
|
|
|
9
9
|
const utils_1 = require("../utils");
|
|
10
10
|
const input_1 = __importDefault(require("../input"));
|
|
11
11
|
const commandLogout = (0, utils_1.newCommand)('logout', texts_1.DESC_COMMAND_LOGOUT);
|
|
12
|
+
commandLogout.usesDefaultContext = true;
|
|
12
13
|
const tryRemovingApp = async () => {
|
|
13
14
|
try {
|
|
14
15
|
const clientId = cfg_1.default.getApiClientId();
|
|
@@ -10,6 +10,7 @@ const output_1 = __importDefault(require("../../output"));
|
|
|
10
10
|
const node_path_1 = require("node:path");
|
|
11
11
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
12
|
const commandProjectLink = (0, utils_1.newCommand)('link', texts_1.DESC_COMMAND_PROJECT_LINK);
|
|
13
|
+
commandProjectLink.usesDefaultContext = true;
|
|
13
14
|
commandProjectLink.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
14
15
|
commandProjectLink.option('-r, --relink', texts_1.OPT_COMMAND_PROJECT_LINK_RELINK);
|
|
15
16
|
commandProjectLink.option('-g, --git', texts_1.OPT_COMMAND_PROJECT_LINK_GIT);
|
|
@@ -8,6 +8,7 @@ const texts_1 = require("../texts");
|
|
|
8
8
|
const output_1 = __importDefault(require("../output"));
|
|
9
9
|
const login_1 = require("./login");
|
|
10
10
|
const commandRegister = (0, utils_1.newCommand)('register', texts_1.DESC_COMMAND_REGISTER);
|
|
11
|
+
commandRegister.usesDefaultContext = true;
|
|
11
12
|
commandRegister.alias('sign-up');
|
|
12
13
|
commandRegister.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
|
|
13
14
|
commandRegister.option('--region <region>', texts_1.OPTION_REST_API_REGION);
|
|
@@ -5,16 +5,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const utils_1 = require("../utils");
|
|
7
7
|
const texts_1 = require("../texts");
|
|
8
|
-
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
9
8
|
const output_1 = __importDefault(require("../output"));
|
|
10
9
|
const input_1 = __importDefault(require("../input"));
|
|
11
|
-
const
|
|
10
|
+
const cfg_1 = __importDefault(require("../project/cfg"));
|
|
12
11
|
const commandWhoami = (0, utils_1.newCommand)('whoami', texts_1.DESC_COMMAND_WHOAMI);
|
|
13
12
|
commandWhoami.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
14
13
|
commandWhoami.action(async (options) => {
|
|
15
|
-
const workspace =
|
|
16
|
-
const localWorkspace = cfg_2.default.getWorkspace();
|
|
17
|
-
const localProject = cfg_2.default.getProject();
|
|
14
|
+
const { workspace, project, localWorkspace } = input_1.default.accountScope();
|
|
18
15
|
const client = input_1.default.restApiTokenClient();
|
|
19
16
|
const user = await client.getInvoker();
|
|
20
17
|
if (!user) {
|
|
@@ -30,12 +27,12 @@ commandWhoami.action(async (options) => {
|
|
|
30
27
|
else {
|
|
31
28
|
obj.Workspace = !workspace ? texts_1.TXT_WHOAMI_NO_WORKSPACE : workspace;
|
|
32
29
|
}
|
|
33
|
-
if (
|
|
34
|
-
obj.Project =
|
|
30
|
+
if (project) {
|
|
31
|
+
obj.Project = project;
|
|
35
32
|
}
|
|
36
|
-
const vtSuite =
|
|
37
|
-
const utSuite =
|
|
38
|
-
const crawlSuite =
|
|
33
|
+
const vtSuite = cfg_1.default.getVtSuite();
|
|
34
|
+
const utSuite = cfg_1.default.getUtSuite();
|
|
35
|
+
const crawlSuite = cfg_1.default.getCrawlSuite();
|
|
39
36
|
if (vtSuite) {
|
|
40
37
|
obj['Visual test suite'] = vtSuite;
|
|
41
38
|
}
|
|
@@ -3,13 +3,13 @@ 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
|
-
const
|
|
6
|
+
const input_1 = __importDefault(require("../../input"));
|
|
7
7
|
const output_1 = __importDefault(require("../../output"));
|
|
8
8
|
const texts_1 = require("../../texts");
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
10
|
const commandWorkspaceGet = (0, utils_1.newCommand)('get', texts_1.DESC_COMMAND_WORKSPACE_GET);
|
|
11
11
|
commandWorkspaceGet.action(async () => {
|
|
12
|
-
const workspace =
|
|
12
|
+
const { workspace } = input_1.default.accountScope();
|
|
13
13
|
if (!workspace) {
|
|
14
14
|
output_1.default.exitError(texts_1.TXT_WORKSPACE_NONE);
|
|
15
15
|
}
|
|
@@ -9,6 +9,7 @@ const texts_1 = require("../../texts");
|
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
10
|
const input_1 = __importDefault(require("../../input"));
|
|
11
11
|
const commandWorkspaceSet = (0, utils_1.newCommand)('set', texts_1.DESC_COMMAND_WORKSPACE_SET);
|
|
12
|
+
commandWorkspaceSet.usesDefaultContext = true;
|
|
12
13
|
commandWorkspaceSet.argument('[workspace]', texts_1.ARG_COMMAND_WORKSPACE);
|
|
13
14
|
commandWorkspaceSet.action(async (workspaceDomain) => {
|
|
14
15
|
output_1.default.handleSignals();
|
package/distTs/src/input.js
CHANGED
|
@@ -36,6 +36,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const cfg_1 = __importDefault(require("./project/cfg"));
|
|
40
|
+
const context_1 = require("./project/context");
|
|
39
41
|
const cliError_1 = __importDefault(require("./cliError"));
|
|
40
42
|
const output_1 = __importDefault(require("./output"));
|
|
41
43
|
const netmask_1 = require("netmask");
|
|
@@ -48,10 +50,159 @@ const utils_1 = require("./utils");
|
|
|
48
50
|
const texts_1 = require("./texts");
|
|
49
51
|
const tunnel_1 = require("./types/tunnel");
|
|
50
52
|
const node_path_1 = __importStar(require("node:path"));
|
|
51
|
-
const
|
|
53
|
+
const cfg_2 = __importDefault(require("./tunnel/cfg"));
|
|
52
54
|
const sandbox_1 = require("./types/sandbox");
|
|
53
55
|
const distro_1 = require("./types/distro");
|
|
54
56
|
class Input {
|
|
57
|
+
static contextOptions = {};
|
|
58
|
+
static resolvedContextScope;
|
|
59
|
+
static configureContext(options) {
|
|
60
|
+
this.contextOptions = options;
|
|
61
|
+
this.resolvedContextScope = undefined;
|
|
62
|
+
}
|
|
63
|
+
static contextName() {
|
|
64
|
+
return this.contextOptions.context || cfg_2.default.getActiveContext();
|
|
65
|
+
}
|
|
66
|
+
static context() {
|
|
67
|
+
return cfg_2.default.getContext(this.contextName());
|
|
68
|
+
}
|
|
69
|
+
static contextScope() {
|
|
70
|
+
const context = this.context();
|
|
71
|
+
if (!context)
|
|
72
|
+
return null;
|
|
73
|
+
this.resolvedContextScope ??= (0, context_1.resolveContextScope)(context, process.cwd());
|
|
74
|
+
return this.resolvedContextScope;
|
|
75
|
+
}
|
|
76
|
+
static contextEditableName(name) {
|
|
77
|
+
if (['default', 'git', 'link'].includes(name))
|
|
78
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_CONTEXT_RESERVED);
|
|
79
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(name))
|
|
80
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_CONTEXT_NAME);
|
|
81
|
+
return name;
|
|
82
|
+
}
|
|
83
|
+
static contextApiEndpoint(api) {
|
|
84
|
+
try {
|
|
85
|
+
const url = new URL(api.includes('://') ? api : `https://${api}`);
|
|
86
|
+
if (url.protocol !== 'https:' ||
|
|
87
|
+
url.username ||
|
|
88
|
+
url.password ||
|
|
89
|
+
url.pathname !== '/' ||
|
|
90
|
+
url.search ||
|
|
91
|
+
url.hash)
|
|
92
|
+
throw new Error();
|
|
93
|
+
return url.origin;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_CONTEXT_API);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
static contextDefinition(options) {
|
|
100
|
+
if ((options.fromLink && options.fromGit) ||
|
|
101
|
+
((options.fromLink || options.fromGit) &&
|
|
102
|
+
(options.workspace !== undefined || options.project !== undefined)) ||
|
|
103
|
+
(options.remote !== undefined && !options.fromGit))
|
|
104
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_CONTEXT_SOURCE);
|
|
105
|
+
if (options.project && !options.workspace)
|
|
106
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_CONTEXT_PROJECT);
|
|
107
|
+
const api = options.api !== undefined
|
|
108
|
+
? this.contextApiEndpoint(options.api)
|
|
109
|
+
: undefined;
|
|
110
|
+
return {
|
|
111
|
+
source: options.fromGit ? 'git' : options.fromLink ? 'link' : 'explicit',
|
|
112
|
+
...(options.workspace ? { workspace: options.workspace } : {}),
|
|
113
|
+
...(options.project ? { project: options.project } : {}),
|
|
114
|
+
...(options.token ? { token: options.token } : {}),
|
|
115
|
+
...(api ? { api } : {}),
|
|
116
|
+
...(options.fromGit ? { remote: options.remote || 'origin' } : {}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Account display preserves the legacy distinction between global and linked
|
|
120
|
+
// workspace, while named contexts own their entire scope.
|
|
121
|
+
static accountScope() {
|
|
122
|
+
if (this.context())
|
|
123
|
+
return {
|
|
124
|
+
workspace: this.restApiWorkspace(undefined, true),
|
|
125
|
+
project: this.restApiProject(undefined, true),
|
|
126
|
+
localWorkspace: '',
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
workspace: cfg_2.default.getWorkspace(),
|
|
130
|
+
project: cfg_1.default.getProject(),
|
|
131
|
+
localWorkspace: cfg_1.default.getWorkspace(),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
static showContext() {
|
|
135
|
+
const context = this.context();
|
|
136
|
+
const workspace = this.restApiWorkspace(this.contextOptions.workspace, true);
|
|
137
|
+
const project = this.restApiProject(this.contextOptions.project, true);
|
|
138
|
+
const auth = this.restApiToken(true, this.contextOptions.token);
|
|
139
|
+
const api = this.restApiBaseUrl(this.contextOptions.api, this.contextOptions.region, auth.token).origin;
|
|
140
|
+
const inSandbox = (0, utils_1.isInSandbox)();
|
|
141
|
+
const tokenSource = this.contextOptions.token
|
|
142
|
+
? 'flag'
|
|
143
|
+
: context?.token
|
|
144
|
+
? 'context'
|
|
145
|
+
: !inSandbox && process.env.BUDDY_TOKEN
|
|
146
|
+
? 'environment'
|
|
147
|
+
: cfg_2.default.getApiToken()
|
|
148
|
+
? 'config'
|
|
149
|
+
: process.env.BUDDY_TOKEN
|
|
150
|
+
? 'environment'
|
|
151
|
+
: null;
|
|
152
|
+
const workspaceSource = this.contextOptions.workspace
|
|
153
|
+
? 'flag'
|
|
154
|
+
: context
|
|
155
|
+
? workspace
|
|
156
|
+
? context.source
|
|
157
|
+
: null
|
|
158
|
+
: !inSandbox && process.env.BUDDY_WORKSPACE
|
|
159
|
+
? 'environment'
|
|
160
|
+
: cfg_1.default.getWorkspace()
|
|
161
|
+
? 'link'
|
|
162
|
+
: cfg_2.default.getWorkspace()
|
|
163
|
+
? 'config'
|
|
164
|
+
: process.env.BUDDY_WORKSPACE
|
|
165
|
+
? 'environment'
|
|
166
|
+
: null;
|
|
167
|
+
const projectSource = !project
|
|
168
|
+
? null
|
|
169
|
+
: this.contextOptions.project
|
|
170
|
+
? 'flag'
|
|
171
|
+
: context
|
|
172
|
+
? context.source
|
|
173
|
+
: process.env.BUDDY_PROJECT
|
|
174
|
+
? 'environment'
|
|
175
|
+
: 'link';
|
|
176
|
+
const apiSource = this.contextOptions.api
|
|
177
|
+
? 'flag'
|
|
178
|
+
: context?.api
|
|
179
|
+
? 'context'
|
|
180
|
+
: this.restApiBaseUrlFromToken(auth.token)
|
|
181
|
+
? 'token'
|
|
182
|
+
: process.env.BUDDY_API_ENDPOINT
|
|
183
|
+
? 'environment'
|
|
184
|
+
: cfg_2.default.getBaseUrl()
|
|
185
|
+
? 'config'
|
|
186
|
+
: this.contextOptions.region
|
|
187
|
+
? 'flag'
|
|
188
|
+
: process.env.BUDDY_REGION
|
|
189
|
+
? 'environment'
|
|
190
|
+
: 'default';
|
|
191
|
+
return {
|
|
192
|
+
name: this.contextName(),
|
|
193
|
+
source: context?.source || 'default',
|
|
194
|
+
workspace,
|
|
195
|
+
project,
|
|
196
|
+
api,
|
|
197
|
+
remote: context?.source === 'git' ? context.remote || 'origin' : null,
|
|
198
|
+
token: { available: !!auth.token, source: tokenSource },
|
|
199
|
+
sources: {
|
|
200
|
+
workspace: workspaceSource,
|
|
201
|
+
project: projectSource,
|
|
202
|
+
api: apiSource,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
55
206
|
static timeout(timeout) {
|
|
56
207
|
const t = parseInt(timeout, 10);
|
|
57
208
|
if (isNaN(t) || t <= 0 || t > 999) {
|
|
@@ -344,7 +495,7 @@ class Input {
|
|
|
344
495
|
// Inside a sandbox, cfg (written by an explicit `bdy login`) takes precedence
|
|
345
496
|
// over the sandbox-injected BUDDY_TOKEN env var. Outside a sandbox, env beats cfg
|
|
346
497
|
const tokenEnv = process.env.BUDDY_TOKEN;
|
|
347
|
-
let t = token;
|
|
498
|
+
let t = token || this.context()?.token || '';
|
|
348
499
|
if (!t && !inSandbox && tokenEnv)
|
|
349
500
|
t = tokenEnv;
|
|
350
501
|
let rf = '';
|
|
@@ -352,11 +503,11 @@ class Input {
|
|
|
352
503
|
let cs = '';
|
|
353
504
|
let ct = '';
|
|
354
505
|
if (!t) {
|
|
355
|
-
t =
|
|
356
|
-
rf =
|
|
357
|
-
cid =
|
|
358
|
-
cs =
|
|
359
|
-
ct =
|
|
506
|
+
t = cfg_2.default.getApiToken();
|
|
507
|
+
rf = cfg_2.default.getApiRefreshApiToken();
|
|
508
|
+
cid = cfg_2.default.getApiClientId();
|
|
509
|
+
cs = cfg_2.default.getApiClientSecret();
|
|
510
|
+
ct = cfg_2.default.getApiClientToken();
|
|
360
511
|
}
|
|
361
512
|
if (!t && inSandbox && tokenEnv)
|
|
362
513
|
t = tokenEnv;
|
|
@@ -869,13 +1020,13 @@ class Input {
|
|
|
869
1020
|
return null;
|
|
870
1021
|
}
|
|
871
1022
|
static restApiBaseUrl(api = '', region = '', token = '') {
|
|
872
|
-
let u = api;
|
|
1023
|
+
let u = api || this.context()?.api || '';
|
|
873
1024
|
if (!u)
|
|
874
1025
|
u = this.restApiBaseUrlFromToken(token);
|
|
875
1026
|
if (!u)
|
|
876
1027
|
u = process.env.BUDDY_API_ENDPOINT || null;
|
|
877
1028
|
if (!u)
|
|
878
|
-
u =
|
|
1029
|
+
u = cfg_2.default.getBaseUrl();
|
|
879
1030
|
if (!u) {
|
|
880
1031
|
const r = region || process.env.BUDDY_REGION;
|
|
881
1032
|
if (r?.toLowerCase() === utils_1.REST_API_REGION.EU) {
|
|
@@ -907,18 +1058,25 @@ class Input {
|
|
|
907
1058
|
return p;
|
|
908
1059
|
}
|
|
909
1060
|
static restApiWorkspace(workspace, allowNull, ignoreProjectConfig = false) {
|
|
1061
|
+
if (!ignoreProjectConfig && this.context()) {
|
|
1062
|
+
const value = workspace || this.contextScope()?.workspace;
|
|
1063
|
+
if (value)
|
|
1064
|
+
return value;
|
|
1065
|
+
if (allowNull)
|
|
1066
|
+
return null;
|
|
1067
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_REST_API_WORKSPACE, texts_1.TXT_CONTEXT_WORKSPACE_HINT);
|
|
1068
|
+
}
|
|
910
1069
|
// Inside a sandbox, cfg/project cfg (set by an explicit `bdy login` or .bdy/cfg.json)
|
|
911
1070
|
// takes precedence over the sandbox-injected BUDDY_WORKSPACE env var.
|
|
912
1071
|
// Outside a sandbox, env beats cfg.
|
|
913
|
-
const ProjectCfg = require('./project/cfg').default;
|
|
914
1072
|
let w = workspace;
|
|
915
1073
|
const inSandbox = (0, utils_1.isInSandbox)();
|
|
916
1074
|
if (!w && !inSandbox && process.env.BUDDY_WORKSPACE)
|
|
917
1075
|
w = process.env.BUDDY_WORKSPACE;
|
|
918
1076
|
if (!w && !ignoreProjectConfig)
|
|
919
|
-
w = ProjectCfg.getWorkspace();
|
|
920
|
-
if (!w)
|
|
921
1077
|
w = cfg_1.default.getWorkspace();
|
|
1078
|
+
if (!w)
|
|
1079
|
+
w = cfg_2.default.getWorkspace();
|
|
922
1080
|
if (!w && inSandbox && process.env.BUDDY_WORKSPACE)
|
|
923
1081
|
w = process.env.BUDDY_WORKSPACE;
|
|
924
1082
|
if (!w) {
|
|
@@ -1247,12 +1405,35 @@ class Input {
|
|
|
1247
1405
|
return sandboxId;
|
|
1248
1406
|
}
|
|
1249
1407
|
static restApiProject(project, allowNull) {
|
|
1250
|
-
const
|
|
1408
|
+
const context = this.context();
|
|
1409
|
+
if (context) {
|
|
1410
|
+
let value = project;
|
|
1411
|
+
if (!value) {
|
|
1412
|
+
let scope;
|
|
1413
|
+
try {
|
|
1414
|
+
scope = this.contextScope();
|
|
1415
|
+
}
|
|
1416
|
+
catch (err) {
|
|
1417
|
+
// An explicit workspace is sufficient for workspace-scoped commands.
|
|
1418
|
+
// If the dynamic source is unavailable, none of its project can carry over.
|
|
1419
|
+
if (!this.contextOptions.workspace || context.source === 'explicit')
|
|
1420
|
+
throw err;
|
|
1421
|
+
}
|
|
1422
|
+
const changedWorkspace = this.contextOptions.workspace && this.contextOptions.workspace !== scope?.workspace;
|
|
1423
|
+
if (!changedWorkspace)
|
|
1424
|
+
value = scope?.project || '';
|
|
1425
|
+
}
|
|
1426
|
+
if (value)
|
|
1427
|
+
return value;
|
|
1428
|
+
if (allowNull)
|
|
1429
|
+
return null;
|
|
1430
|
+
throw new cliError_1.default('usage_error', texts_1.ERR_REST_API_PROJECT, texts_1.TXT_CONTEXT_PROJECT_HINT);
|
|
1431
|
+
}
|
|
1251
1432
|
let p = process.env.BUDDY_PROJECT;
|
|
1252
1433
|
if (project)
|
|
1253
1434
|
p = project;
|
|
1254
1435
|
if (!p)
|
|
1255
|
-
p =
|
|
1436
|
+
p = cfg_1.default.getProject();
|
|
1256
1437
|
if (!p) {
|
|
1257
1438
|
if (allowNull)
|
|
1258
1439
|
return null;
|
|
@@ -1330,14 +1511,14 @@ class Input {
|
|
|
1330
1511
|
const workspace = Input.restApiWorkspace('', true);
|
|
1331
1512
|
const project = Input.restApiProject('', true);
|
|
1332
1513
|
let fromLogin = false;
|
|
1333
|
-
if (!token &&
|
|
1514
|
+
if (!token && (this.context() ? this.restApiToken(true).token : cfg_2.default.getApiToken()) && workspace) {
|
|
1334
1515
|
const client = Input.restApiTokenClient();
|
|
1335
1516
|
const result = await client.getTunnelToken(workspace, project);
|
|
1336
1517
|
token = String(result?.token || '');
|
|
1337
1518
|
fromLogin = true;
|
|
1338
1519
|
}
|
|
1339
1520
|
else if (!token) {
|
|
1340
|
-
token =
|
|
1521
|
+
token = cfg_2.default.getToken();
|
|
1341
1522
|
}
|
|
1342
1523
|
if (!token)
|
|
1343
1524
|
throw new Error(texts_1.ERR_TOKEN_NOT_PROVIDED);
|
|
@@ -1350,7 +1531,7 @@ class Input {
|
|
|
1350
1531
|
throw new Error(texts_1.ERR_WRONG_TOKEN);
|
|
1351
1532
|
}
|
|
1352
1533
|
if (!fromLogin)
|
|
1353
|
-
|
|
1534
|
+
cfg_2.default.setToken(token);
|
|
1354
1535
|
return {
|
|
1355
1536
|
token,
|
|
1356
1537
|
host: d.host,
|
|
@@ -1382,9 +1563,8 @@ class Input {
|
|
|
1382
1563
|
const envToken = process.env.BUDDY_VT_TOKEN;
|
|
1383
1564
|
if (envToken)
|
|
1384
1565
|
return envToken;
|
|
1385
|
-
const
|
|
1386
|
-
|
|
1387
|
-
if (suiteIdentifier && (cfg_1.default.getApiToken() || process.env.BUDDY_TOKEN)) {
|
|
1566
|
+
const suiteIdentifier = cfg_1.default.getVtSuite();
|
|
1567
|
+
if (suiteIdentifier && this.restApiToken(true).token) {
|
|
1388
1568
|
const workspace = Input.restApiWorkspace('', true);
|
|
1389
1569
|
const project = Input.restApiProject('', true);
|
|
1390
1570
|
if (workspace && project) {
|
|
@@ -1402,9 +1582,8 @@ class Input {
|
|
|
1402
1582
|
const envToken = process.env.BUDDY_CRAWL_TOKEN;
|
|
1403
1583
|
if (envToken)
|
|
1404
1584
|
return envToken;
|
|
1405
|
-
const
|
|
1406
|
-
|
|
1407
|
-
if (suiteIdentifier && (cfg_1.default.getApiToken() || process.env.BUDDY_TOKEN)) {
|
|
1585
|
+
const suiteIdentifier = cfg_1.default.getCrawlSuite();
|
|
1586
|
+
if (suiteIdentifier && this.restApiToken(true).token) {
|
|
1408
1587
|
const workspace = Input.restApiWorkspace('', true);
|
|
1409
1588
|
const project = Input.restApiProject('', true);
|
|
1410
1589
|
if (workspace && project) {
|
|
@@ -1422,9 +1601,8 @@ class Input {
|
|
|
1422
1601
|
const envToken = process.env.BUDDY_UT_TOKEN;
|
|
1423
1602
|
if (envToken)
|
|
1424
1603
|
return envToken;
|
|
1425
|
-
const
|
|
1426
|
-
|
|
1427
|
-
if (suiteIdentifier && (cfg_1.default.getApiToken() || process.env.BUDDY_TOKEN)) {
|
|
1604
|
+
const suiteIdentifier = cfg_1.default.getUtSuite();
|
|
1605
|
+
if (suiteIdentifier && this.restApiToken(true).token) {
|
|
1428
1606
|
const workspace = Input.restApiWorkspace('', true);
|
|
1429
1607
|
const project = Input.restApiProject('', true);
|
|
1430
1608
|
if (workspace && project) {
|
package/distTs/src/output.js
CHANGED
|
@@ -375,7 +375,7 @@ class Output {
|
|
|
375
375
|
}
|
|
376
376
|
});
|
|
377
377
|
}
|
|
378
|
-
static async confirm(message = 'Are you sure?') {
|
|
378
|
+
static async confirm(message = 'Are you sure?', quiet = false) {
|
|
379
379
|
if (this.isStdInTTY()) {
|
|
380
380
|
const prompts = require('@inquirer/prompts');
|
|
381
381
|
try {
|
|
@@ -383,15 +383,17 @@ class Output {
|
|
|
383
383
|
message,
|
|
384
384
|
theme: this.getInquirerTheme(),
|
|
385
385
|
default: false,
|
|
386
|
-
});
|
|
386
|
+
}, quiet ? { output: process.stderr } : undefined);
|
|
387
387
|
}
|
|
388
388
|
catch {
|
|
389
389
|
this.exitError(texts_1.ERR_CANCELLED);
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
392
|
+
if (!quiet) {
|
|
393
|
+
this.cyan('? ', false);
|
|
394
|
+
this.label(message, false);
|
|
395
|
+
this.cyan(` No`);
|
|
396
|
+
}
|
|
395
397
|
return false;
|
|
396
398
|
}
|
|
397
399
|
static async inputString(message, def, required, signal) {
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
exports.parseBuddyRemote = parseBuddyRemote;
|
|
7
|
+
exports.resolveContextScope = resolveContextScope;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const cliError_1 = __importDefault(require("../cliError"));
|
|
12
|
+
const utils_1 = require("../utils");
|
|
13
|
+
const texts_1 = require("../texts");
|
|
14
|
+
function parseBuddyRemote(remote) {
|
|
15
|
+
try {
|
|
16
|
+
// Accept both standard URLs and Git's scp-like SSH syntax.
|
|
17
|
+
const value = remote.includes('://')
|
|
18
|
+
? remote
|
|
19
|
+
: remote.replace(/^(?:[^@/:]+@)?([^/:]+):(.+)$/, 'ssh://$1/$2');
|
|
20
|
+
const url = new URL(value);
|
|
21
|
+
if (!['https:', 'ssh:'].includes(url.protocol) ||
|
|
22
|
+
!Object.values(utils_1.REST_API_ENDPOINT).some((endpoint) => (0, utils_1.getAppHostByApiBaseUrl)(new URL(`https://${endpoint}`)) ===
|
|
23
|
+
url.hostname) ||
|
|
24
|
+
url.search ||
|
|
25
|
+
url.hash)
|
|
26
|
+
throw new Error();
|
|
27
|
+
const parts = url.pathname
|
|
28
|
+
.replace(/\/$/, '')
|
|
29
|
+
.replace(/\.git$/, '')
|
|
30
|
+
.split('/')
|
|
31
|
+
.slice(1);
|
|
32
|
+
if (parts.length !== 2 ||
|
|
33
|
+
parts.some((part) => !/^[a-zA-Z0-9_-]+$/.test(part)))
|
|
34
|
+
throw new Error();
|
|
35
|
+
return { workspace: parts[0], project: parts[1] };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Do not include the raw URL: remotes can contain credentials.
|
|
39
|
+
throw new cliError_1.default('git_remote_unsupported', texts_1.ERR_CONTEXT_GIT_URL, texts_1.TXT_CONTEXT_GIT_HINT);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function resolveContextScope(context, cwd) {
|
|
43
|
+
if (context.source === 'explicit')
|
|
44
|
+
return {
|
|
45
|
+
workspace: context.workspace || null,
|
|
46
|
+
project: context.project || null,
|
|
47
|
+
remote: null,
|
|
48
|
+
};
|
|
49
|
+
if (context.source === 'link') {
|
|
50
|
+
let data;
|
|
51
|
+
try {
|
|
52
|
+
data = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(cwd, '.bdy/project.json'), 'utf8'));
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
const missing = err.code === 'ENOENT';
|
|
56
|
+
throw new cliError_1.default(missing ? 'project_link_not_found' : 'project_link_invalid', missing ? texts_1.ERR_CONTEXT_LINK_MISSING : texts_1.ERR_CONTEXT_LINK_INVALID, texts_1.TXT_CONTEXT_LINK_HINT);
|
|
57
|
+
}
|
|
58
|
+
if (typeof data?.workspace !== 'string' ||
|
|
59
|
+
!data.workspace.trim() ||
|
|
60
|
+
typeof data?.project !== 'string' ||
|
|
61
|
+
!data.project.trim())
|
|
62
|
+
throw new cliError_1.default('project_link_invalid', texts_1.ERR_CONTEXT_LINK_INVALID, texts_1.TXT_CONTEXT_LINK_HINT);
|
|
63
|
+
return {
|
|
64
|
+
workspace: data.workspace,
|
|
65
|
+
project: data.project,
|
|
66
|
+
remote: null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const remote = context.remote || 'origin';
|
|
70
|
+
let url;
|
|
71
|
+
try {
|
|
72
|
+
url = (0, node_child_process_1.execFileSync)('git', ['remote', 'get-url', '--', remote], {
|
|
73
|
+
cwd,
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
timeout: 3000,
|
|
76
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
77
|
+
// Git diagnostics are classified below; keep their language deterministic.
|
|
78
|
+
env: { ...process.env, LC_ALL: 'C', LANG: 'C' },
|
|
79
|
+
}).trim();
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const failure = err;
|
|
83
|
+
if (failure.code === 'ENOENT')
|
|
84
|
+
throw new cliError_1.default('git_not_found', texts_1.ERR_CONTEXT_GIT_MISSING, texts_1.TXT_CONTEXT_GIT_HINT);
|
|
85
|
+
if (failure.code === 'ETIMEDOUT')
|
|
86
|
+
throw new cliError_1.default('timeout', texts_1.ERR_CONTEXT_GIT_TIMEOUT, texts_1.TXT_CONTEXT_GIT_HINT);
|
|
87
|
+
const stderr = String(failure.stderr || '');
|
|
88
|
+
if (failure.status === 128 && /fatal: not a git repository/i.test(stderr))
|
|
89
|
+
throw new cliError_1.default('git_repository_not_found', texts_1.ERR_CONTEXT_GIT_REPO, texts_1.TXT_CONTEXT_GIT_HINT);
|
|
90
|
+
if (failure.status === 2 && /error: No such remote /i.test(stderr))
|
|
91
|
+
throw new cliError_1.default('git_remote_not_found', (0, texts_1.ERR_CONTEXT_GIT_REMOTE)(remote), texts_1.TXT_CONTEXT_GIT_HINT);
|
|
92
|
+
// Neither permission errors nor an interrupted Git process imply a missing repo.
|
|
93
|
+
// Never forward raw diagnostics, which may contain remote credentials.
|
|
94
|
+
throw new cliError_1.default('command_failed', texts_1.ERR_CONTEXT_GIT_FAILED, texts_1.TXT_CONTEXT_GIT_HINT);
|
|
95
|
+
}
|
|
96
|
+
return { ...parseBuddyRemote(url), remote };
|
|
97
|
+
}
|
package/distTs/src/texts.js
CHANGED
|
@@ -22,7 +22,8 @@ exports.DESC_COMMAND_ARTIFACT_GET = exports.TXT_ARTIFACT_DOCKER_LOGIN_FAILED = e
|
|
|
22
22
|
exports.EXAMPLE_ROUTE_LIST = exports.EXAMPLE_ROUTE_UPDATE = exports.EXAMPLE_ROUTE_DELETE = exports.EXAMPLE_DISTRO_DELETE = exports.EXAMPLE_ROUTE_GET = exports.EXAMPLE_DISTRO_UPDATE = exports.EXAMPLE_DISTRO_GET = exports.EXAMPLE_DISTRO_LIST = exports.EXAMPLE_SANDBOX_CP = exports.ERR_PROJECT_NO_PROJECTS = exports.TXT_LOGIN_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_CREATED = exports.TXT_COMMAND_PROJECT_LINK_NOT_FOUND = exports.TXT_COMMAND_PROJECT_LINK_NAME = exports.TXT_COMMAND_PROJECT_LINK_SELECT_PROJECT = exports.TXT_COMMAND_PROJECT_LINK_TO = exports.TXT_COMMAND_PROJECT_LINK_EXISTING_DESC = exports.TXT_COMMAND_PROJECT_LINK_EXISTING = exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW_DESC = exports.TXT_COMMAND_PROJECT_LINK_CREATE_NEW = exports.ERR_COMMAND_PROJECT_LINK_DIR_NOT_DIR = exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO_INITIALIZED = exports.TXT_COMMAND_PROJECT_LINK_GIT_REPO = exports.TXT_COMMAND_PROJECT_LINK_DIR_CONFIRM = exports.TXT_COMMAND_PROJECT_LINK_DIR_LINKED = exports.ERR_COMMAND_PROJECT_LINK_DIR_CREATE = exports.OPT_COMMAND_PROJECT_LINK_TRY_NOW = exports.OPT_COMMAND_PROJECT_LINK_SET_GIT_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_HAS_REMOTE = exports.OPT_COMMAND_PROJECT_LINK_DIRECTORY = exports.OPT_COMMAND_PROJECT_LINK_GIT = exports.OPT_COMMAND_PROJECT_LINK_RELINK = exports.DESC_COMMAND_PROJECT_LINK = exports.DESC_COMMAND_PROJECT_LIST = exports.DESC_COMMAND_PROJECT_GIT = exports.DESC_COMMAND_PROJECT_GIT_CREDENTIAL = exports.DESC_COMMAND_PROJECT = exports.TXT_ARTIFACT_VERSION_DOWNLOAD = exports.TXT_ARTIFACT_PUBLISH = exports.TXT_ARTIFACT_CREATED = exports.TXT_ARTIFACT_VERSION_DELETED = exports.TXT_ARTIFACT_DELETED = exports.ERR_COMMAND_ARTIFACT_TYPE = exports.OPT_COMMAND_ARTIFACT_VERSION = exports.OPT_COMMAND_ARTIFACT_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_CREATE_IDENTIFIER = exports.OPT_COMMAND_ARTIFACT_NAME = exports.OPT_COMMAND_ARTIFACT_TYPE = exports.DESC_COMMAND_ARTIFACT_CREATE = exports.DESC_COMMAND_ARTIFACT_COMPOSER_PUBLISH = void 0;
|
|
23
23
|
exports.HELP_PIPELINE_RUN_JSONL = exports.EXAMPLE_PIPELINE_RUN_STATUS = exports.EXAMPLE_PIPELINE_RUN_START = exports.EXAMPLE_SANDBOX_ENDPOINT_LIST = exports.EXAMPLE_SANDBOX_ENDPOINT_GET = exports.EXAMPLE_SANDBOX_ENDPOINT_DELETE = exports.EXAMPLE_SANDBOX_ENDPOINT_CREATE = exports.EXAMPLE_ENVIRONMENT_DELETE = exports.EXAMPLE_ENVIRONMENT_UPDATE = exports.EXAMPLE_ENVIRONMENT_CREATE = exports.EXAMPLE_ENVIRONMENT_GET = exports.EXAMPLE_ENVIRONMENT_LIST = exports.EXAMPLE_TARGET_EXEC_LOGS = exports.EXAMPLE_TARGET_EXEC_LIST = exports.EXAMPLE_TARGET_EXEC_KILL = exports.EXAMPLE_TARGET_EXEC_STATUS = exports.EXAMPLE_TARGET_EXEC_COMMAND = exports.EXAMPLE_TARGET_DELETE = exports.EXAMPLE_TARGET_UPDATE = exports.EXAMPLE_TARGET_CREATE = exports.EXAMPLE_TARGET_GET = exports.EXAMPLE_TARGET_LIST = exports.EXAMPLE_SANDBOX_SNAPSHOT_LIST = exports.EXAMPLE_SANDBOX_SNAPSHOT_GET = exports.EXAMPLE_SANDBOX_SNAPSHOT_DELETE = exports.EXAMPLE_SANDBOX_SNAPSHOT_CREATE = exports.EXAMPLE_SANDBOX_EXEC_STATUS = exports.EXAMPLE_SANDBOX_EXEC_LOGS = exports.EXAMPLE_SANDBOX_APP_STATUS = exports.EXAMPLE_SANDBOX_APP_STOP = exports.EXAMPLE_SANDBOX_APP_REMOVE = exports.EXAMPLE_SANDBOX_APP_ADD = exports.EXAMPLE_SANDBOX_APP_START = exports.EXAMPLE_SANDBOX_APP_LOGS = exports.EXAMPLE_SANDBOX_EXEC_LIST = exports.EXAMPLE_SANDBOX_APP_LIST = exports.EXAMPLE_SANDBOX_EXEC_KILL = exports.EXAMPLE_SANDBOX_SSH = exports.EXAMPLE_SANDBOX_EXEC_COMMAND = exports.EXAMPLE_TUNNEL_START = exports.EXAMPLE_TUNNEL_TCP = exports.EXAMPLE_TUNNEL_TLS = exports.EXAMPLE_AGENT_TUNNEL_START = exports.EXAMPLE_AGENT_TUNNEL_STATUS = exports.EXAMPLE_AGENT_TUNNEL_REMOVE = exports.EXAMPLE_AGENT_TUNNEL_LIST = exports.EXAMPLE_TUNNEL_HTTP = exports.EXAMPLE_SANDBOX_CREATE = exports.EXAMPLE_DISTRO_CREATE = exports.EXAMPLE_ROUTE_CREATE = void 0;
|
|
24
24
|
exports.OPTION_YAML_VALIDATE_FILE = exports.DESC_COMMAND_YAML_VALIDATE = exports.DESC_COMMAND_YAML_ACTIONS_INFO = exports.DESC_COMMAND_YAML_ACTIONS_LIST = exports.DESC_COMMAND_YAML_ACTIONS = exports.DESC_COMMAND_YAML_PIPELINE = exports.DESC_COMMAND_YAML = exports.TXT_ACTION_SUGGESTED_FROM_REPO = exports.TXT_ACTION_USE_LIST = exports.TXT_ACTION_DID_YOU_MEAN = exports.ERR_ACTION_SEARCH_NO_RESULTS = exports.ERR_ACTION_NOT_FOUND = exports.OPTION_ACTION_TYPE = exports.OPTION_ACTION_SEARCH = exports.EXAMPLE_YAML_VALIDATE = exports.EXAMPLE_YAML_ACTIONS_INFO = exports.EXAMPLE_YAML_ACTIONS_LIST = exports.EXAMPLE_YAML_PIPELINE = exports.EXAMPLE_CRAWL_LINK = exports.EXAMPLE_CRAWL_RUN = exports.EXAMPLE_TESTS_CAPTURE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CLOSE = exports.EXAMPLE_TESTS_VISUAL_SESSION_CREATE = exports.EXAMPLE_TESTS_VISUAL_LINK = exports.EXAMPLE_TESTS_VISUAL_UPLOAD = exports.EXAMPLE_TESTS_VISUAL_SETUP = exports.EXAMPLE_TESTS_UNIT_LINK = exports.EXAMPLE_TESTS_UNIT_UPLOAD = exports.EXAMPLE_ARTIFACT_VERSION_DELETE = exports.EXAMPLE_ARTIFACT_VERSION_GET = exports.EXAMPLE_ARTIFACT_VERSION_LIST = exports.EXAMPLE_ARTIFACT_CREATE = exports.EXAMPLE_ARTIFACT_DELETE = exports.EXAMPLE_ARTIFACT_DOWNLOAD = exports.EXAMPLE_ARTIFACT_PUBLISH = exports.EXAMPLE_ARTIFACT_COMPOSER_PUBLISH = exports.EXAMPLE_ARTIFACT_VERSION_CREATE = exports.EXAMPLE_PIPELINE_RUN_RETRY = exports.EXAMPLE_PIPELINE_RUN_LIST = exports.EXAMPLE_PIPELINE_LIST = exports.EXAMPLE_PIPELINE_YML = exports.EXAMPLE_PIPELINE_GET = exports.EXAMPLE_PIPELINE_UPDATE = exports.EXAMPLE_PIPELINE_DELETE = exports.EXAMPLE_PIPELINE_CREATE = exports.EXAMPLE_PIPELINE_RUN_CANCEL = exports.EXAMPLE_PIPELINE_RUN_APPLY = exports.EXAMPLE_PIPELINE_RUN_LOGS = exports.HELP_PIPELINE_RUN_LOGS = exports.HELP_PIPELINE_RUN_STATUS = void 0;
|
|
25
|
-
exports.HELP_AGENT_STATUS_JSON = exports.HELP_SANDBOX_APP_ADD_JSON = exports.EXAMPLE_CONFIG_GET_TUNNELS = exports.EXAMPLE_CONFIG_GET_TUNNEL = exports.HELP_TARGET_EXEC_LOGS_JSONL = exports.HELP_SANDBOX_EXEC_COMMAND_JSONL = exports.HELP_SANDBOX_EXEC_JSONL = exports.HELP_TARGET_EXEC_COMMAND = exports.HELP_TARGET_EXEC_STATUS = exports.HELP_SANDBOX_EXEC_STATUS = exports.HELP_API_INFO_JSON = exports.HELP_DOMAIN_SEARCH_JSON = exports.HELP_YAML_VALIDATE_JSON = exports.EXAMPLE_AGENT_TAGS_GET = exports.EXAMPLE_AGENT_PROXY_STATUS = exports.EXAMPLE_AGENT_TARGET_STATUS = exports.EXAMPLE_AGENT_VERSION = exports.EXAMPLE_AGENT_STATUS = exports.EXAMPLE_DOMAIN_SEARCH = exports.EXAMPLE_API_LIST = exports.EXAMPLE_API_INFO = exports.ERR_API_SCHEMA_NOT_FOUND = exports.EXAMPLE_SANDBOX_LOGS = exports.ERR_YAML_SCHEMA_READ_FAILED = exports.ERR_YAML_SCHEMA_FETCH_FAILED = exports.TXT_YAML_UNKNOWN_TOP_LEVEL_KEYS = exports.ERR_YAML_ITEM_UNKNOWN = exports.ERR_YAML_ITEM_MISSING = exports.ERR_YAML_MUST_BE = exports.ERR_YAML_PIPELINE_NOT_OBJECT = exports.ERR_YAML_EMPTY_ARRAY = exports.ERR_YAML_PLAIN_OBJECT = exports.ERR_YAML_NOT_ARRAY = exports.ERR_YAML_PARSE = exports.ERR_YAML_VALIDATE_FAILED_COUNT = exports.TXT_YAML_VALIDATE_ALL_PASS = exports.ERR_YAML_VALIDATE_FAILED = exports.ERR_YAML_VALIDATE_FILE_NOT_FOUND = void 0;
|
|
25
|
+
exports.OPTION_CONTEXT_TOKEN = exports.OPTION_CONTEXT_REMOTE = exports.OPTION_CONTEXT_GIT = exports.OPTION_CONTEXT_LINK = exports.OPTION_CONTEXT_NAME = exports.DESC_CONTEXT_REMOVE = exports.DESC_CONTEXT_USE = exports.DESC_CONTEXT_SHOW = exports.DESC_CONTEXT_LIST = exports.DESC_CONTEXT_ADD = exports.DESC_CONTEXT = exports.OPTION_CONTEXT = exports.HELP_AGENT_STATUS_JSON = exports.HELP_SANDBOX_APP_ADD_JSON = exports.EXAMPLE_CONFIG_GET_TUNNELS = exports.EXAMPLE_CONFIG_GET_TUNNEL = exports.HELP_TARGET_EXEC_LOGS_JSONL = exports.HELP_SANDBOX_EXEC_COMMAND_JSONL = exports.HELP_SANDBOX_EXEC_JSONL = exports.HELP_TARGET_EXEC_COMMAND = exports.HELP_TARGET_EXEC_STATUS = exports.HELP_SANDBOX_EXEC_STATUS = exports.HELP_API_INFO_JSON = exports.HELP_DOMAIN_SEARCH_JSON = exports.HELP_YAML_VALIDATE_JSON = exports.EXAMPLE_AGENT_TAGS_GET = exports.EXAMPLE_AGENT_PROXY_STATUS = exports.EXAMPLE_AGENT_TARGET_STATUS = exports.EXAMPLE_AGENT_VERSION = exports.EXAMPLE_AGENT_STATUS = exports.EXAMPLE_DOMAIN_SEARCH = exports.EXAMPLE_API_LIST = exports.EXAMPLE_API_INFO = exports.ERR_API_SCHEMA_NOT_FOUND = exports.EXAMPLE_SANDBOX_LOGS = exports.ERR_YAML_SCHEMA_READ_FAILED = exports.ERR_YAML_SCHEMA_FETCH_FAILED = exports.TXT_YAML_UNKNOWN_TOP_LEVEL_KEYS = exports.ERR_YAML_ITEM_UNKNOWN = exports.ERR_YAML_ITEM_MISSING = exports.ERR_YAML_MUST_BE = exports.ERR_YAML_PIPELINE_NOT_OBJECT = exports.ERR_YAML_EMPTY_ARRAY = exports.ERR_YAML_PLAIN_OBJECT = exports.ERR_YAML_NOT_ARRAY = exports.ERR_YAML_PARSE = exports.ERR_YAML_VALIDATE_FAILED_COUNT = exports.TXT_YAML_VALIDATE_ALL_PASS = exports.ERR_YAML_VALIDATE_FAILED = exports.ERR_YAML_VALIDATE_FILE_NOT_FOUND = void 0;
|
|
26
|
+
exports.HELP_CONTEXT_REMOVE = exports.HELP_CONTEXT_USE = exports.HELP_CONTEXT_SHOW = exports.HELP_CONTEXT_LIST = exports.HELP_CONTEXT_ADD = exports.EXAMPLE_CONTEXT_REMOVE = exports.EXAMPLE_CONTEXT_USE = exports.EXAMPLE_CONTEXT_SHOW = exports.EXAMPLE_CONTEXT_LIST = exports.EXAMPLE_CONTEXT_ADD = exports.TXT_CONTEXT_TOKEN_MISSING = exports.TXT_CONTEXT_TOKEN_AVAILABLE = exports.TXT_CONTEXT_TOKEN_LABEL = exports.TXT_CONTEXT_REMOTE_LABEL = exports.TXT_CONTEXT_API_LABEL = exports.TXT_CONTEXT_PROJECT_LABEL = exports.TXT_CONTEXT_WORKSPACE_LABEL = exports.TXT_CONTEXT_SOURCE_LABEL = exports.TXT_CONTEXT_LABEL = exports.TXT_CONTEXT_REMOVE_CONFIRM = exports.ERR_CONTEXT_GIT_FAILED = exports.ERR_CONTEXT_GIT_TIMEOUT = exports.TXT_CONTEXT_PROJECT_HINT = exports.TXT_CONTEXT_WORKSPACE_HINT = exports.HELP_CONTEXT = exports.TXT_CONTEXT_REMOVED = exports.TXT_CONTEXT_ACTIVE = exports.TXT_CONTEXT_SAVED = exports.ERR_CONTEXT_LINK_INVALID = exports.ERR_CONTEXT_LINK_MISSING = exports.ERR_CONTEXT_GIT_URL = exports.ERR_CONTEXT_GIT_REMOTE = exports.ERR_CONTEXT_GIT_REPO = exports.ERR_CONTEXT_GIT_MISSING = exports.ERR_CONTEXT_API = exports.ERR_CONTEXT_PROJECT = exports.ERR_CONTEXT_SOURCE = exports.ERR_CONTEXT_NAME = exports.ERR_CONTEXT_EXISTS = exports.ERR_CONTEXT_RESERVED = exports.ERR_CONTEXT_UNKNOWN = exports.TXT_CONTEXT_LINK_HINT = exports.TXT_CONTEXT_GIT_HINT = exports.TXT_CONTEXT_HINT = exports.OPTION_CONTEXT_API = void 0;
|
|
26
27
|
const utils_1 = require("./utils");
|
|
27
28
|
exports.ERR_CANCELLED = 'Cancelled';
|
|
28
29
|
const TXT_CLI_USAGE_HINT = (command) => `Run '${command} --help' for usage.`;
|
|
@@ -59,8 +60,8 @@ const WARN_REST_API_RATE_LIMIT_LOW = (remaining, rateLimitReset) => {
|
|
|
59
60
|
};
|
|
60
61
|
exports.WARN_REST_API_RATE_LIMIT_LOW = WARN_REST_API_RATE_LIMIT_LOW;
|
|
61
62
|
// Shown on stderr when a list command narrows to PROJECT scope implicitly
|
|
62
|
-
// (linked project / BUDDY_PROJECT), so the narrowing is never silent.
|
|
63
|
-
const TXT_LIST_PROJECT_SCOPE_NOTE = (resource, project) => `Listing ${resource} of project "${project}" (inferred from the linked project or BUDDY_PROJECT). Use --scope WORKSPACE to list workspace ${resource}.`;
|
|
63
|
+
// (context / linked project / BUDDY_PROJECT), so the narrowing is never silent.
|
|
64
|
+
const TXT_LIST_PROJECT_SCOPE_NOTE = (resource, project) => `Listing ${resource} of project "${project}" (inferred from the context, linked project or BUDDY_PROJECT). Use --scope WORKSPACE to list workspace ${resource}.`;
|
|
64
65
|
exports.TXT_LIST_PROJECT_SCOPE_NOTE = TXT_LIST_PROJECT_SCOPE_NOTE;
|
|
65
66
|
exports.ERR_REST_API_URL = 'Valid rest api endpoint is required (--api)';
|
|
66
67
|
exports.ERR_REST_API_REGION = 'Valid rest api region is required (eu, us, as, onprem)';
|
|
@@ -514,6 +515,7 @@ exports.EXAMPLE_DISCOVER = [
|
|
|
514
515
|
},
|
|
515
516
|
];
|
|
516
517
|
exports.DISCOVERY_TIPS = [
|
|
518
|
+
"Use --context git in a Buddy clone, --context link after 'bdy project link', or --context default for legacy configuration. Inspect resolved values with 'bdy context show git --format json'. Prefer --context per invocation in scripts; 'context use' changes the global selection.",
|
|
517
519
|
"Authenticate with 'bdy login'. Discovery itself needs no login or network access.",
|
|
518
520
|
"Set project context with 'bdy project link', or use --workspace / --project and BUDDY_WORKSPACE / BUDDY_PROJECT where supported.",
|
|
519
521
|
'Human-readable identifiers and numeric IDs are not interchangeable. Check the argument description.',
|
|
@@ -2908,3 +2910,126 @@ JSON OUTPUT:
|
|
|
2908
2910
|
An installed but stopped agent returns running=false and exits successfully.
|
|
2909
2911
|
Version is null when unavailable. A missing or unreadable installation is an error.
|
|
2910
2912
|
`;
|
|
2913
|
+
exports.OPTION_CONTEXT = 'Connection and scope context: default, git, link or a saved name. Overrides the globally active context for this invocation.';
|
|
2914
|
+
exports.DESC_CONTEXT = 'Manage connection and workspace/project contexts';
|
|
2915
|
+
exports.DESC_CONTEXT_ADD = 'Save a named context without activating it';
|
|
2916
|
+
exports.DESC_CONTEXT_LIST = 'List built-in and saved contexts without resolving their sources';
|
|
2917
|
+
exports.DESC_CONTEXT_SHOW = 'Show resolved context and value sources without changing the active context';
|
|
2918
|
+
exports.DESC_CONTEXT_USE = 'Select the globally active context';
|
|
2919
|
+
exports.DESC_CONTEXT_REMOVE = 'Remove a saved context; removing the active context selects default';
|
|
2920
|
+
exports.OPTION_CONTEXT_NAME = 'Context name';
|
|
2921
|
+
exports.OPTION_CONTEXT_LINK = 'Resolve workspace and project from .bdy/project.json in the current directory';
|
|
2922
|
+
exports.OPTION_CONTEXT_GIT = 'Resolve workspace and project from a Buddy Git remote in the current repository';
|
|
2923
|
+
exports.OPTION_CONTEXT_REMOTE = 'Git remote to read with --from-git. Default: origin';
|
|
2924
|
+
exports.OPTION_CONTEXT_TOKEN = 'REST API token for this context; omitted means inherit the default authentication mechanism';
|
|
2925
|
+
exports.OPTION_CONTEXT_API = 'HTTPS API endpoint for this context; omitted means inherit the default endpoint mechanism';
|
|
2926
|
+
exports.TXT_CONTEXT_HINT = "Run 'bdy context list' to see available contexts, or use --context default.";
|
|
2927
|
+
exports.TXT_CONTEXT_GIT_HINT = "Run in a Buddy clone with an origin remote, or create a context with 'bdy context add <name> --from-git --remote <remote>'.";
|
|
2928
|
+
exports.TXT_CONTEXT_LINK_HINT = "Run 'bdy project link' in this directory, or use --context default.";
|
|
2929
|
+
const ERR_CONTEXT_UNKNOWN = (name) => `Context not found: ${name}`;
|
|
2930
|
+
exports.ERR_CONTEXT_UNKNOWN = ERR_CONTEXT_UNKNOWN;
|
|
2931
|
+
exports.ERR_CONTEXT_RESERVED = 'The built-in contexts default, git and link cannot be changed or removed.';
|
|
2932
|
+
const ERR_CONTEXT_EXISTS = (name) => `Context already exists: ${name}. Remove it before creating a replacement.`;
|
|
2933
|
+
exports.ERR_CONTEXT_EXISTS = ERR_CONTEXT_EXISTS;
|
|
2934
|
+
exports.ERR_CONTEXT_NAME = 'Use a context name containing letters, numbers, underscores or hyphens, starting with a letter or number.';
|
|
2935
|
+
exports.ERR_CONTEXT_SOURCE = 'Choose exactly one scope source: workspace/project values, --from-link or --from-git. --remote requires --from-git.';
|
|
2936
|
+
exports.ERR_CONTEXT_PROJECT = 'A context with a project must also specify a workspace.';
|
|
2937
|
+
exports.ERR_CONTEXT_API = 'Provide an HTTPS API endpoint without credentials, a path, query or fragment.';
|
|
2938
|
+
exports.ERR_CONTEXT_GIT_MISSING = 'Git is not installed or cannot be executed.';
|
|
2939
|
+
exports.ERR_CONTEXT_GIT_REPO = 'The current directory is not an accessible Git repository.';
|
|
2940
|
+
const ERR_CONTEXT_GIT_REMOTE = (remote) => `Git remote not found or unreadable: ${remote}`;
|
|
2941
|
+
exports.ERR_CONTEXT_GIT_REMOTE = ERR_CONTEXT_GIT_REMOTE;
|
|
2942
|
+
exports.ERR_CONTEXT_GIT_URL = 'The selected remote is not a supported Buddy repository URL.';
|
|
2943
|
+
exports.ERR_CONTEXT_LINK_MISSING = 'No project link exists in the current directory.';
|
|
2944
|
+
exports.ERR_CONTEXT_LINK_INVALID = 'The project link is unreadable or does not contain a workspace and project.';
|
|
2945
|
+
const TXT_CONTEXT_SAVED = (name) => `Context saved: ${name}`;
|
|
2946
|
+
exports.TXT_CONTEXT_SAVED = TXT_CONTEXT_SAVED;
|
|
2947
|
+
const TXT_CONTEXT_ACTIVE = (name) => `Active context: ${name}`;
|
|
2948
|
+
exports.TXT_CONTEXT_ACTIVE = TXT_CONTEXT_ACTIVE;
|
|
2949
|
+
const TXT_CONTEXT_REMOVED = (name) => `Context removed: ${name}`;
|
|
2950
|
+
exports.TXT_CONTEXT_REMOVED = TXT_CONTEXT_REMOVED;
|
|
2951
|
+
exports.HELP_CONTEXT = `
|
|
2952
|
+
Built-in contexts:
|
|
2953
|
+
default: existing flags, environment and configuration rules, including sandbox precedence.
|
|
2954
|
+
git: workspace/project from remote origin of the current Buddy repository (HTTPS or SSH).
|
|
2955
|
+
link: workspace/project from .bdy/project.json in the current directory; no ancestor search.
|
|
2956
|
+
|
|
2957
|
+
Named contexts inherit authentication and endpoint resolution when omitted.
|
|
2958
|
+
Workspace and project never inherit from default, environment or project links.
|
|
2959
|
+
--from-link and --from-git save a dynamic source, not its current values.
|
|
2960
|
+
An unavailable source is an error; sources never fall back to each other.
|
|
2961
|
+
Explicit command flags override context values. Changing workspace drops the
|
|
2962
|
+
context project unless --project is also given. --scope workspace keeps workspace scope.
|
|
2963
|
+
Contexts do not select pipeline branches or revisions.
|
|
2964
|
+
|
|
2965
|
+
--context <name> overrides the active context for one invocation.
|
|
2966
|
+
Without it, the saved active context is used; initially this is default.
|
|
2967
|
+
Use per-invocation selection in concurrent scripts and agents.
|
|
2968
|
+
show resolves locally without authenticating or making API calls. Token output
|
|
2969
|
+
contains only availability and source, never its value; availability does not
|
|
2970
|
+
prove authentication. list does not resolve Git or project links.
|
|
2971
|
+
Built-in names are reserved. Removing an active custom context selects default.
|
|
2972
|
+
login/logout, register, workspace set and project link use the default configuration.
|
|
2973
|
+
`;
|
|
2974
|
+
exports.TXT_CONTEXT_WORKSPACE_HINT = 'Pass --workspace <domain> or select a context containing a workspace.';
|
|
2975
|
+
exports.TXT_CONTEXT_PROJECT_HINT = 'Pass --project <name> or select a context containing a project.';
|
|
2976
|
+
exports.ERR_CONTEXT_GIT_TIMEOUT = 'Git timed out while reading the repository remote.';
|
|
2977
|
+
exports.ERR_CONTEXT_GIT_FAILED = 'Git could not read the repository remote.';
|
|
2978
|
+
const TXT_CONTEXT_REMOVE_CONFIRM = (name) => `Remove context "${name}" and its saved token? If active, default will be selected.`;
|
|
2979
|
+
exports.TXT_CONTEXT_REMOVE_CONFIRM = TXT_CONTEXT_REMOVE_CONFIRM;
|
|
2980
|
+
exports.TXT_CONTEXT_LABEL = 'Context';
|
|
2981
|
+
exports.TXT_CONTEXT_SOURCE_LABEL = 'Source';
|
|
2982
|
+
exports.TXT_CONTEXT_WORKSPACE_LABEL = 'Workspace';
|
|
2983
|
+
exports.TXT_CONTEXT_PROJECT_LABEL = 'Project';
|
|
2984
|
+
exports.TXT_CONTEXT_API_LABEL = 'API';
|
|
2985
|
+
exports.TXT_CONTEXT_REMOTE_LABEL = 'Remote';
|
|
2986
|
+
exports.TXT_CONTEXT_TOKEN_LABEL = 'Token';
|
|
2987
|
+
exports.TXT_CONTEXT_TOKEN_AVAILABLE = 'available';
|
|
2988
|
+
exports.TXT_CONTEXT_TOKEN_MISSING = 'missing';
|
|
2989
|
+
exports.EXAMPLE_CONTEXT_ADD = [
|
|
2990
|
+
{ description: 'Save a fixed workspace and project', command: 'bdy context add backend --workspace acme --project backend' },
|
|
2991
|
+
{ description: 'Resolve the buddy remote on each invocation', command: 'bdy context add company --from-git --remote buddy' },
|
|
2992
|
+
];
|
|
2993
|
+
exports.EXAMPLE_CONTEXT_LIST = [
|
|
2994
|
+
{ description: 'List contexts and the active selection as JSON', command: 'bdy context list --format json' },
|
|
2995
|
+
];
|
|
2996
|
+
exports.EXAMPLE_CONTEXT_SHOW = [
|
|
2997
|
+
{ description: 'Inspect the current repository scope without switching contexts', command: 'bdy context show git --format json' },
|
|
2998
|
+
];
|
|
2999
|
+
exports.EXAMPLE_CONTEXT_USE = [
|
|
3000
|
+
{ description: 'Restore the default configuration for subsequent invocations', command: 'bdy context use default' },
|
|
3001
|
+
];
|
|
3002
|
+
exports.EXAMPLE_CONTEXT_REMOVE = [
|
|
3003
|
+
{ description: 'Remove a saved context without prompting', command: 'bdy context remove backend --force' },
|
|
3004
|
+
];
|
|
3005
|
+
exports.HELP_CONTEXT_ADD = `
|
|
3006
|
+
Save exactly one scope source: explicit --workspace/--project, --from-link or --from-git.
|
|
3007
|
+
--remote requires --from-git and defaults to origin. Dynamic sources are resolved
|
|
3008
|
+
on each invocation, not when saved. Omitted token and endpoint inherit default
|
|
3009
|
+
resolution; workspace and project do not inherit. Adding does not activate the context.
|
|
3010
|
+
Built-in names are reserved; an existing name cannot be overwritten.
|
|
3011
|
+
`;
|
|
3012
|
+
exports.HELP_CONTEXT_LIST = `
|
|
3013
|
+
Lists built-in and saved contexts without reading Git or project links.
|
|
3014
|
+
Text shows names, with * marking the globally active context. JSON includes
|
|
3015
|
+
name, active, builtin and source. No credentials are printed.
|
|
3016
|
+
`;
|
|
3017
|
+
exports.HELP_CONTEXT_SHOW = `
|
|
3018
|
+
Resolves the selected context locally without authenticating or making API calls.
|
|
3019
|
+
An optional name overrides the invocation's --context or globally active context
|
|
3020
|
+
for this inspection only. JSON includes workspace, project, api, remote and
|
|
3021
|
+
sources. Token output contains only availability and source, never its value.
|
|
3022
|
+
Availability does not prove authentication. Dynamic sources resolve in the current directory.
|
|
3023
|
+
`;
|
|
3024
|
+
exports.HELP_CONTEXT_USE = `
|
|
3025
|
+
Saves the active context for subsequent invocations without resolving its scope.
|
|
3026
|
+
For scripts and parallel agents, prefer --context <name> on each command.
|
|
3027
|
+
Use default to restore the existing configuration rules.
|
|
3028
|
+
`;
|
|
3029
|
+
exports.HELP_CONTEXT_REMOVE = `
|
|
3030
|
+
Removes a saved context and its token after confirmation; --force skips the prompt.
|
|
3031
|
+
Built-in contexts cannot be removed. Removing the active context selects default.
|
|
3032
|
+
A declined confirmation leaves both the context and selection unchanged. In JSON,
|
|
3033
|
+
removed is the deleted name, or null when declined; active is the current selection.
|
|
3034
|
+
Non-interactive commands decline without --force.
|
|
3035
|
+
`;
|
package/distTs/src/tunnel/cfg.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const path_1 = require("path");
|
|
4
7
|
const fs_1 = require("fs");
|
|
5
8
|
const utils_1 = require("../utils");
|
|
9
|
+
const cliError_1 = __importDefault(require("../cliError"));
|
|
6
10
|
const texts_1 = require("../texts");
|
|
11
|
+
const texts_2 = require("../texts");
|
|
7
12
|
const tunnel_1 = require("../types/tunnel");
|
|
8
13
|
class Cfg {
|
|
9
14
|
dir;
|
|
@@ -22,7 +27,7 @@ class Cfg {
|
|
|
22
27
|
});
|
|
23
28
|
}
|
|
24
29
|
catch {
|
|
25
|
-
throw new Error((0,
|
|
30
|
+
throw new Error((0, texts_2.ERR_CANT_CREATE_DIR_IN_HOME)('.bdy'));
|
|
26
31
|
}
|
|
27
32
|
try {
|
|
28
33
|
(0, fs_1.chmodSync)(this.dir, 0o700);
|
|
@@ -36,7 +41,7 @@ class Cfg {
|
|
|
36
41
|
(0, fs_1.writeFileSync)(this.file, '{}', 'utf-8');
|
|
37
42
|
}
|
|
38
43
|
catch {
|
|
39
|
-
throw new Error((0,
|
|
44
|
+
throw new Error((0, texts_2.ERR_CANT_CREATE_DIR_IN_HOME)('.bdy/cfg.json'));
|
|
40
45
|
}
|
|
41
46
|
try {
|
|
42
47
|
(0, fs_1.chmodSync)(this.file, 0o600);
|
|
@@ -252,6 +257,40 @@ class Cfg {
|
|
|
252
257
|
getBaseUrl() {
|
|
253
258
|
return this.json.baseUrl || '';
|
|
254
259
|
}
|
|
260
|
+
getContexts() {
|
|
261
|
+
return { ...this.json.contexts };
|
|
262
|
+
}
|
|
263
|
+
getActiveContext() {
|
|
264
|
+
return this.json.activeContext || 'default';
|
|
265
|
+
}
|
|
266
|
+
getContext(name) {
|
|
267
|
+
if (name === 'default')
|
|
268
|
+
return null;
|
|
269
|
+
if (name === 'git')
|
|
270
|
+
return { source: 'git', remote: 'origin' };
|
|
271
|
+
if (name === 'link')
|
|
272
|
+
return { source: 'link' };
|
|
273
|
+
const contexts = this.getContexts();
|
|
274
|
+
if (!Object.hasOwn(contexts, name))
|
|
275
|
+
throw new cliError_1.default('context_not_found', (0, texts_1.ERR_CONTEXT_UNKNOWN)(name), texts_1.TXT_CONTEXT_HINT);
|
|
276
|
+
return contexts[name];
|
|
277
|
+
}
|
|
278
|
+
setContext(name, context) {
|
|
279
|
+
this.json.contexts = { ...this.getContexts(), [name]: context };
|
|
280
|
+
this.save();
|
|
281
|
+
}
|
|
282
|
+
setActiveContext(name) {
|
|
283
|
+
this.getContext(name);
|
|
284
|
+
this.json.activeContext = name;
|
|
285
|
+
this.save();
|
|
286
|
+
}
|
|
287
|
+
removeContext(name) {
|
|
288
|
+
this.getContext(name);
|
|
289
|
+
delete this.json.contexts[name];
|
|
290
|
+
if (this.getActiveContext() === name)
|
|
291
|
+
this.json.activeContext = 'default';
|
|
292
|
+
this.save();
|
|
293
|
+
}
|
|
255
294
|
clearLogin() {
|
|
256
295
|
delete this.json.apiToken;
|
|
257
296
|
delete this.json.apiRefreshToken;
|
|
@@ -282,7 +321,7 @@ class Cfg {
|
|
|
282
321
|
this.json = JSON.parse(txt);
|
|
283
322
|
}
|
|
284
323
|
catch {
|
|
285
|
-
throw new Error(
|
|
324
|
+
throw new Error(texts_2.ERR_CONFIG_CORRUPTED);
|
|
286
325
|
}
|
|
287
326
|
}
|
|
288
327
|
save() {
|
|
@@ -291,7 +330,7 @@ class Cfg {
|
|
|
291
330
|
(0, fs_1.writeFileSync)(this.file, JSON.stringify(this.json, null, 4), 'utf-8');
|
|
292
331
|
}
|
|
293
332
|
catch {
|
|
294
|
-
throw new Error((0,
|
|
333
|
+
throw new Error((0, texts_2.ERR_CANT_CREATE_DIR_IN_HOME)('.bdy/cfg.json'));
|
|
295
334
|
}
|
|
296
335
|
try {
|
|
297
336
|
(0, fs_1.chmodSync)(this.file, 0o600);
|