Commit Graph
33 Commits
Author SHA1 Message Date
dfa908c358 Adopt hatch-vcs dynamic versioning (reworks autotag, pypi-publish, desktop) (#538)
* build: adopt hatch-vcs dynamic versioning (#526)

Replace the static `version = "1.0.2"` with `dynamic = ["version"]` and
derive the version from git tags via hatch-vcs, so source and editable
checkouts report their true git describe version (e.g.
1.0.3.dev110+g<sha>) instead of a stale constant.

Config notes:
- Exclude .dev/.rc/desktop-* tags from derivation. setuptools_scm cannot
  bump custom .devN tags, so the base is taken from the latest plain
  release tag (vX.Y.Z) and the dev distance from commit count.
- Add fallback_version so builds without a git checkout (shallow CI
  clones, Docker COPY src/, source-zip installs) resolve to a sentinel
  instead of hard-failing. CI release builds inject the exact version via
  SETUPTOOLS_SCM_PRETEND_VERSION.

* ci(autotag): derive dev base from the latest release tag (#526)

pyproject no longer carries a static version, so read the base from the
latest plain release tag (vX.Y.Z) reachable from HEAD instead of grepping
pyproject. .dev/.rc/desktop-* tags are excluded so they cannot be mistaken
for the release base. The computed tag (vX.Y.Z.devN) is unchanged.

* ci(pypi-publish): pin build version from tag, drop sed injection (#526)

With dynamic versioning there is no static line to sed. Pin the exact
build version from the pushed tag via SETUPTOOLS_SCM_PRETEND_VERSION so
the published version equals the tag. This is required, not cosmetic: a
naive hatch-vcs build emits 1.0.3.devN+g<sha>, and PyPI rejects local
version segments on upload.

Also add a dry_run input that targets TestPyPI instead of PyPI, for
validating the release path without a production upload.

* ci(desktop): derive dispatch-fallback version from release tag (#526)

The workflow_dispatch fallback grepped the now-removed static pyproject
version. Derive its base from the latest release tag instead (matching
autotag), and give the build-and-release checkout full history and tags
so the derivation works.

---------

Co-authored-by: Jon Saad-Falcon <jonsaadfalcon@gmail.com>
2026-06-14 19:35:17 -07:00
8ef1ab1928 fix(ci): gate secret-bearing Claude workflows by author association (fixes #218) (#547)
The Claude automation workflows (claude-issues.yml, claude-review.yml)
trigger on public, attacker-controllable events (issues, issue_comment,
pull_request_review_comment) and grant the job secrets.ANTHROPIC_API_KEY
plus a write-scoped GITHUB_TOKEN with NO author-association gate.

Because issues / issue_comment / pull_request_review_comment always run in
the base-repo context with full secret access (unlike fork pull_request,
from which GitHub withholds secrets), any external GitHub user could fire
these jobs — draining the API budget and, via contents:write +
pull-requests:write, creating branches/PRs.

Fix:
- Add an author-association gate to every human-triggered, secret-bearing
  if: clause, restricting to OWNER / MEMBER / COLLABORATOR. Uses the correct
  event payload field per trigger: github.event.issue.author_association for
  the `issues` event, github.event.comment.author_association for
  issue_comment and pull_request_review_comment. workflow_dispatch stays
  trusted (requires repo write to invoke).
- Drop unused id-token: write from both workflows (claude-code-action@v1 is
  passed github_token directly, so OIDC is unused).
- Reduce claude-issues.yml timeout-minutes 60 -> 15.

desktop.yml and take-assign.yml are intentionally NOT touched: independently
verified as not exploitable for ANTHROPIC_API_KEY (desktop.yml's only
pull_request job uses no secrets and the trigger is plain pull_request, not
pull_request_target; take-assign.yml uses only GITHUB_TOKEN with issues:write
and no checkout/no Anthropic key). claude-review.yml's stale pull_request
auto-trigger was already removed in 3f2f46e4.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:31:51 -07:00
4523715bff fix(ci): gate live HuggingFace Hub download tests behind hub marker (#507)
The two eval-dataset suites that download real corpora from the
HuggingFace Hub at runtime were running in the default CI lane. When the
Hub was unreachable or rate-limited they failed and reddened `main` even
though no code changed — confirmed by #506 (docs-only) failing on merge
while its own PR run passed an hour earlier. They also dominated CI
wall-time (~33 min of downloads + retry backoff on the failing run).

Add a `hub` pytest marker, apply it to both suites via module-level
`pytestmark`, and exclude it from the default CI lane
(`-m "not live and not cloud and not hub"`). The tests stay runnable on
demand with `pytest -m hub`.

The ADP provider swallows per-config download errors and returns 0
records on a network failure, so a Hub outage surfaced there as
`assert 1 <= 0` (not an exception) — it could not be made non-flaky by
exception handling alone, only by gating.

Coverage holds: removing these from CI drops total from 60.92% to
~60.73% (paranoid worst case 60.18%), still above the 60% gate.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:31:50 -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
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
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
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
289fcb00e2 fix(ci): desktop — translate PEP 440 .devN to SemVer for Tauri (#360)
Tauri's build script enforces strict SemVer
(`MAJOR.MINOR.PATCH[-pre][+build]`) on `tauri.conf.json > version`, but
the autotag scheme introduced in #358 emits PEP 440 dev releases like
`1.0.2.dev661` — PEP 440 separates dev with `.`, SemVer requires `-`.
First post-#358 desktop run failed with:

    tauri.conf.json > version must be a semver string

PyPI requires PEP 440; Tauri requires SemVer. They genuinely don't
agree on `.devN`. Translate just for the Tauri bundle:

  1.0.2.dev661  -> 1.0.2-dev.661   (valid SemVer prerelease)
  1.0.2          -> 1.0.2          (passthrough)
  1.0.0-rc.1     -> 1.0.0-rc.1     (passthrough)

Tag, git history, PyPI wheel, and the updater's `latest.json` all keep
the PEP 440 form. Only the embedded bundle version uses SemVer, and
the comparison the updater does is bundle-vs-latest.json (both SemVer
now) so the upgrade path stays consistent.

Failing run for reference: 26118619500

Co-authored-by: krypticmouse <herumbshandilya123@gmail.com>
2026-05-19 12:22:24 -07:00
4668ea0b7f fix(ci): publish-to-pypi — match Vite's actual outDir (#359)
The frontend bundling step in pypi-publish.yml assumed Vite produced
`frontend/dist/`, but vite.config.ts is configured with
`outDir: '../src/openjarvis/server/static'` and `emptyOutDir: true` —
Vite writes straight to the package's static dir and clears stale
assets itself. The `rm -rf dist; cp -r dist/.` ceremony was dead code
that would have deleted the build output had the assertion not
short-circuited it first.

First post-#358 autotag run failed at this step with
`frontend/dist/index.html missing or empty after build` (build was
fine; the assertion checked the wrong path).

Fix: drop the rm/cp dance and assert the actual output location.

Co-authored-by: krypticmouse <herumbshandilya123@gmail.com>
2026-05-19 12:12:04 -07:00
Tanvir BhathalandGitHub a58d6b6c48 Auto Update (#358) 2026-05-19 11:57:10 -07:00
Robby ManihaniandGitHub 9af0dfe336 feat: Deep Research — personal deep research over Gmail with hybrid retrieval and agentic synthesis (#354) 2026-05-18 17:46:12 -07:00
Jon Saad-FalconandGitHub 9540e85dfb ci: fix env-dependent test failures (gated datasets, server extra, router prefix) (#348) 2026-05-15 21:31:13 -07:00
Avanika NarayanandGitHub e79bc1e196 Add cold-start CLI installer (#313) 2026-05-05 14:42:48 -07:00
Avanika NarayanandGitHub a3ba63d148 AI_stack_support: subprocess-based external framework harness (#311) 2026-05-05 13:37:33 -07:00
Jon Saad-FalconandClaude Opus 4.7 3f2f46e406 ci: stop auto-running Claude PR review on every pull request
Removes the pull_request trigger so the workflow only runs on explicit
@claude mentions or manual workflow_dispatch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 20:23:24 -07:00
Andrew ParkandGitHub 88a7ebcaa3 test: add live marker, CI coverage gate, rust bridge boundary tests (#256) 2026-04-17 11:02:21 -07:00
Andrew ParkandGitHub 55662fc426 refactor: merge desktop/ into frontend/, eliminate duplicate Tauri scaffolding (#246)
The project had two overlapping directories: desktop/ (Tauri Rust backend +
stale React components) and frontend/ (real React app + dead Tauri stub).
This consolidates everything under frontend/:

- Move desktop/src-tauri/ → frontend/src-tauri/ (the real 1,720-line Rust
  backend with Ollama sidecar, backend lifecycle, cloud keys, overlay, etc.)
- Preserve 9 old desktop React components in frontend/src/components/Desktop/
  (excluded from TS build — APIs have drifted, kept for future integration)
- Delete the old frontend/src-tauri/ stub (246 lines, never compiled)
- Delete desktop/ entirely
- Fix tauri.conf.json frontendDist path (../../frontend/dist → ../dist)
- Update CI workflow, bump script, .gitignore, and docs paths
- Rename setup/ → Setup/ for consistent PascalCase component directories
2026-04-14 09:48:12 -07:00
Jon Saad-FalconandClaude Opus 4.6 85089dbb30 chore(ci): bump Node-20 GHA actions to Node-24 majors
Ahead of the 2026-06-02 forced-Node-24 deadline, upgrade the remaining
javascript actions flagged in the workflow annotations:

- actions/setup-python  v5 → v6
- actions/setup-node    v4 → v6 (skipping v5)
- actions/cache         v4 → v5
- actions/deploy-pages  v4 → v5
- actions/upload-pages-artifact v3 → v5.0.0

upload-pages-artifact has no rolling @v5 major tag — only the specific
v5.0.0 release — so it gets an explicit pin, same as astral-sh/setup-uv.

Not touched: swatinem/rust-cache@v2 (still on v2 majors, not flagged),
dtolnay/rust-toolchain@stable (composite), tauri-apps/tauri-action@v0
(composite), anthropics/claude-code-action@v1 (still latest major).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 14:41:16 -07:00
Jon Saad-FalconandClaude Opus 4.6 48673ac45a fix(ci): pin setup-uv to v8.0.0 (no rolling v8 major tag exists)
astral-sh/setup-uv does not publish a rolling @v8 major tag — only the
specific v8.0.0 release. Previous commit's @v8 reference failed to
resolve and broke CI/Docs/PyPI-publish runs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 13:27:27 -07:00
Jon Saad-FalconandClaude Opus 4.6 70cbda8a73 chore: derive __version__ from metadata, bump GHA action versions
- openjarvis.__version__ now comes from importlib.metadata.version("openjarvis")
  instead of a hardcoded string, so it stays in sync with pyproject.toml on every
  release. Tests assert against openjarvis.__version__ rather than a literal.
- Bump actions/checkout@v4 → @v6 and astral-sh/setup-uv@v4 → @v8 across every
  workflow ahead of the 2026-06-02 Node.js 20 deprecation on GitHub Actions runners.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 13:19:19 -07:00
Jon Saad-FalconandClaude Opus 4.6 6fcb6c5115 fix: use TRAFFIC_TOKEN for checkout to bypass branch protection
The clone tracking workflow needs to push directly to main, but branch
protection rules block GITHUB_TOKEN pushes. Using the PAT for checkout
allows the push to succeed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:49:08 -07:00
Jon Saad-FalconandClaude Opus 4.6 65ff68d47d fix: move badges to README and fix clone tracking auth
- Move download/clone/star badges from docs/index.md to README.md
- Use TRAFFIC_TOKEN secret instead of GITHUB_TOKEN for Traffic API
  (requires admin-level access that GITHUB_TOKEN doesn't provide)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:37:30 -07:00
Jon Saad-FalconandClaude Opus 4.6 84582ff64f feat: add download/clone tracking and PyPI publishing
- Add shields.io badges to docs front page (desktop downloads, PyPI
  installs, git clones, GitHub stars)
- Add daily GitHub Action to accumulate git clone traffic data
- Add PyPI publish workflow triggered on tags and releases
- Add PyPI metadata (license, authors, classifiers, URLs) to pyproject.toml

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:14:20 -07:00
Robby ManihaniandGitHub 82ed761784 fix: pass github_token to Claude workflows to bypass OIDC (#186)
Closes #182 — the claude-code-action attempts OIDC token exchange when
no github_token is provided, which fails without the Anthropic GitHub
App installed. Passing secrets.GITHUB_TOKEN skips the OIDC flow.
2026-04-03 22:00:34 -07:00
Robby ManihaniandGitHub bcab7f926d fix: remove invalid trim() from take-assign workflow (#185)
Closes #181 — trim() is not a valid GitHub Actions expression function,
causing the job to fail on every trigger. Use the raw comment body
instead.
2026-04-03 21:59:54 -07:00
Jon Saad-FalconandClaude Opus 4.6 1ff155d445 fix(ci): skip live and cloud tests in CI
The gemma_cpp live tests require local model weights and env vars
(GEMMA_CPP_MODEL_PATH, etc.) that are not available in CI, causing
4 failures since the gemma-cpp-engine PR was merged. Add marker
filters to the pytest invocation so live and cloud tests are skipped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:31:32 -07:00
Jon Saad-FalconandClaude Opus 4.6 cbf6fe3ea2 feat: add take-bot workflow and update contribution docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 03:35:53 +00:00
Jon Saad-FalconandClaude Opus 4.6 3c2d9462ab fix: use correct claude-code-action input params and add id-token permission
- Replace invalid `model` input with default (action auto-selects)
- Replace `review_instructions`/`direct_prompt` with `prompt` (valid input)
- Add `id-token: write` permission required for OIDC token fetching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 17:36:33 -07:00
Jon Saad-Falcon 4ccec01784 ci: add Claude issue fixer workflow 2026-03-24 17:04:46 -07:00
Jon Saad-Falcon 620788bee1 ci: add Claude PR review workflow 2026-03-24 17:04:46 -07:00
Jon Saad-FalconandClaude Opus 4.6 54a99692ba fix: pin macOS desktop build to macos-14 to fix DMG bundling
macos-latest now resolves to macOS 15 (Sequoia), which removed the
SetFile command from Xcode Command Line Tools. Tauri's bundle_dmg.sh
relies on SetFile to set custom icon attributes on the DMG volume,
causing the Desktop Build & Release workflow to fail on the macOS
runner.

Pin to macos-14 (Apple Silicon M1, Sonoma) which still includes
SetFile and supports universal binary builds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:19:40 -07:00
Jon Saad-FalconandGitHub bca60b5706 fix: clean stale desktop release artifacts and fix frontend port mismatch (#52)
Three issues fixed:

1. The desktop-latest release accumulated stale artifacts across builds
   because tauri-action adds new files without removing old ones. Users
   could download an outdated DMG. Added a clean-release job that wipes
   all existing assets before the build matrix runs.

2. The frontend hardcoded DESKTOP_API to port 8000 but the Tauri backend
   starts the server on port 8222. Added a get_api_base Tauri command so
   the frontend fetches the port from the Rust backend at startup,
   keeping JARVIS_PORT as the single source of truth.

3. frontend/package.json version was 1.0.0 while desktop and pyproject
   are 0.1.0, causing duplicate artifact names in the release.
2026-03-13 19:11:39 -07:00
Jon Saad-Falconandkrypticmouse 8798e2ee4f init commit 2026-03-12 17:29:39 +00:00