Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions README.i18n.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
# Bilingual-pair consistency record: the git blob hash of each side as of the last
# confirmed-consistent state. Both languages carry equal authority. Update both files
# and re-record their hashes after editing either side.
README.md: 88fa1de7794bccc9841e53719e4542272472f871
README.zh-CN.md: 4c409b2075e4b9acd264958908d0b1b353f66ba4
README.md: 0001e932629d1d60393f7d5dfab8da9ac5a681fa
README.zh-CN.md: 2739465b697fd7ae4beaa39f230964b25b82b32b
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<p align="center">WorkDSH brings material, experts, skills, and connectors into one workspace, with the SkillHub catalog and installable DSH community plugins.</p>
<p align="center"><a href="#download-desktop">Download Desktop</a> · <a href="#from-material-to-deliverable">Explore the workflow</a> · <a href="#personal-and-enterprise-use">Personal and enterprise</a> · <a href="docs/user-guide.en.md">User guide</a> · <a href="README.zh-CN.md">简体中文</a></p>

[![Desktop release](https://img.shields.io/badge/Desktop-2.0.6--alpha.2-176BFF)](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.2) [![GitHub stars](https://img.shields.io/github/stars/techflag/workdsh?label=stars)](https://github.com/techflag/workdsh) [![MIT License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Desktop release](https://img.shields.io/badge/Desktop-2.0.6--alpha.3-176BFF)](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.3) [![GitHub stars](https://img.shields.io/github/stars/techflag/workdsh?label=stars)](https://github.com/techflag/workdsh) [![MIT License](https://img.shields.io/badge/license-MIT-green)](LICENSE)

![WorkDSH projects home with project templates and the complete desktop sidebar](apps/web/assets/screenshots/workdsh-projects-alpha8-dark.png)

Expand Down Expand Up @@ -81,7 +81,14 @@ The enterprise backend is developed and deployed independently in **[techflag/wo

Administrators should follow the [workdsh-admin deployment and usage guide](https://github.com/techflag/workdsh-admin#readme), then provide members with the backend address and company accounts. Members install this repository's desktop app and Enterprise Connection plugin and connect to that address; the Agent and tools continue to run on their computer.

### Install enterprise plugins
### Enterprise Connection: download, install and sign in

**Enterprise features are enabled by an explicitly installed Enterprise Connection plugin, not bundled in the base Desktop.** One package provides company accounts, colleague collaboration and authenticated requests for independent business plugins.

1. Download `workdsh-enterprise-connection-0.1.0-alpha.2.tgz` from this release and retain the file.
2. In personal mode, open Plugins → Add plugin, enter the full tgz path, install and click Enable now.
3. Open Settings → Enterprise account → Connect enterprise and sign in using the company backend address and member account.
4. Open Collaboration to review shares and configure the company API manually in model settings. Developers can inject `workdshEnterprise`; see the [integration guide](docs/ENTERPRISE-PLUGIN-AUTH.md).

The Enterprise Connection package is delivered independently through our [GitHub Releases](https://github.com/techflag/workdsh/releases), without a third-party marketplace. Download `workdsh-enterprise-connection-<version>.tgz`, retain the file and enter its full path in Add plugin. Release assets include the compatible DSH version manifest and `SHA256SUMS`.

Expand Down Expand Up @@ -148,20 +155,24 @@ WorkDSH Admin — organization overview:

## Download Desktop

The planned desktop installer release is **2.0.6-alpha.2**. Its download links will become available after the [GitHub Release](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.2) is published:
The planned desktop installer release is **2.0.6-alpha.3**. Its download links will become available after the [GitHub Release](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.3) is published:

| Platform | Download |
| --- | --- |
| Windows x64 | [WorkDSH Setup.exe](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-windows-x64--WorkDSH-2.0.6-alpha.2-x64-Setup.exe) |
| macOS Apple Silicon | [WorkDSH arm64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-macos-arm64--WorkDSH-2.0.6-alpha.2-arm64.dmg) |
| macOS Intel | [WorkDSH x64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-macos-x64--WorkDSH-2.0.6-alpha.2-x64.dmg) |
| Windows x64 | [WorkDSH Setup.exe](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-windows-x64--WorkDSH-2.0.6-alpha.3-x64-Setup.exe) |
| macOS Apple Silicon | [WorkDSH arm64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-macos-arm64--WorkDSH-2.0.6-alpha.3-arm64.dmg) |
| macOS Intel | [WorkDSH x64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-macos-x64--WorkDSH-2.0.6-alpha.3-x64.dmg) |

Desktop installers include Node.js, pnpm and Python runtimes by default, so users do not need to install them separately. This is an **Alpha release**: end-to-end project document references, expert execution, and different Office formats are still being validated. The macOS DMGs are unsigned; download updates from [Releases](https://github.com/techflag/workdsh/releases). Start with the [user guide](docs/user-guide.en.md) and [FAQ](docs/faq.en.md).

The base Desktop package does not preinstall enterprise plugins. Install them separately to enable enterprise login. For existing downloads, available features are described in their corresponding release notes.

The **Tools → Terminal command dsh (optional)** menu lets you inspect, install, repair or remove the terminal command. Desktop chat does not require it; its dialog appears only when you select the menu. Installation creates a command entry using the packaged Node, pnpm and official CLI. Removing it does not delete the app or workspace. Commands display the active Desktop space; use `--workdsh-space=personal` or `--workdsh-space=enterprise` to select it explicitly. Initialize the space in Desktop first and keep Desktop signed in for enterprise operations. Plugin changes apply to that space’s Profile.

### Build plugins with enterprise authentication

Host plugins inject `workdshEnterprise` and call `request({ plugin: "reports", operation: "list", method: "POST", body: { page: 1 } })`. Desktop attaches the current member authentication without exposing tokens. The backend must authorize every business operation. See the [integration guide](docs/ENTERPRISE-PLUGIN-AUTH.md) for code, type-package setup and the required new Desktop/plugin versions.

## Development and documentation

Source ownership: [WorkDSH feature packages and Web](apps/web/README.md) · [Desktop carrier](apps/desktop/README.md) · [Architecture](docs/architecture.en.md) · [All documentation](docs/README.en.md). Running from source requires Node.js 22.19+ or 24+, Corepack, and Yarn 4.18.0:
Expand Down
23 changes: 17 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<p align="center">WorkDSH 将资料、专家、技能和连接器带入同一工作台;接入 SkillHub 技能目录,并支持安装 DSH 社区插件。</p>
<p align="center"><a href="#下载桌面版">下载桌面版</a> · <a href="#从资料到成果">了解工作流</a> · <a href="#个人与企业使用">个人与企业</a> · <a href="docs/user-guide.md">使用指南</a> · <a href="README.md">English</a></p>

[![Desktop release](https://img.shields.io/badge/Desktop-2.0.6--alpha.2-176BFF)](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.2) [![GitHub stars](https://img.shields.io/github/stars/techflag/workdsh?label=stars)](https://github.com/techflag/workdsh) [![MIT License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Desktop release](https://img.shields.io/badge/Desktop-2.0.6--alpha.3-176BFF)](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.3) [![GitHub stars](https://img.shields.io/github/stars/techflag/workdsh?label=stars)](https://github.com/techflag/workdsh) [![MIT License](https://img.shields.io/badge/license-MIT-green)](LICENSE)

![WorkDSH 项目主页:项目、模板与完整桌面侧栏](apps/web/assets/screenshots/workdsh-projects-alpha8-dark.png)

Expand Down Expand Up @@ -81,7 +81,14 @@ Desktop 的个人与企业空间分别保存数据和凭据。企业账号插件

管理员请按 [workdsh-admin 的部署与使用说明](https://github.com/techflag/workdsh-admin#readme) 部署后台,并向成员提供后台地址和公司账号。成员安装本仓库的桌面端与企业连接插件后连接该地址;Agent 与工具仍在成员本机执行。

### 安装企业插件
### 企业连接插件:下载、安装与登录

**企业功能通过企业连接插件按需启用,基础桌面包不预装。** 一个包提供企业账号、@同事协作,并向独立业务插件提供认证请求服务。

1. 下载本次发行的 `workdsh-enterprise-connection-0.1.0-alpha.2.tgz`,保留文件。
2. 在个人空间打开“插件 → 添加插件”,填写 tgz 完整路径,安装后点击“立即启用”。
3. 打开“设置 → 企业账号 → 连接企业”,填写公司后台地址和成员账号登录。
4. 在“协作”查看分享,在模型设置中手动配置公司内部 API。开发者可注入 `workdshEnterprise` 复用认证,详见[调用说明](docs/ENTERPRISE-PLUGIN-AUTH.md)。

企业连接包由本项目 [GitHub Releases](https://github.com/techflag/workdsh/releases) 独立交付,不依赖第三方插件市场。下载 `workdsh-enterprise-connection-<版本>.tgz`,保留文件并在添加插件时填写完整路径;发行附件包含兼容 DSH 版本的清单及 `SHA256SUMS`。

Expand Down Expand Up @@ -156,20 +163,24 @@ WorkDSH Admin:组织概览。

## 下载桌面版

计划发布的桌面安装包版本为 **2.0.6-alpha.2**。发布 [GitHub Release](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.2) 后,以下下载链接才会生效:
计划发布的桌面安装包版本为 **2.0.6-alpha.3**。发布 [GitHub Release](https://github.com/techflag/workdsh/releases/tag/desktop-v2.0.6-alpha.3) 后,以下下载链接才会生效:

| 平台 | 下载 |
| --- | --- |
| Windows x64 | [WorkDSH Setup.exe](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-windows-x64--WorkDSH-2.0.6-alpha.2-x64-Setup.exe) |
| macOS Apple Silicon | [WorkDSH arm64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-macos-arm64--WorkDSH-2.0.6-alpha.2-arm64.dmg) |
| macOS Intel | [WorkDSH x64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.2/dsh-plugin-desktop-macos-x64--WorkDSH-2.0.6-alpha.2-x64.dmg) |
| Windows x64 | [WorkDSH Setup.exe](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-windows-x64--WorkDSH-2.0.6-alpha.3-x64-Setup.exe) |
| macOS Apple Silicon | [WorkDSH arm64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-macos-arm64--WorkDSH-2.0.6-alpha.3-arm64.dmg) |
| macOS Intel | [WorkDSH x64.dmg](https://github.com/techflag/workdsh/releases/download/desktop-v2.0.6-alpha.3/dsh-plugin-desktop-macos-x64--WorkDSH-2.0.6-alpha.3-x64.dmg) |

Desktop 安装包默认内置 Node.js、pnpm 和 Python 运行时,普通用户无需单独安装。当前为 **Alpha 版**:项目资料引用、专家执行及不同 Office 格式的端到端体验仍在验收中。macOS DMG 未签名;更新请从 [Releases](https://github.com/techflag/workdsh/releases) 下载。开始使用前请阅读[用户指南](docs/user-guide.md)和[常见问题](docs/faq.md)。

Desktop 基础包不预装企业插件,安装企业插件后启用企业登录。已有下载版本的功能以对应发行说明为准。

桌面菜单“工具 → 终端命令 dsh(可选)”可查看、安装、修复和移除终端命令。普通桌面聊天无需安装此命令,只有主动点击菜单才显示管理弹窗。安装只创建命令入口,使用随包的 Node、pnpm 和官方 CLI;移除命令不会删除应用或工作区。命令默认操作当前 Desktop 工作区,启动时显示空间名称;`--workdsh-space=personal` 或 `--workdsh-space=enterprise` 可明确选择。企业空间须保持 Desktop 登录,首次使用前先在 Desktop 打开对应空间。插件安装、更新和移除遵循该空间的官方 Profile。

### 开发需要企业认证的插件

企业业务插件注入 `workdshEnterprise`,通过 `request({ plugin: "reports", operation: "list", method: "POST", body: { page: 1 } })` 请求公司后台。Desktop 自动携带当前成员认证,插件不读取或保存 Token;后台仍检查成员和业务权限。调用示例、SDK 类型依赖及新旧版本要求见[企业插件认证接入](docs/ENTERPRISE-PLUGIN-AUTH.md)。

## 开发与文档

源码分工:[WorkDSH 功能包与 Web](apps/web/README.zh-CN.md) · [Desktop 外壳](apps/desktop/README.zh.md) · [架构](docs/architecture.md) · [全部文档](docs/README.md)。从源码运行需要 Node.js 22.19+ 或 24+、Corepack 和 Yarn 4.18.0:
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dsh-plugin-desktop",
"version": "2.0.6-alpha.2",
"version": "2.0.6-alpha.3",
"description": "WorkDSH Electron carrier for a pinned DeepSeek Harness runtime Profile",
"license": "MIT",
"publishConfig": {
Expand Down
9 changes: 5 additions & 4 deletions apps/desktop/src/enterprise-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ export async function startEnterpriseAuthority(login: EnterpriseLogin, deviceId:
const auth = ['/auth/me', '/api/auth/me'].includes(url.pathname) && req.method === 'GET' && !url.search
const ingest = url.pathname === '/visible-sessions/ingest' && ['GET', 'POST', 'DELETE'].includes(req.method ?? '')
const collaboration = !url.search && ((req.method === 'GET' && /^\/api\/collaboration\/(?:contract|colleagues|inbox|sent|notifications|(?:materials|handoffs)\/[\w-]{1,160}|handoffs\/[\w-]{1,160}\/messages)$/.test(url.pathname)) || (req.method === 'POST' && /^\/api\/collaboration\/(?:materials|handoffs|notifications\/[\w-]{1,160}\/read|handoffs\/[\w-]{1,160}\/(?:messages|complete))$/.test(url.pathname)));
if (!auth && !ingest && !collaboration) { reject(404, 'Unknown Desktop operation'); return }
const extension = !url.search && ['GET', 'POST'].includes(req.method ?? '') && /^\/api\/extensions\/[a-z][a-z0-9-]{0,63}\/[a-z][a-z0-9-]{0,63}$/.test(url.pathname)
if (!auth && !ingest && !collaboration && !extension) { reject(404, 'Unknown Desktop operation'); return }
let current: EnterpriseMember
try { current = await login.verify() } catch {
reject(401, 'Enterprise authorization unavailable')
Expand All @@ -128,7 +129,7 @@ export async function startEnterpriseAuthority(login: EnterpriseLogin, deviceId:
if (auth) {
res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ...current, deviceId, backendUrl: login.backendUrl })); return
}
if (collaboration) {
if (collaboration || extension) {
try {
let body: string | undefined;
if(req.method==='POST') {
Expand All @@ -139,9 +140,9 @@ export async function startEnterpriseAuthority(login: EnterpriseLogin, deviceId:
}
const response=await login.request(url.pathname,req.method,body);
if(closing)return;
if(!response.ok){reject(response.status,'Enterprise collaboration rejected');return}
if(!response.ok){reject(response.status, extension ? 'Enterprise extension rejected' : 'Enterprise collaboration rejected');return}
res.writeHead(200,{'Content-Type':'application/json'});res.end(JSON.stringify(await response.json()));
} catch {reject(502,'Enterprise collaboration unavailable')}
} catch {reject(502, extension ? 'Enterprise extension unavailable' : 'Enterprise collaboration unavailable')}
return;
}
try {
Expand Down
30 changes: 30 additions & 0 deletions apps/desktop/tests/enterprise-auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,33 @@ describe('Desktop Main enterprise authority', () => {
await expect(login.verify()).rejects.toThrow('已退出')
})
})

describe('enterprise extension transport', () => {
it('forwards only extension operations with Main-owned authentication and rejects other routes', async () => {
const calls: Array<{url: string; init?: RequestInit}> = [];
let active = true;
const request = (async (url: string | URL | Request, init?: RequestInit) => {
calls.push({url: String(url), ...(init ? {init} : {})});
if (String(url).endsWith('/login')) return json({token, member: actor});
if (String(url).endsWith('/me')) return json(actor, active ? 200 : 401);
return json({reports: [1]});
}) as typeof fetch;
const login = await EnterpriseLogin.login('https://company.test', actor.email, 'password', request);
bridge = await startEnterpriseAuthority(login, 'device-a', () => {}, () => {});
const headers = {Authorization: `Bearer ${bridge.key}`, 'Content-Type': 'application/json'};
const response = await fetch(`${bridge.url}/api/extensions/reports/list`, {method: 'POST', headers, body: '{"page":1}'});
expect(await response.json()).toEqual({reports: [1]});
const forwarded = calls.find(call => call.url.endsWith('/api/extensions/reports/list'))!;
expect(forwarded.init?.headers).toMatchObject({Authorization: `Bearer ${token}`});
expect(forwarded.init?.body).toBe('{"page":1}');
for (const path of ['/api/admin/members', '/api/extensions/reports/list?url=https://evil.test', '/api/extensions/reports/list/extra']) {
expect((await fetch(bridge.url + path, {headers})).status).toBe(404);
}
expect((await fetch(`${bridge.url}/api/extensions/reports/list`, {headers: {...headers, Origin: 'https://evil.test'}})).status).toBe(403);
expect((await fetch(`${bridge.url}/api/extensions/reports/list`, {method: 'DELETE', headers})).status).toBe(404);
expect(calls.filter(call => call.url.includes('/api/extensions/'))).toHaveLength(1);
active = false;
expect((await fetch(`${bridge.url}/api/extensions/reports/list`, {headers})).status).toBe(401);
expect(calls.filter(call => call.url.includes('/api/extensions/'))).toHaveLength(1);
});
});
Loading
Loading