The ai-workspace role's final-deployment step downloads the console runtime
from a stable latest-runtime release (matching the bridge/qmd/litellm
convention). Have the publish job refresh a moving `latest-runtime` release
alongside the immutable `runtime-<sha>` one, carrying the same cross-compiled
assets (darwin-arm64, linux-amd64, linux-arm64) + SHA256SUMS, so consumers get
a predictable URL:
releases/download/latest-runtime/xworkspace-console-runtime-<os>-<arch>.tar.gz
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Inject pip --retries/--resume-retries into the cloned litellm install task,
tolerate empty version-probe stdout via default('{}', true), and guard the
OpenClaw download/extract patches so a second pass cannot append a duplicate
`when:` (invalid YAML). Ignore scripts/__pycache__.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the six macOS issues found and fixed during end-to-end
verification of the all-in-one install: litellm dependency version-probe
SyntaxError (TC-028), prisma generator PATH (TC-029), QMD plist undefined
nodejs_version (TC-030), QMD better-sqlite3 Node ABI mismatch (TC-031),
XFCE/XRDP apt-on-macOS (TC-032), and litellm DATABASE_URL password
percent-encoding / P1013 (TC-033), each with its playbooks commit. Update
the fix-dimension summary and the runtime delivery plan status.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`uninstall` / `uninstall --purge` previously removed services and (on
purge) `rm -rf`'d a hand-maintained list of paths with no output, so users
could not see what would be — or had been — deleted (TC-MAC-026).
Add a pre-flight `print_uninstall_summary` that lists the apps/services to
be removed (launchd agents on macOS; systemd units + docker containers on
Linux) and, when --purge is set, every target path with its current
[present]/[absent] status. Centralize the purge paths into a single
source-of-truth inventory and route deletions through a `purge_path`
helper that prints `removed:` / `absent (skipped):` per path. Document the
subcommands in the usage header. Behavior is otherwise unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the playbooks fix for the curl|bash clone path: rewrite
default('{}') | from_json to default('{}', true) | from_json so an empty
probe stdout no longer crashes the install-decision set_fact.
- OpenClaw download sub-patch re-applied on a 2nd pass produced a duplicate when: key (invalid YAML); guard against the already-patched form.
- OpenClaw extract_old drifted from upstream (missing creates:, notify now a list) so the Darwin guard silently never applied and the task tried to unarchive a tarball never downloaded on macOS; realign + idempotent guard.
- Inject pip --retries/--resume-retries + longer timeout into the LiteLLM dependency install for the curl|bash clone path.
Build the dashboard dist once (platform-independent) and cross-compile the Go
API (CGO disabled) for darwin-arm64, linux-amd64, linux-arm64 in a single
ubuntu job. Drops the macOS runners and per-arch docker. node_modules is
excluded from the runtime (nodejs role provides Node on target), so the
tarballs only carry the API binary + built dist + scripts + manifest. macOS is
arm64-only; Linux covers amd64/arm64 (Debian and Ubuntu share the binary).
Merge offline-package workflow jobs into runtime-release.yaml:
build (one linux+darwin matrix) -> publish (outputs runtime_tag) ->
build-offline-package (matrix) -> test-offline-package (matrix) ->
publish-release. One-directional deps: publish-release needs
test-offline-package needs build-offline-package. Offline build uses the
in-pipeline runtime_tag, and publish-release folds in the console-runtime
download (from aaf6c47) plus the >2GiB split-upload. The standalone
offline-package-ai-workspace-installer.yaml is now redundant (dispatch-only;
safe to delete).
A) runtime-release.yaml: add a native build-darwin job (macos-14 arm64 /
macos-13 amd64) that builds the dashboard + cross-correct Go API and
publishes xworkspace-console-runtime-darwin-{arm64,amd64}.tar.gz, fixing the
macOS deploy 404. publish now needs both build jobs and globs all runtimes.
B) offline-package workflow: GitHub caps release assets at 2 GiB. Split any
package >= 2 GiB into 1900 MiB parts plus a <name>.parts manifest and upload
the parts. The offline bootstrap (download_offline_split) falls back to the
manifest and reassembles the parts when the single asset is absent. Verified
the split/reassemble round-trips byte-for-byte.
prefetch_git_repository left the repo on a detached FETCH_HEAD. The dir is
consumed via 'git clone file://<dest>', and a detached/unreachable commit can be
pruned by git gc and is fragile to transfer, surfacing as 'unable to read tree
<sha>' during the downstream console checkout. Point a local branch
(ai-workspace-prefetched) at the fetched commit so it stays reachable and fully
clonable.
Darwin block sets litellm_config_dir=$HOME/.config/litellm; patch_playbook_
litellm_macos now also rewrites the config-dir and env-file ownership to be
OS-conditional on the cloned copy.
litellm_salt_key and litellm_database_password default to /root password-file
lookups, which are empty on macOS, so the 'Materialize persisted LiteLLM
secrets' assert fails. In the Darwin block, pass both from UNIFIED_AUTH_TOKEN
(same shared-secret approach as postgresql_admin_password). Linux unchanged.
init_vault_admin.sh entity-alias fix is confirmed working (rc=0). Restore the
bootstrap task to no_log: true and drop the temporary file-dump diagnostic.
The init_vault_admin.sh patch deleted the 'vault token revoke $bootstrap_token'
line, but on the cloned (remote) revision that line is wrapped in if/fi, so
removing it left an empty then-block -> 'syntax error near fi'. Stop deleting
it; instead set bootstrap_token="" so it stays a harmless no-op under set -u.
Verified against both standalone and if-wrapped revisions. Re-add the file-dump
bootstrap diagnostic to surface any further errors.
Add patch_playbook_postgres_macos() to rewrite the postgres macos.yml install
from the community.general.homebrew module (which can select a crashing stale
Intel Homebrew) to a brew command using the PATH brew, matching the playbooks
repo fix. Documents TC-MAC-018.
postgresql_deploy_mode defaults to compose (Docker) and the admin password is
generated via a /root password-file lookup, both of which fail on a native
macOS deploy (no Docker, /root not writable). The role already ships a native
path (macos.yml, Homebrew postgresql@16). In the script's Darwin block, set
postgresql_deploy_mode=native and pass postgresql_admin_password directly
(highest-precedence extra-var, bypassing the /root lookup). Linux unchanged.
Documents TC-MAC-017.
Root cause of the repeated 'Bootstrap Vault admin userpass auth' failure was
not macOS-specific: init_vault_admin.sh derived entity_id by logging in as the
user, but the login MFA enforcement it creates makes that login MFA-gated on
re-runs (dev Vault persists across deploys), yielding 'missing entityID'.
patch_playbook_vault_macos() now rewrites init_vault_admin.sh to resolve
entity_id via the userpass entity-alias (creating entity+alias on first run),
matching the same fix landed in the playbooks repo. Removes the temporary
no_log/file-dump diagnostic. Documents TC-MAC-016.
Disable no_log on the bootstrap and dump rc/stdout/stderr to
cloud-neutral-toolkit/vault-bootstrap-debug.log so the real init_vault_admin.sh
error can be inspected directly instead of relying on console copy/paste.
The bootstrap runs under no_log, hiding the real failure. Capture the script
result (keeping no_log so the password in the args stays censored), print only
stdout/stderr (no secrets), then assert. Lets the actual init_vault_admin.sh
error surface for diagnosis; to be removed once the root cause is fixed.
vault : Bootstrap Vault admin userpass auth runs init_vault_admin.sh, which
require_cmd's vault/jq/curl/base64. macOS has no jq by default (the apt deps
task is Darwin-skipped) and ansible.builtin.script uses a minimal PATH without
/opt/homebrew/bin. Extend patch_playbook_vault_macos() to brew install jq and
add environment PATH to the bootstrap task. Idempotent; verified. TC-MAC-015.
The common role's 'Base | *' tasks (timedatectl timezone, /etc/hostname,
hostname, /etc/hosts, ssh hardening, fail2ban, file limits, firewall) all run
with become: true against Linux-only tooling/paths and fail on macOS — the
reported timedatectl failure is just the first. Add patch_playbook_common_macos()
(post-clone, Darwin-only) that appends an ansible_os_family != 'Darwin' guard to
the whole Base block. Idempotent; verified against the real role; Linux
unchanged. Documents TC-MAC-014.
The vault role's 'Ensure standalone Vault directories exist' task creates
/etc/vault.d and /opt/vault/data with owner: root and lacks the Darwin guard
its sibling tasks have, so it fails under macOS become=false. Unlike the
bridge dir (owned by the service user, fixable via -e), this owner: root is
hardcoded and not overridable, so the role logic must change.
Since the role lives in a separate playbooks repo, reuse the existing
post-clone patch mechanism (cf. patch_playbook_user_systemd): add
patch_playbook_vault_macos() that, on Darwin only, guards the directory task,
makes vault dirs/binary OS-conditional (macOS -> ~/Library/Application
Support/vault[/data], /opt/homebrew/bin/vault; Linux unchanged), and creates
the user-owned data dir in macos.yml. Idempotent; verified against the real
role. Documents TC-MAC-013.
Switch the macOS bridge base dir to the Apple-standard per-user location
$HOME/Library/Application Support/cloud-neutral/xworkmate-bridge, while Linux
keeps /opt/cloud-neutral/xworkmate-bridge. Applied both as the Darwin -e
override in setup-ai-workspace-all-in-one.sh (the lever that reaches the
curl|bash path) and as an OS-conditional role default. Updates TC-MAC-012 and
the progress report with the not-pushed root cause of the 19:09 re-failure.