Skip to content
Open
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
47 changes: 44 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- {os: 'linux', arch: 'amd64', runner: 'ubuntu-latest'}
- {os: 'linux', arch: 'arm64', runner: 'ubuntu-24.04-arm'}
- {os: 'darwin', arch: 'arm64', runner: 'macos-latest'}
- {os: 'windows', arch: 'amd64', runner: 'windows-latest'}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -29,7 +30,8 @@ jobs:
go-version: '1.23'
cache-dependency-path: src/mcp/go.sum

- name: Build MCP binary
- name: Build MCP binary (Unix)
if: runner.os != 'Windows'
run: |
cd src/mcp
VERSION=${GITHUB_REF_NAME#v}
Expand All @@ -38,7 +40,19 @@ jobs:
LDFLAGS="-s -w -X github.com/m0n0x41d/quint-code/cmd.Version=${VERSION} -X github.com/m0n0x41d/quint-code/cmd.Commit=${COMMIT} -X github.com/m0n0x41d/quint-code/cmd.BuildDate=${DATE}"
go build -o "../../dist/quint-code" -trimpath -ldflags "${LDFLAGS}"

- name: Create release package
- name: Build MCP binary (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
cd src/mcp
$Version = "${{ github.ref_name }}".TrimStart("v")
$Commit = "${{ github.sha }}".Substring(0, 8)
$Date = (Get-Date -AsUTC -Format "yyyy-MM-ddTHH:mm:ssZ")
$Ldflags = "-s -w -X github.com/m0n0x41d/quint-code/cmd.Version=$Version -X github.com/m0n0x41d/quint-code/cmd.Commit=$Commit -X github.com/m0n0x41d/quint-code/cmd.BuildDate=$Date"
go build -o "../../dist/quint-code.exe" -trimpath -ldflags $Ldflags

- name: Create release package (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p "package/bin"
mkdir -p "package/commands"
Expand All @@ -49,7 +63,20 @@ jobs:
tar -czf "$ASSET_NAME" -C "package" .
echo "ASSET_NAME=${ASSET_NAME}" >> $GITHUB_ENV

- name: Extract release notes from CHANGELOG
- name: Create release package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Path "package/bin", "package/commands" -Force
Move-Item "dist/quint-code.exe" "package/bin/quint-code.exe"
Copy-Item "src/mcp/cmd/commands/*" "package/commands/" -Recurse
$Tag = "${{ github.ref_name }}".TrimStart("v")
$AssetName = "quint-code-${Tag}-${{ matrix.platform.os }}-${{ matrix.platform.arch }}.zip"
Compress-Archive -Path "package/*" -DestinationPath $AssetName
"ASSET_NAME=$AssetName" | Out-File -Append $env:GITHUB_ENV

- name: Extract release notes from CHANGELOG (Unix)
if: runner.os != 'Windows'
id: changelog
run: |
VERSION=${GITHUB_REF_NAME#v}
Expand All @@ -59,6 +86,20 @@ jobs:
echo "EOF"
} >> $GITHUB_ENV

- name: Extract release notes from CHANGELOG (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$Version = "${{ github.ref_name }}".TrimStart("v")
$notes = ""
$found = $false
foreach ($line in Get-Content CHANGELOG.md) {
if ($line -match "^## \[$Version\]") { $found = $true; continue }
if ($found -and $line -match "^## \[") { break }
if ($found) { $notes += "$line`n" }
}
"RELEASE_NOTES<<EOF`n$notes`nEOF" | Out-File -Append $env:GITHUB_ENV

- name: Upload to release
uses: svenstaro/upload-release-action@v2
with:
Expand Down
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Structured reasoning for AI coding tools** — make better decisions, remember why you made them.

**Supports:** Claude Code, Cursor, Gemini CLI, Codex CLI
**Supports:** Claude Code, Cursor, Gemini CLI, Codex CLI, GitHub Copilot

> **Works exceptionally well with Claude Code!**

Expand All @@ -19,17 +19,25 @@ queryable, auditable, yours.

### Step 1: Install the Binary

**macOS / Linux:**

```bash
curl -fsSL https://raw.githubusercontent.com/m0n0x41d/quint-code/main/install.sh | bash
```

Or build from source:
**Windows (PowerShell):**

```powershell
irm https://raw.githubusercontent.com/m0n0x41d/quint-code/main/install.ps1 | iex
```

**Or build from source (all platforms):**

```bash
git clone https://github.com/m0n0x41d/quint-code.git
cd quint-code/src/mcp
go build -o quint-code .
sudo mv quint-code /usr/local/bin/
go build -o quint-code . # Linux/macOS
go build -o quint-code.exe . # Windows
```

### Step 2: Initialize a Project
Expand All @@ -53,6 +61,7 @@ This creates:
| `--cursor` | `.cursor/mcp.json` | `~/.cursor/commands/*.md` |
| `--gemini` | `~/.gemini/settings.json` | `~/.gemini/commands/*.toml` |
| `--codex` | `~/.codex/config.toml`* | `~/.codex/prompts/*.md` |
| `--copilot` | `.vscode/mcp.json` | `.github/prompts/*.prompt.md` |
| `--all` | All of the above | All of the above |
| `--local` | — | Commands in project dir instead of global |

Expand Down
129 changes: 129 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Quint Code Installer for Windows
#
# Installs the quint-code binary.
# After installation, run `quint-code init` in each project.
#
# Usage:
# irm https://raw.githubusercontent.com/m0n0x41d/quint-code/main/install.ps1 | iex

$ErrorActionPreference = "Stop"

$Repo = "m0n0x41d/quint-code"
$BinName = "quint-code.exe"
$InstallDir = "$env:LOCALAPPDATA\Programs\quint-code"

function Write-Logo {
Write-Host ""
Write-Host " QUINT CODE" -ForegroundColor Red
Write-Host " First Principles Framework for AI-assisted engineering" -ForegroundColor DarkGray
Write-Host ""
}

function Get-Arch {
switch ($env:PROCESSOR_ARCHITECTURE) {
"AMD64" { return "amd64" }
"ARM64" { return "arm64" }
default { throw "Unsupported architecture: $env:PROCESSOR_ARCHITECTURE" }
}
}

function Install-QuintCode {
Write-Logo
Write-Host " Installing Quint Code..." -ForegroundColor Cyan
Write-Host ""

$arch = Get-Arch
$osArch = "windows-$arch"

if (!(Test-Path $InstallDir)) {
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
}

# Try downloading release
$apiUrl = "https://api.github.com/repos/$Repo/releases/latest"
$downloadUrl = $null

try {
$release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "quint-code-installer" }
$asset = $release.assets | Where-Object { $_.name -like "*$osArch.zip" } | Select-Object -First 1
if ($asset) {
$downloadUrl = $asset.browser_download_url
}
} catch {
# No release found, will build from source
}

if ($downloadUrl) {
Write-Host " Downloading release ($osArch)..." -ForegroundColor DarkGray
$tmpZip = Join-Path $env:TEMP "quint-code-release.zip"
$tmpDir = Join-Path $env:TEMP "quint-code-extract"

Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpZip
if (Test-Path $tmpDir) { Remove-Item $tmpDir -Recurse -Force }
Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force

Copy-Item (Join-Path $tmpDir "bin\$BinName") (Join-Path $InstallDir $BinName) -Force
Remove-Item $tmpZip -Force
Remove-Item $tmpDir -Recurse -Force

Write-Host " [OK] Downloaded release" -ForegroundColor Green
} else {
Write-Host " No release found, building from source..." -ForegroundColor Yellow

$missing = @()
if (!(Get-Command git -ErrorAction SilentlyContinue)) { $missing += "Git" }
if (!(Get-Command go -ErrorAction SilentlyContinue)) { $missing += "Go" }

if ($missing.Count -gt 0) {
Write-Host ""
Write-Host " [ERROR] No prebuilt release found. Building from source requires: $($missing -join ', ')" -ForegroundColor Red
Write-Host ""
if ($missing -contains "Git") {
Write-Host " Install Git: https://git-scm.com/download/win" -ForegroundColor Yellow
Write-Host " Or: winget install Git.Git" -ForegroundColor Yellow
}
if ($missing -contains "Go") {
Write-Host " Install Go: https://go.dev/dl/" -ForegroundColor Yellow
Write-Host " Or: winget install GoLang.Go" -ForegroundColor Yellow
}
Write-Host ""
exit 1
}

$repoDir = Join-Path $env:TEMP "quint-code-build"
if (Test-Path $repoDir) { Remove-Item $repoDir -Recurse -Force }

Write-Host " Cloning repository..." -ForegroundColor DarkGray
git clone --depth 1 "https://github.com/$Repo.git" $repoDir 2>&1 | Out-Null

Write-Host " Building binary..." -ForegroundColor DarkGray
Push-Location (Join-Path $repoDir "src\mcp")
go build -trimpath -o (Join-Path $InstallDir $BinName) .
Pop-Location

Remove-Item $repoDir -Recurse -Force
Write-Host " [OK] Built from source" -ForegroundColor Green
}

Write-Host " [OK] Installed to $InstallDir\$BinName" -ForegroundColor Green

# Check PATH
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($userPath -notlike "*$InstallDir*") {
Write-Host ""
Write-Host " Adding $InstallDir to user PATH..." -ForegroundColor Yellow
[Environment]::SetEnvironmentVariable("Path", "$userPath;$InstallDir", "User")
$env:Path = "$env:Path;$InstallDir"
Write-Host " [OK] Added to PATH (restart terminal for effect)" -ForegroundColor Green
}

Write-Host ""
Write-Host " Installation Complete!" -ForegroundColor Green
Write-Host ""
Write-Host " Next step:" -ForegroundColor White
Write-Host " cd \path\to\your\project" -ForegroundColor White
Write-Host " quint-code init" -ForegroundColor White
Write-Host ""
}

Install-QuintCode
41 changes: 39 additions & 2 deletions src/mcp/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ func installCommands(projectRoot string, platform string, local bool) (string, i
// Codex only supports global prompts in ~/.codex/prompts/
destDir = filepath.Join(homeDir, ".codex", "prompts")
transformer = transformCodex
case "copilot":
// Copilot uses .github/prompts/*.prompt.md (always project-local)
destDir = filepath.Join(projectRoot, ".github", "prompts")
transformer = transformCopilot
default:
return "", 0, fmt.Errorf("unknown platform: %s", platform)
}
Expand Down Expand Up @@ -79,8 +83,8 @@ func installCommands(projectRoot string, platform string, local bool) (string, i

// Make path relative for display
displayPath := destDir
if strings.HasPrefix(destDir, homeDir) {
displayPath = "~" + strings.TrimPrefix(destDir, homeDir)
if homeDir != "" && strings.HasPrefix(destDir, homeDir) {
displayPath = filepath.Join("~", strings.TrimPrefix(destDir, homeDir))
}

return displayPath, count, nil
Expand All @@ -100,6 +104,39 @@ func transformCodex(filename, content string) (string, string) {
return filename, content
}

func transformCopilot(filename, content string) (string, string) {
name := strings.TrimSuffix(filename, ".md")
newFilename := name + ".prompt.md"

// Extract description from existing frontmatter
description := ""
body := content
if strings.HasPrefix(content, "---\n") {
if end := strings.Index(content[4:], "\n---\n"); end != -1 {
frontmatter := content[4 : 4+end]
body = content[4+end+5:]

for _, line := range strings.Split(frontmatter, "\n") {
if strings.HasPrefix(line, "description:") {
description = strings.TrimSpace(strings.TrimPrefix(line, "description:"))
description = strings.Trim(description, `"'`)
break
}
}
}
}

if description == "" {
description = "FPF command: " + name
}

// Build Copilot prompt file with its frontmatter format
result := fmt.Sprintf("---\ndescription: \"%s\"\nname: \"%s\"\nagent: \"agent\"\n---\n%s",
description, name, body)

return newFilename, result
}

func transformGemini(filename, content string) (string, string) {
name := strings.TrimSuffix(filename, ".md")
newFilename := name + ".toml"
Expand Down
Loading