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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

### 变更

- 「对话」会话列表标题栏右侧补上微信式搜索与「+」新建群聊(接入已有 `openGroupChat`)。FreeOS 桌面组织导航始终嵌入 openXYOS 模块(`FREEOS_ORG_INTEGRATED=1` + `FREEOS_ORG_ENABLE=1`),并拉起 bundled Node 运行时;缺失运行时是打包/启动失败,组织页提供重启,而不是静默落到宿主 org-ui。非桌面未集成工作室仍可落到 `/organization/workspace`。已从 Dashboard 包删除宿主旧工作台 UI。装配 / 打包 / 循环仍走 `freeos org` CLI 与 `/api/org-module/*`。桌面首启仍落 `/chat/main`。 / Chat session list header now has WeChat-style search and a + new-group action. FreeOS desktop Org always claims integrated openXYOS and starts the bundled module runtime; a missing runtime is an error/recover overlay, not a host org-ui fallback. Non-desktop studio without integration still uses `/organization/workspace`. Old workbench UI deleted. Assemble/pack/loop remain CLI/API. Desktop first-run still lands on `/chat/main`.
- Windows NSIS 文件复制结束后不再多点一次「下一步」才到结束页;结束页仍让用户勾选「运行 FreeOS」或直接关闭,不会自动启动、也不会自动关窗。静默安装(`/S`)仍不拉起界面。 / After Windows NSIS file copy, Setup advances to the finish page without an extra Next. The user still chooses Run FreeOS or close. No auto-launch / auto-close. Silent `/S` stays headless.
- 桌面首次启动不再要求注册/登录。首屏是可选模型配置(云密钥或本机 Ollama,可跳过);跳过或保存后进入默认智能体对话,而不是停在工作台列表。已有提供商或会话的用户不会被再次拦住。账号仍可稍后在头像菜单里领取,供保存/导出/组织房间使用。首次运行与安全条目一致:不预填云密钥,本机 Ollama 优先。

### 修复

- 组织嵌入仍走 openXYOS 自己的登录(`localStorage token` / sidecar JWT),不把 FreeOS 桌面访客(`auth_token` / `POST /api/auth/local-session`)写进组织房间。重启/恢复 sidecar 始终带 `FREEOS_ORG_LOCAL_TEST=1`,保留 `demo@demo.com` / `user@demo.com`。本机会话跳过组织映射行,不删除、不占用 openXYOS 用户。代理剥离宿主 Cookie 与 `X-FreeOS-*`。 / Org embed keeps openXYOS login; FreeOS local-session must not replace org users. Sidecar restart still seeds test accounts. Proxy drops host cookies and identity headers.
- Windows 升级刷新 `~/.freeos/portable` 时,若目录节点被占用(无法改名为 `portable.previous`,报 “being used by another process”),先尝试结束残留的 portable / `launch.py` 进程,再把新运行时**原地覆盖**进现有文件夹,避免留下空的锁定 `portable` 桩,也不要求重启。 / If renaming `portable` → `portable.previous` fails because the directory is in use, stop leftover host processes and overlay the new runtime in place.
- 桌面 `POST /api/auth/local-session` 对已有 `~/.freeos`(多用户 / 组织映射行)或 WebView 非 `127.0.0.1` Host 返回 403,前端重试后掉进注册登录。本机会话在 loopback / `*.localhost` / Origin 为本机时签发 JWT 并选用已有工作室账号;SPA 在 `/` 跳到 `/projects` 丢掉 `?desktop=1` 之前记住桌面壳。403 修复后的路径是:可选模型配置(云 Key / 本机,可跳过)→ 第一个智能体 `/chat/main`,不经过登录墙,也不停在工作台列表。`/setup` 在 guest 已创建后不再打回登录页。
- Windows 安装 / 覆盖安装 / 同版本重装会刷新 `~/.freeos/portable`:Setup 先结束仍在运行的 FreeOS,写入 `$INSTDIR\FREEOS_INSTALL_STAMP`,并清除已解压树里的 `FREEOS_STAMP`。下次启动按安装戳 + 包内戳重新解压 `packages/` 与内嵌 Dashboard,#88 及后续宿主/界面修复不必再手工热补。用户数据库与设置仍留在 `~/.freeos`。
Expand Down
4 changes: 1 addition & 3 deletions dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@
"pauseReason": "Reason",
"pauseResolveFailed": "Could not resolve this pause",
"pauseResolved": "Pause updated",
"originalAppHint": "Unmigrated App verticals (workflows, contracts, …) still use the original preview — a transition, not the home.",
"originalAppAction": "Open original App (transition)",
"catalogNative": "Host page",
"catalogOriginalApp": "Original App",
"metricPauses": "Pending pauses",
Expand All @@ -197,7 +195,6 @@
"packReceipt": "Packed and pushed to the signed-in openXYOS tenant.",
"packLanded": "Organization workspace {{tenant}}: employees {{employees}}, talent {{talent}}, skills {{skills}}, plugins {{plugins}}",
"packPreviewEmployees": "The preview now opens Employees so you can confirm the result.",
"navWorkbench": "Workbench",
"navWorkspace": "Workspace",
"navAnnouncements": "Announcements",
"navOrgChart": "Org chart",
Expand Down Expand Up @@ -1534,6 +1531,7 @@
"bootstrapKickoff": "Hi — let's get started",
"createSessionFailed": "Failed to create a session — please try again",
"searchSessions": "Search conversations",
"newGroupChat": "New group chat",
"noSearchResults": "No matching conversations",
"expandMore": "Show more",
"pin": "Pin",
Expand Down
4 changes: 1 addition & 3 deletions dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@
"pauseReason": "原因",
"pauseResolveFailed": "无法处理该暂停",
"pauseResolved": "暂停已更新",
"originalAppHint": "尚未迁入的 App 垂类(流程、合同等)仍走原预览——只是过渡,不是首页。",
"originalAppAction": "打开原 App(过渡)",
"catalogNative": "宿主页",
"catalogOriginalApp": "原 App",
"metricPauses": "待处理暂停",
Expand All @@ -197,7 +195,6 @@
"packReceipt": "已打包并推送到当前登录的 openXYOS 租户。",
"packLanded": "本组织工作区 {{tenant}}:员工 {{employees}},人才 {{talent}},技能 {{skills}},插件 {{plugins}}",
"packPreviewEmployees": "右侧预览已打开员工页,可直接核对。",
"navWorkbench": "工作台",
"navWorkspace": "总览",
"navAnnouncements": "通知公告",
"navOrgChart": "组织架构",
Expand Down Expand Up @@ -1534,6 +1531,7 @@
"bootstrapKickoff": "你好,我们开始吧",
"createSessionFailed": "创建会话失败,请重试",
"searchSessions": "搜索会话",
"newGroupChat": "新建群聊",
"noSearchResults": "没有匹配的会话",
"expandMore": "展开更多",
"pin": "置顶",
Expand Down
13 changes: 1 addition & 12 deletions dashboard/src/org-ui/pages/agents/AgentsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export interface AgentsPageProps {
locale: OrgLocale;
/** Present so export App.tsx can pass SHARED_ORG_UI_MODULES without unused props. */
modules?: readonly string[];
workbenchHref?: string;
}

const EMPTY_STATS: OrgColleagueStats = {
Expand Down Expand Up @@ -52,12 +51,7 @@ const EMPTY_FORM: CompileForm = {
capabilities: [],
};

export function AgentsPage({
client,
session,
locale,
workbenchHref = "/organization",
}: AgentsPageProps) {
export function AgentsPage({ client, session, locale }: AgentsPageProps) {
const labels = agentsLabels(locale);
const [colleagues, setColleagues] = useState<OrgColleague[]>([]);
const [stats, setStats] = useState<OrgColleagueStats>(EMPTY_STATS);
Expand Down Expand Up @@ -182,11 +176,6 @@ export function AgentsPage({
</div>
<p className={styles.subtitle}>{labels.subtitle}</p>
</div>
{workbenchHref ? (
<Button href={workbenchHref} data-testid="org-agents-workbench">
{labels.openWorkbench}
</Button>
) : null}
</div>

<section className={styles.callout} data-testid="org-agents-boundary">
Expand Down
2 changes: 0 additions & 2 deletions dashboard/src/org-ui/pages/agents/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const EN = {
openExperts: "FreeOS Experts",
openPersonalization: "Agent personalization",
openEmployees: "Employees directory",
openWorkbench: "Organization workbench",
compileTitle: "Compile a blueprint",
compileHint:
"Writes a tenant workspace (SOUL.md, skills, MEMORY) and registers a draft colleague. No talent-market sidecar, no file-upload studio.",
Expand Down Expand Up @@ -84,7 +83,6 @@ const ZH: typeof EN = {
openExperts: "FreeOS 专家",
openPersonalization: "智能体个性化",
openEmployees: "员工目录",
openWorkbench: "组织工作台",
compileTitle: "编译蓝图",
compileHint:
"写入租户工作区(SOUL.md、技能、MEMORY)并登记为 draft 同事。没有边车人才市场,也没有资料上传工作室。",
Expand Down
13 changes: 1 addition & 12 deletions dashboard/src/org-ui/pages/settings/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export interface SettingsPageProps {
locale: OrgLocale;
/** Present so export App.tsx can pass SHARED_ORG_UI_MODULES without unused props. */
modules?: readonly string[];
workbenchHref?: string;
}

const EMPTY_PREFS: OrgPrefs = { name: "", description: "" };
Expand All @@ -28,12 +27,7 @@ const EMPTY_LINKS: OrgSystemSettingsLinks = {
users: "/system-settings/users",
};

export function SettingsPage({
client,
session,
locale,
workbenchHref = "/organization",
}: SettingsPageProps) {
export function SettingsPage({ client, session, locale }: SettingsPageProps) {
const labels = settingsLabels(locale);
const [catalog, setCatalog] = useState<OrgCapability[]>([]);
const [toggles, setToggles] = useState<Record<string, boolean>>({});
Expand Down Expand Up @@ -132,11 +126,6 @@ export function SettingsPage({
</div>
<p className={styles.subtitle}>{labels.subtitle}</p>
</div>
{workbenchHref ? (
<Button href={workbenchHref} data-testid="org-settings-workbench">
{labels.openWorkbench}
</Button>
) : null}
</div>

<section className={styles.callout} data-testid="org-settings-boundary">
Expand Down
2 changes: 0 additions & 2 deletions dashboard/src/org-ui/pages/settings/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ const EN = {
openSystem: "FreeOS system settings",
openModels: "Models & keys",
openUsers: "Users",
openWorkbench: "Organization workbench",
profileTitle: "Organization profile",
profileHint:
"Shown on this Organization module. Not the FreeOS instance name.",
Expand Down Expand Up @@ -49,7 +48,6 @@ const ZH: typeof EN = {
openSystem: "FreeOS 系统设置",
openModels: "模型与密钥",
openUsers: "用户",
openWorkbench: "组织工作台",
profileTitle: "组织资料",
profileHint: "只用于本组织模块,不是 FreeOS 实例名。",
name: "组织名称",
Expand Down
8 changes: 0 additions & 8 deletions dashboard/src/org-ui/pages/workspace/WorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { workspaceLabels } from "./labels";
import styles from "./WorkspacePage.module.css";

export interface OrgWorkspaceLinks {
workbench: string;
announcements: string;
organization: string;
employees: string;
Expand All @@ -32,12 +31,10 @@ export interface WorkspacePageProps {
locale: OrgLocale;
/** Present so export App.tsx can pass SHARED_ORG_UI_MODULES without unused props. */
modules?: readonly string[];
workbenchHref?: string;
links?: Partial<OrgWorkspaceLinks>;
}

const DEFAULT_LINKS: OrgWorkspaceLinks = {
workbench: "/organization",
announcements: "/organization/announcements",
organization: "/organization/org",
employees: "/organization/employees",
Expand Down Expand Up @@ -79,14 +76,12 @@ export function WorkspacePage({
client,
session,
locale,
workbenchHref,
links,
}: WorkspacePageProps) {
const labels = workspaceLabels(locale);
const hrefs: OrgWorkspaceLinks = {
...DEFAULT_LINKS,
...links,
workbench: workbenchHref || links?.workbench || DEFAULT_LINKS.workbench,
};
const [overview, setOverview] = useState<OrgWorkspaceOverview | null>(null);
const [loading, setLoading] = useState(true);
Expand Down Expand Up @@ -236,9 +231,6 @@ export function WorkspacePage({
<p className={styles.hint}>{labels.hostHint}</p>
<p className={styles.hint}>{labels.roomHint}</p>
</div>
<Button href={hrefs.workbench} data-testid="org-workspace-workbench">
{labels.openWorkbench}
</Button>
</div>

<section
Expand Down
7 changes: 3 additions & 4 deletions dashboard/src/org-ui/pages/workspace/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ const EN = {
subtitle:
"Organization landing overview. Status and links into already-migrated pages — not a second control plane.",
hostHint:
"Assemble, pack, and the growth loop stay on the Organization workbench. This page only summarizes host status.",
"Assemble, pack, and the growth loop stay on `freeos org` / `/api/org-module/*`. This page only summarizes host status.",
notHereTitle: "Chat is not here",
notHereBody:
"openXYOS Chat is not migrated. Conversations stay on FreeOS / Octop. This overview does not open a sidecar inbox.",
openChat: "FreeOS conversations",
openWorkbench: "Organization workbench",
statusTitle: "Organization status",
enabled: "On",
disabled: "Off",
Expand Down Expand Up @@ -66,12 +65,12 @@ const EN = {
const ZH: typeof EN = {
title: "工作台总览",
subtitle: "组织落地页:状态摘要,并链到已迁入宿主的子页。不是第二套控制面。",
hostHint: "装配、打包和自增长循环仍在组织工作台。本页只汇总宿主状态。",
hostHint:
"装配、打包和自增长循环仍走 `freeos org` / `/api/org-module/*`。本页只汇总宿主状态。",
notHereTitle: "对话不在这里",
notHereBody:
"openXYOS Chat 不迁入。对话留在 FreeOS / Octop。本页不会打开边车收件箱。",
openChat: "FreeOS 对话",
openWorkbench: "组织工作台",
statusTitle: "组织状态",
enabled: "已启用",
disabled: "未启用",
Expand Down
25 changes: 22 additions & 3 deletions dashboard/src/pages/Chat/chatSidebar.partial.less
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,34 @@
.sessionHeader {
display: flex;
flex-direction: column;
gap: 10px;
padding: 16px 16px 12px;
gap: 8px;
padding: 12px 12px 8px;
flex-shrink: 0;
}

.sessionHeaderRow {
display: flex;
align-items: center;
gap: 8px;
min-height: 32px;
}

.sessionTitle {
flex: 1;
min-width: 0;
margin: 0;
font-size: 15px;
font-weight: 700;
color: var(--fn-color-brand);
line-height: 1.2;
color: var(--fn-text-primary);
}

.sessionHeaderActions {
display: flex;
align-items: center;
gap: 2px;
flex-shrink: 0;
margin-left: auto;
}

.sessionAddBtn {
Expand Down
6 changes: 2 additions & 4 deletions dashboard/src/pages/Chat/chatThemeOverrides.partial.less
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@
.sessionSearchWrap {
position: relative;
flex-shrink: 0;
margin: 0 0 10px;
margin: 0;
}

.sessionSearchIcon {
Expand Down Expand Up @@ -381,12 +381,10 @@
}

.sessionHeader {
padding: 0 0 12px;
align-items: flex-start;
padding: 0 0 10px;
background: transparent;
border: none;
box-shadow: none;
flex-shrink: 0;
}

.sessionCreateBtn {
Expand Down
27 changes: 25 additions & 2 deletions dashboard/src/pages/Chat/components/MinimalAgentSessionNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { isAgentChatReady } from "../../../utils/agentError";
import { sortSessions, toSession, type Session } from "../hooks/useSessions";
import { formatThreadTitle } from "../utils/threadTitle";
import { onSessionEvent, onStreamEvent } from "../hooks/chatStore";
import SessionListToolbar from "./SessionListToolbar";
import SharedExpertHint from "./SharedExpertHint";
import styles from "../index.module.less";

Expand Down Expand Up @@ -276,6 +277,7 @@ export default function MinimalAgentSessionNav({
const [byAgent, setByAgent] = useState<Record<string, Session[]>>({});
const [workingIds, setWorkingIds] = useState<ReadonlySet<string>>(new Set());
const [loading, setLoading] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [collapsedFolders, setCollapsedFolders] = useState<Set<string>>(() =>
loadCollapsedFolders(),
);
Expand Down Expand Up @@ -494,6 +496,17 @@ export default function MinimalAgentSessionNav({
[activeAgentId, onPinActive, patchLocal],
);

const searchNeedle = searchQuery.trim().toLowerCase();
const visibleAgents = useMemo(() => {
if (!searchNeedle) return sortedAgents;
return sortedAgents.filter((agent) => {
if (agent.name.toLowerCase().includes(searchNeedle)) return true;
return (byAgent[agent.agent_id] ?? []).some((session) =>
session.name.toLowerCase().includes(searchNeedle),
);
});
}, [byAgent, searchNeedle, sortedAgents]);

if (agents.length === 0) {
return (
<div className={styles.sessionEmptyAgents}>
Expand All @@ -513,8 +526,18 @@ export default function MinimalAgentSessionNav({

return (
<div className={`${styles.sessionList} ${styles.minimalAgentNav}`}>
{sortedAgents.map((agent) => {
const list = byAgent[agent.agent_id] ?? [];
<SessionListToolbar
searchQuery={searchQuery}
onSearchQueryChange={setSearchQuery}
agents={sortedAgents}
/>
{visibleAgents.map((agent) => {
const list = (byAgent[agent.agent_id] ?? []).filter((session) =>
searchNeedle
? session.name.toLowerCase().includes(searchNeedle) ||
agent.name.toLowerCase().includes(searchNeedle)
: true,
);
const ready = isAgentChatReady(agent.state);
const expanded = !collapsedFolders.has(agent.agent_id);

Expand Down
Loading
Loading