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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .fvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"flutter": "3.44.6"}
4 changes: 1 addition & 3 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
set -euo pipefail

echo "🔍 Running FlutterGuard static scan..."
dart run flutterguard_cli:flutterguard scan --path . --fail-on high

if [ $? -ne 0 ]; then
if ! dart run flutterguard_cli:flutterguard scan . --fail-on high; then
echo ""
echo "❌ FlutterGuard 检测到高优问题,提交被阻止。"
echo " 运行 'dart run flutterguard_cli:flutterguard scan' 查看详情。"
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
push:
branches: [main, dev]
pull_request:
branches: [main, dev]

jobs:
quality-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Checkout pinned FlutterGuard
uses: actions/checkout@v4
with:
repository: lizy-coding/flutterguard
ref: 9f9be84a73dc4b99a956a8529b8c334849566b03
path: flutterguard

- name: Prepare sibling FlutterGuard dependency
run: mv flutterguard ../flutterguard

- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.44.6"
channel: stable

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20.20.2"

- name: Bootstrap
run: |
flutter pub get
git config core.hooksPath .githooks

- name: Agent doc generation + drift check
run: |
bash tool/generate_harness_ai_analysis.sh
git diff --exit-code -- \
AI_ANALYSIS_SCHEMA.json \
AI_PROJECT_CONTEXT.md \
REFACTOR_PLAN.md \
'lib/**/AI_ANALYSIS.md' \
'lib/AI_MODULE_INDEX.md' \
'packages/**/AI_ANALYSIS.md'

- name: Dart format
run: |
dart format .
git diff --exit-code -- '*.dart'

- name: Flutter analyze
run: flutter analyze --no-fatal-infos --no-fatal-warnings

- name: Tests
run: bash tool/test_all.sh

- name: FlutterGuard scan
run: dart run flutterguard_cli:flutterguard scan . --fail-on high
163 changes: 163 additions & 0 deletions .hermes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Hermes Agent 项目架构记录

> flutter_study 项目 Hermes Agent 托管架构 — 完全托管模式
> 里程碑: online_video_player_landed | 阶段: agent_managed | 更新: 2026-08-02

## 项目概述

flutter_study 是一个 Flutter 模块化学习应用,涵盖基础机制、异步并发、状态管理、UI 动效、弹窗列表、网络平台六大分类共 18 个学习模块。通过 Dart Pub Workspace 管理 4 个内部共享包。

## Agent 文档体系

```
flutter_study/
├── AGENTS.md # Agent 行为契约(入口)
├── AI_ANALYSIS_SCHEMA.json # 文档 schema 定义
├── AI_PROJECT_CONTEXT.md # 项目架构上下文(JSON 机器契约)
├── REFACTOR_PLAN.md # 任务队列与里程碑
├── AI_ANALYSIS.md # 工作区根索引
├── lib/
│ ├── AI_ANALYSIS.md # lib 层索引
│ ├── AI_MODULE_INDEX.md # 模块索引(生成物)
│ ├── app/AI_ANALYSIS.md # 应用壳层
│ ├── app/router/AI_ANALYSIS.md # 路由层
│ ├── module_registry/AI_ANALYSIS.md # 模块注册表
│ ├── shared/AI_ANALYSIS.md # 共享层
│ ├── modules/AI_ANALYSIS.md # 模块根索引
│ └── modules/{category}/{module}/AI_ANALYSIS.md # 18个模块契约
├── packages/
│ ├── gcode_core/AI_ANALYSIS.md # G-code 解析包
│ ├── flutter_study_learning/AI_ANALYSIS.md # 教学模板包
│ ├── file_picker_bridge/AI_ANALYSIS.md # 文件选择桥接
│ └── flutter_ioc_core/AI_ANALYSIS.md # IoC 容器
├── tool/
│ ├── generate_agent_indexes.js # Agent 文档生成器(唯一生成源)
│ ├── validate_agent_docs.js # Agent 文档校验器
│ ├── generate_harness_ai_analysis.sh # 生成+校验入口
│ ├── quality_gate.sh # 全量质量门禁(统一入口)
│ ├── bootstrap.sh # 环境自举
│ ├── check_environment.sh # 环境检查
│ └── test_all.sh # 全量测试
├── docs/
│ ├── DEVELOPMENT.md # 开发指南
│ ├── TESTING.md # 测试指南
│ ├── agent/
│ │ ├── TASK_SCHEMA.json # Agent 任务输入格式
│ │ ├── CHANGE_REPORT_SCHEMA.json # Agent 变更报告格式
│ │ └── COMMANDS.json # 项目命令清单
│ └── adr/
│ ├── README.md # ADR 索引
│ ├── 0001-repository-layout.md # 单仓布局决策
│ └── 0002-agent-contract-source-of-truth.md # 契约生成源决策
├── .github/workflows/ci.yml # CI 流水线(FlutterGuard 固定版本)
├── .fvmrc # Flutter 3.44.6
├── .nvmrc # Node 20.20.2
└── .hermes/
├── README.md # 本文档
├── <task>.codex.json # 单次任务 JSON 提词(Codex 执行依据)
└── plans/ # Agent 执行计划归档
```

总计: 37 个 lib AI_ANALYSIS.md + 4 个 packages AI_ANALYSIS.md = 41 个验证通过。

## 分层架构

```
app/ ← 宿主引导 + 路由组装(禁止被 modules/ 依赖)
module_registry/ ← 模块元数据与分类(仅依赖 Flutter + go_router)
shared/ ← 业务无关能力(禁止依赖 app/ 和 modules/)
modules/ ← 学习模块叶子节点(禁止互相依赖)
packages/ ← 工作区共享包(Dart Pub Workspace,独立可测)
```

## 依赖方向

```
app → module_registry, shared, modules
shared → 仅 Flutter SDK
modules → module_registry, flutter_study_learning, packages/*
packages/* → 仅 Flutter/Dart SDK(独立包,workspace 内互不可见)
```

## 质量门禁(单一入口)

```bash
bash tool/quality_gate.sh
```

内部 5 阶段:
1. Agent 文档生成 + 校验 + 漂移检测 (41 contracts)
2. dart format + git diff (格式不漂移)
3. flutter analyze (0 errors)
4. test_all.sh (5/5 packages)
5. flutterguard --fail-on high (0 HIGH)

## 当前基线 (2026-08-02 — online_video_player_landed)

| 项目 | 状态 |
|------|------|
| Agent 文档 | ✅ 41 契约验证通过,生成源已修正 |
| Pub Workspace | ✅ 4 包,resolution_status=active |
| dart format | ✅ 0 changed |
| flutter analyze | ✅ 0 errors, 198 info |
| flutterguard | ✅ 0 HIGH, 5 MEDIUM(既有) |
| 测试 | ✅ 5/5 通过(含 online_video_player 3 用例) |
| CI | ✅ .github/workflows/ci.yml 已配置(FlutterGuard 固定版本) |
| 工具链锁定 | ✅ .fvmrc (Flutter 3.44.6), .nvmrc (Node 20.20.2) |
| 质量门禁脚本 | ✅ quality_gate.sh, bootstrap.sh, test_all.sh, check_environment.sh |
| 人类文档 | ✅ CONTRIBUTING.md, docs/DEVELOPMENT.md, docs/TESTING.md |
| Agent 协议 | ✅ TASK_SCHEMA.json, CHANGE_REPORT_SCHEMA.json, COMMANDS.json |
| ADR | ✅ 0001-repository-layout, 0002-agent-contract-source-of-truth |
| 托管模式 | ✅ agent_managed (REFACTOR_PLAN.active_phase) |
| 在线视频播放模块 | ✅ lib/modules/platform/online_video_player(media_kit,3 测试全过) |

## 已完成的里程碑

1. directory_layers — 分层目录结构
2. shared_package_extraction — 共享包提取
3. module_analysis_coverage — 模块分析覆盖
4. app_navigation_boundary — 应用导航边界
5. host_bootstrap_boundary — 宿主引导边界
6. workspace_package_import — 工作区包导入
7. agent_takeover_ready — Agent 完全托管就绪
8. online_video_player_landed — 在线视频播放模块落地(media_kit,macOS 优先)← 当前

## 最近进度(2026-07-25 → 2026-08-02)

| 日期 | 事项 |
|------|------|
| 2026-07-25 | quality_gate 5/5 通过,agent_takeover_ready 达成 |
| 2026-08-02 | 修复 tool/test_agent_tools.sh 用例(19/19 全绿) |
| 2026-08-02 | 新增「在线视频播放」模块:JSON 提词 → Codex 落地 → Hermes 验收 |
| 2026-08-02 | media_kit macOS 集成:entitlements 补 network.client、ensureInitialized 时序 |
| 2026-08-02 | 解决 libmpv xcframework 下载不可达(ghfast 镜像 + SHA256 校验) |
| 2026-08-02 | flutter build macos --debug 成功,quality_gate 5/5 通过 |
| 2026-08-02 | Notion 指导文档审查修正 + 配套实操示例页 |

## 待推进 (P1-P2)

| 项目 | 优先级 | 备注 |
|------|--------|------|
| Android 平台适配 (module_platform_contract → android_host) | P1 | REFACTOR_PLAN 中 blocked_by_dependencies |
| mobile_layout_baseline(移动端布局基线) | P1 | REFACTOR_PLAN 中 pending |
| platform_plugin_audit(平台插件审计) | P2 | REFACTOR_PLAN 中 pending |
| FlutterGuard MEDIUM 消减 (5 issues) | P2 | 既有问题,非本模块引入 |
| 教学页视觉证据(截图/golden) | P2 | 人工验收依赖 |

## 后续演进方向

1. **平台扩展**:在线视频播放模块当前 macOS 优先;后续按 REFACTOR_PLAN 推进 android_host,media_kit 三件套已支持 Android,预计补充网络权限声明与真机验证即可复用。
2. **多模块模式沉淀**:online_video_player 已验证「JSON 提词 → Codex → 独立验收」闭环,可作为新平台/新模块的标准执行范式。
3. **CI 强化**:ci.yml 已固定 FlutterGuard 版本;后续可补充 macOS 构建 job(media_kit 原生依赖需可下载的 CI 环境)。
4. **构建环境注意项**:libmpv 依赖 GitHub releases 下载;若网络受限需走镜像(ghfast.top),SHA256 校验 84d2ad98... 已固化在 pub-cache 缓存。
5. **Notion 文档体系**:指导文档 + 实操示例页已关联,后续每个新模块可在实操页追加一节约 1 屏的落地记录。

## Agent 执行约定

1. 修改代码前: read AGENTS.md + .hermes/README.md + 目标 AI_ANALYSIS.md
2. 修改生成源: 编辑 tool/generate_agent_indexes.js,不要手改生成物
3. 验证: bash tool/generate_harness_ai_analysis.sh
4. 门禁: bash tool/quality_gate.sh
5. 禁止: 提交/推送/合并(除非用户明确授权)
6. 禁止: 手改 AI_MODULE_INDEX.md / AI_PROJECT_CONTEXT.md / REFACTOR_PLAN.md / packages/*/AI_ANALYSIS.md
7. 任务提词: 写入 .hermes/<task>.codex.json(schema: flutter_study.agent_task.v1),Codex 只执行提词,Hermes 独立验收
135 changes: 135 additions & 0 deletions .hermes/online-video-player-macos.codex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{
"schema": "flutter_study.agent_task.v1",
"task_id": "FEAT-20260802-online-video-player-macos",
"objective": "macos_first_online_video_player_module",
"scope": "macos_only",
"agent_role": "code_executor",
"background": {
"repo": "/Users/forest/code/flutter_study",
"branch": "dev",
"host": "macos",
"flutter": "3.44.6",
"macos_deployment_target": "10.15",
"workspace": "pub_workspace, 4 internal packages",
"existing_platform_modules": ["dio_interceptor", "usb_detector"],
"reference_module": "lib/modules/platform/usb_detector",
"learning_package": "packages/flutter_study_learning (exports LearningScaffold, LearningObjectives, ConceptChips, CodeSnippetCard, CommonPitfalls, ExerciseCard)",
"plugin_decision": "media_kit ^1.2.6 + media_kit_video ^2.0.1 + media_kit_libs_video ^1.0.7. NOT flutter official video_player (no first-class macOS support).",
"sample_stream": "https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4",
"verified_facts": [
"macos/Runner/DebugProfile.entitlements currently has app-sandbox, cs.allow-jit, network.server, files.user-selected.read-only; MISSING network.client",
"macos/Runner/Release.entitlements currently has app-sandbox, files.user-selected.read-only; MISSING network.client",
"lib/app/app_bootstrap.dart calls WidgetsFlutterBinding.ensureInitialized() first; MediaKit.ensureInitialized() must be added right after it, before runApp",
"ModuleEntry requires: title, path, subtitle, category, difficulty, concepts, estimatedMinutes, status, builder (see lib/module_registry/module_entry.dart)",
"Route table is lib/app/router/app_route_table.dart, _modules list, platform section at bottom"
]
},
"module_contract": {
"directory": "lib/modules/platform/online_video_player",
"route": "/online-video-player",
"category": "platform",
"difficulty": "intermediate",
"title": "在线视频播放",
"subtitle": "使用 media_kit 播放在线 HTTP 视频流并操控播放参数",
"concepts": ["media_kit", "libmpv", "HTTP 流", "播放控制", "倍速", "Player 生命周期"],
"estimatedMinutes": 35,
"status": "ready",
"required_files": [
"module_entry.dart",
"module_root.dart",
"widgets/video_player_controls.dart",
"state/media_kit_player_adapter.dart"
],
"generated_analysis": "AI_ANALYSIS.md (auto-generated via tool/generate_harness_ai_analysis.sh, DO NOT hand-edit)"
},
"implementation_steps": [
{
"step": 1,
"action": "pubspec.yaml",
"detail": "add dependencies: media_kit ^1.2.6, media_kit_video ^2.0.1, media_kit_libs_video ^1.0.7; run flutter pub get"
},
{
"step": 2,
"action": "lib/app/app_bootstrap.dart",
"detail": "import package:media_kit/media_kit.dart; add MediaKit.ensureInitialized() immediately after WidgetsFlutterBinding.ensureInitialized()"
},
{
"step": 3,
"action": "macos entitlements",
"detail": "add com.apple.security.network.client=true to BOTH macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements (insert alphabetically, keep existing keys untouched)"
},
{
"step": 4,
"action": "state/media_kit_player_adapter.dart",
"detail": "wrap Player + VideoController; openAndPlay() opens Media(sampleStreamUrl) with play:true; expose play/pause/togglePlayPause/seek(Duration)/setVolume(double 0-1)/setRate(double); ValueNotifier<PlayerUiState> uiState (idle/loading/playing/paused/error) + ValueNotifier<Duration> position/duration + ValueNotifier<double> volume/rate; listen player.stream.position/duration/playing; dispose() disposes all notifiers + player; error branch catches open failure and sets uiState=error"
},
{
"step": 5,
"action": "widgets/video_player_controls.dart",
"detail": "StatelessWidget taking adapter; Row: play/pause IconButton (loading -> CircularProgressIndicator, disabled), position/duration text (mm:ss), DropdownButton rate 0.5x/1.0x/1.5x/2.0x; Slider for seek (max=duration, disabled when zero, clamp), Row: volume icon + Slider + percent text; all via ValueListenableBuilder on adapter notifiers"
},
{
"step": 6,
"action": "module_root.dart",
"detail": "MyHomePage StatefulWidget; initState -> adapter.openAndPlay(); dispose -> adapter.dispose(); LearningScaffold(title, floatingActionButton refresh -> openAndPlay, interactiveDemo: AspectRatio 16:9 with ValueListenableBuilder on uiState: error->error placeholder, idle->idle placeholder, else Stack[Video(controller), loading overlay]; below: VideoPlayerControls + sample URL text; sections: LearningObjectives/ConceptChips/CodeSnippetCard/CommonPitfalls/ExerciseCard as in reference module)"
},
{
"step": 7,
"action": "module_entry.dart",
"detail": "OnlineVideoPlayerEntry extends StatelessWidget -> const MyHomePage(title: '在线视频播放')"
},
{
"step": 8,
"action": "lib/app/router/app_route_table.dart",
"detail": "import online_video_player/module_entry.dart; append ModuleEntry to _modules platform section with ALL required metadata fields"
},
{
"step": 9,
"action": "tool/generate_agent_indexes.js",
"detail": "modules array append ['platform','online_video_player','/online-video-player','ready',['flutter_study_learning','media_kit','media_kit_video','module_registry']]; categoryMeta.platform children array append 'online_video_player'; depends array append 'media_kit' 'media_kit_video'"
},
{
"step": 10,
"action": "regenerate",
"detail": "run bash tool/generate_harness_ai_analysis.sh; verify no git diff on generated docs; AI_MODULE_INDEX count 17->18"
},
{
"step": 11,
"action": "test",
"detail": "test/modules/platform/online_video_player/online_video_player_test.dart: widget test with a FAKE adapter (subclass or mock, no real Player in test env); assert controls render, play/pause toggles icon, error state shows error placeholder; keep tests hermetic (no network)"
},
{
"step": 12,
"action": "verify",
"detail": "bash tool/quality_gate.sh; flutter build macos --debug (must succeed, proves libmpv native link)"
}
],
"acceptance_criteria": [
"flutter analyze 0 errors",
"dart format no drift",
"tool/test_agent_tools.sh 19/19 PASS",
"quality_gate.sh 5/5 PASS",
"AI_MODULE_INDEX.md count = 18",
"route /online-video-player registered and reachable from module home",
"flutter build macos --debug succeeds",
"module_entry.dart has full metadata: category/difficulty/concepts/estimatedMinutes/status/subtitle",
"at least 1 page uses flutter_study_learning teaching components",
"no flutterguard HIGH issues",
"AI_ANALYSIS.md files are generated, not hand-edited"
],
"forbidden_changes": [
"no hand-edit of AI_PROJECT_CONTEXT.md / REFACTOR_PLAN.md / AI_MODULE_INDEX.md / packages/*/AI_ANALYSIS.md (regenerate only)",
"no changes to other modules or packages",
"no changes to flutterguard_cli dependency",
"no android/ios platform dirs (out of scope)",
"no commit/push without explicit user approval"
],
"validation": [
"bash tool/generate_harness_ai_analysis.sh",
"dart format .",
"flutter analyze",
"bash tool/test_all.sh",
"dart run flutterguard_cli:flutterguard scan . --fail-on high",
"flutter build macos --debug"
]
}
Loading
Loading