puter-cli 1.1.4 → 1.2.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/.github/workflows/npm-build.yml +21 -0
- package/.github/workflows/{npm-publish-github-packages.yml → npm-publish.yml} +5 -10
- package/README.md +26 -11
- package/bin/index.js +27 -5
- package/package.json +4 -3
- package/{commands → src/commands}/apps.js +19 -16
- package/{commands → src/commands}/auth.js +1 -1
- package/{commands → src/commands}/files.js +3 -3
- package/{commands → src/commands}/init.js +1 -1
- package/{commands → src/commands}/shell.js +3 -3
- package/{commands → src/commands}/sites.js +2 -2
- package/{commands → src/commands}/subdomains.js +1 -1
- package/{commands → src}/commons.js +1 -1
- package/{commands → src}/executor.js +75 -16
- package/{commands → src}/utils.js +12 -1
- package/tests/login.test.js +2 -2
- /package/{commands → src}/crypto.js +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# This workflow will run tests using node on every push
|
|
2
|
+
|
|
3
|
+
name: Build package
|
|
4
|
+
|
|
5
|
+
on: push
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
node-version: ['18.x', '20.x', '23.x']
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: ${{ matrix.node-version }}
|
|
20
|
+
- run: npm ci
|
|
21
|
+
- run: npm test
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
2
|
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
3
|
|
|
4
|
-
name:
|
|
4
|
+
name: Publish package
|
|
5
5
|
|
|
6
|
-
on:
|
|
7
|
-
release:
|
|
8
|
-
types: [created]
|
|
6
|
+
on: push
|
|
9
7
|
|
|
10
8
|
jobs:
|
|
11
9
|
build:
|
|
@@ -18,19 +16,16 @@ jobs:
|
|
|
18
16
|
- run: npm ci
|
|
19
17
|
- run: npm test
|
|
20
18
|
|
|
21
|
-
publish-
|
|
19
|
+
publish-npm:
|
|
22
20
|
needs: build
|
|
23
21
|
runs-on: ubuntu-latest
|
|
24
|
-
permissions:
|
|
25
|
-
contents: read
|
|
26
|
-
packages: write
|
|
27
22
|
steps:
|
|
28
23
|
- uses: actions/checkout@v4
|
|
29
24
|
- uses: actions/setup-node@v4
|
|
30
25
|
with:
|
|
31
26
|
node-version: 20
|
|
32
|
-
registry-url: https://
|
|
27
|
+
registry-url: https://registry.npmjs.org/
|
|
33
28
|
- run: npm ci
|
|
34
29
|
- run: npm publish
|
|
35
30
|
env:
|
|
36
|
-
NODE_AUTH_TOKEN: ${{secrets.
|
|
31
|
+
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Puter-CLI
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img alt="test" src="https://github.com/bitsnaps/puter-cli/actions/workflows/npm-
|
|
4
|
+
<img alt="test" src="https://github.com/bitsnaps/puter-cli/actions/workflows/npm-build.yml/badge.svg">
|
|
5
5
|
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/bitsnaps/puter-cli">
|
|
6
6
|
</p>
|
|
7
7
|
|
|
@@ -123,17 +123,17 @@ P.S. These commands consider the current directory as the base path for every op
|
|
|
123
123
|
#### User Information
|
|
124
124
|
- **Get User Info**: Display user information.
|
|
125
125
|
```bash
|
|
126
|
-
puter whoami
|
|
126
|
+
puter> whoami
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
#### Disk Usage
|
|
130
130
|
- **Check Disk Usage**: Display disk usage information.
|
|
131
131
|
```bash
|
|
132
|
-
puter df
|
|
132
|
+
puter> df
|
|
133
133
|
```
|
|
134
134
|
- **Get Usage Info**: Fetch usage information for services.
|
|
135
135
|
```bash
|
|
136
|
-
puter usage
|
|
136
|
+
puter> usage
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
#### Application Management
|
|
@@ -142,25 +142,25 @@ The **Application** are sepcial type of hosted web app, they're served from the
|
|
|
142
142
|
|
|
143
143
|
- **List Applications**: List all applications.
|
|
144
144
|
```bash
|
|
145
|
-
puter apps [period]
|
|
145
|
+
puter> apps [period]
|
|
146
146
|
```
|
|
147
147
|
P.S. Please check the help command `help apps` for more details about any argument.
|
|
148
148
|
|
|
149
149
|
- **Create Application**: Create a new application.
|
|
150
150
|
```bash
|
|
151
|
-
puter app:create <name> [<
|
|
151
|
+
puter> app:create <name> [<directory>] [--description="My App Description"] [--url=<url>]
|
|
152
152
|
```
|
|
153
153
|
P.S. By default a new `index.html` with basic content will be created, but you can set a directory when you create a new application as follows: `app:create nameOfApp ./appDir`, so all files will be copied to the `AppData` directoy, you can then update your app using `app:update <name> <remote_dir>`. This command will attempt to create a subdomain with a random `uid` prefixed with the name of the app.
|
|
154
154
|
|
|
155
155
|
- **Update Application**: Update an application.
|
|
156
156
|
```bash
|
|
157
|
-
puter app:update <name> <remote_dir>
|
|
157
|
+
puter> app:update <name> <remote_dir>
|
|
158
158
|
```
|
|
159
159
|
**IMPORTANT** All existing files will be overwritten, new files are copied, other files are just ignored.
|
|
160
160
|
|
|
161
161
|
- **Delete Application**: Delete an application.
|
|
162
162
|
```bash
|
|
163
|
-
puter app:delete [-f] <name>
|
|
163
|
+
puter> app:delete [-f] <name>
|
|
164
164
|
```
|
|
165
165
|
P.S. This command will lookup for the allocated `subdomain` and attempt to delete it if it exists.
|
|
166
166
|
|
|
@@ -170,20 +170,31 @@ The static sites are served from the selected directory (or the current director
|
|
|
170
170
|
|
|
171
171
|
- **Deploy Site**: Deploy a static website from a directory.
|
|
172
172
|
```bash
|
|
173
|
-
puter site:create <app_name> [<dir>] [--subdomain=<name>]
|
|
173
|
+
puter> site:create <app_name> [<dir>] [--subdomain=<name>]
|
|
174
174
|
```
|
|
175
175
|
P.S. If the subdomain already exists, it will generate a new random one can set your own subdomain using `--subdomain` argument.
|
|
176
176
|
|
|
177
177
|
- **List Sites**: List all hosted sites.
|
|
178
178
|
```bash
|
|
179
|
-
puter sites
|
|
179
|
+
puter> sites
|
|
180
180
|
```
|
|
181
181
|
- **Delete Site**: Delete a hosted site.
|
|
182
182
|
```bash
|
|
183
|
-
puter site:delete <uid>
|
|
183
|
+
puter> site:delete <uid>
|
|
184
184
|
```
|
|
185
185
|
P.S. You can find the `<uid>` in the list of `sites`.
|
|
186
186
|
|
|
187
|
+
#### Commands history
|
|
188
|
+
|
|
189
|
+
- **Display history**: Display the history executed commands
|
|
190
|
+
```bash
|
|
191
|
+
puter> history
|
|
192
|
+
```
|
|
193
|
+
- **Copy command from history**: Copy a previous command from history by line number
|
|
194
|
+
```bash
|
|
195
|
+
puter> history <line_number>
|
|
196
|
+
```
|
|
197
|
+
|
|
187
198
|
#### Interactive Shell
|
|
188
199
|
- **Start Shell**: Launch an interactive shell.
|
|
189
200
|
```bash
|
|
@@ -198,10 +209,14 @@ or just type (you'll need to login):
|
|
|
198
209
|
- **General Help**: Display a list of available commands.
|
|
199
210
|
```bash
|
|
200
211
|
puter help
|
|
212
|
+
# or inside the interactive shell:
|
|
213
|
+
puter> help
|
|
201
214
|
```
|
|
202
215
|
- **Command Help**: Display detailed help for a specific command.
|
|
203
216
|
```bash
|
|
204
217
|
puter help <command>
|
|
218
|
+
# or inside the interactive shell:
|
|
219
|
+
puter> help <command>
|
|
205
220
|
```
|
|
206
221
|
|
|
207
222
|
---
|
package/bin/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { login, logout } from '../commands/auth.js';
|
|
4
|
-
import { init } from '../commands/init.js';
|
|
5
|
-
import { startShell } from '../commands/shell.js';
|
|
6
|
-
import { PROJECT_NAME, getLatestVersion } from '../
|
|
3
|
+
import { login, logout } from '../src/commands/auth.js';
|
|
4
|
+
import { init } from '../src/commands/init.js';
|
|
5
|
+
import { startShell } from '../src/commands/shell.js';
|
|
6
|
+
import { PROJECT_NAME, getLatestVersion } from '../src/commons.js';
|
|
7
7
|
|
|
8
8
|
async function main() {
|
|
9
9
|
const { version } = await getLatestVersion(PROJECT_NAME);
|
|
@@ -34,10 +34,32 @@ async function main() {
|
|
|
34
34
|
.description('Start interactive shell')
|
|
35
35
|
.action(startShell);
|
|
36
36
|
|
|
37
|
+
|
|
38
|
+
// App commands
|
|
39
|
+
program
|
|
40
|
+
.command('app:create <name>')
|
|
41
|
+
.description('Create a new Puter application')
|
|
42
|
+
.argument('<name>', 'Name of the application')
|
|
43
|
+
.argument('[directory]', 'Local directory path')
|
|
44
|
+
.option('-d, --description <description>', 'Application description')
|
|
45
|
+
.option('-u, --url <url>', 'Application URL', 'https://dev-center.puter.com/coming-soon.html')
|
|
46
|
+
.action(async (name, directory, options) => {
|
|
47
|
+
try {
|
|
48
|
+
await createApp({
|
|
49
|
+
name,
|
|
50
|
+
directory: directory || '',
|
|
51
|
+
description: options.description || '',
|
|
52
|
+
url: options.url
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error(chalk.red(error.message));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
37
59
|
if (process.argv.length === 2) {
|
|
38
60
|
startShell();
|
|
39
61
|
} else {
|
|
40
|
-
program.parse();
|
|
62
|
+
program.parse(process.argv);
|
|
41
63
|
}
|
|
42
64
|
}
|
|
43
65
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "puter-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Command line interface for Puter cloud platform",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"chalk": "^5.3.0",
|
|
28
28
|
"cli-table3": "^0.6.5",
|
|
29
|
-
"commander": "^
|
|
29
|
+
"commander": "^13.0.0",
|
|
30
30
|
"conf": "^12.0.0",
|
|
31
31
|
"cross-spawn": "^7.0.3",
|
|
32
32
|
"glob": "^11.0.0",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"minimatch": "^10.0.1",
|
|
35
35
|
"node-fetch": "^3.3.2",
|
|
36
36
|
"ora": "^8.0.1",
|
|
37
|
-
"uuid": "^11.0.5"
|
|
37
|
+
"uuid": "^11.0.5",
|
|
38
|
+
"yargs-parser": "^21.1.1"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"vitest": "^2.1.8"
|
|
@@ -2,13 +2,13 @@ import path from 'path';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import fetch from 'node-fetch';
|
|
4
4
|
import Table from 'cli-table3';
|
|
5
|
-
import { displayNonNullValues, formatDate } from '
|
|
6
|
-
import { API_BASE, getHeaders, getDefaultHomePage, isValidAppName, resolvePath } from '
|
|
5
|
+
import { displayNonNullValues, formatDate } from '../utils.js';
|
|
6
|
+
import { API_BASE, getHeaders, getDefaultHomePage, isValidAppName, resolvePath } from '../commons.js';
|
|
7
7
|
import { createSubdomain, getSubdomains } from './subdomains.js';
|
|
8
8
|
import { deleteSite } from './sites.js';
|
|
9
9
|
import { copyFile, createFile, listRemoteFiles, pathExists, removeFileOrDirectory } from './files.js';
|
|
10
10
|
import { getCurrentDirectory } from './auth.js';
|
|
11
|
-
import crypto from '
|
|
11
|
+
import crypto from '../crypto.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* List all apps
|
|
@@ -126,25 +126,28 @@ export async function appInfo(args = []) {
|
|
|
126
126
|
/**
|
|
127
127
|
* Create a new web application
|
|
128
128
|
* @param {string} name The name of the App
|
|
129
|
+
* @param {string} directory Optional directory path
|
|
129
130
|
* @param {string} description A description of the App
|
|
130
131
|
* @param {string} url A default coming-soon URL
|
|
131
|
-
* @returns Output JSON data
|
|
132
|
+
* @returns {Promise<Object>} Output JSON data
|
|
132
133
|
*/
|
|
133
|
-
export async function createApp(args
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return;
|
|
134
|
+
export async function createApp(args) {
|
|
135
|
+
const name = args.name; // App name (required)
|
|
136
|
+
console.log(args);
|
|
137
|
+
if (!isValidAppName(name)) {
|
|
138
|
+
throw new Error('Invalid application name');
|
|
139
139
|
}
|
|
140
|
-
const name = args[0]; // App name (required)
|
|
141
140
|
// Use the default home page if the root directory if none specified
|
|
142
|
-
const localDir =
|
|
143
|
-
// Optional description
|
|
144
|
-
const description =
|
|
145
|
-
const url =
|
|
141
|
+
const localDir = args.directory ? resolvePath(getCurrentDirectory(), args.directory) : '';
|
|
142
|
+
// Optional description
|
|
143
|
+
const description = args.description || '';
|
|
144
|
+
const url = args.url || '';
|
|
145
|
+
|
|
146
|
+
console.log(chalk.green(`Creating app "${name}"...`));
|
|
147
|
+
console.log(chalk.dim(`Directory: ${localDir || '[default]'}`));
|
|
148
|
+
console.log(chalk.dim(`Description: ${description}`));
|
|
149
|
+
console.log(chalk.dim(`URL: ${url}`));
|
|
146
150
|
|
|
147
|
-
console.log(chalk.dim(`Creating app: ${chalk.green(name)}...\n`));
|
|
148
151
|
try {
|
|
149
152
|
// Step 1: Create the app
|
|
150
153
|
const createAppResponse = await fetch(`${API_BASE}/drivers/call`, {
|
|
@@ -3,7 +3,7 @@ import chalk from 'chalk';
|
|
|
3
3
|
import Conf from 'conf';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import fetch from 'node-fetch';
|
|
6
|
-
import { PROJECT_NAME, API_BASE, getHeaders, BASE_URL } from '
|
|
6
|
+
import { PROJECT_NAME, API_BASE, getHeaders, BASE_URL } from '../commons.js'
|
|
7
7
|
const config = new Conf({ projectName: PROJECT_NAME });
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -6,12 +6,12 @@ import chalk from 'chalk';
|
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import Conf from 'conf';
|
|
8
8
|
import fetch from 'node-fetch';
|
|
9
|
-
import { API_BASE, BASE_URL, PROJECT_NAME, getHeaders, showDiskSpaceUsage, resolvePath } from '
|
|
10
|
-
import { formatDate, formatDateTime, formatSize } from '
|
|
9
|
+
import { API_BASE, BASE_URL, PROJECT_NAME, getHeaders, showDiskSpaceUsage, resolvePath } from '../commons.js';
|
|
10
|
+
import { formatDate, formatDateTime, formatSize } from '../utils.js';
|
|
11
11
|
import inquirer from 'inquirer';
|
|
12
12
|
import { getAuthToken, getCurrentDirectory, getCurrentUserName } from './auth.js';
|
|
13
13
|
import { updatePrompt } from './shell.js';
|
|
14
|
-
import crypto from '
|
|
14
|
+
import crypto from '../crypto.js';
|
|
15
15
|
|
|
16
16
|
const config = new Conf({ projectName: PROJECT_NAME });
|
|
17
17
|
|
|
@@ -3,7 +3,7 @@ import chalk from 'chalk';
|
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import { promises as fs } from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import { generateAppName } from '
|
|
6
|
+
import { generateAppName } from '../commons.js';
|
|
7
7
|
|
|
8
8
|
export async function init() {
|
|
9
9
|
const answers = await inquirer.prompt([
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import readline from 'node:readline';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import Conf from 'conf';
|
|
4
|
-
import { execCommand, getPrompt } from '
|
|
4
|
+
import { execCommand, getPrompt } from '../executor.js';
|
|
5
5
|
import { getAuthToken } from './auth.js';
|
|
6
|
-
import { PROJECT_NAME } from '
|
|
6
|
+
import { PROJECT_NAME } from '../commons.js';
|
|
7
7
|
|
|
8
8
|
const config = new Conf({ projectName: PROJECT_NAME });
|
|
9
9
|
|
|
10
|
-
const rl = readline.createInterface({
|
|
10
|
+
export const rl = readline.createInterface({
|
|
11
11
|
input: process.stdin,
|
|
12
12
|
output: process.stdout,
|
|
13
13
|
prompt: null
|
|
@@ -2,8 +2,8 @@ import chalk from 'chalk';
|
|
|
2
2
|
import fetch from 'node-fetch';
|
|
3
3
|
import Table from 'cli-table3';
|
|
4
4
|
import { getCurrentUserName, getCurrentDirectory } from './auth.js';
|
|
5
|
-
import { API_BASE, getHeaders, generateAppName, resolvePath, isValidAppName } from '
|
|
6
|
-
import { displayNonNullValues, formatDate, formatDateTime } from '
|
|
5
|
+
import { API_BASE, getHeaders, generateAppName, resolvePath, isValidAppName } from '../commons.js';
|
|
6
|
+
import { displayNonNullValues, formatDate, formatDateTime } from '../utils.js';
|
|
7
7
|
import { getSubdomains, createSubdomain, deleteSubdomain } from './subdomains.js';
|
|
8
8
|
|
|
9
9
|
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import ora from 'ora';
|
|
3
2
|
import Conf from 'conf';
|
|
4
|
-
import { listApps, appInfo, createApp, updateApp, deleteApp } from './apps.js';
|
|
5
|
-
import { listSites, createSite, deleteSite, infoSite } from './sites.js';
|
|
3
|
+
import { listApps, appInfo, createApp, updateApp, deleteApp } from './commands/apps.js';
|
|
4
|
+
import { listSites, createSite, deleteSite, infoSite } from './commands/sites.js';
|
|
6
5
|
import { listFiles, makeDirectory, renameFileOrDirectory,
|
|
7
6
|
removeFileOrDirectory, emptyTrash, changeDirectory, showCwd,
|
|
8
7
|
getInfo, getDiskUsage, createFile, readFile, uploadFile,
|
|
9
|
-
downloadFile, copyFile, syncDirectory } from './files.js';
|
|
10
|
-
import { getUserInfo, getUsageInfo } from './auth.js';
|
|
8
|
+
downloadFile, copyFile, syncDirectory } from './commands/files.js';
|
|
9
|
+
import { getUserInfo, getUsageInfo } from './commands/auth.js';
|
|
11
10
|
import { PROJECT_NAME, API_BASE, getHeaders } from './commons.js';
|
|
12
11
|
import inquirer from 'inquirer';
|
|
13
12
|
import { exec } from 'node:child_process';
|
|
13
|
+
import { parseArgs } from './utils.js';
|
|
14
|
+
import { rl } from './commands/shell.js';
|
|
14
15
|
|
|
15
16
|
const config = new Conf({ projectName: PROJECT_NAME });
|
|
16
17
|
|
|
18
|
+
// History of commands
|
|
19
|
+
const commandHistory = [];
|
|
20
|
+
|
|
17
21
|
/**
|
|
18
22
|
* Update the prompt function
|
|
19
23
|
* @returns The current prompt
|
|
@@ -26,7 +30,7 @@ const commands = {
|
|
|
26
30
|
help: showHelp,
|
|
27
31
|
exit: () => process.exit(0),
|
|
28
32
|
logout: async () => {
|
|
29
|
-
await import('./auth.js').then(m => m.logout());
|
|
33
|
+
await import('./commands/auth.js').then(m => m.logout());
|
|
30
34
|
process.exit(0);
|
|
31
35
|
},
|
|
32
36
|
whoami: getUserInfo,
|
|
@@ -37,12 +41,48 @@ const commands = {
|
|
|
37
41
|
});
|
|
38
42
|
},
|
|
39
43
|
app: appInfo,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
history: async (args) => {
|
|
45
|
+
const lineNumber = parseInt(args[0]);
|
|
46
|
+
|
|
47
|
+
if (isNaN(lineNumber)) {
|
|
48
|
+
// Display full history
|
|
49
|
+
commandHistory.forEach((command, index) => {
|
|
50
|
+
console.log(chalk.cyan(`${index + 1}: ${command}`));
|
|
51
|
+
});
|
|
52
|
+
} else {
|
|
53
|
+
// Copy the command at the specified line number
|
|
54
|
+
if (lineNumber < 1 || lineNumber > commandHistory.length) {
|
|
55
|
+
console.error(chalk.red(`Invalid line number. History has ${commandHistory.length} entries.`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const commandToCopy = commandHistory[lineNumber - 1];
|
|
60
|
+
// Simulate typing the command in the shell
|
|
61
|
+
rl.write(commandToCopy);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
'app:create': async (rawArgs) => {
|
|
65
|
+
try {
|
|
66
|
+
const args = parseArgs(rawArgs.join(' '));
|
|
67
|
+
// Consider using explicit argument definition if necessary
|
|
68
|
+
// const args = parseArgs(rawArgs.join(' '), {string: ['description', 'url'],
|
|
69
|
+
// alias: { d: 'description', u: 'url', },
|
|
70
|
+
// });
|
|
71
|
+
|
|
72
|
+
if (!args.length < 1) {
|
|
73
|
+
console.log(chalk.red('Usage: app:create <name> [directory] [--description="My App Description"] [--url=app-url]'));
|
|
43
74
|
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await createApp({
|
|
78
|
+
name: args._[0],
|
|
79
|
+
directory: args._[1] || '',
|
|
80
|
+
description: args.description || '',
|
|
81
|
+
url: args.url || 'https://dev-center.puter.com/coming-soon.html'
|
|
82
|
+
});
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error(chalk.red(error.message));
|
|
44
85
|
}
|
|
45
|
-
await createApp(args);
|
|
46
86
|
},
|
|
47
87
|
'app:update': async (args) => {
|
|
48
88
|
if (args.length < 1) {
|
|
@@ -51,13 +91,20 @@ const commands = {
|
|
|
51
91
|
}
|
|
52
92
|
await updateApp(args);
|
|
53
93
|
},
|
|
54
|
-
'app:delete': async (
|
|
94
|
+
'app:delete': async (rawArgs) => {
|
|
95
|
+
const args = parseArgs(rawArgs.join(' '), {
|
|
96
|
+
string: ['_'],
|
|
97
|
+
boolean: ['f'],
|
|
98
|
+
configuration: {
|
|
99
|
+
'populate--': true
|
|
100
|
+
}
|
|
101
|
+
});
|
|
55
102
|
if (args.length < 1) {
|
|
56
103
|
console.log(chalk.red('Usage: app:delete <name>'));
|
|
57
104
|
return;
|
|
58
105
|
}
|
|
59
|
-
const name = args.
|
|
60
|
-
const force = args.
|
|
106
|
+
const name = args._[0];
|
|
107
|
+
const force = !!args.f;
|
|
61
108
|
|
|
62
109
|
if (!force){
|
|
63
110
|
const { confirm } = await inquirer.prompt([
|
|
@@ -96,7 +143,7 @@ const commands = {
|
|
|
96
143
|
sites: listSites,
|
|
97
144
|
site: infoSite,
|
|
98
145
|
'site:delete': deleteSite,
|
|
99
|
-
'site:create': createSite
|
|
146
|
+
'site:create': createSite,
|
|
100
147
|
};
|
|
101
148
|
|
|
102
149
|
/**
|
|
@@ -106,6 +153,12 @@ const commands = {
|
|
|
106
153
|
export async function execCommand(input) {
|
|
107
154
|
const [cmd, ...args] = input.split(' ');
|
|
108
155
|
|
|
156
|
+
|
|
157
|
+
// Add the command to history (skip the "history" command itself)
|
|
158
|
+
if (cmd !== 'history') {
|
|
159
|
+
commandHistory.push(input);
|
|
160
|
+
}
|
|
161
|
+
|
|
109
162
|
if (cmd === 'help') {
|
|
110
163
|
// Handle help command
|
|
111
164
|
const command = args[0];
|
|
@@ -144,6 +197,7 @@ export async function execCommand(input) {
|
|
|
144
197
|
* @param {string} [command] - The command to display help for.
|
|
145
198
|
*/
|
|
146
199
|
function showHelp(command) {
|
|
200
|
+
// Consider using `program.helpInformation()` function for global "help" command...
|
|
147
201
|
const commandHelp = {
|
|
148
202
|
help: `
|
|
149
203
|
${chalk.cyan('help [command]')}
|
|
@@ -187,9 +241,9 @@ function showHelp(command) {
|
|
|
187
241
|
Example: app myapp
|
|
188
242
|
`,
|
|
189
243
|
'app:create': `
|
|
190
|
-
${chalk.cyan('app:create <name> [<remote_dir>] [--url=<url>]')}
|
|
244
|
+
${chalk.cyan('app:create <name> [<remote_dir>] [--description="<description>"] [--url=<url>]')}
|
|
191
245
|
Create a new app.
|
|
192
|
-
Example: app:create myapp https://
|
|
246
|
+
Example: app:create myapp https://myapp.puter.site
|
|
193
247
|
`,
|
|
194
248
|
'app:update': `
|
|
195
249
|
${chalk.cyan('app:update <name> [dir]')}
|
|
@@ -288,6 +342,11 @@ function showHelp(command) {
|
|
|
288
342
|
Execute a command on the host machine.
|
|
289
343
|
Example: !ls -la
|
|
290
344
|
`,
|
|
345
|
+
'history [line]': `
|
|
346
|
+
${chalk.cyan('history [line]')}
|
|
347
|
+
Display history of commands or copy command by line number
|
|
348
|
+
Example: history 2
|
|
349
|
+
`,
|
|
291
350
|
};
|
|
292
351
|
|
|
293
352
|
if (command && commandHelp[command]) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import yargsParser from 'yargs-parser';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Convert "2024-10-07T15:03:53.000Z" to "10/7/2024, 15:03:53"
|
|
@@ -89,4 +90,14 @@ export function displayNonNullValues(data) {
|
|
|
89
90
|
});
|
|
90
91
|
console.log(chalk.cyan('-'.repeat(maxKeyLength*3)));
|
|
91
92
|
console.log(chalk.cyan(`You have ${chalk.green(tableData.length)} key/value pair(s).`));
|
|
92
|
-
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Parse command line arguments including quoted strings
|
|
97
|
+
* @param {string} input Raw command line input
|
|
98
|
+
* @returns {Object} Parsed arguments
|
|
99
|
+
*/
|
|
100
|
+
export function parseArgs(input, options = {}) {
|
|
101
|
+
const result = yargsParser(input, options);
|
|
102
|
+
return result;
|
|
103
|
+
}
|
package/tests/login.test.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { login, logout, getUserInfo, isAuthenticated, getAuthToken, getCurrentUserName,
|
|
3
|
-
getCurrentDirectory, getUsageInfo } from '
|
|
3
|
+
getCurrentDirectory, getUsageInfo } from '../src/commands/auth.js';
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import ora from 'ora';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import fetch from 'node-fetch';
|
|
8
8
|
import Conf from 'conf';
|
|
9
|
-
import { BASE_URL } from '../
|
|
9
|
+
import { BASE_URL } from '../src/commons.js';
|
|
10
10
|
|
|
11
11
|
// Mock console to prevent actual logging
|
|
12
12
|
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
File without changes
|