Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.

refactor(notion+gmail): unify auth lifecycle on start(), fix proxy /v1 prefix regression#12

Merged
senamakel merged 15 commits into
tinyhumansai:mainfrom
senamakel:fix/skill-states
Apr 10, 2026
Merged

refactor(notion+gmail): unify auth lifecycle on start(), fix proxy /v1 prefix regression#12
senamakel merged 15 commits into
tinyhumansai:mainfrom
senamakel:fix/skill-states

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 10, 2026

Summary

  • Move Notion and Gmail activation into a dedicated start.ts per skill: one entry point that picks up credentials, optionally validates them against the upstream API, and registers cron — replacing the old onOAuthComplete / onAuthComplete hooks.
  • Fix /v1 proxy-prefix regression in src/core/notion/helpers.ts: PR Notion and Gmail Auth Fetch Changes #11 dropped the /v1 prefix from oauth.fetch() calls assuming the encrypted-proxy backend prepends apiBaseUrl from the manifest. It does not — it forwards paths verbatim. Result: every Notion oauth.fetch('/users/me') reached Notion as /users/me and came back 400 "Invalid request URL", which made oauth/complete validation fail and rolled back the credential. This was the root cause of the "Notion not connected" cascade reported in #484.
  • Test harness: runtimeUrl() is now a getter (re-evaluated per call so live scripts can flip SKILLS_RUNTIME_URL after import) and defaults to port 7799 to match openhuman-core skills run --port 7799.
  • Stress test (src/core/notion/live-test-stress.ts) now inspects the oauth/complete result, fails fast on {status:'error'} with the validation error and a pointer to live-test.ts for fresh OAuth, and verifies state.connection_status === 'connected' before kicking off the stress phase.
  • New publish-state.ts in both skills extracts the state.setPartial contract so start.ts and index.ts share the same shape without re-introducing a circular import.
  • types/skill.d.ts updated for the new Skill.start: (args?: SkillStartArgs) => MaybeAsync<SkillStartResult | void> signature; onOAuthComplete / onAuthComplete removed from the interface.
  • Bumps openhuman submodule to pull in the matching Rust-side rewrite (refactor(skills): unify auth/oauth handshake on start({validate}) and drop enabled flag openhuman#484).

Problem

Two long-standing issues collided here:

  1. Lifecycle confusion: Notion and Gmail had three places where credentials could be wired up (onOAuthComplete, onAuthComplete, start) and two parallel "is the skill on?" flags upstream (enabled vs setup_complete). The handshake was order-dependent and easy to half-finish — credential persisted to disk, but cron never registered, or cron registered against an upstream the API rejects on the next call.
  2. Silent /v1 regression: PR Notion and Gmail Auth Fetch Changes #11 ("Notion and Gmail Auth Fetch Changes") removed the /v1 prefix from oauth.fetch calls in notionFetch, claiming "path is relative to manifest `apiBaseUrl`, same as Gmail." The encrypted-proxy backend doesn't actually prepend apiBaseUrl — it forwards paths verbatim — so every Notion proxy call started returning Notion's 400 invalid_request_url. The stress test never noticed because it ignored the oauth/complete return value and printed OK whenever the RPC didn't throw.

Solution

  • src/core/notion/start.ts (new) and src/core/gmail/start.ts (new): own credential pickup, validation, cron registration, and publishState(). Both validators (validateNotionOAuth / validateGmailOAuth etc.) hit the upstream API the same way the runtime will at tool-call time, so a bad credential fails the handshake instead of poisoning the activated state.
  • src/core/notion/publish-state.ts (new) and src/core/gmail/publish-state.ts (new): single publishState() / publishSkillState() function shared between start.ts and index.ts, breaking the circular import that previously kept this logic inlined.
  • src/core/notion/index.ts / src/core/gmail/index.ts: stripped of inline start, validators, onOAuthComplete, onAuthComplete, and the duplicated state-publish helpers.
  • src/core/notion/helpers.ts:106: restore \/v1${path}`` on the proxy path with a comment explaining why the backend can't prepend it (so a future drive-by refactor doesn't reintroduce the same regression).
  • dev/test-harness/index.ts:28: runtimeUrl() getter, default 127.0.0.1:7799. Re-evaluating per call lets live-test scripts override SKILLS_RUNTIME_URL after the harness has been imported.
  • src/core/notion/live-test-stress.ts: inspect oauthComplete result; on {status:'error'} print the validation errors and exit non-zero with a pointer to npx tsx src/core/notion/live-test.ts (which has the interactive OAuth flow that mints fresh credentials). Adds a "Verifying connection..." step that checks getSkillStatus(...).state.connection_status === 'connected' before the warmup/stress phase so a silent rollback can never go undetected again.
  • types/skill.d.ts: add SkillStartArgs / SkillStartResult; broaden Skill.start to accept the credential bag and return a status; drop onOAuthComplete / onAuthComplete.

Submission Checklist

  • Live testnpx tsx src/core/notion/live-test-stress.ts 12 → 12/12 passed across list-users, list-pages, list-databases, search (avg 2504ms, p95 6174ms).
  • Live testnpx tsx src/core/notion/live-test.ts walks the full happy path (start → oauth → connect → tools → sync) end-to-end against the real Rust runtime.
  • Typecheckyarn typecheck clean.
  • Buildyarn build regenerates the bundled skills/notion/index.js and skills/gmail/index.js with the new /v1 prefix path.
  • No hardcoded secrets — JWT now sourced from ~/.openhuman/users/<active>/auth-profiles.json via the harness, not the env.
  • Doc commentsstart.ts and publish-state.ts files lead with a header explaining the contract; the /v1 proxy comment in helpers.ts calls out why the prefix is required.

Impact

  • Runtime: Desktop core (QuickJS skills runtime). Requires the matching Rust-side handler rewrite in refactor(skills): unify auth/oauth handshake on start({validate}) and drop enabled flag openhuman#484 — old runtimes will still call the removed onOAuthComplete / onAuthComplete hooks (which now no-op cleanly because they're undefined on the JS side, but without the validate-then-persist contract).
  • Behavior change: A bad OAuth credential now fails oauth/complete loudly with {status:'error', errors:[...]} instead of silently persisting and breaking on the first tool call. Existing UI code that ignored the result will need to surface the error.
  • Bundle size: net wash — moved code, not added.

Related

Summary by CodeRabbit

  • New Features

    • Structured credential validation and detailed error reporting for Gmail and Notion; new start-based activation contract.
  • Refactor

    • Unified activation flow and centralized state publishing; Gmail and Notion split start/publish responsibilities into shared modules.
  • Bug Fixes

    • OAuth proxy path logging/handling corrected; Gmail refreshes stored user email on account changes; startup/auth gates added to tests/tools.
  • Tests

    • Tests converted to async/await and added safer tool-call helpers.
  • Chores

    • Runtime URL now read dynamically from environment; git submodule pointer updated.

…re effectively. Introduced interfaces for start arguments, improved credential handling, and removed unused OAuth complete functions. Enhanced logging for better debugging and streamlined sync scheduling logic. Updated openhuman submodule to the latest commit.
…lidation and error handling. Introduced `validate` flag in start arguments to trigger API checks during authentication. Improved logging for better debugging and streamlined the overall structure of the code. Updated openhuman submodule to the latest commit for alignment with recent changes.
…zed state publishing and improving credential validation. Added `publishSkillState` and `start` functions for both skills to streamline state management and connection handling. Removed unused credential validation functions and refactored code for better readability and maintainability. This update enhances the overall functionality and user experience of the integrations.
…ns to streamline code and improve maintainability. This update enhances readability and focuses on essential functionality, aligning with recent improvements in credential handling and state management.
…zed OAuth validation functions. Updated validation logic to streamline credential checks and improve error handling during the authentication process. This refactor enhances code maintainability and aligns with recent improvements in state management.
…nt with recent changes and improvements in the project.
… maintainability. Removed unnecessary whitespace and standardized function signatures for credential validation. This update enhances overall code clarity and aligns with recent improvements in state management.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2990c8f6-8080-42e5-afab-901231c1b8c5

📥 Commits

Reviewing files that changed from the base of the PR and between 31a77e4 and bf2bf6b.

📒 Files selected for processing (5)
  • openhuman
  • scripts/validate.mjs
  • src/core/gmail/__tests__/test-gmail.ts
  • src/core/gmail/start.ts
  • src/core/notion/start.ts

📝 Walkthrough

Walkthrough

Centralizes auth into a new start(args?) lifecycle, removes callback auth-completion hooks, extracts start and state-publish logic for Gmail and Notion into dedicated modules, makes test-harness runtime URL read env at call time, updates validators/tests, and advances the openhuman submodule pointer.

Changes

Cohort / File(s) Summary
Skill types & contract
types/skill.d.ts
Replaced callback-based auth hooks with `start(args?: SkillStartArgs): MaybeAsync<SkillStartResult
Validation & tooling
scripts/validate.mjs
Validator now requires/export-detection for start and consolidates auth validation to the start lifecycle; added warnIfLegacyAuthHooks and removed legacy completion-hook enforcement.
Test harness runtime
dev/test-harness/index.ts
Replaced module-level RUNTIME_URL with runtimeUrl() that reads process.env.SKILLS_RUNTIME_URL per call; updated JSON-RPC and REST helpers to use it.
Gmail core refactor
src/core/gmail/index.ts, src/core/gmail/start.ts, src/core/gmail/publish-state.ts, src/core/gmail/api/helpers.ts, src/core/gmail/__tests__/test-gmail.ts
Extracted start and publishSkillState into new modules; removed in-file onOAuthComplete/onAuthComplete and startup sync from index; loadGmailProfile() now refreshes persisted userEmail when profile differs; tests converted to async/await and added resilient tool-call helper.
Notion core refactor & helpers
src/core/notion/index.ts, src/core/notion/start.ts, src/core/notion/publish-state.ts, src/core/notion/helpers.ts, src/core/notion/live-test-stress.ts
Extracted start and publishState; removed local auth-complete hooks from index; adjusted OAuth-proxy path to prefix /v1 for proxy calls; live stress test now validates oauth result and connection status before proceeding.
Submodule update
openhuman
Advanced the openhuman git submodule pointer to a newer commit.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Orchestrator as Skill Orchestrator
  participant Skill as Skill Module
  participant State as State/DB
  participant Cron as CronRegistry

  Client->>Orchestrator: POST /start(args)
  Orchestrator->>Skill: invoke start(args)
  Skill->>Skill: validate credentials (oauth/self-hosted/text)
  alt validation fails
    Skill->>Orchestrator: return {status:'error', errors}
  else validation succeeds
    Skill->>State: persist config (credentialId, userEmail/workspace)
    Skill->>Cron: unregister existing sync job
    Skill->>Cron: register sync with interval
    Skill->>State: publishSkillState()/publishState()
    Skill->>Orchestrator: return {status:'complete', message?}
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hopped through code with nimble paws tonight,
Swapped old hooks for one start — everything feels right.
Gmail and Notion now publish states in tune,
Crons re-register, configs saved by moon.
Hop, test, deploy — the skills are taking flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the primary refactoring: unifying auth lifecycle on start() and fixing the proxy /v1 prefix regression.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

… and OAuth validation. Introduced a dynamic `runtimeUrl` function for better flexibility in setting the skills runtime URL. Enhanced error handling in the Notion live test script to verify skill authentication status before proceeding with stress tests. These changes improve code maintainability and ensure more reliable integration with the Notion API.
@senamakel senamakel changed the title Fix/skill states refactor(notion+gmail): unify auth lifecycle on start(), fix proxy /v1 prefix regression Apr 10, 2026
@senamakel senamakel marked this pull request as ready for review April 10, 2026 06:21
…g a unified `start` function requirement. Updated the validation process to check for legacy hooks and ensure skills export the `start` function, which is now the primary entry point for OAuth and auth lifecycle events. This refactor improves clarity and maintainability of the authentication setup process.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
src/core/notion/helpers.ts (1)

125-127: Consider logging proxyPath instead of path for OAuth proxy calls.

Line 126 logs path for all calls, but for OAuth proxy calls the actual request uses proxyPath (with /v1 prefix). This could cause confusion when debugging proxy-related issues.

Suggested fix
+    const logPath = notionAuth.type === 'proxy' ? `/v1${path}` : path;
     console.log(
-      `[notion][fetch] ${method} ${path} status=${response.status} (${elapsed}ms, ${bodyLen}b)`
+      `[notion][fetch] ${method} ${logPath} status=${response.status} (${elapsed}ms, ${bodyLen}b)`
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/notion/helpers.ts` around lines 125 - 127, The log currently prints
the original request `path` which is misleading for OAuth proxy calls that
actually use `proxyPath`; update the logging in the fetch/HTTP helper (the
console.log that references `method`, `path`, `response.status`, `elapsed`, and
`bodyLen`) to print `proxyPath` when it is defined/used (falling back to `path`
otherwise) so proxy requests show the real URL used for the request.
scripts/validate.mjs (1)

234-245: Consider strengthening the ./start import detection heuristic.

Pattern 3 (from\s+['"]\.\/start['"]) assumes that any import from ./start implies a start function is exported. This could produce false positives if a file imports something else from ./start (e.g., import { someHelper } from './start').

A more robust check might combine this with verifying start appears in the import specifiers or is re-exported:

Suggested improvement
 function hasStartLifecycle(allContent) {
   if (/export\s+function\s+start\s*\(/.test(allContent)) return true;
   if (/export\s*\{[^}]*\bstart\b[^}]*\}/.test(allContent)) return true;
-  if (/from\s+['"]\.\/start['"]/.test(allContent)) return true;
+  // Check for re-export from ./start: `export { start } from './start'`
+  // or import+re-export: `import { start } from './start'` + `export { start }`
+  if (/export\s*\{[^}]*\bstart\b[^}]*\}\s*from\s+['"]\.\/start['"]/.test(allContent)) return true;
+  if (/import\s*\{[^}]*\bstart\b[^}]*\}\s*from\s+['"]\.\/start['"]/.test(allContent)) return true;
   return false;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/validate.mjs` around lines 234 - 245, The heuristic in
hasStartLifecycle is too broad for the "./start" case: update the third check so
it only returns true when the import/export actually mentions start (e.g.,
detect import specifiers like "import { start" or "import start" from './start',
re-exports "export { start } from './start'", or wildcard re-exports "export *
from './start'"); specifically modify the regex for the "./start" branch in
hasStartLifecycle to require "start" in the import/export specifiers or allow a
true re-export, ensuring we still catch re-exports and default/name imports that
actually refer to start.
src/core/notion/start.ts (1)

22-30: Reuse the shared lifecycle types here.

NotionStartArgs and StartResult duplicate the new contract in types/skill.d.ts, and src/core/gmail/start.ts now carries the same copy. Reusing SkillStartArgs / SkillStartResult will keep future host-side lifecycle changes from drifting across skills.

As per coding guidelines: Keep concerns separated into dedicated files and folders. Use modular file layout with separate files for types, state, setup, sync, database schema/helpers, API calls per domain, tools per function, and update handlers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/notion/start.ts` around lines 22 - 30, The NotionStartArgs and
StartResult types duplicate the shared contract—replace these local types with
imports of SkillStartArgs and SkillStartResult from the central types/skill.d.ts
and update any usages in this file (and ensure consistency with
src/core/gmail/start.ts) to refer to those imported names; remove the duplicate
interfaces NotionStartArgs and StartResult and export or re-export the shared
types as needed so the skill uses the canonical lifecycle types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/gmail/publish-state.ts`:
- Around line 36-37: The code unconditionally calls new Date(...).toISOString()
on s.syncStatus.lastSyncTime and s.syncStatus.nextSyncTime which throws if the
value is undefined (and yields epoch for 0); update the mapping in
src/core/gmail/publish-state.ts so that lastSyncTime and nextSyncTime are only
converted when truthy (e.g., check s.syncStatus.lastSyncTime and
s.syncStatus.nextSyncTime) and otherwise set to null/undefined (or omit),
mirroring the Notion publish-state pattern; update references to lastSyncTime,
nextSyncTime and s.syncStatus accordingly.

In `@src/core/gmail/start.ts`:
- Around line 229-242: When args.validate is true ensure unknown auth.mode
values are rejected: inside the validation block that checks auth and auth.mode,
add an explicit else branch that sets validationError to an error describing
"unsupported auth mode" (or missing/invalid credentials) when auth.mode is
present but not 'self_hosted', 'text', or 'managed'; also handle the case where
args.auth exists but auth.mode is undefined/invalid by treating it as an invalid
mode. Update the logic surrounding validateGmailSelfHosted, validateGmailText,
and validateGmailOAuth so validationError is non-null for unsupported modes,
preventing connected from becoming truthy with unusable credentials.
- Around line 211-218: The OAuth handling currently only sets s.config.userEmail
when it is blank, so when reconnecting a different account the previous
userEmail remains; update the block that processes args.oauth (the oauthCred
handling in start.ts) to always overwrite s.config.userEmail when
oauthCred.accountLabel is present (remove the if (!s.config.userEmail) guard)
and persist with state.set('config', s.config); also remove the identical guard
inside loadGmailProfile() so that loadGmailProfile() will likewise refresh the
stored userEmail when the OAuth account changes.

In `@src/core/notion/live-test-stress.ts`:
- Around line 257-258: The code uses optional chaining when reading
connection_status into connState; replace "(verify.state as {
connection_status?: string } | undefined)?.connection_status" with an explicit
null/undefined check: first cast or access verify.state, check if verify &&
verify.state (or if verify.state !== undefined/null) then read
verify.state.connection_status into connState, then compare connState !==
'connected'. Update the variable access around connState, verify.state, and
connection_status to avoid any "?.", ensuring the same behavior when state is
missing.

In `@src/core/notion/start.ts`:
- Around line 43-46: The code only sets
getNotionSkillState().config.workspaceName when the existing value is empty,
which prevents updating the stored workspace label on reconnection; change the
logic in the OAuth validation block (where the local variable name is derived
from user.name) to assign getNotionSkillState().config.workspaceName = name
whenever name is defined (remove the "only if empty" guard) so the workspaceName
refreshes on reconnects; apply the same unconditional-overwrite fix to the spot
that copies accountLabel (the code that currently copies accountLabel only if
blank) so credential changes replace the stored label.
- Around line 106-114: The parsing assumes a `results` array but the
`/v1/users/me` endpoint returns a single user object; update the parsing logic
in the token validation block that reads `response.body` so it handles both
shapes: if the parsed `data` has a top-level `type` (e.g., data.type === 'bot')
use `data.name` to set getNotionSkillState().config.workspaceName, otherwise
fall back to the existing `results` array logic (find u.type === 'bot'). Ensure
this change touches the block that defines `botUser` and assigns to
getNotionSkillState().config.workspaceName so metadata extraction works for the
`/users/me` response.

---

Nitpick comments:
In `@scripts/validate.mjs`:
- Around line 234-245: The heuristic in hasStartLifecycle is too broad for the
"./start" case: update the third check so it only returns true when the
import/export actually mentions start (e.g., detect import specifiers like
"import { start" or "import start" from './start', re-exports "export { start }
from './start'", or wildcard re-exports "export * from './start'"); specifically
modify the regex for the "./start" branch in hasStartLifecycle to require
"start" in the import/export specifiers or allow a true re-export, ensuring we
still catch re-exports and default/name imports that actually refer to start.

In `@src/core/notion/helpers.ts`:
- Around line 125-127: The log currently prints the original request `path`
which is misleading for OAuth proxy calls that actually use `proxyPath`; update
the logging in the fetch/HTTP helper (the console.log that references `method`,
`path`, `response.status`, `elapsed`, and `bodyLen`) to print `proxyPath` when
it is defined/used (falling back to `path` otherwise) so proxy requests show the
real URL used for the request.

In `@src/core/notion/start.ts`:
- Around line 22-30: The NotionStartArgs and StartResult types duplicate the
shared contract—replace these local types with imports of SkillStartArgs and
SkillStartResult from the central types/skill.d.ts and update any usages in this
file (and ensure consistency with src/core/gmail/start.ts) to refer to those
imported names; remove the duplicate interfaces NotionStartArgs and StartResult
and export or re-export the shared types as needed so the skill uses the
canonical lifecycle types.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 69db152d-f342-42a1-a5c6-50a342b7df5e

📥 Commits

Reviewing files that changed from the base of the PR and between 22eca6e and 4b4fa3b.

📒 Files selected for processing (12)
  • dev/test-harness/index.ts
  • openhuman
  • scripts/validate.mjs
  • src/core/gmail/index.ts
  • src/core/gmail/publish-state.ts
  • src/core/gmail/start.ts
  • src/core/notion/helpers.ts
  • src/core/notion/index.ts
  • src/core/notion/live-test-stress.ts
  • src/core/notion/publish-state.ts
  • src/core/notion/start.ts
  • types/skill.d.ts

Comment thread src/core/gmail/publish-state.ts Outdated
Comment thread src/core/gmail/start.ts
Comment thread src/core/notion/live-test-stress.ts Outdated
Comment thread src/core/notion/start.ts
Comment thread src/core/notion/start.ts Outdated
…l and Notion skill authentication by refining validation logic for credential handling. Improved error handling in the `start` functions and ensured consistent state management across skills. These changes enhance code clarity and maintainability while aligning with recent improvements in the project.
…th` and `start` function signatures to use more specific types. This change enhances type safety and improves code clarity, aligning with recent improvements in the project's authentication logic.
…consistency. Updated test cases to handle asynchronous operations in skill lifecycle methods and tool calls, enhancing error handling and ensuring proper cleanup after tests. This change aligns with recent improvements in the project's testing framework.
…solidated assertion logic to enhance clarity while maintaining functionality. This change aligns with ongoing efforts to improve code quality and maintainability in the testing framework.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/validate.mjs`:
- Around line 240-249: The helper hasStartLifecycle currently scans any file
content and treats imports/exports from './start' as satisfying the lifecycle;
restrict this by changing hasStartLifecycle to accept an optional filename (or
update callers) and only consider imports/exports from './start' as valid when
the examined file is the skill entry (e.g., its basename is index.ts, index.tsx,
index.js, or index.jsx), otherwise only count explicit exported function/ named
export occurrences; update calls in validateSetupFlow to pass the file name or
run hasStartLifecycle only against the entry file content so private helper
files can't falsely satisfy the contract.

In `@src/core/gmail/__tests__/test-gmail.ts`:
- Around line 53-57: Replace empty catch blocks used in test teardown hooks
(e.g., the afterAll wrapping stopSkill(SKILL_ID) and the other similar try/catch
blocks) with minimal handling to satisfy no-empty: either add a concise comment
like // ignore errors during cleanup or log the error (e.g.,
process.stderr.write or console.debug) inside each catch. Update the catch
bodies for the occurrences around the afterAll at startLine 53 and the other
blocks referenced (around lines 65-70, 80-84, 92-97, 137-141) so they are
non-empty while keeping semantics unchanged.

In `@src/core/gmail/start.ts`:
- Around line 205-212: The code currently mutates s.config and calls
state.set('config') before running validateGmailOAuth(), which can persist
invalid OAuth data; instead, keep the incoming oauth values in local temporaries
(e.g., tempCredentialId, tempAccountLabel) and pass them to
validateGmailOAuth(); only if validateGmailOAuth() succeeds assign them to
s.config and call state.set('config'); apply the same change for the later block
that updates s.config (the other occurrence referenced around validateGmailOAuth
usage).

In `@src/core/notion/start.ts`:
- Around line 136-145: The code writes oauthCred (credentialId/accountLabel)
into s.config and calls state.set('config', s.config) before validation;
instead, move the state.set call (and any mutation of persisted config) to after
validateNotionOAuth() succeeds in start(), so update s.config locally when
args.oauth is present but only persist via state.set('config', s.config) after
validateNotionOAuth() returns successfully; apply the same change for the
duplicate oauth-handling block that also writes state (the other block around
validateNotionOAuth usage) to ensure rejected credentials are never persisted.
- Around line 156-194: The code currently treats any auth with a non-'managed'
mode as direct and skips validation when auth.mode is missing, allowing cron
registration with invalid/unknown modes; update the start logic to explicitly
handle supported modes (e.g., 'managed' and 'direct'), reject missing or unknown
auth.mode before proceeding, and only set connected/allow cron.register when
validation passes: in start.ts adjust the auth/validation block (references:
args.auth, auth.mode, validateNotionAuthDirect, validateNotionOAuth,
validationError, connected, cron.register) so that if auth is present but
auth.mode is undefined or not in the allowed set you assign a validationError
(or return it), otherwise call validateNotionOAuth for 'managed' and
validateNotionAuthDirect for 'direct', and ensure connected is derived only
after successful validation to prevent scheduling 'notion-sync' when auth is
invalid.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37fef112-e2f1-489b-a0fc-255be0a51a4f

📥 Commits

Reviewing files that changed from the base of the PR and between 4b4fa3b and 31a77e4.

📒 Files selected for processing (9)
  • openhuman
  • scripts/validate.mjs
  • src/core/gmail/__tests__/test-gmail.ts
  • src/core/gmail/api/helpers.ts
  • src/core/gmail/publish-state.ts
  • src/core/gmail/start.ts
  • src/core/notion/helpers.ts
  • src/core/notion/live-test-stress.ts
  • src/core/notion/start.ts
✅ Files skipped from review due to trivial changes (1)
  • openhuman
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/core/notion/helpers.ts
  • src/core/gmail/publish-state.ts

Comment thread scripts/validate.mjs Outdated
Comment thread src/core/gmail/__tests__/test-gmail.ts
Comment thread src/core/gmail/start.ts
Comment thread src/core/notion/start.ts
Comment thread src/core/notion/start.ts
…nt with recent changes and improvements in the project.
…cycle` function to ensure proper checks for exported `start` functions in entry files. Updated the `start` functions in Gmail and Notion skills to temporarily store OAuth metadata until validation succeeds, preventing overwrites of existing credentials. Improved error handling in test cases to ignore cleanup errors. These changes enhance code clarity, maintainability, and ensure robust credential management across skills.
@senamakel senamakel merged commit 18db3bf into tinyhumansai:main Apr 10, 2026
1 of 2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant