Repository navigation
Conversation
…tes, plugin-scoped gate matcher, 3-OS CI - crustdata-login: detect WSL and hand the sign-in URL to Windows via powershell.exe Start-Process (printed-URL fallback unchanged). - credential-store: retry the atomic rename briefly on EPERM/EACCES/EBUSY — Windows AV scans and the session-start read can hold the destination open, and a failed swap must not drop a fresh login. - hooks.json: the PreToolUse gate matched ^mcp__crustdata__ only, but tools from a plugin-bundled MCP server are scoped mcp__plugin_<plugin>_<server>__*, so the gate never fired. Match both forms. - README: document the supported platforms and their credential-store semantics. - CI: run the suite on ubuntu/macos/windows x Node 20/24 so the platform claims are enforced, not asserted.
…odies + remaining URLs The candidate-sourcing and email-enrichment skills were written against the previous server's per-endpoint tools; replace both with their Code Mode rewrites (same workflows, driven through execute/callTool) in the skills/ layout. Point every remaining connector instruction (README, authoring guide) at install.crustdata.com/mcp — .mcp.json already was — and fix the README's relative skill links, stale since the skills moved under skills/. Follow-up after merge: re-cut the Releases .skill bundles from these bodies.
23716d9 to
7812764
Compare
First real windows-latest run: statSync reports 0o666 for a writable file regardless of the mode passed (Node only maps the read-only attribute), so the exact-0o644 pin is POSIX-only. Keep it there; on win32 assert the actual C6 invariant — no exec bit leaks through (0o666 has none).
…er successful sign-in) Both windows-latest Node 24 CI runs aborted identically: the sign-in fully succeeds (code exchange + store write + confirmation printed), then process.exit() races the loopback server's still-closing handles and libuv asserts (src/win/async.c, STATUS_STACK_BUFFER_OVERRUN). Two changes: wait for server.close() to complete (bounded at 1s so a lingering connection can't stall the result), and let the event loop drain naturally with process.exitCode — keeping an unref'd 3s process.exit backstop in case some handle unexpectedly holds the loop open.
main already serves 0.1.0, and Claude Code detects plugin updates by version — without the bump, existing installs would never pull the migrated skills and cross-platform fixes in this branch.
…sync personal-email path Mirrors the same fix at the source of truth (skills-internal, same branch day): the GitHub-fallback snippet passed a LinkedIn URL as profile_url, which the API rejects with a 400 — steer to crustdata_person_id — and the personal-email note predated batch_person_identify, the async v2 path that does resolve personal emails (1 credit per matched identifier).
Mirrors the source-of-truth commit: six-phase renumber (async batch_person_identify becomes a real Phase 2 Branch B, the empty email-substring phase is dropped), standalone Candidate verification section, and no version-comparative phrasing anywhere in bodies, READMEs, or evals.
Keeps this branch's skills/ byte-identical with the source of truth (skills-internal) so the publish sync after its merge cannot conflict here.
… OAuth The plugin shipped a second OAuth client: /crustdata:login, a 450-line browser/PKCE/DCR flow, a ~/.crustdata credential store with a cross-process refresh lock, an MCP headersHelper, a SessionStart token refresh, and a PreToolUse gate. Claude Code already does all of this for an http MCP server, so the layer was duplicated work with its own failure modes. install.crustdata.com serves everything the native flow needs — verified live: an unauthenticated POST /mcp answers 401 with a www-authenticate challenge carrying resource_metadata=.../.well-known/oauth-protected-resource/mcp, which resolves to an authorization server advertising PKCE S256, a registration endpoint (DCR) and refresh grants. Dropping headersHelper is the change that hands the connection back to the client: while one is configured the plugin supplies the Authorization header itself, and a client-managed token has nothing to attach to. Signing in is now: Claude prompts on first use, or /mcp -> crustdata -> Authenticate. Nothing to paste, no command to remember. The PreToolUse gate had to be deleted rather than left inert. It exits 2 when the store holds no token, and the store is now permanently empty, so it would have blocked every Crustdata tool call on an otherwise working connection. Skill sync keeps its own path and now reads CRUSTDATA_API_KEY only. The client's token stays inside Claude Code with no supported way for a hook subprocess to read it, so the previously shared credential is gone. Without the env var the SessionStart hook no-ops exactly as it always did when no key was configured; bundled skills are unaffected. Existing installs keep a stale ~/.crustdata/credentials.json (or $CRUSTDATA_CONFIG_DIR) holding a live refresh token. Nothing reads it any more; it is safe to delete and the release notes should say so.
|
Superseded by crustdata/skills-internal#258 — the plugin is now maintained from That PR adds a The tree in Closing rather than merging so there's one path into this repo. Nothing is lost — the branch stays if anything needs to be recovered. |
Rebuilt on the latest
main. Three things, ending in a large deletion.1. Drop the plugin's custom login stack (
6709537)The plugin shipped a second OAuth client:
/crustdata:login, a 450-line browser/PKCE/DCR flow, a~/.crustdatacredential store with a cross-process refresh lock, an MCPheadersHelper, a SessionStart token refresh, and a PreToolUse gate. Claude Code already does all of this for anhttpMCP server, so the layer was duplicated work carrying its own failure modes (the Windows/WSL and Node-24 fixes in this very PR were all fixes to that layer).install.crustdata.comalready serves everything the native flow needs — verified live:POST /mcp(no auth)401+www-authenticate: Bearer … resource_metadata=".../.well-known/oauth-protected-resource/mcp"GET /.well-known/oauth-protected-resource/mcp200→authorization_servers: ["https://install.crustdata.com/"]GET /.well-known/oauth-authorization-server200→ PKCES256,registration_endpoint(DCR),authorization_code+refresh_tokenRemoving
headersHelperis the change that hands the connection back to the client: while one is configured the plugin supplies theAuthorizationheader itself, and a client-managed token has nothing to attach to.Sign-in is now: Claude prompts on first Crustdata tool use, or
/mcp→ crustdata → Authenticate. Nothing to paste, no command to remember.The PreToolUse gate had to be deleted rather than left inert — it exits 2 when the store has no token, and the store is now permanently empty, so it would have blocked every Crustdata tool call on a working connection.
Skill sync keeps its own path and now reads
CRUSTDATA_API_KEYonly. The client's token stays inside Claude Code with no supported way for a hook subprocess to read it, so the previously shared credential is gone. Without the env var the SessionStart hook no-ops exactly as it always did when no key was configured; bundled skills are unaffected. This is the one behaviour change worth a second opinion.Net: −1,599 lines, five test files gone. Remaining suite (21 tests) green on Node 18/20/22/24 × 3 OS; the hook was also run standalone in both auth states (no key → one stderr line, exit 0; with key → normal path).
2. Migration to the current MCP server
candidate-sourcingandemail-enrichmentwere written against the previous server's per-endpoint tools; both are replaced with their Code Mode rewrites (same workflows, driven throughexecute/callTool). Every remaining connector instruction points atinstall.crustdata.com/mcp.3. Cross-platform CI
The suite runs on ubuntu × macos × windows over Node 18/20/22/24, so the documented
Node ≥ 18floor is enforced rather than asserted. This survives the deletion and now covers the sync hook.Notes for review
/mcp. They also keep a stale~/.crustdata/credentials.json(or$CRUSTDATA_CONFIG_DIR) holding a live refresh token — nothing reads it any more, it is safe to delete, and the release notes should say so.Authorizationheader — which suppresses the 401 challenge and so cannot be layered on the same entry as native OAuth. Called out rather than half-solved.plugin.json0.2.0→0.3.0(user-visible auth change).