mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-08 00:54:38 +02:00
5da649986016e4010da8156f83f5bfc9c0128be4
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e0b64529b3 |
feat(auth): normalize agent login in the sandbox onto one session table and a capability contract (#11730)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Sandbox agents need a safe login path for each supported adapter > - Codex device login and Claude setup-token login used separate session stores and route logic > - Separate stores made session lookup, expiry, and login capability checks harder to keep consistent > - This pull request unifies both flows on one session table and one capability contract > - The benefit is one company-scoped login model with public session identifiers and shared lifecycle rules ## Linked Issues or Issue Description **Subsystem affected** Cross-cutting (multiple of the above) **Problem or motivation** Codex and Claude sandbox login used separate session stores and different route paths. This split increased the risk of inconsistent company scoping, session lookup, and cleanup. **Proposed solution** Use `adapter_auth_sessions` for both login flows. Use public session identifiers for API access. Select login behavior from projected adapter capability data. Share the route spine, lease arguments, runner lifecycle, and reaper rules. **Alternatives considered** Keep two session tables and add matching fixes to both routes. This keeps duplicate logic and does not provide one capability contract, so this pull request uses shared infrastructure. **Roadmap alignment** This change supports the shipped Cloud / Sandbox agents milestone in `ROADMAP.md`. ## What Changed - Unify Codex device login and Claude setup-token login on `adapter_auth_sessions`. - Return and look up sessions with company-scoped public session identifiers. - Enforce one active session for each company, owner, and adapter. - Share the login route spine, sandbox lease arguments, runner lifecycle, and missing-auth check. - Add a standalone setup-token reaper with adapter-specific row selection. - Add optional login capability projection for adapters and drive route and UI selection from that data. - Rename the provider flag to `supportsLoginPty` and validate its deprecated alias. - Remove the old Claude setup-token session table and add the required migrations. ## Verification - Server typecheck passed with `tsc`. - Database typecheck passed. - UI typecheck passed with `tsc -b`. - Codex login service and route suites passed. - Setup-token session, route, and reaper suites passed. - Adapter session schema, plugin validator, capability projection, UI render, and Daytona suites passed. - GitHub Actions must confirm the complete CI gate after pull request creation. ## Risks - The migrations remove short-lived in-flight login rows during deployment. A login that spans the migration can continue until its provider lease expires. - The Codex credential store remains company-scoped. A cross-owner credential race remains a documented, board-accepted risk. - API clients that use internal session row identifiers no longer work. The API accepts only public session identifiers. ## Model Used Codex, GPT-5, exact runtime model ID not exposed in this handoff, large context window, reasoning, and repository tool use. The implementing engineer produced the code with AI assistance. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs: #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
0a1f9fda65 |
fix(adapters): wrap modulePath in pathToFileURL() before dynamic import (Windows) (#4287)
## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - One of its pluggability surfaces is external adapter packages,
loaded at startup by `server/src/adapters/plugin-loader.ts` and routed
through the adapter registry so third parties can override built-in
adapters like `claude_local`
> - `loadExternalAdapterPackage` calls `await import(modulePath)` where
`modulePath` is an absolute filesystem path
> - On Windows that path begins with a drive letter (`C:\…`), which
Node's ESM loader parses as a URL scheme and rejects with
`ERR_UNSUPPORTED_ESM_URL_SCHEME`; the defensive `try/catch` around the
call masks the failure and the builtin adapter silently keeps serving
traffic, so the override never activates
> - `reloadExternalAdapter` in the same file already tries to build a
`file://` URL, but does it via template-string concatenation
(`file://${modulePath}`) which produces a malformed URL on Windows
(`file://C:\…` instead of `file:///C:/…`) — so dev hot-reload of
adapters is broken on Windows even after initial load works on POSIX
> - This pull request swaps both paths to `pathToFileURL()` from
`node:url`, the idiomatic cross-platform conversion
> - The benefit is external adapter packages load reliably on Windows
with no changes required to existing adapters, and the two sibling paths
in the same file stop diverging in their URL-handling discipline
Closes #4286.
## What Changed
- `server/src/adapters/plugin-loader.ts`:
- Import `pathToFileURL` from `node:url`.
- `loadExternalAdapterPackage`: wrap `modulePath` in
`pathToFileURL(modulePath).href` before passing to `import()`.
- `reloadExternalAdapter`: replace `` `file://${modulePath}` `` string
concatenation with `pathToFileURL(modulePath).href` so the cache-bust
URL is well-formed on Windows too (drive letter, UNC, percent-encoding).
Three lines changed + one import. No behavior change on POSIX:
`pathToFileURL("/foo/bar.js").href === "file:///foo/bar.js"`, which
Node's ESM loader accepts identically to the bare path.
## Verification
**Runtime, Windows 11, Node v24, `@paperclipai/server@2026.416.0`:**
Before (installed dist, vanilla):
```
INFO: Loading external adapter package {packageName: "@reforged/adapter-claude-local", modulePath: "C:\\Users\\…\\index.js"}
WARN: Failed to dynamically load external adapter; skipping
err: ERR_UNSUPPORTED_ESM_URL_SCHEME … Received protocol 'c:'
```
After (same dist with the equivalent two-line patch applied):
```
INFO: Loading external adapter package {packageName: "@reforged/adapter-claude-local"}
INFO: Loaded external adapters from plugin store {count: 1, adapters: ["claude_local"]}
```
End-to-end: the override actually services execute calls and its
telemetry fields (e.g. `errorCode: "rate_limited"` on 429) surface into
heartbeat-run records — I've been running this heartbeat through the
override on a vendor-patched copy while drafting this PR.
**Static / logic review:**
- `pathToFileURL` is part of Node's stdlib since v10.12.0, no new dep.
- On POSIX, `path.resolve("/a", "b") → "/a/b"` and
`pathToFileURL("/a/b").href → "file:///a/b"`. `await
import("file:///a/b")` and `await import("/a/b")` both resolve to the
same ESM module — no double-load risk.
- Reload path: the existing cache-bust query (`?t=${Date.now()}`) still
appends cleanly because `pathToFileURL(...).href` returns a normalized
`file:///…` URL with no pre-existing query string.
**Local test suite:** I did not run the full `pnpm test` suite in this
fork — the monorepo test infrastructure (embedded Postgres, pnpm
workspace install) is a significant local-setup cost and this change is
surgical enough that CI should be the source of truth. Happy to iterate
based on CI signal. No existing test directly exercises
`plugin-loader.ts`'s initial-load path.
## Risks
**Low.** This aligns the initial-load path with the already-existing
intent of the reload path (which tried, but imperfectly, to use a
`file://` URL). POSIX behavior is unchanged. The only runtime difference
is that Windows stops throwing and starts loading the adapter — which is
exactly the bug being fixed.
Edge cases worth naming:
- **UNC paths** (`\\server\share\…`): previously broken the same way on
the load path, still broken with `file://` string concat on the reload
path. `pathToFileURL` handles UNC correctly (→
`file:////server/share/…`), so this change also quietly fixes UNC-path
adapter installs on Windows.
- **Bun**: the reload path has a Bun cache-eviction block that keys off
`modulePath` and the old `fileUrl`. Bun accepts both `file://` URLs and
bare paths in its module cache keys, so changing the URL form is
consistent with the existing evict-both pattern (we still evict both
`fileUrl` and `modulePath` after the change).
## Model Used
Claude Opus 4.7 (`claude-opus-4-7`, provider: Anthropic) via Claude
Code, running as the CTO agent in a Paperclip-orchestrated company. 200k
context, tool use. No extended thinking mode. Model authored the patch,
the issue body, and this PR description; human review by the company's
principal (fronc) is pending.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [ ] I have run tests locally and they pass — *deferred to CI, see
Verification note*
- [ ] I have added or updated tests where applicable — *no existing
tests for this file; adding one would require stubbing
`adapter-plugin-store` + filesystem, which seemed out of scope for a
3-line fix. Happy to add one on request.*
- [x] If this change affects the UI, I have included before/after
screenshots — *not UI, N/A*
- [x] I have updated relevant documentation to reflect my changes — *no
user-facing docs affected; behavior unchanged on POSIX and now-working
on Windows*
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
|
||
|
|
47f3cdc1bb |
fix(ui): external adapter selection, config field placement, and transcript parser freshness
- Fix external adapters (hermes, droid) not auto-selected when navigating with ?adapterType= param — was using a stale module-level Set built before async adapter registration - Move SchemaConfigFields to render after thinking effort (same visual area as Claude's chrome toggle) instead of bottom of config section - Extract SelectField into its own component to fix React hooks order violation when schema fields change between renders - Add onAdapterChange() subscription in registry.ts so registerUIAdapter() notifies components when dynamic parsers load, fixing stale parser for old runs - Add parserTick to both RunTranscriptView and useLiveRunTranscripts to force recomputation on parser change |
||
|
|
14d59da316 |
feat(adapters): external adapter plugin system with dynamic UI parser
- Plugin loader: install/reload/remove/reinstall external adapters from npm packages or local directories - Plugin store persisted at ~/.paperclip/adapter-plugins.json - Self-healing UI parser resolution with version caching - UI: Adapter Manager page, dynamic loader, display registry with humanized names for unknown adapter types - Dev watch: exclude adapter-plugins dir from tsx watcher to prevent mid-request server restarts during reinstall - All consumer fallbacks use getAdapterLabel() for consistent display - AdapterTypeDropdown uses controlled open state for proper close behavior - Remove hermes-local from built-in UI (externalized to plugin) - Add docs for external adapters and UI parser contract |