shoud-cli 1.0.10 → 3.0.1

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.
@@ -0,0 +1,71 @@
1
+ const { spawn } = require('child_process');
2
+ const os = require('os');
3
+
4
+ function getShell() {
5
+ if (os.platform() === 'win32') return 'powershell.exe';
6
+ return process.env.SHELL || '/bin/bash';
7
+ }
8
+
9
+ function getShellArgs(command) {
10
+ if (os.platform() === 'win32') {
11
+ const escaped = command.replace(/"/g, '`"');
12
+ return ['-NoProfile', '-Command', `& { ${escaped} } | Out-String -Width 4096`];
13
+ }
14
+ return ['-c', command];
15
+ }
16
+
17
+ /**
18
+ * Execute a shell command and stream output to `onOutput` (if provided).
19
+ * Returns { ok, exitCode, stdout, stderr, duration }.
20
+ */
21
+ function runShell(command, { cwd, timeout, onOutput, env } = {}) {
22
+ return new Promise((resolve) => {
23
+ const start = Date.now();
24
+ let stdout = '';
25
+ let stderr = '';
26
+ let timedOut = false;
27
+
28
+ const child = spawn(getShell(), getShellArgs(command), {
29
+ cwd,
30
+ env: { ...process.env, ...(env || {}) },
31
+ windowsHide: true,
32
+ });
33
+
34
+ const timer = timeout ? setTimeout(() => {
35
+ timedOut = true;
36
+ try { child.kill('SIGKILL'); } catch (_) {}
37
+ }, timeout) : null;
38
+
39
+ const forward = (chunk, isErr) => {
40
+ const text = chunk.toString();
41
+ if (isErr) stderr += text; else stdout += text;
42
+ if (onOutput) onOutput(text, isErr);
43
+ };
44
+
45
+ child.stdout.on('data', (c) => forward(c, false));
46
+ child.stderr.on('data', (c) => forward(c, true));
47
+
48
+ child.on('close', (code) => {
49
+ if (timer) clearTimeout(timer);
50
+ resolve({
51
+ ok: code === 0 && !timedOut,
52
+ exitCode: code,
53
+ timedOut,
54
+ stdout: stdout.trim(),
55
+ stderr: stderr.trim(),
56
+ duration: Date.now() - start,
57
+ });
58
+ });
59
+
60
+ child.on('error', (err) => {
61
+ if (timer) clearTimeout(timer);
62
+ resolve({
63
+ ok: false, exitCode: -1, timedOut: false,
64
+ stdout, stderr: stderr + '\n' + err.message,
65
+ duration: Date.now() - start,
66
+ });
67
+ });
68
+ });
69
+ }
70
+
71
+ module.exports = { runShell };
@@ -0,0 +1,20 @@
1
+ const chalk = require('chalk');
2
+
3
+ const BANNER_ART = [
4
+ " ███████╗██╗ ██╗ ██████╗ ██╗ ██╗██████╗ ",
5
+ " ██╔════╝██║ ██║██╔═══██╗██║ ██║██╔══██╗",
6
+ " ███████╗███████║██║ ██║██║ ██║██║ ██║",
7
+ " ╚════██║██╔══██║██║ ██║██║ ██║██║ ██║",
8
+ " ███████║██║ ██║╚██████╔╝╚██████╔╝██████╔╝",
9
+ " ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ "
10
+ ];
11
+
12
+ function printStaticBanner() {
13
+ const color = chalk.hex('#B5F96C');
14
+ console.log(color(BANNER_ART.join('\n')));
15
+ console.log(color(' ┌──────────────────────────────────────────────────────────┐'));
16
+ console.log(color(' │ Give your computer a job. │'));
17
+ console.log(color(' └──────────────────────────────────────────────────────────┘'));
18
+ }
19
+
20
+ module.exports = { printStaticBanner, BANNER_ART };
@@ -0,0 +1,17 @@
1
+ const chalk = require('chalk');
2
+
3
+ const sym = {
4
+ ok: chalk.green('✓'),
5
+ fail: chalk.red('✗'),
6
+ warn: chalk.yellow('⚠'),
7
+ info: chalk.cyan('●'),
8
+ bullet: chalk.gray('·'),
9
+ };
10
+
11
+ function section(title) { console.log(chalk.bold('\n' + title)); }
12
+ function ok(msg) { console.log(` ${sym.ok} ${msg}`); }
13
+ function fail(msg) { console.log(` ${sym.fail} ${msg}`); }
14
+ function warn(msg) { console.log(` ${sym.warn} ${msg}`); }
15
+ function info(msg) { console.log(` ${sym.info} ${msg}`); }
16
+
17
+ module.exports = { section, ok, fail, warn, info, sym };
@@ -0,0 +1,47 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+
5
+ const CONFIG_DIR = path.join(os.homedir(), '.shoud');
6
+ const JOBS_DIR = path.join(CONFIG_DIR, 'jobs');
7
+ const LOGS_DIR = path.join(CONFIG_DIR, 'logs');
8
+
9
+ function ensureDir(dir, mode = 0o700) {
10
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode });
11
+ }
12
+
13
+ function initDirs() {
14
+ ensureDir(CONFIG_DIR);
15
+ ensureDir(JOBS_DIR);
16
+ ensureDir(LOGS_DIR);
17
+ }
18
+
19
+ const paths = {
20
+ CONFIG_DIR,
21
+ JOBS_DIR,
22
+ LOGS_DIR,
23
+ SESSION_FILE: path.join(CONFIG_DIR, 'session.json'),
24
+ ALLOWLIST_FILE: path.join(CONFIG_DIR, 'allowlist.json'),
25
+ SETTINGS_FILE: path.join(CONFIG_DIR, 'settings.json'),
26
+ jobDir: (id) => path.join(JOBS_DIR, id),
27
+ jobFile: (id, name) => path.join(JOBS_DIR, id, name),
28
+ };
29
+
30
+ const DEFAULT_SETTINGS = {
31
+ apiUrl: 'https://shoud.online/api',
32
+ billingUrl: 'https://shoud.vantyrixtek.online',
33
+ defaultBudget: 2.0,
34
+ shellDefaults: { read: 30000, test: 300000, build: 600000, install: 600000 },
35
+ telemetry: false,
36
+ };
37
+
38
+ function loadSettings() {
39
+ try {
40
+ if (fs.existsSync(paths.SETTINGS_FILE)) {
41
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(fs.readFileSync(paths.SETTINGS_FILE, 'utf-8')) };
42
+ }
43
+ } catch (_) {}
44
+ return { ...DEFAULT_SETTINGS };
45
+ }
46
+
47
+ module.exports = { paths, initDirs, loadSettings, DEFAULT_SETTINGS };
@@ -0,0 +1,21 @@
1
+ class ShoudError extends Error {
2
+ constructor(message, code = 1, meta = {}) {
3
+ super(message);
4
+ this.name = 'ShoudError';
5
+ this.code = code;
6
+ this.meta = meta;
7
+ }
8
+ }
9
+
10
+ const ExitCodes = {
11
+ VERIFIED: 0,
12
+ FAILED: 1,
13
+ BLOCKED: 2,
14
+ PERMISSION_DENIED: 3,
15
+ VERIFICATION_FAILED: 4,
16
+ BUDGET_EXCEEDED: 5,
17
+ AUTH_REQUIRED: 6,
18
+ CANCELLED: 130,
19
+ };
20
+
21
+ module.exports = { ShoudError, ExitCodes };