feat: prepare Zhinian desktop client for pilot release
This commit is contained in:
200
docs/M1_HANDOFF.md
Normal file
200
docs/M1_HANDOFF.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# YINIAN Desktop M1 Handoff
|
||||
|
||||
> Updated: 2026-04-26
|
||||
> Scope: M1 foundation closure after ClawX fork adaptation. See `docs/PILOT_QA.md` for the current M2 pilot demo and QA gate.
|
||||
|
||||
## 1. What M1 Delivers
|
||||
|
||||
M1 turns the ClawX fork into a YINIAN-ready desktop foundation without removing the original ClawX/OpenClaw capabilities.
|
||||
|
||||
Delivered:
|
||||
|
||||
- YINIAN login-first product flow.
|
||||
- Auth session restore and logout cleanup.
|
||||
- Hotel tenant context and hotel switching.
|
||||
- Config snapshot sync from mock or HTTP control plane.
|
||||
- Local skill registry grouped by `hotelId`.
|
||||
- Skills sync v0 from manifest to registry.
|
||||
- Today page as the new production home route.
|
||||
- Skills page replaced with YINIAN skill control surface.
|
||||
- Gateway auto-start deferred until YINIAN authentication.
|
||||
- Legacy ClawX E2E compatibility preserved.
|
||||
- Workspace packages added for future kernel/skill/UI boundaries.
|
||||
|
||||
Not delivered in M1:
|
||||
|
||||
- Real skill bundle download.
|
||||
- Signature verification and unpacking.
|
||||
- Real OTA skill execution.
|
||||
- Final backend API contract.
|
||||
- Customer-ready pilot dashboard depth.
|
||||
|
||||
## 2. Main Behavior
|
||||
|
||||
### Production Flow
|
||||
|
||||
1. App starts.
|
||||
2. Renderer calls `window.yinian.auth.restoreSession()`.
|
||||
3. If no valid session exists, user is redirected to `/login`.
|
||||
4. Login succeeds through mock control plane by default, or HTTP mode when configured.
|
||||
5. App loads config and local skill registry for the current hotel.
|
||||
6. App navigates to `/today`.
|
||||
7. Gateway initializes and starts only after authenticated hotel context exists.
|
||||
|
||||
### E2E Compatibility Flow
|
||||
|
||||
When Electron is launched with `CLAWX_E2E=1`, main process appends `e2e=1` to the renderer URL.
|
||||
|
||||
In E2E mode:
|
||||
|
||||
- Legacy setup flow remains available.
|
||||
- `/` renders the original Chat page, not Today.
|
||||
- Default language is English unless the test changes it.
|
||||
- Gateway store is initialized after setup, but gateway is not auto-started.
|
||||
|
||||
This keeps the inherited ClawX regression suite valid while production behavior moves to YINIAN.
|
||||
|
||||
## 3. Environment Switches
|
||||
|
||||
| Variable | Values | Default | Purpose |
|
||||
|---|---|---:|---|
|
||||
| `YINIAN_API_BASE_URL` | URL | unset | Enables HTTP control plane. When unset, app uses mock mode. |
|
||||
| `CLAWX_LEGACY_AUTOSTART` | `1` / unset | unset | Restores old main-process gateway auto-start for debugging. Production YINIAN keeps gateway deferred until login. |
|
||||
| `CLAWX_E2E` | `1` / unset | unset | Enables E2E compatibility mode. Used by Playwright fixtures. |
|
||||
| `CLAWX_E2E_SKIP_SETUP` | `1` / unset | unset | Adds `e2eSkipSetup=1` for tests that bypass setup. |
|
||||
|
||||
## 4. Storage Boundary
|
||||
|
||||
YINIAN uses a separate Electron store namespace:
|
||||
|
||||
- Store name: `yinian`
|
||||
- Helper: `electron/yinian/storage.ts`
|
||||
|
||||
Stored data:
|
||||
|
||||
- `session`: persisted YINIAN session metadata.
|
||||
- `configs`: config snapshots keyed by hotel id.
|
||||
- `skillRegistryByHotel`: local skill registries keyed by hotel id.
|
||||
|
||||
Important constraints:
|
||||
|
||||
- Renderer never reads tokens directly.
|
||||
- Renderer accesses auth/config/skill data only through `window.yinian`.
|
||||
- Mock mode persists enough session data to restore the local demo.
|
||||
- HTTP mode keeps `accessToken` in memory and reserves persistence for `refreshToken`.
|
||||
- Logout clears session, current hotel config, and current hotel skill registry through the control plane.
|
||||
|
||||
## 5. Public Renderer API
|
||||
|
||||
The preload exposes `window.yinian`:
|
||||
|
||||
```ts
|
||||
window.yinian.auth.restoreSession()
|
||||
window.yinian.auth.getSessionState()
|
||||
window.yinian.auth.loginWithSms(input)
|
||||
window.yinian.auth.loginWithPassword(input)
|
||||
window.yinian.auth.logout()
|
||||
|
||||
window.yinian.app.getConfig()
|
||||
window.yinian.app.switchHotel(hotelId)
|
||||
|
||||
window.yinian.skills.sync()
|
||||
window.yinian.skills.listLocal()
|
||||
window.yinian.skills.getRegistry(hotelId?)
|
||||
```
|
||||
|
||||
Shared types live in `shared/yinian.ts`.
|
||||
|
||||
## 6. Module Inventory
|
||||
|
||||
### Electron Main
|
||||
|
||||
- `electron/main/ipc/yinian.ts`
|
||||
- IPC handlers for auth, config, hotel switching, skill sync, and registry reads.
|
||||
- `electron/yinian/control-plane.ts`
|
||||
- Chooses mock or HTTP control plane.
|
||||
- `electron/yinian/mock-control-plane.ts`
|
||||
- Local demo implementation with persisted session/config/registry.
|
||||
- `electron/yinian/http-control-plane.ts`
|
||||
- HTTP implementation scaffold for server integration.
|
||||
- `electron/yinian/storage.ts`
|
||||
- YINIAN-specific storage namespace.
|
||||
- `electron/main/index.ts`
|
||||
- Defers gateway auto-start.
|
||||
- Adds E2E renderer query parameters.
|
||||
- `electron/preload/index.ts`
|
||||
- Exposes `window.yinian`.
|
||||
|
||||
### Renderer
|
||||
|
||||
- `src/stores/yinian.ts`
|
||||
- Auth/session/config store.
|
||||
- Restores session on boot.
|
||||
- Refreshes config and skill registry after login and hotel switch.
|
||||
- `src/stores/yinian-skills.ts`
|
||||
- Local registry and skill sync store.
|
||||
- `src/pages/YinianLogin/`
|
||||
- Login UI.
|
||||
- `src/pages/Today/`
|
||||
- M1 hotel home surface.
|
||||
- `src/pages/YinianSkills/`
|
||||
- Skill registry and sync surface.
|
||||
- `src/components/layout/YinianTenantBar.tsx`
|
||||
- Current hotel switcher and logout.
|
||||
- `src/App.tsx`
|
||||
- YINIAN auth gate, production `/today`, E2E compatibility paths.
|
||||
|
||||
### Workspace Packages
|
||||
|
||||
- `packages/kernel-core`
|
||||
- `packages/kernel-context`
|
||||
- `packages/kernel-adapter-openclaw`
|
||||
- `packages/skill-spec`
|
||||
- `packages/skills-hotel-core`
|
||||
- `packages/ui-kit`
|
||||
|
||||
These are M1 boundary scaffolds. They are intentionally thin and should harden during M2/M3.
|
||||
|
||||
### Tests
|
||||
|
||||
- `tests/unit/yinian-control-plane.test.ts`
|
||||
- `tests/unit/yinian-store.test.ts`
|
||||
- `tests/unit/yinian-skills-store.test.ts`
|
||||
|
||||
Inherited ClawX unit and E2E tests are still expected to pass.
|
||||
|
||||
## 7. Verification Baseline
|
||||
|
||||
Last known green run:
|
||||
|
||||
```bash
|
||||
pnpm run typecheck
|
||||
pnpm run test
|
||||
pnpm run test:e2e
|
||||
```
|
||||
|
||||
Results:
|
||||
|
||||
- Typecheck: passed.
|
||||
- Unit tests: 89 files, 572 tests passed.
|
||||
- E2E: 26 passed, 1 skipped.
|
||||
|
||||
Known non-blocking warnings:
|
||||
|
||||
- Vitest `MaxListenersExceededWarning`.
|
||||
- Vite dynamic/static import chunk warnings.
|
||||
- Vite large chunk warning.
|
||||
- Playwright/Electron `NO_COLOR` ignored because `FORCE_COLOR` is set.
|
||||
|
||||
## 8. M2 Entry Points
|
||||
|
||||
Recommended next steps:
|
||||
|
||||
1. Define real server contract v0.
|
||||
2. Upgrade Today page into a pilot operations cockpit.
|
||||
3. Expand Skills Manager status model and UI.
|
||||
4. Start design system consolidation across Login, Today, Skills, and tenant switcher.
|
||||
|
||||
See `task_plan.md` for the active phased plan.
|
||||
|
||||
The first draft of the server contract now lives in `docs/SERVER_CONTRACT_V0.md`.
|
||||
256
docs/PILOT_QA.md
Normal file
256
docs/PILOT_QA.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# YINIAN Desktop Pilot QA
|
||||
|
||||
> Updated: 2026-04-26
|
||||
> Scope: M1/M2 pilot demo package for B-end business desktop flow
|
||||
|
||||
## 1. Pilot Scope
|
||||
|
||||
This pilot validates the desktop product loop that is already implemented:
|
||||
|
||||
- Login-first YINIAN entry.
|
||||
- Session restore and logout cleanup.
|
||||
- Single workspace/service context in the sidebar.
|
||||
- Customer-facing sidebar focused on the service Dashboard card, `快速使用`, `对话`, and `设置`.
|
||||
- Knowledge Base v0 upload/list/search surface.
|
||||
- Service-managed model/Agent/channel/schedule configuration notice in Settings.
|
||||
- Config sync in mock or HTTP mode.
|
||||
- Today operations cockpit.
|
||||
- Workspace-scoped local skill registry.
|
||||
- Skills Manager sync/status flow.
|
||||
- Gateway start after authenticated workspace context.
|
||||
- Legacy ClawX/OpenClaw compatibility in E2E mode.
|
||||
|
||||
Out of scope for this pilot:
|
||||
|
||||
- Real skill bundle download.
|
||||
- Signature verification and unpacking.
|
||||
- Real OTA/PMS task execution.
|
||||
- Real payment, provisioning, or account administration.
|
||||
- Customer-specific branding beyond current YINIAN visual system pass.
|
||||
|
||||
## 2. Environment Modes
|
||||
|
||||
### Mock Mode
|
||||
|
||||
Default mode. Do not set `YINIAN_API_BASE_URL`.
|
||||
|
||||
Use this for product walkthroughs, local QA, and stakeholder demos before the NIANXX server is ready.
|
||||
|
||||
### HTTP Mode
|
||||
|
||||
Set `YINIAN_API_BASE_URL` to enable server-backed control plane calls:
|
||||
|
||||
```bash
|
||||
YINIAN_API_BASE_URL=https://api.example.com pnpm run dev
|
||||
```
|
||||
|
||||
HTTP mode expects the contract documented in `docs/SERVER_CONTRACT_V0.md`.
|
||||
|
||||
### E2E Compatibility Mode
|
||||
|
||||
Playwright uses `CLAWX_E2E=1` through test fixtures. In this mode, legacy ClawX setup/main flows stay available so inherited regression tests remain meaningful.
|
||||
|
||||
## 3. Demo Script
|
||||
|
||||
Use mock mode unless the server is explicitly being validated.
|
||||
|
||||
1. Start the app:
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
2. Confirm first screen is YINIAN login.
|
||||
|
||||
3. Login with mock SMS credentials:
|
||||
|
||||
- Phone: `13800000000`
|
||||
- Code: `123456`
|
||||
|
||||
4. Confirm the app lands on `/today`.
|
||||
|
||||
5. Review Today cockpit:
|
||||
|
||||
- Service name and login user are visible.
|
||||
- Clicking the sidebar service card returns to Today/Dashboard.
|
||||
- Application readiness cards render.
|
||||
- Status queue explains app sync/update/failed states.
|
||||
- Application status board merges server entitlements and local registry.
|
||||
|
||||
6. Open `/skills`.
|
||||
|
||||
7. Confirm Skills Manager:
|
||||
|
||||
- Entitlement count is visible.
|
||||
- Local registry count is visible.
|
||||
- Empty registry warning appears before sync when relevant.
|
||||
- Each skill explains its current state.
|
||||
|
||||
8. Click `同步 Skills`.
|
||||
|
||||
9. Confirm:
|
||||
|
||||
- Sync completes without leaving the page.
|
||||
- Skill cards update to installed/skipped/updated states.
|
||||
- Today page reflects local registry status after returning.
|
||||
|
||||
10. Open `知识库`.
|
||||
|
||||
11. Confirm:
|
||||
|
||||
- Upload entry is visible.
|
||||
- Empty state is readable before upload.
|
||||
- Search and document list area are present.
|
||||
|
||||
12. Hover `历史会话`.
|
||||
|
||||
13. Confirm:
|
||||
|
||||
- History popover opens.
|
||||
- Clicking `历史会话` opens the latest session when history exists, otherwise opens Chat.
|
||||
|
||||
14. Open Settings.
|
||||
|
||||
15. Confirm:
|
||||
|
||||
- `账号与组织` shows the current service and user.
|
||||
- `同步组织配置` refreshes config for the current service.
|
||||
- Model, Agent, channel, and scheduling-policy configuration are shown as server-managed capabilities.
|
||||
- Today and Skills stay scoped to the same workspace context.
|
||||
|
||||
16. Click Settings `退出登录`.
|
||||
|
||||
13. Confirm:
|
||||
|
||||
- App returns to `/login`.
|
||||
- Current workspace config and local registry context are cleaned for the logged-out session.
|
||||
|
||||
## 4. QA Checklist
|
||||
|
||||
### Auth And Session
|
||||
|
||||
- [ ] Login succeeds in mock mode.
|
||||
- [ ] App restores a valid mock session after relaunch.
|
||||
- [ ] Logout returns to `/login`.
|
||||
- [ ] Logout clears current workspace config and current business skill registry context.
|
||||
- [ ] HTTP mode restore calls `/auth/refresh` when a persisted refresh token exists.
|
||||
- [ ] HTTP mode does not persist access tokens.
|
||||
|
||||
### Workspace Context
|
||||
|
||||
- [ ] Sidebar service context appears only after authentication.
|
||||
- [ ] No workspace switcher is visible in the product shell.
|
||||
- [ ] Settings sync refreshes config for the current service.
|
||||
- [ ] Today and Skills stay scoped to the current workspace registry.
|
||||
|
||||
### Sidebar And Settings IA
|
||||
|
||||
- [ ] Production sidebar service card opens Today/Dashboard.
|
||||
- [ ] Production sidebar quick-use area shows `Skills`, `定时任务`, and `知识库`.
|
||||
- [ ] Chat area shows `新对话` and `历史会话`.
|
||||
- [ ] Hovering `历史会话` reveals the history popover.
|
||||
- [ ] Models, Agents, Channels, and Dev Console are not visible in normal customer navigation.
|
||||
- [ ] Account logout lives in Settings, not as a primary sidebar action.
|
||||
- [ ] Settings explains that model/provider strategy, Agent orchestration, channels, and scheduling policy are managed by the service side.
|
||||
|
||||
### Knowledge Base
|
||||
|
||||
- [ ] Knowledge page opens from the sidebar.
|
||||
- [ ] Upload button opens the system file picker.
|
||||
- [ ] Uploaded files appear in the local document list.
|
||||
- [ ] Search filters the visible document list.
|
||||
- [ ] Empty state distinguishes "no files yet" from "no search matches".
|
||||
|
||||
### Gateway Boundary
|
||||
|
||||
- [ ] Gateway does not start before login in production mode.
|
||||
- [ ] Gateway starts once after authenticated workspace context exists.
|
||||
- [ ] `CLAWX_LEGACY_AUTOSTART=1` restores the old ClawX startup behavior for debugging.
|
||||
- [ ] E2E compatibility mode keeps legacy setup and Chat defaults available.
|
||||
|
||||
### Today
|
||||
|
||||
- [ ] Today renders without config errors after login.
|
||||
- [ ] Empty states are visible when there are no pending items, skills, or actions.
|
||||
- [ ] Skill status labels are clear:
|
||||
- `已开通未同步`
|
||||
- `已安装`
|
||||
- `已更新`
|
||||
- `已是最新`
|
||||
- `有更新`
|
||||
- `已禁用`
|
||||
- `同步失败`
|
||||
- [ ] Refresh button updates config without triggering duplicate gateway starts.
|
||||
|
||||
### Skills Manager
|
||||
|
||||
- [ ] Empty entitlement state appears when an organization has no opened skills.
|
||||
- [ ] Empty local registry state is distinct from no entitlements.
|
||||
- [ ] Sync first install marks skills as installed/updated.
|
||||
- [ ] Syncing the same manifest again marks same-version skills as skipped.
|
||||
- [ ] Failed sync surfaces an error and retry affordance.
|
||||
- [ ] Disabled entitlements cannot run.
|
||||
- [ ] Version drift is shown as `有更新`.
|
||||
|
||||
### Visual System
|
||||
|
||||
- [ ] Login, Today, Skills, and sidebar feel like one product.
|
||||
- [ ] Primary actions use the YINIAN navy treatment.
|
||||
- [ ] Status colors are restrained and readable.
|
||||
- [ ] Panels use 8px radius or less.
|
||||
- [ ] Text does not overflow buttons, cards, or status badges at common desktop widths.
|
||||
- [ ] No marketing-style hero page appears after authentication.
|
||||
- [ ] Visual smoke screenshots are refreshed for Login, Today, Skills, Knowledge, and Settings.
|
||||
|
||||
## 5. Verification Commands
|
||||
|
||||
Run this full gate before a guided demo:
|
||||
|
||||
```bash
|
||||
pnpm run typecheck
|
||||
pnpm run test
|
||||
pnpm run build:vite
|
||||
pnpm run test:e2e
|
||||
```
|
||||
|
||||
Last known green verification:
|
||||
|
||||
- Typecheck: passed.
|
||||
- Unit tests: 89 files, 572 tests passed.
|
||||
- Vite build: passed.
|
||||
- E2E: 26 passed, 1 skipped.
|
||||
- Visual smoke: Login, Today, Skills, Knowledge, and Settings passed.
|
||||
|
||||
Known non-blocking warnings:
|
||||
|
||||
- Vitest `MaxListenersExceededWarning`.
|
||||
- Vite dynamic/static import chunk warnings.
|
||||
- Vite large chunk warning.
|
||||
- Playwright/Electron `NO_COLOR` ignored because `FORCE_COLOR` is set.
|
||||
|
||||
## 6. Packaging Notes
|
||||
|
||||
For local macOS pilot packaging, prefer:
|
||||
|
||||
```bash
|
||||
pnpm run package:mac:local
|
||||
```
|
||||
|
||||
This skips preinstalled skills and is more suitable for a fast local artifact. Full release packaging should use the platform-specific `package:*` scripts after dependency and signing decisions are settled.
|
||||
|
||||
Do not treat the current pilot build as production-ready until:
|
||||
|
||||
- Real server auth is validated end to end.
|
||||
- Real bundle download and signature verification are implemented.
|
||||
- The installer signing/notarization path is finalized.
|
||||
- Customer-specific privacy and logging requirements are reviewed.
|
||||
|
||||
## 7. Known Issues And Product Gaps
|
||||
|
||||
- Today uses config and local registry as its data source; real PMS/OTA/task data is not connected yet.
|
||||
- Skills sync consumes manifest metadata only; it does not download, verify, or execute real bundles.
|
||||
- Knowledge Base v0 is local UI state only; persistence, indexing, permissions, and service sync are not connected yet.
|
||||
- HTTP control plane contract is still draft v0.
|
||||
- Device identity is still a placeholder and should become a stable installation id.
|
||||
- Legacy ClawX configuration pages remain available for compatibility/E2E routes, but should stay hidden from production customer navigation until an admin/developer mode is explicitly designed.
|
||||
- Bundle size warnings remain from the inherited app structure.
|
||||
2311
docs/PRD.md
Normal file
2311
docs/PRD.md
Normal file
File diff suppressed because it is too large
Load Diff
243
docs/SERVER_CONTRACT_V0.md
Normal file
243
docs/SERVER_CONTRACT_V0.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# YINIAN Server Contract v0
|
||||
|
||||
> Updated: 2026-04-26
|
||||
> Status: Draft contract for M2 integration
|
||||
> Client switch: set `YINIAN_API_BASE_URL` to enable HTTP mode. Without it, desktop uses mock mode.
|
||||
|
||||
## 1. Transport
|
||||
|
||||
- Base URL: `YINIAN_API_BASE_URL`
|
||||
- Content type: `application/json`
|
||||
- Auth header: `Authorization: Bearer <accessToken>`
|
||||
- Desktop header: `X-YINIAN-App-Version: 0.1.0`
|
||||
- Timestamps: Unix milliseconds.
|
||||
- Field casing: server should prefer `camelCase`; desktop accepts key `snake_case` aliases for M1/M2 migration.
|
||||
|
||||
## 2. Error Shape
|
||||
|
||||
Non-2xx responses should return:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "SESSION_EXPIRED",
|
||||
"message": "Session expired"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The desktop currently surfaces `error.message` and falls back to `YINIAN API request failed: <status>`.
|
||||
|
||||
Recommended error codes:
|
||||
|
||||
- `INVALID_CREDENTIALS`
|
||||
- `INVALID_SMS_CODE`
|
||||
- `SESSION_EXPIRED`
|
||||
- `WORKSPACE_FORBIDDEN`
|
||||
- `CONFIG_UNAVAILABLE`
|
||||
- `SKILLS_MANIFEST_UNAVAILABLE`
|
||||
|
||||
## 3. Device Payload
|
||||
|
||||
Login requests include:
|
||||
|
||||
```json
|
||||
{
|
||||
"device": {
|
||||
"device_id": "dev_local_electron",
|
||||
"platform": "darwin",
|
||||
"app_version": "0.1.0",
|
||||
"machine_name": "YINIAN Desktop"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The exact `device_id` is a placeholder in M2 and should be replaced by a stable desktop installation id later.
|
||||
|
||||
## 4. Auth
|
||||
|
||||
### POST `/auth/login/sms`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"phone": "13800000000",
|
||||
"code": "123456",
|
||||
"device": {}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"accessToken": "access_demo",
|
||||
"refreshToken": "refresh_demo",
|
||||
"accessTokenExpiresAt": 1777188600000
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/auth/login/password`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"account": "ops@example.com",
|
||||
"password": "secret",
|
||||
"device": {}
|
||||
}
|
||||
```
|
||||
|
||||
Response shape is the same as SMS login.
|
||||
|
||||
### POST `/auth/refresh`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"refreshToken": "refresh_demo",
|
||||
"device": {}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"accessToken": "access_refreshed",
|
||||
"refreshToken": "refresh_rotated",
|
||||
"accessTokenExpiresAt": 1777189500000
|
||||
}
|
||||
```
|
||||
|
||||
M2 desktop persists only `refreshToken`; `accessToken` remains memory-only.
|
||||
|
||||
### GET `/auth/me`
|
||||
|
||||
Headers:
|
||||
|
||||
```http
|
||||
Authorization: Bearer access_demo
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
"id": "user_ops_001",
|
||||
"name": "王管理员",
|
||||
"phone": "13800000000",
|
||||
"email": "ops@example.com",
|
||||
"avatar": "https://cdn.example.com/avatar.png"
|
||||
},
|
||||
"hotels": [
|
||||
{
|
||||
"id": "workspace_hangzhou_ops",
|
||||
"name": "智念企业组织空间",
|
||||
"brand": "智念"
|
||||
}
|
||||
],
|
||||
"currentHotelId": "workspace_hangzhou_ops",
|
||||
"accessTokenExpiresAt": 1777188600000
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Config Sync
|
||||
|
||||
### GET `/config/sync?hotel_id=<hotelId>`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"serverTime": 1777188000000,
|
||||
"hotel": {
|
||||
"id": "workspace_hangzhou_ops",
|
||||
"name": "智念企业组织空间",
|
||||
"brand": "智念"
|
||||
},
|
||||
"entitlements": [
|
||||
{
|
||||
"skillId": "daily-report",
|
||||
"name": "日报生成助手",
|
||||
"version": "1.0.0",
|
||||
"enabled": true,
|
||||
"category": "reporting",
|
||||
"triggers": ["scheduled", "manual"],
|
||||
"lastRunAt": 1777184400000
|
||||
}
|
||||
],
|
||||
"notificationChannels": [
|
||||
{
|
||||
"id": "wechat_ops",
|
||||
"kind": "wecom",
|
||||
"label": "业务通知群",
|
||||
"recipient": "room_001",
|
||||
"enabled": true,
|
||||
"source": "nianxx"
|
||||
}
|
||||
],
|
||||
"featureFlags": {
|
||||
"skillsSync": true,
|
||||
"advancedSettings": false
|
||||
},
|
||||
"uiPolicy": {
|
||||
"defaultPage": "today",
|
||||
"showAdvancedSettings": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Skills Manifest
|
||||
|
||||
### GET `/skills/manifest?hotel_id=<hotelId>`
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"serverTime": 1777188000000,
|
||||
"hotelId": "workspace_hangzhou_ops",
|
||||
"manifestVersion": "2026.04.26.1",
|
||||
"skills": [
|
||||
{
|
||||
"skillId": "data-check",
|
||||
"name": "数据检查助手",
|
||||
"version": "1.2.0",
|
||||
"enabled": true,
|
||||
"bundleSha256": "sha256-demo",
|
||||
"bundleUrl": "https://cdn.example.com/skills/data-check-1.2.0.tgz"
|
||||
},
|
||||
{
|
||||
"skillId": "customer-reply-helper",
|
||||
"name": "客户回复助手",
|
||||
"version": "0.9.0",
|
||||
"enabled": false,
|
||||
"bundleSha256": "sha256-disabled"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
M2 desktop consumes manifest metadata only. It does not download `bundleUrl`, verify signatures, or unpack bundles yet.
|
||||
|
||||
## 7. Client Normalization Rules
|
||||
|
||||
The desktop accepts:
|
||||
|
||||
- `camelCase` and `snake_case` aliases for known fields.
|
||||
- Missing `user.name` as `未命名用户`.
|
||||
- Missing hotel fields with safe empty/default values.
|
||||
- Unknown skill categories as `ops-automation`.
|
||||
- Unknown trigger values are ignored.
|
||||
- Missing `uiPolicy.defaultPage` defaults to `today`.
|
||||
- Missing arrays default to `[]`.
|
||||
|
||||
Malformed server responses should not break the shell, but required auth fields still fail fast:
|
||||
|
||||
- Missing `accessToken` after login or refresh throws `服务端未返回 access token`.
|
||||
- Authenticated config/skills calls without a session throw `请先登录`.
|
||||
47
docs/START_HERE.md
Normal file
47
docs/START_HERE.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# YINIAN Desktop 项目启动说明
|
||||
|
||||
## 当前基线
|
||||
|
||||
- 上游基础:ClawX `0.3.11`
|
||||
- 产品定位:快速使用 AI Agent 桌面客户端
|
||||
- 当前分支:`yinian-main`
|
||||
- PRD:`docs/PRD.md`
|
||||
- M1 交付说明:`docs/M1_HANDOFF.md`
|
||||
- 服务端契约草案:`docs/SERVER_CONTRACT_V0.md`
|
||||
- Pilot QA 清单:`docs/PILOT_QA.md`
|
||||
|
||||
## 第一阶段目标
|
||||
|
||||
1. 保留 ClawX 基础功能可运行。
|
||||
2. 接入 YINIAN 登录态和工作空间上下文。
|
||||
3. 建立 `kernel-core` 端口契约。
|
||||
4. 建立 OpenClaw Adapter 的最小实现。
|
||||
5. 替换首屏为“今日”工作台。
|
||||
6. 跑通一个服务端下发 skill 的闭环。
|
||||
|
||||
## 工程边界
|
||||
|
||||
- Renderer 不直接访问 NIANXX 服务端。
|
||||
- Renderer 不读取 token。
|
||||
- 客户端不保存第三方模型 API key。
|
||||
- Skill bundle 必须签名后才能加载。
|
||||
- OpenClaw 相关调用必须逐步收口到 `packages/kernel-adapter-openclaw`。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm run typecheck
|
||||
pnpm run test
|
||||
pnpm run build:vite
|
||||
pnpm run test:e2e
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
## 关键环境变量
|
||||
|
||||
| 变量 | 用途 |
|
||||
|---|---|
|
||||
| `YINIAN_API_BASE_URL` | 配置后启用真实 HTTP control plane;未配置时使用 mock。 |
|
||||
| `CLAWX_LEGACY_AUTOSTART=1` | 调试时恢复 ClawX 旧的 Gateway 启动行为。 |
|
||||
| `CLAWX_E2E=1` | Playwright E2E 兼容模式,保留旧 setup/main flow。 |
|
||||
34
docs/adr/0001-fork-and-layering-strategy.md
Normal file
34
docs/adr/0001-fork-and-layering-strategy.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# ADR 0001: ClawX Fork 与 YINIAN 分层改造策略
|
||||
|
||||
## 状态
|
||||
|
||||
Accepted
|
||||
|
||||
## 背景
|
||||
|
||||
智念桌面端基于 ClawX fork,目标用户从开发者切换为酒店前台、运营、店长和 NIANXX 实施人员。ClawX 提供了 Electron 壳、OpenClaw Gateway 生命周期、技能、渠道、Cron 等基础能力,但其产品心智仍是通用开发者工具。
|
||||
|
||||
## 决策
|
||||
|
||||
v1 阶段采取渐进式改造:
|
||||
|
||||
1. 保留 ClawX 根应用结构、构建链路和 Gateway 管理能力。
|
||||
2. 新增 `packages/*` 作为 YINIAN 平台边界层。
|
||||
3. 在 Renderer 中逐步从通用 ClawX 页面迁移到酒店运营工作台。
|
||||
4. 在 Main 中新增 Auth、Config Sync、Skill Manager、Kernel Lifecycle 安全增强。
|
||||
5. 在 ClawX 上游变更稳定后,再评估是否迁移到 `apps/desktop` 目录结构。
|
||||
|
||||
## 后果
|
||||
|
||||
好处:
|
||||
|
||||
- 第一阶段可快速运行和验证。
|
||||
- 保留上游同步能力。
|
||||
- YINIAN 领域边界可以逐步变硬。
|
||||
|
||||
代价:
|
||||
|
||||
- 初期目录结构不是最终理想形态。
|
||||
- 一段时间内 ClawX 与 YINIAN 命名会共存。
|
||||
- 需要 CI 逐步补上依赖方向约束。
|
||||
|
||||
Reference in New Issue
Block a user