Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0a47108
fix(update): checkpoint SQLite WAL before desktop process restart (#918)
Theater-ahyeon Sep 23, 2026
0b2ac8b
fix(ollama): discover user-started local daemon
Oct 3, 2026
fff8411
fix(config): never rewrite an unparseable config.json as empty (#730)…
huangcheng Sep 17, 2026
6acc177
chore(release): prepare FreeOS 0.1.0
XYAIStudio Oct 7, 2026
61ee8c2
fix(release): enforce native checks and repair organization dependenc…
XYAIStudio Oct 10, 2026
75e9e51
fix(release): close 0.1.0 CI and sidecar security blockers
cursoragent Oct 21, 2026
17bc806
fix(release): brand new FnOS packages and clear npm audit
cursoragent Oct 21, 2026
65c5b56
fix(release): publish GitHub wheels as freeos-0.1.0
cursoragent Oct 21, 2026
b2f6964
fix(install): stop pointing users at the upstream Octop script
cursoragent Oct 21, 2026
26a153a
chore(release): cut 0.1.0rc1 and publish SHA256SUMS
cursoragent Oct 26, 2026
7d4f7e8
fix(deps): patch npm audit findings without major bumps
cursoragent Oct 26, 2026
b8bcd2a
fix(release): include FnOS packages in SHA256SUMS
cursoragent Oct 26, 2026
4399748
fix(desktop): map prerelease versions onto numeric Windows resources
cursoragent Oct 26, 2026
5ca8e23
fix(release): sort SHA256SUMS by filename on every platform
cursoragent Oct 26, 2026
b6f4b9c
fix(install): label user-visible install logs as FreeOS
cursoragent Oct 27, 2026
0e5c67f
fix(home): keep FreeOS writes inside FREEOS_HOME
cursoragent Oct 29, 2026
3fe1cd2
fix(models): note missing llama.cpp when another provider is up
cursoragent Oct 29, 2026
71f5c8a
docs: point one-click install at this branch
cursoragent Oct 29, 2026
9884fea
fix(org): stop forcing demo bootstrap on sidecar launch
cursoragent Oct 29, 2026
a6c4cc8
fix(org): seed demo accounts at most once, and never on release
cursoragent Oct 29, 2026
95ce119
fix(org): stop reinserting P16 deployment reflections
cursoragent Oct 29, 2026
7b270b5
fix(org): do not auto-install the paid contract plugin
cursoragent Oct 29, 2026
d581aa7
fix(backup): restore workspaces under --home
cursoragent Oct 29, 2026
b2769ed
fix(upgrade): full backup with sha256 before replacing an install
cursoragent Oct 29, 2026
94c1bfd
F10 upgrade cleanup: invalidate seeded accounts and disable the auto-…
cursoragent Oct 29, 2026
a70183f
F10 release bundle: keep demo seed out of the shipped organization tree
cursoragent Oct 29, 2026
2073c3c
F6 plugin install: disable on uninstall and require paid-price confir…
cursoragent Oct 29, 2026
3c1a070
F7 audit: pin qs 6.16.2 and deepmerge 4.1.2
cursoragent Oct 29, 2026
25468e4
F9 backup: exercise install.sh upgrade backup and block NSIS overwrit…
cursoragent Oct 29, 2026
af078e9
F2 bootstrap tests: empty database and upgrade residue stay unchanged
cursoragent Oct 29, 2026
c28cabe
F1 launch flags: ignore inherited demo-seed switches in release builds
cursoragent Oct 29, 2026
afde946
H bind loopback: default organization and Docker listeners to 127.0.0.1
cursoragent Oct 29, 2026
8227926
I ui tenant: never prefer demo or seed tenants
cursoragent Oct 29, 2026
d4701a5
J plugin price: hide paid plugins after cleanup until price is confirmed
cursoragent Oct 29, 2026
4aed65c
K security contact: replace the personal mailbox with the pending pla…
cursoragent Oct 29, 2026
54231f2
F9 lint: format the new backup and bind-loopback tests
cursoragent Oct 29, 2026
1c5597c
fix test: custom agent create fake exposes agent_workspace
cursoragent Oct 29, 2026
dc04535
F9 tests: stub the desktop pre-upgrade backup by default
cursoragent Oct 29, 2026
df18457
F9 tests: run install.sh backup behaviour only on POSIX
cursoragent Oct 29, 2026
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
36 changes: 25 additions & 11 deletions .github/workflows/fnos-build-fpk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ permissions:
packages: read

concurrency:
group: build-octop-fnos
group: build-freeos-fnos
cancel-in-progress: false

jobs:
Expand Down Expand Up @@ -99,14 +99,14 @@ jobs:

- name: Build Docker FPK
env:
FPK_NAME_PREFIX: Octop-fnos
FPK_NAME_PREFIX: FreeOS-fnos
run: bash scripts/build-fpk.sh docker

- name: Upload docker fpk artifact
uses: actions/upload-artifact@v4
with:
name: docker-fpk
path: dist/Octop-fnos-docker-*.fpk
path: dist/FreeOS-fnos-docker-*.fpk
if-no-files-found: error

native:
Expand All @@ -131,8 +131,8 @@ jobs:
set -euo pipefail
mkdir -p dist
REL_TAG="v${VER}"
if gh release download "$REL_TAG" --repo "${{ github.repository }}" -p 'octop-*.whl' -D dist 2>/tmp/wheel-dl.err; then
ls -lh dist/octop-*.whl
if gh release download "$REL_TAG" --repo "${{ github.repository }}" -p 'freeos-*.whl' -D dist 2>/tmp/wheel-dl.err; then
ls -lh dist/freeos-*.whl
echo "source=release" >> "$GITHUB_OUTPUT"
echo "Reusing wheel from GitHub Release ${REL_TAG}"
else
Expand Down Expand Up @@ -169,7 +169,7 @@ jobs:
python3 -m pip install --quiet build
python3 -m build --wheel
echo "=== built wheel ==="
ls -lh dist/octop-*.whl
ls -lh dist/freeos-*.whl

- name: Install Octop core into app/site-packages (no Chromium, no preinstalled skills)
id: install_core
Expand All @@ -185,7 +185,7 @@ jobs:
{
python3 -m pip install --quiet uv
python3 -m uv pip install --python python3.12 \
--target "$SP" --no-cache "$(ls dist/octop-*.whl | head -1)"
--target "$SP" --no-cache "$(ls dist/freeos-*.whl | head -1)"
rm -rf "$SP/mcp" "$SP"/mcp-*.dist-info \
"$SP/langchain_mcp_adapters" "$SP"/langchain_mcp_adapters-*.dist-info
mkdir -p /tmp/octop-pinned
Expand All @@ -195,26 +195,26 @@ jobs:
echo "Extracting pinned wheel: $whl"
python3.12 -m zipfile -e "$whl" "$SP"
done
cp dist/octop-*.whl "$SP/octop.whl"
cp dist/freeos-*.whl "$SP/freeos.whl"
PYTHONPATH="$SP" python3.12 \
-c "import octop, mcp, langchain_mcp_adapters; from octop.launch import run_foreground_blocking; print('octop', octop.__version__, '| mcp', mcp.__version__, '| lcma', langchain_mcp_adapters.__version__)"
} 2>&1 | tee -a "$LOG"

- name: Build native FPK
id: build_native
env:
FPK_NAME_PREFIX: Octop-fnos
FPK_NAME_PREFIX: FreeOS-fnos
run: bash scripts/build-fpk.sh native

- name: Show native fpk size
run: ls -lh dist/Octop-fnos-native-*.fpk
run: ls -lh dist/FreeOS-fnos-native-*.fpk

- name: Upload native fpk artifact
id: upload_native
uses: actions/upload-artifact@v4
with:
name: native-fpk
path: dist/Octop-fnos-native-*.fpk
path: dist/FreeOS-fnos-native-*.fpk
if-no-files-found: error

- name: Upload native install log (for debugging)
Expand Down Expand Up @@ -273,12 +273,26 @@ jobs:
exit 1
fi

- name: Classify pre-release
id: channel
run: python3 scripts/release_prerelease.py "${{ needs.version.outputs.tag }}" >> "$GITHUB_OUTPUT"

- name: Attach fpk to GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.version.outputs.tag }}
files: dist/*.fpk
fail_on_unmatched_files: true
generate_release_notes: false
prerelease: ${{ steps.channel.outputs.prerelease }}
make_latest: ${{ steps.channel.outputs.prerelease == 'true' && 'false' || 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Refresh SHA256SUMS after FreeOS-fnos-*.fpk lands. Release and Desktop
# Package publish the same file earlier; this pass adds the FnOS packages
# and keeps installers, zips, wheels, and sdists already on the release.
- name: Publish SHA256SUMS
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/publish_sha256sums.sh "${{ needs.version.outputs.tag }}" dist
56 changes: 54 additions & 2 deletions .github/workflows/octop-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,44 @@ jobs:
- name: Build frontend → src/octop/dashboard
run: make build-frontend

- name: Check dashboard dependencies
working-directory: dashboard
run: npm audit --registry=https://registry.npmjs.org

- name: Test dashboard
working-directory: dashboard
env:
NODE_OPTIONS: "--no-experimental-webstorage"
run: npm run lint && npm test

- uses: actions/upload-artifact@v7
with:
name: dashboard-dist
path: src/octop/dashboard/
if-no-files-found: error
retention-days: 7

organization-quality:
name: Verify organization module
if: github.event_name != 'workflow_dispatch' || github.event.inputs.attach_from_run == ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: "24"
cache: npm
cache-dependency-path: modules/openxyos/package-lock.json
- name: Install organization dependencies
working-directory: modules/openxyos
run: npm ci
- name: Check organization module
working-directory: modules/openxyos
run: npm run ci
- name: Check organization dependencies
working-directory: modules/openxyos
run: npm audit --registry=https://registry.npmjs.org

# Job-level `if` cannot read `matrix.*` (GitHub 422). Filter here so only
# selected runners start — PRs → darwin-* + windows-*; dispatch honors `platforms`.
select-platforms:
Expand Down Expand Up @@ -134,7 +165,7 @@ jobs:

package:
name: "${{ matrix.plat }}"
needs: [frontend, select-platforms]
needs: [frontend, select-platforms, organization-quality]
runs-on: ${{ matrix.os }}
# Matrix runners are native for each plat; pin host detection so x64 Git Bash
# on windows-11-arm does not mis-classify the job as windows-amd64 cross-build.
Expand Down Expand Up @@ -177,7 +208,7 @@ jobs:

- uses: actions/setup-node@v5
with:
node-version: "20"
node-version: "24"
cache: npm
cache-dependency-path: modules/openxyos/package-lock.json

Expand Down Expand Up @@ -260,6 +291,10 @@ jobs:
- name: Install Wails v3 CLI
run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.13

- name: Test native desktop lifecycle and updater
working-directory: desktop/src
run: go test ./...

- name: Install NSIS
if: runner.os == 'Windows'
shell: pwsh
Expand Down Expand Up @@ -325,6 +360,8 @@ jobs:
contents: write
actions: read
steps:
- uses: actions/checkout@v4

- name: Resolve release tag
id: rel
run: |
Expand All @@ -339,6 +376,10 @@ jobs:
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"

- name: Classify pre-release
id: channel
run: python3 scripts/release_prerelease.py "${{ steps.rel.outputs.tag }}" >> "$GITHUB_OUTPUT"

# v8 required for archive:false artifacts. skip-decompress keeps the
# uploaded .zip / .tar.gz / .dmg / .exe intact — default unzip turns portable
# zips into directories, so files: release-assets/* would skip them.
Expand Down Expand Up @@ -369,4 +410,15 @@ jobs:
files: release-assets/*
fail_on_unmatched_files: true
# Upsert: works whether Release workflow already created the release.
# Keep rc/a/b/dev tags as prereleases so attaching assets cannot mark them latest.
generate_release_notes: false
prerelease: ${{ steps.channel.outputs.prerelease }}
make_latest: ${{ steps.channel.outputs.prerelease == 'true' && 'false' || 'true' }}

# Refresh SHA256SUMS after desktop installers and portable zips land.
# Release publishes the same file for wheel/sdist; this pass adds the
# packages just uploaded and any freeos-* assets already on the release.
- name: Publish SHA256SUMS
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/publish_sha256sums.sh "${{ steps.rel.outputs.tag }}" release-assets
53 changes: 29 additions & 24 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Release

# 版本标签 v* → 测包、发 PyPI、建 GitHub Release,再级联:
# 版本标签 v* → 测包、构建 GitHub Release 制品,再级联:
# - Sync Main Into Develop
# - Build Octop FPK(复用本 Release 的 wheel;等待 docker-publish 的 GHCR 镜像)
#
Expand All @@ -18,7 +18,6 @@ on:
permissions:
contents: write
actions: write
id-token: write

concurrency:
group: release-${{ github.ref }}
Expand All @@ -43,6 +42,11 @@ jobs:
echo "Refusing release: tag $GITHUB_REF_NAME does not match pyproject.toml $package_version" >&2
exit 1
fi
git fetch origin main
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
echo "Refusing release: production tags must point to a commit on main" >&2
exit 1
fi

- uses: astral-sh/setup-uv@v4
with:
Expand All @@ -54,7 +58,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
cache: npm
cache-dependency-path: dashboard/package-lock.json

Expand All @@ -73,26 +77,9 @@ jobs:
name: dist
path: dist/

publish:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
environment: pypi
steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish package
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}

github-release:
name: Create GitHub Release
needs: publish
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -128,21 +115,39 @@ jobs:
echo ""
echo "## Install"
echo ""
echo "**Do not** \`pip install octop\`. PyPI \`octop\` is upstream Octop, not this FreeOS release."
echo "Install the wheel attached to this GitHub Release:"
echo '```bash'
echo "pip install octop==$version"
echo "uv pip install ./freeos-$version-py3-none-any.whl"
echo '```'
} > .release-notes.md
fi
if ! grep -q '^## Downloads' .release-notes.md; then
python3 scripts/release_download_links.py "$version" >> .release-notes.md
fi

- name: Classify pre-release
id: channel
run: python3 scripts/release_prerelease.py "${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"

- name: Create release
uses: softprops/action-gh-release@v2
with:
body_path: .release-notes.md
files: dist/*
generate_release_notes: true
prerelease: ${{ steps.channel.outputs.prerelease }}
make_latest: ${{ steps.channel.outputs.prerelease == 'true' && 'false' || 'true' }}

# Hash wheel/sdist plus any desktop installers and portable zips already
# attached by Desktop Package. That workflow runs the same script again
# after its own upload, so the last publisher leaves one SHA256SUMS that
# covers every class. v0.1.0rc1 is a prerelease via release_prerelease.py
# (PEP 440 rcN). v0.1.0-rc.1 is not.
- name: Publish SHA256SUMS
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/publish_sha256sums.sh "${GITHUB_REF_NAME}" dist

# workflow_run / release:published are unreliable when Release itself was
# started via GITHUB_TOKEN workflow_dispatch (Auto Tag). Explicitly cascade.
Expand All @@ -165,7 +170,7 @@ jobs:
-f version="${{ github.ref_name }}"

# FnOS FPK:复用本 Release 的 wheel + docker-publish 的 GHCR 镜像。
# 与 sync-develop 并行。Dispatch 失败必须让本 workflow 变红(PyPI 已发布仍如此)。
# 与 sync-develop 并行。Dispatch 失败必须让本 workflow 变红,以便发现下游构建漏触发。
trigger-fnos:
name: Trigger FnOS FPK build
needs: github-release
Expand All @@ -175,7 +180,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# --ref 用版本 tag,保证 FPK 打在与 PyPI / 镜像相同的 commit 上
# --ref 用版本 tag,保证 FPK 打在与 GitHub Release / 镜像相同的 commit 上
gh workflow run fnos-build-fpk.yml \
--repo "${{ github.repository }}" \
--ref "${{ github.ref_name }}"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
build/
!desktop/src/build/
!desktop/src/build/**
desktop/src/build/windows/nsis/product_version.nsh
dist/

# OS
Expand Down
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,32 @@

格式遵循 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),版本号遵循 [语义化版本规范](https://semver.org/spec/v2.0.0.html)。

## [Unreleased]
## [0.1.0rc1] - TBD

FreeOS **0.1.0rc1** is a prerelease of an independent semver baseline. It does not track or align with Octop 1.0.x. The release tag is `v0.1.0rc1`. GitHub Release Python artifacts are `freeos-0.1.0rc1*` (sdist and wheel). The import package stays `octop`. This release does not publish to PyPI, and `pip install octop` installs upstream Octop, not FreeOS. Older Release files may still be named `octop-0.0.10*`.

### Upgrade from 0.0.10

- In-app update and a manual reinstall keep the data directory the process already uses. New installs use `~/.freeos` (`FREEOS_HOME`, then `OCTOP_HOME`, then an existing `~/.freeos`; the desktop app does not adopt a leftover `~/.octop`). CLI installs keep an existing `~/.octop` when `~/.freeos` is not there yet. Sessions, local models, knowledge bases, organization data, and `config.json` stay in that directory. This release does not copy one tree into the other.
- Desktop portable upgrades copy a SQLite backup under the data directory's `backups/` before replacing the runtime, and checkpoint the WAL before the process restarts.
- A `config.json` that cannot be parsed is left in place and reported. It is not rewritten as an empty file.
- Roll back by installing the **v0.0.10** desktop package again, or restore a backup with `octop backup restore`. Do not point install scripts at PyPI `octop`; that package is upstream Octop, not this release. Use [GitHub Releases](https://github.com/XYAIStudio/FreeOS/releases) or `scripts/install.sh` (add `--from-pypi` only when you explicitly want upstream Octop).

### Changed

- Publish Python distributions as GitHub Release assets only. The release workflow no longer publishes to PyPI, and install scripts default to the FreeOS GitHub source.
- The bundled openXYOS sidecar listens on `127.0.0.1` by default. Local bootstrap accounts are created only when `FREEOS_ORG_LOCAL_TEST=1`, with a random password in `{data}/bootstrap-credentials.txt` that must be changed on first sign-in. The UI no longer embeds a shared demo password.

### Fixed

- Remove checkpoint-resident system messages before model calls while preserving the active compiled prompt, preventing strict Qwen chat templates from failing when an older conversation contains a stale bootstrap message.
- Detect models from an already-running Ollama daemon even when FreeOS-managed Ollama startup is disabled; model discovery never starts Ollama unless the user enabled it.
- Preserve `config.json` when it is malformed: startup and configuration writers now report the file and parser position, avoid leaking stored credentials, and use atomic replacement instead of silently rebuilding an empty configuration. Absorbed from upstream Octop #730 / #738.
- Checkpoint the SQLite WAL before the desktop process restarts so an in-app update does not drop the latest writes. Absorbed from upstream Octop #918.

### Not in 0.1.0rc1

Harness migration, cloud bridge default-on, default LDAP/SSO, Teams, and a whole-repo catch-up to Octop are out of scope.

## [0.0.10] - 2026-10-03

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ See [AGENTS.md](AGENTS.md) for module boundaries and coding conventions.

1. Cut `release/x.y.z` from latest `develop` (version bump + CHANGELOG on that branch)
2. Open PR: `release/x.y.z` → `main` and merge when green
3. Tag `v<version>` on **main tip** and push — GitHub Actions builds, publishes to PyPI, and creates the GitHub Release
3. Tag `v<version>` on **main tip** and push — GitHub Actions builds Python distributions and creates a GitHub Release with the artifacts; FreeOS does not publish the `octop` distribution to PyPI
4. Delete `release/x.y.z`; Actions syncs `main` → `develop` (or opens `chore/sync-develop-after-*` if merge conflicts / branch protection)

Agent-assisted publish: `.cursor/skills/publish` (`/publish <version>`).
Expand Down
Loading
Loading