Commit Graph
31 Commits
Author SHA1 Message Date
Jon Wingender ef176dbb68 Merge public/main (PR #11) into packaging branch
package / wheel (pull_request) Waiting to run
2026-08-26 13:43:23 -05:00
Jon Wingender a0f033142f fix(packaging): remove the memory-service integration this CLI reintroduced
synapse/memory/service.py was deleted on 2026-08-25 when memory curation
moved in-process (curator.py) - there is no longer a second FastAPI app
to run on :8001. This CLI was evidently built against a pre-curator
baseline: `nexus serve` spawned `synapse.memory.service:app` (fails
with ModuleNotFoundError, logged only to memory.log where nobody would
see it), `nexus start memory`/`stop memory` had no handler at all
(silently fell through to show_help()), and doctor/status/monitor all
carried a "memory service" row that could never be anything but down.

Removed rather than repaired, since there's nothing to repair: the
service, its SERVICES entry, --memory-port/--no-memory, the -m/--memory
target everywhere it was offered (start/stop/logs/LEGACY_TARGETS), and
the memory_port/memory_url settings this PR had added. The `nexus
memory list|add|rm` data commands (nexus_api.py, hitting the backend's
own /memory REST endpoint) are untouched - unrelated, and still work.
2026-08-26 13:40:50 -05:00
Jon Wingender c4d7dc42f2 Merge public/main (PR #5) into preview branch, resolve test_smoke.py append conflict 2026-08-26 13:13:49 -05:00
Jon Wingender 0d26f630e6 fix(preview): hung-frame watchdog + require approval for guessed action calls
A runaway preview script (sync infinite loop, or a re-render loop
outpacing the bootstrap's own coalescing) had nothing detecting it -
the frame just spun. The bootstrap now heartbeats every second, and the
parent tears the iframe down if it goes _WATCHDOG_MS silent, whatever
the cause.

_coerce_tool_calls recovers a tool call guessed from `content` for
models with no native tool_calls field. That guess is weaker evidence
than the API's own structured field - a model can land on JSON shaped
like a call while only meaning to describe one - so an action tool
recovered this way now always requires approval, even under the
"allow" policy that lets a native tool_calls field run unattended.
2026-08-26 13:08:58 -05:00
Athena 5f67d19e80 fix(packaging): include backend modules in distributions
package / wheel (pull_request) Waiting to run
2026-08-26 08:17:25 -05:00
Athena KaminskyandClaude Opus 5 9104c724c4 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-26 08:11:39 -05:00
Athena d579502a5b feat: add portable NexusOS CLI and packaging 2026-08-26 08:11:39 -05:00
Athena 952ef8a0c4 refactor(preview): simplify compile and validation paths
Load Sucrase only when a JSX/TSX preview is opened, remove the hand-written transform, and leave subjective render evaluation to the reader while retaining structural fence validation.
2026-08-26 03:37:29 -05:00
Athena 7262e7730e fix(preview): harden sandbox and transformation 2026-08-26 03:34:52 -05:00
AthenaandCursor 656c14caf3 feat(preview): add sandboxed live code previews
Render validated HTML, SVG, JSX, and TSX fences locally while preserving tool context and preventing explanatory JSON from triggering actions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 03:34:19 -05:00
Athena 2ebe93b4f7 fix(ollama): normalize hosts, errors, and reasoning output
Separate bind and client addresses, include Ollama's response body in HTTP failures, and strip inline <think> blocks from complete and streamed replies.
2026-08-26 03:32:45 -05:00
Athena d56d579755 fix(memory): sweep legacy orphaned message vectors
Repair vector rows left behind by older databases at store startup. Keep the existing single-statement delete path from main and avoid reintroducing the redundant batched helper.
2026-08-26 03:32:34 -05:00
Athena c3a7b6eefd fix(sync): close SQLite handles before restore
Use contextlib.closing for dump, comparison, and restore connections so Windows can unlink the live database immediately after the comparison step.
2026-08-26 03:32:15 -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
janvanwanandClaude Opus 5 8691a67803 fix(sync,memory,gpu): restorable memory dump, curator grounding, GPU + Models fixes
Ported from downstream development. Four independent defects.

1. The memory dump was unrestorable. iterdump() serializes sqlite_vec virtual
   tables as a raw INSERT INTO sqlite_master(...) followed by inserts into a
   table the replaying connection cannot see, so replaying memory.db.sql died
   on "no such table: vec_messages" and left ZERO tables behind. dump_db() now
   loads the vec0 extension and filters the derived vec tables out of the
   iterdump stream, matched on each statement's target table rather than as a
   substring - a chat message whose text mentions vec_messages is an
   INSERT INTO "messages" and has to survive.

   compare() reported an unreadable dump as "diverged", which read like a real
   verdict and made both guards refuse backup AND restore, locking the machine
   out of syncing in either direction. Unreadable is now its own verdict.

   _extra() compared updated_at against a "" default, but the column is REAL,
   so the comparison raises TypeError on the first conversation the other side
   lacks - exactly the case it counts. It tests membership first now. The
   direction test declared updated_at TEXT, which is why this survived: the
   test compared str to str while the field compared str to float.

2. The memory curator invented facts. It attributed the ASSISTANT's words to
   the user, wrote absence claims read off the existing-memory block, and added
   judgements ("favorite") the user never used. The prompt now scopes the USER
   line as the only source, and two deterministic guards drop absence claims
   and facts whose distinctive tokens appear nowhere in the user's message -
   prompt wording alone did not hold on a 7B curator.

3. _best_vulkan_device scored Mesa's llvmpipe above an integrated GPU, pinning
   Ollama to a software rasterizer advertising 31 GiB of "VRAM" - CPU inference
   with Vulkan overhead on top. Software rasterizers are dropped.

4. Models.jsx compared catalog names to installed names literally, but Ollama
   resolves a bare name to ":latest", so an untagged entry (nomic-embed-text)
   read as missing forever and the Required gate never opened. Chatbot.jsx
   fetched the model list once on mount although App keeps the page mounted
   behind display:none, so a newly pulled model never appeared in the picker
   until a full browser reload.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 17:33:43 -05:00
jonandClaude Opus 4.8 031e522704 feat(models): auto-mode intent remap + real coder models in preference
Settings "Auto model routing" picks which installed model fires for chat vs
coding intent when no model is pinned (auto_chat_model / auto_code_model).
_auto_select_model honors the remap; _MODEL_PREFERENCE["code"] prefers real
coder models first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:06:46 -05:00
jonandClaude Opus 4.8 9aea6d4228 feat(models): skip install-time pull; hardware-aware picks in Models tab
Windows installer no longer auto-downloads models; points to the Models tab.
synapse/hardware.py detects RAM + best-effort VRAM and a curated catalog;
GET /models/recommended annotates each model with fit (gpu/ram/no); the Models
page shows detected RAM/VRAM with fit badges and per-row Pull buttons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 15:46:48 -05:00
jonandClaude Opus 4.8 52b3c5c3f0 feat(tools): per-call approval for action tools
3-way action_tool_policy (off/ask/allow). In "ask", the chat stream stays
open and the tool loop awaits approval: emits event:tool_request, the UI
shows Approve/Deny, POST /chat/approve resumes the same stream. Declined
actions return a denied result; a timeout denies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:39:00 -05:00
jonandClaude Opus 4.8 492020b547 feat: per-conversation project binding + action-tool consent gate
- Conversations bind to a project on creation; RAG scopes to the
  conversation's project, not the global setting.
- Action tools (web_search/fetch_url/remember) are withheld unless
  allow_action_tools is enabled (off by default). Settings toggle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:29:40 -05:00
jonandClaude Opus 4.8 ba6a4ac4e4 feat: workspaces, agentic action tools, local Whisper STT, vec recall
- Projects/workspaces: documents grouped into projects; chat RAG scopes to the
  active project. Switcher in the Documents page.
- Agentic action tools: web_search, fetch_url, and remember (first write tool),
  allowlist-gated per playbook.
- Local Whisper STT (faster-whisper, no torch): on-device dictation replacing
  the browser Web Speech API. POST /stt + GET /stt/status; browser fallback.
- Vector index extended to conversation recall (message_vectors), with the
  brute-force cosine scan kept as the fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 14:22:46 -05:00
jonandClaude Opus 4.8 f4aea78b55 feat(rag): overlapping chunker, retrieval knobs, sqlite-vec index
- Chunker: char overlap across boundaries + hard-split of oversized paragraphs.
- Retrieval knobs: rag_top_k / rag_min_score in settings + Settings UI.
- Vector index: sqlite-vec ANN over document embeddings, dual-written and
  backfilled, with brute-force cosine as the guaranteed fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:58:05 -05:00
jonandClaude Opus 4.8 ac0eb1e5f6 feat(rag): PDF/docx ingest + chat citations
- Upload endpoint (base64 JSON, no multipart dep): extracts text from
  pdf/docx/txt/md via pypdf + python-docx, then runs the existing
  chunk/embed pipeline. Documents page uploads files straight through.
- Citations: the chat stream emits an SSE `sources` event listing the
  documents that fed the answer; the UI shows them as chips under the reply.
- Deps: pypdf, python-docx (both pure-Python, Windows-safe).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:48:32 -05:00
jonandClaude Opus 4.8 f509034fdd feat: playbook tools, RAG, vision, voice, chat controls, faster boot
- Tool-using playbooks: read-only tool registry (search_memory,
  search_history, search_documents, list_models, get_time), per-playbook
  allowlist, agentic loop, and a "running tool" status indicator.
- Document ingest / RAG: documents table + chunker + embed/cosine retrieval
  reusing the existing stack; Documents page (upload/paste, viewer, delete);
  top-k chunks injected into the system prompt.
- Vision chat: attach images, base64 into /api/chat.
- Voice I/O: Web Speech dictation + read-aloud (browser-native, no backend).
- Chat controls: stop, regenerate, edit-and-resend; num_ctx knob in Settings.
- Per-playbook model override.
- History polish: per-conversation + bulk ShareGPT export.
- Faster ncp start: UI up first, Ollama warms in the background, with a
  per-phase timing readout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 13:31:48 -05:00
jonandClaude Opus 4.8 d562b93ff4 fix(install-windows): ask before downloading models instead of offering Ctrl+C
Ctrl+C in PS 5.1 kills the whole script, so the advertised way to skip the
download was also the way to abort the install before its final steps. Now a
'Download them now? [Y/n]' prompt, so declining continues to the end. The
default-model seed moves above the pull - it only writes a settings row and was
being lost along with the download. A test forbids offering Ctrl+C again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 16:00:09 -05:00
jonandClaude Opus 4.8 786552b790 fix: delete management/ncp.ps1 - it shadowed the ncp.cmd PATH shim
PowerShell resolves ExternalScript (.ps1) ahead of Application (.cmd), and both
lived in the directory the installer puts on PATH -- so in PowerShell `ncp` ran
the .ps1 and was execution-policy-bound again, the exact thing the .cmd exists
to avoid. Its other justification (giving ncp to pwsh on Linux) stopped being
true once /usr/local/bin/ncp existed: pwsh runs a PATH symlink to a shell script
as an Application. A test now prevents the file coming back.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:59:56 -05:00
jonandClaude Opus 4.8 4961d765c8 fix(install-windows): pull models last, so Ctrl+C can't abort the install
Ctrl+C in PS 5.1 kills the whole script, and the multi-GB model pull sat in the
middle -- skipping the download also skipped the ncp PATH registration and the
desktop shortcut. Moves the pull after them. Also drops the pipe that buffered
ollama's progress bar (a running download looked like a hang) and replaces a
try/catch that native commands never trigger with $LASTEXITCODE checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 14:30:09 -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
jonandClaude Opus 4.8 9befa1d561 Sync from upstream: runtime-stage $HOME check allows the pwsh profile
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 11:42:31 -05:00
jonandClaude Opus 4.8 ca8bc7425c Sync from upstream: ncp is Python now, runs on Windows too
management/ncp.py replaces the bash CLI's logic; nexus-cli.sh and the new
ncp.ps1 are thin wrappers, so Linux keeps its entry point and Windows gains one.
psutil handles process and port work on both platforms.

install-windows.ps1 registers ncp in the PowerShell profile. The panel VPN
switch now resolves its WireGuard connection through NetworkManager instead of
a hardcoded name, and the .ps1 ASCII guard globs rather than naming files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 11:34:15 -05:00
jonandClaude Opus 4.8 ee6e5bead7 Replace stale bin/install.sh with a wrapper over sync.py restore
bin/install.sh still rsynced --delete from a backup path retired in July, so
the documented Linux install both failed and could erase a working tree. Every
step it claimed to do already lives in bin/sync.py, shared with Windows.

Root ./install.sh is now a thin wrapper over `sync.py restore`, so deployment
stays one bash command. It also registers ncp/promethean in ~/.bashrc, which
was the only thing the old script uniquely did.

Split restore-linux.sh into runtime (Ollama binary, shell aliases) and desktop
(XFCE panel, theme, os-release). Only desktop writes outside the repo, it now
auto-skips off XFCE, and `--no-desktop` skips it explicitly. Two tests keep the
stage names in sync and the $HOME writes confined to the desktop stage.

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