@vendian/cli 0.0.1 → 0.0.3

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/src/process.js DELETED
@@ -1,50 +0,0 @@
1
- import { spawn, spawnSync } from 'node:child_process';
2
-
3
- export function commandExists(command) {
4
- const result = spawnSync(command, ['--version'], { stdio: 'ignore', shell: false });
5
- return result.status === 0;
6
- }
7
-
8
- export function runCapture(command, args, options = {}) {
9
- const result = spawnSync(command, args, {
10
- encoding: 'utf8',
11
- shell: false,
12
- ...options
13
- });
14
- return {
15
- ok: result.status === 0,
16
- status: result.status ?? 1,
17
- stdout: result.stdout || '',
18
- stderr: result.stderr || ''
19
- };
20
- }
21
-
22
- export function runInherit(command, args, options = {}) {
23
- const result = spawnSync(command, args, {
24
- stdio: 'inherit',
25
- shell: false,
26
- ...options
27
- });
28
- if (result.error) {
29
- throw result.error;
30
- }
31
- return result.status ?? 1;
32
- }
33
-
34
- export function spawnForward(command, args, options = {}) {
35
- return new Promise((resolve, reject) => {
36
- const child = spawn(command, args, {
37
- stdio: 'inherit',
38
- shell: false,
39
- ...options
40
- });
41
- child.on('error', reject);
42
- child.on('exit', (code, signal) => {
43
- if (signal) {
44
- reject(new Error(`command terminated by ${signal}`));
45
- return;
46
- }
47
- resolve(code ?? 1);
48
- });
49
- });
50
- }
package/src/prompt.js DELETED
@@ -1,38 +0,0 @@
1
- import readline from 'node:readline';
2
-
3
- export function prompt(question, { defaultValue, secret = false } = {}) {
4
- const suffix = defaultValue ? ` [${defaultValue}]` : '';
5
- const rl = readline.createInterface({
6
- input: process.stdin,
7
- output: process.stdout,
8
- terminal: true
9
- });
10
-
11
- if (!secret) {
12
- return new Promise((resolve) => {
13
- rl.question(`${question}${suffix}: `, (answer) => {
14
- rl.close();
15
- resolve(answer.trim() || defaultValue || '');
16
- });
17
- });
18
- }
19
-
20
- const originalWrite = rl._writeToOutput;
21
- rl._writeToOutput = function writeHidden(stringToWrite) {
22
- if (rl.stdoutMuted) {
23
- rl.output.write(stringToWrite.replace(/[^\r\n]/g, '*'));
24
- } else {
25
- originalWrite.call(rl, stringToWrite);
26
- }
27
- };
28
-
29
- return new Promise((resolve) => {
30
- rl.stdoutMuted = true;
31
- rl.question(`${question}${suffix}: `, (answer) => {
32
- rl.stdoutMuted = false;
33
- rl.output.write('\n');
34
- rl.close();
35
- resolve(answer.trim() || defaultValue || '');
36
- });
37
- });
38
- }
package/src/python.js DELETED
@@ -1,77 +0,0 @@
1
- import fs from 'node:fs';
2
- import { commandExists, runCapture, runInherit } from './process.js';
3
- import { venvPython } from './paths.js';
4
-
5
- export function findPython(platform = process.platform) {
6
- const candidates = platform === 'win32'
7
- ? [
8
- { command: 'py', args: ['-3.11'] },
9
- { command: 'python', args: [] },
10
- { command: 'python3', args: [] }
11
- ]
12
- : [
13
- { command: 'python3.12', args: [] },
14
- { command: 'python3.11', args: [] },
15
- { command: 'python3', args: [] },
16
- { command: 'python', args: [] }
17
- ];
18
-
19
- for (const candidate of candidates) {
20
- const version = runCapture(candidate.command, [
21
- ...candidate.args,
22
- '-c',
23
- 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")'
24
- ]);
25
- if (!version.ok) {
26
- continue;
27
- }
28
- const match = version.stdout.trim().match(/^(\d+)\.(\d+)\./);
29
- if (!match) {
30
- continue;
31
- }
32
- const major = Number(match[1]);
33
- const minor = Number(match[2]);
34
- if (major > 3 || (major === 3 && minor >= 11)) {
35
- return candidate;
36
- }
37
- }
38
- return null;
39
- }
40
-
41
- export function ensureVenv(venvPath, pythonCandidate, platform = process.platform) {
42
- const pythonPath = venvPython(venvPath, platform);
43
- if (fs.existsSync(pythonPath)) {
44
- return pythonPath;
45
- }
46
- fs.mkdirSync(venvPath, { recursive: true });
47
- const status = runInherit(pythonCandidate.command, [
48
- ...pythonCandidate.args,
49
- '-m',
50
- 'venv',
51
- venvPath
52
- ]);
53
- if (status !== 0) {
54
- throw new Error('Could not create the managed Vendian Python environment.');
55
- }
56
- return pythonPath;
57
- }
58
-
59
- export function hasUv() {
60
- return commandExists('uv');
61
- }
62
-
63
- export function pythonVersion(pythonPath) {
64
- const result = runCapture(pythonPath, [
65
- '-c',
66
- 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")'
67
- ]);
68
- return result.ok ? result.stdout.trim() : null;
69
- }
70
-
71
- export function verifyVendianImports(pythonPath) {
72
- const result = runCapture(pythonPath, [
73
- '-c',
74
- 'import vendian_agents, vendian_agents_runtime; print("ok")'
75
- ]);
76
- return result.ok;
77
- }
@@ -1,94 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
-
3
- const SERVICE = 'Vendian CLI';
4
- const PACKAGE_TOKEN_ACCOUNT = 'gitlab-package-token';
5
-
6
- function run(command, args, options = {}) {
7
- return spawnSync(command, args, {
8
- encoding: 'utf8',
9
- shell: false,
10
- ...options
11
- });
12
- }
13
-
14
- export function packageTokenSecretName() {
15
- return PACKAGE_TOKEN_ACCOUNT;
16
- }
17
-
18
- export function savePackageTokenSecret(token, config = {}, platform = process.platform) {
19
- if (!token) {
20
- return { ok: false };
21
- }
22
- if (platform === 'darwin') {
23
- const result = run('security', [
24
- 'add-generic-password',
25
- '-a',
26
- PACKAGE_TOKEN_ACCOUNT,
27
- '-s',
28
- SERVICE,
29
- '-w',
30
- token,
31
- '-U'
32
- ]);
33
- return { ok: result.status === 0, provider: 'macos-keychain' };
34
- }
35
- if (platform === 'win32') {
36
- const encrypted = run(
37
- 'powershell.exe',
38
- [
39
- '-NoProfile',
40
- '-NonInteractive',
41
- '-Command',
42
- '$secure = ConvertTo-SecureString -String $env:VENDIAN_SECRET_VALUE -AsPlainText -Force; $secure | ConvertFrom-SecureString'
43
- ],
44
- { env: { ...process.env, VENDIAN_SECRET_VALUE: token } }
45
- );
46
- if (encrypted.status !== 0 || !encrypted.stdout.trim()) {
47
- return { ok: false, provider: 'windows-dpapi' };
48
- }
49
- const nextConfig = {
50
- ...config,
51
- secretStore: {
52
- ...(config.secretStore || {}),
53
- [PACKAGE_TOKEN_ACCOUNT]: {
54
- provider: 'windows-dpapi',
55
- value: encrypted.stdout.trim()
56
- }
57
- }
58
- };
59
- return { ok: true, provider: 'windows-dpapi', config: nextConfig };
60
- }
61
- return { ok: false };
62
- }
63
-
64
- export function loadPackageTokenSecret(config = {}, platform = process.platform) {
65
- if (platform === 'darwin') {
66
- const result = run('security', [
67
- 'find-generic-password',
68
- '-a',
69
- PACKAGE_TOKEN_ACCOUNT,
70
- '-s',
71
- SERVICE,
72
- '-w'
73
- ]);
74
- return result.status === 0 ? result.stdout.trim() : '';
75
- }
76
- if (platform === 'win32') {
77
- const entry = config.secretStore?.[PACKAGE_TOKEN_ACCOUNT];
78
- if (!entry || entry.provider !== 'windows-dpapi' || !entry.value) {
79
- return '';
80
- }
81
- const result = run(
82
- 'powershell.exe',
83
- [
84
- '-NoProfile',
85
- '-NonInteractive',
86
- '-Command',
87
- '$secure = ConvertTo-SecureString -String $env:VENDIAN_SECRET_BLOB; $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure); try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) }'
88
- ],
89
- { env: { ...process.env, VENDIAN_SECRET_BLOB: entry.value } }
90
- );
91
- return result.status === 0 ? result.stdout.trim() : '';
92
- }
93
- return '';
94
- }
package/src/setup.js DELETED
@@ -1,121 +0,0 @@
1
- import fs from 'node:fs';
2
- import { loginWithVendianOAuth, saveCloudToken } from './auth.js';
3
- import { DEFAULT_GITLAB_HOST, DEFAULT_SDK_PUBLIC_PROJECT_ID, DEFAULT_SDK_RUNTIME_PROJECT_ID } from './constants.js';
4
- import { loadConfig, saveConfig, redact } from './config.js';
5
- import { installVendianPackages, registryConfig } from './install.js';
6
- import { managedVenvPath, venvVendian } from './paths.js';
7
- import { findPython, ensureVenv, pythonVersion, verifyVendianImports } from './python.js';
8
- import { savePackageTokenSecret } from './secret-store.js';
9
-
10
- export async function setup({
11
- nonInteractive = false,
12
- backend = undefined,
13
- apiUrl = undefined,
14
- noBrowser = false,
15
- env = process.env,
16
- platform = process.platform
17
- } = {}) {
18
- const existing = loadConfig(env, platform);
19
- const registry = registryConfig(existing, env, platform);
20
- const next = {
21
- ...existing,
22
- gitlabHost: registry.gitlabHost || DEFAULT_GITLAB_HOST,
23
- gitlabUsername: registry.username || '__token__',
24
- sdkPublicProjectId: registry.sdkProjectId || DEFAULT_SDK_PUBLIC_PROJECT_ID,
25
- sdkRuntimeProjectId: registry.runtimeProjectId || DEFAULT_SDK_RUNTIME_PROJECT_ID
26
- };
27
- let cloudAuthApiUrl;
28
-
29
- console.log('Vendian setup');
30
- console.log('This installs the private Vendian Python CLI/runtime into a managed local environment.');
31
- console.log('Agent requirements.txt files stay reserved for agent-owned dependencies.');
32
- console.log('');
33
-
34
- if (!registry.token && !nonInteractive) {
35
- console.log('Opening Vendian sign-in to get package access...');
36
- const login = await loginWithVendianOAuth({ backend, apiUrl, noBrowser, env });
37
- saveCloudToken(login, { env, platform });
38
- cloudAuthApiUrl = login.apiUrl;
39
- const packageCredentials = login.packageCredentials;
40
- if (!packageCredentials?.token) {
41
- throw new Error('Vendian login succeeded, but the backend did not return package credentials. Configure CLI_PACKAGE_REGISTRY_TOKEN on the backend.');
42
- }
43
- next.gitlabHost = packageCredentials.gitlabHost || next.gitlabHost;
44
- next.gitlabUsername = packageCredentials.username || next.gitlabUsername;
45
- next.sdkPublicProjectId = packageCredentials.sdkProjectId || next.sdkPublicProjectId;
46
- next.sdkRuntimeProjectId = packageCredentials.runtimeProjectId || next.sdkRuntimeProjectId;
47
- next.vendianAgentsVersion = packageCredentials.vendianAgentsVersion || next.vendianAgentsVersion;
48
- next.vendianAgentsRuntimeVersion = packageCredentials.vendianAgentsRuntimeVersion || next.vendianAgentsRuntimeVersion;
49
-
50
- const secret = savePackageTokenSecret(packageCredentials.token, next, platform);
51
- if (secret.ok) {
52
- Object.assign(next, secret.config || {});
53
- delete next.gitlabToken;
54
- console.log(`Package token saved with ${secret.provider}.`);
55
- } else {
56
- next.gitlabToken = packageCredentials.token;
57
- console.log('Package token saved in the local Vendian CLI config file.');
58
- }
59
- } else if (registry.token) {
60
- if (registry.tokenSource !== 'secret-store') {
61
- next.gitlabToken = registry.token;
62
- }
63
- console.log(`Using GitLab package token ${redact(registry.token)}.`);
64
- }
65
-
66
- const installRegistry = registryConfig(next, env, platform);
67
- if (!installRegistry.token) {
68
- throw new Error('Setup needs package access. Run interactive `vendian login` to sign in, or set GITLAB_TOKEN for local development.');
69
- }
70
-
71
- const python = findPython(platform);
72
- if (!python) {
73
- throw new Error('Python 3.11+ was not found. Install Python 3.11 or newer, then rerun `vendian login`.');
74
- }
75
-
76
- const venvPath = managedVenvPath(env, platform);
77
- console.log(`Managed environment: ${venvPath}`);
78
- const pythonPath = ensureVenv(venvPath, python, platform);
79
- console.log(`Python: ${pythonVersion(pythonPath) || pythonPath}`);
80
-
81
- saveConfig(next, env, platform);
82
- installVendianPackages({ pythonPath, venvPath, config: next, env, platform });
83
- saveConfig({ ...next, lastManagedUpdateAt: new Date().toISOString() }, env, platform);
84
-
85
- if (!verifyVendianImports(pythonPath)) {
86
- throw new Error('Vendian packages installed, but import verification failed.');
87
- }
88
-
89
- const vendianPath = venvVendian(venvPath, platform);
90
- if (!fs.existsSync(vendianPath)) {
91
- throw new Error('Vendian executable was not found after install.');
92
- }
93
-
94
- console.log('');
95
- for (const line of setupCompletionLines({ cloudAuthApiUrl, backend, apiUrl })) {
96
- console.log(line);
97
- }
98
- }
99
-
100
- export function setupCompletionLines({ cloudAuthApiUrl, backend, apiUrl } = {}) {
101
- const lines = ['Vendian setup complete.'];
102
- if (cloudAuthApiUrl) {
103
- lines.push(`Cloud authentication saved for ${cloudAuthApiUrl}.`);
104
- lines.push('Next: vendian cloud local serve --agents-dir ./agents');
105
- return lines;
106
- }
107
-
108
- lines.push(`Next: ${cloudAuthLoginCommand({ backend, apiUrl })}`);
109
- lines.push('Then: vendian cloud local serve --agents-dir ./agents');
110
- return lines;
111
- }
112
-
113
- function cloudAuthLoginCommand({ backend, apiUrl } = {}) {
114
- if (apiUrl) {
115
- return `vendian cloud auth login --api-url ${apiUrl}`;
116
- }
117
- if (backend) {
118
- return `vendian cloud auth login --backend ${backend}`;
119
- }
120
- return 'vendian cloud auth login';
121
- }