Skip to content
Closed
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
23 changes: 23 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Force LF line endings everywhere — no platform-specific CRLF nonsense.
# This ensures consistent diffs across Linux, macOS, and Windows.
* text=auto eol=lf

# Explicitly mark binary files so git doesn't try to normalize them
*.node binary
*.wasm binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pptx binary
*.xlsx binary
*.docx binary
*.zip binary
*.tar binary
*.gz binary
*.tgz binary
*.exe binary
*.dll binary
*.so binary
*.dylib binary
17 changes: 12 additions & 5 deletions .github/workflows/pr-validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,8 @@ jobs:
run: just test-all

# Build and test on all hypervisor configurations (1ES runners have Rust + just)
# NOTE: Windows WHP support is temporarily disabled pending upstream
# hyperlight fix for multiple SurrogateProcessManager instances.
# See: https://github.com/hyperlight-dev/hyperagent/issues/1
build-and-test:
name: Build & Test (${{ matrix.hypervisor }}-${{ matrix.config }})
name: Build & Test (${{ matrix.build }})
needs: [docs-pr]
if: needs.docs-pr.outputs.docs-only != 'true'
strategy:
Expand All @@ -98,6 +95,8 @@ jobs:
- linux-kvm-release
- linux-mshv-debug
- linux-mshv-release
- windows-whp-debug
- windows-whp-release
include:
- build: linux-kvm-debug
os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
Expand All @@ -115,6 +114,14 @@ jobs:
os: [self-hosted, Linux, X64, "1ES.Pool=hld-azlinux3-mshv-amd"]
hypervisor: mshv
config: release
- build: windows-whp-debug
os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"]
hypervisor: whp
config: debug
- build: windows-whp-release
os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"]
hypervisor: whp
config: release
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
Expand Down Expand Up @@ -142,7 +149,7 @@ jobs:
if: matrix.config == 'release'
uses: actions/upload-artifact@v7
with:
name: hyperagent-linux-x64-${{ matrix.hypervisor }}
name: hyperagent-${{ matrix.build }}
path: dist/
retention-days: 7

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
# Test on all hypervisor configurations before publishing
# NOTE: Windows WHP temporarily disabled (see pr-validate.yml)
test:
name: Test (${{ matrix.hypervisor }})
name: Test (${{ matrix.build }})
strategy:
fail-fast: true
matrix:
Expand Down
24 changes: 21 additions & 3 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ runtime-dir := justfile_dir() / "src" / "sandbox" / "runtime"
# -D__wasi__=1 to disable pthreads. Uses cargo metadata to find the
# include/ dir from the hyperlight-js-runtime dependency.
# Fails loudly if resolution fails — empty CFLAGS causes cryptic build errors.
runtime-cflags := `node -e "var m=JSON.parse(require('child_process').execSync('cargo +1.89 metadata --format-version 1 --manifest-path src/sandbox/runtime/Cargo.toml',{encoding:'utf8',stdio:['pipe','pipe','inherit'],maxBuffer:20*1024*1024}));var p=m.packages.find(function(p){return p.name==='hyperlight-js-runtime'});if(!p){process.stderr.write('ERROR: hyperlight-js-runtime not found in cargo metadata\n');process.exit(1)}console.log('-I'+require('path').join(require('path').dirname(p.manifest_path),'include')+' -D__wasi__=1')"`
runtime-cflags := `node -e "var m=JSON.parse(require('child_process').execSync('cargo +1.89 metadata --format-version 1 --manifest-path src/sandbox/runtime/Cargo.toml',{encoding:'utf8',stdio:['pipe','pipe','inherit'],maxBuffer:20*1024*1024}));var p=m.packages.find(function(p){return p.name==='hyperlight-js-runtime'});if(!p){process.stderr.write('ERROR: hyperlight-js-runtime not found in cargo metadata\n');process.exit(1)}var inc=require('path').join(require('path').dirname(p.manifest_path),'include').split(require('path').sep).join('/');console.log('-I'+inc+' -D__wasi__=1')"`

# Export HYPERLIGHT_CFLAGS so cargo-hyperlight picks them up when building runtimes
export HYPERLIGHT_CFLAGS := runtime-cflags
Expand Down Expand Up @@ -71,6 +71,12 @@ resolve-hyperlight-dir:
fi
echo "$dir"

# Resolve hyperlight-js workspace root (Windows variant).
[private]
[windows]
resolve-hyperlight-dir:
node -e "var m=JSON.parse(require('child_process').execSync('cargo +1.89 metadata --format-version 1 --manifest-path src/sandbox/runtime/Cargo.toml',{encoding:'utf8',stdio:['pipe','pipe','pipe'],maxBuffer:20*1024*1024}));var p=m.packages.find(function(p){return p.name==='hyperlight-js-runtime'});if(p)console.log(require('path').resolve(require('path').dirname(p.manifest_path),'..','..'));else{process.stderr.write('hyperlight-js-runtime not found');process.exit(1)}"

# Install required Rust toolchains and cargo subcommands.
# Cross-platform (Linux/macOS/Windows) — no bash required.
[private]
Expand All @@ -84,8 +90,7 @@ ensure-tools:
# 2. Discovers the hyperlight-js workspace from Cargo's checkout
# 3. Builds the NAPI addon with our custom runtime embedded
# 4. Symlinks deps/js-host-api → checkout/src/js-host-api for npm file: dep
# NOTE: [unix] only — Windows support is disabled pending upstream fix (issue #1).
# When Windows lands, add [windows] variants using mklink /J for junctions.
# NOTE: [unix] only — add [windows] variant below for Windows WHP support.
[private]
[unix]
build-hyperlight target="debug": (build-runtime-release)
Expand All @@ -101,6 +106,13 @@ build-hyperlight target="debug": (build-runtime-release)
ln -sfn "${hl_dir}/src/js-host-api" "{{hyperlight-link}}"
echo "🔗 deps/js-host-api → ${hl_dir}/src/js-host-api"

# Build hyperlight-js NAPI addon (Windows variant — PowerShell + junction link).
# All statements on one line because just runs each line as a separate pwsh -Command.
[private]
[windows]
build-hyperlight target="debug": (build-runtime-release)
$hl_dir = just resolve-hyperlight-dir; Push-Location (Join-Path $hl_dir "src" "hyperlight-js"); cargo clean -p hyperlight-js 2>$null; Pop-Location; Push-Location $hl_dir; just build {{ if target == "debug" { "" } else { target } }}; Pop-Location; $linkPath = [IO.Path]::GetFullPath("{{hyperlight-link}}"); $targetPath = Join-Path $hl_dir "src" "js-host-api"; New-Item -ItemType Directory -Path (Split-Path $linkPath) -Force | Out-Null; if (Test-Path $linkPath) { cmd /c rmdir /q $linkPath 2>$null }; cmd /c mklink /J $linkPath $targetPath; Write-Output "🔗 deps/js-host-api → $targetPath"

# Build the hyperlight-analysis-guest NAPI addon (debug)
[private]
build-analysis-guest:
Expand Down Expand Up @@ -165,9 +177,15 @@ start *ARGS: install
npx tsx src/agent/index.ts {{ARGS}}

# Run with crash diagnostics (generates crash report .json files on SIGSEGV)
[unix]
start-debug *ARGS: install
NODE_OPTIONS="--report-on-signal --report-on-fatalerror --report-directory=$HOME/.hyperagent/logs" npx tsx src/agent/index.ts {{ARGS}}

# Run with crash diagnostics (Windows variant)
[windows]
start-debug *ARGS: install
$env:NODE_OPTIONS="--report-on-signal --report-on-fatalerror --report-directory=$env:USERPROFILE/.hyperagent/logs"; npx tsx src/agent/index.ts {{ARGS}}

# Run the agent with release-built native addon (faster sandbox execution)
start-release *ARGS: install-release
npx tsx src/agent/index.ts {{ARGS}}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ Ask the agent to compute things, and it writes & runs JavaScript in a hardware-i

### Prerequisites

- **Linux with KVM**, **Azure Linux with MSHV**, or **WSL2 with KVM** (hardware virtualization required)
- **Linux with KVM**, **Azure Linux with MSHV**, **Windows with WHP**, or **WSL2 with KVM** (hardware virtualization required)
- **GitHub authentication** (see [below](#github-authentication))
- **Docker** (for containerized option)
- **Node.js 22+** (for npm install / source builds only)
- **Rust + just** (for source builds only — see [Contributing](#contributing))

**NOTE:** HyperAgent does not currently run on macOS [due to this issue](https://github.com/hyperlight-dev/hyperlight/issues/45). Native Windows support (WHP) is planned — for now, use [WSL2 with KVM](https://learn.microsoft.com/en-us/windows/wsl/install) on Windows.
**NOTE:** HyperAgent does not currently run on macOS [due to this issue](https://github.com/hyperlight-dev/hyperlight/issues/45).

### GitHub Authentication

Expand Down
2 changes: 1 addition & 1 deletion builtin-modules/ooxml-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Shared OOXML infrastructure - units, colors, themes, Content_Types, relationships",
"author": "system",
"mutable": false,
"sourceHash": "sha256:24c8441a3504052f",
"sourceHash": "sha256:1e939013c13555bc",
"dtsHash": "sha256:9f88e7c59a56854c",
"importStyle": "named",
"hints": {
Expand Down
2 changes: 1 addition & 1 deletion builtin-modules/pptx-charts.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "OOXML DrawingML chart generation - bar, pie, line charts for PPTX presentations",
"author": "system",
"mutable": false,
"sourceHash": "sha256:029765ed53b96536",
"sourceHash": "sha256:5c521ce93ff39626",
"dtsHash": "sha256:5f653830226c3554",
"importStyle": "named",
"hints": {
Expand Down
6 changes: 4 additions & 2 deletions builtin-modules/pptx-tables.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
"description": "Styled tables for PPTX presentations - headers, borders, alternating rows",
"author": "system",
"mutable": false,
"sourceHash": "sha256:399b5349b1c8c187",
"sourceHash": "sha256:0739a7db5a8ab428",
"dtsHash": "sha256:82d903ffbf4dfb1e",
"importStyle": "named",
"hints": {
"overview": "Table generation for PPTX. Always used with ha:pptx.",
"relatedModules": ["ha:pptx"],
"relatedModules": [
"ha:pptx"
],
"criticalRules": [
"comparisonTable: options array must not be empty, each option needs {name, values}"
],
Expand Down
2 changes: 1 addition & 1 deletion builtin-modules/pptx.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "PowerPoint PPTX presentation builder - slides, text, shapes, themes, layouts",
"author": "system",
"mutable": false,
"sourceHash": "sha256:a13871a41506a523",
"sourceHash": "sha256:093b19522e994756",
"dtsHash": "sha256:2107e369816b4bd5",
"importStyle": "named",
"hints": {
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

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

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
"fmt": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"plugins/**/*.ts\" \"builtin-modules/**/*.js\"",
"fmt:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"plugins/**/*.ts\" \"builtin-modules/**/*.js\"",
"check": "npm run fmt:check && npm run typecheck && npm run test",
"prepare": "[ ! -f scripts/build-modules.js ] || npm run build:modules",
"postinstall": "[ ! -f scripts/patch-vscode-jsonrpc.js ] || (node scripts/patch-vscode-jsonrpc.js && node scripts/check-native-runtime.js)"
"prepare": "node -e \"if(require('fs').existsSync('scripts/build-modules.js'))require('child_process').execSync('npm run build:modules',{stdio:'inherit'})\"",
"postinstall": "node -e \"var fs=require('fs'),cp=require('child_process');if(fs.existsSync('scripts/patch-vscode-jsonrpc.js')){cp.execSync('node scripts/patch-vscode-jsonrpc.js',{stdio:'inherit'});cp.execSync('node scripts/check-native-runtime.js',{stdio:'inherit'})}\""
},
"dependencies": {
"@github/copilot-sdk": "^0.1.32",
Expand Down
14 changes: 6 additions & 8 deletions plugins/fs-read/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,12 @@ export function createHostFunctions(
// on the length parameter. Not configurable by design.
const maxReadChunkBytes = MAX_READ_CHUNK_KB * 1024;

// Platform guard: O_NOFOLLOW is POSIX-only. If the platform doesn't
// support it (Windows), fail loudly rather than silently losing
// symlink protection — O_NOFOLLOW is required.
if (FS_CONSTANTS.O_NOFOLLOW === undefined) {
throw new Error(
"[fs-read] O_NOFOLLOW not supported on this platform — cannot guarantee symlink safety",
);
}
// O_NOFOLLOW atomically rejects symlinks at open() on POSIX.
// On Windows it doesn't exist — we rely on the lstatSync pre-check
// in validatePath() plus a post-open fstatSync/lstatSync comparison.
// The residual TOCTOU window is narrow and requires symlink creation
// privileges (SeCreateSymbolicLinkPrivilege or Developer Mode).
const O_NOFOLLOW = FS_CONSTANTS.O_NOFOLLOW ?? 0;

// ── Host function implementations ────────────────────────────

Expand Down
11 changes: 6 additions & 5 deletions plugins/fs-write/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,12 @@ export function createHostFunctions(
safeNumericConfig(cfg.maxWriteSizeKb, 20480, MAX_SIZE_LIMIT_KB) * 1024;
const maxWriteChunkBytes = MAX_WRITE_CHUNK_KB * 1024;

if (FS_CONSTANTS.O_NOFOLLOW === undefined) {
throw new Error(
"[fs-write] O_NOFOLLOW not supported on this platform — cannot guarantee symlink safety",
);
}
// O_NOFOLLOW atomically rejects symlinks at open() on POSIX.
// On Windows it doesn't exist — we rely on the lstatSync pre-check
// in validatePath() plus a post-open fstatSync/lstatSync comparison.
// The residual TOCTOU window is narrow and requires symlink creation
// privileges (SeCreateSymbolicLinkPrivilege or Developer Mode).
const O_NOFOLLOW = FS_CONSTANTS.O_NOFOLLOW ?? 0;

const maxEntries = Math.floor(
safeNumericConfig(cfg.maxEntries, 500, MAX_ENTRIES_LIMIT),
Expand Down
Loading
Loading