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

## [Unreleased]

### 新增

- Organization OS 首页双循环:FreeOS 数据面与 openXYOS 控制面的实时状态、一键装配员工 / 打包回流 / 运行 org loop,以及边车离线时的启动恢复。

### 变更

- 桌面更新通道只跟踪 `github.com/XYAIStudio/FreeOS/releases`。不再读取 PyPI `octop`、腾讯云 COS 或其它 Octop 镜像;当前已是最新 FreeOS `v0.0.1` 时不会误报更新。
- 默认主题与残留 Octop `rose` 存储一次性迁移为 XYAI 蓝 `#0033FF`(之后仍可手动选玫瑰粉)。

### 修复

- Windows NSIS uninstall now stops FreeOS / host / sidecar processes and recursively removes `$INSTDIR` (quoted `RMDir /r`, plus a delayed cleanup after `uninstall.exe` exits). If those processes are still running, uninstall asks first (cancel aborts and leaves them running; confirm closes them then wipes the install dir). User profile data under `%USERPROFILE%\.freeos` / `FREEOS_HOME` / legacy `~/.octop` is kept. Product version remains 0.0.1.
Expand Down
2 changes: 1 addition & 1 deletion dashboard/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html lang="en" data-palette="freeos">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favico.svg" />
Expand Down
102 changes: 102 additions & 0 deletions dashboard/src/api/modules/orgModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,115 @@ export interface OrgModuleStatus {
notes: string[];
}

export interface OrgPlaneCounts {
employees: number;
employee_states: Record<string, number>;
agents: number;
spawned_colleagues: number;
org_skills: number;
skill_packages: number;
mcp: number;
tasks: number;
}

export interface OrgControlPlane {
reachable: boolean;
url: string;
detail: string;
modules: number;
governance: boolean;
tenant_id: string;
approvals: number;
}

export interface OrgOverview {
enabled: boolean;
sidecar_reachable: boolean;
sidecar_url: string;
start_available: boolean;
start_command: string;
home: string;
last_sync: string | null;
freeos: OrgPlaneCounts;
openxyos: OrgControlPlane;
last_loop: Record<string, unknown> | null;
notes: string[];
catalog: OrgCapability[];
}

export interface OrgSidecarStart {
started: boolean;
already: boolean;
reachable: boolean;
url: string;
command: string;
detail: string;
launcher: string;
}

export interface OrgAssembleResult {
sidecar_reachable: boolean;
employees: string[];
spawned: Array<{ agent_id: string; slug: string; name: string }>;
imported: Record<string, unknown> | null;
notes: string[];
}

export interface OrgPackResult {
pack: {
directory: string;
skill_count: number;
plugin_count: number;
mcp_count: number;
agent_count: number;
notes: string[];
};
applied: {
pack_dir: string;
mirror_dir: string;
remote_applied: boolean;
mirrored: boolean;
notes: string[];
};
}

export interface OrgLoopProof {
ok: boolean;
tenant_id: string;
home: string;
skills: string[];
employees: string[];
agents: Array<Record<string, unknown>>;
lifecycle: Record<string, string>;
pack_dir: string;
mirror_dir: string;
remote_applied: boolean;
imported_roundtrip: Record<string, unknown>;
governance_blocked: boolean;
governance: Record<string, unknown>;
notes: string[];
updated_at?: string;
}

export const orgModuleApi = {
status: () => request<OrgModuleStatus>("/org-module/status"),
overview: () => request<OrgOverview>("/org-module/overview"),
catalog: () => request<{ modules: OrgCapability[] }>("/org-module/catalog"),
setEnabled: (enabled: boolean, sidecar_url?: string) =>
request<OrgModuleStatus>("/org-module", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ enabled, sidecar_url }),
}),
startSidecar: () =>
request<OrgSidecarStart>("/org-module/sidecar/start", { method: "POST" }),
assemble: () =>
request<OrgAssembleResult>("/org-module/assemble", { method: "POST" }),
pack: () => request<OrgPackResult>("/org-module/pack", { method: "POST" }),
runLoop: () =>
request<OrgLoopProof>("/org-module/loop/run", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({}),
}),
};
6 changes: 3 additions & 3 deletions dashboard/src/api/modules/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ export interface UpdateStatus {
is_editable: boolean;
/** Non-null when the process was launched via `octop service start` (systemd or launchd). */
service_mode: "systemd" | "launchd" | null;
/** True when Octop is spawned by the Wails desktop shell (or ``OCTOP_DESKTOP=1``). */
/** True when FreeOS is spawned by the Wails desktop shell (or ``OCTOP_DESKTOP=1``). */
desktop?: boolean;
error: string | null;
/** Stable error code (e.g. "pypi_unreachable") for localized UI messages; null on success. */
/** Stable error code (e.g. "github_unreachable") for localized UI messages; null on success. */
error_code: string | null;
/** Mirror that served the version info (null/`pypi.org` = official source). */
/** GitHub Releases source label (``github.com/XYAIStudio/FreeOS``). */
source: string | null;
last_check_time: string | null;
/** Markdown changelog for latest_version, null if not available. */
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/hooks/useUpdateStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
storeUpdateStatus,
} from "../utils/updateStatusCache";

/** Shared in-flight probe so Header + Sidebar mounts don't stampede PyPI. */
/** Shared in-flight probe so Header + Sidebar mounts don't stampede GitHub. */
let inFlight: Promise<UpdateStatus | null> | null = null;

async function probeUpdateStatus(): Promise<UpdateStatus | null> {
Expand Down Expand Up @@ -57,7 +57,7 @@ export function useUpdateStatus() {
return () => window.removeEventListener("focus", onFocus);
}, [refreshStatus]);

// Keep checking while the dashboard stays open (cache TTL still gates PyPI).
// Keep checking while the dashboard stays open (cache TTL still gates GitHub).
useEffect(() => {
const id = window.setInterval(() => {
void refreshStatus(false);
Expand Down
104 changes: 71 additions & 33 deletions dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,60 @@
},
"organization": {
"title": "Organization OS",
"subtitle": "Grow AI employees through the FreeOS ↔ openXYOS loop. Enable the organization control plane as a sidecar.",
"subtitle": "A dual loop: FreeOS does the work, openXYOS governs the org — they grow each other.",
"heroTitle": "Organization OS",
"heroStory": "FreeOS does the work. openXYOS owns organization and governance. They grow each other.",
"toggleLabel": "Enable organization module",
"on": "Enabled",
"off": "Disabled",
"sidecarUp": "Sidecar reachable",
"sidecarUp": "Sidecar online",
"sidecarDown": "Sidecar offline",
"bridgeHint": "FreeOS produces employees, skills, plugins, and MCPs. Those assets assemble into openXYOS; org blueprints and policies feed back into FreeOS. Run `freeos org loop run` to prove the loop.",
"lastSync": "Last sync",
"neverSynced": "Not synced yet",
"dataPlane": "Data plane",
"controlPlane": "Control plane",
"flowUp": "Assets back",
"flowDown": "Blueprints out",
"metricEmployees": "Digital employees",
"metricSkills": "Org skills",
"metricMcp": "MCP / connectors",
"metricTasks": "Tasks",
"metricModules": "Governance modules",
"metricGovernance": "Governance engine",
"metricHealth": "Control-plane health",
"metricTenant": "Tenant",
"assembleTitle": "Assemble employees from a blueprint",
"assembleBody": "Compile an openXYOS blueprint (or the bundled fixture) into FreeOS digital employees and register them for chat.",
"assembleAction": "Assemble into FreeOS",
"assembleDone": "Assembled {{count}} digital employee(s)",
"packTitle": "Pack assets back to openXYOS",
"packBody": "Publish FreeOS skills, plugins, and MCP as an asset pack, mirror it, and push to the control plane when live.",
"packAction": "Pack and apply",
"packDone": "Asset pack published",
"packRemoteYes": "Attempted a live write to openXYOS",
"packRemoteNo": "Sidecar offline: wrote the local mirror only",
"loopTitle": "Run the organization loop",
"loopBody": "Blueprint → employees → pack → import → governance block, with a real timeline below.",
"loopAction": "Run org loop",
"loopOk": "Organization loop completed",
"loopPartial": "Loop ran; some steps did not finish (see timeline)",
"timelineTitle": "Loop timeline",
"timelineEmpty": "No loop proof yet. Run the organization loop to see real results here.",
"timelineOk": "Loop result",
"timelineEmployees": "Employees",
"timelineSkills": "Skills",
"timelineRemote": "Pushed to control plane",
"timelineGovernance": "High-risk tool blocked by governance",
"emptyTitle": "First look at Organization OS",
"emptyBody": "FreeOS on the left owns employees, skills, MCP, and tasks. openXYOS on the right owns blueprints, modules, and approvals. Start the sidecar, or run the loop once to see a real cycle.",
"startSidecarTitle": "openXYOS sidecar is offline",
"startSidecarBody": "Live approvals and remote apply need the sidecar. Start it here; if no launcher is bundled, use the command beside the button.",
"startSidecarAction": "Start sidecar",
"sidecarStarted": "Sidecar is reachable",
"sidecarStartPending": "Start attempted; refresh in a moment",
"bridgeHint": "FreeOS produces employees, skills, plugins, and MCPs. Those assets assemble into openXYOS; org blueprints and policies feed back into FreeOS.",
"home": "Data home",
"sidecar": "Sidecar URL",
"startSidecarTitle": "Start the organization sidecar",
"startSidecarBody": "The module is on, but openXYOS is not running. From the repo root:",
"notesTitle": "How this module is wired",
"catalogTitle": "openXYOS capabilities",
"colKey": "Key",
Expand All @@ -31,6 +74,7 @@
"openSidecar": "Open in new tab",
"loadFailed": "Could not load organization module status",
"saveFailed": "Could not update organization module",
"actionFailed": "Action failed",
"enabled": "Organization module enabled",
"disabled": "Organization module disabled"
},
Expand Down Expand Up @@ -201,7 +245,7 @@
"common": "Common",
"control": "Control",
"experts": "Experts",
"organization": "Organization",
"organization": "Organization OS",
"tasks": "Automation",
"connectors": "Connectors",
"acp": "ACP",
Expand Down Expand Up @@ -3052,9 +3096,9 @@
},
"update": {
"title": "Version & Updates",
"description": "Check for the latest release and upgrade in place; use the guide on the right for other install methods.",
"description": "Checks only XYAIStudio/FreeOS GitHub Releases. Does not track upstream Octop or Tencent Cloud install feeds.",
"panelTitle": "Version upgrade",
"panelDesc": "Check for a new release and install it when supported. Restart the service after a successful upgrade.",
"panelDesc": "Prompts only when GitHub has a newer FreeOS desktop build. Restart the desktop app so the shell can apply the portable zip.",
"stableOnlyLabel": "Stable releases only",
"stableOnlyHint": "Automatic checks do not remind you about alpha, beta, rc, or dev builds. You can still check and upgrade to a pre-release manually.",
"prereleaseBadge": "Pre-release",
Expand All @@ -3072,19 +3116,21 @@
"updateAvailable": "New version available",
"upgradeSuccess": "Upgrade completed!",
"upgradeFailed": "Upgrade failed",
"restartHint": "Please restart Octop for the update to take effect.",
"restartHint": "Restart the FreeOS desktop app for the update to take effect.",
"restartCommand": "Restart command",
"editableHint": "Development install detected. Use git pull to update.",
"networkError": "Could not reach update server. Check your network.",
"mirrorSource": "Version info served by mirror {{source}}; it may lag slightly behind pypi.org.",
"networkError": "Could not reach GitHub Releases. Check your network.",
"githubSource": "Version info from {{source}} (XYAIStudio/FreeOS only).",
"mirrorSource": "Version info from {{source}}.",
"errors": {
"pypi_unreachable": "Could not reach PyPI. Check your network and try again."
"github_unreachable": "Could not reach GitHub Releases for XYAIStudio/FreeOS. Check your network and try again.",
"pypi_unreachable": "Could not reach GitHub Releases for XYAIStudio/FreeOS. Check your network and try again."
},
"notChecked": "Not checked yet",
"stageStarting": "Starting...",
"stageDownloading": "Downloading...",
"stageInstalling": "Installing...",
"manualUpgradeHint": "You can also run: octop update --verbose",
"manualUpgradeHint": "You can also run: freeos update --verbose",
"restartServiceBtn": "Restart Service",
"restarting": "Restarting...",
"restartingHint": "This typically takes 1-2 minutes. Please wait.",
Expand All @@ -3093,41 +3139,33 @@
"restartCancel": "Cancel",
"restartSuccess": "Restarted successfully, refreshing...",
"restartReadyHint": "Service is back online. Refreshing shortly.",
"restartTimeout": "Restart timed out. Run manually: octop service restart",
"restartTimeout": "Restart timed out. Quit and reopen the FreeOS desktop app.",
"restartFailed": "Restart request failed. Check the service and try again.",
"releaseNotes": "Release Notes",
"updateModalTitle": "New Version Available",
"guideTitle": "Update by install method",
"guideIntro": "If the one-click upgrade on the left is unavailable, pick the commands for your install method. Restart after upgrading; data stays in ~/.octop (or OCTOP_HOME).",
"guideDataNote": "Upgrades do not wipe local data: accounts, agents, chats and memory, skills, channels, and model settings live in the working directory. Reinstalling or updating the package keeps using that data.",
"guideTitle": "Update FreeOS from GitHub",
"guideIntro": "FreeOS only fetches desktop builds from github.com/XYAIStudio/FreeOS/releases. Do not install upstream Octop, and do not upgrade from Tencent COS or PyPI.",
"guideDataNote": "Upgrades do not wipe local data: accounts, agents, chats, and memory stay in ~/.freeos (or FREEOS_HOME).",
"guide": {
"ui": {
"title": "In-console upgrade",
"body": "Prefer Check for Updates and Upgrade Now on the left (package installs, not editable/source). In service mode you can Restart Service when done."
"body": "Prefer Check for Updates and Upgrade Now on the left. Desktop builds download a FreeOS portable zip; the shell applies it on the next launch."
},
"installer": {
"title": "One-line installer",
"body": "If you used the official install script, re-run the same install command to upgrade in place (it reuses the environment and data under ~/.octop)."
"github": {
"title": "GitHub Releases",
"body": "Manually download the FreeOS-desktop / FreeOS-portable asset for your architecture:"
},
"cli": {
"title": "CLI: octop update",
"body": "If the octop command is on your PATH (installer or managed venv), run:"
},
"pip": {
"title": "pip install",
"body": "If you installed into your own Python environment with pip:"
"title": "CLI: freeos update",
"body": "Check or stage a newer FreeOS desktop build from GitHub:"
},
"source": {
"title": "From source",
"body": "For git / editable installs, in-page upgrade is disabled. Pull the latest code, build the dashboard, then reinstall:"
},
"docker": {
"title": "Docker",
"body": "Rebuild and restart the image, and keep the same data volume (~/.octop or octop-data) so nothing is lost:"
"body": "Pull XYAIStudio/FreeOS and rebuild the dashboard:"
},
"restart": {
"title": "Restart after upgrade",
"body": "The new package only takes effect after the process restarts. Use the command that matches how you launched Octop:"
"body": "Quit and reopen the desktop app so the shell can extract pending-portable.zip and keep FREEOS_STAMP."
}
}
}
Expand Down
Loading
Loading