Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,50 @@ jobs:
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
cache-on-failure: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}

# sherpa-onnx-sys downloads its native static libraries from GitHub
# Releases at build time. Hosted runners intermittently fail that
# download (network/rate limits), so pre-fetch and extract the archive
# here, then point SHERPA_ONNX_LIB_DIR at the extracted lib directory.
# The build script uses that variable directly without any cache/rerun
# logic, so both `cargo check` and `cargo test` link against the same
# pre-fetched libraries. Windows is skipped: its archive is already
# cached in the rust-cache path and the previous failures were Linux and
# macOS only.
- name: Pre-download sherpa-onnx native libraries
if: runner.os != 'Windows'
shell: bash
env:
SHERPA_VERSION: "1.13.4"
run: |
set -euo pipefail
case "${{ runner.os }}" in
Linux)
archive="sherpa-onnx-v${SHERPA_VERSION}-linux-x64-static-lib.tar.bz2"
;;
macOS)
archive="sherpa-onnx-v${SHERPA_VERSION}-osx-arm64-static-lib.tar.bz2"
;;
*)
exit 0
;;
esac
mkdir -p "$RUNNER_TEMP/sherpa-onnx-libs"
archive_path="$RUNNER_TEMP/sherpa-onnx-libs/$archive"
if [ ! -f "$archive_path" ]; then
curl -fL --retry 5 --retry-all-errors \
"https://github.com/k2-fsa/sherpa-onnx/releases/download/v${SHERPA_VERSION}/${archive}" \
-o "$archive_path"
fi
lib_dir="$RUNNER_TEMP/sherpa-onnx-libs/lib"
if [ ! -d "$lib_dir" ]; then
tar -xjf "$archive_path" -C "$RUNNER_TEMP/sherpa-onnx-libs"
# The archive extracts to a versioned directory; its lib/ is the
# native library directory the build script expects.
lib_dir="$(find "$RUNNER_TEMP/sherpa-onnx-libs" -maxdepth 2 -type d -name lib | head -n 1)"
fi
test -n "$lib_dir" && test -f "$lib_dir/libsherpa-onnx-c-api.a"
echo "SHERPA_ONNX_LIB_DIR=$lib_dir" >> "$GITHUB_ENV"

- name: Check compilation
run: cargo check --locked --workspace

Expand Down
22 changes: 11 additions & 11 deletions .github/workflows/desktop-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
env:
NODE_OPTIONS: --max-old-space-size=6144
BITFUN_ENABLE_UPDATER_ARTIFACTS: ${{ needs.prepare.outputs.upload_to_release }}
TAURI_UPDATER_ENDPOINT: https://github.com/GCWing/BitFun/releases/latest/download/latest.json
TAURI_UPDATER_ENDPOINT: https://github.com/${{ github.repository }}/releases/latest/download/latest.json
TAURI_UPDATER_PUBKEY: ${{ secrets.TAURI_UPDATER_PUBKEY }}
# Same trust root, compiled into the Desktop binary so one-click relay
# deploy can verify the signed checksum locally and hand the remote host
Expand Down Expand Up @@ -285,7 +285,7 @@ jobs:
contents: write
packages: write
env:
IMAGE: ghcr.io/gcwing/bitfun-relay-server
IMAGE: ghcr.io/${{ github.repository_owner }}/bitfun-relay-server

steps:
- name: Checkout
Expand All @@ -311,7 +311,7 @@ jobs:
set -euo pipefail
mkdir -p linux-release-assets
gh release download "${RELEASE_TAG}" \
--repo GCWing/BitFun \
--repo "${{ github.repository }}" \
--dir linux-release-assets \
--pattern 'bitfun-relay-server-*.tar.gz' \
--pattern 'bitfun-relay-server-*.tar.gz.sha256'
Expand Down Expand Up @@ -359,7 +359,7 @@ jobs:
if [[ "${IMAGE_ONLY}" == "true" ]]; then
# Backfilling an older release must not roll the floating tag
# backwards. GitHub's latest endpoint excludes prereleases.
latest_release="$(gh api repos/GCWing/BitFun/releases/latest --jq .tag_name)"
latest_release="$(gh api repos/${{ github.repository }}/releases/latest --jq .tag_name)"
if [[ "${RELEASE_TAG}" == "${latest_release}" ]]; then
echo "${IMAGE}:latest"
fi
Expand Down Expand Up @@ -537,7 +537,7 @@ jobs:
--manual-assets-dir release-manual-assets \
--version "${{ needs.prepare.outputs.version }}" \
--tag "${{ needs.prepare.outputs.release_tag }}" \
--repo "GCWing/BitFun" \
--repo "${{ github.repository }}" \
--out release-updater-assets/latest.json \
--required-platforms "${REQUIRED_UPDATER_PLATFORMS}"

Expand All @@ -555,7 +555,7 @@ jobs:
--assets-dir linux-release-assets \
--version "${{ needs.prepare.outputs.version }}" \
--tag "${{ needs.prepare.outputs.release_tag }}" \
--repo "GCWing/BitFun" \
--repo "${{ github.repository }}" \
--out linux-release-assets/linux-binaries.json

# The Tauri bundler signs the five updater artifacts during `tauri build`,
Expand Down Expand Up @@ -616,7 +616,7 @@ jobs:
- name: Verify published updater manifest
run: |
curl -fsSL --retry 5 --retry-delay 3 \
"https://github.com/GCWing/BitFun/releases/download/${{ needs.prepare.outputs.release_tag }}/latest.json" \
"https://github.com/${{ github.repository }}/releases/download/${{ needs.prepare.outputs.release_tag }}/latest.json" \
-o latest.published.json
node scripts/verify-tauri-latest-json.mjs \
--manifest latest.published.json \
Expand All @@ -628,7 +628,7 @@ jobs:
- name: Verify published Linux binaries manifest
run: |
curl -fsSL --retry 5 --retry-delay 3 \
"https://github.com/GCWing/BitFun/releases/download/${{ needs.prepare.outputs.release_tag }}/linux-binaries.json" \
"https://github.com/${{ github.repository }}/releases/download/${{ needs.prepare.outputs.release_tag }}/linux-binaries.json" \
-o linux-binaries.published.json
test "$(jq -r '.version' linux-binaries.published.json)" = "${{ needs.prepare.outputs.version }}"
while IFS= read -r cli_url; do
Expand All @@ -639,13 +639,13 @@ jobs:
- name: Verify published Relay image descriptor
run: |
curl -fsSL --retry 5 --retry-delay 3 \
"https://github.com/GCWing/BitFun/releases/download/${{ needs.prepare.outputs.release_tag }}/relay-image.json" \
"https://github.com/${{ github.repository }}/releases/download/${{ needs.prepare.outputs.release_tag }}/relay-image.json" \
-o relay-image.published.json
test "$(jq -r '.tag' relay-image.published.json)" = "${{ needs.prepare.outputs.release_tag }}"
test "$(jq -r '.image' relay-image.published.json)" = "ghcr.io/gcwing/bitfun-relay-server"
test "$(jq -r '.image' relay-image.published.json)" = "ghcr.io/${{ github.repository_owner }}/bitfun-relay-server"
jq -e '.digest | test("^sha256:[0-9a-f]{64}$")' relay-image.published.json >/dev/null
curl -fsSL --retry 5 --retry-delay 3 \
"https://github.com/GCWing/BitFun/releases/download/${{ needs.prepare.outputs.release_tag }}/relay-image.json.sig" \
"https://github.com/${{ github.repository }}/releases/download/${{ needs.prepare.outputs.release_tag }}/relay-image.json.sig" \
-o /dev/null

# Nudge the openbitfun.com mirror to sync now instead of on its next
Expand Down
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,44 @@ dist-ssr
# Build outputs - Rust/Tauri
target/
**/target/
.target/
/.targets/
# Local evidence working dir (fully ignored; intermediate artifacts go to
# outside the repo)
target2/
# The deployable Rust services use the workspace lockfile for reproducible
# container builds.
!Cargo.lock

# Work artifacts that must never enter the repo (S-37/S-56 hygiene):
# recon/fix/verify/report/sediment intermediates, sync records, ws-check data.
/docs/plans/RECON-*
/docs/plans/FIX-*
/docs/plans/VERIFY-*
/docs/plans/REPORT-*
/docs/plans/SEDIMENT-*
/docs/plans/sync-record-*
/docs/plans/recon-*
/docs/plans/fix-*
/docs/plans/doc-governance-report-*
/docs/plans/pr-final-*
/docs/plans/ws-check-*
/docs/plans/del-*.json
/docs/plans/侦查-*
/docs/plans/核对-*
/docs/plans/核查-*
/docs/plans/*.log
/docs/plans/*.json
/docs/plans/*.cjs

# Local customization docs stay out of the repo (S-56 sanitize)

/docs/功能文档/
/交接文档-现状与决议.md
/fix-dualfeed-停止回报.md
/docs/plans/review-upstream-sync-*
/docs/features/agent-hot-reload.md

# Monaco Editor - copied from node_modules
public/monaco-editor/
src/web-ui/public/monaco-editor/
Expand Down Expand Up @@ -91,5 +124,9 @@ external/
/.bitfun/search/flashgrep-index/
.agents/
/.flashgrep-index-engine/
/src/apps/desktop/.bitfun/search/flashgrep-index/
/target/debug/.bitfun/search/flashgrep-index/

.design/
__pycache__/
*.pyc
12 changes: 10 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ resolver = "2"
version = "0.2.16" # x-release-please-version
authors = ["BitFun Team"]
edition = "2021"
license = "MIT"

[workspace.lints.rust]
unsafe_op_in_unsafe_fn = "warn"
Expand Down
83 changes: 83 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# =============================================================================
# cargo-deny configuration
# License compliance + dependency review + vulnerability gate
# =============================================================================
# Reference: https://embarkstudios.github.io/cargo-deny/

[advisories]
# Ignore the following advisories (each needs an explicit reason)
# ignore = [
# # Example: { id = "RUSTSEC-2024-0001", reason = "explain why this is ignored" },
# ]
vulnerability = "deny"
unmaintained = "warn"
notice = "warn"
severity-threshold = "high"
# Ignore yanked crate warnings (decide per-case when upstream is unmaintained)
ignore-yanked = false

[bans]
# Ban specific crates
multiple-versions = "deny" # multiple versions of the same crate are not allowed
wildcard-predicates = "deny" # "*" version requirements are not allowed
deny = []
# skip list - allow multiple versions for some crates (usually unavoidable via transitive deps)
skip = []
# skip-tree - allow multiple versions for an entire subtree rooted at a crate
skip-tree = [
# tokio-util multiple versions are common via transitive dependencies
{ name = "tokio-util", version = "0.6" },
{ name = "tokio-util", version = "0.7" },
# Some crates depend on different versions of the object-storage SDK
{ name = "aws-sdk-s3", version = "0.39" },
{ name = "aws-sdk-s3", version = "1.0" },
]

[licenses]
# Allowed licenses
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-3.0",
"Unlicense",
"CC0-1.0",
"Zlib",
"MPL-2.0",
]
# Licenses requiring explicit approval
deny = [
"AGPL-3.0",
"GPL-3.0",
"GPL-2.0",
"LGPL-3.0",
"CC-BY-4.0", # some CC licenses may restrict commercial use
]
# Licenses requiring manual confirmation
copyleft = "deny"
allow-osi-fsf-free = "both"
confidence-threshold = 0.8
default = "deny"
# Exceptions - crates with explicit license approval
exceptions = [
# Allow specific licenses for specific crates
{ allow = ["MPL-2.0"], name = "ring" },
{ allow = ["MPL-2.0"], name = "webpki" },
{ allow = ["MPL-2.0"], name = "untrusted" },
{ allow = ["ISC"], name = "ipnetwork" },
]

[sources]
# Allowed crate sources
allow-git-registry = true
allow-registry = true
# Unknown sources (e.g. git deps not published to crates.io) need explicit approval
unknown-registry = "deny"
unknown-git = "deny"
# Git dependency allowlist
allow-git = [
# List git dependencies not published to crates.io here
]
10 changes: 3 additions & 7 deletions docs/architecture/cli-product-line-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
- 公开 Agent SDK:[`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md)
- 产品定制:[`product-customization-blueprint.md`](product-customization-blueprint.md)
- 外部 AI 工作来源:[`extensions/external-ai-work-sources-design.md`](extensions/external-ai-work-sources-design.md)
- 外部 AI 应用连接体验:[`extensions/external-ai-app-connection-experience-design.md`](extensions/external-ai-app-connection-experience-design.md)
- 外部 AI 应用连接执行计划:[`../plans/external-ai-app-connection-experience-plan.md`](../plans/external-ai-app-connection-experience-plan.md)
- OpenCode 兼容矩阵:[`extensions/opencode-extension-compatibility.md`](extensions/opencode-extension-compatibility.md)
- 插件 Runtime:[`extensions/plugin-runtime-design.md`](extensions/plugin-runtime-design.md)
- Detached Dispatch:[`detached-task-dispatch.md`](detached-task-dispatch.md)
Expand Down Expand Up @@ -146,7 +144,7 @@ SHELL composer
- `stream-json` stdout 每行是一个完整 Agent event。
- 日志与诊断进入 stderr 或日志文件。
- 默认拒绝需要人工确认的操作;只有显式调用级策略可以自动批准。
- 目标连接体验交付后,只有 Agent Runtime 沿现有事件流返回与当前执行域、工作区作用域、根会话和根轮次完全匹配的依赖结果时,CLI 才投影类型化 `action-required`;当前实现尚未提供该结果。子代理必须通过现有父子关系事件证明仍属于根依赖链,无关待办或后台子代理不得改变退出结果
- 非交互入口不等待人工确认,也不从全局外部来源状态推断特殊任务结果。能力不可用时返回普通失败;能够可靠归属到 Tool、Agent 或 MCP owner 时,错误只给出对应管理入口
- 取消、事件失步、失败完成和 Patch 失败不能报告成功。

## 5. TUI 内部边界
Expand Down Expand Up @@ -185,10 +183,8 @@ CLI 通过 `DeliveryProfile::Cli` 消费经过校验的产品 Runtime parts。

CLI 只消费 typed summary 与 typed action:

> **实现状态:部分交付。** 交互式 TUI 已通过 Host 返回的 V2 快照提供应用级状态、连接、断开、暂不使用和分页批量确认;Embedded 连接旧 Host 时回退既有 V1 只读状态,未接线的 Shared Runtime 明确不支持且绝不回退到控制进程本地执行。任务相关 `action-required` 与非交互 CLI 结果仍未交付。

- `/extensions` 是应用级摘要、首次连接和状态恢复入口;`/extensions review` 提供与 GUI 等价的单页批量确认。
- `/tools`、`/agent`、`/mcp` 和 `/hooks` 保留能力专项或高级管理职责,不复制应用级连接流程。
- `/extensions` 只提供外部应用/来源的简短状态、启停和刷新,不拥有审批、冲突或批量决策。
- `/tools`、`/agent`、`/mcp` 和 `/hooks` 是对应能力的直接管理入口;需要用户允许时由真实 owner 在该入口处理,不再增加跨能力复审流程。
- 静态发现不等于代码执行或服务健康。
- 配置导入不授予插件执行权限。
- ACP、MCP import、Hook import、可执行插件和 TUI contribution 使用独立状态与生命周期。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ OpenCode,多语言协议与发布一致性参考 Copilot SDK。最终结构和

## 10. 产品体验要求

1. **不阻塞正常工作**:发现、准备、兼容检查和无关待确认项在后台进行;只有当前操作真正依赖待确认能力时返回
类型化 `action-required`
1. **不阻塞正常工作**:发现、准备、兼容检查和无关待确认项在后台进行;当前操作真正依赖不可用能力时,由该能力 owner
返回普通失败并指向对应的权限或配置入口,不增加跨能力任务结果类型
2. **能力状态可解释**:设置页、CLI 和 SDK 能看到来源范围、执行位置、外部宿主、native/degraded 状态、最终 Provider、权限
上限、最近错误和恢复动作;默认界面只显示需处理项和聚合摘要。
3. **不重复打扰**:同一来源/能力/候选内容摘要只询问一次;内部 `prepare/ready/activate` 阶段不逐层重复审批。
Expand Down
Loading