Commit Graph
10 Commits
Author SHA1 Message Date
Athena 26b471d259 Merge origin/main (v1.2.0: Projects, modules, in-app updates)
Reconciles 17 commits of this session's work (self-alteration tools,
vendored Curry, slash-command dispatch, Windows toolchain/gate fixes)
against origin/main's v1.2.0 sync (Projects/RAG scoping, a new modules/
system for mail and network, in-app updates, the standalone memory
microservice folded into an in-process curator, KDE desktop theme
overhaul). Nine real conflicts, each resolved by hand after reading both
sides' actual diffs rather than picking one side wholesale:

- synapse/tools.py, tests/test_tools.py: origin/main's diff here was
  small and clean (read_file/list_files, two new tests) despite git's
  diff3 flagging the whole file as one conflict blob -- reset to this
  branch's version and hand-spliced their addition in at the same
  points they used, rather than trying to reconcile a false 800-line
  conflict. Found and fixed a real bug while verifying: _list_files
  returned backslash-separated paths on Windows, which don't match the
  forward-slash glob patterns the tool's own schema documents.
- synapse/main.py: kept this branch's cue-based standing advertisement
  of render_preview/run_snippet (independent of any playbook granting
  them) AND adopted origin/main's fix for routed reference playbooks
  not bringing their own tools along -- dropping either would have been
  a real regression, not just a style difference. Also: the standalone
  memory service (port 8001) is gone upstream, so its dead CORS/kill-
  target entries were removed; NEXUS_BACKEND_PORT parameterization and
  the manage_ollama-conditional kill logic (this branch's remote-Ollama
  support) were kept over origin/main's hardcoded equivalents.
- synapse/memory/store.py: kept this branch's _delete_message_vectors
  helper (already reused elsewhere, batches to stay under SQLite's
  variable limit) over origin/main's inline duplicate of the same fix.
- synapse/nexus_config.py, nexusos_cli/ncp.py: dropped the now-dead
  memory-service port/service entries; kept NEXUS_BACKEND_PORT env
  override and the manage_ollama-conditional kill-target list.
- CLAUDE.md, README.md: merged both sides' additions, no real conflict.

Found and fixed three more issues while independently verifying the
merged tree, none of them mine or origin/main's alone -- only visible
once both sides actually ran together:

- modules/ (the new mail+network package) was never added to
  pyproject.toml's wheel `packages` list OR the sdist's `include`
  allowlist, so `from modules.registry import ROUTERS` in main.py would
  ImportError on any wheel install. Fixed both; bin/check.sh's
  packaging gate now asserts modules/ actually ships. tests/
  test_packaging_deps.py's FIRST_PARTY/SHIPPED_PACKAGES sets were
  updated to recognize the new package.
- tests/test_mail_creds.py's 0600-mode assertions are POSIX-only --
  NTFS has no equivalent permission bits, so os.open(path, 0o600) on
  Windows just creates a normal file and stat.S_IMODE reports 0o666
  regardless. Made the assertions platform-aware rather than skip real
  coverage (the temp-file-cleanup and password round-trip checks in the
  same test still run on Windows) or paper over a genuine OS
  limitation with a fake pass.
- tests/test_kde_theme.py used bare Path.read_text() in fifteen places;
  Windows' default locale encoding (cp1252, not UTF-8) can't decode a
  real UTF-8 byte in the QML it reads, and did fail on one of the
  fifteen. Fixed all fifteen, not just the one that happened to trip
  today, since the other fourteen were equally fragile.

Verified: full bin/check.sh reports OK end-to-end on this Windows
checkout -- pytest (tests + management): 295 passed, 0 failed, 9
skipped; eslint clean; frontend node:test 57/57; PowerShell/shell
parse clean; wheel + sdist pass twine check and now correctly carry
modules/ (60 files, up from 52 pre-merge). synapse.main:app builds
with 74 routes (up from 54 pre-merge, matching the new Projects/mail/
network endpoints).
2026-08-26 02:09:23 -05:00
AthenaandClaude Sonnet 5 cac6e636fc docs: update CLAUDE.md for curry tool wiring + slash commands
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 22:11:37 -05:00
AthenaandClaude Sonnet 5 cb3d3f0a1f feat: vendor Curry, preloaded and callable across the one universal wheel
Vendors curry_core.py from Athena-Pro/Curry (with the str.format()/format_map()
sandbox-escape fix from https://github.com/Athena-Pro/Curry/pull/4 already
applied) into synapse/, since Curry itself isn't a pip-installable package -
it's meant to be pointed at via a config path, which only works from a source
checkout. Vendoring a single self-contained, stdlib-only file ships it inside
NexusOS's own wheel with no extra dependency to reconcile.

synapse/curry_store.py opens it into a module-level singleton (curry_db) at
import time, the same pattern as memory.store.store and
playbooks.store.playbook_store, and main.py imports it so it's genuinely
initialized at process startup - preloaded, not lazy-on-first-use. Backed by
its own CURRY_DB file (nexus_config.py), separate from memory.db.

NexusOS builds exactly one wheel (py3-none-any, no compiled extensions) -
there is no separate Windows/macOS/Linux artifact; platform differences are
handled by requirement overlays at install time, not by building different
wheels. Verified the same wheel actually carries this correctly: built it,
confirmed twine check passes, confirmed synapse/curry_core.py and
curry_store.py are present in the archive (bin/check.sh's packaging gate now
asserts this too), then installed that exact wheel into a throwaway venv and
round-tripped a declare_constant/get_constant_latest call against it with no
source checkout present - proving "preloaded and ready to be called" holds
from the shipped artifact, not just editable-install execution.

Android/Termux is unaffected by this change in either direction: it already
has a separate, documented, pre-existing blocker in docs/TERMUX.md (no
published Android pydantic-core wheel) that has nothing to do with Curry,
which is pure stdlib and adds no new native/binary dependency.

Scope: preload only, nothing wired into a chat-facing tool yet - no model or
user-authored content reaches declare_function/call_function today.

Verified: 216 backend tests pass (4 new in test_curry_store.py, including a
regression test proving the vendored sandbox fix survived the copy); the 12
pre-existing C/C++/Rust toolchain failures are unrelated and unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 21:40:41 -05:00
janvanwan 42eaed647a feat: sync with upstream — v1.2.0, in-app updates, Projects, modules
Brings the public tree back in line with the development repo after several
weeks of drift caused by a stale publish include list.

New:
- In-app update path: GET /update/check compares the checkout against
  origin/main and POST /update/apply runs `ncp upgrade` detached (pull,
  rebuild, restart). The sidebar shows the version, checks on click, and
  offers an "update available" pill.
- Projects: a project workspace groups chats and RAG documents, with
  per-project instructions and document retrieval scoped to the active
  project. Replaces the standalone Documents page.
- modules/: auto-discovered feature plugins (mail, network) with their
  frontend counterparts and tests.
- Memory curation runs in-process (synapse/memory/curator.py) on the chat
  model when a conversation goes idle. The separate memory service on :8001
  is gone, along with the launcher lines that started it.

Also: the KDE theme, panel and Promethean terminal assets, the full test
suite, and VERSION 1.2.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-25 09:13:55 -05:00
Athena Kaminsky 27f222dbcd feat(cli): add interactive TUI chat
Add a Textual chat interface with threaded SSE streaming, slash commands, interrupt handling, and bare nexus dispatch. Package it behind the tui extra, document usage, and cover command routing, dependencies, and headless interaction with tests.
2026-08-21 15:39:28 -05:00
Athena KaminskyandClaude Opus 5 6e8067fe7d feat(macos): native install path via Homebrew
install-macos.sh mirrors install.sh's split: every portable step - git pull,
venv, pip with the right overlay, npm build - stays in bin/sync.py, shared
with Linux and Windows. The script only does what sync.py cannot do for
itself on a bare Mac, which is install the Homebrew packages needed before a
Python exists to run sync.py with.

Two stages had to learn about darwin. ensure_exec_bits() keyed off
`os.name == "nt"`, which is false on macOS, so it ran the Linux path; and
requirements() had no darwin branch. linux_stage() now no-ops there, which is
what makes skipping the Ollama fetch correct rather than an omission:
bin/fetch-ollama.sh only ships a Linux x86-64 binary, and _ollama_bin() in
synapse/ollama_manager.py already prefers the bundled copy and falls back to
whatever `ollama` is on PATH. On macOS that is the brewed one, with Metal
acceleration and no flags needed.

The XFCE desktop branding is Linux-only and was already gated off macOS the
same way, so there is nothing to install for it here.

install-macos.sh joins the shell-parse list in bin/check.sh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:32:53 -05:00
Athena KaminskyandClaude Opus 5 affba1805c feat(chat): add run_snippet, an execution track beside the render track
render_preview validates markup and hands it to the browser, which renders it
in an opaque-origin sandboxed iframe. Nothing executes server-side. That model
fits HTML/SVG/JSX and cannot fit C, Rust or Erlang, which need a real
toolchain - so those get a second tool instead of a widened first one.

The split is the feature: the model picks a track by picking a tool, rather
than picking a `lang` value from an enum where half the entries run
server-side and half do not.

synapse/code_run.py compiles and runs one file in a throwaway directory and
returns a ```nexus-run fence carrying the source and its captured output
together, so a model cannot paste output without the code that produced it.
Backticks in the source are re-encoded as ` - still valid JSON, and it
cannot close the fence early.

It is not a sandbox, and the module docstring says so up front. What it gives
is containment by layers: consent (an action tool, gated by
action_tool_policy, per-call Approve/Deny on "ask"), static screening, a
scrubbed environment in a temp dir, wall-clock and POSIX rlimits, and a
network namespace on Linux where unprivileged userns are available. Screening
is a tripwire against a model reaching for `requests` out of habit, not a
boundary against an adversary; layers 1 and 3-5 are the load-bearing ones.

Backend RUN_LANGS and frontend run-langs.js are separate registries because
the two sides need different things - one executes, one labels - and neither
should depend on the other at runtime. tests/test_tools.py asserts the key
sets and the fence tag stay equal, so drift fails the gate instead of
rendering a run result under the wrong language.

tests/snippet_probes/ is a data catalog rather than inlined cases, so adding a
language is a data change and the meta-tests can assert every RUN_LANGS key
has both a smoke probe and a screening probe. Probes skip cleanly on hosts
without the toolchain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:30:03 -05:00
Athena KaminskyandClaude Opus 5 425184a30b feat(packaging): move the CLI into nexusos_cli and make the wheel self-sufficient
The CLI shipped from `management/`, which also holds desktop-only pieces (the
Tk control panel, the XFCE panel wiring, the shell wrappers). Packaging that
directory meant the wheel either dragged in tkinter or shipped a broken import.
Split it: `nexusos_cli/` is what the wheel ships and what `nexus`/`ncp`/
`nexusos` dispatch to, `management/` keeps the desktop half.

Alongside the move:

* hatch_build.py decides the interface/web/dist include at build time. dist/
  is gitignored, so a static force-include aborts `pip install -e .` on a
  fresh clone - before the reader reaches the `npm run build` step. Editable
  installs now skip a missing dist; wheels and sdists hard-error naming the
  command to run.
* synapse/proc_util.py gives frontend_manager and ncp process inspection and
  termination without psutil, which became an optional extra when the wheel
  landed. It routes around Windows having no signals, where os.kill(pid, 15)
  is an unblockable TerminateProcess rather than a polite request.
* nexusos_cli/monitor.py adds `ncp monitor`, an ASCII dashboard with no curses
  or rich dependency so it works in Termux, plain SSH and Windows Terminal.
  Collector and renderer are separate so tests feed fixtures, no stack needed.
* tests/test_packaging_deps.py fails the gate when synapse or nexusos_cli
  import a distribution pyproject does not declare, and when an optional
  dependency is imported at module scope instead of lazily.
* bin/check.sh now builds the wheel, twine-checks it, and asserts the compiled
  UI and seed playbooks are actually inside it. A wheel that builds but ships
  no dist/ serves a blank page, which only shows up after release.

tests/test_nexus_api.py moves to tests/ with the module it covers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 14:29:17 -05:00
jonandClaude Opus 4.8 6137710c25 feat: put ncp on PATH on both platforms; rename WSL reqs to Windows
Ports the ncp PATH work from upstream. Registering ncp as a shell-profile
function failed three ways on Windows: the default Restricted execution policy
blocks the profile itself, profiles don't exist outside PowerShell (cmd, Win+R,
Task Scheduler), and the self-elevating installer writes the admin's profile.

Windows now ships management/ncp.cmd and the installer appends management\ to
the Machine PATH via [Environment]::SetEnvironmentVariable -- never setx, which
truncates PATH at 1024 chars. A .cmd is exempt from the execution policy.

Linux symlinks /usr/local/bin/ncp -> management/nexus-cli.sh, falling back to
the old .bashrc function when sudo is unavailable.

Also renames requirements-wsl.txt to requirements-windows.txt and purges stale
WSL references, including vite.config.js's dev-server comment and
controlpanel.py's "Check WSLg." error string.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:11:18 -05:00
Jon Wingender 714b9fc890 Initial commit: NexusOS - local AI assistant platform 2026-07-21 22:48:38 -05:00