merge: enable guided Robot onboarding by default
This commit is contained in:
@@ -10,14 +10,14 @@
|
||||
- Electron 双视口预检必须检查与最终 `built_archive` 相同的内存文件字节;预检失败不得上传,预检成功不得被表述为可信审核凭据。
|
||||
- 上传协议必须同时携带源码归档、构建归档和严格版本化 artifact contract;服务端独立重算摘要、校验合同并固化不可变 Release。
|
||||
- Renderer 不得获得发布凭据、归档、临时目录、构建 origin 或任意本地路径;旧客户端和旧 sandbox/browser 任务必须提示升级后重新构建提交。
|
||||
- Robot Guided Hotspot Binding 实现必须保持固件零改动、Main-owned default-off capability、固定系统浏览器 portal 和现有六位 Binding facade;Makelore 不得接触 Wi-Fi 凭据,也不得把 Binding 成功等同于在线。
|
||||
- Robot Guided Hotspot Binding 必须保持固件零改动、Main-owned default-on capability、精确环境值 `0` 回滚、固定系统浏览器 portal 和现有六位 Binding facade;Makelore 不得接触 Wi-Fi 凭据,也不得把 Binding 成功等同于在线。
|
||||
|
||||
## Quality Checks
|
||||
|
||||
- 发布安装包前运行 `pnpm verify:publish-runtime`,并对最终 Windows 产物运行 `pnpm verify:artifact:win`;固定 npm 闭包缺失或版本不符时 fail closed。
|
||||
- 至少覆盖 release builder/静态产物服务/发布路由/Renderer 状态的聚焦测试、typecheck、scoped lint、Vite 构建和真实 Electron 双视口 production-seam E2E。
|
||||
- 真实生产发布仍需成组验证服务端合同、不可变 Release、运营审核、CDN/App 播放;客户端本地验证不能替代该整链验收。
|
||||
- Robot 试点开启前必须通过聚焦 Renderer/Main 测试、真实 Host API Electron E2E、指定固件镜像核对、六位码发行契约核对与真机 smoke;公共/default 配置保持关闭。
|
||||
- Robot 默认引导路径必须通过聚焦 Renderer/Main 测试并保留 `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` 回滚。真实 Host API Electron E2E、指定固件镜像、六位码发行契约与真机 smoke 未完成前,不得宣称完整硬件兼容或端到端配网已经验收。
|
||||
|
||||
## Last Reviewed
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Accepted
|
||||
|
||||
Implementation status: implemented; the capability remains disabled by default until all pilot release gates pass.
|
||||
Implementation status: implemented and enabled by default. Exact environment value `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` disables the guided path as an operational rollback.
|
||||
|
||||
## Date
|
||||
|
||||
@@ -39,9 +39,9 @@ V1 is a Renderer-guided, Main-gated workflow:
|
||||
- Binding continues to use the existing `bindAiHardwareDevice(activationCode, agentId, { operationId })` cloud contract.
|
||||
- `bound` means account Binding succeeded. It does not prove the Robot is currently online or protocol-ready.
|
||||
|
||||
The guided path is controlled by a Main-owned `guidedHotspotBinding` capability. It is `false` by default. Public builds with the capability disabled retain the existing direct six-digit Binding flow.
|
||||
The guided path is controlled by a Main-owned `guidedHotspotBinding` capability and is `true` by default. Electron Main derives the packaged default from `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING !== '0'`; an exact `0` disables the path without changing the binary. Disabled builds and Renderer capability-read failures retain the existing direct six-digit Binding flow.
|
||||
|
||||
The planned Host API surface is deliberately small:
|
||||
The implemented Host API surface is deliberately small:
|
||||
|
||||
- `GET /api/works/ai-hardware/provisioning-capabilities` has no body/query and succeeds with the standard Host envelope `{ success: true, data: { guided_hotspot_binding: boolean } }`.
|
||||
- `POST /api/works/ai-hardware/provisioning-portal/open` accepts the exact body `{}`, has no query, and succeeds with `{ success: true, data: { opened: true } }`.
|
||||
@@ -50,21 +50,21 @@ The planned Host API surface is deliberately small:
|
||||
|
||||
## Security And Recovery Rules
|
||||
|
||||
- The current firmware hotspot and portal are open/plain HTTP. V1 is an internal pilot only; product copy must warn the user not to perform the flow in an untrusted public environment.
|
||||
- The current firmware hotspot and portal are open/plain HTTP. Default-on accepts that compatibility risk but does not make the channel authenticated; product copy must warn the user not to perform the flow in an untrusted public environment.
|
||||
- Wi-Fi SSID/password entry stays in the firmware portal. Makelore must not collect, log, persist, or proxy Wi-Fi credentials.
|
||||
- Cancel, back, and application restart never imply that Wi-Fi changes on the Robot were reverted. The user is guided to reconnect and restart provisioning if needed.
|
||||
- A same-process ambiguous Binding retry reuses the same operation ID. An invalid/expired/consumed activation code clears both code and retained operation ID; the next freshly issued code gets a new operation ID.
|
||||
- Main must project `ai_hardware_activation_code_invalid` as non-retryable even if an upstream response incorrectly marks it retryable.
|
||||
- After application restart, Makelore cannot correlate an earlier code or Binding outcome from the current overview DTO. It must not replay the old code or operation ID; the user obtains a fresh code or stops.
|
||||
|
||||
## Release Gates
|
||||
## Default-On Acceptance And Remaining Verification
|
||||
|
||||
The capability may be enabled only after all of the following are evidenced:
|
||||
The user explicitly chose default-on on 2026-08-16 while retaining the current firmware behavior. The open SoftAP/plain-HTTP channel remains a known residual risk; choosing the product default is not evidence that the physical flow or its security has passed. Before claiming complete hardware compatibility or end-to-end provisioning acceptance, all of the following still require evidence:
|
||||
|
||||
1. The exact shipped Robot component/image is confirmed to use the audited Hotspot portal flow and fixed portal address.
|
||||
1. The exact shipped Robot component/image uses the audited Hotspot portal flow and fixed portal address.
|
||||
2. The deployed activation issuer emits exactly six ASCII digits accepted by the existing Works Binding validator, with documented freshness and consumption behavior.
|
||||
3. Focused Renderer/Main route tests, Electron E2E through the real Host API seam, and a physical-device smoke all pass.
|
||||
4. The public/default configuration remains disabled until the open SoftAP/plain-HTTP risk is explicitly accepted for the intended pilot population.
|
||||
3. Electron E2E through the real Host API/native-opener seam and a physical-device smoke pass; focused Renderer/Main route tests already cover default-on, exact `0` rollback, fixed portal ownership, local-before-cloud behavior, and error redaction.
|
||||
4. Release/support instructions retain the exact `=0` rollback and do not describe V1 as authenticated discovery, automatic Wi-Fi delivery, automatic claim, or proof of online readiness.
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
| ID | Decision | Status | Date | Applies To | Detail |
|
||||
|---|---|---|---|---|---|
|
||||
| ADR-001 | AI 绘画采用 Workspace / Conversation / Task 分层状态与服务端持久 Conversation Session | Accepted | 2026-08-11 | AI 绘画客户端、Main 适配器、Works Square API | `adr-001-ai-design-conversation-ownership.md` |
|
||||
| ADR-002 | Robot V1 采用 Main 门控的引导式热点配网并衔接现有六位 Binding | Accepted / implemented, default off | 2026-08-16 | Robot Renderer、Host API、Electron Main、现有固件热点入口 | `adr-002-robot-guided-hotspot-binding-v1.md` |
|
||||
| ADR-002 | Robot V1 采用 Main 门控的引导式热点配网并衔接现有六位 Binding | Accepted / implemented, default on | 2026-08-16 | Robot Renderer、Host API、Electron Main、现有固件热点入口 | `adr-002-robot-guided-hotspot-binding-v1.md` |
|
||||
|
||||
## Superseded Decisions
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
| 设计消息与确认 | 当前 Conversation | Main ↔ 持久 Agent Gateway Session WebSocket → Conversation 快照 | `command.submit`、Run 与设计事件共用连接;传输失败才以同一幂等 ID 回退 REST;结构化业务错误不重试且未知文本由 Main 脱敏;请求和流式结果同时绑定 Workspace + Conversation |
|
||||
| 设计单图来源选择 | 当前 Workspace 已完成图片 / 本地图片 | 现有 Asset 上传或选择 → `attachmentAssetIds` → 当前 Conversation Turn | 图片 Brief 用作图生图参考图;视频 Brief 用作首帧;只提交一个真实 Workspace Asset ID |
|
||||
| 设计任务同步 | 任一 Conversation 的事件流 / Quote REST 对账 | Renderer Workspace 任务列表 | Task 和 Asset 按 Workspace 归并;任务已落库但 Run 失败时恢复可见性,内部对账失败不覆盖新会话错误,切换 Conversation 后仍同步任务但不回写旧会话 |
|
||||
| Robot 引导式热点配网 V1(计划、默认关闭) | Robot Binding 页面 | 用户进入固件配网模式 → 操作系统连接 Robot 热点 → Main 在系统浏览器打开固定 portal → 用户在 portal 配置 Wi-Fi → 电脑恢复互联网 → 现有六位 Binding | Makelore 不扫描附近设备、不收集 Wi-Fi 密码、不修改固件;`bound` 不等于 online/ready |
|
||||
| Robot 引导式热点配网 V1(已实现、默认开启) | Robot Binding 页面 | 用户选择引导配网 → 进入固件配网模式 → 操作系统连接 Robot 热点 → Main 在系统浏览器打开固定 portal → 用户在 portal 配置 Wi-Fi → 电脑恢复互联网 → 现有六位 Binding | 精确环境值 `0` 或 capability 读取失败回退直接六位码;Makelore 不扫描设备、不收集 Wi-Fi 密码、不修改固件,`bound` 不等于 online/ready |
|
||||
|
||||
## State Ownership
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
- Main-owned electron-updater IPC 与 Works Square 平台/架构稳定 feed;正式安装产物发布不由 Renderer 控制。
|
||||
- 服务端安全投影后的公共 `play_url`;只接受同源 HTTPS、精确 App 路径和可信版本状态。
|
||||
- Works Square Workspace/Conversation API、每个 Conversation 的持久 Agent Gateway Session、单次 WebSocket ticket、双向命令/事件帧与幂等 REST 传输回退。
|
||||
- 计划中的本机 Robot provisioning capability 与固定 portal-open Host API。它们是本地 Main 操作,不读取 Works access token、不调用上游,也不接受任意 URL。
|
||||
- 已实现的本机 Robot provisioning capability 与固定 portal-open Host API。它们是本地 Main 操作,不读取 Works access token、不调用上游,也不接受任意 URL。
|
||||
|
||||
## Last Updated
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
| `src/stores/image-workspace.ts` | 当前 Workspace/Conversation、项目任务及流式更新状态 | Quote/task 按 Workspace 无 UI 错误副作用地对账;Conversation 写入按 Workspace-load + Conversation-selection generation/revision 防护 |
|
||||
| `src/pages/ImageCanvas/index.tsx` | Conversation 对话、Quote 确认、统一任务列表、新会话入口与单图来源选择器 | 图片 Brief 选择/上传图生图参考图;视频 Brief 绑定首帧;均提交一个 Workspace Asset ID |
|
||||
| `src/components/layout/ImageWorkspaceSidebar.tsx` | Workspace 与近期 Conversation 切换/创建 | 切换会话不清空项目级任务 |
|
||||
| `src/pages/AiHardware/index.tsx` | Robot 管理、现有六位 Binding,以及计划中的 default-off 引导式热点配网状态机 | 只编排非敏感步骤;不接收 Wi-Fi 密码,不把 `bound` 展示为在线证明 |
|
||||
| `src/lib/ai-hardware.ts` | Renderer 侧 Robot Host API 类型、安全错误映射和稳定 Binding facade | 计划新增只读 capability 与无参数固定 portal-open 操作;不添加任意 URL 或 Renderer IPC |
|
||||
| `electron/api/routes/ai-hardware.ts` | Main-owned Robot 云端代理,以及计划中的本地配网 capability/portal action | 本地操作必须在认证/上游访问前返回;系统浏览器只能打开固定 `http://192.168.4.1/` |
|
||||
| `src/pages/AiHardware/index.tsx` | Robot 管理、现有六位 Binding,以及已实现的 default-on 引导式热点配网状态机 | 只编排非敏感步骤;不接收 Wi-Fi 密码,不把 `bound` 展示为在线证明 |
|
||||
| `src/lib/ai-hardware.ts` | Renderer 侧 Robot Host API 类型、安全错误映射和稳定 Binding facade | 读取 Main-owned capability 并调用无参数固定 portal-open;不添加任意 URL 或 Renderer IPC |
|
||||
| `electron/api/routes/ai-hardware.ts` | Main-owned Robot 云端代理,以及已实现的本地配网 capability/portal action | 默认开启、精确环境值 `0` 回滚;本地操作必须在 Works token/上游访问前返回,系统浏览器只能打开固定 `http://192.168.4.1/` |
|
||||
|
||||
## Dependency Direction
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
- Gateway 命令的 REST fallback 只处理 WebSocket 发送、断连和 ACK 超时,必须复用 `client_command_id`;业务错误回退会造成重复提交。Quote 任务恢复只更新 Workspace 所有的任务,不能覆盖当前 Conversation。
|
||||
- `closeEventSessions` 只负责本地流和缓存生命周期;远端 Conversation Session 是服务端持久资源。
|
||||
- 单图来源选择器当前仍由精确中文 quick reply 触发,并以 Brief medium 判断图生图或视频首帧用途;扩展更多输入用途前应先把消息协议升级为结构化 action/purpose,避免展示文案与行为继续耦合。
|
||||
- Guided Hotspot Binding 依赖当前固件的开放热点和明文 HTTP portal,只能作为 default-off 内部试点;未完成指定固件镜像核对、六位码发行契约和真机 smoke 前不得开启。
|
||||
- Guided Hotspot Binding 已由产品决策默认开启,但仍依赖当前固件的开放热点和明文 HTTP portal。未完成指定固件镜像核对、六位码发行契约、原生 opener E2E 和真机 smoke 前不得宣称完整兼容;现场异常使用精确环境值 `0` 回滚。
|
||||
|
||||
## Last Updated
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Makelore 是 Electron 桌面客户端。Renderer 负责项目操作与状态展
|
||||
|
||||
| Robot Workspace | Account-scoped agent configuration, device activation/binding, assignment, and credential-recovery UI | Renderer receives only safe Works Square projections. Configuration choices come from the USER-scoped safe catalog; unavailable current values remain editable without exposing provider credentials or configuration internals. |
|
||||
| AI Hardware Main Route | Fixed `/api/works/ai-hardware` Host API to Works Square proxy | Main owns Bearer auth, stable operation IDs, bounded retry, ETag/If-Match, request/response limits, error redaction, and the fixed no-store configuration-catalog proxy. Versioned responses accept only canonical strong or weak numeric ETags that equal the DTO revision; mutations always emit strong `If-Match`. It never forwards Renderer authorization headers. |
|
||||
| Guided Hotspot Binding V1 | Implemented, default-off Renderer journey over the current firmware Hotspot portal and six-digit Binding | System Wi-Fi selection and portal credential entry remain user/firmware-owned. Main exposes only a boolean capability and a fixed system-browser open action; no BLE, automatic claim, or firmware change is part of V1. |
|
||||
| Guided Hotspot Binding V1 | Implemented, default-on Renderer journey over the current firmware Hotspot portal and six-digit Binding | Exact environment value `0` disables the journey. System Wi-Fi selection and portal credential entry remain user/firmware-owned; no BLE, automatic claim, or firmware change is part of V1. |
|
||||
|
||||
## Important Boundaries
|
||||
|
||||
@@ -33,7 +33,7 @@ Makelore 是 Electron 桌面客户端。Renderer 负责项目操作与状态展
|
||||
- Robot model, language, and voice choices are dynamically projected from the Xiaozhi USER catalog through Works Square and Electron Main; the catalog is bounded, account-scoped, and `private, no-store` at each public hop.
|
||||
- One local account maps to one server-side Xiaozhi account binding. Agents and devices are resources beneath that account binding, not separate Xiaozhi users.
|
||||
- Robot/Canvas/module-selection routes must not initialize AI Programming projects or providers.
|
||||
- Guided Hotspot Binding is implemented behind a Main-owned capability that remains false by default; disabled/public builds keep the current direct six-digit Binding UI. The guided state is process-local, opener failures expose only the same fixed address for manual copy, and Binding conflicts refresh the safe account overview.
|
||||
- Guided Hotspot Binding is implemented behind a Main-owned capability that is true by default; exact `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` disables it, while capability-read failure falls back to direct six-digit Binding. The guided state is process-local, opener failures expose only the same fixed address for manual copy, and Binding conflicts refresh the safe account overview.
|
||||
- The fixed portal action may open only `http://192.168.4.1/` in the system browser and must not acquire cloud credentials or call Works Square. Renderer never supplies a portal URL and never handles Wi-Fi credentials.
|
||||
- A successful Binding means account ownership was established; it is not evidence that the Robot is currently online or protocol-ready.
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ This file is the integrated default-branch snapshot. Feature tasks record progre
|
||||
|
||||
## Integrated Through
|
||||
|
||||
- `b7a1590` / `14afe4a`: implemented and accepted firmware-zero-change Guided Hotspot Binding V1 with a Main-owned default-off capability, fixed portal action, in-memory Renderer journey, and existing six-digit Binding contract.
|
||||
- `b78fc07`: Guided Hotspot Binding is enabled by default in Electron Main, with exact environment value `0` as rollback and direct six-digit fallback on capability-read failure; firmware and Host/cloud contracts are unchanged.
|
||||
- `b7a1590` / `14afe4a`: initial firmware-zero-change Guided Hotspot Binding V1 implementation and decision used a Main-owned default-off capability, fixed portal action, in-memory Renderer journey, and existing six-digit Binding contract; `b78fc07` above supersedes only that default.
|
||||
- `ea75b06`: Robot configuration reads accept canonical weak numeric response ETags introduced by public response compression only when the numeric revision exactly matches the strictly projected DTO; configuration and assignment writes continue to emit strong `If-Match`.
|
||||
- `fe55dee`: Robot configuration editing uses the safe Xiaozhi/Works catalog for model, language, and voice selections, with bounded sliders for TTS numeric controls and no-store catalog responses.
|
||||
- `fd9b5b46a913c515e94e4e26f185d43866c2581f` / `7a811590c4943b7b1b7ea5f3b4d3ce3ce05622a5`: Codex-style persistent AI Programming context-compaction timeline, run-lifecycle separation, polling-idle completion, and cold-hydration hardening.
|
||||
@@ -32,9 +33,12 @@ AI 编程首次发送在新建 OpenCode session 已知为空时不再等待冗
|
||||
|
||||
Updater 仍由 Electron Main 选择目标 feed、记录原始诊断并保持失败语义。正式稳定源缺少对应平台 manifest 时,设置页只显示一条简洁中文提示并允许重试,不把缺包误报为已是最新版,也不向普通界面暴露堆栈、URL、路径或错误码;签名产物发布和真实升级安装仍属于外部 Release Gate。
|
||||
|
||||
Robot 绑定设备默认先显示“引导配网 / 已有激活码”路径选择。引导路径只编排现有固件 Hotspot、固定 `http://192.168.4.1/` 系统浏览器页面、恢复互联网和现有六位 Binding;精确环境值 `0` 可回滚为直接六位码。Makelore 不扫描附近设备、不接收 Wi-Fi 密码、不修改固件,也不把 Binding 成功等同于在线。指定固件/发行契约、原生 opener 和真机整链仍未完成验证。
|
||||
|
||||
## Recently Completed
|
||||
|
||||
- 2026-08-16: Implemented ADR-002's Robot onboarding V1 in Makelore without changing firmware. Main owns a default-off capability and the fixed portal opener; Renderer guides manual hotspot/Wi-Fi handoff and reuses six-digit Binding, clears secrets/retry identity safely, and does not equate Binding with online readiness. Pilot enablement still requires the documented firmware, issuer/validator, gate-on Electron, and physical-device evidence.
|
||||
- 2026-08-16: Enabled the existing Guided Hotspot Binding journey by default after explicit product confirmation. Exact `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` remains the operational rollback; fixed portal ownership, direct-code fallback, security warnings, firmware-zero-change, and Binding-without-online semantics are preserved.
|
||||
- 2026-08-16: Initially implemented ADR-002's Robot onboarding V1 without changing firmware, behind a default-off Main capability and fixed portal opener. The later `b78fc07` decision above changes only the default; the same firmware/issuer/native-opener/physical evidence remains outstanding.
|
||||
- 2026-08-15: Corrected the deployed Robot configuration-read contract after the compressed public Works response was observed with `ETag: W/\"0\"` and matching numeric `config_revision: 0`. Electron Main now accepts only canonical strong or weak numeric response tags, still requires exact DTO revision equality, and always sends strong `If-Match` for mutations. No production client rollout is claimed.
|
||||
- 2026-08-16: Integrated selection-oriented Robot configuration editing. Enabled model and caller-safe voice metadata now flows from Xiaozhi through Works Square and Electron Main without exposing provider secrets; unavailable current values and `clear_fields` semantics remain intact. Production deployment of the matching service endpoints is still required.
|
||||
- 2026-08-15:AI 编程上下文压缩改为 Codex 风格的会话内时间线事件;手动与自动压缩原位展示并持久保留,历史回放去重且状态只允许从 running 单调进入 completed,压缩完成不再冒充整个 run idle。
|
||||
@@ -57,7 +61,7 @@ Updater 仍由 Electron Main 选择目标 feed、记录原始诊断并保持失
|
||||
|
||||
## Next Recommended Steps
|
||||
|
||||
1. 核对指定固件镜像与六位码发行/消费契约,补齐 capability-on 原生 opener Electron E2E 和真机 smoke 后,再决定是否只为内部试点开启 Guided Hotspot Binding。
|
||||
1. 对 default-on Guided Hotspot Binding 核对指定固件镜像与六位码发行/消费契约,补齐原生 opener Electron E2E 和真机 smoke;发布支持保留精确 `=0` 回滚,不把缺失证据表述为已验收。
|
||||
2. 成组核对客户端 source+built+contract 上传 → 服务端逐字节校验 → OSS immutable Release → CDN/Edge 的发布契约与客户端 `play_url` 消费契约。
|
||||
3. 配置真实生产环境,分别执行“小游戏/小程序创建 → 客户端本地构建与同字节预检 → 提交 → 服务端合同/摘要校验与不可变 Release 固化 → 运营批准 → App 播放”。
|
||||
|
||||
@@ -67,6 +71,7 @@ Updater 仍由 Electron Main 选择目标 feed、记录原始诊断并保持失
|
||||
|
||||
## Risky Areas
|
||||
|
||||
- Guided Hotspot Binding 默认开启,但当前 Hotspot/portal 仍是开放 SoftAP + 明文 HTTP,且精确出货镜像、激活码发行契约、原生 opener 与真机整链尚未验证。界面必须保留环境警告,异常发布可用精确环境值 `0` 回滚;不得宣称自动发现、自动认领或在线证明。
|
||||
- 一键提交已成功但本机 submission binding 落盘失败时必须保持提交成功、显示固定 `binding_warning` 并继续轮询,避免用户误判上传失败。
|
||||
- 公共 `play_url` 必须满足 Works Square 同源 HTTPS、无 userinfo/loopback、精确 `/apps/{app_id}/` 路径、无 query/fragment、版本非空且上游标记可播放。
|
||||
- `/api/works/projects/publish-source` 必须在读取凭据和项目文件前校验 Renderer capability;Host token/base 不能替代该 UI 边界。
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
- Worktree: D:\Datas\OthersProjects\makelore
|
||||
- Base commit: 4fbd1d3b24493532ce479729da2c5e5e1709c8a9
|
||||
- Owner: codex
|
||||
- Status: Blocked
|
||||
- Status: In Review
|
||||
|
||||
## Scope
|
||||
|
||||
- On 2026-08-16, resume the existing Integration owner to merge reviewed default-on Guided Hotspot Binding source `b78fc07` into local `main`, accept the user's explicit reversal of the prior default-off policy, preserve exact environment value `0` as rollback, and keep firmware edits and remote push outside this resumption.
|
||||
- On 2026-08-16, resume the existing Integration owner to merge reviewed Robot Guided Hotspot Binding implementation commit `b7a1590` into local `main`, reconcile canonical memory from planned to implemented/default-off, and keep firmware edits, capability enablement, and remote push outside this resumption.
|
||||
- On 2026-08-16, resume the existing Integration owner to accept reviewed Robot Guided Hotspot Binding V1 design commit `14afe4a`, promote only its confirmed minimal-firmware decision into canonical memory, and keep product implementation, firmware changes, and remote push outside this integration step.
|
||||
- On 2026-08-16, resume the existing Integration owner to merge reviewed Robot configuration-catalog/editor source `fe55dee` into local `main`, promote the accepted dynamic catalog boundary, and keep remote push outside this resumption.
|
||||
@@ -46,6 +47,7 @@
|
||||
- The 2026-08-15 context-compaction request likewise authorizes only a local `main` merge. It does not authorize a remote push or changing the existing OpenCode/model compaction threshold.
|
||||
- The 2026-08-16 Robot onboarding confirmation accepts the current-firmware Hotspot + six-digit Binding V1. It does not authorize firmware edits, claim automatic nearby discovery, enable the pilot capability by default, or revive the unready Security 2/automatic-claim proposal as a V1 contract.
|
||||
- The reviewed implementation may move canonical truth from planned to present, but release guidance must retain the exact shipped-firmware, issuer/validator, gate-on Electron, and physical-device smoke prerequisites. The source task record remains read-only and must stay on its feature history.
|
||||
- The user's latest instruction explicitly authorizes default-on and supersedes only the earlier default-off/capability-not-enabled constraint. It does not authorize firmware changes, automatic discovery/claim claims, arbitrary portal URLs, Wi-Fi credential handling, or remote push. Missing installed-Electron/physical-device evidence remains an explicit residual release risk, not completed evidence.
|
||||
|
||||
## Project Context Loaded
|
||||
|
||||
@@ -93,6 +95,14 @@ Relevant understanding:
|
||||
Gate result:
|
||||
- Passed.
|
||||
|
||||
### 2026-08-16 Guided Hotspot Default-On Integration Resume
|
||||
|
||||
- Reused the existing Integration owner because it still exclusively owns clean local `main` at `971865c256c2ddfe1f8ab4f8f4731a1f608599c0`; `task_context.py touch` refreshed the reservation and the registry reports this exact `main` worktree/branch owner.
|
||||
- Verified feature task `20260816-enable-guided-hotspot-4e91c2` is `ready_for_integration`, reviewed source commit `b78fc07` is based exactly on current `main`, and independent final Sol review returned PASS with no P0-P3 findings.
|
||||
- Read the source outcome, verification, follow-ups, and promotion candidate against ADR-002 and current canonical Robot memory. The source changes only the Main default and focused route tests; firmware, Renderer, Host wire shape, fixed portal, cloud Binding, and credential boundaries remain unchanged.
|
||||
- The current user decision resolves the sole semantic conflict: Guided Hotspot Binding is now default-on, with exact environment value `0` as rollback. The exact shipped firmware/issuer and real native-opener/physical-device evidence remain unverified and must not be claimed as passed.
|
||||
- Gate result: Passed for local merge and canonical policy reconciliation. Remote push remains outside this resumption.
|
||||
|
||||
### 2026-08-14 AI Canvas Integration Resume
|
||||
|
||||
- Reused the same Integration owner because it still exclusively owns `main` and the repository integration lock; `task_context.py touch` refreshed the existing reservation.
|
||||
@@ -137,6 +147,13 @@ Gate result:
|
||||
|
||||
## Plan
|
||||
|
||||
### 2026-08-16 Guided Hotspot Default-On Integration Plan
|
||||
|
||||
1. Merge reviewed source `b78fc07` into local `main` with a normal no-ff merge, preserve feature history, and exclude the source-owned task record from the integrated tree.
|
||||
2. Reconcile ADR-002, decision index, success criteria, Robot architecture/domain/current-state memory, glossary, and support wording from default-off/planned enablement to default-on with exact `=0` rollback; preserve all non-default security and evidence caveats.
|
||||
3. Run Robot focused tests, typecheck, scoped lint, production build, bounded-concurrency full tests, task-aware document drift, whitespace/topology checks, and an independent final Sol integration review.
|
||||
4. Commit the verified local merge. Do not modify firmware or push remotely.
|
||||
|
||||
### 2026-08-16 Robot Guided Hotspot Binding Implementation Integration Plan
|
||||
|
||||
1. Merge reviewed source commit `b7a1590` into local `main` with a normal no-ff merge, preserve the source parent, and exclude the source-owned task record from the final main tree.
|
||||
@@ -188,6 +205,10 @@ Gate result:
|
||||
|
||||
## Outcome
|
||||
|
||||
- On 2026-08-16, started a normal `--no-ff --no-commit` merge of reviewed default-on source `b78fc07`; Git reported no textual conflicts. The feature task record remains reachable on the source commit/branch and is excluded from the integrated `main` tree.
|
||||
- Integrated only the Main default change and focused route regressions: unset environment reports guided capability true; exact `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` and dependency-injected false report disabled. Renderer, Host wire shape, fixed portal, cloud Binding contract, credentials, and firmware are unchanged.
|
||||
- Reconciled ADR-002, decision index, success criteria, current state, Robot architecture/domain/glossary, README, and commitments to default-on with exact `=0` rollback. The documents explicitly preserve unverified shipped-firmware, activation-issuer, native-opener, and physical-device evidence instead of claiming those checks passed.
|
||||
- Prepared merge topology uses first parent `971865c256c2ddfe1f8ab4f8f4731a1f608599c0` and reviewed source second parent `b78fc07dba0d720e88c55667f8a36ebc50134f87`. Final independent integration re-review returned PASS; the merge is ready to commit.
|
||||
- On 2026-08-16, started a normal `--no-ff --no-commit` merge of reviewed Guided Hotspot Binding source `b7a1590`; Git reported no textual conflicts. The source task record remains reachable on the source commit/feature branch and is excluded from the local `main` result.
|
||||
- Integrated the default-off Main capability and strict local Host actions, fixed system-browser portal ownership, in-memory Renderer guided/direct Binding journey, safe conflict/retry/secret cleanup, and Bound-without-online semantics. No firmware file, BLE/Wi-Fi discovery, cloud claim route, or capability enablement was added.
|
||||
- Reconciled canonical current state, system overview, and decision index from planned/not implemented to implemented/default off. Release gates remain exact firmware and issuer/validator verification, gate-on native-opener Electron coverage, and physical-device smoke.
|
||||
@@ -283,6 +304,15 @@ Gate result:
|
||||
|
||||
## Verification
|
||||
|
||||
- 2026-08-16 default-on feature final Sol review — `PASS`, no P0-P3 findings; independently confirmed default-on, exact environment opt-out, dependency-injection opt-out, fixed portal ownership, local-before-Works-token behavior, error redaction, unchanged Binding contract, and zero firmware changes.
|
||||
- Merged-main Robot selection — 3 files / 94 tests passed, including fresh-module exact `=0` rollback coverage.
|
||||
- Merged-main `pnpm run typecheck` and scoped ESLint on the two source files — passed.
|
||||
- Merged-main `pnpm run build:vite` — Renderer, Electron Main, and Preload passed; only existing mixed-import/chunk-size warnings remain.
|
||||
- Merged-main bounded full suite `pnpm vitest run --maxWorkers=4` — 156 files / 1758 tests passed. The source task separately records why bounded concurrency was used after the unrelated OpenCode port-release test hit its 10-second limit under default all-suite parallelism but passed 40/40 in isolation.
|
||||
- Merged-main Electron module-navigation smoke — 1/1 passed through the existing packaged Main/Renderer fixture and entered `/ai-hardware`. The fixture still cannot authenticate a Robot overview or observe the native external opener, so that deeper E2E remains a tracked release-validation gap.
|
||||
- `check_project_docs.py` — passed; all required planning/canonical files exist.
|
||||
- Integration task-aware document drift, task registry doctor, staged/unstaged whitespace checks, unmerged-entry check, and exact merge-base/parent checks — passed.
|
||||
- Independent final default-on integration review initially returned `FAIL`: default-on was incorrectly expanded into explicit SoftAP/plain-HTTP risk acceptance, one obsolete follow-up still said “before pilot enablement,” and the default-on test depended on ambient environment state. Canonical wording now records only the explicit default-on/current-firmware decision while retaining the security risk; the follow-up targets the next default-on release/compatibility claim; the test deletes the environment variable and reloads the route module before asserting true. Final re-review returned `PASS` with no P0-P3 findings and independently passed route tests both normally and with ambient `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0`.
|
||||
- 2026-08-16 Robot device-selection merged-tree regression selection — 3 files / 92 tests passed.
|
||||
- Robot device-selection merged-tree `pnpm run typecheck` and scoped ESLint — passed.
|
||||
- Staged/unstaged whitespace checks and unmerged-entry checks — passed before independent review.
|
||||
@@ -365,8 +395,9 @@ Gate result:
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Keep `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING` unset/default false in production; do not touch `D:\Datas\HardwareProjects\xiaozhi-esp32-firmware` for this V1.
|
||||
- Before any pilot enablement, identify the exact shipped Robot component/firmware image, verify that the deployed issuer produces six ASCII digits with compatible freshness/consumption semantics, and pass a real device smoke through the Host API/Electron flow.
|
||||
- Before claiming complete compatibility for the default-on Robot journey, verify the exact shipped firmware/fixed portal, six-digit issuer/validator freshness and consumption semantics, real Host API/native opener behavior, and a physical-device provisioning + Binding smoke. Keep exact `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` in support rollback instructions.
|
||||
- The earlier default-false production instruction is superseded by the user's explicit default-on decision. Keep exact value `0` only as rollback, and do not touch `D:\Datas\HardwareProjects\xiaozhi-esp32-firmware` for this V1.
|
||||
- Before the next default-on release or any complete-compatibility claim, identify the exact shipped Robot component/firmware image, verify that the deployed issuer produces six ASCII digits with compatible freshness/consumption semantics, and pass a real device smoke through the Host API/Electron flow.
|
||||
- Deploy matching Xiaozhi and Works Square catalog endpoints before releasing this client; otherwise the editor preserves current values but cannot populate dynamic choices.
|
||||
- The Robot integration is complete on local `main`. Production still requires matching Works Square/Xiaozhi deployment, feature configuration, credentials, and a real one-time activation-code smoke.
|
||||
- Stable mutation operation IDs are retained across ambiguous retries in the running app but are not persisted across an application restart.
|
||||
@@ -384,6 +415,7 @@ Gate result:
|
||||
|
||||
## Promotion Candidates
|
||||
|
||||
- The implementation truth from `b7a1590` was promoted from planned to implemented/default-off in canonical current state, system overview, and ADR index. Its release-enablement procedure/support matrix candidate remains deferred because the mandatory gate-on Electron and physical/firmware evidence does not yet exist.
|
||||
- The default-on candidate from `b78fc07` was promoted into ADR-002, current state, decision/success criteria, Robot architecture/domain/glossary, README, and a concrete release-validation commitment. No unresolved canonical candidate remains; the missing native/physical evidence is tracked as a pending commitment rather than overclaimed.
|
||||
- The implementation truth from `b7a1590` was originally promoted as implemented/default-off. `b78fc07` now supersedes only that default; its former enablement evidence requirements remain tracked as default-on release validation and rollback commitments.
|
||||
- The Guided Hotspot Binding V1 candidate from `14afe4a` was promoted into ADR-002, success criteria, system/module/data-flow architecture, business rules, glossary, and current state. No unresolved candidate remains for this design acceptance.
|
||||
- The context-compaction source candidate was promoted into current state, module map, data flow, evidence, and upgrade commitments. No unresolved candidate remains for this local merge.
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
- 视频首帧与图生图参考图复用单图选择器,但用途由当前 Brief medium 决定:只有明确 `image` 使用图生图语义,`video`、null 或缺失值保持视频首帧兼容语义。选择作品或上传成功后应关闭弹窗。
|
||||
- 当前 quick reply 文案匹配只是兼容契约;新增更多素材输入用途前,应改为结构化 action/purpose,不得继续依赖本地化展示字符串推断行为。
|
||||
- Robot V1 把现有固件 Hotspot 配网指导放进现有 Binding 体验,但不宣称自动发现附近设备、自动下发 Wi-Fi、自动认领设备或自动确认在线;这些能力需要另行接受的协议与 ADR。
|
||||
- Guided Hotspot Binding capability 由 Electron Main 持有且默认关闭。关闭时保留现有六位码 Binding;Renderer 可以读取 capability,但不能覆盖它。
|
||||
- Guided Hotspot Binding capability 由 Electron Main 持有且默认开启。精确 `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` 关闭引导;关闭或 capability 读取失败时保留现有六位码 Binding,Renderer 可以读取但不能覆盖它。
|
||||
- Robot portal 必须由 Main 以系统浏览器打开固定 `http://192.168.4.1/`。Renderer 不得提交任意 URL;该本地动作不得读取 Works 凭据或访问云端。
|
||||
- Wi-Fi SSID/密码只在现有固件 portal 内输入。Makelore 不收集、不代理、不日志记录、不持久化 Wi-Fi 凭据。
|
||||
- 当前开放 SoftAP 与明文 HTTP portal 只允许 default-off 内部试点。未核对精确固件镜像、六位码发行/消费契约并完成真机 smoke 前,不得面向公共用户开启。
|
||||
- 产品已明确选择在保留当前固件行为时 default-on;开放 SoftAP 与明文 HTTP portal 仍是已知残余风险,不能据此推断安全风险已被单独验收。界面必须保留不在不可信公共环境操作的警告。未核对精确固件镜像、六位码发行/消费契约、原生 opener E2E 与真机 smoke 前,不得宣称完整兼容或端到端验收;现场异常必须可用精确环境值 `0` 回滚。
|
||||
- Binding 成功仅表示设备与账号/Agent 的云端关系建立,不表示设备在线或业务协议 ready。
|
||||
- 同一进程内无法确认结果的 Binding 重试必须复用原 operation ID。无效、过期或已消费 activation code 必须清除 code 与 operation ID;下一个新码使用新 operation ID。Main 必须把 `ai_hardware_activation_code_invalid` 投影为 non-retryable,不信任上游相反标记。
|
||||
- 应用重启后,当前 overview DTO 不能证明旧码对应的 Binding 结果;客户端不得重放旧码或旧 operation ID,必须要求新码,无法取得时停止流程。
|
||||
@@ -47,7 +47,7 @@
|
||||
- 图生图随客户端发布前,需确认相匹配的服务端 `image_to_image` Brief/Quote/Task 冻结、私有源图复核与 Bailian edit 执行链已部署,并使用真实 Workspace Asset 完成生产 smoke。
|
||||
- Updater 生产恢复仍需对齐权威版本、发布正式签名/公证的平台产物,并从旧安装版本执行发现、下载、重启和安装 smoke;源码提示修复本身不构成发布链恢复。
|
||||
- AI Canvas 双向 Gateway 与 Quote 任务恢复仍需真实账号执行一次生产确认 smoke,核对 WebSocket 不产生 `/runs/{run_id}` 轮询、任务按 Quote 出现在 Workspace 列表,并区分真正的 `agent_runtime_unavailable` worker 故障。
|
||||
- Robot Guided Hotspot Binding 试点需确认指定硬件/固件确实提供被审计的 Hotspot portal、部署端签发严格六位 ASCII 数字码且与 Works validator 的时效/消费语义一致,并完成真实设备端到端 smoke。
|
||||
- Robot Guided Hotspot Binding default-on 发布仍需确认指定硬件/固件确实提供被审计的 Hotspot portal、部署端签发严格六位 ASCII 数字码且与 Works validator 的时效/消费语义一致,并完成真实设备端到端 smoke。
|
||||
|
||||
## Last Reviewed
|
||||
|
||||
|
||||
@@ -19,5 +19,5 @@
|
||||
| Robot Provisioning | 让 Robot 获得目标 Wi-Fi 凭据并尝试联网的阶段 | 与云端 Activation、账号 Binding、协议在线是不同阶段;V1 由现有固件 Hotspot portal 完成 |
|
||||
| Robot Activation | Robot 联网后向既有服务获取六位激活码的阶段 | 激活码由设备展示/播报给用户;Makelore 不生成该码 |
|
||||
| Robot Binding | 用户把六位激活码和 Agent 提交到 Works Square,建立账号侧设备关系 | `bound` 不等于设备当前 online 或 protocol-ready |
|
||||
| Guided Hotspot Binding | Makelore 内计划提供的 default-off 引导流程 | 串联系统热点连接、固定 portal、恢复互联网和现有 Binding;不包含自动发现、Wi-Fi 代填或固件修改 |
|
||||
| `guidedHotspotBinding` | Electron Main 所有的本地 capability | Renderer 只读;公共默认 false,试点满足 release gates 后才可开启 |
|
||||
| Guided Hotspot Binding | Makelore 已实现的 default-on 引导流程 | 串联系统热点连接、固定 portal、恢复互联网和现有 Binding;不包含自动发现、Wi-Fi 代填或固件修改 |
|
||||
| `guidedHotspotBinding` | Electron Main 所有的本地 capability | Renderer 只读;默认 true,精确环境值 `0` 回滚为 false,读取失败时 Renderer 回退直接六位码 |
|
||||
|
||||
@@ -4,6 +4,7 @@ Track future-facing memory: promised follow-ups, unfinished loops, timed checks,
|
||||
|
||||
| Date | Commitment | Trigger / Due | Owner | Status | Next Action |
|
||||
|---|---|---|---|---|---|
|
||||
| 2026-08-16 | 验收 default-on Robot Guided Hotspot Binding 的真实设备链路 | 下一份包含 default-on 行为的安装包发布前 | 客户端/硬件/服务端集成 | Pending | 核对精确出货固件与固定 portal、六位码发行/消费语义,执行真实 Host API/native opener Electron smoke 和真机端到端配网+Binding;保留 `NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING=0` 回滚,并记录支持矩阵 |
|
||||
| 2026-08-10 | 完成客户端提交到 App `play_url` 播放的真实生产整链验收 | source+built+contract 服务端协议、OSS immutable Release、CDN/Edge 与 App 消费链成组集成后 | 客户端/服务端集成 | Pending | 使用真实账号执行小游戏和小程序创建、客户端本地构建与同字节预检、双归档提交、服务端逐字节校验/不可变 Release 固化、运营批准、CDN 发布、App 播放与监控核对;如需不可绕过 runtime gate,另行设计可信 verifier |
|
||||
| 2026-08-12 | Windows 发布流水线保留固定 npm 运行时产物门禁 | 每次生成正式 Windows 安装器时 | 客户端发布 | Pending | 运行 `pnpm verify:publish-runtime` 和 `pnpm verify:artifact:win`;当前 223,547,912-byte / SHA-256 `08A0BB7BC66EE4AD8B120E8955B149951CD86AF53CC966C7973AD4D77A5815C1` 安装器仅为本地证据,尚未发布 |
|
||||
| 2026-08-10 | 删除客户端 `runtime_url` 兼容回退 | 一个客户端兼容版本结束,且服务端与存量数据稳定提供 `play_url` | 客户端 | Pending | 删除类型字段、读取分支和对应回归测试 |
|
||||
|
||||
@@ -6,7 +6,7 @@ Makelore 是一个面向软件、视觉创作与智能机器人的 AI 桌面工
|
||||
|
||||
- `Makelore Code|AI 编程`:管理本地项目、项目 Agent、会话、文件上下文、代码变更和运行时。
|
||||
- `Makelore Canvas|AI 绘画`:以设计项目(Workspace)组织 Agent 对话、方向确认、文生图、单参考图生图、视频生成任务和私有结果;参考图可从当前项目作品选择或从本地上传。
|
||||
- `Makelore Robot|AI 机器`:管理机器人智能体、设备激活绑定、智能体配置与设备分配,让 AI 能力走进真实世界。
|
||||
- `Makelore Robot|AI 机器`:管理机器人智能体、设备激活绑定、智能体配置与设备分配;绑定设备时默认先选择“引导配网”或“已有激活码”,引导路径复用机器人现有热点配网页面,不修改固件,也不由 Makelore 接收 Wi-Fi 密码。
|
||||
- `Makelore Learning|AI 学习`:数学与知识宇宙主题的学习入口,当前暂未接入;入口保持可见,点击暂不进入工作区。
|
||||
|
||||
应用启动默认进入 AI 模块入口选择页。入口页可在未登录状态浏览;未登录用户点击已开通模块时进入浏览器授权,授权成功后回到入口选择页,已登录用户可直接进入对应工作区。
|
||||
|
||||
@@ -18,7 +18,7 @@ const CATALOG_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,254}$/;
|
||||
const OPERATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||
const MAX_RETRY_AFTER_SECONDS = 2;
|
||||
const PROVISIONING_PORTAL_URL = 'http://192.168.4.1/';
|
||||
const GUIDED_HOTSPOT_BINDING_ENABLED = process.env.NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING === '1';
|
||||
const GUIDED_HOTSPOT_BINDING_ENABLED = process.env.NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING !== '0';
|
||||
|
||||
type TokenGetter = typeof getValidWorksSquareAccessToken;
|
||||
|
||||
|
||||
@@ -65,8 +65,41 @@ async function invoke(handler: ReturnType<typeof createAiHardwareRouteHandler>,
|
||||
}
|
||||
|
||||
describe('AI hardware Host API route', () => {
|
||||
it('returns the default-off provisioning capability before credentials or upstream access', async () => {
|
||||
const { handler, fetchImpl, getAccessToken } = setup();
|
||||
it('returns the default-on provisioning capability before credentials or upstream access', async () => {
|
||||
const environmentName = 'NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING';
|
||||
const previousValue = process.env[environmentName];
|
||||
delete process.env[environmentName];
|
||||
vi.resetModules();
|
||||
try {
|
||||
const { createAiHardwareRouteHandler: createHandlerWithoutEnv } = await import('@electron/api/routes/ai-hardware');
|
||||
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse(overview));
|
||||
const getAccessToken = vi.fn().mockResolvedValue('secret-token');
|
||||
const handler = createHandlerWithoutEnv({
|
||||
fetchImpl,
|
||||
getAccessToken,
|
||||
apiBaseUrl: 'https://square.example',
|
||||
});
|
||||
const result = await invoke(
|
||||
handler,
|
||||
'GET',
|
||||
'/api/works/ai-hardware/provisioning-capabilities',
|
||||
);
|
||||
|
||||
expect(result.payload).toEqual({
|
||||
success: true,
|
||||
data: { guided_hotspot_binding: true },
|
||||
});
|
||||
expect(getAccessToken).not.toHaveBeenCalled();
|
||||
expect(fetchImpl).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
if (previousValue === undefined) delete process.env[environmentName];
|
||||
else process.env[environmentName] = previousValue;
|
||||
vi.resetModules();
|
||||
}
|
||||
});
|
||||
|
||||
it('honors an explicitly injected disabled provisioning capability', async () => {
|
||||
const { handler, fetchImpl, getAccessToken } = setup(undefined, { guidedHotspotBinding: false });
|
||||
const result = await invoke(
|
||||
handler,
|
||||
'GET',
|
||||
@@ -81,6 +114,36 @@ describe('AI hardware Host API route', () => {
|
||||
expect(fetchImpl).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('honors the exact environment opt-out when Main loads the route', async () => {
|
||||
vi.stubEnv('NIANCODE_AI_HARDWARE_GUIDED_HOTSPOT_BINDING', '0');
|
||||
vi.resetModules();
|
||||
try {
|
||||
const { createAiHardwareRouteHandler: createHandlerWithEnv } = await import('@electron/api/routes/ai-hardware');
|
||||
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValue(jsonResponse(overview));
|
||||
const getAccessToken = vi.fn().mockResolvedValue('secret-token');
|
||||
const handler = createHandlerWithEnv({
|
||||
fetchImpl,
|
||||
getAccessToken,
|
||||
apiBaseUrl: 'https://square.example',
|
||||
});
|
||||
const result = await invoke(
|
||||
handler,
|
||||
'GET',
|
||||
'/api/works/ai-hardware/provisioning-capabilities',
|
||||
);
|
||||
|
||||
expect(result.payload).toEqual({
|
||||
success: true,
|
||||
data: { guided_hotspot_binding: false },
|
||||
});
|
||||
expect(getAccessToken).not.toHaveBeenCalled();
|
||||
expect(fetchImpl).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
vi.unstubAllEnvs();
|
||||
vi.resetModules();
|
||||
}
|
||||
});
|
||||
|
||||
it('rejects queried, body-bearing, and wrong-method capability requests locally', async () => {
|
||||
const { handler, fetchImpl, getAccessToken } = setup();
|
||||
const queried = await invoke(
|
||||
@@ -129,7 +192,7 @@ describe('AI hardware Host API route', () => {
|
||||
|
||||
it('rejects disabled, expanded, or queried portal opens before invoking native or cloud dependencies', async () => {
|
||||
const openExternal = vi.fn().mockResolvedValue(undefined);
|
||||
const disabled = setup(undefined, { openExternal });
|
||||
const disabled = setup(undefined, { guidedHotspotBinding: false, openExternal });
|
||||
const disabledResult = await invoke(
|
||||
disabled.handler,
|
||||
'POST',
|
||||
|
||||
Reference in New Issue
Block a user