Skip to content

Commit 2658830

Browse files
Release v0.5.0: compilation cache, --bench, --watch, config files, CI
Major features: - Compilation cache for Rust, C, C++, Go, Java, Kotlin, Zig (skip recompilation on repeated runs) - --bench N flag and :bench REPL command for execution benchmarking with statistics - --watch / -w flag for automatic file re-execution on save - :type / :which REPL command to show active language and session state - Project config files (run.toml / .runrc) for default language, timeout, timing - Per-language package installation (run install <pkg>) - Tab completion for REPL meta-commands and language names - Session variable _ stores last evaluation result - GitHub Actions CI pipeline (fmt, clippy, test on Linux/macOS/Windows) Improvements: - REPL startup banner, help, and error output redesigned - Duration display uses human-readable format (1m 3s, 12.34s, 56ms) - Improved multi-line input for Python blocks - Professional codebase tone throughout Tests: - 13 new tests covering cache, bench, watch, and config Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent add734c commit 2658830

39 files changed

+3596
-226
lines changed

.github/workflows/ci.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
check:
14+
name: Check & Lint
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: dtolnay/rust-toolchain@stable
19+
with:
20+
components: clippy, rustfmt
21+
- name: cargo fmt
22+
run: cargo fmt --all -- --check
23+
- name: cargo clippy
24+
run: cargo clippy --all-targets -- -D warnings
25+
- name: cargo check
26+
run: cargo check --all-targets
27+
28+
test:
29+
name: Test (${{ matrix.os }})
30+
runs-on: ${{ matrix.os }}
31+
strategy:
32+
matrix:
33+
os: [ubuntu-latest, macos-latest, windows-latest]
34+
steps:
35+
- uses: actions/checkout@v4
36+
- uses: dtolnay/rust-toolchain@stable
37+
38+
- name: Install language toolchains (Ubuntu)
39+
if: runner.os == 'Linux'
40+
run: |
41+
sudo apt-get update
42+
sudo apt-get install -y python3 nodejs golang-go
43+
44+
- name: cargo test
45+
run: cargo test --lib --tests
46+
timeout-minutes: 15
47+
48+
build:
49+
name: Build release
50+
runs-on: ubuntu-latest
51+
needs: [check, test]
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: dtolnay/rust-toolchain@stable
55+
- name: cargo build --release
56+
run: cargo build --release
57+
- name: Binary size
58+
run: ls -lh target/release/run

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ registry-server/target/
2929
# Logs
3030
*.log
3131

32+
# Local sandbox
33+
.run-lab/
34+
3235
# Exclude incomplete/redundant directories
3336
/runtime/
34-
/examples/swap-demo/
37+
/examples/swap-demo/

CHANGELOG.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,35 @@ All notable changes to this project will be documented in this file. The format
66

77
Nothing yet.
88

9+
## [0.5.0] - 2026-02-06
10+
11+
### Added
12+
13+
- **Compilation cache** for compiled languages (Rust, C, C++, Go, Java, Kotlin, Zig). Repeated runs of the same source skip recompilation, dramatically improving execution speed.
14+
- **`--bench N`** CLI flag to benchmark code execution with statistical output (min, max, avg, median, stddev).
15+
- **`--watch` / `-w`** flag for file watching — automatically re-executes on save.
16+
- **`:bench [N] <code>`** REPL command for in-session benchmarking.
17+
- **`:type` / `:which`** REPL command to display the active language and session state.
18+
- **`run install <package>`** per-language package installation (pip, npm, cargo, etc.).
19+
- **Project config files** (`run.toml` / `.runrc`) for default language, timeout, and timing settings.
20+
- **GitHub Actions CI** pipeline with check, test, and build jobs across Linux, macOS, and Windows.
21+
22+
### Changed
23+
24+
- REPL startup banner redesigned with cleaner styling and language count.
25+
- REPL error output now displayed in red for visibility.
26+
- Duration display uses human-readable format (e.g., "1m 3s", "12.34s", "56ms").
27+
- Improved multi-line input handling for Python blocks (def, class, if, for, while, try, with).
28+
- Tab completion for REPL meta-commands and language names.
29+
- Session variable `_` stores the last evaluation result.
30+
- Help output reformatted with categorized commands and descriptions.
31+
- Removed informal comments; professional codebase tone throughout.
32+
33+
### Fixed
34+
35+
- Python dict literals with `:` no longer falsely trigger multi-line block mode.
36+
- Compilation errors in Rust/C/C++ inline snippets now display properly in the REPL.
37+
938
## [0.4.0] - 2026-02-05
1039

1140
### Added
@@ -94,7 +123,8 @@ Nothing yet.
94123
- `-c/--code` and `-f/--file` flags are accepted immediately after the language selector without consuming snippet text.
95124
- Added regression coverage ensuring `run python -c` continues to consume piped input in future releases.
96125

97-
[Unreleased]: https://github.com/esubaalew/run/compare/v0.4.0...HEAD
126+
[Unreleased]: https://github.com/esubaalew/run/compare/v0.5.0...HEAD
127+
[0.5.0]: https://github.com/esubaalew/run/compare/v0.4.0...v0.5.0
98128
[0.4.0]: https://github.com/esubaalew/run/compare/v0.3.2...v0.4.0
99129
[0.3.2]: https://github.com/esubaalew/run/compare/v0.3.1...v0.3.2
100130
[0.3.1]: https://github.com/esubaalew/run/compare/v0.3.0...v0.3.1

Cargo.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "run-kit"
3-
version = "0.4.1"
3+
version = "0.5.0"
44
edition = "2024"
55
description = "Universal multi-language runner and smart REPL"
66
license = "Apache-2.0"
@@ -67,6 +67,8 @@ futures = { version = "0.3", optional = true }
6767
reqwest = { version = "0.12", features = ["json", "multipart"], optional = true }
6868
urlencoding = "2.1"
6969
cap-std = "3.4"
70+
indexmap = "2.13.0"
71+
wit-parser = { version = "0.217.1", features = ["decoding"] }
7072

7173
# WASI 0.2 Component Runtime (wasmtime)
7274
wasmtime = { version = "25.0", features = ["component-model", "cranelift", "async"], optional = true }
@@ -82,6 +84,7 @@ assert_cmd = "2.0"
8284
predicates = "3.1"
8385
criterion = "0.5"
8486
futures = "0.3"
87+
wat = "1.244.0"
8588

8689
[[bench]]
8790
name = "run_v2"

registry-server/src/main.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ struct VersionInfo {
424424
async fn fetch_all_packages_with_info(db: &SqlitePool) -> Result<Vec<PackageInfo>, sqlx::Error> {
425425
let rows = sqlx::query(
426426
r#"SELECT p.name,
427-
(SELECT version FROM versions WHERE package_id = p.id ORDER BY published_at DESC LIMIT 1) as latest_version,
427+
COALESCE((SELECT version FROM versions WHERE package_id = p.id ORDER BY published_at DESC LIMIT 1), '') as latest_version,
428428
p.description,
429429
COALESCE((SELECT SUM(downloads) FROM versions WHERE package_id = p.id), 0) as total_downloads
430430
FROM packages p
@@ -433,13 +433,20 @@ async fn fetch_all_packages_with_info(db: &SqlitePool) -> Result<Vec<PackageInfo
433433
.fetch_all(db)
434434
.await?;
435435

436-
Ok(rows.iter().filter_map(|row| {
437-
Some(PackageInfo {
438-
name: row.try_get("name").ok()?,
439-
latest_version: row.try_get("latest_version").ok()?,
436+
Ok(rows.iter().map(|row| {
437+
let latest_version: String = row.try_get("latest_version").unwrap_or_default();
438+
let latest_version = if latest_version.is_empty() {
439+
"N/A".to_string()
440+
} else {
441+
latest_version
442+
};
443+
444+
PackageInfo {
445+
name: row.try_get("name").unwrap_or_default(),
446+
latest_version,
440447
description: row.try_get("description").unwrap_or_default(),
441448
downloads: row.try_get("total_downloads").unwrap_or(0),
442-
})
449+
}
443450
}).collect())
444451
}
445452

@@ -561,41 +568,43 @@ async fn publish_package(
561568
let mut targets: Option<Vec<String>> = None;
562569
let mut expected_sha256: Option<String> = None;
563570

564-
while let Some(field) = multipart.next_field().await.unwrap() {
571+
while let Ok(Some(field)) = multipart.next_field().await {
565572
let field_name = field.name().unwrap_or("").to_string();
566573

567574
match field_name.as_str() {
568575
"name" => {
569-
name = Some(field.text().await.unwrap());
576+
name = field.text().await.ok();
570577
}
571578
"version" => {
572-
version = Some(field.text().await.unwrap());
579+
version = field.text().await.ok();
573580
}
574581
"description" => {
575-
description = field.text().await.unwrap();
582+
description = field.text().await.unwrap_or_default();
576583
}
577584
"license" => {
578-
license = Some(field.text().await.unwrap());
585+
license = field.text().await.ok();
579586
}
580587
"repository" => {
581-
repository = Some(field.text().await.unwrap());
588+
repository = field.text().await.ok();
582589
}
583590
"wit_url" => {
584-
wit_url = Some(field.text().await.unwrap());
591+
wit_url = field.text().await.ok();
585592
}
586593
"dependencies" => {
587-
let raw = field.text().await.unwrap();
588-
dependencies = serde_json::from_str(&raw).ok();
594+
if let Ok(raw) = field.text().await {
595+
dependencies = serde_json::from_str(&raw).ok();
596+
}
589597
}
590598
"targets" => {
591-
let raw = field.text().await.unwrap();
592-
targets = serde_json::from_str(&raw).ok();
599+
if let Ok(raw) = field.text().await {
600+
targets = serde_json::from_str(&raw).ok();
601+
}
593602
}
594603
"sha256" => {
595-
expected_sha256 = Some(field.text().await.unwrap());
604+
expected_sha256 = field.text().await.ok();
596605
}
597606
"component" | "artifact" => {
598-
artifact_data = Some(field.bytes().await.unwrap().to_vec());
607+
artifact_data = field.bytes().await.ok().map(|b| b.to_vec());
599608
}
600609
_ => {}
601610
}

0 commit comments

Comments
 (0)