@eduwork/dsh-oidc 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.en.md +6 -38
  2. package/CHANGELOG.md +7 -39
  3. package/CODE_OF_CONDUCT.en.md +1 -1
  4. package/CODE_OF_CONDUCT.md +1 -1
  5. package/CONTRIBUTING.en.md +1 -1
  6. package/CONTRIBUTING.md +1 -1
  7. package/README.md +19 -16
  8. package/{README.en.md → README_EN.md} +15 -8
  9. package/SECURITY.en.md +1 -1
  10. package/SECURITY.md +1 -1
  11. package/SUPPORT.en.md +1 -1
  12. package/SUPPORT.md +1 -1
  13. package/docs/EDUWORK-MIGRATION.en.md +2 -8
  14. package/docs/EDUWORK-MIGRATION.md +2 -8
  15. package/docs/compatibility.en.md +3 -25
  16. package/docs/compatibility.md +3 -25
  17. package/docs/desktop-host.en.md +55 -55
  18. package/docs/desktop-host.md +64 -64
  19. package/docs/development.en.md +44 -44
  20. package/docs/development.md +4 -4
  21. package/docs/dsh-integration.en.md +2 -2
  22. package/docs/dsh-integration.md +2 -2
  23. package/docs/getting-started.en.md +4 -4
  24. package/docs/getting-started.md +4 -4
  25. package/docs/open-integration.en.md +73 -0
  26. package/docs/open-integration.md +73 -0
  27. package/docs/release-checklist.en.md +7 -61
  28. package/docs/release-checklist.md +7 -61
  29. package/docs/server-integration-contract.en.md +4 -2
  30. package/docs/server-integration-contract.md +5 -3
  31. package/examples/enterprise-profile.example.json +78 -78
  32. package/examples/identity-only.example.json +1 -1
  33. package/examples/resources-discovery.example.json +1 -1
  34. package/lib/provider/transforms.js +0 -1
  35. package/lib/typert.host.js +38 -38
  36. package/lib/typert.remote-client.js +37 -37
  37. package/package.json +6 -5
  38. package/schema/enterprise-profile.v1alpha1.schema.json +193 -193
@@ -1,60 +1,60 @@
1
- # Desktop hosts without a persistent Web server
2
-
3
- [简体中文](desktop-host.md)
4
-
5
- Local candidate `0.2.0-dev.20260910.1` adds `backend: desktop`. OIDC validation, host credentials, Key Binding, model discovery and `authorizedFetch()` reuse the Web implementation; existing `web` and legacy native bridge modes remain supported.
6
-
7
- ```yaml
8
- - id: enterprise-oidc
9
- name: '@eduwork/dsh-oidc'
10
- config:
11
- backend: desktop
12
- allowEmptyProfiles: true
13
- profilePathEnv: EDUWORK_OIDC_PROFILE
14
- desktop:
15
- callbackPort: 0
16
- flowTimeoutMs: 600000
17
- ```
18
-
19
- The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
20
-
21
- When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
22
-
23
- Resource binding accepts the original `worker.user-center.v1`, the transitional `worker-user-center/v1`, and `eduwork-resources/v1`. Unknown versions and mismatched Provider IDs are rejected before creating a model credential. Completed identity sign-in is retained, with an error identifying the separate resource/configuration problem.
24
-
25
- The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
26
-
27
- Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
28
-
29
- Shared Host/Client RPC additions:
30
-
31
- - `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
32
- - `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
33
- - `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
34
- - `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
35
- - `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
36
-
37
- Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
38
-
39
- Explicit sign-in with a connected key, or confirmed key provisioning, selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
40
-
41
- Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
42
-
43
- For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Key/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
44
-
45
- The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
46
-
47
- An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
48
-
49
- Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
50
-
51
- The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, managed key and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
52
-
53
- The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
54
-
1
+ # Desktop hosts without a persistent Web server
2
+
3
+ [简体中文](desktop-host.md)
4
+
5
+ `backend: desktop` uses a temporary loopback callback for desktop sign-in. OIDC validation, host credentials, Key Binding, model discovery and `authorizedFetch()` reuse the Web implementation; existing `web` and legacy native bridge modes remain supported.
6
+
7
+ ```yaml
8
+ - id: enterprise-oidc
9
+ name: '@eduwork/dsh-oidc'
10
+ config:
11
+ backend: desktop
12
+ allowEmptyProfiles: true
13
+ profilePathEnv: EDUWORK_OIDC_PROFILE
14
+ desktop:
15
+ callbackPort: 0
16
+ flowTimeoutMs: 600000
17
+ ```
18
+
19
+ The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
20
+
21
+ When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
22
+
23
+ Resource binding accepts the original `worker.user-center.v1`, the transitional `worker-user-center/v1`, and `eduwork-resources/v1`. Unknown versions and mismatched Provider IDs are rejected before creating a model credential. Completed identity sign-in is retained, with an error identifying the separate resource/configuration problem.
24
+
25
+ The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
26
+
27
+ Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
28
+
29
+ Shared Host/Client RPC additions:
30
+
31
+ - `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
32
+ - `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
33
+ - `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
34
+ - `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
35
+ - `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
36
+
37
+ Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
38
+
39
+ Explicit sign-in with a connected key, or confirmed key provisioning, selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
40
+
41
+ Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
42
+
43
+ For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Key/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
44
+
45
+ The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
46
+
47
+ An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
48
+
49
+ Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
50
+
51
+ The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, managed key and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
52
+
53
+ The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
54
+
55
55
  Run `npm run check` from an isolated dependency tree coherent with the exact target DSH. Do not relabel a bundle built using old root dependencies. `npm run check:browser` additionally uses that Runtime's `playwright-core` and locally installed headless Edge (or Chrome through `DSH_OIDC_BROWSER_CHANNEL`) to load the compiled client, verify menu/shared state/logout and capture branded callback pages. It does not replace native vault/system-browser acceptance.
56
56
 
57
- ## macOS handoff acceptance
57
+ ## macOS integration requirements
58
58
 
59
59
  The OIDC npm package is platform-independent JavaScript. It bundles no Electron, Wails, Keychain or Windows credential binary; macOS consumes the same exact version and integrity. The plugin has no platform branch: the Host interfaces above own shell differences. Windows validation does not establish macOS readiness.
60
60
 
@@ -1,67 +1,67 @@
1
- # 无常驻 Web 服务的桌面宿主
2
-
3
- [English](desktop-host.en.md)
4
-
5
- 本地候选 `0.2.0-dev.20260910.1` 新增 `backend: desktop`。它复用 Web 后端的 OIDC 校验、Host credentials、Key Binding、模型发现协议,只替换登录回调传输。既有 `web` 和 Go 桥 `native` 配置继续可用。
6
-
7
- ```yaml
8
- - id: enterprise-oidc
9
- name: '@eduwork/dsh-oidc'
10
- config:
11
- backend: desktop
12
- allowEmptyProfiles: true
13
- profilePathEnv: EDUWORK_OIDC_PROFILE
14
- desktop:
15
- callbackPort: 0
16
- flowTimeoutMs: 600000
17
- ```
18
-
19
- 宿主应注册 Cordis `desktopServices` 服务,提供 Host-only 方法:
20
-
21
- ```ts
22
- openExternal(url: string): Promise<void>
23
- // 可选:仅打开宿主预先确定的配置文件或示例目录。
24
- openConfiguration(target: 'config' | 'examples'): Promise<void>
25
- ```
26
-
27
- OIDC 从受信 Profile 对应的 Discovery 构造 HTTP(S) 授权 URL。此 URL 只交给 Host 服务;浏览器侧不能传入自选 URL。外壳负责用系统浏览器打开,拒绝非 HTTP(S)、userinfo URL,并且不得记录授权查询参数。插件不自行执行系统命令,不依赖 Electron/Wails 的 JavaScript 包。服务可以稍后加载;移除服务会取消尚未完成的登录。
28
-
29
- 发行方提供 `configFile: {path, examplesPath}` 时,企业服务保持只读,由用户编辑文件后重启应用。若宿主提供 `openConfiguration`,设置显示“打开配置文件”和“查看示例”;RPC 只接收 `config` / `examples`,由宿主解析固定路径,不允许 renderer 传路径或命令。`configuration().configFile.canOpen` 声明是否可直接打开;Web 或未提供该能力的宿主显示配置文件位置作为备用。个人 API Key 设置和已配置企业的身份登录继续可用。
30
-
31
- 资源绑定兼容既有 `worker.user-center.v1`、过渡写法 `worker-user-center/v1` 与 `eduwork-resources/v1`。未知版本或不匹配的 Provider ID 在创建模型凭据前拒绝,保留已完成的身份登录,并提示检查模型资源服务或企业配置;它们不是身份验证失败。
32
-
33
- 宿主必须提供 `credentials.resolve/set/unset`。本插件没有明文凭据文件或存储失败后的备用路径;桌面发行方负责接入操作系统保险库。模型调用仍使用独立运行 Key,OAuth token 不经 RPC 返回 renderer。`oidcAccounts.authorizedFetch()` 仍是 Host-only 公共授权请求入口。
34
-
35
- 只有用户点击登录时才监听 `127.0.0.1`。默认随机端口,回调为 `http://127.0.0.1:<port>/oauth/callback`;需在身份提供方注册支持动态 loopback 端口的公共 PKCE 客户端。若身份提供方只接受精确回调端口,可在受信配置固定 `callbackPort`(端口占用时明确失败,不改用未注册端口)。不支持配置其他监听地址。取消、失效、成功、合法回调失败、服务卸载和 Host 退出均清理监听。错误路径、Host、Origin、state 或 HTTP 方法不会消费合法的待登录状态。
36
-
37
- RPC 扩展(共用 Host/Client Typert schema):
38
-
39
- | 方法 | 返回 |
40
- | --- | --- |
41
- | `begin(profileID)` | 桌面返回 `{mode:'external', loginID, expiresAt}`;Web 仍返回 `redirect`,旧 native 仍可返回 `completed`。 |
42
- | `loginStatus(loginID)` | `{loginID, profileID, state, expiresAt, status?, errorCode?}`。state 为 pending/completed/cancelled/expired/failed。 |
43
- | `cancelLogin(loginID)` | 同上;等待正在写入的登录撤回,避免取消后重新出现凭据。 |
44
- | `openConfiguration(target)` | 文件管理模式下返回 `{opened:true}`;目标仅为 `config` / `examples`。系统打开失败时返回简短提示。 |
45
- | `selectEnterpriseModel(profileID, {onlyIfMissing?})` | DSH 0.1.5 上返回 `{changed, selection?}`,通过官方 `agentDefaultModel.saveSelection()` 保存企业默认模型。 |
46
-
47
- 客户端账号快照由登录页、侧栏和企业设置共享。宿主凭据 Provider 应在 set/unset 后按官方契约发出 `credentials/reference-updated`;客户端监听该标准 Remote 事件及 `connection/reset`,不依赖不会由官方 Remote 转发的自定义账号事件。
48
-
49
- 明确登录并连接 Key 或确认创建 Key 后,自动选择企业目录中第一个可解析模型。还没有会话时也会保存未来会话的默认值;存在主会话时通过官方 `modelDirectories.directoryFor(sessionID).select()` 同步当前选择,不改子代理。宿主应加载官方 `agentDefaultModel` 和可写 `settings` 服务。旧宿主缺少此能力时明确提示从模型菜单选择。
50
-
51
- 升级后的首次加载使用 `onlyIfMissing:true`:已有有效默认值则保留,缺失或已不能解析才修复;当前会话中可用的个人选择也保留。凭据事件、检查连接和后续状态刷新不会切模型,个人 Key 与其他设置不受影响。
52
-
53
- 双桌面联调可运行 `node scripts/serve-desktop-oidc-fixture.mjs --config <新的测试配置文件>`。脚本只绑定本机随机端口,生成合成身份、完整 HTTP PKCE/Key/模型/配额服务及公开 JSONC 配置;配置文件必须不存在,不覆盖用户配置。每套外壳使用独立测试数据目录;用 Ctrl+C 关闭服务。服务不接触真实账号,也不消耗模型额度。
54
-
55
- `loginID` 是独立随机句柄,不是 OAuth state。响应不包含授权 URL、code、nonce、PKCE verifier 或 token。前端以一秒间隔轮询,显示在浏览器中完成登录与取消按钮;登录最长十分钟,页面卸载取消尚未完成的尝试。关闭外部浏览器无法被跨平台可靠检测,用户可在应用中取消,或等待短时监听过期。
56
-
57
- 空 Profile 是有效配置,不会监听端口,也不要求机构登录。纯身份 Profile 不要求资源端点;登出仅移除该机构的身份/托管 Key,个人 API Key 保留。身份登录成功后资源接口暂不可用时保留已登录身份,后续可以重试资源连接。
58
-
59
- 验证入口:`node --test test/desktop.test.js test/desktop-host.test.js`。后者可通过 `DSH_OIDC_PACKAGE_ROOT` 指向安装的冻结包目录,并设置 `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`,使用该安装目录的真实 DSH 依赖运行无 WebServer 的 Host、可选浏览器服务和 loopback PKCE 验证。所有凭据与用户均为测试合成值;产品主进程保险库、窗口和操作系统浏览器行为仍由发行方联合验收。
60
-
61
- `.20260910.6` 的公共侧栏头像显示账户刷新和注销;配额内容由可选机构扩展提供。菜单通过 portal 支持收窄侧栏;支持方向键、Home/End、Escape、外部点击/失焦关闭。注销清理该机构本地身份、模型 Key、模型元数据缓存,序列化保险库写操作并拒绝旧请求写回;个人 Key 不受影响。
62
-
63
- 临时 HTTP 回调页读取本次 Profile 的 `brand.productName/organizationName/logoURL/mark/primaryColor`,按浏览器 Accept-Language 选择中英文。没有外部字体、脚本或原始错误回显,清楚提示返回应用。普通 Web 验证仍跳回本地应用;不会把生产模型 Key 交给浏览器。
64
-
1
+ # 无常驻 Web 服务的桌面宿主
2
+
3
+ [English](desktop-host.en.md)
4
+
5
+ `backend: desktop` 通过临时 loopback 回调接入桌面登录,复用 Web 后端的 OIDC 校验、Host credentials、Key Binding 和模型发现协议。既有 `web` 和 Go 桥 `native` 配置继续可用。
6
+
7
+ ```yaml
8
+ - id: enterprise-oidc
9
+ name: '@eduwork/dsh-oidc'
10
+ config:
11
+ backend: desktop
12
+ allowEmptyProfiles: true
13
+ profilePathEnv: EDUWORK_OIDC_PROFILE
14
+ desktop:
15
+ callbackPort: 0
16
+ flowTimeoutMs: 600000
17
+ ```
18
+
19
+ 宿主应注册 Cordis `desktopServices` 服务,提供 Host-only 方法:
20
+
21
+ ```ts
22
+ openExternal(url: string): Promise<void>
23
+ // 可选:仅打开宿主预先确定的配置文件或示例目录。
24
+ openConfiguration(target: 'config' | 'examples'): Promise<void>
25
+ ```
26
+
27
+ OIDC 从受信 Profile 对应的 Discovery 构造 HTTP(S) 授权 URL。此 URL 只交给 Host 服务;浏览器侧不能传入自选 URL。外壳负责用系统浏览器打开,拒绝非 HTTP(S)、userinfo URL,并且不得记录授权查询参数。插件不自行执行系统命令,不依赖 Electron/Wails 的 JavaScript 包。服务可以稍后加载;移除服务会取消尚未完成的登录。
28
+
29
+ 发行方提供 `configFile: {path, examplesPath}` 时,企业服务保持只读,由用户编辑文件后重启应用。若宿主提供 `openConfiguration`,设置显示“打开配置文件”和“查看示例”;RPC 只接收 `config` / `examples`,由宿主解析固定路径,不允许 renderer 传路径或命令。`configuration().configFile.canOpen` 声明是否可直接打开;Web 或未提供该能力的宿主显示配置文件位置作为备用。个人 API Key 设置和已配置企业的身份登录继续可用。
30
+
31
+ 资源绑定兼容既有 `worker.user-center.v1`、过渡写法 `worker-user-center/v1` 与 `eduwork-resources/v1`。未知版本或不匹配的 Provider ID 在创建模型凭据前拒绝,保留已完成的身份登录,并提示检查模型资源服务或企业配置;它们不是身份验证失败。
32
+
33
+ 宿主必须提供 `credentials.resolve/set/unset`。本插件没有明文凭据文件或存储失败后的备用路径;桌面发行方负责接入操作系统保险库。模型调用仍使用独立运行 Key,OAuth token 不经 RPC 返回 renderer。`oidcAccounts.authorizedFetch()` 仍是 Host-only 公共授权请求入口。
34
+
35
+ 只有用户点击登录时才监听 `127.0.0.1`。默认随机端口,回调为 `http://127.0.0.1:<port>/oauth/callback`;需在身份提供方注册支持动态 loopback 端口的公共 PKCE 客户端。若身份提供方只接受精确回调端口,可在受信配置固定 `callbackPort`(端口占用时明确失败,不改用未注册端口)。不支持配置其他监听地址。取消、失效、成功、合法回调失败、服务卸载和 Host 退出均清理监听。错误路径、Host、Origin、state 或 HTTP 方法不会消费合法的待登录状态。
36
+
37
+ RPC 扩展(共用 Host/Client Typert schema):
38
+
39
+ | 方法 | 返回 |
40
+ | --- | --- |
41
+ | `begin(profileID)` | 桌面返回 `{mode:'external', loginID, expiresAt}`;Web 仍返回 `redirect`,旧 native 仍可返回 `completed`。 |
42
+ | `loginStatus(loginID)` | `{loginID, profileID, state, expiresAt, status?, errorCode?}`。state 为 pending/completed/cancelled/expired/failed。 |
43
+ | `cancelLogin(loginID)` | 同上;等待正在写入的登录撤回,避免取消后重新出现凭据。 |
44
+ | `openConfiguration(target)` | 文件管理模式下返回 `{opened:true}`;目标仅为 `config` / `examples`。系统打开失败时返回简短提示。 |
45
+ | `selectEnterpriseModel(profileID, {onlyIfMissing?})` | DSH 0.1.5 上返回 `{changed, selection?}`,通过官方 `agentDefaultModel.saveSelection()` 保存企业默认模型。 |
46
+
47
+ 客户端账号快照由登录页、侧栏和企业设置共享。宿主凭据 Provider 应在 set/unset 后按官方契约发出 `credentials/reference-updated`;客户端监听该标准 Remote 事件及 `connection/reset`,不依赖不会由官方 Remote 转发的自定义账号事件。
48
+
49
+ 明确登录并连接 Key 或确认创建 Key 后,自动选择企业目录中第一个可解析模型。还没有会话时也会保存未来会话的默认值;存在主会话时通过官方 `modelDirectories.directoryFor(sessionID).select()` 同步当前选择,不改子代理。宿主应加载官方 `agentDefaultModel` 和可写 `settings` 服务。旧宿主缺少此能力时明确提示从模型菜单选择。
50
+
51
+ 升级后的首次加载使用 `onlyIfMissing:true`:已有有效默认值则保留,缺失或已不能解析才修复;当前会话中可用的个人选择也保留。凭据事件、检查连接和后续状态刷新不会切模型,个人 Key 与其他设置不受影响。
52
+
53
+ 双桌面联调可运行 `node scripts/serve-desktop-oidc-fixture.mjs --config <新的测试配置文件>`。脚本只绑定本机随机端口,生成合成身份、完整 HTTP PKCE/Key/模型/配额服务及公开 JSONC 配置;配置文件必须不存在,不覆盖用户配置。每套外壳使用独立测试数据目录;用 Ctrl+C 关闭服务。服务不接触真实账号,也不消耗模型额度。
54
+
55
+ `loginID` 是独立随机句柄,不是 OAuth state。响应不包含授权 URL、code、nonce、PKCE verifier 或 token。前端以一秒间隔轮询,显示在浏览器中完成登录与取消按钮;登录最长十分钟,页面卸载取消尚未完成的尝试。关闭外部浏览器无法被跨平台可靠检测,用户可在应用中取消,或等待短时监听过期。
56
+
57
+ 空 Profile 是有效配置,不会监听端口,也不要求机构登录。纯身份 Profile 不要求资源端点;登出仅移除该机构的身份/托管 Key,个人 API Key 保留。身份登录成功后资源接口暂不可用时保留已登录身份,后续可以重试资源连接。
58
+
59
+ 验证入口:`node --test test/desktop.test.js test/desktop-host.test.js`。后者可通过 `DSH_OIDC_PACKAGE_ROOT` 指向安装的冻结包目录,并设置 `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`,使用该安装目录的真实 DSH 依赖运行无 WebServer 的 Host、可选浏览器服务和 loopback PKCE 验证。所有凭据与用户均为测试合成值;产品主进程保险库、窗口和操作系统浏览器行为仍由发行方联合验收。
60
+
61
+ `.20260910.6` 的公共侧栏头像显示账户刷新和注销;配额内容由可选机构扩展提供。菜单通过 portal 支持收窄侧栏;支持方向键、Home/End、Escape、外部点击/失焦关闭。注销清理该机构本地身份、模型 Key、模型元数据缓存,序列化保险库写操作并拒绝旧请求写回;个人 Key 不受影响。
62
+
63
+ 临时 HTTP 回调页读取本次 Profile 的 `brand.productName/organizationName/logoURL/mark/primaryColor`,按浏览器 Accept-Language 选择中英文。没有外部字体、脚本或原始错误回显,清楚提示返回应用。普通 Web 验证仍跳回本地应用;不会把生产模型 Key 交给浏览器。
64
+
65
65
  在与目标 DSH 完全一致的隔离依赖树运行 `npm run check`,不要从旧版本根依赖构建后标为新基线。可再运行 `npm run check:browser`:使用该 Runtime 的 `playwright-core` 和本机 Edge 无头浏览器(可用 `DSH_OIDC_BROWSER_CHANNEL` 指定 Chrome),直接加载编译客户端,验证菜单/多个组件共享状态/注销,并生成品牌回调截图。本检查不替代主进程保险库与真实操作系统浏览器联验。
66
66
 
67
67
  ## macOS 接手验收
@@ -1,44 +1,44 @@
1
- # Development and release preparation
2
-
3
- [简体中文](development.md) | **English**
4
-
5
- The plugin version is `0.2.0`. Its development baseline is DSH `0.1.5-rc.1`, Cordis `4.0.2`, and pi-ai `0.85.1`. Product versions do not determine plugin versions; consult the registry for npm publication status. This stable-version freeze does not change dev.7 runtime sources or replace earlier frozen artifacts.
6
-
7
- ## Verify a clean checkout
8
-
9
- Use Node.js 22 or 24 in this repository:
10
-
11
- ```sh
12
- npm ci
13
- npm run check
14
- ```
15
-
16
- The manifest declares exact development dependencies for the required DSH test closure, and the lock records public-registry URLs and integrity. Upstream prerelease carets may select a later RC, so pinning only direct peers is insufficient. `check:lock` rejects mixed versions, machine paths and missing integrity; `check:dsh` verifies the actually loaded baseline. Do not substitute junctions into a running desktop for a clean installation, or suppress conflicts with `--force` or `--legacy-peer-deps`.
17
-
18
- This is the plugin's development/CI closure, not a full desktop product. Consumers still reuse the host through peerDependencies. The [compatibility matrix](compatibility.en.md) distinguishes historical evidence; a historical peer declaration does not mean every old combination was rerun for each commit.
19
-
20
- The complete check covers TypeScript, the dependency lock and official contracts, Host/Client builds and loading, Node tests, schemas/examples, document links, sensitive-data/license scans, and package inspection. Optional `npm run check:browser` uses Playwright Core with a locally installed Edge/Chrome; `DSH_OIDC_BROWSER_CHANNEL` selects the installed channel (default `msedge`). It downloads no browser and does not replace real distribution login acceptance.
21
-
22
- ## Source map
23
-
24
- | Path | Responsibility |
25
- | --- | --- |
26
- | `src/host/profile.js` | Trusted Profile, bounded branding/models and common credential reference |
27
- | `src/host/oidc.js` | PKCE, Token/UserInfo, Key Binding, sessions and credential ownership |
28
- | `src/host/desktop-oidc.js` | Temporary loopback login shared by both desktop shells |
29
- | `src/host/resources.js` | Conservative model-catalog normalization |
30
- | `src/host/provider/` | Official PiAi Provider and explicit image-transform boundary |
31
- | `src/host/index.js`, `typert.*.js` | Host service, official lifecycle and public RPC |
32
- | `src/client/` | Official settings slots, account/login UI and bounded branding |
33
- | `test/` | Synthetic IdP/gateway, HTTP, Host, migration and race regressions |
34
- | `schema/`, `protocol/` | Profile Schema and implemented resource HTTP contracts |
35
-
36
- `scripts/build-host.mjs` copies native Host ESM to `lib`; tsdown bundles the Client. Do not edit `lib` by hand. New wire fields require corresponding implementation, Schema/OpenAPI, bilingual documentation and contract tests. Avoid mechanical tests for simple presentation/documentation changes.
37
-
38
- ## Public scope and remaining release work
39
-
40
- The public package owns identity, managed keys, model discovery/inference and their account UI. Quota, heartbeat, campus search and speech business services belong in institution/product plugins. [Account extensions](account-extensions.en.md) are Host transport and slot contracts, not hidden institution-feature switches. Examples contain placeholder domains, public client IDs and no secrets.
41
-
42
- CI defines Windows/Linux × Node 22/24. A local Windows result does not cover unexecuted matrix cells. Before joint publication, complete the matrix, deployment acceptance and history/supply-chain review on the selected commit, then freeze the stable version, tag and tarball using the [release checklist](release-checklist.en.md). Existing npm versions and frozen artifacts are not rewritten. Local preparation does not push, release or publish.
43
-
44
- Reasoning-field compatibility and its regression checks are documented in [Reasoning replay compatibility](reasoning-replay.en.md). The guide distinguishes a source fix from the installed npm package.
1
+ # Development and release preparation
2
+
3
+ [简体中文](development.md) | **English**
4
+
5
+ The plugin version is `0.2.3`. Its development baseline is DSH `0.1.5-rc.1`, Cordis `4.0.2`, and pi-ai `0.85.1`. Product versions do not determine plugin versions; consult the registry for npm publication status. Source is maintained in EduWork; migration does not overwrite published npm packages.
6
+
7
+ ## Verify a clean checkout
8
+
9
+ Use Node.js 22 or 24 in `EduWork/packages/dsh-oidc`:
10
+
11
+ ```sh
12
+ npm ci
13
+ npm run check
14
+ ```
15
+
16
+ The manifest declares exact development dependencies for the required DSH test closure, and the lock records public-registry URLs and integrity. Upstream prerelease carets may select a later RC, so pinning only direct peers is insufficient. `check:lock` rejects mixed versions, machine paths and missing integrity; `check:dsh` verifies the actually loaded baseline. Do not substitute junctions into a running desktop for a clean installation, or suppress conflicts with `--force` or `--legacy-peer-deps`.
17
+
18
+ This is the plugin's development/CI closure, not a full desktop product. Consumers still reuse the host through peerDependencies. The [compatibility matrix](compatibility.en.md) distinguishes historical evidence; a historical peer declaration does not mean every old combination was rerun for each commit.
19
+
20
+ The complete check covers TypeScript, the dependency lock and official contracts, Host/Client builds and loading, Node tests, schemas/examples, document links, sensitive-data/license scans, and package inspection. Optional `npm run check:browser` uses Playwright Core with a locally installed Edge/Chrome; `DSH_OIDC_BROWSER_CHANNEL` selects the installed channel (default `msedge`). It downloads no browser and does not replace real distribution login acceptance.
21
+
22
+ ## Source map
23
+
24
+ | Path | Responsibility |
25
+ | --- | --- |
26
+ | `src/host/profile.js` | Trusted Profile, bounded branding/models and common credential reference |
27
+ | `src/host/oidc.js` | PKCE, Token/UserInfo, Key Binding, sessions and credential ownership |
28
+ | `src/host/desktop-oidc.js` | Temporary loopback login shared by both desktop shells |
29
+ | `src/host/resources.js` | Conservative model-catalog normalization |
30
+ | `src/host/provider/` | Official PiAi Provider and explicit image-transform boundary |
31
+ | `src/host/index.js`, `typert.*.js` | Host service, official lifecycle and public RPC |
32
+ | `src/client/` | Official settings slots, account/login UI and bounded branding |
33
+ | `test/` | Synthetic IdP/gateway, HTTP, Host, migration and race regressions |
34
+ | `schema/`, `protocol/` | Profile Schema and implemented resource HTTP contracts |
35
+
36
+ `scripts/build-host.mjs` copies native Host ESM to `lib`; tsdown bundles the Client. Do not edit `lib` by hand. New wire fields require corresponding implementation, Schema/OpenAPI, bilingual documentation and contract tests. Avoid mechanical tests for simple presentation/documentation changes.
37
+
38
+ ## Extensions and publication
39
+
40
+ The public package owns identity, managed keys, model discovery/inference and their account UI. Quota, heartbeat, campus search and speech business services belong in institution/product plugins. [Account extensions](account-extensions.en.md) are Host transport and slot contracts, not hidden institution-feature switches. Examples contain placeholder domains, public client IDs and no secrets.
41
+
42
+ Module checks and publication use the [shared EduWork workflow](https://github.com/ecnu/EduWork/blob/main/docs/PACKAGES_EN.md). Validate deployment-specific sign-in separately; published npm versions are immutable.
43
+
44
+ Reasoning-field compatibility and its regression checks are documented in [Reasoning replay compatibility](reasoning-replay.en.md). The guide distinguishes a source fix from the installed npm package.
@@ -2,11 +2,11 @@
2
2
 
3
3
  **简体中文** | [English](development.en.md)
4
4
 
5
- 当前插件版本为 `0.2.0`,开发基线是 DSH `0.1.5-rc.1`、Cordis `4.0.2`、pi-ai `0.85.1`。产品版本不决定插件版本;npm 发布状态以 registry 为准。本次稳定版本冻结不改动 dev.7 的运行源码,也不替换既有冻结 tarball。
5
+ 当前插件版本为 `0.2.3`,开发基线是 DSH `0.1.5-rc.1`、Cordis `4.0.2`、pi-ai `0.85.1`。产品版本不决定插件版本;npm 发布状态以 registry 为准。源码位于 EduWork 的 `packages/dsh-oidc`。
6
6
 
7
7
  ## 从干净 checkout 验证
8
8
 
9
- 使用 Node.js 22 或 24,在本仓库执行:
9
+ 使用 Node.js 22 或 24,在 `EduWork/packages/dsh-oidc` 执行:
10
10
 
11
11
  ```sh
12
12
  npm ci
@@ -37,8 +37,8 @@ Host ESM 由 `scripts/build-host.mjs` 复制至 `lib`,Client 由 tsdown 打包
37
37
 
38
38
  思考内容的字段兼容与回归入口见[思考内容回传兼容](reasoning-replay.md)。该说明区分源码修复与已安装插件包,避免沿用旧 npm 锁时误判为修复已交付。
39
39
 
40
- ## 开源边界与发布待办
40
+ ## 扩展与发布
41
41
 
42
42
  公共包只拥有身份、托管 Key、模型目录/调用及对应账号 UI。配额、心跳、校内检索和语音业务由机构/产品插件负责;[账户扩展](account-extensions.md)是 Host 运输与插槽边界,不是暗中启用机构功能的开关。所有示例均使用占位域名、Public Client ID 与无秘密配置。
43
43
 
44
- CI 声明 Windows/Linux × Node 22/24;本机 Windows 的结果不能代替尚未执行的矩阵单元。下一次共同发行前,应在目标提交上完成矩阵、实际部署联调、历史与供应链审查,再按[发布检查表](release-checklist.md)冻结正式版本、tag 与 tarball。既有 npm 版本和本地冻结包不改写;本地准备不执行 push、release 或 publish。
44
+ 模块通过 EduWork 的统一工作流检查和发布,参见[包维护说明](https://github.com/ecnu/EduWork/blob/main/docs/PACKAGES.md)。依赖锁、合成测试与实际部署登录分别验证;发布包使用新版本,不覆盖已有 npm 版本。
@@ -71,8 +71,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
71
71
  For auditing, development, or validating unpublished changes, install a reviewed local checkout instead:
72
72
 
73
73
  ```bash
74
- git clone https://github.com/freedomkk-qfeng/dsh-oidc.git
75
- cd dsh-oidc
74
+ git clone https://github.com/ecnu/EduWork.git
75
+ cd EduWork/packages/dsh-oidc
76
76
  npm ci
77
77
  npm run check
78
78
  dsh plugin --profile web add .
@@ -71,8 +71,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
71
71
  需要审计、开发或验证尚未发布的改动时,可以安装经过审查的本地 checkout:
72
72
 
73
73
  ```bash
74
- git clone https://github.com/freedomkk-qfeng/dsh-oidc.git
75
- cd dsh-oidc
74
+ git clone https://github.com/ecnu/EduWork.git
75
+ cd EduWork/packages/dsh-oidc
76
76
  npm ci
77
77
  npm run check
78
78
  dsh plugin --profile web add .
@@ -65,8 +65,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
65
65
  For auditing, development, or testing unpublished changes, install from a local checkout instead:
66
66
 
67
67
  ```bash
68
- git clone https://github.com/freedomkk-qfeng/dsh-oidc.git
69
- cd dsh-oidc
68
+ git clone https://github.com/ecnu/EduWork.git
69
+ cd EduWork/packages/dsh-oidc
70
70
  npm ci
71
71
  npm run check
72
72
  dsh plugin --profile web add .
@@ -75,7 +75,7 @@ dsh plugin --profile web add .
75
75
  From the parent directory, the equivalent explicit relative-path command is:
76
76
 
77
77
  ```bash
78
- dsh plugin --profile web add ./dsh-oidc
78
+ dsh plugin --profile web add ./EduWork/packages/dsh-oidc
79
79
  ```
80
80
 
81
81
  DSH links the checkout into `$DSH_HOME/profiles/web`; it does not scan or copy the invoking directory. Keep the checkout in place and pin a reviewed commit for source-based deployments. Production and team Profiles should use an exact npm version and must not mix another DSH prerelease line.
@@ -89,7 +89,7 @@ dsh --profile web --host 127.0.0.1 --port 3080 --no-open
89
89
 
90
90
  The plugin constructs `http://127.0.0.1:<port>/oauth/callback` from the DSH WebServer port. It does not accept `publicBaseURL` and does not infer an address from proxy headers. If the startup port changes, update the OIDC Public Client registration to the same port.
91
91
 
92
- The package's `cordis.patch.yml` mounts one `enterprise-oidc` plugin instance. It does not traverse the current workspace or replace DSH Web, sessions, Workspace, LLM services, the Credential Provider, or other official capabilities. The invoking directory matters only when resolving a relative package path such as `.` or `./dsh-oidc`.
92
+ The package's `cordis.patch.yml` mounts one `enterprise-oidc` plugin instance. It does not traverse the current workspace or replace DSH Web, sessions, Workspace, LLM services, the Credential Provider, or other official capabilities. The invoking directory matters only when resolving a relative package path such as `.` or `./EduWork/packages/dsh-oidc`.
93
93
 
94
94
  ## 6. Advanced product composition
95
95
 
@@ -130,8 +130,8 @@ dsh plugin --profile web add @eduwork/dsh-oidc@0.2.0
130
130
  需要审计、开发或测试尚未发布的改动时,再从本地 checkout 安装:
131
131
 
132
132
  ```bash
133
- git clone https://github.com/freedomkk-qfeng/dsh-oidc.git
134
- cd dsh-oidc
133
+ git clone https://github.com/ecnu/EduWork.git
134
+ cd EduWork/packages/dsh-oidc
135
135
  npm ci
136
136
  npm run check
137
137
  dsh plugin --profile web add .
@@ -140,7 +140,7 @@ dsh plugin --profile web add .
140
140
  也可以在项目父目录中显式传入相对路径:
141
141
 
142
142
  ```bash
143
- dsh plugin --profile web add ./dsh-oidc
143
+ dsh plugin --profile web add ./EduWork/packages/dsh-oidc
144
144
  ```
145
145
 
146
146
  DSH 会把本地 checkout 链接到 `$DSH_HOME/profiles/web`,不会扫描或复制当前目录;安装完成后不要移动或删除 checkout。源码部署应固定经过审核的 commit。生产或团队 Profile 应使用精确 npm 版本,不要混装其他 DSH 预发布线。
@@ -161,7 +161,7 @@ dsh --profile web --host 127.0.0.1 --port 3080 --no-open
161
161
 
162
162
  插件会从 DSH WebServer 的端口构造 `http://127.0.0.1:<port>/oauth/callback`,不接受 `publicBaseURL`,也不会从代理 header 推断地址。若启动参数改变端口,必须同步修改 OIDC Public Client 的登记值。
163
163
 
164
- 安装命令会把 `dsh-oidc` 作为 Bundle 加到 Profile,并由包内 `cordis.patch.yml` 挂载插件。它不会遍历当前工作目录,也不会替换 DSH 的 Web、会话、Workspace、LLM、Credential Provider 或其他官方能力;当前目录只用于解析 `.`、`./dsh-oidc` 等相对安装路径。
164
+ 安装命令会把 `dsh-oidc` 作为 Bundle 加到 Profile,并由包内 `cordis.patch.yml` 挂载插件。它不会遍历当前工作目录,也不会替换 DSH 的 Web、会话、Workspace、LLM、Credential Provider 或其他官方能力;当前目录只用于解析 `.`、`./EduWork/packages/dsh-oidc` 等相对安装路径。
165
165
 
166
166
  ## 6. 高级组合:自定义 Bundle 或桌面宿主
167
167
 
@@ -0,0 +1,73 @@
1
+ # Open Identity and Model Integration Initiative
2
+
3
+ [简体中文](open-integration.md) | **English**
4
+
5
+ **Make institutional accounts and model services reusable across AI clients.**
6
+
7
+ Schools and businesses already have identity systems and are building model services. Users want to sign in with a familiar account and start working in their chosen AI client. Our aim is for one server implementation of an open contract to serve multiple compatible clients, and for a client to connect another organization primarily through configuration.
8
+
9
+ EduWork puts this into practice through `dsh-oidc`. We invite identity platforms, model gateways, client developers, and plugin authors to improve the contract together.
10
+
11
+ > Status: this is a community initiative. The accompanying RFC EW-IDENTITY-1 documents implemented interfaces, with future protocol changes open for discussion. It is not a standard published by DSH, the OpenID Foundation, or the IETF, and does not imply that other clients are already compatible.
12
+
13
+ ## The experience we want to enable
14
+
15
+ A user selects an organization, signs in through the system browser, grants authorization, and confirms credential creation when required. The client then loads the organization's models so the user can start a task. Personal API keys and other models remain available.
16
+
17
+ ```mermaid
18
+ flowchart LR
19
+ A[Choose an organization] --> B[Browser sign-in and authorization]
20
+ B --> C[Confirm when needed and obtain model credentials]
21
+ C --> D[Load available models]
22
+ D --> E[Start working]
23
+ ```
24
+
25
+ This is the intended managed-model experience. An organization that only needs identity can start with OIDC alone and let users configure their models, without first building a model-credential service.
26
+
27
+ | Participant | Work we hope to reduce together |
28
+ | --- | --- |
29
+ | Users | Repeatedly copying keys, finding endpoint addresses, and entering model parameters. |
30
+ | Schools and businesses | Reimplementing identity and model integration for each client. |
31
+ | Client developers | Maintaining a separate sign-in, credential, and model adapter for every organization. |
32
+ | Plugin authors | Implementing another sign-in flow or storing another copy of a user's credentials in a tool plugin. |
33
+
34
+ ## What we propose to agree on
35
+
36
+ 1. **Use existing identity standards.** Use OpenID Connect with PKCE for local public clients, and derive identity from verified OIDC results. Resource services authorize model access without replacing the identity source.
37
+ 2. **Define an open model-access contract.** Specify requests and responses for credential state, provisioning, resolution, renewal, and model catalogs. OIDC handles identity; model credentials and catalogs require separate resource APIs. Successful sign-in alone does not establish model integration.
38
+ 3. **Keep institution configuration as data.** Declare branding, trusted endpoints, and model policy in local configuration. Configuration cannot deliver scripts, install tools, or replace executable modules. Add behavior through explicitly installed plugins.
39
+ 4. **Preserve user choice and institution boundaries.** Institutional and personal models can coexist. Public integration does not require a particular school, desktop shell, quota system, or activity heartbeat. Institution-specific capabilities remain optional extensions.
40
+ 5. **Make compatibility verifiable.** Document fields, errors, versions, and migrations in specifications, OpenAPI, examples, and tests. Follow the [compatibility policy](compatibility.en.md) when changing the protocol, so clients do not have to guess.
41
+
42
+ ## Build on the existing implementation
43
+
44
+ The protocol and client implementation are available for server integration and client interoperability work.
45
+
46
+ | Part | Current scope | Start here |
47
+ | --- | --- | --- |
48
+ | Identity | OIDC Discovery, Authorization Code + PKCE, Token, JWKS, and UserInfo, including identity-only mode. | [OIDC interoperability requirements](oidc-interoperability.en.md) |
49
+ | Managed credentials | Bootstrap and the provision, resolve, and renew lifecycle endpoints. | [Complete server interfaces and requests](server-integration-contract.en.md) · [Key Binding OpenAPI](../protocol/openapi.yaml) |
50
+ | Model catalog | A static catalog in trusted configuration, or explicitly enabled `/models` discovery. | [Client modes and model discovery](public-resource-protocol.en.md) |
51
+ | DSH client | The independent npm package `@eduwork/dsh-oidc`, used by EduWork and available to other compatible DSH hosts. | [Module guide](../README_EN.md) · [Desktop host integration](desktop-host.en.md) |
52
+ | Institution extensions | Configuration, skills, and plugins that reuse public integration capabilities. | [EduWork@ECNU example](https://github.com/ecnu/EduWork-ECNU) |
53
+
54
+ A server must implement the interfaces required by its selected mode. This repository does not include a deployable OIDC or Key Binding server. Current clients are single-user local applications; local Web is for validation and does not provide shared multi-user sign-in sessions.
55
+
56
+ Remote organization-profile discovery and remote model-key revocation remain optional proposals in the RFC. Quota and activity heartbeats remain institution extensions. Proposals or capability declarations do not activate unimplemented features. The model gateway uses the documented OpenAI Chat Completions compatible contract; other model and media APIs require separate validation against their own contracts.
57
+
58
+ Other clients can implement these network interfaces without adopting EduWork's UI or desktop shell. Interoperability depends on the declared protocol versions and actual integration results.
59
+
60
+ ## How to participate
61
+
62
+ - **Identity and model platform developers:** start with the [server specification](server-integration-contract.en.md) and [integration guide](getting-started.en.md). Contribute sanitized examples and explain constraints that are difficult for existing platforms to meet.
63
+ - **Client developers:** integrate `dsh-oidc` or implement the network protocol independently. Verify sign-in, credential lifecycle, model catalogs, and error handling; share interoperability results with explicit version information.
64
+ - **Plugin authors:** connect institution capabilities through the [account extension interfaces](account-extensions.en.md), reusing the host's authorized transport and account state where possible.
65
+ - **Specification contributors:** describe use cases and compatibility issues in [EduWork Issues](https://github.com/ecnu/EduWork/issues). Discuss interface changes first, then update the specification, machine-readable contract, examples, and necessary tests following the [contribution guide](../CONTRIBUTING.en.md).
66
+
67
+ Implementations from different organizations and clients are welcome. Use placeholder configuration and synthetic data in examples; report authentication vulnerabilities and credential issues through the [security reporting process](../SECURITY.en.md).
68
+
69
+ ## Relationship to the DSH plugin ecosystem
70
+
71
+ [DSH Desktop's plugin ecosystem initiative](https://github.com/anywhere-labs/dsh-desktop/blob/master/docs/plugin-ecosystem.en.md) promotes plugin composition and collaboration. We share that direction and aim to contribute implementable, discussable public interfaces for identity and model access. The initiatives are independent; this reference does not imply that DSH Desktop has adopted this protocol.
72
+
73
+ The next result we hope to establish together is that one institutional service can connect to more clients through a clear protocol and a small amount of configuration, and continue working across upgrades.