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: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

### 修复

- Windows 安装包解压 openXYOS 时修正 `extract-openxyos.cmd` 的 `cmd.exe` 标签(`:liveNodeOk`)。原先写成 `liveNodeOk:`,goto 找不到标签会以退出码 1 结束;文件已齐备时 livez 在 90 秒内未就绪改为警告并继续安装,不再整包 Abort。`.install-ready` 在 layout 通过后、livez 探测前写入,HKCU Run / 登录任务保留,组织页可随后拉起边车。
- Windows 安装把 openXYOS 预配改成 **Setup 子进程**(随包装的 `provision-openxyos.ps1`,NSIS `nsExec` 等待退出码)。子进程用 `tar.exe` 解压到 `%LOCALAPPDATA%\\FreeOS\\openxyos`、整理嵌套/扁平布局、以中完整性启动 FE/BE、通过 `livez` 后才写 `.install-ready`。失败按真实原因提示(解压 / Node / 启动 / 健康检查),不再默认归咎 3780 端口,也不再软跳过 livez。不注册 HKCU Run / 登录计划任务;之后由 FreeOS 启动时带上本机 openXYOS。组织页直接嵌入 `http://127.0.0.1:3780`,不再出现「启动边车」。
- 安装期不再在 livez 探测后 `taskkill` 边车:Setup 把 `start-sidecar.ps1` 写到 `%LOCALAPPDATA%\\FreeOS\\openxyos`,用当前用户(IShellDispatch2 / HKCU Run / 登录计划任务)常驻拉起 FE+BE,确认 `http://127.0.0.1:3780/api/health/livez` 后保持运行。组织页在 `.install-ready` 时自动嵌入本机 openXYOS,不再把「启动边车」当主按钮;仅自动启动失败才显示「重试启动」和中文原因。
- 「下载最新 openXYOS 源码」端到端 UTF-8:Wails 文件夹选择器以 UTF-8 Base64 回传路径(不再把 GBK/ACP 当 UTF-8);落盘前修复 CP1252/Latin-1 误读的目标路径;解压按 zip UTF-8 标志或 GBK 还原中文目录名,避免乱码。
- Windows 知识库本地文件夹挂接:选择器与列表预览按 UTF-8 处理中文路径/文件名,避免 `项目…` 这类乱码;挂接与列表预览不再因向量模型未就绪返回 409。
Expand Down
29 changes: 15 additions & 14 deletions dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"toggleLabel": "Enable organization module",
"on": "Enabled",
"off": "Disabled",
"sidecarUp": "Sidecar online",
"sidecarDown": "Sidecar offline",
"sidecarUp": "Local openXYOS connected",
"sidecarDown": "Opening local openXYOS",
"sidecarOpening": "Opening local openXYOS",
"lastSync": "Last sync",
"neverSynced": "Not synced yet",
"dataPlane": "Data plane",
Expand All @@ -39,7 +40,7 @@
"packAction": "Push to openXYOS",
"packDone": "Asset pack published",
"packRemoteYes": "Landed on the live openXYOS control plane",
"packRemoteNo": "Sidecar offline: wrote the local mirror only",
"packRemoteNo": "Local openXYOS is not connected yet: wrote the local mirror only",
"loopTitle": "Run the growth loop",
"loopBody": "Produce experts / assistants on FreeOS, land them on the control plane as department employees, feed back as colleagues, and leave durable proof below.",
"loopAction": "Run growth loop",
Expand Down Expand Up @@ -69,17 +70,17 @@
"timelineGovernance": "High-risk tool blocked by governance",
"emptyTitle": "First look at Organization",
"emptyBody": "FreeOS on the left owns colleagues, experts / assistants not yet in a department, skills, MCP, and tasks. openXYOS on the right owns department employees, blueprints, modules, and approvals. After Setup the local console opens on its own; you can also run the loop once to see a real cycle.",
"startSidecarTitle": "openXYOS did not start automatically",
"startSidecarBody": "The install-time local console is not reachable. The reason is below; click Retry after you fix it.",
"startSidecarAction": "Retry start",
"startSidecarTitle": "Opening local openXYOS",
"startSidecarBody": "Organization opens the local test URL http://127.0.0.1:3780 directly.",
"startSidecarAction": "Open local openXYOS",
"sidecarStarted": "Local openXYOS is ready",
"sidecarStartPending": "Connecting to local openXYOS…",
"sidecarRecoverHint": "Only needed when auto-start fails. A healthy install should never ask you to start the sidecar.",
"sidecarAutoStarting": "Connecting the install-time local openXYOS…",
"sidecarAutoStartFailed": "Auto-start failed: {{detail}}",
"sidecarStartPending": "Opening local openXYOS (http://127.0.0.1:3780)…",
"sidecarRecoverHint": "Organization embeds the local openXYOS test URL. There is no separate start step.",
"sidecarAutoStarting": "Opening local openXYOS (http://127.0.0.1:3780)…",
"sidecarAutoStartFailed": "Local openXYOS is not connected yet: {{detail}}",
"bridgeHint": "FreeOS produces experts / assistants not yet in a department, plus skills, plugins, and MCPs. Those assets assemble into openXYOS as department employees; org blueprints and policies feed back as colleagues.",
"home": "Data home",
"sidecar": "Sidecar URL",
"sidecar": "Local openXYOS URL",
"notesTitle": "How this module is wired",
"catalogTitle": "openXYOS capabilities",
"colKey": "Key",
Expand All @@ -96,8 +97,8 @@
"enabled": "Organization module enabled",
"disabled": "Organization module disabled",
"previewTitle": "openXYOS preview",
"previewOffline": "Sidecar is offline. Start it to preview the organization console here.",
"previewLoading": "Starting openXYOS…",
"previewOffline": "Opening local openXYOS (http://127.0.0.1:3780)…",
"previewLoading": "Opening local openXYOS…",
"fullscreen": "Fullscreen",
"exitFullscreen": "Exit fullscreen",
"downloadSource": "Download latest openXYOS source",
Expand All @@ -110,7 +111,7 @@
"catalogEnabled": "Shown",
"catalogDisabled": "Hidden",
"catalogToggleHint": "When off, the module disappears from the openXYOS preview sidebar.",
"autoStartingSidecar": "Starting the openXYOS sidecar…",
"autoStartingSidecar": "Opening local openXYOS…",
"glossary": "Employees: already assigned to a department. Colleagues: peers in the same organization (use this word in group chat). Experts / smart helpers: not yet placed in a department — manage them on Experts.",
"receiptTitle": "What just happened",
"assembleReceipt": "Imported {{count}} employee(s) assigned to a department. In group chat call them colleagues, not experts.",
Expand Down
29 changes: 15 additions & 14 deletions dashboard/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"toggleLabel": "启用组织模块",
"on": "已启用",
"off": "已关闭",
"sidecarUp": "边车在线",
"sidecarDown": "边车未运行",
"sidecarUp": "本机 openXYOS 已连接",
"sidecarDown": "正在打开本机 openXYOS",
"sidecarOpening": "正在打开本机 openXYOS",
"lastSync": "最近同步",
"neverSynced": "尚未同步",
"dataPlane": "数据面",
Expand All @@ -39,7 +40,7 @@
"packAction": "推送到 openXYOS",
"packDone": "资产包已发布",
"packRemoteYes": "已写入在线 openXYOS 控制面",
"packRemoteNo": "边车离线:仅写入本地镜像",
"packRemoteNo": "本机 openXYOS 尚未连上:仅写入本地镜像",
"loopTitle": "运行自增长循环",
"loopBody": "在 FreeOS 生产专家 / 智能助手,写入控制面成为部门员工,再回流为本组织同事,并在下方留下可核对的证据。",
"loopAction": "运行自增长循环",
Expand Down Expand Up @@ -69,17 +70,17 @@
"timelineGovernance": "高风险工具被治理拦截",
"emptyTitle": "第一次打开组织",
"emptyBody": "左侧 FreeOS 负责同事、尚未入部门的专家 / 智能助手、技能、MCP 与任务;右侧 openXYOS 负责部门员工、蓝图、模块与审批。安装完成后会自动打开本机 openXYOS;也可直接运行组织循环看一次真实闭环。",
"startSidecarTitle": "openXYOS 未能自动启动",
"startSidecarBody": "安装期本机控制台没有连上。下面是具体原因;修好后点「重试启动」。",
"startSidecarAction": "重试启动",
"startSidecarTitle": "正在打开本机 openXYOS",
"startSidecarBody": "组织界面直接访问本机测试网址 http://127.0.0.1:3780。",
"startSidecarAction": "打开本机 openXYOS",
"sidecarStarted": "本机 openXYOS 已就绪",
"sidecarStartPending": "正在自动连接本机 openXYOS…",
"sidecarRecoverHint": "仅在自动启动失败时需要处理。健康安装不应再点「启动边车」。",
"sidecarAutoStarting": "正在自动连接安装期本机 openXYOS…",
"sidecarAutoStartFailed": "自动启动失败:{{detail}}",
"sidecarStartPending": "正在打开本机 openXYOS(http://127.0.0.1:3780)…",
"sidecarRecoverHint": "组织界面直接嵌入本机 openXYOS 测试网址,无需单独启动。",
"sidecarAutoStarting": "正在打开本机 openXYOS(http://127.0.0.1:3780)…",
"sidecarAutoStartFailed": "本机 openXYOS 尚未连上:{{detail}}",
"bridgeHint": "FreeOS 生产尚未入部门的专家 / 智能助手、技能、插件与 MCP;推入 openXYOS 后成为部门员工;组织蓝图与策略再回流,登记为本组织同事。",
"home": "数据目录",
"sidecar": "边车地址",
"sidecar": "本机 openXYOS 地址",
"notesTitle": "模块如何接入",
"catalogTitle": "openXYOS 能力目录",
"colKey": "键",
Expand All @@ -96,8 +97,8 @@
"enabled": "组织模块已启用",
"disabled": "组织模块已关闭",
"previewTitle": "openXYOS 预览",
"previewOffline": "边车未运行。启动后可在此预览组织控制台。",
"previewLoading": "正在启动 openXYOS…",
"previewOffline": "正在打开本机 openXYOS(http://127.0.0.1:3780)…",
"previewLoading": "正在打开本机 openXYOS…",
"fullscreen": "全屏",
"exitFullscreen": "退出全屏",
"downloadSource": "下载最新 openXYOS 源码",
Expand All @@ -110,7 +111,7 @@
"catalogEnabled": "已显示",
"catalogDisabled": "已隐藏",
"catalogToggleHint": "关闭后,该模块会从右侧 openXYOS 预览的侧栏消失。",
"autoStartingSidecar": "正在自动启动 openXYOS 边车…",
"autoStartingSidecar": "正在打开本机 openXYOS…",
"glossary": "员工:已经编入某个部门。同事:同一组织里一起干活的人(群聊里这样叫)。专家 / 智能助手:还没编入部门的帮手,在「专家」页管理。",
"receiptTitle": "刚才的结果",
"assembleReceipt": "已导入 {{count}} 名员工(已入编部门)。群聊里请称他们为同事,不要叫专家。",
Expand Down
138 changes: 23 additions & 115 deletions dashboard/src/pages/Organization/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
} from "../../utils/desktopFolder";
import { message } from "../../utils/antdMessage";
import { resolveOpenxyosSourceDest } from "./pickSourceDest";
import { sidecarRecoverPhase } from "./sidecarRecover";
import styles from "./Organization.module.less";

type ActionKey = "assemble" | "pack" | "loop" | "sidecar" | "produce" | null;
Expand All @@ -57,7 +56,6 @@ export default function OrganizationPage() {
const [lastActionNotes, setLastActionNotes] = useState<string[]>([]);
const [lastReceipt, setLastReceipt] = useState<LastReceipt | null>(null);
const [previewFullscreen, setPreviewFullscreen] = useState(false);
const [previewPending, setPreviewPending] = useState(false);
const [moduleToggles, setModuleToggles] = useState<Record<string, boolean>>(
{},
);
Expand All @@ -67,8 +65,6 @@ export default function OrganizationPage() {
const [produceName, setProduceName] = useState("");
const [produceIma, setProduceIma] = useState("");
const [landed, setLanded] = useState<Record<string, unknown> | null>(null);
const [autoStartFailed, setAutoStartFailed] = useState(false);
const [recoverDetail, setRecoverDetail] = useState("");
const autoStartRef = useRef(false);
const iframeRef = useRef<HTMLIFrameElement | null>(null);

Expand Down Expand Up @@ -178,35 +174,19 @@ export default function OrganizationPage() {
}
};

const startSidecar = (opts?: { silent?: boolean }) =>
const startSidecar = () =>
runAction("sidecar", async () => {
setPreviewPending(true);
setAutoStartFailed(false);
try {
const result = await orgModuleApi.startSidecar();
setLastActionNotes([result.detail, result.command].filter(Boolean));
const next = result.reachable
? await applyOverview(true)
: await waitForSidecar();
if (next?.sidecar_reachable) {
setRecoverDetail("");
if (!opts?.silent) {
message.success(t("organization.sidecarStarted"));
}
return;
}
const detail = result.detail || t("organization.sidecarStartPending");
setAutoStartFailed(true);
setRecoverDetail(detail);
message.error(t("organization.sidecarAutoStartFailed", { detail }));
} catch (err) {
const detail =
err instanceof Error ? err.message : t("organization.actionFailed");
setAutoStartFailed(true);
setRecoverDetail(detail);
message.error(t("organization.sidecarAutoStartFailed", { detail }));
} finally {
setPreviewPending(false);
} catch {
// FreeOS still embeds the local URL; no user-facing start CTA.
}
});

Expand All @@ -219,7 +199,7 @@ export default function OrganizationPage() {
if (!overview || overview.sidecar_reachable) return;
if (!canSilentStart) return;
autoStartRef.current = true;
void startSidecar({ silent: true });
void startSidecar();
}, [canSilentStart, overview, overview?.sidecar_reachable]);

const toggleModule = async (key: string, enabled: boolean) => {
Expand Down Expand Up @@ -396,22 +376,17 @@ export default function OrganizationPage() {
.map((row) => row.key),
[catalog, moduleToggles],
);
const localConsoleUrl = (
overview?.sidecar_url || "http://127.0.0.1:3780"
).replace(/\/$/, "");
const previewUrl = useMemo(() => {
if (!overview?.sidecar_url) return "";
const base = `${overview.sidecar_url.replace(/\/$/, "")}/`;
const base = `${localConsoleUrl}/`;
if (!disabledKeys.length) return base;
return `${base}?freeos_disabled=${encodeURIComponent(
disabledKeys.join(","),
)}`;
}, [overview?.sidecar_url, disabledKeys]);
const showFrame = Boolean(sidecarUp && previewUrl);
const recoverPhase = sidecarRecoverPhase({
sidecarUp,
installReady: Boolean(overview?.install_ready),
startAvailable: Boolean(overview?.start_available),
autoStarting: previewPending || busy === "sidecar",
autoStartFailed,
});
}, [localConsoleUrl, disabledKeys]);
const showFrame = Boolean(previewUrl);

const pushTogglesToPreview = useCallback(() => {
const frame = iframeRef.current?.contentWindow;
Expand Down Expand Up @@ -460,7 +435,7 @@ export default function OrganizationPage() {
<span className={styles.chip}>
{sidecarUp
? t("organization.sidecarUp")
: t("organization.sidecarDown")}
: t("organization.sidecarOpening")}
</span>
<span className={styles.chip}>
{t("organization.lastSync")}: {lastSync}
Expand All @@ -487,47 +462,6 @@ export default function OrganizationPage() {
/>
</div>

{recoverPhase === "starting" && !sidecarUp && (
<section className={styles.recover}>
<p className={styles.recoverTitle}>
{t("organization.sidecarAutoStarting")}
</p>
<p className={styles.recoverBody}>
{t("organization.sidecarStartPending")}
</p>
</section>
)}

{recoverPhase === "recover" && (
<section className={styles.recover}>
<p className={styles.recoverTitle}>
{t("organization.startSidecarTitle")}
</p>
<p className={styles.recoverBody}>
{t("organization.startSidecarBody")}
</p>
{recoverDetail ? (
<p className={styles.recoverBody}>{recoverDetail}</p>
) : null}
<p className={styles.recoverBody}>
{t("organization.sidecarRecoverHint")}
</p>
<Space wrap>
<Button
icon={<Play size={14} />}
loading={busy === "sidecar"}
disabled={!overview?.start_available && !overview}
onClick={() => void startSidecar()}
>
{t("organization.startSidecarAction")}
</Button>
{overview?.start_command && (
<code>{overview.start_command}</code>
)}
</Space>
</section>
)}

{firstRun && (
<section className={styles.empty}>
<p className={styles.emptyTitle}>
Expand Down Expand Up @@ -629,7 +563,9 @@ export default function OrganizationPage() {
</div>
<div className={styles.metric}>
<span className={styles.metricValue}>
{sidecarUp ? t("organization.sidecarUp") : "—"}
{sidecarUp
? t("organization.sidecarUp")
: t("organization.sidecarOpening")}
</span>
<span className={styles.metricLabel}>
{t("organization.metricHealth")}
Expand Down Expand Up @@ -914,43 +850,15 @@ export default function OrganizationPage() {
</Space>
</div>
<div className={styles.previewBody}>
{showFrame ? (
<iframe
ref={iframeRef}
title={t("organization.previewTitle")}
src={previewUrl}
className={styles.embed}
allow="clipboard-read; clipboard-write"
onLoad={pushTogglesToPreview}
/>
) : (
<div className={styles.previewEmpty}>
<p className={styles.recoverTitle}>
{recoverPhase === "starting" || previewPending
? t("organization.previewLoading")
: t("organization.startSidecarTitle")}
</p>
<p className={styles.recoverBody}>
{recoverPhase === "starting" || previewPending
? t("organization.sidecarAutoStarting")
: recoverDetail || t("organization.previewOffline")}
</p>
{recoverPhase === "recover" && (
<Space wrap>
<Button
icon={<Play size={14} />}
loading={busy === "sidecar" || previewPending}
onClick={() => void startSidecar()}
>
{t("organization.startSidecarAction")}
</Button>
{overview?.start_command && (
<code>{overview.start_command}</code>
)}
</Space>
)}
</div>
)}
<iframe
key={sidecarUp ? "open" : "opening"}
ref={iframeRef}
title={t("organization.previewTitle")}
src={previewUrl}
className={styles.embed}
allow="clipboard-read; clipboard-write"
onLoad={pushTogglesToPreview}
/>
</div>
</aside>
</div>
Expand Down
Loading
Loading