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: 5 additions & 3 deletions docs/architecture/core-decomposition.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,11 @@ owner 边界,否则不要把一个 feature group 继续拆成更小的 crate
- 当前 `product-domains` runtime port/facade closure 只迁移 port-backed owner
orchestration:MiniApp 的 deps/restart/recompile/sync/rollback 状态持久化可经
storage facade 执行,function-agent commit / work-state facade 可基于 Git/AI port
组装结果。core 仍持有 MiniApp filesystem IO、compiler 调度、worker process、host
dispatch、built-in seed/update,以及 function-agent Git/AI service、prompt template、
JSON extraction 和 error mapping;现有 function-agent 产品路径尚未切到新 facade。
组装结果。Git commit-message 产品路径可通过 core-owned Git/AI adapter 接入该 facade;
Startchat work-state 仍需先保留 git-state、git-diff fallback 与 time-info 等价性后再接线。
core 仍持有 MiniApp filesystem IO、compiler 调度、worker process、host dispatch、
built-in seed/update,以及 function-agent Git/AI service adapter、prompt template、
JSON extraction 和 error mapping。

## 产品表面边界(Product Surface Boundary)

Expand Down
4 changes: 2 additions & 2 deletions docs/plans/core-decomposition-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -1128,7 +1128,7 @@ product-full = ["miniapp", "function-agents"]
- 2026-05-18 update: MiniApp draft manifest/response DTO, draft/customization storage path helpers, import layout / fallback payload contracts, manager lifecycle state-transition helpers, runtime executable search-plan helpers, customization draft-apply metadata policy, and built-in update/decline metadata decisions have been moved to `bitfun-product-domains::miniapp`; core continues to own draft/import filesystem IO, compile orchestration, built-in asset seeding/source-hash lookup, host dispatch execution, `PathManager` integration, worker process execution, and compatibility facades. The current PR also records core-owned MiniApp import / sync / recompile / rollback / dependency-state behavior as migration-before tests, including the existing `sync_from_fs` snapshot boundary.
- 已迁移到 `bitfun-product-domains::function_agents`:公共 `common` 类型、git/startchat function-agent 的纯 DTO 类型、git function-agent 的纯路径 / 变更分类 / commit summary / message assembly / prompt format / commit type parser / AI response parsing policy、startchat prompt / action / AI response parsing policy / git porcelain / diff combine / time-of-day helper、Git/AI port contract,以及只读本地文件的 project context analyzer;core-owned Git snapshot adapter 已由等价测试覆盖,AI client、Git service、prompt template、AI request、JSON extraction、错误映射与分析运行逻辑仍留在 core。
- 2026-05-18 update: Git function-agent diff truncation and commit prompt preparation are now owner-crate helpers used by core; AI client calls, prompt template ownership, JSON extraction, error mapping, and runtime analysis execution remain core-owned. The current PR adds focused core snapshots for staged-only Git commit diff collection and AI response JSON extraction / error mapping before any Git/AI runtime migration.
- 2026-05-19 update: `bitfun-product-domains` now owns port-backed MiniApp runtime-state and function-agent runtime facades. Core delegates only MiniApp storage-backed lifecycle persistence through the MiniApp facade; compilation, source reads, storage IO adapter, worker process execution, host dispatch, built-in seeding, Git service calls, AI calls, prompt templates, JSON extraction, and concrete error mapping remain core-owned. The function-agent facade and core AI adapter shape are contract-ready but existing product call paths are not rewired yet.
- 2026-05-19 update: `bitfun-product-domains` now owns port-backed MiniApp runtime-state and function-agent runtime facades. Core delegates only MiniApp storage-backed lifecycle persistence through the MiniApp facade; compilation, source reads, storage IO adapter, worker process execution, host dispatch, built-in seeding, prompt templates, JSON extraction, and concrete error mapping remain core-owned. The Git commit-message product path now routes through the function-agent facade using core-owned Git/AI adapters; Startchat work-state remains on the existing core path until its git-state, git-diff fallback, and time-info behavior are equivalence-locked for wiring.
- boundary check 已补充 product-domain owner anchor:`MiniAppStoragePort` / `MiniAppRuntimePort` 的 core adapter、MiniApp host/customization 纯 contract、MiniApp manager preflight tests、function-agent Git adapter 与 AI response parsing helper 必须存在,防止把 port contract 或 pure parser 误读成 storage IO、worker process、host dispatch、customization draft runtime、Git/AI service runtime 已完成迁移。
- miniapp runtime/storage/manager/host dispatch/exporter/builtin 与 function-agent 运行逻辑继续迁移前,需要先确认 agent/tool/provider port 和 Git/AI service 边界。

Expand Down Expand Up @@ -1741,7 +1741,7 @@ git diff -- package.json scripts/dev.cjs scripts/desktop-tauri-build.mjs scripts
15. 已完成:agent tools + `tool-packs` owner 化低风险闭环;tool contract / DTO、runtime restriction、path resolution、portable context facts/provider、generic registry / static provider installation / dynamic provider container 已归属 `bitfun-agent-tools`,`tool-packs` 只提供计划内 feature-group scaffold,core 保留 core-owned product provider groups、snapshot decorator、`ToolUseContext` 和 concrete tool implementation,后续外移需单独 service port/provider 设计。
16. 已完成:关键语义回归 baseline,不移动 runtime owner。覆盖 MCP config failure / catalog invalidation / 既有 list-changed helper / dynamic manifest、tool manifest / `GetToolSpec`、product-domains adapter equivalence、remote workspace search fallback 的 focused tests 或 snapshots。
17. 已完成:remote-connect runtime 当前批次收口。已基于当前 port baseline 记录 remote command/response、remote model catalog、poll response、model catalog delta、session restore、active turn、cancel、image context、tracker event、queue/event fanout 的输入输出和验证命令;tracker state / registry lifecycle、legacy image context fallback / preference、restore target decision、cancel decision 与 remote file transfer size/chunk/name policy 已迁入 `bitfun-services-integrations`。dispatcher / product execution、`ImageContextData` adapter、file IO/path resolution、terminal pre-warm 与 workspace/session restore 执行显式保留在 core-owned runtime;后续只有在另起 port/provider 设计且 focused regression 继续通过时才允许继续移动这些 runtime owner,不能把 generic attachment guard 当作已接入多模态行为。
18. 当前 PR:`product-domains` runtime port/facade closure。已迁入 MiniApp storage-backed runtime-state facade 与 function-agent Git/AI port-backed runtime facade,并补充 focused contract tests;core 只对 MiniApp deps/restart/recompile/sync/rollback 的状态持久化委托 facade,仍保留 `PathManager` 注入、filesystem IO、worker process execution、host dispatch 执行、built-in asset seeding/source-hash lookup、Git/AI service 调用、prompt template、JSON extraction 和 error mapping adapter。function-agent facadecore AI adapter 只作为后续接线入口,现有产品路径暂不切换
18. 当前阶段:`product-domains` runtime port/facade closure。已迁入 MiniApp storage-backed runtime-state facade 与 function-agent Git/AI port-backed runtime facade,并补充 focused contract tests;core 只对 MiniApp deps/restart/recompile/sync/rollback 的状态持久化委托 facade,仍保留 `PathManager` 注入、filesystem IO、worker process execution、host dispatch 执行、built-in asset seeding/source-hash lookup、prompt template、JSON extraction 和 error mapping adapter。Git commit-message 产品路径已通过 core-owned Git/AI adapter 接入 function-agent facade;Startchat work-state 仍保留在旧 core 路径,后续必须先等价锁定 git-state、git-diff fallback 与 time-info 行为再接线
19. 后续独立评估:`bitfun-core default = []`、per-product feature set、依赖版本收敛或构建收益优化;任何收益声明都需要记录 `cargo check -p bitfun-core`、workspace check 和目标 crate check 的前后数据。

冗余清理 PR 不进入上述主线序号。只有在满足 `0A.6` 的绝对等价要求时,才可以插入到相邻里程碑之间,并且不得与主线拆分 PR 混合。
Expand Down
57 changes: 57 additions & 0 deletions scripts/check-core-boundaries.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,26 @@ const forbiddenContentRules = [
},
],
},
{
path: 'src/crates/core/src/function_agents/git-func-agent/commit_generator.rs',
patterns: [
{
regex: /\bGitService::get_status\b/,
message:
'Git function-agent commit generator must use CoreFunctionAgentGitAdapter through FunctionAgentRuntimeFacade',
},
{
regex: /\bAIAnalysisService::new_with_agent_config\b/,
message:
'Git function-agent commit generator must use CoreFunctionAgentAiAdapter through FunctionAgentRuntimeFacade',
},
{
regex: /\bto_string_lossy\b/,
message:
'Git function-agent commit generator must preserve PathBuf paths when routing through the facade',
},
],
},
{
path: 'src/crates/core/src/service/mcp/server/config.rs',
patterns: [
Expand Down Expand Up @@ -2219,6 +2239,25 @@ const requiredContentRules = [
},
],
},
{
path: 'src/crates/core/src/function_agents/git-func-agent/commit_generator.rs',
reason:
'Git function-agent commit generation must route through the product-domain runtime facade while core keeps concrete adapters',
patterns: [
{
regex: /\bFunctionAgentRuntimeFacade\b/,
message: 'missing product-domain function-agent runtime facade routing',
},
{
regex: /\bCoreFunctionAgentGitAdapter\b/,
message: 'missing core-owned Git adapter wiring',
},
{
regex: /\bCoreFunctionAgentAiAdapter\b/,
message: 'missing core-owned AI adapter wiring',
},
],
},
{
path: 'src/crates/product-domains/src/function_agents/ports.rs',
reason:
Expand All @@ -2240,6 +2279,14 @@ const requiredContentRules = [
regex: /\bgit_work_state_from_snapshot\b/,
message: 'missing Startchat Git snapshot projection helper',
},
{
regex: /\bStartchatTimeSnapshot\b/,
message: 'missing Startchat time snapshot contract',
},
{
regex: /\bstartchat_time_snapshot\b/,
message: 'missing Startchat time snapshot port',
},
],
},
{
Expand Down Expand Up @@ -3131,13 +3178,23 @@ function runManifestParserSelfTest() {
'parse_commit_response_preserves_core_json_extraction_and_error_mapping',
],
},
{
path: 'src/crates/core/src/function_agents/git-func-agent/commit_generator.rs',
contracts: [
'FunctionAgentRuntimeFacade',
'CoreFunctionAgentGitAdapter',
'CoreFunctionAgentAiAdapter',
],
},
{
path: 'src/crates/product-domains/src/function_agents/ports.rs',
contracts: [
'FunctionAgentRuntimeFacade',
'generate_commit_message',
'analyze_work_state',
'git_work_state_from_snapshot',
'StartchatTimeSnapshot',
'startchat_time_snapshot',
],
},
{
Expand Down
4 changes: 4 additions & 0 deletions src/crates/core/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ SessionManager → Session → DialogTurn → ModelRound
- When touching session/token usage paths, keep `cached_content_token_count`
as cache reads/hits and `cache_creation_token_count` as a separate provider
fact.
- Function-agent commit-message orchestration may route through
`bitfun-product-domains`; keep Git/AI service adapters, prompt templates,
JSON extraction, and error mapping core-owned until a reviewed migration
proves equivalence.
- Do not add new cross-layer references from `service` to `agentic` without a
small port/interface boundary.
- Do not move platform-specific logic, build-script behavior, or product
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use super::ai_service::AIAnalysisService;
use super::context_analyzer::ContextAnalyzer;
use super::types::*;
use crate::function_agents::common::{AgentError, AgentResult};
use crate::function_agents::common::AgentResult;
use crate::function_agents::port_adapters::{
CoreFunctionAgentAiAdapter, CoreFunctionAgentGitAdapter,
};
use crate::infrastructure::ai::AIClientFactory;
use crate::service::git::{GitDiffParams, GitService};
use bitfun_product_domains::function_agents::ports::FunctionAgentRuntimeFacade;
/**
* Git Function Agent - commit message generator
*
* Uses AI to deeply analyze code changes and generate compliant commit messages
*/
use log::{debug, info};
use log::info;
use std::path::Path;
use std::sync::Arc;

Expand All @@ -26,88 +27,11 @@ impl CommitGenerator {
repo_path
);

let status = GitService::get_status(repo_path)
let git_adapter = CoreFunctionAgentGitAdapter::default();
let ai_adapter = CoreFunctionAgentAiAdapter::new(factory);
let facade = FunctionAgentRuntimeFacade::new(&git_adapter, &ai_adapter);
facade
.generate_commit_message(repo_path.to_path_buf(), options)
.await
.map_err(|e| AgentError::git_error(format!("Failed to get Git status: {}", e)))?;

let changed_files: Vec<String> = status.staged.iter().map(|f| f.path.clone()).collect();

if changed_files.is_empty() {
return Err(AgentError::invalid_input(
"Staging area is empty, please stage files first",
));
}

debug!(
"Staged files: count={}, files={:?}",
changed_files.len(),
changed_files
);

let diff_content = Self::get_full_diff(repo_path).await?;

if diff_content.trim().is_empty() {
return Err(AgentError::invalid_input("Diff content is empty"));
}

let project_context = ContextAnalyzer::analyze_project_context(repo_path)
.await
.unwrap_or_default(); // Fallback to default on failure

debug!(
"Project context: type={}, tech_stack={:?}",
project_context.project_type, project_context.tech_stack
);

let ai_service =
AIAnalysisService::new_with_agent_config(factory, "git-func-agent").await?;

let ai_analysis = ai_service
.generate_commit_message_ai(&diff_content, &project_context, &options)
.await?;

debug!(
"AI analysis completed: commit_type={:?}, confidence={}",
ai_analysis.commit_type, ai_analysis.confidence
);

let changes_summary = super::utils::build_changes_summary_from_paths(
&changed_files,
status.staged.len(),
status.unstaged.len(),
);

let full_message = super::utils::assemble_commit_message(
&ai_analysis.title,
&ai_analysis.body,
&ai_analysis.breaking_changes,
);

Ok(CommitMessage {
title: ai_analysis.title,
body: ai_analysis.body,
footer: ai_analysis.breaking_changes,
full_message,
commit_type: ai_analysis.commit_type,
scope: ai_analysis.scope,
confidence: ai_analysis.confidence,
changes_summary,
})
}

async fn get_full_diff(repo_path: &Path) -> AgentResult<String> {
let diff_params = GitDiffParams {
staged: Some(true),
stat: Some(false),
files: None,
..Default::default()
};

let diff = GitService::get_diff(repo_path, &diff_params)
.await
.map_err(|e| AgentError::git_error(format!("Failed to get diff: {}", e)))?;

debug!("Got staged diff: length={} chars", diff.len());
Ok(diff)
}
}
32 changes: 23 additions & 9 deletions src/crates/core/src/function_agents/port_adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::Arc;

use bitfun_product_domains::function_agents::ports::{
CommitAiAnalysisRequest, FunctionAgentAiPort, FunctionAgentFuture, FunctionAgentGitPort,
GitCommitSnapshot, StartchatGitSnapshot, WorkStateAiAnalysisRequest,
GitCommitSnapshot, StartchatGitSnapshot, StartchatTimeSnapshot, WorkStateAiAnalysisRequest,
};
use bitfun_product_domains::function_agents::startchat_func_agent::AheadBehind;
use bitfun_product_domains::function_agents::{
Expand All @@ -21,15 +21,29 @@ use crate::service::git::{GitDiffParams, GitService};
pub struct CoreFunctionAgentGitAdapter;

impl FunctionAgentGitPort for CoreFunctionAgentGitAdapter {
fn git_commit_snapshot(&self, repo_path: String) -> FunctionAgentFuture<'_, GitCommitSnapshot> {
Box::pin(async move { Self::build_git_commit_snapshot(PathBuf::from(repo_path)).await })
fn git_commit_snapshot(
&self,
repo_path: PathBuf,
) -> FunctionAgentFuture<'_, GitCommitSnapshot> {
Box::pin(async move { Self::build_git_commit_snapshot(repo_path).await })
}

fn startchat_git_snapshot(
&self,
repo_path: String,
repo_path: PathBuf,
) -> FunctionAgentFuture<'_, StartchatGitSnapshot> {
Box::pin(async move { Self::build_startchat_git_snapshot(PathBuf::from(repo_path)).await })
Box::pin(async move { Self::build_startchat_git_snapshot(repo_path).await })
}

fn startchat_time_snapshot(
&self,
repo_path: PathBuf,
) -> FunctionAgentFuture<'_, StartchatTimeSnapshot> {
Box::pin(async move {
Ok(StartchatTimeSnapshot {
last_commit_timestamp: git_last_commit_timestamp(&repo_path),
})
})
}
}

Expand Down Expand Up @@ -277,7 +291,7 @@ mod tests {

let adapter = CoreFunctionAgentGitAdapter::default();
let snapshot = adapter
.git_commit_snapshot(repo.path().to_string_lossy().to_string())
.git_commit_snapshot(repo.path().to_path_buf())
.await
.unwrap();

Expand All @@ -303,7 +317,7 @@ mod tests {

let adapter = CoreFunctionAgentGitAdapter::default();
let snapshot = adapter
.git_commit_snapshot(repo.path().to_string_lossy().to_string())
.git_commit_snapshot(repo.path().to_path_buf())
.await
.unwrap();

Expand All @@ -328,7 +342,7 @@ mod tests {

let adapter = CoreFunctionAgentGitAdapter::default();
let snapshot = adapter
.startchat_git_snapshot(repo.path().to_string_lossy().to_string())
.startchat_git_snapshot(repo.path().to_path_buf())
.await
.unwrap();

Expand All @@ -348,7 +362,7 @@ mod tests {

let adapter = CoreFunctionAgentGitAdapter::default();
let result = adapter
.startchat_git_snapshot(repo.path().to_string_lossy().to_string())
.startchat_git_snapshot(repo.path().to_path_buf())
.await;

assert!(result.is_err());
Expand Down
8 changes: 4 additions & 4 deletions src/crates/product-domains/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ moves here gradually.
- `function-agents` owns pure function-agent DTOs, prompt assembly helpers,
commit prompt preparation, AI-response parsing policy, diff truncation policy,
local file-shape analysis, Git/AI port traits, and port-backed runtime facade
orchestration.
orchestration, including the commit-message facade used by core adapters.
- Core still owns MiniApp filesystem IO, worker process execution, host dispatch
execution, built-in asset seeding/source-hash lookup, `PathManager`
integration, function-agent Git/AI calls, prompt templates, JSON extraction,
error mapping, and any product call-path rewiring not covered by equivalence
tests.
integration, function-agent Git/AI service adapters, prompt templates, JSON
extraction, error mapping, and Startchat work-state product path wiring until
equivalence tests cover that migration.

## Verification

Expand Down
Loading
Loading