|
|
62e1e02036
|
docs(ohos): README 两处事实修正(产物路径前置条件、≤400 行约定的边界)
1. **安装小节的产物路径**:`entry/build/` 是纯构建产物、不入库,干净 clone 或清理过
工作区时该文件不存在。补明"必须先跑完第 2 步",并说明目录名随
`-p product=<名字>` 变化、同目录还有 unsigned 版(`hdc install` 要用 signed)。
本次实际构建校验过路径:`entry/build/default/outputs/default/entry-default-signed.hap`。
2. **≤400 行约定补边界**:不到 400 行的文件不要为了拆分而拆分 ——
`@Component` 的 `build()` 只允许一个根节点,多节点 `@Builder` 改组件会多出一层
Column 包裹,布局等价是推理出来的、不是看出来的,每拆一次都要付一次
"未上机验证"的账。并记下 `pages/Index.ets`(396) 属于"不越线就不动"的一类。
无代码改动,纯文档。
|
2026-09-13 22:42:37 +08:00 |
|
|
|
8a58cde3ee
|
docs(ohos): 本地构建前置条件 + 运行时验证清单 + 工程结构表刷新
1. **oh_modules 前置条件**:该目录被 .gitignore 忽略但必须存在 —— hvigor 不会
自动 ohpm install,移走后构建直接报 arkts-no-untyped-obj-literals(依赖类型
声明缺失)且不重建目录。写明"clone 后先 ohpm install,别当垃圾清掉",
同时说明 entry/build 与 .hvigor 是纯产物、可随时删(冷构建 ~8s)。
2. **hvigorw 绝对路径**:仓库里的 ./hvigorw 是符号链接,启动脚本按
$(dirname $0) 定位,会报 File not found: <repo>/cmd/ohos/hvigor/bin/hvigorw;
统一改用 <command-line-tools>/bin/hvigorw(本机 /opt/huawei/command-line-tools/bin/hvigorw)。
3. **运行时验证清单**:把"构建通过 ≠ UI 行为不变"这件事写进仓库而不是留在邮件里
(流式对话/思考卡与工具卡/附件上传/设置与设备与插件的二级页/宽屏分栏),
并注明无提权环境起不来模拟器时需在真机补验证。
4. 工程结构表按前几轮拆分后的实际情况刷新(common/components/pages 新增文件与职责),
并记下"单文件 ≤400 行、页面只做壳"的约定。
无代码改动,纯文档。
|
2026-09-13 22:35:29 +08:00 |
|
|
|
e733d05a5e
|
refactor(ohos): DevicePage 560→307 行(入口列表/四个面板/模型拆分)
- common/DeviceModel.ets(73):device_id 兜底(桥 id 优先 → 持久化 → 生成并落盘,
顺序与原 aboutToAppear 一致)、/device/online 响应解析、四个二级页路由 id
- components/DeviceRootEntries.ets(92):一级入口(本机/通道两组 NavRow 列表);
宽屏高亮自己读 AppStorage 的 isWideScreen,页面只给 activeSub 与 onOpen
- components/DevicePanes.ets(316):DeviceLocalPane(基本信息 + 授权开关)、
DeviceCapsPane(能力清单)、DeviceGatewayPane(网关信息 + 刷新)、
DeviceListPane(在线设备列表)、DeviceKvRow;每个面板自带 SubPageLayer
页面保留导航栈、openSub/closeSub、授权开关、toast、refreshDevices 与
SubDestination 分发。所有文案、图标、颜色、过渡与失败分支逐字保留;
面板内容多了一层无 padding 的 Column 根节点(@Component 的 build() 只允许
一个根),宽度 100% + Start 对齐,与 SubPageLayer 内容槽的布局一致。
验证:hvigorw assembleHap BUILD SUCCESSFUL。
|
2026-09-13 22:34:20 +08:00 |
|
|
|
8a9fc05451
|
refactor(ohos): DeviceBridge 409→296 行(协议类型与帧构造移到 BridgeProtocol)
- common/BridgeProtocol.ets(168):hello/bind/cmd_result/cmd_data_start/
cmd_data_end/event/status 七个消息结构、CHUNK_SIZE、BridgeCmdHandler 回调类型,
以及 bridgeHelloFrame / bridgeBindFrame / bridgeResultFrame /
bridgeDataStartFrame / bridgeDataEndFrame / bridgeEventFrame /
bridgeStatusFrame / bridgeChunkSlices 八个纯构造/切片函数
- common/DeviceBridge.ets(296):只剩 socket 生命周期、重连代际、绑定状态机
与命令分发
**DeviceBridgeClient 的对外方法名与签名一字未改**(isConnected / getDeviceId /
setCmdHandler / setStateListener / connect / updateAuthorized / disconnect /
sendResult / sendDataChunked / sendEvent / sendStatus / send),
`send*` 仍是"拼帧 + 发出去"两步,拼帧那一步搬走;分块发送的
"start → chunks(失败即 break)→ end"顺序与 `bytes.slice` 语义保持不变。
外部只有 deviceBridge 单例被 import(BridgeRouter / DeviceBridgeSession /
DevicePage),无其它符号依赖。
验证:hvigorw assembleHap BUILD SUCCESSFUL;diff 中 DeviceBridge.ets 无
状态机/回调/重连逻辑改动。
|
2026-09-13 22:28:53 +08:00 |
|
|
|
31bbde9cdd
|
refactor(ohos): Attachment 463→344 行(纯函数与字节解码移出 components)
- common/AttachmentMeta.ets(106):parseAttachment / attachmentFromChannelOutput /
fileNameOf / formatBytes / oneDecimal / extLabel / sanitize,纯函数无平台依赖
- common/AttachmentImage.ets(37):loadPixelMap(沙箱 file:// 与远端 /files 两条路径)
components/Attachment.ets 只留 UI:AttachmentCard 与 AttachmentDetailContent。
**两者的导出名、@Prop 形状与 import 路径均未变**(ChatPage 仍从
'../components/Attachment' 取 AttachmentDetailContent),组件内部的布局、
过渡、提示文案与失败分支逐字保留,仅函数体搬走。引用方 5 处 import 路径同步更新。
验证:hvigorw assembleHap BUILD SUCCESSFUL;diff 中 Attachment.ets 只有
"-删除纯函数 + import 改写",无属性/布局改动。
|
2026-09-13 22:27:34 +08:00 |
|
|
|
e0514c3692
|
refactor(ohos): ChatPage 1962→207 行(状态机/SSE/气泡/输入区拆分)
- common/ChatStore.ets(388):消息数组、分页游标、新消息入场标记、
SSE 连接与重连、防抖刷新(50ms)统一成一个单例状态机
- common/ChatSse.ets(192):SSE 事件 → 状态的翻译层,逐分支照搬
channel_output/agent_output/reasoning/delta/tool_call/stage/agent_error/
sync_required;通过 ChatStreamSink 接口写入,避免与 ChatStore 形成循环依赖
- common/ChatSession.ets(176):POST /chat 与 POST /chat/file 的发送、
超时兜底、POST 响应与 SSE 的合并判定
- common/ChatFormat.ets(223):mime 推断、ForEach 键 structSig、工具卡
状态/颜色、渠道判定与头像配色
- common/ChatHistory.ets(96):历史载荷与 tool_calls 解析
- components/ChatBubble.ets(247):气泡(头像/渠道名/思考卡/工具卡/附件卡/正文)
- components/ChatToolCard.ets(253):思考卡 + 工具卡
- components/ChatStream.ets(210):消息列表 + 顶栏遮罩 + 底部淡出 + 触顶懒加载
- components/ChatComposer.ets(357):输入行、选图/选文件、沙箱落盘、发送
- components/ChatAttachBar.ets(139):加号菜单 + 待发送附件条
响应式语义刻意保持不变:数组不进 AppStorage,改用自增版本号 K_CHAT_REV
通知订阅组件重取快照(ChatStream 把它镜像进 @State messages,ForEach 每次
拿到的仍是新数组引用,与拆分前 this.messages = this.messages.slice() 等价);
structSig 仍不含 content,正文靠 MarkdownView 的 @Prop 流式更新;
markNew 仍不切片、入场动画交给紧随其后的 refresh();
animateTo 只能存在于组件里,所以折叠翻转的动作留在 ChatStream 内。
验证:hvigorw assembleHap BUILD SUCCESSFUL;SSE 各分支、ensureToolCall、
markNew、sendChat/sendWithAttachment 的守卫顺序均与原实现逐条比对过,
守卫从"页面方法内"移到输入区组件时保持了原有先后(连接判定先于清空输入)。
|
2026-09-13 22:19:05 +08:00 |
|
|
|
f79e0f82dd
|
refactor(ohos): SettingsPage 1463→389 行(模型/条目卡/四个面板拆分)
- common/SettingsModel.ets(313):设置载荷解析、分类归并、分页切片、
路由常量,纯逻辑无 UI
- components/SettingsEntryCard.ets(215):单条设置卡(值编辑/保存)
- components/SettingsRootEntries.ets(100):一级入口行 + 状态汇总卡
- components/SettingsHome.ets(95):一级页壳(顶栏/浮层/提示条)
- components/ConnectionsPane.ets(347):后端连接 CRUD(自带二级页壳)
- components/AppearancePane.ets(265):主题/背景/透明度(自带二级页壳)
- components/BackendSettingsPane.ets(172):分类与条目两个二级面板
页面保留 @State 集合、加载/保存编排与 SubDestination 分发;数组仍走
@Link 直传(未引入 AppStorage 数组)。相册选择、重启前台桥等既有行为
与提示文案逐字保留。
验证:hvigorw assembleHap BUILD SUCCESSFUL。
|
2026-09-13 22:18:56 +08:00 |
|
|
|
131c1ff0e9
|
refactor(ohos): PluginsPage 995→374 行(接口/状态/列表/详情/浮层拆分)
拆分方向按职责切,页面只留导航与数据编排:
- common/PluginApi.ets(174):fetchPluginRows / fetchPluginDetail
- common/PluginStatus.ets(78):状态判定、文案、颜色、副标题
- components/PluginListView.ets(166):列表卡 + 列表
- components/PluginDetailPane.ets(291):详情面板
- components/PluginsOverlays.ets(65):安装表单
- components/ToastBar.ets(48):提示条,PluginsToast 与 SettingsPage 的
toast 合并成这一个组件(此前两处各写一份)
UI 结构与文案逐字保留(含 92%/layoutWeight 等既有布局修法)。
验证:hvigorw assembleHap BUILD SUCCESSFUL。
|
2026-09-13 22:18:49 +08:00 |
|
|
|
414e6a1627
|
refactor(ohos): StaticMarkdown 604→332 行(Markdown 解析抽到 common/MarkdownParser)
把"文本 → 块/片段"的纯解析逻辑(MdBlock/MdSpan、parseBlocks、parseInline、
表格/分隔线/有序列表判定)整体搬到 common/MarkdownParser.ets(282 行),
StaticMarkdown.ets 只留 StaticMarkdownView 组件(332 行)。
解析规则逐字保留,未改任何排版行为;MdBlock/MdSpan 原本只被
StaticMarkdown.ets 使用(唯一引用方是 components/MarkdownView.ets,
它只用 StaticMarkdownView)。
验证:hvigorw assembleHap BUILD SUCCESSFUL。
|
2026-09-13 22:18:43 +08:00 |
|
|
|
8f40b91dea
|
feat(ohos): 设备桥会话管理、状态/设备信息载荷与能力路由完善
- 新增 `DeviceBridgeSession.ets`:会话生命周期(创建/复用/回收)与 TTS 会话显式 shutdown;
- `BridgeCaps`/`BridgeRouter` 与内核实际支持的本机命令保持一一对应,补齐 status/deviceinfo;
- 页面与状态存储调整(DevicePage/Index/SettingsPage/StatusStore/SubPage)、新增 ScreensuePage;
- module.json5 与 string.json 同步(新增页面与文案)。
|
2026-09-12 20:21:01 +08:00 |
|
|
|
02cc74ce11
|
fix(proc): 子进程崩溃自愈 + 集中台账 + 注册面摘除
根因:子进程插件被 kill 后,内核只发了一个无人订阅的事件,
工具/stage handler/IO 通道全留在注册表里指向死进程,
模型继续调用只吃 ErrProcessExited,没有任何路径把插件拉回来。
## 四层修复
### 1. 专职 waitLoop(进程收割)
- 每个子进程配一根 waitLoop goroutine,是 cmd.Wait() 的唯一调用点
- 不再依赖 stdout EOF 判定死亡(孙子进程继承 stdout 时 EOF 永不到来)
- 手工 os.Pipe 替代 cmd.StdinPipe/StdoutPipe,避免 waitLoop 与
os/exec 的内部关闭竞争
- host.go: Host.Supervisor(),Host.Close() 先 StopAll 再拆段
### 2. 集中台账 Supervisor
- proc/supervisor.go: 插件 Spawn 握手成功即 track,进程退出即 untrack
- StopAll: 并发发 plugin.stop 走优雅路径,到期仍在的一律 Kill
- 关停后才完成握手的进程被立即结束,不会活过内核
- 消除「孤儿进程持共享段映射 → SIGBUS」的隐患
### 3. 注册面摘除(detachPlugin)
- 新增 StageHost.UnregisterPluginStages:摘除指定插件的全部 stage handler
- 新增 Registry.pluginChannels 台账:记录每个插件注册的 IO 通道
- 三条路径统一走 detachPlugin:Disable / ReloadOne / RemovePlugin
- StopAndUnload 漏了 IO 通道也一并补上
### 4. 自动重启
- onProcCrash 从「只发事件」改为「摘注册面 → 从注册表移除 → 异步排重启」
- scheduleProcRestart: 窗口 5 分钟内最多 3 次,线性退避 1s/2s/3s
- 超限停手留日志;重启前复核是否已被 Disable 或被其他路径加载
- 崩溃计数窗口过期自动归零
### 5. 主动停止 vs 崩溃的区分
- proc.Plugin 新增 stopping 标志:Stop()/Close() 里 Set(true)
- handleExit 读 stopping 标志,主动停止不上报 onCrash
- 防止重载/禁用/卸载被误判为崩溃触发多余重启
### 6. Linux Pdeathsig 兜底
- procattr_linux.go: SysProcAttr.Pdeathsig = SIGKILL
- 兜 homed 自身被 SIGKILL/OOM 时子进程变孤儿的场景
- macOS/Windows 无等价物,空实现
### 7. pluginmgr 升级
- PluginManager 接口新增 PluginRuntime / ListPluginRuntimes
- plugin_list 输出运行态:loaded / alive / pid / crash_count / channel
- 新增 plugin_status: 全量运行期快照 + dead/unhealthy 汇总
- 新增 plugin_restart: 无条件重启单个插件(plgreload 不动未改二进制的插件)
### 测试
- process_test.go: 3 例(grandchild stdout 感知 / Supervisor track-untrack /
StopAll 无孤儿)
- crash_recovery_test.go: 8 例(detach 三项齐全 / 通道重注册 / 崩溃不阻塞 /
退避阈值 / 窗口过期 / 关停中跳过 / PluginRuntime 通道识别)
- stages_plugin_test.go: 4 例(stage 按插件摘除 / 空 stage 清理 / 空名 no-op /
工具+stage 双摘后可重新注册同名)
|
2026-09-03 12:37:58 +08:00 |
|
|
|
48b5c2401c
|
feat(ohos): MotionBase 统一按压动效 + 分层图标随主题切换
## 动效统一
各组件重复实现按压反馈(@State pressed + scale + animation + onTouch 四件套),
时长各写魔数导致全局手感不一致。
- 新增 components/MotionBase.ets:通用动效的"父组件"。ArkUI V1 的 @Component
struct 无法继承他人 build,改用组合表达继承——调用组件把内容经 @BuilderParam
内容插槽传入,MotionBase 在包装节点统一挂动效修饰器。
pressEnabled 默认关(纯展示容器零开销);fillWidth=false 供气泡内卡片按内容
自适应宽度;flexWeight 供等分排列按钮参与剩余空间分配。
onPress 只作按压瞬时轻量钩子,导航/提交语义仍由调用组件 onClick 负责,
避免"按下即触发"的手感偏差。
- Constants.ets 新增动效 token:ANIM_FAST(150) / ANIM_NORMAL(220) /
ANIM_ENTER(280) / ANIM_SLOW(400) / PRESS_SCALE(0.97)。
取值依据:状态切换 150-250ms(>300ms 显拖沓),大位移进出场 300-400ms
才不突兀;曲线统一 EaseOut 起步快收尾缓。
- NavRow / StatusSummaryCard / AttachmentCard / 插件卡片等公共组件接入
MotionBase,移除各自的按压四件套。组件专属动效(聊天输入框上弹、加号菜单
浮起、折叠面板展开、toast 进出场)保留在各组件内,不塞进父组件。
## 图标与启动页随主题切换
原先直接指向位图 app_icon.png,浅色底被烧进图标,深色模式下桌面与启动页跳脱。
- 改用分层图标 layered_image:foreground 为字形,background(沉淀色)在
base/ 与 dark/ 各一份,随系统主题切换。app.json5 与 module.json5 的
icon 均指向 :layered_image。
- startWindowIcon 改用透明底 start_icon.png,配合 start_window_background
的 base(#F1F3F5) / dark(#000000) 两份取值,浅深模式遮罩与图标都能对上。
## 验证
清空 entry/build 后全量重编:hvigorw assembleHap BUILD SUCCESSFUL(9.8s),
零 ArkTS 错误。提交内容已确认不含 build/ oh_modules/ .hap 与签名材料。
|
2026-08-30 17:23:40 +08:00 |
|
|
|
8510a2f2eb
|
fix(ohos): 移除硬编码后端凭据,地址规范化默认 https
- Model.ets: defaultConnection 不再内置 url/apiKey,改为空白模板
- 新增 normalizeBaseUrl:补协议(默认 https)、去尾斜杠、去误粘的 /api/v1
裸域名走 http 会被反代 302 到门户站,客户端只拿到 404,表现为"连接直接失败"
- ConnStore: 增删改与读取存量数据时统一规范化 url
- 去掉 ensureDefaultConnection,首启不再预置连接,未配置时走统一提示
|
2026-08-29 13:49:30 +08:00 |
|
|
|
46e942f0c2
|
feat(ohos): 鸿蒙端聊天历史分段懒加载 + 首次提交完整工程
原有 cmd/ohos/HomeAgent 是未入库的鸿蒙原生 ArkTS 工程,本次随改动一并入库,
保证他人 clone 后可直接编译(含 .gitignore 排除 build/oh_modules/签名材料,
提供 build-profile.json5.example 模板)。
本次功能改动(与 WebUI / GUI 三端对齐):
- /chat/history 首屏只拉最新 CHAT_PAGE_SIZE(40) 条,1.26MB → 48.5KB
- 抽出 parseHistoryPayload() 复用解析,记录 chatOffset/chatHasMore
- 新增 loadOlderChat():向上滚动触顶(yOffset<60)懒加载更早页
- 工具调用 args/result 与 reasoning_content 完整还原,不做裁剪
构建验证:hvigorw assembleHap BUILD SUCCESSFUL(7.8s,ChatPage 零告警)
|
2026-08-29 10:25:12 +08:00 |
|