Skip to content
Closed
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
19 changes: 18 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,21 @@ coverage
.vscode
*.suo
*.lock
src/utils/vendor/
src/utils/vendor/

# AI tool runtime directories
.agents/
.codex/
.omx/

# Binary / screenshot files (root only)
/*.png
*.bmp

# Agent / tool state dirs
.swarm/
.agents/__pycache__/

# Python bytecode
__pycache__/
*.pyc
18 changes: 1 addition & 17 deletions DEV-LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

## Computer Use Windows 增强:窗口绑定截图 + UI Automation + OCR (2026-04-03)


在三平台基础实现之上,利用 Windows 原生 API 增强 Computer Use 的 Windows 专属能力。

**新增文件:**
Expand Down Expand Up @@ -118,23 +119,6 @@ packages/@ant/computer-use-{input,swift}/src/
| `vendor/audio-capture/{platform}/audio-capture.node` | 6 个平台的原生音频二进制(cpal,来自参考项目) |
| `vendor/audio-capture-src/index.ts` | 原生模块加载器(按 `${arch}-${platform}` 动态 require `.node`) |

**修改文件:**

| 文件 | 变更 |
|------|------|
| `packages/audio-capture-napi/src/index.ts` | SoX 子进程 stub → 原生 `.node` 加载器(含 `process.cwd()` workspace 路径 fallback) |
| `scripts/dev.ts` | `DEFAULT_FEATURES` 加 `"VOICE_MODE"` |
| `build.ts` | `DEFAULT_BUILD_FEATURES` 加 `"VOICE_MODE"` |
| `docs/features/voice-mode.md` | 追加恢复计划章节(第八节) |

**验证结果:**

- `isNativeAudioAvailable()` → `true`(Windows x64 原生 `.node` 加载成功)
- `feature('VOICE_MODE')` → `ENABLED`
- `bun run build` → voice 代码编入产物

**运行时前置条件:** claude.ai OAuth 登录 + 麦克风权限

---

## Enable Claude in Chrome MCP (2026-04-03)
Expand Down
88 changes: 44 additions & 44 deletions build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,62 @@ import { readdir, readFile, writeFile, cp } from "fs/promises";
import { join } from "path";
import { getMacroDefines } from "./scripts/defines.ts";

const outdir = "dist";
const outdir = 'dist'

// Step 1: Clean output directory
const { rmSync } = await import("fs");
rmSync(outdir, { recursive: true, force: true });
const { rmSync } = await import('fs')
rmSync(outdir, { recursive: true, force: true })

// Default features that match the official CLI build.
// Additional features can be enabled via FEATURE_<NAME>=1 env vars.
const DEFAULT_BUILD_FEATURES = ["AGENT_TRIGGERS_REMOTE", "CHICAGO_MCP", "VOICE_MODE"];

// Collect FEATURE_* env vars → Bun.build features
const envFeatures = Object.keys(process.env)
.filter(k => k.startsWith("FEATURE_"))
.map(k => k.replace("FEATURE_", ""));
const features = [...new Set([...DEFAULT_BUILD_FEATURES, ...envFeatures])];
.filter(k => k.startsWith('FEATURE_'))
.map(k => k.replace('FEATURE_', ''))
const features = [...new Set([...DEFAULT_BUILD_FEATURES, ...envFeatures])]

// Step 2: Bundle with splitting
const result = await Bun.build({
entrypoints: ["src/entrypoints/cli.tsx"],
outdir,
target: "bun",
splitting: true,
define: getMacroDefines(),
features,
});
entrypoints: ['src/entrypoints/cli.tsx'],
outdir,
target: 'bun',
splitting: true,
define: getMacroDefines(),
features,
})

if (!result.success) {
console.error("Build failed:");
for (const log of result.logs) {
console.error(log);
}
process.exit(1);
console.error('Build failed:')
for (const log of result.logs) {
console.error(log)
}
process.exit(1)
}

// Step 3: Post-process — replace Bun-only `import.meta.require` with Node.js compatible version
const files = await readdir(outdir);
const IMPORT_META_REQUIRE = "var __require = import.meta.require;";
const COMPAT_REQUIRE = `var __require = typeof import.meta.require === "function" ? import.meta.require : (await import("module")).createRequire(import.meta.url);`;
const files = await readdir(outdir)
const IMPORT_META_REQUIRE = 'var __require = import.meta.require;'
const COMPAT_REQUIRE = `var __require = typeof import.meta.require === "function" ? import.meta.require : (await import("module")).createRequire(import.meta.url);`

let patched = 0;
let patched = 0
for (const file of files) {
if (!file.endsWith(".js")) continue;
const filePath = join(outdir, file);
const content = await readFile(filePath, "utf-8");
if (content.includes(IMPORT_META_REQUIRE)) {
await writeFile(
filePath,
content.replace(IMPORT_META_REQUIRE, COMPAT_REQUIRE),
);
patched++;
}
if (!file.endsWith('.js')) continue
const filePath = join(outdir, file)
const content = await readFile(filePath, 'utf-8')
if (content.includes(IMPORT_META_REQUIRE)) {
await writeFile(
filePath,
content.replace(IMPORT_META_REQUIRE, COMPAT_REQUIRE),
)
patched++
}
}

console.log(
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for Node.js compat)`,
);
`Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for Node.js compat)`,
)

// Step 4: Copy native .node addon files (audio-capture)
const vendorDir = join(outdir, "vendor", "audio-capture");
Expand All @@ -66,16 +66,16 @@ console.log(`Copied vendor/audio-capture/ → ${vendorDir}/`);

// Step 5: Bundle download-ripgrep script as standalone JS for postinstall
const rgScript = await Bun.build({
entrypoints: ["scripts/download-ripgrep.ts"],
outdir,
target: "node",
});
entrypoints: ['scripts/download-ripgrep.ts'],
outdir,
target: 'node',
})
if (!rgScript.success) {
console.error("Failed to bundle download-ripgrep script:");
for (const log of rgScript.logs) {
console.error(log);
}
// Non-fatal — postinstall fallback to bun run scripts/download-ripgrep.ts
console.error('Failed to bundle download-ripgrep script:')
for (const log of rgScript.logs) {
console.error(log)
}
// Non-fatal — postinstall fallback to bun run scripts/download-ripgrep.ts
} else {
console.log(`Bundled download-ripgrep script to ${outdir}/`);
console.log(`Bundled download-ripgrep script to ${outdir}/`)
}
Loading
Loading