Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/bash-types/src/bash.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CommandHandler, CustomCommand } from "./command";
import type { BaseRuntime } from "./runtime";

export interface BashOptions {
Expand All @@ -6,6 +7,11 @@ export interface BashOptions {
*/
runtime: BaseRuntime;

/**
* Array with custom commands added at runtime
*/
customCommands?: CustomCommand[];

/**
* The host workspace directory
*/
Expand Down
36 changes: 26 additions & 10 deletions packages/bash-types/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,26 @@ import { State } from "./state";
/**
* The context of a command execution
*/
export type CommandContext = {
export interface CommandContext {
opts: CommandOptions;
stdin: string;
state: State;
runtime: BaseRuntime;
};

/**
* The handler of a command execution
*/
export type CommandHandler = (ctx: CommandContext) => Promise<CommandResult>;

/**
* The result of a command execution
*/
export type CommandResult = {
export interface CommandResult {
stdout: string;
stderr: string;
exitCode: number;
};


/**
* The options of a command execution
*/
export type CommandOptions = {
export interface CommandOptions {
raw: string[];
flags: Set<string>;
options: Map<string, string>;
Expand All @@ -40,10 +34,32 @@ export type CommandOptions = {
/**
* The manual of a command
*/
export type CommandManual = {
export interface CommandManual {
name: string;
description: string;
usage: string;
options?: Record<string, string>;
};

/**
* The custom command creation result
*/
export interface CustomCommand {
name: string;
handler: CommandHandler;
manual?: CommandManual;
}

/**
* The handler of a command execution
*/
export type CommandHandler = (ctx: CommandContext) => Promise<CommandResult>;


/**
* The builder to create a custom command
*/
export type CreateCustomCommand = (name: string, handler: CommandHandler, manual?: CommandManual) => CustomCommand;



2 changes: 1 addition & 1 deletion packages/bash-types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { State } from "./state";
export { BaseRuntime, RuntimeResult } from "./runtime";
export { BashOptions } from "./bash";
export { CommandResult, CommandHandler, CommandContext, CommandOptions, CommandManual } from "./command";
export { CommandResult, CommandHandler, CommandContext, CommandOptions, CommandManual, CustomCommand, CreateCustomCommand } from "./command";
9 changes: 6 additions & 3 deletions packages/bash/src/core/bash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BaseRuntime, BashOptions, CommandResult } from "@capsule-run/bash-types";
import type { BaseRuntime, BashOptions, CommandHandler, CommandResult, CustomCommand } from "@capsule-run/bash-types";
import { StateManager } from "./stateManager";
import { Filesystem } from "./filesystem";
import { Parser } from "./parser";
Expand All @@ -9,16 +9,19 @@ export class Bash {
private filesystem: Filesystem;
private parser: Parser;
private executor: Executor;
private customCommands: CustomCommand[];

public readonly stateManager: StateManager;

constructor({ runtime, hostWorkspace = ".capsule/session/workspace", initialCwd = "workspace" }: BashOptions) {
constructor({ runtime, customCommands = [], hostWorkspace = ".capsule/session/workspace", initialCwd = "workspace" }: BashOptions) {
this.runtime = runtime;
this.runtime.hostWorkspace = hostWorkspace;
this.customCommands = customCommands;

this.stateManager = new StateManager(runtime, initialCwd);
this.filesystem = new Filesystem(hostWorkspace);
this.parser = new Parser();
this.executor = new Executor(runtime, this.stateManager.state);
this.executor = new Executor(runtime, this.customCommands, this.stateManager.state);

this.filesystem.init();
}
Expand Down
8 changes: 7 additions & 1 deletion packages/bash/src/core/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import path from 'path';
import { parsedCommandOptions } from '../helpers/commandOptions';
import { displayCommandManual } from '../helpers/commandManual';

import type { BaseRuntime, CommandHandler, CommandManual, CommandResult, State } from '@capsule-run/bash-types';
import type { BaseRuntime, CommandHandler, CommandManual, CommandResult, CustomCommand, State } from '@capsule-run/bash-types';
import type { ASTNode, CommandNode } from './parser';


export class Executor {

constructor(
private readonly runtime: BaseRuntime,
private readonly customCommands: CustomCommand[],
private readonly state: State,
) {}

Expand Down Expand Up @@ -138,6 +139,11 @@ export class Executor {
const commandsDir = path.resolve(__dirname, '../commands');
const handlerPath = path.join(commandsDir, name, 'handler');

const customCommand = this.customCommands.find(cmd => cmd.name === name);
if (customCommand) {
return { handler: customCommand.handler, manual: customCommand.manual };
}

try {
const mod = require(handlerPath);
return { handler: mod.handler as CommandHandler, manual: mod.manual as CommandManual };
Expand Down
1 change: 1 addition & 0 deletions packages/bash/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Bash } from "./core/bash";
export { createCommand } from "./utilities/createCommand";
5 changes: 5 additions & 0 deletions packages/bash/src/utilities/createCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CreateCustomCommand } from "@capsule-run/bash-types";

export const createCommand: CreateCustomCommand = (name, handler, manual) => {
return { name, handler, manual };
}
Loading