diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5f19147b..dd0e3ff33 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,8 @@ jobs: path: ~/.bun/install/cache key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }} - run: bun install --frozen-lockfile + - name: Generate WASM base64 + run: bun packages/coding-agent/scripts/generate-wasm-b64.ts - name: Build binaries run: | cd packages/coding-agent @@ -75,6 +77,7 @@ jobs: bun build --compile --target=bun-linux-x64 ./src/cli.ts --outfile binaries/omp-linux-x64 bun build --compile --target=bun-linux-arm64 ./src/cli.ts --outfile binaries/omp-linux-arm64 bun build --compile --target=bun-windows-x64 ./src/cli.ts --outfile binaries/omp-windows-x64.exe + bun build --compile --target=bun-windows-arm64 ./src/cli.ts --outfile binaries/omp-windows-arm64.exe - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: diff --git a/.gitignore b/.gitignore index 6493551c8..d80a4949b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ packages/ai/test/.temp-images/ changes/ __pycache__/ +*.b64.js diff --git a/bun.lock b/bun.lock index f516c7cf4..a0f0d9b8a 100644 --- a/bun.lock +++ b/bun.lock @@ -21,7 +21,7 @@ }, "packages/agent": { "name": "@oh-my-pi/pi-agent-core", - "version": "5.7.67", + "version": "5.8.0", "dependencies": { "@oh-my-pi/pi-ai": "workspace:*", "@oh-my-pi/pi-tui": "workspace:*", @@ -33,7 +33,7 @@ }, "packages/ai": { "name": "@oh-my-pi/pi-ai", - "version": "5.7.67", + "version": "5.8.0", "bin": { "pi-ai": "./src/cli.ts", }, @@ -60,7 +60,7 @@ }, "packages/coding-agent": { "name": "@oh-my-pi/pi-coding-agent", - "version": "5.7.67", + "version": "5.8.0", "bin": { "omp": "src/cli.ts", }, @@ -100,7 +100,7 @@ }, "packages/git-tool": { "name": "@oh-my-pi/pi-git-tool", - "version": "5.7.67", + "version": "5.8.0", "devDependencies": { "@types/node": "^24.3.0", "vitest": "^3.2.4", @@ -108,7 +108,7 @@ }, "packages/tui": { "name": "@oh-my-pi/pi-tui", - "version": "5.7.67", + "version": "5.8.0", "dependencies": { "@types/mime-types": "^2.1.4", "chalk": "^5.5.0", diff --git a/packages/agent/package.json b/packages/agent/package.json index 91846e433..a80b02911 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-agent-core", - "version": "5.7.67", + "version": "5.8.0", "description": "General-purpose agent with transport abstraction, state management, and attachment support", "type": "module", "main": "./src/index.ts", diff --git a/packages/ai/package.json b/packages/ai/package.json index 5a4d4d427..968c0b99d 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-ai", - "version": "5.7.67", + "version": "5.8.0", "description": "Unified LLM API with automatic model discovery and provider configuration", "type": "module", "main": "./src/index.ts", diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 42312a834..090125e69 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -1,6 +1,28 @@ # Changelog ## [Unreleased] +### Added + +- Added Windows ARM64 binary support + +### Fixed + +- Fixed TTSR abbreviation expansion from TTSR to Time Traveling Stream Rules + +## [5.8.0] - 2026-01-19 +### Changed + +- Updated WASM loading to use streaming for development environments with base64 fallback +- Added scripts directory to published package files + +## [5.7.68] - 2026-01-18 +### Changed + +- Updated WASM loading to use base64-encoded WASM for better compatibility with compiled binaries + +### Fixed + +- Fixed WASM loading issues in compiled binary builds ## [5.7.67] - 2026-01-18 ### Changed diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 5dfb36a67..0d6a51426 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -52,29 +52,29 @@ Works on Linux, macOS, and Windows (requires bash; see [Windows Setup](#windows- **npm (recommended):** ```bash -npm install -g @oh-my-pi/omp-coding-agent +npm install -g @oh-my-pi/pi-coding-agent ``` **Standalone binary:** -Download from [GitHub Releases](https://github.com/badlogic/pi-mono/releases): +Download from [GitHub Releases](https://github.com/can1357/oh-my-pi/releases): -| Platform | Archive | +| Platform | Binary | | ------------------- | ------------------------ | -| macOS Apple Silicon | `omp-darwin-arm64.tar.gz` | -| macOS Intel | `omp-darwin-x64.tar.gz` | -| Linux x64 | `omp-linux-x64.tar.gz` | -| Linux ARM64 | `omp-linux-arm64.tar.gz` | -| Windows x64 | `omp-windows-x64.zip` | +| macOS Apple Silicon | `omp-darwin-arm64` | +| macOS Intel | `omp-darwin-x64` | +| Linux x64 | `omp-linux-x64` | +| Linux ARM64 | `omp-linux-arm64` | +| Windows x64 | `omp-windows-x64.exe` | +| Windows ARM64 | `omp-windows-arm64.exe` | ```bash # macOS/Linux -tar -xzf omp-darwin-arm64.tar.gz -./omp +chmod +x omp-darwin-arm64 +./omp-darwin-arm64 # Windows -unzip omp-windows-x64.zip -omp.exe +omp-windows-x64.exe ``` **macOS note:** The binary is unsigned. If blocked, run: `xattr -c ./omp` @@ -133,24 +133,7 @@ return config ### API Keys & OAuth -**Option 1: Auth file** (recommended) - -Add API keys to `~/.omp/agent/auth.json`: - -```json -{ - "anthropic": [ - { "type": "api_key", "key": "sk-ant-..." }, - { "type": "api_key", "key": "sk-ant-..." } - ], - "openai": { "type": "api_key", "key": "sk-..." }, - "google": { "type": "api_key", "key": "..." } -} - -If a provider has multiple credentials, new sessions round robin across them and stay sticky per session. -``` - -**Option 2: Environment variables** +**Option 1: Environment variables** (recommended) | Provider | Auth Key | Environment Variable | | ---------- | ------------ | -------------------- | @@ -164,16 +147,16 @@ If a provider has multiple credentials, new sessions round robin across them and | OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | | ZAI | `zai` | `ZAI_API_KEY` | -Auth file keys take priority over environment variables. - -**OAuth Providers:** +**Option 2: OAuth** Use `/login` to authenticate with subscription-based or free-tier providers: | Provider | Models | Cost | | -------------------------- | ----------------------------------------------- | --------------------- | | Anthropic (Claude Pro/Max) | Claude models via your subscription | Subscription | +| Cursor | Claude, GPT-4o via Cursor Pro subscription | Subscription | | GitHub Copilot | GPT-4o, Claude, Gemini via Copilot subscription | Subscription | +| OpenAI Codex | o3, o4-mini via ChatGPT Plus/Pro subscription | Subscription | | Google Gemini CLI | Gemini 2.0/2.5 models | Free (Google account) | | Google Antigravity | Gemini 3, Claude, GPT-OSS | Free (Google account) | @@ -182,7 +165,7 @@ omp /login # Select provider, authorize in browser ``` -**Note:** `/login` replaces any existing API keys for that provider with OAuth credentials in `auth.json`. If OAuth credentials already exist, `/login` appends another entry. +**Note:** `/login` replaces any existing API keys for that provider with OAuth credentials. If OAuth credentials already exist, `/login` appends another entry. **GitHub Copilot notes:** @@ -196,7 +179,7 @@ omp - Both are free with any Google account, subject to rate limits - Paid Cloud Code Assist subscriptions: set `GOOGLE_CLOUD_PROJECT` or `GOOGLE_CLOUD_PROJECT_ID` env var to your project ID -Credentials stored in `~/.omp/agent/auth.json`. Use `/logout` to clear. +Credentials stored in `~/.omp/agent/agent.db`. Use `/logout` to clear. ### Quick Start @@ -617,7 +600,7 @@ Select theme via `/settings` or set in `~/.omp/agent/settings.json`. ```bash mkdir -p ~/.omp/agent/themes -cp $(npm root -g)/@oh-my-pi/omp-coding-agent/dist/theme/dark.json ~/.omp/agent/themes/my-theme.json +cp $(npm root -g)/@oh-my-pi/pi-coding-agent/dist/theme/dark.json ~/.omp/agent/themes/my-theme.json ``` Select with `/settings`, then edit the file. Changes apply on save. @@ -740,7 +723,7 @@ Hooks are TypeScript modules that extend omp's behavior by subscribing to lifecy **Quick example** (permission gate): ```typescript -import type { HookAPI } from "@oh-my-pi/omp-coding-agent/hooks"; +import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks"; export default function (omp: HookAPI) { omp.on("tool_call", async (event, ctx) => { @@ -759,7 +742,7 @@ Use `omp.sendMessage(message, triggerTurn?)` to inject messages into the session ```typescript import * as fs from "node:fs"; -import type { HookAPI } from "@oh-my-pi/omp-coding-agent/hooks"; +import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks"; export default function (omp: HookAPI) { omp.on("session_start", async () => { @@ -802,7 +785,7 @@ Custom tools let you extend the built-in toolset (read, write, edit, bash, ...) ```typescript import { Type } from "@sinclair/typebox"; -import type { CustomToolFactory } from "@oh-my-pi/omp-coding-agent"; +import type { CustomToolFactory } from "@oh-my-pi/pi-coding-agent"; const factory: CustomToolFactory = (omp) => ({ name: "greet", @@ -970,7 +953,7 @@ For adding new tools, see [Custom Tools](#custom-tools) in the Configuration sec For embedding omp in Node.js/TypeScript applications, use the SDK: ```typescript -import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/omp-coding-agent"; +import { createAgentSession, discoverAuthStorage, discoverModels, SessionManager } from "@oh-my-pi/pi-coding-agent"; const authStorage = discoverAuthStorage(); const modelRegistry = discoverModels(authStorage); diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index 67f615c18..ec2c2fc73 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-coding-agent", - "version": "5.7.67", + "version": "5.8.0", "description": "Coding agent CLI with read, bash, edit, write tools and session management", "type": "module", "ompConfig": { @@ -24,6 +24,7 @@ }, "files": [ "src", + "scripts", "docs", "examples", "CHANGELOG.md" @@ -32,9 +33,10 @@ "check": "tsgo -p tsconfig.check.json", "clean": "rm -rf dist", "build": "tsgo -p tsconfig.build.json && chmod +x dist/cli.js", - "build:binary": "bun build --compile ./src/cli.ts --outfile dist/omp", + "build:binary": "bun run generate-wasm-b64 && bun build --compile ./src/cli.ts --outfile dist/omp", + "generate-wasm-b64": "bun scripts/generate-wasm-b64.ts", "generate-template": "bun scripts/generate-template.ts", - "postinstall": "[ -f scripts/generate-template.ts ] && bun run generate-template || true", + "postinstall": "[ -f scripts/generate-wasm-b64.ts ] && bun run generate-wasm-b64 && bun run generate-template || true", "test": "bun test", "prepublishOnly": "bun run generate-template && bun run clean && bun run build" }, diff --git a/packages/coding-agent/scripts/generate-wasm-b64.ts b/packages/coding-agent/scripts/generate-wasm-b64.ts new file mode 100755 index 000000000..ccf7ff18b --- /dev/null +++ b/packages/coding-agent/scripts/generate-wasm-b64.ts @@ -0,0 +1,13 @@ +#!/usr/bin/env bun +import { readFileSync, writeFileSync } from "node:fs"; +import { join, dirname } from "node:path"; + +const vendorDir = join(dirname(import.meta.dir), "src/vendor/photon"); +const wasmPath = join(vendorDir, "photon_rs_bg.wasm"); +const b64Path = join(vendorDir, "photon_rs_bg.wasm.b64.js"); + +const wasmBytes = readFileSync(wasmPath); +const wasmB64 = wasmBytes.toString("base64"); +writeFileSync(b64Path, `export default "${wasmB64}";\n`); + +console.log(`Generated ${b64Path} (${wasmB64.length} chars)`); diff --git a/packages/coding-agent/src/migrations.ts b/packages/coding-agent/src/migrations.ts index 71382a38b..591fe7839 100644 --- a/packages/coding-agent/src/migrations.ts +++ b/packages/coding-agent/src/migrations.ts @@ -10,7 +10,6 @@ import { AgentStorage } from "./core/agent-storage"; import type { AuthCredential } from "./core/auth-storage"; import { logger } from "./core/logger"; - /** * Migrate legacy oauth.json and settings.json apiKeys to agent.db. * diff --git a/packages/coding-agent/src/modes/interactive/components/settings-defs.ts b/packages/coding-agent/src/modes/interactive/components/settings-defs.ts index 321ecba98..b1764fdc1 100644 --- a/packages/coding-agent/src/modes/interactive/components/settings-defs.ts +++ b/packages/coding-agent/src/modes/interactive/components/settings-defs.ts @@ -83,7 +83,8 @@ const THINKING_DESCRIPTIONS: Record = { * - behavior: Core agent behavior (compaction, modes, retries, notifications) * - tools: Tool-specific settings (bash, git, python, edit, MCP, skills) * - display: Visual/UI settings (theme, images, thinking) - * - voice: Voice mode and TTSR settings + * - voice: Voice mode and TTS settings + * - ttsr: Time Traveling Stream Rules settings * - status: Status line configuration * - lsp: LSP integration settings * - exa: Exa search tool settings @@ -443,7 +444,7 @@ export const SETTINGS_DEFS: SettingDef[] = [ }, // ═══════════════════════════════════════════════════════════════════════════ - // Voice tab - Voice mode and TTSR settings + // Voice tab - Voice mode and TTS settings // ═══════════════════════════════════════════════════════════════════════════ { id: "voiceEnabled", @@ -501,9 +502,13 @@ export const SETTINGS_DEFS: SettingDef[] = [ { value: "flac", label: "FLAC", description: "Lossless compression" }, ], }, + + // ═══════════════════════════════════════════════════════════════════════════ + // TTSR tab - Time Traveling Stream Rules + // ═══════════════════════════════════════════════════════════════════════════ { id: "ttsrEnabled", - tab: "voice", + tab: "ttsr", type: "boolean", label: "TTSR enabled", description: "Time Traveling Stream Rules: interrupt agent when output matches patterns", @@ -512,7 +517,7 @@ export const SETTINGS_DEFS: SettingDef[] = [ }, { id: "ttsrContextMode", - tab: "voice", + tab: "ttsr", type: "enum", label: "TTSR context mode", description: "What to do with partial output when TTSR triggers", @@ -522,7 +527,7 @@ export const SETTINGS_DEFS: SettingDef[] = [ }, { id: "ttsrRepeatMode", - tab: "voice", + tab: "ttsr", type: "enum", label: "TTSR repeat mode", description: "How rules can repeat: once per session or after a message gap", @@ -532,7 +537,7 @@ export const SETTINGS_DEFS: SettingDef[] = [ }, { id: "ttsrRepeatGap", - tab: "voice", + tab: "ttsr", type: "submenu", label: "TTSR repeat gap", description: "Messages before a rule can trigger again (when repeat mode is after-gap)", diff --git a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts index cb3c42ea7..d249356fa 100644 --- a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts @@ -118,6 +118,7 @@ const SETTINGS_TABS: Tab[] = [ { id: "tools", label: "Tools" }, { id: "display", label: "Display" }, { id: "voice", label: "Voice" }, + { id: "ttsr", label: "TTSR" }, { id: "status", label: "Status" }, { id: "lsp", label: "LSP" }, { id: "exa", label: "Exa" }, diff --git a/packages/coding-agent/src/vendor/photon/index.js b/packages/coding-agent/src/vendor/photon/index.js index 5516c4f58..12060a415 100644 --- a/packages/coding-agent/src/vendor/photon/index.js +++ b/packages/coding-agent/src/vendor/photon/index.js @@ -4453,7 +4453,29 @@ const cachedTextEncoder = new TextEncoder(); let WASM_VECTOR_LEN = 0; -const wasmUrl = new URL('photon_rs_bg.wasm', import.meta.url); -const wasmInstantiated = await WebAssembly.instantiateStreaming(fetch(wasmUrl), __wbg_get_imports()); +// Load WASM - try each source until one instantiates successfully +let wasmInstantiated; +const imports = __wbg_get_imports(); + +// Try .wasm file first (dev) - streaming is most efficient +let streamingError; +try { + const wasmPath = new URL("./photon_rs_bg.wasm", import.meta.url); + wasmInstantiated = await WebAssembly.instantiateStreaming(fetch(wasmPath), imports); +} catch (e) { + streamingError = e; +} + +// Fall back to base64 (compiled binary/npm) +if (!wasmInstantiated) { + try { + const { default: wasmBase64 } = await import("./photon_rs_bg.wasm.b64.js"); + const wasmBytes = Uint8Array.from(atob(wasmBase64), c => c.charCodeAt(0)); + wasmInstantiated = await WebAssembly.instantiate(wasmBytes, imports); + } catch (b64Error) { + throw new Error(`Failed to load photon WASM:\n streaming: ${streamingError?.message}\n base64: ${b64Error.message}`); + } +} + const wasm = wasmInstantiated.instance.exports; wasm.__wbindgen_start(); diff --git a/packages/git-tool/package.json b/packages/git-tool/package.json index ec157ffec..752e8d5be 100644 --- a/packages/git-tool/package.json +++ b/packages/git-tool/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-git-tool", - "version": "5.7.67", + "version": "5.8.0", "description": "Structured Git tool with safety guards and typed output", "type": "module", "main": "./src/index.ts", diff --git a/packages/tui/package.json b/packages/tui/package.json index 883a0a224..f0291e9c8 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-tui", - "version": "5.7.67", + "version": "5.8.0", "description": "Terminal User Interface library with differential rendering for efficient text-based applications", "type": "module", "main": "src/index.ts", diff --git a/scripts/install-tests/binary.dockerfile b/scripts/install-tests/binary.dockerfile new file mode 100644 index 000000000..cfa81a95e --- /dev/null +++ b/scripts/install-tests/binary.dockerfile @@ -0,0 +1,23 @@ +# Test binary build from local source +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y curl ca-certificates unzip && rm -rf /var/lib/apt/lists/* + +# Install bun +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:$PATH" + +# Copy local repo +WORKDIR /repo +COPY . . + +# Build binary +RUN bun install --frozen-lockfile +RUN cd packages/coding-agent && bun run build:binary + +# Install binary to PATH +RUN mkdir -p /root/.local/bin && cp packages/coding-agent/dist/omp /root/.local/bin/ +ENV PATH="/root/.local/bin:$PATH" + +# Verify +RUN omp --version diff --git a/scripts/install-tests/run.sh b/scripts/install-tests/run.sh new file mode 100755 index 000000000..edafd6cbc --- /dev/null +++ b/scripts/install-tests/run.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +cd "$(dirname "$0")/../.." + +echo "=== Testing binary build ===" +podman build -f scripts/install-tests/binary.dockerfile -t omp-test-binary . + +echo "" +echo "=== Testing source install ===" +podman build -f scripts/install-tests/source.dockerfile -t omp-test-source . + +echo "" +echo "=== All tests passed ===" diff --git a/scripts/install-tests/source.dockerfile b/scripts/install-tests/source.dockerfile new file mode 100644 index 000000000..d83d33e94 --- /dev/null +++ b/scripts/install-tests/source.dockerfile @@ -0,0 +1,19 @@ +# Test --source install from local repo +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y curl ca-certificates unzip && rm -rf /var/lib/apt/lists/* + +# Install bun +RUN curl -fsSL https://bun.sh/install | bash +ENV PATH="/root/.bun/bin:$PATH" + +# Copy local repo +WORKDIR /repo +COPY . . + +# Install dependencies and link globally +RUN bun install --frozen-lockfile +RUN cd packages/coding-agent && bun link + +# Verify +RUN omp --version diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 13a14edba..ba16e7199 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -17,9 +17,17 @@ param( $ErrorActionPreference = "Stop" $Repo = "can1357/oh-my-pi" -$Package = "@oh-my-pi/omp-coding-agent" +$Package = "@oh-my-pi/pi-coding-agent" $InstallDir = if ($env:OMP_INSTALL_DIR) { $env:OMP_INSTALL_DIR } else { "$env:LOCALAPPDATA\omp" } -$BinaryName = "omp-windows-x64.exe" + +function Get-ArchitectureSuffix { + $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture + switch ($arch) { + "X64" { return "x64" } + "Arm64" { return "arm64" } + default { throw "Unsupported architecture: $arch" } + } +} function Test-BunInstalled { try { @@ -39,6 +47,91 @@ function Test-GitInstalled { } } +function Test-GitLfsInstalled { + try { + $null = Get-Command git-lfs -ErrorAction Stop + return $true + } catch { + return $false + } +} + +function Find-BashShell { + # Check Git Bash first (most common on Windows) + $gitBash = "C:\Program Files\Git\bin\bash.exe" + if (Test-Path $gitBash) { + return $gitBash + } + + # Check bash.exe on PATH (Cygwin, MSYS2, WSL) + try { + $bashCmd = Get-Command bash.exe -ErrorAction Stop + return $bashCmd.Source + } catch { + return $null + } +} + +function Configure-BashShell { + try { + $settingsDir = Join-Path $env:USERPROFILE ".omp\agent" + $settingsFile = Join-Path $settingsDir "settings.json" + + # Check if settings.json already has a shellPath configured + if (Test-Path $settingsFile) { + try { + $existingSettings = Get-Content $settingsFile -Raw | ConvertFrom-Json + if ($existingSettings.shellPath) { + Write-Host "Bash shell already configured: $($existingSettings.shellPath)" -ForegroundColor Cyan + return + } + } catch { + # Invalid JSON, we'll overwrite it + } + } + + $bashPath = Find-BashShell + + if ($bashPath) { + Write-Host "Found bash shell: $bashPath" -ForegroundColor Cyan + + # Create settings directory if needed + if (-not (Test-Path $settingsDir)) { + New-Item -ItemType Directory -Force -Path $settingsDir | Out-Null + } + + # Read existing settings or create new + $settings = @{} + if (Test-Path $settingsFile) { + try { + $settings = Get-Content $settingsFile -Raw | ConvertFrom-Json -AsHashtable + } catch { + $settings = @{} + } + } + + # Set shellPath + $settings["shellPath"] = $bashPath + + # Write settings + $settings | ConvertTo-Json -Depth 10 | Set-Content $settingsFile -Encoding UTF8 + Write-Host "✓ Configured shell path in $settingsFile" -ForegroundColor Green + } else { + Write-Host "" + Write-Host "⚠ No bash shell found!" -ForegroundColor Yellow + Write-Host " OMP requires a bash shell on Windows. Options:" -ForegroundColor Yellow + Write-Host " 1. Install Git for Windows: https://git-scm.com/download/win" -ForegroundColor Yellow + Write-Host " 2. Use WSL, Cygwin, or MSYS2" -ForegroundColor Yellow + Write-Host "" + Write-Host " After installing, you can set a custom path in:" -ForegroundColor Yellow + Write-Host " $settingsFile" -ForegroundColor Yellow + Write-Host ' { "shellPath": "C:\\path\\to\\bash.exe" }' -ForegroundColor Yellow + } + } catch { + Write-Host "⚠ Could not configure bash shell: $_" -ForegroundColor Yellow + } +} + function Install-Bun { Write-Host "Installing bun..." irm bun.sh/install.ps1 | iex @@ -76,25 +169,47 @@ function Install-ViaBun { } } + # Pull LFS files + if (Test-GitLfsInstalled) { + Push-Location $tmpRoot + try { + git lfs pull | Out-Null + } finally { + Pop-Location + } + } + $packagePath = Join-Path $tmpRoot "packages\coding-agent" if (-not (Test-Path $packagePath)) { throw "Expected package at $packagePath" } bun install -g $packagePath + if ($LASTEXITCODE -ne 0) { + throw "Failed to install from $packagePath via bun" + } } finally { Remove-Item -Recurse -Force $tmpRoot -ErrorAction SilentlyContinue } } else { bun install -g $Package + if ($LASTEXITCODE -ne 0) { + throw "Failed to install $Package via bun" + } } Write-Host "" Write-Host "✓ Installed omp via bun" -ForegroundColor Green + + Configure-BashShell + Write-Host "Run 'omp' to get started!" } function Install-Binary { + $archSuffix = Get-ArchitectureSuffix + $BinaryName = "omp-windows-$archSuffix.exe" + if ($Ref) { Write-Host "Fetching release $Ref..." try { @@ -126,9 +241,15 @@ function Install-Binary { # Add to PATH if not already there $UserPath = [Environment]::GetEnvironmentVariable("Path", "User") - if ($UserPath -notlike "*$InstallDir*") { + $needsRestart = $UserPath -notlike "*$InstallDir*" + if ($needsRestart) { Write-Host "Adding $InstallDir to PATH..." [Environment]::SetEnvironmentVariable("Path", "$UserPath;$InstallDir", "User") + } + + Configure-BashShell + + if ($needsRestart) { Write-Host "Restart your terminal, then run 'omp' to get started!" } else { Write-Host "Run 'omp' to get started!" diff --git a/scripts/install.sh b/scripts/install.sh index 4af49e0fb..56f21538b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -11,7 +11,7 @@ set -e # -r Shorthand for --ref REPO="can1357/oh-my-pi" -PACKAGE="@oh-my-pi/omp-coding-agent" +PACKAGE="@oh-my-pi/pi-coding-agent" INSTALL_DIR="${OMP_INSTALL_DIR:-$HOME/.local/bin}" # Parse arguments @@ -38,6 +38,10 @@ while [ $# -gt 0 ]; do ;; --ref=*) REF="${1#*=}" + if [ -z "$REF" ]; then + echo "Missing value for --ref" + exit 1 + fi shift ;; -r) @@ -50,7 +54,8 @@ while [ $# -gt 0 ]; do shift ;; *) - shift + echo "Unknown option: $1" + exit 1 ;; esac done @@ -73,11 +78,21 @@ has_git() { # Install bun install_bun() { echo "Installing bun..." - curl -fsSL https://bun.sh/install | bash + if command -v bash >/dev/null 2>&1; then + curl -fsSL https://bun.sh/install | bash + else + echo "bash not found; attempting install with sh..." + curl -fsSL https://bun.sh/install | sh + fi export BUN_INSTALL="$HOME/.bun" export PATH="$BUN_INSTALL/bin:$PATH" } +# Check if git-lfs is available +has_git_lfs() { + command -v git-lfs >/dev/null 2>&1 +} + # Install via bun install_via_bun() { echo "Installing via bun..." @@ -97,14 +112,25 @@ install_via_bun() { (cd "$TMP_DIR" && git checkout "$REF") fi + # Pull LFS files + if has_git_lfs; then + (cd "$TMP_DIR" && git lfs pull) + fi + if [ ! -d "$TMP_DIR/packages/coding-agent" ]; then echo "Expected package at ${TMP_DIR}/packages/coding-agent" exit 1 fi - bun install -g "$TMP_DIR/packages/coding-agent" + bun install -g "$TMP_DIR/packages/coding-agent" || { + echo "Failed to install from source" + exit 1 + } else - bun install -g "$PACKAGE" + bun install -g "$PACKAGE" || { + echo "Failed to install $PACKAGE" + exit 1 + } fi echo "" echo "✓ Installed omp via bun"