sloss-cli 1.2.1 → 1.3.0

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/bin/sloss.js CHANGED
@@ -120,15 +120,15 @@ program
120
120
  // Build command
121
121
  program
122
122
  .command('build')
123
- .description('Queue a build via the Sloss build agent')
123
+ .description('Run a local EAS build and upload to Sloss')
124
124
  .option('--platform <platform>', 'Platform (ios or android)', 'ios')
125
125
  .option('--profile <profile>', 'Build profile (development, preview, production)', 'development')
126
126
  .option('--bump <type>', 'Version bump type for production (patch, minor, major)', 'patch')
127
- .option('--dir <path>', 'Project directory (default: current directory)', '.')
127
+ .option('--dir <path>', 'Project directory (default: current directory)')
128
+ .option('--yes', 'Skip confirmation prompt')
128
129
  .action(async (options) => {
129
130
  try {
130
- const config = resolveConfig(program.opts());
131
- await buildCommand(options, config);
131
+ await buildCommand(options);
132
132
  } catch (error) {
133
133
  console.error(`Error: ${error.message}`);
134
134
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sloss-cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "CLI for Sloss — a self-hosted IPA/APK distribution server",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,115 +1,40 @@
1
1
  /**
2
- * Build command - Tar up the project and queue a remote build via Sloss agent
2
+ * Build command thin wrapper that execs cli/build.sh with CLI flags passed through.
3
3
  */
4
4
 
5
- import { SlossClient } from '../client.js';
6
- import { existsSync, readFileSync } from 'fs';
7
- import { resolve, basename } from 'path';
8
- import { execSync } from 'child_process';
9
- import { tmpdir } from 'os';
10
- import { join } from 'path';
11
- import { formatBuild } from '../format.js';
5
+ import { resolve, dirname, join } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { execFileSync } from 'child_process';
12
8
 
13
- export async function buildCommand(options, config) {
14
- const platform = (options.platform || 'ios').toLowerCase();
15
- const profile = (options.profile || 'development').toLowerCase();
16
- const bump = options.bump || 'patch';
17
- const projectDir = resolve(options.dir || '.');
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const BUILD_SCRIPT = resolve(__dirname, '../../build.sh');
18
11
 
19
- // Validate platform
20
- if (!['ios', 'android'].includes(platform)) {
21
- throw new Error('Platform must be "ios" or "android"');
22
- }
12
+ export async function buildCommand(options) {
13
+ const args = [];
23
14
 
24
- // Validate profile
25
- if (!['development', 'preview', 'production'].includes(profile)) {
26
- throw new Error('Profile must be "development", "preview", or "production"');
15
+ if (options.platform) {
16
+ args.push('--platform', options.platform);
27
17
  }
28
-
29
- // Check for .sloss.json
30
- const slossConfigPath = join(projectDir, '.sloss.json');
31
- if (!existsSync(slossConfigPath)) {
32
- throw new Error(
33
- `.sloss.json not found in ${projectDir}\n` +
34
- ' Create a .sloss.json config file in your project root.\n' +
35
- ' See: https://github.com/aualdrich/sloss#build-agent'
36
- );
18
+ if (options.profile) {
19
+ args.push('--profile', options.profile);
37
20
  }
38
-
39
- // Read config for display
40
- const slossConfig = JSON.parse(readFileSync(slossConfigPath, 'utf8'));
41
-
42
- console.log('╔══════════════════════════════════════════╗');
43
- console.log('║ SLOSS BUILD ║');
44
- console.log('╠══════════════════════════════════════════╣');
45
- console.log(`║ app : ${(slossConfig.app_name || '—').padEnd(27)} ║`);
46
- console.log(`║ platform : ${platform.padEnd(27)} ║`);
47
- console.log(`║ profile : ${profile.padEnd(27)} ║`);
48
- console.log(`║ bump : ${bump.padEnd(27)} ║`);
49
- console.log(`║ server : ${config.baseUrl.padEnd(27)} ║`);
50
- console.log('╚══════════════════════════════════════════╝');
51
- console.log('');
52
-
53
- // Create tarball
54
- console.log('📦 Packaging project...');
55
- const tarballPath = join(tmpdir(), `sloss-build-${Date.now()}.tar.gz`);
56
-
57
- // Use git archive if in a git repo (respects .gitignore), otherwise tar with excludes
58
- let tarCmd;
59
- try {
60
- execSync('git rev-parse --git-dir', { cwd: projectDir, stdio: 'pipe' });
61
- // git archive from the repo root, only including the project subdir if needed
62
- const gitRoot = execSync('git rev-parse --show-toplevel', { cwd: projectDir, encoding: 'utf8' }).trim();
63
- const relPath = projectDir.replace(gitRoot, '').replace(/^\//, '');
64
-
65
- if (relPath) {
66
- // Project is in a subdirectory — include only that dir
67
- tarCmd = `cd "${gitRoot}" && git archive --format=tar HEAD -- "${relPath}" | gzip > "${tarballPath}"`;
68
- } else {
69
- tarCmd = `cd "${projectDir}" && git archive --format=tar.gz HEAD > "${tarballPath}"`;
70
- }
71
- } catch {
72
- // Not a git repo — fall back to tar with common excludes
73
- tarCmd = `cd "${projectDir}" && tar czf "${tarballPath}" --exclude=node_modules --exclude=.git --exclude=ios/build --exclude=android/build .`;
21
+ if (options.bump) {
22
+ args.push('--bump', options.bump);
74
23
  }
75
-
76
- execSync(tarCmd, { stdio: 'pipe' });
77
-
78
- // Get tarball size for display
79
- const { statSync } = await import('fs');
80
- const tarSize = statSync(tarballPath).size;
81
- const sizeMB = (tarSize / (1024 * 1024)).toFixed(1);
82
- console.log(` → ${sizeMB} MB`);
83
-
84
- // Read version info from .sloss.json's version_file
85
- let version = '';
86
- let buildNumber = '';
87
- if (slossConfig.version_file) {
88
- const versionFilePath = join(projectDir, slossConfig.version_file);
89
- if (existsSync(versionFilePath)) {
90
- const versionData = JSON.parse(readFileSync(versionFilePath, 'utf8'));
91
- version = versionData.version || '';
92
- buildNumber = versionData.buildNumber || '';
93
- }
24
+ if (options.dir) {
25
+ args.push('--dir', resolve(options.dir));
26
+ }
27
+ if (options.yes) {
28
+ args.push('--yes');
94
29
  }
95
30
 
96
- // Upload tarball to start build
97
- console.log('🚀 Queuing build...');
98
- const client = new SlossClient(config.baseUrl, config.apiKey);
99
- const result = await client.startBuild(tarballPath, {
100
- profile,
101
- platform,
102
- bump,
103
- appName: slossConfig.app_name || '',
104
- bundleId: slossConfig.bundle_id || '',
105
- version,
106
- buildNumber,
107
- });
108
-
109
- // Clean up tarball
110
- const { unlinkSync } = await import('fs');
111
- try { unlinkSync(tarballPath); } catch { /* ignore */ }
112
-
113
- console.log('');
114
- console.log(formatBuild(result, config.jsonMode));
31
+ try {
32
+ execFileSync('bash', [BUILD_SCRIPT, ...args], {
33
+ stdio: 'inherit',
34
+ env: process.env,
35
+ });
36
+ } catch (error) {
37
+ // build.sh handles its own error messages; just exit with the same code
38
+ process.exit(error.status || 1);
39
+ }
115
40
  }
@@ -20,13 +20,8 @@ const CREDENTIALS_PATH = join(homedir(), '.config', 'sloss', 'credentials.json')
20
20
  */
21
21
  function prompt(question, hidden = false) {
22
22
  return new Promise((resolve) => {
23
- const rl = createInterface({
24
- input: process.stdin,
25
- output: process.stdout,
26
- });
27
-
28
23
  if (hidden) {
29
- // Suppress echoed characters for password input
24
+ // Raw mode password input no readline (avoids echo)
30
25
  process.stdout.write(question);
31
26
 
32
27
  let value = '';
@@ -34,19 +29,16 @@ function prompt(question, hidden = false) {
34
29
  const onData = (char) => {
35
30
  char = char.toString();
36
31
  if (char === '\n' || char === '\r' || char === '\u0004') {
37
- // Enter pressed
38
32
  process.stdin.setRawMode(false);
39
33
  process.stdin.pause();
40
34
  process.stdin.removeListener('data', onData);
41
35
  process.stdout.write('\n');
42
- rl.close();
43
36
  resolve(value);
44
37
  } else if (char === '\u0003') {
45
- // Ctrl+C
38
+ process.stdin.setRawMode(false);
46
39
  process.stdout.write('\n');
47
40
  process.exit(0);
48
41
  } else if (char === '\u007f' || char === '\b') {
49
- // Backspace
50
42
  if (value.length > 0) {
51
43
  value = value.slice(0, -1);
52
44
  }
@@ -60,6 +52,10 @@ function prompt(question, hidden = false) {
60
52
  process.stdin.setEncoding('utf8');
61
53
  process.stdin.on('data', onData);
62
54
  } else {
55
+ const rl = createInterface({
56
+ input: process.stdin,
57
+ output: process.stdout,
58
+ });
63
59
  rl.question(question, (answer) => {
64
60
  rl.close();
65
61
  resolve(answer);