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
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ Be respectful, kind, and constructive. We welcome contributors of all background
### Prerequisites

- Node.js (LTS recommended)
- npm
- Rust toolchain (install via rustup)
- Tauri dependencies for desktop development
- pnpm (run `corepack enable`)
- Rust toolchain (install via [rustup](https://rustup.rs/))
- [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for desktop development

### Install dependencies

```bash
npm install
pnpm install
```

### Common commands
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
### 环境准备

- Node.js(建议 LTS 版本)
- npm
- pnpm(执行 `corepack enable`)
- Rust toolchain(通过 rustup 安装)
- 桌面端开发需准备 Tauri 依赖

### 安装依赖

```bash
npm install
pnpm install
```

### 常用命令
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,35 @@ BitFun is an Agentic Development Environment (ADE). While featuring a cutting-ed


## Quick Start

### Use Directly

Download the latest installer for the desktop app from [Release](https://github.com/GCWing/BitFun/releases). After installation, configure your model and you're ready to go.

Other form factors are currently only specification drafts and not yet developed. If needed, please build from source.

### Build from Source

Make sure you have the following prerequisites installed:

- Node.js (LTS recommended)
- pnpm (run `corepack enable`)
- Rust toolchain (install via [rustup](https://rustup.rs/))
- [Tauri prerequisites](https://v2.tauri.app/start/prerequisites/) for desktop development

```bash
# Install dependencies
pnpm install

# Run desktop app in development mode
npm run desktop:dev

# Build desktop app
npm run desktop:build
```

For more details, see the [Contributing Guide](./CONTRIBUTING.md).

## Platform Support

The project uses a Rust + TypeScript tech stack, supporting cross-platform and multi-form-factor reuse.
Expand Down
27 changes: 26 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,35 @@ BitFun 是一款代理式开发环境(ADE,Agentic Development Environment)


## 快速开始
桌面端程序在[Release](https://github.com/GCWing/BitFun/releases)处下载最新安装包,安装后配置模型即可开始使用。

### 直接使用

桌面端程序在 [Release](https://github.com/GCWing/BitFun/releases) 处下载最新安装包,安装后配置模型即可开始使用。

其他形态暂时仅是规范雏形未完成开发,如有需要请从源码构建。

### 从源码构建

请确保已安装以下前置依赖:

- Node.js(推荐 LTS 版本)
- pnpm(执行 `corepack enable`)
- Rust 工具链(通过 [rustup](https://rustup.rs/) 安装)
- [Tauri 前置依赖](https://v2.tauri.app/start/prerequisites/)(桌面端开发需要)

```bash
# 安装依赖
pnpm install

# 以开发模式运行桌面端
npm run desktop:dev

# 构建桌面端
npm run desktop:build
```

更多详情请参阅[贡献指南](./CONTRIBUTING_CN.md)。

## 平台支持

项目采用 Rust + TypeScript 技术栈,支持跨平台和多形态复用。
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
"build:web": "cd src/web-ui && vite build",
"preview": "cd src/web-ui && vite preview",
"desktop:dev": "node scripts/dev.cjs desktop",
"desktop:dev:raw": "cd src/apps/desktop && cargo tauri dev",
"desktop:build": "npm run build:web && cd src/apps/desktop && cargo tauri build",
"desktop:build:exe": "npm run build:web && cd src/apps/desktop && cargo tauri build --no-bundle",
"desktop:build:nsis": "npm run build:web && cd src/apps/desktop && cargo tauri build --bundles nsis",
"desktop:build:x86_64": "npm run build:web && cd src/apps/desktop && cargo tauri build --target x86_64-apple-darwin",
"desktop:dev:raw": "cd src/apps/desktop && pnpm tauri dev",
"desktop:build": "npm run build:web && cd src/apps/desktop && pnpm tauri build",
"desktop:build:exe": "npm run build:web && cd src/apps/desktop && pnpm tauri build --no-bundle",
"desktop:build:nsis": "npm run build:web && cd src/apps/desktop && pnpm tauri build --bundles nsis",
"desktop:build:x86_64": "npm run build:web && cd src/apps/desktop && pnpm tauri build --target x86_64-apple-darwin",
"cli:dev": "cd src/apps/cli && cargo run --",
"cli:build": "cd src/apps/cli && cargo build --release",
"cli:run": "cd src/apps/cli && cargo run --release --",
Expand Down Expand Up @@ -52,7 +52,7 @@
"@lezer/highlight": "^1.2.1",
"@monaco-editor/react": "^4.6.0",
"@react-sigma/core": "^5.0.6",
"@tauri-apps/api": "~2.9.0",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.6",
"@tauri-apps/plugin-fs": "^2",
"@tauri-apps/plugin-log": "^2.8.0",
Expand Down
2 changes: 1 addition & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 59 additions & 9 deletions scripts/dev.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,58 @@ const ROOT_DIR = path.resolve(__dirname, '..');
*/
function runSilent(command, cwd = ROOT_DIR) {
try {
execSync(command, {
const stdout = execSync(command, {
cwd,
stdio: 'pipe',
encoding: 'utf-8'
encoding: 'buffer'
});
return true;
return { ok: true, stdout: decodeOutput(stdout), stderr: '' };
} catch (error) {
return false;
const stdout = error.stdout ? decodeOutput(error.stdout) : '';
const stderr = error.stderr ? decodeOutput(error.stderr) : '';
return { ok: false, stdout, stderr, error };
}
}

function decodeOutput(output) {
if (!output) return '';
if (typeof output === 'string') return output;
const buffer = Buffer.isBuffer(output) ? output : Buffer.from(output);
if (process.platform !== 'win32') return buffer.toString('utf-8');

const utf8 = buffer.toString('utf-8');
if (!utf8.includes('�')) return utf8;

try {
const { TextDecoder } = require('util');
const decoder = new TextDecoder('gbk');
const gbk = decoder.decode(buffer);
if (gbk && !gbk.includes('�')) return gbk;
return gbk || utf8;
} catch (error) {
return utf8;
}
}

function tailOutput(output, maxLines = 12) {
if (!output) return '';
const lines = output
.split(/\r?\n/)
.map((line) => line.trimEnd())
.filter((line) => line.trim() !== '');
if (lines.length <= maxLines) return lines.join('\n');
return lines.slice(-maxLines).join('\n');
}

/**
* Run command with inherited output
*/
function runInherit(command, cwd = ROOT_DIR) {
try {
execSync(command, { cwd, stdio: 'inherit' });
return true;
return { ok: true, error: null };
} catch (error) {
return false;
return { ok: false, error };
}
}

Expand Down Expand Up @@ -86,17 +118,35 @@ async function main() {

// Step 1: Copy resources
printStep(1, 3, 'Copy resources');
if (runSilent('npm run copy-monaco --silent')) {
const copyResult = runSilent('npm run copy-monaco --silent');
if (copyResult.ok) {
printSuccess('Monaco Editor resources ready');
} else {
printError('Copy resources failed');
const output = tailOutput(copyResult.stderr || copyResult.stdout);
if (output) {
printError(output);
} else if (copyResult.error) {
printError(copyResult.error.message);
}
if (copyResult.error && copyResult.error.status !== undefined) {
printError(`Exit code: ${copyResult.error.status}`);
}
printInfo('Hint: run `pnpm install` in repo root if dependencies are missing');
process.exit(1);
}

// Step 2: Generate version info
printStep(2, 3, 'Generate version info');
if (!runInherit('node scripts/generate-version.cjs')) {
const versionResult = runInherit('node scripts/generate-version.cjs');
if (!versionResult.ok) {
printError('Generate version info failed');
if (versionResult.error && versionResult.error.message) {
printError(versionResult.error.message);
}
if (versionResult.error && versionResult.error.status !== undefined) {
printError(`Exit code: ${versionResult.error.status}`);
}
process.exit(1);
}

Expand All @@ -110,7 +160,7 @@ async function main() {

try {
if (mode === 'desktop') {
await runCommand('cargo tauri dev', path.join(ROOT_DIR, 'src/apps/desktop'));
await runCommand('pnpm tauri dev', path.join(ROOT_DIR, 'src/apps/desktop'));
} else {
await runCommand('npx vite', path.join(ROOT_DIR, 'src/web-ui'));
}
Expand Down
4 changes: 2 additions & 2 deletions src/apps/desktop/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"version": "0.1.0",
"identifier": "com.bitfun.desktop",
"build": {
"beforeDevCommand": "cd ../.. && npm run dev:web",
"beforeDevCommand": "npm run dev:web",
"devUrl": "http://localhost:1422",
"beforeBuildCommand": "cd ../.. && npm run build:web",
"beforeBuildCommand": "npm run build:web",
"frontendDist": "../../../dist"
},
"bundle": {
Expand Down
1 change: 1 addition & 0 deletions src/crates/core/src/agentic/agents/agentic_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl AgenticMode {
"AnalyzeImage".to_string(),
"Skill".to_string(),
"AskUserQuestion".to_string(),
"Git".to_string(),
],
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const PLACEHOLDER_PROJECT_LAYOUT: &str = "{PROJECT_LAYOUT}";
const PLACEHOLDER_RULES: &str = "{RULES}";
const PLACEHOLDER_MEMORIES: &str = "{MEMORIES}";
const PLACEHOLDER_LANGUAGE_PREFERENCE: &str = "{LANGUAGE_PREFERENCE}";
const PLACEHOLDER_VISUAL_MODE: &str = "{VISUAL_MODE}";

pub struct PromptBuilder {
pub workspace_path: String,
Expand Down Expand Up @@ -156,6 +157,32 @@ These files are maintained by the user and should NOT be modified unless explici
}
}

/// Get visual mode instruction from user config
///
/// Reads `app.ai_experience.enable_visual_mode` from global config.
/// Returns a prompt snippet when enabled, or empty string when disabled.
async fn get_visual_mode_instruction(&self) -> String {
let enabled = match GlobalConfigManager::get_service().await {
Ok(service) => service
.get_config::<bool>(Some("app.ai_experience.enable_visual_mode"))
.await
.unwrap_or(false),
Err(e) => {
debug!("Failed to read visual mode config: {}", e);
false
}
};

if enabled {
r"# Visualizing complex logic as you explain
Use Mermaid diagrams to visualize complex logic, workflows, architectures, and data flows whenever it helps clarify the explanation.
Prefer MermaidInteractive tool when available, otherwise output Mermaid code blocks directly.
".to_string()
} else {
String::new()
}
}

/// Get user language preference instruction
///
/// Read app.language from global config, generate simple language instruction
Expand Down Expand Up @@ -194,6 +221,7 @@ These files are maintained by the user and should NOT be modified unless explici
/// - `{PROJECT_CONTEXT_FILES}` - Project context files (AGENTS.md, CLAUDE.md, etc.)
/// - `{RULES}` - AI rules
/// - `{MEMORIES}` - AI memories
/// - `{VISUAL_MODE}` - Visual mode instruction (Mermaid diagrams, read from global config)
///
/// If a placeholder is not in the template, corresponding content will not be added
pub async fn build_prompt_from_template(&self, template: &str) -> BitFunResult<String> {
Expand Down Expand Up @@ -264,6 +292,12 @@ These files are maintained by the user and should NOT be modified unless explici
result = result.replace(PLACEHOLDER_MEMORIES, &memories);
}

// Replace {VISUAL_MODE}
if result.contains(PLACEHOLDER_VISUAL_MODE) {
let visual_mode = self.get_visual_mode_instruction().await;
result = result.replace(PLACEHOLDER_VISUAL_MODE, &visual_mode);
}

Ok(result.trim().to_string())
}
}
1 change: 1 addition & 0 deletions src/crates/core/src/agentic/agents/prompts/agentic_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ I've found some existing telemetry code. Let me mark the first todo as in_progre
# Asking questions as you work
You have access to the AskUserQuestion tool to ask the user questions when you need clarification, want to validate assumptions, or need to make a decision you're unsure about. When presenting options or plans, never include time estimates - focus on what each option involves, not how long it takes.

{VISUAL_MODE}
# Doing tasks
The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended:
- NEVER propose changes to code you haven't read. If a user asks about or wants you to modify a file, read it first. Understand existing code before suggesting modifications.
Expand Down
11 changes: 8 additions & 3 deletions src/crates/core/src/service/config/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,15 @@ impl GlobalConfigManager {
Ok(())
}

/// Reloads configuration.
/// Reloads configuration in-place.
///
/// Re-reads the config from disk into the existing `ConfigService` instance,
/// preserving the `Arc` pointer so that all holders (e.g. `AppState`) stay in sync.
pub async fn reload() -> BitFunResult<()> {
let new_service = Arc::new(ConfigService::new().await?);
Self::update_service(new_service).await
let service = Self::get_service().await?;
service.reload().await?;
Self::broadcast_update(ConfigUpdateEvent::ConfigReloaded).await;
Ok(())
}

/// Subscribes to configuration update events.
Expand Down
4 changes: 2 additions & 2 deletions src/crates/core/src/service/config/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,8 @@ pub(crate) fn migrate_0_0_0_to_1_0_0(mut config: Value) -> BitFunResult<Value> {
app.insert(
"ai_experience".to_string(),
serde_json::json!({
"enableSessionTitleGeneration": true,
"enableWelcomePanelAiAnalysis": true
"enable_session_title_generation": true,
"enable_welcome_panel_ai_analysis": true
}),
);
}
Expand Down
5 changes: 4 additions & 1 deletion src/crates/core/src/service/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ pub struct AppConfig {

/// AI experience configuration.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
#[serde(default)]
pub struct AIExperienceConfig {
/// Whether to enable automatic AI-generated summaries for session titles.
pub enable_session_title_generation: bool,
/// Whether to enable AI analysis of work status on the FlowChat welcome page.
pub enable_welcome_panel_ai_analysis: bool,
/// Whether to enable visual mode.
pub enable_visual_mode: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -862,6 +864,7 @@ impl Default for AIExperienceConfig {
Self {
enable_session_title_generation: true,
enable_welcome_panel_ai_analysis: true,
enable_visual_mode: false,
}
}
}
Expand Down
Loading