Skip to content
Draft
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
28 changes: 17 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,18 @@ 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 }}
48 changes: 46 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,7 @@ 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' }}
43 changes: 19 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,29 @@ 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' }}

# workflow_run / release:published are unreliable when Release itself was
# started via GITHUB_TOKEN workflow_dispatch (Auto Tag). Explicitly cascade.
Expand All @@ -165,7 +160,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 +170,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 }}"
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.0] - TBD

FreeOS **0.1.0** is an independent semver baseline. It does not track or align with Octop 1.0.x. GitHub Release Python artifacts are `freeos-0.1.0*` (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.0

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
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ REPO_ROOT := $(shell pwd)
DASHBOARD_DIR := $(REPO_ROOT)/dashboard
DASHBOARD_DEST := $(REPO_ROOT)/src/octop/dashboard
DIST_DIR := $(REPO_ROOT)/dist
FRONTEND_NODE_OPTIONS ?= --max-old-space-size=4096

# PyPI repository (override: make publish PYPI_REPO=testpypi)
PYPI_REPO ?= pypi
Expand All @@ -29,7 +30,7 @@ RUN := $(if $(UV),uv run,)
PYTHON := $(if $(UV),uv run python,python3)
PIP := $(if $(UV),uv pip,python3 -m pip)
# Parallel workers for make test / make test-fast (override: make test PYTEST_JOBS=4)
PYTEST_JOBS ?= auto
PYTEST_JOBS ?= 4

# ─── Help ────────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -98,7 +99,7 @@ build-frontend:
@echo "[build-frontend] Installing npm dependencies..."
cd $(DASHBOARD_DIR) && npm ci
@echo "[build-frontend] Building dashboard (output: $(DASHBOARD_DEST))..."
cd $(DASHBOARD_DIR) && NODE_ENV=production NODE_OPTIONS="--max-old-space-size=2048" npm run build
cd $(DASHBOARD_DIR) && NODE_ENV=production NODE_OPTIONS="$(FRONTEND_NODE_OPTIONS)" npm run build
@echo "[build-frontend] Done."

.PHONY: build-wheel
Expand Down
Loading
Loading