@reshapr/reshapr-cli 0.0.4 → 0.0.6

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.
@@ -26,11 +26,28 @@ export const loginCommand = new Command('login')
26
26
  .description(`Login to ${CLI_LABEL}`)
27
27
  .option('-u, --username <username>', `Your ${CLI_LABEL} username`)
28
28
  .option('-p, --password <password>', `Your ${CLI_LABEL} password`)
29
- .option('-t, --token <token>', `Your ${CLI_LABEL} authentication token`)
30
29
  .option('-o, --org <org>', `Your ${CLI_LABEL} organization name`)
31
- .option('-s, --server <server>', `Your ${CLI_LABEL} Control Plane URL`, 'https://app.resphar.io')
30
+ .option('-s, --server <server>', `Your ${CLI_LABEL} Control Plane URL`, 'https://try.reshapr.io')
32
31
  .option('-k, --insecure', 'Skip SSL certificate validation')
32
+ .option('--password-stdin', 'Read password from stdin')
33
33
  .action(async (options) => {
34
+ // Validate that --password and --password-stdin are not both provided.
35
+ if (options.password && options.passwordStdin) {
36
+ Logger.error('--password and --password-stdin are mutually exclusive.');
37
+ process.exit(1);
38
+ }
39
+ // If --password-stdin is set, read the password from stdin.
40
+ if (options.passwordStdin) {
41
+ if (process.stdin.isTTY) {
42
+ Logger.error('Error: --password-stdin requires piped input (e.g. echo "password" | reshapr login --password-stdin -u user)');
43
+ process.exit(1);
44
+ }
45
+ options.password = await readFromStdin();
46
+ if (!options.password) {
47
+ Logger.error('Error: password is empty when reading from stdin.');
48
+ process.exit(1);
49
+ }
50
+ }
34
51
  // First validate server URL and fetch server configuration.
35
52
  const configResponse = await fetch(`${options.server}/api/config`, {
36
53
  method: 'GET'
@@ -50,6 +67,15 @@ export const loginCommand = new Command('login')
50
67
  await handleSaaSLogin(options);
51
68
  }
52
69
  });
70
+ function readFromStdin() {
71
+ return new Promise((resolve, reject) => {
72
+ let data = '';
73
+ process.stdin.setEncoding('utf8');
74
+ process.stdin.on('data', (chunk) => { data += chunk; });
75
+ process.stdin.on('end', () => { resolve(data.trim()); });
76
+ process.stdin.on('error', (err) => { reject(err); });
77
+ });
78
+ }
53
79
  async function handleOnPremisesLogin(options) {
54
80
  // Handle on-premises login logic here if needed.
55
81
  if (!options.username) {
@@ -88,13 +88,13 @@ async function downloadComposeFile(release, destPath) {
88
88
  let content = await response.text();
89
89
  // Replace image tags with the requested release.
90
90
  content = content.replace(/(quay\.io\/reshapr\/[^:]+):[\w.-]+/g, `$1:${release}`);
91
- fs.mkdirSync(RESHAPR_DIR, { recursive: true });
92
- fs.writeFileSync(destPath, content, 'utf-8');
91
+ fs.mkdirSync(RESHAPR_DIR, { recursive: true, mode: 0o700 });
92
+ fs.writeFileSync(destPath, content, { encoding: 'utf-8', mode: 0o600 });
93
93
  Logger.success(`Compose file saved to ${destPath}`);
94
94
  }
95
95
  function saveRunState(release, composeFile) {
96
96
  const state = { release, composeFile, startedAt: new Date().toISOString() };
97
- fs.writeFileSync(RUN_STATE_FILE, JSON.stringify(state, null, 2), 'utf-8');
97
+ fs.writeFileSync(RUN_STATE_FILE, JSON.stringify(state, null, 2), { encoding: 'utf-8', mode: 0o600 });
98
98
  }
99
99
  export function readRunState() {
100
100
  if (!fs.existsSync(RUN_STATE_FILE)) {
@@ -23,7 +23,7 @@ export class ConfigUtil {
23
23
  static writeConfig(config) {
24
24
  if (!fs.existsSync(ConfigUtil.configPath)) {
25
25
  try {
26
- fs.mkdirSync(`${os.homedir()}/.${CLI_NAME}`, { recursive: true });
26
+ fs.mkdirSync(`${os.homedir()}/.${CLI_NAME}`, { recursive: true, mode: 0o700 });
27
27
  }
28
28
  catch (err) {
29
29
  Logger.error('Failed to create config directory: ' + err);
@@ -48,7 +48,7 @@ export class ConfigUtil {
48
48
  Logger.error('Failed to parse token: ' + err);
49
49
  }
50
50
  }
51
- fs.writeFileSync(ConfigUtil.configPath, JSON.stringify(config, null, 2));
51
+ fs.writeFileSync(ConfigUtil.configPath, JSON.stringify(config, null, 2), { mode: 0o600 });
52
52
  Logger.success(`Configuration saved to ${ConfigUtil.configPath}`);
53
53
  ConfigUtil.config = config;
54
54
  }
@@ -25,7 +25,7 @@ export async function openUpdateEditor(initialContent, onChanged) {
25
25
  const tempDir = os.tmpdir();
26
26
  const tempFile = path.join(tempDir, `${CLI_NAME}-update.json`);
27
27
  const initialData = JSON.stringify(initialContent, null, 2);
28
- await fs.writeFile(tempFile, initialData, 'utf8');
28
+ await fs.writeFile(tempFile, initialData, { encoding: 'utf-8', mode: 0o600 });
29
29
  // Get the initial modification time
30
30
  const statsBefore = await fs.stat(tempFile);
31
31
  const mtimeBefore = statsBefore.mtime.getTime();
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const CLI_VERSION = "0.0.4";
1
+ export const CLI_VERSION = "0.0.6";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reshapr/reshapr-cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "CLI for reshapr.io - The MCP Gateway for AI-Native API Access!",
5
5
  "type": "module",
6
6
  "main": "src/cli.ts",
@@ -24,12 +24,13 @@
24
24
  "lint": "eslint src/**/*.ts"
25
25
  },
26
26
  "dependencies": {
27
+ "@scarf/scarf": "^1.4.0",
27
28
  "chalk": "^5.4.1",
28
29
  "commander": "^14.0.0",
29
30
  "get-port": "^7.1.0",
30
31
  "inquirer": "^12.7.0",
31
32
  "js-yaml": "^4.1.0",
32
- "open": "^10.2.0",
33
+ "open": "^11.0.0",
33
34
  "yocto-spinner": "^1.0.0"
34
35
  },
35
36
  "devDependencies": {