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
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

on:
push:
branches:
- master
pull_request:

# Cancel superseded runs on the same ref to save CI minutes.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

# Least privilege: this workflow only reads the repository.
permissions:
contents: read

jobs:
build:
name: Typecheck & Lint
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

# Phase 1: install root deps only, skipping workspace packages entirely.
# npm --ignore-scripts does NOT suppress `prepare` for local workspace
# packages (known npm v7+ behaviour). --workspaces=false avoids linking
# the `cli` workspace so its prepare script never runs here.
- name: Install root dependencies
run: npm install --workspaces=false --ignore-scripts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# grpc-tools postinstall is skipped above; provide a system protoc
# as the fallback in build-proto.mjs.
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

# Phase 2: generate protos before the cli workspace is installed so
# that cli's prepare (tsc) can resolve the generated types.
- name: Generate Protocol Buffers
run: npm run protos

# Phase 3: install the cli workspace. Its prepare script now runs
# successfully because the generated proto files already exist.
- name: Install cli workspace
run: npm install --workspace=cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Phase 4: webview-ui is not a declared workspace; install its deps
# so that `check-types` can run `tsc --noEmit` inside it.
- name: Install webview-ui dependencies
run: cd webview-ui && npm install
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# check-types re-runs protos (idempotent) then runs tsc for root,
# webview-ui, and cli.
- name: Check types
run: npm run check-types

- name: Lint
run: npm run lint

test:
name: Unit Tests (non-blocking)
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install root dependencies
run: npm install --workspaces=false --ignore-scripts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

- name: Generate Protocol Buffers
run: npm run protos

- name: Install cli workspace
run: npm install --workspace=cli
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# The mocha unit suite is currently fragile in CI (ts-node ESM +
# VS Code shims). It runs non-blocking so it surfaces failures as a
# signal without gating merges; hardening it is tracked separately.
- name: Run unit tests
run: npm run test:unit
continue-on-error: true
1 change: 0 additions & 1 deletion cli/src/utils/__tests__/ailiance-memory.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import * as fs from "fs/promises"
import * as path from "path"
import * as os from "os"
import {
deleteMemory,
findMemories,
Expand Down
61 changes: 60 additions & 1 deletion scripts/build-proto.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import chalk from "chalk"
import { execSync } from "child_process"
import * as fsSync from "fs"
import * as fs from "fs/promises"
import { globby } from "globby"
import { createRequire } from "module"
Expand All @@ -12,7 +13,65 @@ import { main as generateHostBridgeClient } from "./generate-host-bridge-client.
import { main as generateProtoBusSetup } from "./generate-protobus-setup.mjs"

const require = createRequire(import.meta.url)
const PROTOC = path.join(require.resolve("grpc-tools"), "../bin/protoc")

// Resolve the `protoc` binary with a fallback chain so the build does not
// hard-fail when grpc-tools failed to download its bundled binary on install.
function resolveProtoc() {
const isWin = process.platform === "win32"

// 1. Bundled grpc-tools binary keeps priority for version consistency.
try {
const grpcToolsDir = path.dirname(require.resolve("grpc-tools/package.json"))
const bundled = path.join(grpcToolsDir, "bin", isWin ? "protoc.exe" : "protoc")
fsSync.accessSync(bundled, fsSync.constants.X_OK)
return bundled
} catch {
// Fall through to a system protoc.
}

// 2. A `protoc` available on the PATH.
const lookup = isWin ? "where" : "which"
try {
const found = execSync(`${lookup} protoc`, { stdio: ["ignore", "pipe", "ignore"] })
.toString()
.split(/\r?\n/)[0]
.trim()
if (found) {
console.warn(
chalk.yellow(
`grpc-tools protoc missing; using system protoc at ${found}. ` +
`Generated code may differ if its version diverges from grpc-tools.`,
),
)
return found
}
} catch {
// `which`/`where` found nothing.
}

// 3. Last resort: trust `protoc` if it answers on the PATH.
try {
execSync("protoc --version", { stdio: "ignore" })
console.warn(chalk.yellow("grpc-tools protoc missing; using `protoc` from PATH."))
return "protoc"
} catch {
// No protoc anywhere.
}

console.error(
chalk.red(
"Could not find a `protoc` binary.\n" +
"The grpc-tools bundled binary is missing (its postinstall download likely failed)\n" +
"and no `protoc` was found on your PATH.\n" +
"Fix this by either:\n" +
" - installing protoc (e.g. `brew install protobuf` or your distro's package), or\n" +
" - reinstalling grpc-tools (`npm install grpc-tools --force`) to restore the bundled binary.",
),
)
process.exit(1)
}

const PROTOC = resolveProtoc()

const PROTO_DIR = path.resolve("proto")
const TS_OUT_DIR = path.resolve("src/shared/proto")
Comment on lines +74 to 77
Expand Down
6 changes: 1 addition & 5 deletions src/utils/ailiance-memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,7 @@ async function quarantineCorruptMemory(filePath: string, reason: string): Promis
try {
await fs.rename(filePath, quarantinedPath)
const msg = `[ailiance-memory] corrupt memory file quarantined: ${filePath} → ${quarantinedPath} (${reason})`
try {
Logger.warn(msg)
} catch {
console.warn(msg)
}
Logger.warn(msg)
} catch {
// Quarantine failed (file vanished, permissions, etc.) — silent.
}
Expand Down
Loading