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
4 changes: 2 additions & 2 deletions plugins/cua/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"integrityDescriptor": "runtime/${target.platform}/${arch}/integrity.json",
"adapterContract": {
"hostBundleId": "com.wefonk.deepchat",
"driverVersion": "0.17.0",
"driverVersion": "0.19.2",
"contractVersion": "0.6.0",
"toolsListSchemaVersion": "1",
"capabilityVersion": "1",
Expand All @@ -47,7 +47,7 @@
"mode": "user-confirmed",
"provider": "trycua",
"strategy": "bundled-plugin-helper",
"minVersion": "0.17.0",
"minVersion": "0.19.2",
"guideUrl": "https://cua.ai/docs/cua-driver/guide/getting-started/installation"
}
},
Expand Down
32 changes: 16 additions & 16 deletions plugins/cua/vendor/cua-driver/upstream.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@
"sourceKind": "upstream-release",
"upstreamRepo": "https://github.com/trycua/cua.git",
"upstreamSubdir": "libs/cua-driver/rust",
"tag": "cua-driver-rs-v0.17.0",
"commit": "10279552e2bbe479e367a082f78b1b98ee85a697",
"version": "0.17.0",
"updatedAt": "2026-08-03",
"releaseUrl": "https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.17.0",
"tag": "cua-driver-rs-v0.19.2",
"commit": "20bb34b16ad7c6c56221c332e46b1875e9d8af8c",
"version": "0.19.2",
"updatedAt": "2026-08-07",
"releaseUrl": "https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.19.2",
"checksumsAsset": "checksums.txt",
"checksumsSha256": "a3d58c35df49b35c63135a5b969879a7bd831f7d59d9d76b44c6c341ce1bfd7f",
"checksumsSha256": "2aa497943793980bba915ebd6ebfab3aae9b7837064464055804862fd03068b4",
"supportedTargets": ["darwin/arm64", "darwin/x64", "win32/x64", "win32/arm64", "linux/x64"],
"unsupportedTargets": ["linux/arm64"],
"assets": {
"darwin-arm64": {
"name": "cua-driver-rs-0.17.0-darwin-arm64.tar.gz",
"sha256": "55ed672850492080ff4e7dab4948b4f3bc70c3b84884a89b1eb8521a5d8177a8"
"name": "cua-driver-rs-0.19.2-darwin-arm64.tar.gz",
"sha256": "c30a81f6b5cfd44d40653f7549d7d714b445e9cbd0ed012c4c524f1c43d2872b"
},
"darwin-x64": {
"name": "cua-driver-rs-0.17.0-darwin-x86_64.tar.gz",
"sha256": "cbabf2f71a25b6b158a42384b775d3a75fac15185280d2036d175ee8b49301ae"
"name": "cua-driver-rs-0.19.2-darwin-x86_64.tar.gz",
"sha256": "a9c0ae771f984077dfaddde50f340e52e8b9919f2b8f5917f44334bce92e92de"
},
"windows-x64": {
"name": "cua-driver-rs-0.17.0-windows-x86_64-binary.zip",
"sha256": "f7e366edc4b7148b4f6f78957782b2a2d962620b0daaeb99df7cf9dce6176193"
"name": "cua-driver-rs-0.19.2-windows-x86_64-binary.zip",
"sha256": "9868b60999e64ed1028a0f65082624dab7523b06f33b68d582fa0a187d1bf618"
},
"windows-arm64": {
"name": "cua-driver-rs-0.17.0-windows-arm64-binary.zip",
"sha256": "bd3febdabff06331efd0951495f34ef7a5fb2cc230fd5270bd34292bc7ee036a"
"name": "cua-driver-rs-0.19.2-windows-arm64-binary.zip",
"sha256": "3976148f985912d03c1876766284898dfbe672db5cc2daa2fb03a0ccb755a1fd"
},
"linux-x64": {
"name": "cua-driver-rs-0.17.0-linux-x86_64-binary.tar.gz",
"sha256": "d8fc3e69fc83f01e6c3a70acef1b16e59a2dfc3c91aa98276360a6d211a61017"
"name": "cua-driver-rs-0.19.2-linux-x86_64-binary.tar.gz",
"sha256": "13372e584fcfe4020fe0c5a70ac8d4f0e1c37125f104702d0156d0dddf98fc15"
}
},
"releasePolicy": "Stage pinned upstream release assets at build time. Do not run upstream installers or require PATH-installed runtime binaries for the bundled DeepChat plugin."
Expand Down
19 changes: 14 additions & 5 deletions scripts/build-cua-plugin-runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from './cua-macos-contract.mjs'
import { signMacHelper } from './sign-cua-helper.mjs'
import { parseCuaToolCatalog } from './cua-tool-catalog-contract.mjs'
import { writeCuaRuntimeIntegrityDescriptor } from './package-plugin.mjs'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const rootDir = process.env.DEEPCHAT_ROOT_DIR
Expand Down Expand Up @@ -675,12 +676,12 @@ export function enforceDarwinLoadPathContract(

async function signDarwinHelper(runtimeDir, targetPlatform, packagePurpose) {
if (targetPlatform !== 'darwin' || process.platform !== 'darwin') {
return
return null
}
ensureTool('codesign', ['--version'])
const helperAppPath = path.join(runtimeDir, darwinHelperAppDirName)
const entitlementsPath = path.join(pluginDir, 'build', 'entitlements.plist')
await signMacHelper({
return signMacHelper({
appPath: helperAppPath,
entitlementsPath,
purpose: packagePurpose,
Expand Down Expand Up @@ -734,19 +735,27 @@ async function main() {
if (targetPlatform === 'darwin' && process.platform === 'darwin') {
enforceDarwinLoadPathContract(executable)
}
await signDarwinHelper(runtimeDir, targetPlatform, packagePurpose)
const signingResult = await signDarwinHelper(runtimeDir, targetPlatform, packagePurpose)
smokeCheck(executable, targetPlatform, targetArch)
await generateCuaToolCatalog(
executable,
path.join(runtimeDir, 'tool-catalog.json'),
metadata.version
)

const relativeRuntimePath = path.relative(rootDir, runtimeDir)
const stat = await fs.stat(executable)
if (stat.size === 0) {
throw new Error('Staged CUA runtime is invalid')
}
const { descriptorPath } = writeCuaRuntimeIntegrityDescriptor(pluginDir, {
targetPlatform,
targetArch,
purpose: signingResult?.purpose ?? packagePurpose
})
console.log(
`Generated CUA runtime integrity descriptor: ${path.relative(rootDir, descriptorPath)}`
)

const relativeRuntimePath = path.relative(rootDir, runtimeDir)
console.log(`CUA Driver ${metadata.tag} staged at ${relativeRuntimePath}`)
} catch (error) {
buildError = error
Expand Down
103 changes: 83 additions & 20 deletions scripts/package-plugin.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
import { createHash } from 'node:crypto'
import { createHash, randomUUID } from 'node:crypto'
import { pathToFileURL } from 'node:url'
import { zipSync } from 'fflate'
import { readCuaToolCatalog } from './cua-tool-catalog-contract.mjs'
import { CUA_DARWIN_ALLOWED_ENTITLEMENTS } from './cua-macos-contract.mjs'
Expand All @@ -14,7 +15,7 @@ const CUA_PLUGIN_ID = 'com.deepchat.plugins.cua'
const CUA_INTEGRITY_DESCRIPTOR_NAME = 'integrity.json'
const CUA_EMBEDDED_ADAPTER_CONTRACT = Object.freeze({
hostBundleId: 'com.wefonk.deepchat',
driverVersion: '0.17.0',
driverVersion: '0.19.2',
contractVersion: '0.6.0',
toolsListSchemaVersion: '1',
capabilityVersion: '1',
Expand Down Expand Up @@ -654,6 +655,60 @@ export function createCuaRuntimeIntegrityDescriptor(files, manifest, args) {
}
}

export function writeCuaRuntimeIntegrityDescriptor(pluginDir, args) {
const sourceManifest = readManifest(pluginDir)
const manifest = createPackageManifest(sourceManifest, {
version: sourceManifest.version,
releaseVersionFromRoot: false,
targetPlatform: args.targetPlatform,
targetArch: args.targetArch
})
const files = collectFiles(pluginDir, pluginDir, {}, manifest, args)
const descriptor = createCuaRuntimeIntegrityDescriptor(files, manifest, args)
const descriptorRelativePath = assertSafeRelativePath(
manifest.runtime.integrityDescriptor,
'CUA runtime integrity descriptor'
)
const descriptorPath = path.join(pluginDir, ...descriptorRelativePath.split('/'))
const temporaryPath = path.join(
path.dirname(descriptorPath),
`.${path.basename(descriptorPath)}-${randomUUID()}.tmp`
)
const backupPath = `${temporaryPath}.backup`
fs.mkdirSync(path.dirname(descriptorPath), { recursive: true })
try {
fs.writeFileSync(temporaryPath, `${JSON.stringify(descriptor, null, 2)}\n`, { flag: 'wx' })
try {
fs.renameSync(temporaryPath, descriptorPath)
} catch (error) {
if (
!(error instanceof Error) ||
!['EEXIST', 'EPERM'].includes(error.code)
) {
throw error
}
fs.renameSync(descriptorPath, backupPath)
try {
fs.renameSync(temporaryPath, descriptorPath)
} catch (replacementError) {
try {
fs.renameSync(backupPath, descriptorPath)
} catch (restoreError) {
throw new AggregateError(
[replacementError, restoreError],
'CUA runtime integrity descriptor replacement and rollback failed'
)
}
throw replacementError
}
fs.rmSync(backupPath, { force: true })
}
} finally {
fs.rmSync(temporaryPath, { force: true })
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
return { descriptor, descriptorPath }
}

function packagePlugin(pluginDir, outDir, manifest, args) {
const files = collectFiles(pluginDir, pluginDir, {}, manifest, args)
files['plugin.json'] = {
Expand Down Expand Up @@ -686,22 +741,30 @@ function packagePlugin(pluginDir, outDir, manifest, args) {
return outPath
}

try {
const args = parseArgs(process.argv.slice(2))
const sourceManifest = readManifest(args.pluginDir)
const manifest = createPackageManifest(sourceManifest, args)
validateManifest(args.pluginDir, manifest)
if (!isManifestTargetSupported(manifest, args.targetPlatform, args.targetArch)) {
throw new Error(`Plugin ${manifest.id} does not support ${targetKey(args.targetPlatform, args.targetArch)}`)
}
scopeCuaToolPolicyToTarget(args.pluginDir, manifest, args)
validateCuaRuntime(args.pluginDir, manifest, args)
if (args.validateOnly) {
console.log(`Plugin ${manifest.id}@${manifest.version} is valid`)
} else {
const outPath = packagePlugin(args.pluginDir, args.outDir, manifest, args)
console.log(`Packaged ${manifest.id}@${manifest.version}: ${outPath}`)
}
} catch (error) {
fail(error instanceof Error ? error.message : String(error))
function main() {
try {
const args = parseArgs(process.argv.slice(2))
const sourceManifest = readManifest(args.pluginDir)
const manifest = createPackageManifest(sourceManifest, args)
validateManifest(args.pluginDir, manifest)
if (!isManifestTargetSupported(manifest, args.targetPlatform, args.targetArch)) {
throw new Error(
`Plugin ${manifest.id} does not support ${targetKey(args.targetPlatform, args.targetArch)}`
)
}
scopeCuaToolPolicyToTarget(args.pluginDir, manifest, args)
validateCuaRuntime(args.pluginDir, manifest, args)
if (args.validateOnly) {
console.log(`Plugin ${manifest.id}@${manifest.version} is valid`)
} else {
const outPath = packagePlugin(args.pluginDir, args.outDir, manifest, args)
console.log(`Packaged ${manifest.id}@${manifest.version}: ${outPath}`)
}
} catch (error) {
fail(error instanceof Error ? error.message : String(error))
}
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
main()
}
2 changes: 1 addition & 1 deletion src/main/plugin/cuaToolAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const CUA_DEGRADED_REASON_CODES = [
const CUA_WINDOW_ESCALATION_TARGETS = new Set(['px', 'foreground'])

const CUA_REFUSAL_CODE_PATTERN = /^[a-z][a-z0-9_]{0,127}$/
// Lexical trust-boundary checks for the exact 0.17.0 contract. Callers still treat both handles
// Lexical trust-boundary checks for cua-driver-contract 0.6.0. Callers still treat both handles
// as opaque and never derive, increment, or synthesize them.
const CUA_SNAPSHOT_ID_PATTERN = /^s[0-9a-f]{8}$/
const CUA_ELEMENT_TOKEN_PATTERN = /^s[0-9a-f]{8}:[0-9]+$/
Expand Down
4 changes: 2 additions & 2 deletions test/main/plugin/cuaEmbeddedAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ vi.mock('node:fs', async () => {

const contract: CuaEmbeddedRuntimeContract = {
hostBundleId: 'com.wefonk.deepchat',
driverVersion: '0.17.0',
driverVersion: '0.19.2',
contractVersion: '0.6.0',
toolsListSchemaVersion: '1',
capabilityVersion: '1',
Expand All @@ -40,7 +40,7 @@ const cuaEnvironment = {
}

const metadata = (pid: number): CuaDaemonMetadata => ({
driver_version: '0.17.0',
driver_version: '0.19.2',
contract_version: '0.6.0',
tools_list_schema_version: '1',
capability_version: '1',
Expand Down
34 changes: 17 additions & 17 deletions test/main/plugin/pluginService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1785,13 +1785,13 @@ describe('PluginService', () => {
)
expect(manifest.runtime.adapterContract).toEqual({
hostBundleId: 'com.wefonk.deepchat',
driverVersion: '0.17.0',
driverVersion: '0.19.2',
contractVersion: '0.6.0',
toolsListSchemaVersion: '1',
capabilityVersion: '1',
mcpProtocolVersion: '2025-06-18'
})
expect(manifest.runtime.install.minVersion).toBe('0.17.0')
expect(manifest.runtime.install.minVersion).toBe('0.19.2')
expect(server.args).toEqual(['mcp', '--embedded'])
expect(server.env).toBeUndefined()
expect(mcpConfig.env).toBeUndefined()
Expand All @@ -1812,7 +1812,7 @@ describe('PluginService', () => {
)
})

it('keeps CUA v0.17.0 tool policies explicit and conservative', async () => {
it('keeps CUA v0.19.2 tool policies explicit and conservative', async () => {
const manifest = JSON.parse(await readFile('plugins/cua/plugin.json', 'utf8'))
const policy = JSON.parse(await readFile('plugins/cua/policies/tool-policy.json', 'utf8'))
const manifestTools = manifest.toolPolicies.find(
Expand Down Expand Up @@ -1924,33 +1924,33 @@ describe('PluginService', () => {
sourceKind: 'upstream-release',
upstreamRepo: 'https://github.com/trycua/cua.git',
upstreamSubdir: 'libs/cua-driver/rust',
tag: 'cua-driver-rs-v0.17.0',
commit: '10279552e2bbe479e367a082f78b1b98ee85a697',
version: '0.17.0',
checksumsSha256: 'a3d58c35df49b35c63135a5b969879a7bd831f7d59d9d76b44c6c341ce1bfd7f',
tag: 'cua-driver-rs-v0.19.2',
commit: '20bb34b16ad7c6c56221c332e46b1875e9d8af8c',
version: '0.19.2',
checksumsSha256: '2aa497943793980bba915ebd6ebfab3aae9b7837064464055804862fd03068b4',
supportedTargets: ['darwin/arm64', 'darwin/x64', 'win32/x64', 'win32/arm64', 'linux/x64'],
unsupportedTargets: ['linux/arm64']
})
expect(metadata.assets).toEqual({
'darwin-arm64': {
name: 'cua-driver-rs-0.17.0-darwin-arm64.tar.gz',
sha256: '55ed672850492080ff4e7dab4948b4f3bc70c3b84884a89b1eb8521a5d8177a8'
name: 'cua-driver-rs-0.19.2-darwin-arm64.tar.gz',
sha256: 'c30a81f6b5cfd44d40653f7549d7d714b445e9cbd0ed012c4c524f1c43d2872b'
},
'darwin-x64': {
name: 'cua-driver-rs-0.17.0-darwin-x86_64.tar.gz',
sha256: 'cbabf2f71a25b6b158a42384b775d3a75fac15185280d2036d175ee8b49301ae'
name: 'cua-driver-rs-0.19.2-darwin-x86_64.tar.gz',
sha256: 'a9c0ae771f984077dfaddde50f340e52e8b9919f2b8f5917f44334bce92e92de'
},
'windows-x64': {
name: 'cua-driver-rs-0.17.0-windows-x86_64-binary.zip',
sha256: 'f7e366edc4b7148b4f6f78957782b2a2d962620b0daaeb99df7cf9dce6176193'
name: 'cua-driver-rs-0.19.2-windows-x86_64-binary.zip',
sha256: '9868b60999e64ed1028a0f65082624dab7523b06f33b68d582fa0a187d1bf618'
},
'windows-arm64': {
name: 'cua-driver-rs-0.17.0-windows-arm64-binary.zip',
sha256: 'bd3febdabff06331efd0951495f34ef7a5fb2cc230fd5270bd34292bc7ee036a'
name: 'cua-driver-rs-0.19.2-windows-arm64-binary.zip',
sha256: '3976148f985912d03c1876766284898dfbe672db5cc2daa2fb03a0ccb755a1fd'
},
'linux-x64': {
name: 'cua-driver-rs-0.17.0-linux-x86_64-binary.tar.gz',
sha256: 'd8fc3e69fc83f01e6c3a70acef1b16e59a2dfc3c91aa98276360a6d211a61017'
name: 'cua-driver-rs-0.19.2-linux-x86_64-binary.tar.gz',
sha256: '13372e584fcfe4020fe0c5a70ac8d4f0e1c37125f104702d0156d0dddf98fc15'
}
})
for (const asset of Object.values(metadata.assets) as Array<{ sha256: string }>) {
Expand Down
Loading