Skip to content

Prepare FreeOS 0.1.0 runtime and distribution fixes - #107

Draft
XYAIStudio wants to merge 39 commits into
developfrom
codex/freeos-0.1.0-upstream-foundation
Draft

XYAIStudio wants to merge 39 commits into
developfrom
codex/freeos-0.1.0-upstream-foundation

Conversation

@XYAIStudio

@XYAIStudio XYAIStudio commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Prepare FreeOS 0.1.0 with safer SQLite restart, user-controlled Ollama discovery, malformed-config preservation and cleanup of stale system messages before model calls. Align Python/runtime version metadata and route FreeOS distribution through GitHub Releases without publishing the Octop-compatible package name to PyPI.

Validation so far: backend 3,611 passed / 117 skipped; frontend 1,075 passed; Ruff, mypy, frontend lint/typecheck/format checks and production build passed. The 0.1.0 wheel and sdist have been built and the embedded dashboard/version metadata verified.

This is the development integration PR. Packaged runtime, native desktop and security acceptance are in progress; do not publish a stable release until those checks are complete. v0.0.10 remains available until the replacement release and its assets are verified.

Prepare FreeOS 0.1.0 with safer SQLite restart, user-controlled Ollama discovery, malformed-config preservation and cleanup of stale system messages before model calls. Align Python/runtime version metadata and route FreeOS distribution through GitHub Releases without publishing the Octop-compatible package name to PyPI.

Validation so far: backend 3,611 passed / 117 skipped; frontend 1,075 passed.

Follow-up on this branch (still draft, not merged, not tagged): one-time v0.0.x residue cleanup, demo seed excluded from the release tree, paid-plugin install confirmation, pre-upgrade backup behaviour, release builds ignore inherited demo-seed flags, loopback bind by default, UI tenant no longer prefers demo tenants, and the security contact line is a placeholder. Head df18457ccf1f970e5ca1889da44b921ab5228086. CI https://github.com/XYAIStudio/FreeOS/actions/runs/40849963899 and desktop https://github.com/XYAIStudio/FreeOS/actions/runs/40849963814 are green.

Open in Web Open in Cursor 

Theater-ahyeon and others added 30 commits October 3, 2026 23:22
* fix(update): checkpoint SQLite WAL before desktop process restart

In desktop/portable mode, POST /api/update/restart replaced the process
image with os.execv without flushing the SQLite WAL. Because SqlitePool
uses WAL mode with a large autocheckpoint window, all writes since the
last checkpoint were lost on restart (#800).

Change _restart_desktop_process to accept the OctopServer, and before
execv run PRAGMA wal_checkpoint(TRUNCATE) and close the pool when the
database is SQLite. The restart endpoint now injects the server via
Depends(get_server).

Fixes #800.

* style(tests): format desktop restart regression cases
… (#738)

* fix(config): never rewrite an unparseable config.json as empty (#730)

Four call sites read config.json, treated a parse failure as an empty dict and
wrote that back, destroying every other key. One trailing comma plus one
`octop run --port 8088` wiped 17 of 18 keys including the whole `database`
section; the next boot silently came up as a greenfield SQLite instance (fresh
setup-wizard password, zero warnings) while the PostgreSQL data sat unreachable.
Losing `bind_host` the same way is what makes #730's reporter unable to reach
the server from the LAN.

A torn write creates the same precondition with no user error: three of the four
sites wrote config.json with a bare write_text, so a crash / OOM / full disk
mid-write left invalid JSON that the next plugin toggle then wiped.

One shared policy in a new leaf helper, infra/utils/json_file.py:

  absent file            -> {} and write (first run, unchanged)
  valid JSON object      -> merge and write (unchanged)
  unparseable/non-object -> raise CONFIG_FILE_CORRUPT, write nothing

The error names the file and the parser line/column but never the contents,
which hold database credentials. Writes now go through write_json_atomic (temp +
os.replace, fd closed on every path, temp removed on failure) so no reader can
observe a torn file.

Sites: cli/commands/run.py (_save_configfile_overrides, plus
_load_configfile_overrides which used to fall back to launch defaults),
infra/agents/plugins/manager.py (_write_global_plugin_enabled = the dashboard
toggle), infra/setup/service.py (persist_bind_options),
infra/agents/plugins/seed.py. `octop run` / `octop service start` report the
error and exit 1 via fail_octop (now NoReturn) instead of a traceback.

Supersedes the pinned "treat a malformed file as empty so the next run rewrites
it cleanly" contract: its fixture (`{not valid json`) had nothing to lose, so
the test could not observe the destruction. Rewritten as
test_run_reports_corrupt_config_cleanly and
test_run_does_not_overwrite_corrupt_config.

Verified end-to-end against a real OctopServer + real PostgreSQL. Before: one
`octop run --port` flipped driver postgresql -> sqlite, the instance reverted to
the first-run wizard, and users=1/agents=1 were orphaned in PG with no warning.
After: exit 1, config.json byte-identical, boot fails loudly instead of
switching backends. Mutation check: restoring the lenient policy in the helper
reddens 9 tests spanning all four sites.

make all green (3299 passed, 16 skipped); mypy --strict clean; dashboard
`npx tsc --noEmit` clean.

* fix(config): name the file when config.json is corrupt (#730)

`load_config` let a bare `json.JSONDecodeError` escape: it reports a line and
column but never says *which* file failed, and this entry point is reached from
boot, backup and several CLI commands — not only `octop run`. Raise a ValueError
naming the path and the parser position, refuse a non-object document, and never
echo file contents (config.json holds database credentials).

Same policy as infra/utils/json_file.py, duplicated here because octop.config
must stay free of infra imports (AGENTS.md §5).

`octop run` already exits cleanly on a corrupt config through resolve_bind; this
covers the remaining entry points.

make all green (3301 passed, 16 skipped); mypy --strict clean.

* fix(config): preserve config.json permissions in atomic writes

Self-review against CONTRIBUTING.md / AGENTS.md §7 caught a regression in the
atomic writer added earlier in this branch: tempfile.mkstemp creates the temp
file 0600, so replacing config.json silently tightened an existing 0644 file to
0600. Under `octop service start --scope system` that runs as root and writes
into the service user's home, a root-owned 0600 config.json is unreadable by the
service user and the unit cannot start; the bare write_text it replaced produced
the umask default.

write_json_atomic now chmods the temp file to the mode of the file being
replaced, or to `0o666 & ~umask` for a new file — matching the two pre-existing
config.json writers (infra/db/rebind.py, infra/backup/auto.py; both
write_text + replace) rather than mkstemp's 0600. POSIX-guarded, so Windows
behaviour is unchanged and no test asserts mode bits off POSIX (AGENTS.md §7).

Also adds the missing CHANGELOG line for the load_config error-message change.

Verified: new file -> 0644, existing 0644 -> 0644, existing 0600 -> 0600.
make all green (3303 passed, 16 skipped); make typecheck-frontend green;
eslint 0 errors (67 pre-existing react-hooks warnings).

Note: `make check-all` is red on develop itself — prettier --check fails on
dashboard/src/pages/Agent/Skills/components/SkillsTabs.tsx exactly as committed
by 83378876. Left untouched here; confirmed pre-existing by checking develop's
version of that file in isolation.
Refresh the openXYOS lock so npm ci resolves on Node 24 and require Node >=22.12.
Wait for the SearchConfig source label before asserting it; that was the Node 24
dashboard failure while the spinner was still mounted.

Bind the organization sidecar to 127.0.0.1 from the server default and every
desktop launcher. Seed local accounts only under FREEOS_ORG_LOCAL_TEST, with a
random password stored beside the database and a forced change on first sign-in.
The UI no longer shows a shared demo password.

Mark rc/a/b/dev tags as GitHub prereleases in the release, desktop attach, and
FNOS attach workflows. Collapse the changelog to a single 0.1.0 section and
stop README_CN from directing installs at PyPI octop. Order desktop version
compare so a final release sorts above its rc.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Name new FnOS artifacts FreeOS-fnos-*.fpk in the workflow, build script,
release links, and user docs. Older Release assets may still be named
Octop-fnos-*.

Remove the expired WeCom QR from the user guide and README_CN. Readers
go to GitHub Discussions or the existing Discord link.

Bump vite to 6.4.5, vitest to 4.1.12, and follow-redirects to 1.16.1 so
Desktop Package npm audit exits 0.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Set the distribution name to freeos so the wheel and sdist are freeos-0.1.0*.
The import package and the octop CLI alias stay. FnOS, portable packaging,
and release notes use the new filenames and say not to pip install octop.

User-facing paths in the docs this change touches name ~/.octop as the data
directory. FREEOS_HOME applies only when it is already set; this release
does not migrate that directory to ~/.freeos.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
README and the user guide no longer recommend the Tencent COS
octop/install URLs. Those scripts install PyPI octop. Desktop packages
on GitHub Releases are the primary install path; CLI installs use this
repo's develop scripts.

New installs use ~/.freeos. install.sh, install.ps1, and install.bat
follow PathLayout: FREEOS_HOME, OCTOP_HOME, an existing ~/.freeos, an
existing ~/.octop when ~/.freeos is absent, otherwise ~/.freeos. The
desktop app still does not adopt a leftover ~/.octop.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Point the package version at 0.1.0rc1 so tag v0.1.0rc1 matches
pyproject and stays a GitHub prerelease. Attach SHA256SUMS for desktop
installers, portable zips, wheels, and sdists. Align the employee
password hint and backup home help with the code.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
npm audit fix updates DOMPurify, fast-uri, and serialize-javascript in
the dashboard lock, and those plus body-parser, ip-address, multer, and
undici in the organization module. All stay on the current major.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Hash FreeOS-fnos-*.fpk with the other release artifacts, and refresh
SHA256SUMS after the FnOS workflow attaches those packages.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
NSIS VIProductVersion and go-winres file_version reject 0.1.0rc1.
Keep the display string, and write 0.1.0.0 for the numeric fields.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Windows pathlib orders paths case-insensitively, so freeos-* sorted
ahead of FreeOS-*. Compare the filename string instead.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Operators still saw [octop] and "Installing Octop" while installing FreeOS.
Log prefixes, success lines, and install prompts now say FreeOS. Paths, the
octop CLI, and notes about upstream PyPI Octop stay unchanged.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Default agent root_dir followed Path.home(), so setup/finish seeded
main at ~/.octop/workspaces and overwrote an existing profile when
--home pointed elsewhere. Workspaces, the wizard password file, and
llama.cpp logs now stay under the product home. A pre-existing
directory outside that home is refused, and default-agent seed will
not replace files that are already there.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
The built-in runtime warning stays red only when no provider answers a
connectivity check. Ollama or another reachable base URL turns it into
a grey note, and an Ollama model can still be selected for chat.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Install snippets no longer fetch the develop script. Node is described
as absent from the default single-process install, and Docker is no
longer called the production recommendation. Data-directory examples
use ~/.freeos / FREEOS_HOME.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
FREEOS_ORG_LOCAL_TEST is set only when FREEOS_ORG_DEV_BOOTSTRAP or
FREEOS_ORG_LOCAL_TEST is already explicitly on. Release launches leave
it unset. FREEOS_ORG_INTEGRATED stays, because real installs use it for
distinct organization tenants and host identity, not for demo accounts.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
ensureLocalBootstrap runs only when FREEOS_ORG_DEV_BOOTSTRAP or
FREEOS_ORG_LOCAL_TEST is explicit, and only when the database has no
users and no one-time marker. It no longer reactivates tenants, recreates
deleted accounts, or rotates passwords. Release starts do not create
demo@demo.com or user@demo.com.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Startup no longer writes the internal deployment-rules reflections into
tenant 1. Deleting those rows stays deleted across later starts.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Startup no longer inserts AI合同智能解析 for every tenant. Uninstalling
it stays uninstalled. The catalog entry for an explicit install remains.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
New archives store workspace_dir relative to the product home. Restore
remaps old absolute paths onto the home given to --home and refuses a
target outside that directory, so a live workspace is not overwritten.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
install.sh, install.ps1, and the desktop in-app upgrade now run
octop backup create --include-chats before replacing the runtime.
The archive sha256 is recorded beside it, and a failed backup aborts
the upgrade.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
…installed contract plugin once

After the pre-upgrade backup, one marker-gated pass replaces seeded demo and bootstrap-admin passwords, disables accounts that own no data, deletes exact P16 reflections, and disables the v0.0.x contract plugin row without removing it.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Demo inserts live in backend/dev, which the sidecar bundle excludes. The release seed entry refuses to load them unless FREEOS_DEV_BUILD is set, and a scan of the shipped tree rejects the demo account strings.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
…mation

Uninstall now sets the plugin status to disabled so the contract parser gate turns off, and a paid install stays disabled until the client confirms the exact price. Both actions write an audit row. The catalog row is kept.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
CI run 40838520982 failed npm audit, not the compile. qs 6.16.0 is inside GHSA-6pq8-jhm2-2vcw, and vite-plugin-pwa pulls deepmerge >=4.2.0 (GHSA-gcqx-w48m-w2h4) which has no patched 4.2 release. Overrides move both trees onto versions outside those ranges.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
…e without one

install.sh can run the real pre-upgrade backup against a fake existing home and abort when that backup fails. The Windows NSIS overwrite path now runs the same full backup before copying files and aborts Setup when it fails. makensis itself is not executed here.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
A release process with inherited local-test flags creates no demo accounts on an empty database, and three later starts leave an existing password hash and tenant status alone.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
cursoragent and others added 9 commits October 29, 2026 08:16
FREEOS_ORG_LOCAL_TEST and FREEOS_ORG_DEV_BOOTSTRAP are dropped unless FREEOS_DEV_BUILD is explicitly set. Parent environments can no longer turn demo seeding on for a release sidecar.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Inherited HOST is ignored. LAN or NAS exposure requires FREEOS_ORG_BIND_HOST or OCTOP_BIND_HOST. Compose keeps a container-internal 0.0.0.0 only where the published port defaults to 127.0.0.1; host-network mobile stays on loopback.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
resolveUiTenantId follows the logged-in non-seed user. A later demo login and the openxyos-local slug no longer win over that user's own tenant.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
The catalog list no longer returns a price, and the plugin center shows an amount only after the install API asks for confirmation. A migrated contract plugin stays out of the active list; uninstall goes through the HTTP route and leaves the row disabled.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
…ceholder

The vulnerability contact line is now 「漏洞接收邮箱:待董事长指定」 and does not name an inbox.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Ruff format --check failed CI on these two files.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
create() now resolves the workspace through agent_workspace before ensure_agent_workspace. The unit fake only stubbed the old method, so CI make test failed with AttributeError.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
Portable upgrade tests embed a fake python. After the full backup became mandatory, those tests executed it and failed with exec format error. The default stub writes an archive; the backup-specific tests still replace it.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>
install.sh exits immediately when uname is not Linux or Darwin. The Windows CI runner was executing that path through Git bash and failing before the backup hook.

Co-authored-by: haoboy007-sudo <haoboy007-sudo@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants