Skip to content

Commit b340cf2

Browse files
committed
dev: add last-error command, context, and modules
This change first adds a concept of a "context" which is passed to the command executor, and "modules" which can act on this context at initialization. We initialize this context with an event emitter so that all modules can listen for or emit events. Since commands have their cli arguments passed as a single argument to the command function, this makes it possible to also pass the context object to commands as a second argument. This was used to enable two things: - sites command (as an example) emits an event on error - ErrorModule holds onto ERROR_BUFFER_LIMIT errors - `last-error` command (new) asks ErrorModule for errors The new command `last-error` references ErrorAPI directly which isn't ideal; instead modules should be able to provide commands, but this requires a refactor in how commands are loaded.
1 parent ecf3bb9 commit b340cf2

File tree

6 files changed

+58
-6
lines changed

6 files changed

+58
-6
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"author": "Ibrahim.H",
2727
"license": "MIT",
2828
"dependencies": {
29+
"@heyputer/putility": "^1.0.2",
2930
"chalk": "^5.3.0",
3031
"cli-table3": "^0.6.5",
3132
"commander": "^13.0.0",

src/commands/shell.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Conf from 'conf';
44
import { execCommand, getPrompt } from '../executor.js';
55
import { getAuthToken, login } from './auth.js';
66
import { PROJECT_NAME } from '../commons.js';
7+
import ErrorModule from '../modules/ErrorModule.js';
8+
import putility, { AdvancedBase } from '@heyputer/putility';
79

810
const config = new Conf({ projectName: PROJECT_NAME });
911

@@ -32,6 +34,16 @@ export async function startShell() {
3234
process.exit(0);
3335
}
3436

37+
const modules = [
38+
ErrorModule,
39+
];
40+
41+
const context = new putility.libs.context.Context({
42+
events: new putility.libs.event.Emitter(),
43+
});
44+
45+
for ( const module of modules ) module({ context });
46+
3547
try {
3648
console.log(chalk.green('Welcome to Puter-CLI! Type "help" for available commands.'));
3749
rl.setPrompt(getPrompt());
@@ -41,7 +53,7 @@ export async function startShell() {
4153
const trimmedLine = line.trim();
4254
if (trimmedLine) {
4355
try {
44-
await execCommand(trimmedLine);
56+
await execCommand(context, trimmedLine);
4557
} catch (error) {
4658
console.error(chalk.red(error.message));
4759
}

src/commands/sites.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import { getCurrentUserName, getCurrentDirectory } from './auth.js';
55
import { API_BASE, getHeaders, generateAppName, resolvePath, isValidAppName } from '../commons.js';
66
import { displayNonNullValues, formatDate, isValidAppUuid } from '../utils.js';
77
import { getSubdomains, createSubdomain, deleteSubdomain } from './subdomains.js';
8+
import { ErrorAPI } from '../modules/ErrorModule.js';
89

910

1011
/**
1112
* Listing subdomains
1213
*/
13-
export async function listSites(args = {}) {
14+
export async function listSites(args = {}, context) {
1415
try {
1516
const data = await getSubdomains(args);
1617

@@ -57,6 +58,7 @@ export async function listSites(args = {}) {
5758
}
5859

5960
} catch (error) {
61+
context.events.emit('error', { error });
6062
console.error(chalk.red('Error listing sites:'), error.message);
6163
throw error;
6264
}

src/commons.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { fileURLToPath } from 'url';
66
import { dirname, join } from 'path';
77

88
export const PROJECT_NAME = 'puter-cli';
9-
export const API_BASE = 'https://api.puter.com';
10-
export const BASE_URL = 'https://puter.com';
9+
export const API_BASE = 'http://api.puter.localhost:4100';
10+
export const BASE_URL = 'http://puter.localhost:4100';
1111

1212
/**
1313
* Get headers with the correct Content-Type for multipart form data.

src/executor.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import inquirer from 'inquirer';
1212
import { exec } from 'node:child_process';
1313
import { parseArgs } from './utils.js';
1414
import { rl } from './commands/shell.js';
15+
import { ErrorAPI } from './modules/ErrorModule.js';
1516

1617
const config = new Conf({ projectName: PROJECT_NAME });
1718

@@ -61,6 +62,9 @@ const commands = {
6162
rl.write(commandToCopy);
6263
}
6364
},
65+
'last-error': async (_, context) => {
66+
context[ErrorAPI].showLast();
67+
},
6468
'app:create': async (rawArgs) => {
6569
try {
6670
const args = parseArgs(rawArgs.join(' '));
@@ -150,7 +154,7 @@ const commands = {
150154
* Execute a command
151155
* @param {string} input The command line input
152156
*/
153-
export async function execCommand(input) {
157+
export async function execCommand(context, input) {
154158
const [cmd, ...args] = input.split(' ');
155159

156160

@@ -184,7 +188,7 @@ export async function execCommand(input) {
184188
}
185189
if (commands[cmd]) {
186190
try {
187-
await commands[cmd](args);
191+
await commands[cmd](args, context);
188192
} catch (error) {
189193
console.error(chalk.red(`Error executing command: ${error.message}`));
190194
}

src/modules/ErrorModule.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const ERROR_BUFFER_LIMIT = 20;
2+
3+
export const ErrorAPI = Symbol('ErrorAPI');
4+
5+
export default ({ context }) => {
6+
// State Variables
7+
const errors = [];
8+
9+
context.events.on('error', (error) => {
10+
context[ErrorAPI].report(error);
11+
});
12+
13+
// Module Methods
14+
context[ErrorAPI] = {
15+
// Add an error to the error history
16+
report (error) {
17+
errors.push(error);
18+
if (errors.length > ERROR_BUFFER_LIMIT) {
19+
errors = errors.slice(errors.length - ERROR_BUFFER_LIMIT);
20+
}
21+
},
22+
// Print the last error from the error history,
23+
// and remove it from the history
24+
showLast () {
25+
const err = errors.pop();
26+
if (err) {
27+
console.error(err);
28+
} else {
29+
console.log('No errors to report');
30+
}
31+
}
32+
};
33+
};

0 commit comments

Comments
 (0)