refactor(ai): ship Harness as optional companion (#561)
* Revert "feat(ai): add HarnessAgent sidecar foundation (#560)"
This reverts commit 83a5ea1b42.
* Revert "Revert "feat(ai): add HarnessAgent sidecar foundation (#560)""
This reverts commit 0d8c03515888c62dc47186d4a3b0b7b04e78f8af.
* refactor(ai): ship Harness as optional companion
* fix(ai): support Harness companion on Windows
* test(ai): restore navigator after Harness Windows test
This commit is contained in:
parent
83a5ea1b42
commit
62ba072b26
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
|
|
@ -53,10 +53,6 @@ jobs:
|
||||||
|
|
||||||
- uses: ./.github/actions/setup-bun
|
- uses: ./.github/actions/setup-bun
|
||||||
|
|
||||||
- name: Build Harness sidecar
|
|
||||||
shell: bash
|
|
||||||
run: bun run build:harness-sidecar -- ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Extract release notes
|
- name: Extract release notes
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
id: changelog
|
id: changelog
|
||||||
|
|
@ -110,7 +106,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build packages for publish
|
- name: Build packages for publish
|
||||||
run: |
|
run: |
|
||||||
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/vue"
|
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/harness packages/vue"
|
||||||
for dir in $publish_packages; do
|
for dir in $publish_packages; do
|
||||||
if [ -f "$dir/package.json" ] && node -p "require('./$dir/package.json').scripts?.build" 2>/dev/null | grep -qv undefined; then
|
if [ -f "$dir/package.json" ] && node -p "require('./$dir/package.json').scripts?.build" 2>/dev/null | grep -qv undefined; then
|
||||||
echo "Building $dir..."
|
echo "Building $dir..."
|
||||||
|
|
@ -138,7 +134,7 @@ jobs:
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
root_dir="$PWD"
|
root_dir="$PWD"
|
||||||
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/vue"
|
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/harness packages/vue"
|
||||||
for dir in $publish_packages; do
|
for dir in $publish_packages; do
|
||||||
pack_if_new "$dir"
|
pack_if_new "$dir"
|
||||||
done
|
done
|
||||||
|
|
@ -163,7 +159,7 @@ jobs:
|
||||||
npm publish "./.npm-packages/${tarball}" --access public --provenance
|
npm publish "./.npm-packages/${tarball}" --access public --provenance
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/vue"
|
publish_packages="packages/scene-graph packages/pen packages/kiwi packages/fig packages/core packages/dom-css packages/cli packages/mcp packages/harness packages/vue"
|
||||||
for dir in $publish_packages; do
|
for dir in $publish_packages; do
|
||||||
publish_if_new "$dir"
|
publish_if_new "$dir"
|
||||||
done
|
done
|
||||||
|
|
|
||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -135,9 +135,6 @@ jobs:
|
||||||
|
|
||||||
- uses: ./.github/actions/setup-bun
|
- uses: ./.github/actions/setup-bun
|
||||||
|
|
||||||
- name: Build Harness sidecar
|
|
||||||
run: bun run build:harness-sidecar -- x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
- name: Typecheck native interaction tests
|
- name: Typecheck native interaction tests
|
||||||
run: bun run check:native-test
|
run: bun run check:native-test
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Bun workspace packages:
|
||||||
- `packages/vue` — `@open-pencil/vue`: headless Vue 3 SDK (Reka UI-style) for building custom OpenPencil-powered editor shells and embedded editing surfaces. Renderless components and composables. The app is one consumer of the SDK.
|
- `packages/vue` — `@open-pencil/vue`: headless Vue 3 SDK (Reka UI-style) for building custom OpenPencil-powered editor shells and embedded editing surfaces. Renderless components and composables. The app is one consumer of the SDK.
|
||||||
- `packages/cli` — `@open-pencil/cli`: headless CLI for .fig inspection, export, linting. Uses `citty` + `agentfmt`.
|
- `packages/cli` — `@open-pencil/cli`: headless CLI for .fig inspection, export, linting. Uses `citty` + `agentfmt`.
|
||||||
- `packages/mcp` — `@open-pencil/mcp`: MCP server for AI coding tools. Stdio + HTTP (Hono). Reuses core tools.
|
- `packages/mcp` — `@open-pencil/mcp`: MCP server for AI coding tools. Stdio + HTTP (Hono). Reuses core tools.
|
||||||
- `packages/harness` — `@open-pencil/harness`: private Node sidecar runtime for backend-neutral coding-agent sessions. Owns HarnessAgent adapters, opaque resume-state persistence, and the JSONL host protocol; app/editor integration remains outside the package.
|
- `packages/harness` — `@open-pencil/harness`: optional Node companion CLI for backend-neutral coding-agent sessions. Owns HarnessAgent adapters, opaque resume-state persistence, and the JSONL host protocol; the desktop detects and launches the separately installed command instead of bundling a JavaScript runtime.
|
||||||
- `packages/docs` — `@open-pencil/docs`: published VitePress documentation site. Use `bun run docs:dev` for authoring, `bun run docs:build` for the default fast local render check without minification or generated LLM files, and `bun run docs:build:production` for the complete deployment output.
|
- `packages/docs` — `@open-pencil/docs`: published VitePress documentation site. Use `bun run docs:dev` for authoring, `bun run docs:build` for the default fast local render check without minification or generated LLM files, and `bun run docs:build:production` for the complete deployment output.
|
||||||
|
|
||||||
The root app (`src/`) is the Tauri/Vite desktop editor. App-specific editor, document, AI, collaboration, shell, tabs, demo, and automation code lives under `src/app/*`. The app consumes scene graph primitives from `@open-pencil/scene-graph`, editor/rendering services through targeted `@open-pencil/core` subpath exports, and `@open-pencil/vue` through the public Vue SDK entrypoint.
|
The root app (`src/`) is the Tauri/Vite desktop editor. App-specific editor, document, AI, collaboration, shell, tabs, demo, and automation code lives under `src/app/*`. The app consumes scene graph primitives from `@open-pencil/scene-graph`, editor/rendering services through targeted `@open-pencil/core` subpath exports, and `@open-pencil/vue` through the public Vue SDK entrypoint.
|
||||||
|
|
@ -153,7 +153,7 @@ Release commits are the exception: keep using `Release v0.x.y`.
|
||||||
|
|
||||||
Keep this section light; implementation details move often.
|
Keep this section light; implementation details move often.
|
||||||
|
|
||||||
- Harness-based coding agents live in the private `packages/harness` Node sidecar package rather than the browser app. Keep its session service backend-neutral, persist only opaque non-secret resume state, and expose host integration through its bounded JSONL protocol. Pi may use local `just-bash` for development, but that in-memory sandbox does not provide process-restart recovery.
|
- Harness-based coding agents live in the optional `@open-pencil/harness` Node companion rather than the browser app. Keep its session service backend-neutral, persist only opaque non-secret resume state, and expose host integration through its bounded JSONL protocol. Do not bundle a JavaScript runtime into Tauri; launch the separately installed `openpencil-harness` command. Pi may use local `just-bash`, but that in-memory sandbox does not provide process-restart recovery.
|
||||||
- ACP UI/transport lives under `src/app/ai/acp/**`; provider definitions live in `packages/core/src/constants.ts`; app prompts live under `src/app/ai/**`. Direct model configuration lives under `src/app/ai/models/**`: reusable profiles reference provider connections, roles resolve to profiles, and runtime creation resolves credentials lazily. Keep model profiles, provider connections, and role assignments separate rather than returning to singleton provider/model settings. Public docs: `packages/docs/programmable/ai-chat.md` and `packages/docs/programmable/mcp-server.md`.
|
- ACP UI/transport lives under `src/app/ai/acp/**`; provider definitions live in `packages/core/src/constants.ts`; app prompts live under `src/app/ai/**`. Direct model configuration lives under `src/app/ai/models/**`: reusable profiles reference provider connections, roles resolve to profiles, and runtime creation resolves credentials lazily. Keep model profiles, provider connections, and role assignments separate rather than returning to singleton provider/model settings. Public docs: `packages/docs/programmable/ai-chat.md` and `packages/docs/programmable/mcp-server.md`.
|
||||||
- ACP transport uses Tauri shell permissions, so check `desktop/capabilities/**` when changing agent launch behavior.
|
- ACP transport uses Tauri shell permissions, so check `desktop/capabilities/**` when changing agent launch behavior.
|
||||||
- Collaboration lives under `src/app/collab/**` and is documented in `packages/docs/programmable/collaboration.md`. It uses Trystero + Yjs + awareness; preserve crypto-safe room IDs and peer cleanup semantics when changing it.
|
- Collaboration lives under `src/app/collab/**` and is documented in `packages/docs/programmable/collaboration.md`. It uses Trystero + Yjs + awareness; preserve crypto-safe room IDs and peer cleanup semantics when changing it.
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,8 @@ Not every provider works in the browser, and not every model streams tool calls
|
||||||
|
|
||||||
Use Claude Code, Codex, or Gemini CLI directly in the chat panel. The agent connects to the editor's MCP server and uses all 100+ design tools. Requires the desktop app and the agent CLI installed locally.
|
Use Claude Code, Codex, or Gemini CLI directly in the chat panel. The agent connects to the editor's MCP server and uses all 100+ design tools. Requires the desktop app and the agent CLI installed locally.
|
||||||
|
|
||||||
|
Pi is also available as an optional AI SDK Harness provider. Install its companion CLI with `npm install -g @open-pencil/harness`, then add a **Pi** model profile in **Settings → AI & agents**. The companion is installed separately so OpenPencil does not bundle a JavaScript runtime for users who do not enable Harness providers.
|
||||||
|
|
||||||
**Setup (Claude Code):**
|
**Setup (Claude Code):**
|
||||||
|
|
||||||
1. Install the ACP adapter: `npm install -g @agentclientprotocol/claude-agent-acp`
|
1. Install the ACP adapter: `npm install -g @agentclientprotocol/claude-agent-acp`
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
{ "name": "codex-acp", "cmd": "codex-acp", "args": true },
|
{ "name": "codex-acp", "cmd": "codex-acp", "args": true },
|
||||||
{ "name": "gemini", "cmd": "gemini", "args": true },
|
{ "name": "gemini", "cmd": "gemini", "args": true },
|
||||||
{ "name": "openpencil-mcp-http", "cmd": "openpencil-mcp-http", "args": true },
|
{ "name": "openpencil-mcp-http", "cmd": "openpencil-mcp-http", "args": true },
|
||||||
{ "name": "binaries/openpencil-harness", "sidecar": true, "args": false },
|
{ "name": "openpencil-harness", "cmd": "openpencil-harness", "args": false },
|
||||||
{ "name": "cmd", "cmd": "cmd", "args": true }
|
{ "name": "cmd", "cmd": "cmd", "args": true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"identifier": "net.dannote.open-pencil",
|
"identifier": "net.dannote.open-pencil",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run generate:tauri-menu && bun run build:harness-sidecar && bun run dev",
|
"beforeDevCommand": "bun run generate:tauri-menu && bun run dev",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
"beforeBuildCommand": "bun run generate:tauri-menu && bun run build:harness-sidecar && bun run build",
|
"beforeBuildCommand": "bun run generate:tauri-menu && bun run build",
|
||||||
"frontendDist": "../dist"
|
"frontendDist": "../dist"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
"active": true,
|
"active": true,
|
||||||
"targets": "all",
|
"targets": "all",
|
||||||
"createUpdaterArtifacts": true,
|
"createUpdaterArtifacts": true,
|
||||||
"externalBin": ["binaries/openpencil-harness"],
|
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/32x32.png",
|
"icons/32x32.png",
|
||||||
"icons/128x128.png",
|
"icons/128x128.png",
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"build-storybook": "storybook build",
|
"build-storybook": "storybook build",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"build:harness-sidecar": "bun tools/harness-sidecar/src/build.ts",
|
|
||||||
"build:native-test": "bun run build:packages && bun tauri build --debug --no-bundle --features native-test --config desktop/tauri.native-test.conf.json",
|
"build:native-test": "bun run build:packages && bun tauri build --debug --no-bundle --features native-test --config desktop/tauri.native-test.conf.json",
|
||||||
"test:native": "bun run build:native-test && wdio run wdio.conf.ts",
|
"test:native": "bun run build:native-test && wdio run wdio.conf.ts",
|
||||||
"lint": "bun run lint:structure && oxlint -c oxlint.json --type-aware --type-check src/ packages/scene-graph/src/ packages/core/src/ packages/vue/src/ packages/cli/src/ packages/mcp/src/ packages/harness/src/ packages/dom-css/src/ packages/pen/src/ packages/kiwi/src/ packages/fig/src/",
|
"lint": "bun run lint:structure && oxlint -c oxlint.json --type-aware --type-check src/ packages/scene-graph/src/ packages/core/src/ packages/vue/src/ packages/cli/src/ packages/mcp/src/ packages/harness/src/ packages/dom-css/src/ packages/pen/src/ packages/kiwi/src/ packages/fig/src/",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# @open-pencil/harness
|
# @open-pencil/harness
|
||||||
|
|
||||||
Private Node runtime for coding-agent harness sessions. It owns the backend-neutral session lifecycle, opaque resume-state persistence, and the JSONL sidecar protocol used by host applications.
|
Optional Node companion runtime for coding-agent harness sessions. It owns the backend-neutral session lifecycle, opaque resume-state persistence, and the JSONL sidecar protocol used by host applications.
|
||||||
|
|
||||||
The first backend uses AI SDK `HarnessAgent`, Pi, and local `just-bash`. Pi runs in the Node host process; `just-bash` provides an isolated in-memory workspace and shell without requiring cloud infrastructure.
|
The first backend uses AI SDK `HarnessAgent`, Pi, and local `just-bash`. Pi runs in the Node host process; `just-bash` provides an isolated in-memory workspace and shell without requiring cloud infrastructure.
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ The first backend uses AI SDK `HarnessAgent`, Pi, and local `just-bash`. Pi runs
|
||||||
- JSONL stdio sidecar transport.
|
- JSONL stdio sidecar transport.
|
||||||
- Pi + `just-bash` backend.
|
- Pi + `just-bash` backend.
|
||||||
|
|
||||||
The package is not wired into the desktop application yet. Credentials are supplied to the sidecar process at runtime and are never written to resume-state storage.
|
The package is installed as an optional companion CLI for the desktop application. It is not bundled into every Tauri build; install `@open-pencil/harness` globally to make the `openpencil-harness` command available. Credentials are supplied to the companion process at runtime and are never written to resume-state storage.
|
||||||
|
|
||||||
## Local sandbox limitation
|
## Local sandbox limitation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "@open-pencil/harness",
|
"name": "@open-pencil/harness",
|
||||||
"version": "0.0.0",
|
"version": "0.14.0",
|
||||||
"private": true,
|
"private": false,
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "Optional OpenPencil companion CLI for coding-agent Harness sessions",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
|
|
@ -20,6 +22,16 @@
|
||||||
"test": "bun test tests",
|
"test": "bun test tests",
|
||||||
"typecheck": "bunx tsc --noEmit -p tsconfig.json"
|
"typecheck": "bunx tsc --noEmit -p tsconfig.json"
|
||||||
},
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/open-pencil/open-pencil.git",
|
||||||
|
"directory": "packages/harness"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"provenance": true
|
||||||
|
},
|
||||||
|
"files": ["dist", "README.md"],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/harness": "1.0.74",
|
"@ai-sdk/harness": "1.0.74",
|
||||||
"@ai-sdk/harness-pi": "1.0.76",
|
"@ai-sdk/harness-pi": "1.0.76",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import type { HarnessSidecarMessage } from '@open-pencil/harness'
|
import type { HarnessSidecarMessage } from '@open-pencil/harness'
|
||||||
|
|
||||||
|
import { resolvePlatformCommand } from '@/app/tauri/command'
|
||||||
|
|
||||||
export type HarnessChild = {
|
export type HarnessChild = {
|
||||||
write(data: number[]): Promise<void>
|
write(data: number[]): Promise<void>
|
||||||
kill(): Promise<void>
|
kill(): Promise<void>
|
||||||
|
|
@ -16,7 +18,8 @@ export async function spawnHarnessProcess(options: {
|
||||||
onUnexpectedClose: () => void
|
onUnexpectedClose: () => void
|
||||||
}): Promise<HarnessProcess> {
|
}): Promise<HarnessProcess> {
|
||||||
const { Command } = await import('@tauri-apps/plugin-shell')
|
const { Command } = await import('@tauri-apps/plugin-shell')
|
||||||
const command = Command.sidecar('binaries/openpencil-harness', [], {
|
const resolved = resolvePlatformCommand('openpencil-harness')
|
||||||
|
const command = Command.create(resolved.command, resolved.args, {
|
||||||
encoding: 'raw',
|
encoding: 'raw',
|
||||||
env: options.environment
|
env: options.environment
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,14 @@ afterEach(async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Harness sidecar process', () => {
|
describe('Harness sidecar process', () => {
|
||||||
test('spawns the bundled sidecar and keeps credentials in process environment', async () => {
|
test('spawns the optional companion and keeps credentials in process environment', async () => {
|
||||||
let onEvent: ((event: unknown) => void) | undefined
|
let onEvent: ((event: unknown) => void) | undefined
|
||||||
const calls: Array<{ cmd: string; args: unknown }> = []
|
const calls: Array<{ cmd: string; args: unknown }> = []
|
||||||
await mockTauriIPC((cmd, args) => {
|
await mockTauriIPC((cmd, args) => {
|
||||||
calls.push({ cmd, args })
|
calls.push({ cmd, args })
|
||||||
if (cmd === 'plugin:shell|spawn') {
|
if (cmd === 'plugin:shell|spawn') {
|
||||||
expect(args).toMatchObject({
|
expect(args).toMatchObject({
|
||||||
program: expect.stringContaining('openpencil-harness'),
|
program: 'openpencil-harness',
|
||||||
args: [],
|
args: [],
|
||||||
options: {
|
options: {
|
||||||
encoding: 'raw',
|
encoding: 'raw',
|
||||||
|
|
@ -51,4 +51,33 @@ describe('Harness sidecar process', () => {
|
||||||
JSON.stringify(calls.find((call) => call.cmd === 'plugin:shell|stdin_write'))
|
JSON.stringify(calls.find((call) => call.cmd === 'plugin:shell|stdin_write'))
|
||||||
).not.toContain('secret')
|
).not.toContain('secret')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('routes the npm launcher through cmd on Windows', async () => {
|
||||||
|
const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator')
|
||||||
|
try {
|
||||||
|
Object.defineProperty(globalThis, 'navigator', {
|
||||||
|
configurable: true,
|
||||||
|
value: { userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' }
|
||||||
|
})
|
||||||
|
await mockTauriIPC((cmd, args) => {
|
||||||
|
if (cmd === 'plugin:shell|spawn') {
|
||||||
|
expect(args).toMatchObject({
|
||||||
|
program: 'cmd',
|
||||||
|
args: ['/c', 'openpencil-harness'],
|
||||||
|
options: { encoding: 'raw', env: {} }
|
||||||
|
})
|
||||||
|
return 46
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
const process = await spawnHarnessProcess({
|
||||||
|
environment: {},
|
||||||
|
onUnexpectedClose: () => undefined
|
||||||
|
})
|
||||||
|
await process.child.kill()
|
||||||
|
} finally {
|
||||||
|
if (originalNavigator) Object.defineProperty(globalThis, 'navigator', originalNavigator)
|
||||||
|
else Reflect.deleteProperty(globalThis, 'navigator')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@open-pencil/harness-sidecar-tools",
|
|
||||||
"private": true,
|
|
||||||
"type": "module"
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { execFileSync } from 'node:child_process'
|
|
||||||
import { chmod, mkdir } from 'node:fs/promises'
|
|
||||||
import { join } from 'node:path'
|
|
||||||
|
|
||||||
const hostTarget = (): string => {
|
|
||||||
if (process.platform === 'darwin')
|
|
||||||
return process.arch === 'arm64' ? 'aarch64-apple-darwin' : 'x86_64-apple-darwin'
|
|
||||||
if (process.platform === 'linux' && process.arch === 'x64') return 'x86_64-unknown-linux-gnu'
|
|
||||||
if (process.platform === 'win32') {
|
|
||||||
return process.arch === 'arm64' ? 'aarch64-pc-windows-msvc' : 'x86_64-pc-windows-msvc'
|
|
||||||
}
|
|
||||||
throw new Error(`Unsupported Harness sidecar host: ${process.platform}/${process.arch}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = process.argv[2] ?? process.env.TAURI_ENV_TARGET_TRIPLE ?? hostTarget()
|
|
||||||
const bunTargetByRustTarget: Record<string, string> = {
|
|
||||||
'aarch64-apple-darwin': 'bun-darwin-arm64',
|
|
||||||
'x86_64-apple-darwin': 'bun-darwin-x64',
|
|
||||||
'x86_64-unknown-linux-gnu': 'bun-linux-x64',
|
|
||||||
'x86_64-pc-windows-msvc': 'bun-windows-x64',
|
|
||||||
'aarch64-pc-windows-msvc': 'bun-windows-arm64'
|
|
||||||
}
|
|
||||||
const bunTarget = bunTargetByRustTarget[target]
|
|
||||||
if (!bunTarget) throw new Error(`Unsupported Harness sidecar target: ${target}`)
|
|
||||||
|
|
||||||
const extension = target.includes('windows') ? '.exe' : ''
|
|
||||||
const output = join('desktop', 'binaries', `openpencil-harness-${target}${extension}`)
|
|
||||||
await mkdir(join('desktop', 'binaries'), { recursive: true })
|
|
||||||
execFileSync(
|
|
||||||
'bun',
|
|
||||||
[
|
|
||||||
'build',
|
|
||||||
'--compile',
|
|
||||||
`--target=${bunTarget}`,
|
|
||||||
'packages/harness/src/stdio.ts',
|
|
||||||
'--outfile',
|
|
||||||
output
|
|
||||||
],
|
|
||||||
{ stdio: 'inherit' }
|
|
||||||
)
|
|
||||||
if (!extension) await chmod(output, 0o755)
|
|
||||||
|
|
@ -35,6 +35,7 @@ export const DEFAULT_PACKAGES: PackagePublishConfig[] = [
|
||||||
{ dir: 'packages/dom-css', include: ['dist'], extraFiles: ['README.md'] },
|
{ dir: 'packages/dom-css', include: ['dist'], extraFiles: ['README.md'] },
|
||||||
{ dir: 'packages/cli', include: ['bin', 'dist'], extraFiles: [] },
|
{ dir: 'packages/cli', include: ['bin', 'dist'], extraFiles: [] },
|
||||||
{ dir: 'packages/mcp', include: ['dist'], extraFiles: [] },
|
{ dir: 'packages/mcp', include: ['dist'], extraFiles: [] },
|
||||||
|
{ dir: 'packages/harness', include: ['dist'], extraFiles: ['README.md'] },
|
||||||
{ dir: 'packages/vue', include: ['dist'], extraFiles: ['README.md'] }
|
{ dir: 'packages/vue', include: ['dist'], extraFiles: ['README.md'] }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ describe('DEFAULT_PACKAGES', () => {
|
||||||
'packages/dom-css',
|
'packages/dom-css',
|
||||||
'packages/cli',
|
'packages/cli',
|
||||||
'packages/mcp',
|
'packages/mcp',
|
||||||
|
'packages/harness',
|
||||||
'packages/vue'
|
'packages/vue'
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue