diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9968fc..4dd01850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,18 +5,26 @@ ## [Unreleased] +## [0.5.0] — 2026-10-12 + ### Added +- 千问办公新增 Windows 原生助手接入,WSL 员工通过私有通道提交专属会话并查看进度与结果;审批留在客户端,取消与退出仅处理本次任务,模型、工具、账号及额度遵循客户端设置。 - WorkBuddy 增加 Windows 客户端本地登录接入,WSL 员工通过桌面拥有的私有通道复用客户端自动模型;提供本地登录/API 选择,接入失效时保持原员工绑定。 ### Changed +- 员工编辑改为紧凑的基本信息、技能、连接器和高级权限区域,补齐输入校验与无效改动检测;千问办公员工只编辑名称,工具与审批在客户端设置。 +- 岗位搜索采用同高的搜索框与展开/收起图标,支持清空及键盘焦点恢复;项目列表、看板与排期统一主题颜色和留白。 +- 单聊、群聊与流式回复统一显示可点击链接、重点加粗、换行及代码复制反馈;格式提示保留用户指定格式和原始请求记录。 + - 审批与上报统一使用工作台的背景、字体、边距和中性选中态,移除收件箱独立蓝黑配色及加高顶栏;风险和错误标签沿用全局状态配色。 - 导航与选择控件采用中性灰底、轻量文字和无外框选项组,去除彩色边框与选中底线;保持选中、悬停、键盘焦点及禁用状态的区别,静态分组名称与可点击选项分开显示,主题与群聊列表补齐选中状态语义。 - 关系图谱默认从员工和关联资料开始,能力与配置、完整对象列表、图形和来源信息按需展开;依据侧栏仅在主动查证时打开,并提供真实工作区对象的三步实操引导。 ### Fixed +- Codex 接入检查使用实际解析到的 CLI,并验证员工会话所需的启动参数与工具开关;不兼容的旧安装提示升级,避免显示可用后启动即失败。 - Windows 的 Qoder 探测不再把 IDE 启动器当成代理 CLI,模型选择测试隔离本机目录探测,避免读员工卡片或运行测试时意外打开编辑器。 - WorkBuddy 的模型配置使用自身接入信息,避免读取 Codex 模型缓存。 - 图谱回访已浏览对象时收回重复路径,避免员工、资料来源和文档之间往返造成重复层级;切换对象后回到内容顶部,当前位置显示为文本。 diff --git a/README.md b/README.md index 39185f4e..26e234a0 100644 --- a/README.md +++ b/README.md @@ -22,20 +22,20 @@ Its organizing principle is simple: **the file tree is the org chart.** Roles li For example, an open-source maintenance team can have a repository owner with three supporting roles: an issue researcher, a community operator, and a release engineer. The repository includes an [example workspace](examples/oss-maintainer) with this structure and role budgets. -The v0.4.0 source adds a persistent approval center, project execution with human acceptance, goal and progress workspaces, connected drive browsing, a workspace Markdown vault with manual Mem synchronization, and relationship/organization graph views. Conversations gain image/PDF attachments, a visible thought/tool activity trail, and a Gemini CLI host; Windows can download and install updates after explicit confirmation. See the [release notes](docs/releases/v0.4.0.md) for compatibility changes and [continuing work with an AI team](docs/thread-context-and-collaboration.md) for usage and limits. Older v0.3.0 installers do not include these changes. +The v0.5.0 source adds local WorkBuddy and Qwen Office client connections, improves Agent readiness checks, and refines employee settings, organization search, project layouts and rich conversation replies. See the [v0.5.0 notes](docs/releases/v0.5.0.md) for the local candidate and [continuing work with an AI team](docs/thread-context-and-collaboration.md) for usage and limits. Workspace auto-open diagnostics remain best-effort: an unavailable stderr stream does not turn a diagnostic write into a failed startup. The current source restores an accessible workspace you previously opened and honors explicit workspace overrides. Otherwise, it starts without a workspace; it does not create or open a demo automatically. This empty first-launch behavior ships with v0.2.0. ## Download -RoleWeave is an **early preview**. This source targets **v0.4.0**. The versioned downloads below become available when the release is published; use the [latest published release](https://github.com/bytefolk/roleweave/releases/latest) until then. +RoleWeave is an **early preview**. This source targets **v0.5.0**, currently a local Windows candidate. The downloads below point to the published v0.4.0 installers; use the [latest published release](https://github.com/bytefolk/roleweave/releases/latest) for public packages. | Platform | Download | | --- | --- | | macOS, Apple Silicon | [DMG installer](https://github.com/bytefolk/roleweave/releases/download/v0.4.0/roleweave-0.4.0-arm64.dmg) · [ZIP archive](https://github.com/bytefolk/roleweave/releases/download/v0.4.0/roleweave-0.4.0-arm64.zip) | | Windows, x64 | [EXE installer](https://github.com/bytefolk/roleweave/releases/download/v0.4.0/roleweave-0.4.0-x64.exe) | -See the [v0.4.0 release notes](docs/releases/v0.4.0.md) for this candidate's changes and [all releases](https://github.com/bytefolk/roleweave/releases) for published packages. Intel Mac and Linux installers are not included in this release target. +See the [v0.5.0 notes](docs/releases/v0.5.0.md) for current source changes, the [v0.4.0 release notes](docs/releases/v0.4.0.md) for the published installers and [all releases](https://github.com/bytefolk/roleweave/releases) for published packages. Intel Mac and Linux installers are not included in this release target. **Installation notes:** macOS packages are not Apple Developer ID-signed or notarized, and the Windows installer is not Authenticode-signed. Your operating system may show a security prompt on installation or first launch. The macOS update manifest has a separate cryptographic signature; this does not provide Apple code-signing trust. Windows updates use the HTTPS release feed and the installer's SHA-512 checksum, without publisher verification. Users of older Org Workbench development builds need to install RoleWeave manually once. Existing unsigned Windows builds that disable in-app installation also need one manual upgrade to a build containing this update change. diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 4d9d5596..19c18472 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@roleweave/desktop", - "version": "0.4.0", + "version": "0.5.0", "description": "Electron shell for RoleWeave. Spawns the local control plane and renders the org tree via a whitelisted IPC bridge.", "license": "Apache-2.0", "private": true, diff --git a/apps/desktop/packaging/runtime-layout.cjs b/apps/desktop/packaging/runtime-layout.cjs index 63449485..a324a3d4 100644 --- a/apps/desktop/packaging/runtime-layout.cjs +++ b/apps/desktop/packaging/runtime-layout.cjs @@ -20,6 +20,8 @@ const DESKTOP_RUNTIME_FILES = [ "src/wsl-bootstrap.cjs", "src/workbuddy-bridge.cjs", "src/workbuddy-client.cjs", + "src/qwen-office-bridge.cjs", + "src/qwen-office-client.cjs", "src/docs-ipc.cjs", "src/drive-ipc.cjs", "src/vault-ipc.cjs", @@ -65,6 +67,7 @@ const SERVER_RUNTIME_FILES = [ "src/workbuddy-binary.js", "src/workbuddy-runtime.js", "src/workbuddy-local.js", + "src/qwen-office-local.js", "src/local-provider-config.js", "src/windows-launcher.js", "dist/src/agent-binding.js", @@ -114,6 +117,7 @@ const SERVER_RUNTIME_FILES = [ "dist/src/per-key-lock.js", "dist/src/qoder-binary.js", "dist/src/qoder-model-catalog.js", + "dist/src/qwen-office-local.js", "dist/src/relationships/project.js", "dist/src/routes/approvals.js", "dist/src/routes/assets.js", @@ -295,9 +299,11 @@ const APP_RESOURCE_REQUIRED_ENTRIES = [ "apps/server/src/workbuddy-binary.js", "apps/server/src/workbuddy-runtime.js", "apps/server/src/workbuddy-local.js", + "apps/server/src/qwen-office-local.js", "apps/server/dist/src/workbuddy-binary.js", "apps/server/dist/src/workbuddy-runtime.js", "apps/server/dist/src/workbuddy-local.js", + "apps/server/dist/src/qwen-office-local.js", "node_modules/@roleweave/shared/package.json", "node_modules/@roleweave/shared/dist/index.js", "node_modules/@roleweave/shared/dist/agent-binding.js", diff --git a/apps/desktop/renderer/src/App.tsx b/apps/desktop/renderer/src/App.tsx index 38d484d6..7052a5ec 100644 --- a/apps/desktop/renderer/src/App.tsx +++ b/apps/desktop/renderer/src/App.tsx @@ -451,13 +451,17 @@ function AppInner({ setEditPosition(null); void window.owb.position(editTargetId).then((res) => { if (!alive) return; - const body = res.body as { position?: PositionCardData; code?: string }; + const body = res.body as { position?: PositionCardData; code?: string; agentEngine?: unknown }; if (res.status !== 200 || !body.position) { setEditTargetId(undefined); setOrgFeedback({ tone: "warn", text: t("org.stalePosition") }); return; } setEditPosition(normalizePositionForDisplay(body.position, locale)); + if (isTurnEngine(body.agentEngine)) { + const targetEngine = body.agentEngine; + setPositionEngines(current => ({ ...current, [body.position!.id]: targetEngine })); + } }).catch(() => { if (alive) setEditTargetId(undefined); }); @@ -1828,6 +1832,13 @@ function AppInner({ model: health?.hosts?.["workbuddy-local"]?.model, connection: health?.hosts?.["workbuddy-local"]?.connection, }, + "qwen-office-local": { + configured: health?.hosts?.["qwen-office-local"]?.configured === true, + ready: health?.hosts?.["qwen-office-local"]?.ready === true, + reason: health?.hosts?.["qwen-office-local"]?.nextStep ?? t("office.connectionUnavailable"), + modelPinnable: false, + connection: health?.hosts?.["qwen-office-local"]?.connection, + }, gemini: { configured: health?.hosts?.gemini?.configured === true, ready: health?.hosts?.gemini?.ready === true, @@ -2160,6 +2171,7 @@ function AppInner({ setEditTargetId(undefined)} onSave={(patch) => saveEmployeeProfile(patch, editTargetId)} @@ -2398,6 +2410,7 @@ function AppInner({
void; onSave: (patch: PositionProfilePatch) => Promise<{ ok: true; name: string } | { ok: false; code: string }>; }) { const t = useT(); + const clientManaged = engine === "qwen-office-local"; const [name, setName] = useState(""); const [mode, setMode] = useState("read_only"); const [permissions, setPermissions] = useState({ tools: [], rules: [] }); @@ -90,8 +94,8 @@ export function EditEmployeeDrawer({ const permissionsChanged = initial !== null && permissionFingerprint(permissions) !== permissionFingerprint(initial); const changed = position !== null && ( trimmedName !== position.name - || mode !== position.mode - || permissionsChanged + || (!clientManaged && mode !== position.mode) + || (!clientManaged && permissionsChanged) ); const canSave = position !== null && nameValid && changed && !saving && !busy; @@ -101,8 +105,8 @@ export function EditEmployeeDrawer({ // permission grant this drawer did not intend to touch stays byte-identical. const patch: PositionProfilePatch = {}; if (trimmedName !== position.name) patch.name = trimmedName; - if (mode !== position.mode) patch.mode = mode; - if (permissionsChanged) patch.permissions = permissions; + if (!clientManaged && mode !== position.mode) patch.mode = mode; + if (!clientManaged && permissionsChanged) patch.permissions = permissions; setSaving(true); setError(null); const outcome = await onSave(patch); @@ -114,7 +118,7 @@ export function EditEmployeeDrawer({ } const copyKey = FAILURE_COPY_KEYS[outcome.code]; setError(copyKey !== undefined ? t(copyKey) : t("profile.failUnknown", { code: outcome.code })); - }, [canSave, messageApi, mode, onClose, onSave, permissions, permissionsChanged, position, t, trimmedName]); + }, [canSave, clientManaged, messageApi, mode, onClose, onSave, permissions, permissionsChanged, position, t, trimmedName]); return (
{nameValid ? null : } -
+ {!clientManaged ?
chooseAvatarFile(event.target.files?.[0])} />
- + {clientManaged ?

{t("office.clientSettings")}

: }

{t("hire.memoryTitle")}

{t("hire.memoryHint")}

{MEMORY_OPTIONS.map((option) => )}
-
+ {!clientManaged ?
: null}
{t("hire.budgetTitle")}
{t("hire.poolAllocated", { allocated: allocated.toLocaleString(), total: budgetPoolTokens.toLocaleString() })}
{parsedDayTokens > remainingPool ?

{t("hire.budgetExceeded", { remaining: remainingPool.toLocaleString() })}

: parsedTaskTokens > parsedDayTokens ?

{t("hire.taskBudgetExceeded")}

: null}
- + {clientManaged ?

{t("office.budgetManaged")}

: }
diff --git a/apps/desktop/renderer/src/org/TreeManagement.tsx b/apps/desktop/renderer/src/org/TreeManagement.tsx index 21424054..64a9d929 100644 --- a/apps/desktop/renderer/src/org/TreeManagement.tsx +++ b/apps/desktop/renderer/src/org/TreeManagement.tsx @@ -63,7 +63,7 @@ export function EmployeeSettings({ id, positions, targets, isOwner, descendantCo return () => { alive = false; }; }, [id]); const chooseModel = async (model: string) => { - if (!window.owb.setPositionModel) return; + if (!window.owb.setPositionModel || engine === "qwen-office-local" || !config?.editable) return; setSaving(true); setError(false); try { const res = await window.owb.setPositionModel({ positionId: id, model }); @@ -105,9 +105,10 @@ export function EmployeeSettings({ id, positions, targets, isOwner, descendantCo

{t("manage.model")}

{engine}

- ({ value: model.id, label: `${model.id === "provider-default" ? t(engine === "qwen-office-local" ? "office.currentModel" : "model.agentDefault") : model.name}${model.id === config.recommended ? ` · ${t("model.recommended")}` : ""}` }))} onChange={(model) => void chooseModel(model)} /> +

{t(engine === "qwen-office-local" ? "office.modelReadonly" : "model.switchHint")}

+ {engine === "qwen-office-local" ?

{t("office.clientManaged")}

: null}

{t("manage.reporting")}