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
31 changes: 31 additions & 0 deletions .cursor/rules/git-commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Git Commands

Always use `--no-abbrev-commit` and proper formatting flags for all git terminal commands to avoid shell parsing issues.

## Specific Commands to Use:

**Instead of:**
```bash
git log --oneline
git show --stat HEAD
git branch -v
```

**Use:**
```bash
git log --pretty=format:"%h %s" --no-abbrev-commit
git show --stat --no-abbrev-commit HEAD
git branch --show-current
```

## Key Flags:
- `--no-abbrev-commit` - Prevents abbreviated commit hashes
- `--pretty=format:"..."` - Use explicit formatting
- `--porcelain` - For cleaner output when available
- `--no-color` - Remove ANSI color codes
- `--show-current` - For branch operations

## Common Patterns:
- `git log master..HEAD` β†’ `git log --pretty=format:"%h %s" --no-abbrev-commit master..HEAD`
- `git status` β†’ `git status --porcelain`
- `git diff --name-only master` β†’ `git diff --name-only master`
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"crates/plugin-ls",
"crates/plugin-cat",
"crates/plugin-weather",
"crates/plugin-tee",
"crates/repl-logic-guest",
]

Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pluginlab\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_echo.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_weather.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_cat.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_tee.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin-echo-c.wasm\
--allow-all
```
Expand All @@ -106,6 +107,7 @@ pluginlab\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_echo.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_weather.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_cat.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_tee.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin-echo-c.wasm\
--allow-all
[Host] Starting REPL host...
Expand All @@ -115,6 +117,8 @@ pluginlab\
[Host] Loading plugin: https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_echo.wasm
[Host] Loading plugin: https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_weather.wasm
[Host] Loading plugin: https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_cat.wasm
[Host] Loading plugin: https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_tee.wasm
[Host] Loading plugin: https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin-echo-c.wasm
repl(0)> echo foo
foo
repl(0)> echo $ROOT/$USER
Expand Down Expand Up @@ -220,6 +224,7 @@ This will (see [justfile](./justfile)):
--plugins ./target/wasm32-wasip1/debug/plugin_echo.wasm\
--plugins ./target/wasm32-wasip1/debug/plugin_weather.wasm\
--plugins ./target/wasm32-wasip1/debug/plugin_cat.wasm\
--plugins ./target/wasm32-wasip1/debug/plugin_tee.wasm\
--plugins ./c_modules/plugin-echo/plugin-echo-c.wasm\
--allow-all
```
Expand Down Expand Up @@ -378,13 +383,14 @@ When a git tag is pushed, a pre-release is prepared on github, linked to the tag

```sh
pluginlab\
--repl-logic https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/repl_logic_guest.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_greet.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_ls.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_echo.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_weather.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_cat.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin-echo-c.wasm\
--repl-logic https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/repl_logic_guest.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_greet.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_ls.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_echo.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_weather.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_cat.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_tee.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin-echo-c.wasm\
--allow-all
```

Expand Down
1 change: 1 addition & 0 deletions crates/plugin-tee/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/bindings.rs
18 changes: 18 additions & 0 deletions crates/plugin-tee/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "plugin-tee"
version = "0.1.0"
edition = { workspace = true }
publish = false
description = "Example tee plugin for REPL based on WebAssembly Component Model - demonstrates file system access and modification"

[dependencies]
wit-bindgen-rt = { workspace = true, features = ["bitflags"] }

[lib]
crate-type = ["cdylib"]

[package.metadata.component]
package = "repl:api"
target = { path = "../pluginlab/wit", world = "plugin-api" }

[package.metadata.component.dependencies]
14 changes: 14 additions & 0 deletions crates/plugin-tee/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# plugin-tee

Basic plugin for this REPL. Behaves like the `tee` command.

## Notes

This crate was initialized with `cargo component new`.

The building process is handled by the [`justfile`](../../justfile) in the root of the project.

The `cargo component build` command is used to build the plugin.

- It generates the `src/bindings.rs` file, based on the `package.metadata.component` section in the `Cargo.toml` file that describes where to find the component definition (wit files).
- It then compiles the plugin to WebAssembly.
99 changes: 99 additions & 0 deletions crates/plugin-tee/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#[allow(warnings)]
mod bindings;

use std::io::Write;

use crate::bindings::exports::repl::api::plugin::Guest;
use crate::bindings::repl::api::host_state_plugin;
use crate::bindings::repl::api::transport;

struct Component;

impl Guest for Component {
fn name() -> String {
"tee".to_string()
}

fn man() -> String {
r#"
NAME
tee - Copy $0 content to a file (built with RustπŸ¦€)

USAGE
tee <file>
tee -a <file>

OPTIONS
-a, --append Append to the file instead of overwriting it

DESCRIPTION
Copy $0 content to a file.

"#
.to_string()
}

fn run(payload: String) -> Result<transport::PluginResponse, ()> {
match run_inner(payload) {
Ok(content) => Ok(transport::PluginResponse {
status: transport::ReplStatus::Success,
stdout: Some(format!("{}", content)),
stderr: None,
}),
Err(e) => {
// e.kind() - verify if the error is a permission error
return Ok(transport::PluginResponse {
status: transport::ReplStatus::Error,
stdout: None,
stderr: Some(format!("{}", e)),
});
}
}
}
}

fn run_inner(payload: String) -> Result<String, String> {
let is_append = payload.starts_with("-a") || payload.starts_with("--append");
let filepath = if is_append {
let Some((_, filepath)) = payload.split_once(" ") else {
return Err("Invalid arguments. Usage: tee <file> or tee -a <file>".to_string());
};
filepath.to_string()
} else {
payload
};

let content = host_state_plugin::get_repl_var("0").unwrap_or("".to_string());
let content_as_bytes = content.as_bytes();

if !is_append {
let mut file = std::fs::File::create(&filepath)
.map_err(|e| enhanced_error(e, format!("Failed to create file '{}'", filepath)))?;
file.write_all(content_as_bytes)
.map_err(|e| enhanced_error(e, format!("Failed to write to file '{}'", filepath)))?;
return Ok(content);
} else {
let mut file = std::fs::File::options()
.append(true)
.open(&filepath)
.map_err(|e| {
enhanced_error(
e,
format!("Failed to open file in append mode '{}'", filepath),
)
})?;
// Add a newline before the content in append mode
file.write_all(b"\n").map_err(|e| {
enhanced_error(e, format!("Failed to write newline to file '{}'", filepath))
})?;
file.write_all(content_as_bytes)
.map_err(|e| enhanced_error(e, format!("Failed to write to file '{}'", filepath)))?;
return Ok(content);
}
}

fn enhanced_error(e: std::io::Error, more_info: String) -> String {
format!("{} - {} - {}", e.kind(), more_info, e.to_string())
}

bindings::export!(Component with_types_in bindings);
19 changes: 11 additions & 8 deletions crates/pluginlab/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pluginlab\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_echo.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_weather.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_cat.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_tee.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin-echo-c.wasm\
--allow-all
```
Expand All @@ -85,6 +86,7 @@ pluginlab\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_echo.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_weather.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_cat.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin_tee.wasm\
--plugins https://topheman.github.io/webassembly-component-model-experiments/plugins/plugin-echo-c.wasm\
--allow-all
[Host] Starting REPL host...
Expand Down Expand Up @@ -133,13 +135,14 @@ The plugins are also versioned in [github releases](https://github.com/topheman/
<summary>Example of running the CLI host with old versions of the plugins (if you have an old version of <code>pluginlab</code></summary>
<pre>
pluginlab\
--repl-logic https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/repl_logic_guest.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_greet.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_ls.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_echo.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_weather.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_cat.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin-echo-c.wasm\
--repl-logic https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/repl_logic_guest.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_greet.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_ls.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_echo.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_weather.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_cat.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_tee.wasm\
--plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin-echo-c.wasm\
--allow-all
</pre>
</summary>
Expand All @@ -163,7 +166,7 @@ pluginlab\
[Host] You are most likely trying to use a plugin not compatible with pluginlab@0.4.1
[Host]
[Host] Try using a compatible version of the plugin by passing the following flag:
[Host] --plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.4.1/plugin_echo.wasm
[Host] --plugins https://github.com/topheman/webassembly-component-model-experiments/releases/download/pluginlab@0.5.0/plugin_echo.wasm
[Host]
[Host] If it doesn't work, make sure to use the latest version of pluginlab: `cargo install pluginlab`
[Host]
Expand Down
8 changes: 6 additions & 2 deletions crates/pluginlab/src/engine.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::cli::Cli;
use crate::permissions::NetworkPermissions;
use anyhow::Result;
use std::collections::HashMap;

use std::path::Path;
use wasmtime::component::{Component, Linker as ComponentLinker, ResourceTable};
use wasmtime::{Config, Engine, Store};
Expand Down Expand Up @@ -120,15 +120,19 @@ impl WasmEngine {

/// Create a new store with WASI context
pub fn create_store(&self, wasi_ctx: WasiCtx, cli: &Cli) -> Store<WasiState> {
let repl_vars =
std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));

Store::new(
&self.engine,
WasiState {
ctx: wasi_ctx,
table: ResourceTable::new(),
plugin_host: PluginHost {
network_permissions: NetworkPermissions::from(cli),
repl_vars: repl_vars.clone(),
},
repl_vars: HashMap::new(),
repl_vars,
plugins_names: Vec::new(),
},
)
Expand Down
18 changes: 14 additions & 4 deletions crates/pluginlab/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

/// Handles setting exit status codes in REPL variables
pub struct StatusHandler;

impl StatusHandler {
/// Set the exit status in the REPL variables
pub fn set_exit_status(repl_vars: &mut HashMap<String, String>, success: bool) {
pub fn set_exit_status(repl_vars: &mut Arc<Mutex<HashMap<String, String>>>, success: bool) {
let status = if success { "0" } else { "1" };
repl_vars.insert("?".to_string(), status.to_string());
repl_vars
.lock()
.expect("Failed to acquire repl_vars lock")
.insert("?".to_string(), status.to_string());
}
}

pub struct StdoutHandler;

impl StdoutHandler {
pub fn print_and_set_last_result(repl_vars: &mut HashMap<String, String>, result: String) {
pub fn print_and_set_last_result(
repl_vars: &mut Arc<Mutex<HashMap<String, String>>>,
result: String,
) {
println!("{}", result);
repl_vars.insert("0".to_string(), result);
repl_vars
.lock()
.expect("Failed to acquire repl_vars lock")
.insert("0".to_string(), result);
}
}

Expand Down
Loading
Loading