Run LocalThought integrations entirely in the browser - #1401
Merged
michielbdejong merged 4 commits intoSep 9, 2026
Conversation
This was referenced Sep 9, 2026
michielbdejong
force-pushed
the
codex/browser-integrations
branch
from
September 9, 2026 12:50
be0fde3 to
cb81923
Compare
michielbdejong
changed the base branch from
develop
to
codex/localthought-api-plugins
September 9, 2026 12:51
3 tasks
* Add browser Devonian issue tracker sync demo * Use browser tenant connections and test two-way issue sync * Record live proxy OAuth verification and repository access blocker * Run one-way Google Calendar sync entirely in the browser (#1398) * Show one-way Google Calendar imports in a calendar view * Verify browser-only Calendar sync through shared mock proxy --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io>
michielbdejong
merged commit Sep 9, 2026
d24722b
into
codex/localthought-api-plugins
0 of 2 checks passed
michielbdejong
added a commit
that referenced
this pull request
Sep 9, 2026
) * Add LocalThought catalog plugins with typed paginated imports * Record successful live GitHub import verification * Add bounded Calendar event imports through Syncables * Record successful scoped Calendar live import * Fix LocalThought lint and retain upstream preview timing checks * Fix shared Cargo cache locking across CI containers * Allow the full-app compiler test to finish on hosted CI * Queue main CI runs instead of replacing pending validation * Run LocalThought integrations entirely in the browser (#1401) * Run LocalThought integrations entirely in the browser * Run focused Pets E2E on the browser integration branch * Add browser Devonian issue tracker sync demo (#1399) * Add browser Devonian issue tracker sync demo * Use browser tenant connections and test two-way issue sync * Record live proxy OAuth verification and repository access blocker * Run one-way Google Calendar sync entirely in the browser (#1398) * Show one-way Google Calendar imports in a calendar view * Verify browser-only Calendar sync through shared mock proxy --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io>
michielbdejong
added a commit
that referenced
this pull request
Sep 11, 2026
* feat(integrations): add trivial demo Pets plugin First commit toward rebuilding the API-plugins direction from PR #1383 on feat/plugin-model. Pets is a static, provider-free demo integration (five pets, no OAuth, no secrets) that walks every touch point a real API plugin needs: a code-first ontology, an import mapping into the shared sandbox, a reproducible plugin.js bundle, an installable connection with a table and view, integration discovery in the UI, and a server-side sandbox test. See planning/api-plugins.md for the direction, including the next step: discovering providers through a localthought proxy instead of hand-writing integrations/<name>. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix: discover local Ollama and restore feedback hover (#1389) * fix: subscribe to live collaborator profile updates (#1390) * Allow recovery-code secret reveal and additional passkey enrollment * Security audit: fix sync, authentication and rights gaps, bump advisories (#1384) * docs(planning): security and code-quality audit, September 2026 Consolidated findings for server, lib, browser, desktop, CLI and CI: unauthenticated /iroh-sync, SYNC_PUSH without per-entry authorization, agent impersonation via /agents/{key} URLs on arbitrary hosts, committed API keys, forwarded-host trust, plus dependency advisories and a list of sloppy code with file:line references. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * fix(security): close the sync, authentication and rights gaps from the September audit Findings from planning/security-audit-2026-09.md fixed on this branch: - Remove the committed editor config carrying live API keys, plus the tracked pnpm-store and vitest cache files; ignore them. - /iroh-sync requires a signed agent with write on the drive (or the policy's leave to bring a new drive here) and only answers POST. Dial- side owner trust is confined to the drive that was dialed for. - SYNC_PUSH checks every entry against the admitted drive: an existing resource must carry it as its stored drive stamp, a new one must resolve to it via its parent or its own stamp. - Legacy https://host/agents/{key} subjects bind the key in the path to the signing key in both header auth and commit validation; agent subjects on other hosts are refused instead of fetched. - check_append no longer falls back to the new resource's own write array, and a parentless did:ad:agent genesis is accepted only from that key or the node's own agent. Regression tests for both. - Request origin is taken from Host/X-Forwarded-* only for the configured domain, its tenants or loopback; the WebSocket handler uses the same origin. Unit tests. - /forget-peer requires write on a drive the peer was paired for (known peers now record those) or the node's own agent. - Desktop and Android bind the embedded server to 127.0.0.1 by default. - The data-browser accepts a node-reported portalUrl only as https (or http on localhost), pins the portal a device token was issued by, and routes every portal navigation through safePortalUrl. URI values and downloadUrl reject javascript:/data:/vbscript: schemes. - BLOB_RESPONSE bytes must hash to the requested key; downloadUrl is escaped in the SPA meta tags; the plugin-ui query string is attribute- escaped; multipart uploads and search limits are bounded; LanceDB filter literals are quoted; origin() no longer panics; image rendition parameters are quantized before caching; config.toml is written 0600; plugin RPC ignores foreign message sources; the session cookie is Secure on https. - Sloppy code: ValueComp comma-case, unawaited resource.save() calls, the CLI agent race, a commented-out tool block, the duplicate EventManager, SIGNER set twice, bitwise & on bools, the empty authorization test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * fix(server): treat *.localhost names as loopback in the request-origin check CI serves the app at atomic.localhost for a server whose domain is `atomic`, so the browser signs its WebSocket AUTH and requests for that origin. The host allowlist added for the forwarded-host fix rejected it, fell back to the configured origin, and every signed request failed ("requestedSubject ... does not name this server"). Names under .localhost resolve to loopback by definition (RFC 6761), so accept them like localhost itself. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * test(browser): mock setManagedDeviceToken in the managed session test logoutManagedSession now also drops the device token, so the api mock from develop's new session test needs that export too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * fix(security): bind Iroh AUTH to the responder, close the remaining rights gaps, bump advisories Second round of fixes from planning/security-audit-2026-09.md: - Iroh AUTH: the dialer signs `drive#<responder node id>` and the accept side verifies its own node id as the connection's challenge, so a proof captured by one responder cannot open another. A proof without a node id is honoured only from a peer this node paired with. - check_append: a parentless non-agent DID is allowed only when it has no parent at all, or when its drive stamp names a drive the agent may append to; a non-DID top-level Drive needs the node's own agent. - Path-only auth signatures are no longer accepted; the signer's Agent resource is created only after the commit is accepted; genesis certs with a parent or drive must match the document; did: resources are indexed only into their own drive's watched queries; Agent and SharedConfig redact secrets in Debug. - Plugin zips and bookmark bodies are fetched through the SSRF guard with size caps; EPHEMERAL Loro payloads are relayed only from a subscriber; the ACME flow returns errors instead of panicking and a daily task renews the certificate on disk; /plugin-list and plugin UI files are read as the calling agent (the data-browser signs the list request) and the plugin parameter is validated; default_service logs at debug. - The Flutter bridge deletes the database only on a corruption error; the atomic-saas checkout no longer persists its PAT; release.yml has per-job permissions; notarization secrets go through env; the desktop devtools feature is opt-in. - Dependencies: wasmtime 47.0.4, h2 0.4.19, quinn-proto, rustls-webpki 0.103.13; @tiptap/* 3.30, @modelcontextprotocol/sdk 1.30 and the transitive build tools, after which pnpm audit reports nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * docs: changelog entry for the security audit fixes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * test(lib): upload integration tests create the agent's private drive The fixture fell back to the server's root URL as the upload parent when the config carried no initialDrive. A fresh server has no resource at that URL since the key-derived drive became the default, and the tightened check_append now refuses a child whose parent is not on the server, so the roundtrip test failed with "Parent ... not found". Materialize the private drive through Store.ensurePrivateDrive, the same path the data-browser takes at sign-in, and upload into that. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * Fix desktop workspace discovery and restore feedback * style(browser): fix the lint errors develop gained in #1389 and #1390 `pnpm lint` failed on develop's own head after those merges: missing blank lines in websockets.ts, LocalOllamaDiscovery.tsx and the two new e2e specs, and three shadowed names in username-live.spec.ts. The CI pipeline stops at the first failing package, which hid the rest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * test(data-browser): give the whole-app compiler test a 60 second budget It transforms every TSX file in the app: about two seconds on a workstation and on the self-hosted runner, nine on a two-core hosted runner, where vitest's default five-second budget failed it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * revert(lib): drop the drive-scoping of DID resources in watched queries For a `did:` query, `QueryFilter.drive` is `drive_prefix_from_subject` of the queried subject, which is that subject itself rather than the drive root. Comparing it with a resource's `drive` stamp excluded every legitimate row, and the query_aggregates tests failed on the first CI run that reached them. Back to develop's index; C17 moves to the report's not-fixed list with what a correct fix needs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * test(lib): drop the drive-scoping test that went with the reverted C17 change It asserted the watched-query index behaviour the previous commit withdrew, so it failed on the first CI run after the revert. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * fix(lib): do not steal our own OPFS lock during a slow cold start Ported from #1386. When the leader election window (2 s) elapses while this tab already holds the lock and its worker is still importing WASM and opening OPFS, the election treated the silence as a ghost leader, logged the "stealing OPFS lock" warning and re-requested the lock with steal. On a loaded CI runner every fresh page hit that path, and the browser-diagnostics gate from #1382 fails a spec on any warning, so the light e2e suite was red on develop and on this branch. Skip the steal when our own worker already exists; the settle wait below still covers the genuine ghost case. Adds #1386's unit test for the cold start. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * fix(data-browser): skip the SaaS logout call on a FOSS server Ported from #1386. Signing out posted /api/logout to whatever getManagedApiBase resolved to, and on a self-hosted node that is the node's own origin, which answers 405. The browser logs that as an error, and the diagnostics gate from #1382 fails the sign-out smoke spec on it (the only failure left on this branch's hosted run). logoutManagedSession now returns early when no control plane is known: no linked portal, no build-time API base, no remembered portal and no compiled-in portal URL. The local device token is still dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * chore(browser): dedupe prosemirror-model and prosemirror-view The @tiptap bumps in this PR pulled prosemirror-model 1.25.11 in next to the 1.25.7 that @tiptap/pm still resolved, and the two copies made `pnpm typecheck` in data-browser fail on incompatible Node types in the RTE chunks. `pnpm dedupe prosemirror-model prosemirror-view` collapses them (and, as dedupe does, other duplicates to versions the lockfile already carried: vite 8.2.2, codemirror state and lint, picomatch). Typecheck, lint, the data-browser unit tests and the vite build pass; a frozen offline install is consistent. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014tcSpZhjA3SgzcEfRdUr67 * Fix formatting and lint checks for desktop restore PR * Validate sync entries before persistence and bind discovery authentication --------- Co-authored-by: Claude <noreply@anthropic.com> * Fix per-drive hosting status, metadata and collaboration UX (#1386) * Cancel automatic Vault work when the account session ends * Improve collaboration profiles and managed subscription UX * Fix nodeless profile loading and cold database startup warnings * Settle lint and formatting after develop integration * Allow cold CI time for whole-app compiler regression check * Scope Cloud Server hosting and sync status to the selected drive * Preserve drive display metadata and scope managed billing requests * Prepare 0.41.0-beta.6 release (#1393) * Prepare 0.41.0-beta.6 versions and release gates * Record full beta.6 E2E results and release blockers * Fix release E2E regressions in sync and plugin loading * Finalize beta.6 release notes after passing E2E * test(integrations): cover Pets setup flow * fix(server): rustfmt pets_tests.rs CI's fmt check failed on the multi-line assert! in pets_tests.rs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * ci: run Pets browser journey on its branch * fix(ci): mount integration sources for browser build * fix(ci): alias /browser for integrations' tsconfig extends in jsBuild() Mounting /integrations (previous commit) fixed the UNRESOLVED_IMPORT errors, but every integrations/*/tsconfig.json extends the repo-root- relative ../../browser/tsconfig.build.json, which doesn't resolve inside the container: browser mounts at /app, not /browser. jsTest() and integrationCertificationReport() already hit this and fix it with `ln -s /app /browser`; apply the same fix to jsBuild(), which backs the production vite build, e2e and netlify-preview pipelines. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(i18n): settle translation catalogs for the Pets integration card The e2e run showed the Pets card rendering with a blank heading and description text: wuchale renders an untranslated string as empty rather than falling back to source text, and these new literal strings (IntegrationDiscovery.tsx's bundledIntegrations() entry) were never extracted into the catalogs. Settled by running the app, per AGENTS.md's translation-catalog guidance (matches the dev server's fixed point, unlike the standalone `wuchale --clean` extractor). ConnectPets.tsx's own strings (only reachable once the setup dialog is opened against a real drive) still need the same treatment in a follow-up commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(i18n): settle translation catalogs for ConnectPets.tsx Same issue as the previous commit, for the strings only reachable once the Pets setup dialog is actually opened (Install/Reinstall demo pets, the description paragraph, Open Pets). Settled by running the app against a real dev-drive session and opening the dialog, so this matches the dev server's fixed point exactly (verified: purely additive, 20 lines per locale, no reordering). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(pets): restore production labels and display pet names * fix(e2e): give the Pets install-and-apply assertion room to actually finish Root-caused the CI failure at "Apply 5 changes": not a hang, not a missing translation, and not an artifact of a locally-underbuilt server (ruled that out by rebuilding atomic-server with the real wasm32-wasip2 plugin runtime and rerunning). Installing genuinely takes ~24s — pluginClassesFor's six sequential lookups, two ensureSchema calls, three ensureInstallationResource calls, then the sandboxed plugin run itself — measured locally on a fresh, otherwise idle server via the real `playwright test`, not a synthetic script. The dialog's default 10s expect timeout is tuned for interaction latency, not this one-time setup cost. Same targeted-timeout pattern already used elsewhere in this file (vault-backup-restore.spec.ts, onboarding.spec.ts, etc.). Verified: `playwright test -g "Pets installs its demo table"` passes end to end (~47s) against a real dev-drive session with the actual embedded plugin runtime. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(ci): install wasm32-wasip2 before building the e2e server binary The Pets E2E job consistently failed at "Apply 5 changes" never enabling, even with a generous timeout. The server log in the job output shows why: `/plugin-run` 500s with "this server was built without the plugin runtime... Rebuild with the wasm32-wasip2 target installed." rustBuild()'s e2e path enables the `wasm-plugins` cargo feature, whose build.rs compiles atomic-plugin-runtime for wasm32-wasip2 as a nested cargo build. Without that target's std lib installed, the nested build fails and build.rs treats it as an optional degradation — it embeds an empty runtime instead of failing the outer build, so the gap is silent until something actually calls /plugin-run. rustTest() already adds this target for the identical reason; rustBuild() (which builds the binary the e2e Playwright suite actually talks to) never did. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(e2e): type plugin test fixtures to unblock CI * fix(ci): mount testdata/ and lib/defaults/tasks.json for lib tests jsBuild()/jsTest() only mounted testdata/pairing-request.json as a single file and never mounted lib/defaults/tasks.json outside the Vite-only /app/lib-defaults alias. Newly added browser/lib/src/plugin-manifest.test.ts, plugin-plan.fixtures.test.ts, and task-schema.test.ts read these repo-root fixtures directly via readFileSync/readdirSync (not Vite-resolved), so `vitest run` failed with ENOENT for all three in CI while passing locally against a full checkout. plugin-plan.fixtures.test.ts also readdirSync()s the whole testdata/plugin-plans/ directory, which a single-file mount can't provide, so testdata/ is now mounted whole (it isn't an OS path, so unlike /lib there's no collision risk). lib/defaults/tasks.json stays a single-file mount, matching the existing genesis_test_vectors.json precedent, to avoid touching /lib itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(ci): bump rust-target cache volume to unstick the plugin runtime The wasm32-wasip2 fix (20368ff) didn't take: the Pets E2E run on that exact commit still failed with the identical "this server was built without the plugin runtime" 500. build.rs's build_plugin_runtime() only declares `rerun-if-changed` on plugin-runtime/{src,wit} and the ATOMICSERVER_SKIP_PLUGIN_RUNTIME env var — nothing tells cargo that "the wasm32-wasip2 target just became installed" should invalidate its build-script fingerprint. Every prior CI run had already cached an empty embedded runtime (from before that target existed) in the rust-target-v3 volume, so cargo kept trusting that stale fingerprint and never re-ran the nested wasm32-wasip2 build to notice the target was now there. This is the same class of staleness bug TOUCH_WORKSPACE_SOURCES already documents fixing twice before (the -v2 and -v3 renames on this same volume, for the same "cached artifact looks newer than fresh sources" reason) — same fix, one more rename to force a clean re-evaluation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(ci): isolate the WASI plugin build from musl compiler settings * fix(data-browser): give the full-app oxc-transform sweep real headroom src/oxc-react-compiler.test.ts's "transforms every app TSX/JSX file without a fatal error" test compiles every TSX/JSX file under src/ one at a time in a single it() block, with vitest's default 5000ms budget. That budget was already tight and now consistently times out in CI (reproduced twice in a row on the same commit, ~38s total suite duration but this one test alone exceeding 5s) — this is deterministic under CI load, not a flake, and the file count only grows over time. Give it its own 20s timeout; the assertions are unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * fix(data-browser): fix oxfmt formatting from the previous timeout fix My previous commit's manual reformatting for the it() timeout argument didn't match oxfmt's expected style, which failed the format-check lint step. Move the explanatory comment onto a named constant instead of a trailing comment after the test body, which oxfmt formats cleanly and reads better besides. Verified with oxfmt --check, oxlint, and a local vitest run. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkL48idFqkuYw8n7KdH6Dj * Revert "fix(data-browser): fix oxfmt formatting from the previous timeout fix" This reverts commit 740d603. * Revert "fix(data-browser): give the full-app oxc-transform sweep real headroom" This reverts commit d59d4d2. * Add LocalThought catalog plugins with typed paginated imports * Record successful live GitHub import verification * Add bounded Calendar event imports through Syncables * Record successful scoped Calendar live import * Fix LocalThought lint and retain upstream preview timing checks * Fix shared Cargo cache locking across CI containers * Remove temporary Pets E2E workflow * Allow the full-app compiler test to finish on hosted CI * Run LocalThought integrations entirely in the browser * Run focused Pets E2E on the browser integration branch * Add browser Devonian issue tracker sync demo * Use browser tenant connections and test two-way issue sync * Show one-way Google Calendar imports in a calendar view * Verify browser-only Calendar sync through shared mock proxy * API plugins: LocalThought connections and typed Syncables imports (#1394) * Add LocalThought catalog plugins with typed paginated imports * Record successful live GitHub import verification * Add bounded Calendar event imports through Syncables * Record successful scoped Calendar live import * Fix LocalThought lint and retain upstream preview timing checks * Fix shared Cargo cache locking across CI containers * Allow the full-app compiler test to finish on hosted CI * Queue main CI runs instead of replacing pending validation * Run LocalThought integrations entirely in the browser (#1401) * Run LocalThought integrations entirely in the browser * Run focused Pets E2E on the browser integration branch * Add browser Devonian issue tracker sync demo (#1399) * Add browser Devonian issue tracker sync demo * Use browser tenant connections and test two-way issue sync * Record live proxy OAuth verification and repository access blocker * Run one-way Google Calendar sync entirely in the browser (#1398) * Show one-way Google Calendar imports in a calendar view * Verify browser-only Calendar sync through shared mock proxy --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Allow reconnecting Devonian trackers and record live write blocker * Preserve and render exclusive date-only all-day event ranges * Recognize namespaced all-day properties in installed Google calendars * Document all-day validation and remaining Google Calendar import gaps * Document successful live browser issue sync verification * Add reviewed two-way Google Calendar event edits (#1408) Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Support recurring Google Calendar meetings and exceptions (#1409) * Preserve and render exclusive date-only all-day event ranges * Import and render recurring calendar series with exceptions and timezone support --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Keep local integration resource reads off the server (#1407) * Fix local integration reads reaching the server * Fix integration formatting errors blocking CI --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Connect LocalThought platforms without pasting tenant secrets (#1417) * Connect LocalThought integrations without pasting a tenant secret * Satisfy demo callback statement-spacing lint * Apply Rust formatting required by CI * Format calendar recurrence library for workspace CI * Clarify automated coverage and live verification records * Lint the plugin feature set used by CI tests and deployment * Fix Node MCP loading and complete plugin CI feature coverage * Declare certification compiler and report failed checks * Align compiler dependency with workspace override --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Externalize platform integrations and extend metadata-driven imports (#1419) * Load Clockify and Notion integrations from Devonian * Load OAuth token endpoint from trusted metadata * Remove server tests for extracted integration bundles * Restore integration regression tests during migration * Follow OpenAPI links across sync collections * Describe only root sync parameters * Validate full Moneybird traversal fixture * Consume platform lenses from Devonian * Make integration OAuth provider-driven * Keep import budgets in consumer and preserve mixed record fields * Pin generated OAuth provider metadata * Apply catalog import selections explicitly * Handle declared absent objects and share link response context * Document generic platform traversal regression coverage * Extract GitHub and Calendar platform code * Verify explicit selection removes inherited query defaults * Validate per-item link selection and query removals * Update Calendar import coverage ownership * Load platform UI from Devonian registry * Restore neutral external action test fixture * Run external platform tests against pinned package * Neutralize embedded platform host fixtures * Document pinned external platform regression coverage * Run external platform regressions in JS CI * Render platform UI from external metadata --------- Co-authored-by: Michiel de Jong <michielbdejong@ontola.io> * Preserve bundled plugins and add configurable integration proxy settings * Fix integration test root, local reads, and reconnect isolation * Fix regression test statement spacing * Make integration certification independent of CI mount paths * Split general CI hardening out of the integration feature * Restore required shared test fixture mounts in CI --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Joep Meindertsma <joep@ontola.io> Co-authored-by: Michiel de Jong <michielbdejong@ontola.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Run the LocalThought catalog, tenant-secret handoff, OAuth return, paginated imports, review and apply entirely in the browser. A user can paste TENANT_SECRET and import into the local Store/OPFS database with no AtomicServer HTTP instance available. LocalThought remains the remote OAuth/API proxy.
The browser owns credential rotation and serializes requests with Web Locks. Syncables runs in the Atomic WASM bundle using in-memory catalog documents. Installation and schema recovery use local identity lookup, and the shipped mapper produces ordinary reviewed proposals. The native
/integration-proxy/*handlers and server Syncables dependency are removed. Existing server-held connections need reconnecting in the browser; legacy direct integrations, actions and schedules are outside this migration.Validation
Live provider OAuth on this browser path has not been verified. Deploy the proxy CORS change before live use. Connection credentials remain in browser storage outside the synced graph; the tenant secret is used in tab memory only.
Related Issues
codex/localthought-api-plugins(API plugins: LocalThought connections and typed Syncables imports #1394) and shows only the browser migration and its focused CI wiring.Checklist