Skip to content

feat(core): per-provider scope catalog (supportedScopes)#136

Merged
khaliqgant merged 4 commits into
mainfrom
feat/scope-catalog
Jun 1, 2026
Merged

feat(core): per-provider scope catalog (supportedScopes)#136
khaliqgant merged 4 commits into
mainfrom
feat/scope-catalog

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

What

Adds a per-provider scope catalog to @relayfile/adapter-core, mirroring the existing trigger catalog. Scope keys are the user-facing connection filters a persona sets under integrations.<provider>.scope (e.g. githubowner/repo) — distinct from infra config (connectionId, tokens) and from trigger event names.

Why

@agentworkforce/persona-kit types persona triggers per provider (TriggerNameFor<P>) by importing KNOWN_TRIGGER_CATALOG from @relayfile/adapter-core/triggers. There was no equivalent for scope, so integrations.<provider>.scope was an untyped Record<string, string>. This adds the source-of-truth catalog so persona authoring can autocomplete/lint scope keys per provider (consumed in a follow-up persona-kit PR).

Scope keys aren't derivable from adapter config (it mixes infra + filters with no marker), so each adapter explicitly declares them — exactly what supportedScopes() is for.

Changes

  • supportedScopes(): string[] on adapters (parallel to supportedEvents()), with a mapping.yaml scopes: fallback. Seeds github → [owner, repo].
  • scopes/catalog-generator.ts — faithful mirror of the triggers generator; reuses findRepoRoot. Emits scopes/catalog.generated.{ts,json} (KNOWN_SCOPE_CATALOG, KnownScopeProviderName, KnownScopeKey<P>) + an adapters-without-known-scopes report.
  • @relayfile/adapter-core/scopes subpath export + index re-export.
  • adapter-core scopes generate|check CLI (the check form is a CI gate).
  • In-sync generator test + the deterministic github → owner/repo assertion.

Other providers report "no known scopes" gracefully (just like adapters-without-known-triggers) until their owners declare a scope contract.

Notes

  • No version bump (per the manual publish.yml release flow).
  • I did not touch the triggers catalog — its committed file is already out of sync with current adapters on main (pre-existing drift, unrelated to this PR).

Test

adapter-core scopes generate is deterministic across partial/full builds; the new test (KNOWN_SCOPE_CATALOG.github === ['owner','repo'] + full in-sync regeneration) passes after turbo build.

🤖 Generated with Claude Code

Mirrors the trigger catalog pipeline for connection **scope** keys — the
user-facing filter params a persona sets under integrations.<provider>.scope
(e.g. github owner/repo), distinct from infra config and trigger events.

- Adapters declare keys via supportedScopes() (with a mapping.yaml `scopes:`
  fallback), parallel to supportedEvents().
- New scopes/catalog-generator.ts scans adapters into KNOWN_SCOPE_CATALOG +
  KnownScopeKey<P>, emitted to scopes/catalog.generated.{ts,json} and an
  adapters-without-known-scopes report.
- Exported at @relayfile/adapter-core/scopes; `adapter-core scopes generate|check`
  CLI; in-sync test.
- Seeds github -> [owner, repo]; other providers declare their scope contract
  later (generator records "no known scopes" gracefully, like triggers).

Consumed by @agentworkforce/persona-kit to type integrations.<provider>.scope
per provider. Did not touch the triggers catalog (its committed drift is
pre-existing and unrelated).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@khaliqgant, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 44 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f035fab-9d41-4286-b199-ca70d3cf9504

📥 Commits

Reviewing files that changed from the base of the PR and between e938fe7 and 550071f.

📒 Files selected for processing (17)
  • AGENTS.md
  • README.md
  • packages/core/package.json
  • packages/core/src/cli.ts
  • packages/core/src/index.ts
  • packages/core/src/scope-keys/adapters-without-known-scope-keys.generated.json
  • packages/core/src/scope-keys/catalog-generator.ts
  • packages/core/src/scope-keys/catalog.generated.json
  • packages/core/src/scope-keys/catalog.generated.ts
  • packages/core/src/triggers/adapters-without-known-triggers.generated.json
  • packages/core/src/triggers/catalog-generator.ts
  • packages/core/src/triggers/catalog.generated.json
  • packages/core/src/triggers/catalog.generated.ts
  • packages/core/tests/scope-keys/catalog-generator.test.ts
  • packages/core/tsconfig.json
  • packages/github/src/index.ts
  • packages/github/src/types.ts
📝 Walkthrough

Walkthrough

This pull request introduces a scope catalog system that automatically discovers OAuth scope definitions declared by adapters. The system scans adapter packages for either explicit supportedScopes() methods or mapping.yaml files, aggregates results into a provider-keyed catalog, and exposes the catalog through CLI commands (scopes generate / scopes check), package exports, and TypeScript types.

Changes

Scope Catalog System

Layer / File(s) Summary
Adapter Interface and GitHub Implementation
packages/github/src/types.ts, packages/github/src/index.ts
IntegrationAdapter gains optional supportedScopes(): string[] method. GitHubAdapter implements it, declaring owner and repo as connection-level persona scopes.
Scope Catalog Generator Implementation
packages/core/src/scopes/catalog-generator.ts
Implements generateScopeCatalog() and writeScopeCatalog() to scan adapter packages, discover scope definitions from adapter supportedScopes() methods or mapping.yaml files, instantiate adapters using stubs, normalize and dedupe keys, aggregate by provider, and optionally write or check JSON/TS artifacts. Includes helpers for package enumeration, YAML parsing, adapter instantiation, key normalization, catalog sorting, and file I/O.
Generated Catalog Artifacts
packages/core/src/scopes/catalog.generated.json, packages/core/src/scopes/catalog.generated.ts, packages/core/src/scopes/adapters-without-known-scopes.generated.json
catalog.generated.json and catalog.generated.ts export KNOWN_SCOPE_CATALOG (github → owner, repo) and ADAPTERS_WITHOUT_KNOWN_SCOPES metadata. TS file includes derived type exports KnownScopeProviderName and KnownScopeKey<P> for compile-time scope validation.
Package Exports and Configuration
packages/core/package.json, packages/core/src/index.ts
Package.json adds ./scopes subpath export resolving to generated dist files (types and JS). Index.ts re-exports all generated catalog exports.
CLI Command Integration
packages/core/src/cli.ts
Adds top-level scopes command group with generate and check subcommands, wiring writeScopeCatalog() and rendering results to stdout via renderScopeSummary().
Tests and TypeScript Configuration
packages/core/tests/scopes/catalog-generator.test.ts, packages/core/tsconfig.json
Adds test suite verifying catalog generation reproduces expected JSON/TS outputs and matches exported constants. Updates tsconfig to include tests/scopes/**/*.test.ts.

Sequence Diagram

sequenceDiagram
  participant User
  participant CLI
  participant Generator
  participant Adapters
  participant YAML as mapping.yaml
  participant FileSystem
  
  User->>CLI: scopes generate
  CLI->>Generator: writeScopeCatalog()
  Generator->>Generator: listAdapterPackages()
  
  loop For each adapter
    Generator->>Adapters: dynamically import
    Adapters-->>Generator: export list
    Generator->>Adapters: instantiate with stubs
    Adapters-->>Generator: call supportedScopes()
    Generator->>YAML: read mapping.yaml
    YAML-->>Generator: scope keys
  end
  
  Generator->>Generator: sortCatalog()
  Generator->>Generator: renderScopeCatalogModule()
  Generator->>FileSystem: write catalog.generated.json
  Generator->>FileSystem: write catalog.generated.ts
  Generator->>FileSystem: write adapters-without-known-scopes.generated.json
  Generator-->>CLI: ScopeCatalogGeneration
  CLI-->>User: catalog generation summary
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A catalog of scopes is born,
From adapters far and wide,
GitHub's owner, repo worn,
In generated types they'll hide!
The CLI commands now convey,
What each provider lets you say. 🔐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: adding a per-provider scope catalog with supportedScopes functionality to the core adapter package.
Description check ✅ Passed Description comprehensively documents the change, explaining what was added (scope catalog), why it was needed (persona-kit typing), and how it works (explicit adapter declarations with mapping.yaml fallback).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/scope-catalog

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/scopes/catalog-generator.ts`:
- Around line 69-94: The code is merging mappingScopes into entries even when
supportedScopes provides keys; change behavior so mappingScopes is treated as a
fallback: if readSupportedScopes(adapterPackage).keys.length > 0, do NOT push
mappingScopes into entries/sources (or alternatively throw/fail-fast if you want
to detect divergence) — update the logic around mappingScopes, supportedScopes,
entries, sources and hasKnownScopes so mappingScopes is only used when
supportedScopes.keys is empty (use adapterPackage.provider as before), and
consider emitting an error/log if both exist but differ to surface stale YAML
instead of merging into KNOWN_SCOPE_CATALOG.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e044afb-2d4d-42eb-97a4-7e6133272f15

📥 Commits

Reviewing files that changed from the base of the PR and between 53b78ef and e938fe7.

📒 Files selected for processing (11)
  • packages/core/package.json
  • packages/core/src/cli.ts
  • packages/core/src/index.ts
  • packages/core/src/scopes/adapters-without-known-scopes.generated.json
  • packages/core/src/scopes/catalog-generator.ts
  • packages/core/src/scopes/catalog.generated.json
  • packages/core/src/scopes/catalog.generated.ts
  • packages/core/tests/scopes/catalog-generator.test.ts
  • packages/core/tsconfig.json
  • packages/github/src/index.ts
  • packages/github/src/types.ts

Comment thread packages/core/src/scopes/catalog-generator.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/scopes/catalog-generator.ts">

<violation number="1" location="packages/core/src/scopes/catalog-generator.ts:84">
P2: Treat `mapping.scopes` as a fallback only when `supportedScopes()` has no keys. Merging both sources can keep stale YAML scope keys in `KNOWN_SCOPE_CATALOG` after an adapter removes or renames a supported scope.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

hasKnownScopes = true;
}

if (mappingScopes.length > 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Treat mapping.scopes as a fallback only when supportedScopes() has no keys. Merging both sources can keep stale YAML scope keys in KNOWN_SCOPE_CATALOG after an adapter removes or renames a supported scope.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/scopes/catalog-generator.ts, line 84:

<comment>Treat `mapping.scopes` as a fallback only when `supportedScopes()` has no keys. Merging both sources can keep stale YAML scope keys in `KNOWN_SCOPE_CATALOG` after an adapter removes or renames a supported scope.</comment>

<file context>
@@ -0,0 +1,435 @@
+      hasKnownScopes = true;
+    }
+
+    if (mappingScopes.length > 0) {
+      const provider = supportedScopes.keys.length > 0 ? supportedScopes.provider : adapterPackage.provider;
+      entries.push({ provider, keys: mappingScopes });
</file context>

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed and fixed PR #136.

Changes made:

  • Made scope catalog discovery stable for common adapter builds by checking dist/index.js and avoiding raw TS execution failures in the compiled CLI: catalog-generator.ts.
  • Added a source literal fallback for simple supportedScopes() declarations so GitHub scopes remain discoverable without package dists: catalog-generator.ts.
  • Aligned the existing trigger catalog generator with the repo’s normal dist/index.js build output: catalog-generator.ts.
  • Regenerated the trigger catalog so Granola’s mapping-declared recording.created trigger is no longer incorrectly listed as missing: catalog.generated.json.

Verification:

  • npm run build -w packages/core
  • npm test -w packages/core
  • node --import tsx packages/core/src/cli.ts scopes check --repo-root /home/daytona/workspace
  • node --import tsx packages/core/src/cli.ts triggers check --repo-root /home/daytona/workspace
  • npx turbo build typecheck test --concurrency=2 passed: 125/125 tasks successful.

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed e1c2eca to this PR. The notes below describe what changed.

Reviewed and fixed PR #136.

Changes made:

  • Made scope catalog discovery stable for common adapter builds by checking dist/index.js and avoiding raw TS execution failures in the compiled CLI: catalog-generator.ts.
  • Added a source literal fallback for simple supportedScopes() declarations so GitHub scopes remain discoverable without package dists: catalog-generator.ts.
  • Aligned the existing trigger catalog generator with the repo’s normal dist/index.js build output: catalog-generator.ts.
  • Regenerated the trigger catalog so Granola’s mapping-declared recording.created trigger is no longer incorrectly listed as missing: catalog.generated.json.

Verification:

  • npm run build -w packages/core
  • npm test -w packages/core
  • node --import tsx packages/core/src/cli.ts scopes check --repo-root /home/daytona/workspace
  • node --import tsx packages/core/src/cli.ts triggers check --repo-root /home/daytona/workspace
  • npx turbo build typecheck test --concurrency=2 passed: 125/125 tasks successful.

@agent-relay-code agent-relay-code Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pr-reviewer applied fixes — committed and pushed e1c2eca to this PR. The notes below describe what changed.

Reviewed and fixed PR #136.

Changes made:

  • Made scope catalog discovery stable for common adapter builds by checking dist/index.js and avoiding raw TS execution failures in the compiled CLI: catalog-generator.ts.
  • Added a source literal fallback for simple supportedScopes() declarations so GitHub scopes remain discoverable without package dists: catalog-generator.ts.
  • Aligned the existing trigger catalog generator with the repo’s normal dist/index.js build output: catalog-generator.ts.
  • Regenerated the trigger catalog so Granola’s mapping-declared recording.created trigger is no longer incorrectly listed as missing: catalog.generated.json.

Verification:

  • npm run build -w packages/core
  • npm test -w packages/core
  • node --import tsx packages/core/src/cli.ts scopes check --repo-root /home/daytona/workspace
  • node --import tsx packages/core/src/cli.ts triggers check --repo-root /home/daytona/workspace
  • npx turbo build typecheck test --concurrency=2 passed: 125/125 tasks successful.

@agent-relay-code

Copy link
Copy Markdown
Contributor

ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed.

pr-reviewer could not complete review for #136 in AgentWorkforce/relayfile-adapters.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@agent-relay-code agent-relay-code Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed.

pr-reviewer could not complete review for #136 in AgentWorkforce/relayfile-adapters.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/scopes/catalog-generator.ts">

<violation number="1" location="packages/core/src/scopes/catalog-generator.ts:254">
P2: Import error gets swallowed. Catalog can silently lose provider scopes and report wrong reason. Preserve and propagate import failure details.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

let moduleExports: Record<string, unknown>;
try {
moduleExports = (await import(pathToFileURL(entryPoint).href)) as Record<string, unknown>;
} catch {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Import error gets swallowed. Catalog can silently lose provider scopes and report wrong reason. Preserve and propagate import failure details.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/scopes/catalog-generator.ts, line 254:

<comment>Import error gets swallowed. Catalog can silently lose provider scopes and report wrong reason. Preserve and propagate import failure details.</comment>

<file context>
@@ -215,27 +215,44 @@ async function listAdapterPackages(repoRoot: string): Promise<AdapterPackage[]>
-      provider: adapterPackage.provider,
-      error: `Could not import built adapter entrypoint: ${errorMessage(error)}`,
-    };
+  } catch {
+    return { keys: [], provider: adapterPackage.provider };
   }
</file context>

…ract

Disambiguates from OAuth "scopes" (docs/integration-scopes.yaml / required_scopes):
the connection-filter catalog is now scope-**keys** throughout.

- supportedScopes() -> supportedScopeKeys(); KNOWN_SCOPE_CATALOG ->
  KNOWN_SCOPE_KEY_CATALOG; KnownScopeKey -> ScopeKey; KnownScopeProviderName ->
  ScopeKeyProvider; dir scopes/ -> scope-keys/; export /scopes -> /scope-keys;
  CLI `scopes` -> `scope-keys`; mapping fallback block `scopes:` -> `scopeKeys:`.
- AGENTS.md: new "Declared catalogs: triggers and scope keys" section — the
  supportedEvents/supportedScopeKeys contract, the regen commands, the CI
  in-sync gate, and the cross-repo bump caveat. README points to it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 14 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/scopes/catalog-generator.ts">

<violation number="1" location="packages/core/src/scopes/catalog-generator.ts:84">
P2: Treat `mapping.scopes` as a fallback only when `supportedScopes()` has no keys. Merging both sources can keep stale YAML scope keys in `KNOWN_SCOPE_CATALOG` after an adapter removes or renames a supported scope.</violation>

<violation number="2" location="packages/core/src/scopes/catalog-generator.ts:254">
P2: Import error gets swallowed. Catalog can silently lose provider scopes and report wrong reason. Preserve and propagate import failure details.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/core/src/cli.ts Outdated
…pagation, CLI summary)

Resolves CodeRabbit + cubic findings on #136:
- mapping `scopeKeys:` is now a FALLBACK only (else-if), never merged with
  supportedScopeKeys() — a stale YAML key can no longer outlive an adapter that
  renamed/removed a scope. (scope keys have one source of truth, unlike triggers
  where mapping webhooks are a legitimate second delivery contract.)
- propagate the adapter import failure into the "no scope keys" reason instead
  of swallowing it and reporting the generic "no implementation" message; re-add
  the errorMessage() helper the refactor dropped.
- restore the dropped subcommand in the CLI summary (`scope-keys ${command}`),
  so `generate` and `check` outputs are distinct again.

Catalog unchanged (github -> owner/repo); scope-keys check passes in-sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@khaliqgant

Copy link
Copy Markdown
Member Author

Addressed the review findings in 550071f:

  • mapping scopeKeys: is now fallback-only (CodeRabbit + cubic) — changed the merge to an else if, so supportedScopeKeys() wins and a stale YAML key can't outlive an adapter that renamed/removed a scope. (Scope keys have one source of truth; this intentionally diverges from the triggers generator, where mapping webhooks are a legitimate second delivery contract.)
  • Import error no longer swallowed (cubic) — readSupportedScopeKeysFromModule now returns the import failure, which surfaces as the adapter's "no scope keys" reason instead of the generic "no implementation" message. Re-added the errorMessage() helper the earlier refactor dropped.
  • CLI summary keeps the subcommand (cubic) — command: \scope-keys ${command}`, so generatevscheck` outputs are distinct again.

Catalog is unchanged (github → owner/repo); scope-keys check passes in-sync; tsc + tests green.

Note: CodeRabbit and gemini both bailed on the full review (rate-limit / daily-quota), so their green checks don't reflect a completed pass — the actionable items above came from CodeRabbit's one inline comment + cubic.

@khaliqgant khaliqgant merged commit 8e103ca into main Jun 1, 2026
3 checks passed
@khaliqgant khaliqgant deleted the feat/scope-catalog branch June 1, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant