Skip to content

feat: gate Dreams and add start control#953

Merged
ashione merged 8 commits intomainfrom
auto/dev-mode-dream
May 1, 2026
Merged

feat: gate Dreams and add start control#953
ashione merged 8 commits intomainfrom
auto/dev-mode-dream

Conversation

@ashione
Copy link
Copy Markdown
Contributor

@ashione ashione commented May 1, 2026

Summary

  • Hide the native Dreams sidebar entry until Developer Mode is enabled and redirect direct /dreams navigation when Developer Mode is disabled
  • Add a native Dreams start/stop control backed by config.get + config.patch, including raw patch transport support
  • Keep Dreams refresh available while the Gateway process is running and dedupe automatic refreshes without blocking manual refresh
  • Probe a lightweight Gateway RPC before marking the ready fallback as globally ready
  • Clean stale Gateway startup config: bundled OpenClaw plugin paths, missing external plugins.allow entries, and escaped workspace skill symlinks
  • Reduce restrictive plugin allowlists to installed/configured external plugins plus active provider plugins, avoiding broad startup-time plugin runtime mirroring
  • Defer heartbeat restart during the initial gateway.ready grace window so long synchronous Gateway initialization can complete instead of restart-looping

Test plan

  • pnpm run typecheck
  • pnpm exec vitest run tests/unit/openclaw-auth.test.ts tests/unit/skills-symlink-cleanup.test.ts tests/unit/gateway-manager-heartbeat.test.ts tests/unit/gateway-ready-fallback.test.ts
  • pnpm run lint:check
  • pnpm run build:vite
  • pnpm exec playwright test tests/e2e/openclaw-dreams.spec.ts
  • git diff --check
  • Changed-file secret scan
  • Runtime smoke: system-presence, doctor.memory.status, and doctor.memory.dreamDiary return after Gateway startup

Notes

  • lint:check passes with one pre-existing warning in src/pages/Chat/ChatInput.tsx about selectedSkill in a hook dependency array.
  • The first E2E attempt raced with a concurrent production build and hit a temporary missing dist/index.html; rerunning after the build completed passed all 3 Dreams specs.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6768dd42d5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/App.tsx
<Route path="/skills" element={<Skills />} />
<Route path="/cron" element={<Cron />} />
<Route path="/dreams" element={<Dreams />} />
<Route path="/dreams" element={devModeUnlocked ? <Dreams /> : <Navigate to="/" replace />} />
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.

P2 Badge Delay guarded Dreams redirect until settings hydrate

This unconditional guard can mis-route users who open #/dreams with Developer Mode already enabled in persisted main-process settings: devModeUnlocked starts as false in the renderer store and is only corrected later by async init(), so the first render executes <Navigate ... replace> and permanently rewrites the URL to / before hydration completes. In that startup path, authorized users lose deep-link access to Dreams even though their saved setting allows it.

Useful? React with 👍 / 👎.

@ashione ashione changed the title feat: gate Dreams behind developer mode feat: gate Dreams and add start control May 1, 2026
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dca22c1392

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread electron/gateway/manager.ts Outdated

logger.info('Gateway ready fallback triggered; probing health before marking ready');
try {
await this.rpc('health', {}, 5_000);
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.

P1 Badge Use the correct RPC method in gateway-ready fallback probe

The new fallback probe calls this.rpc('health', {}, 5_000), but the Gateway client in this repo uses system.health as the health RPC (electron/gateway/client.ts), so this probe can consistently fail on runtimes that only implement the namespaced method. In the exact scenario this fallback is meant to cover (no gateway:ready event), repeated probe failures keep gatewayReady false indefinitely, which leaves Dreams and other gateway-gated UI/actions disabled even though the process is running.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4488dbff05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +237 to +238
if (refreshInFlightRef.current && !options?.force) {
return refreshInFlightRef.current;
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.

P2 Badge Prevent action refresh from reusing stale in-flight load

refreshAll() now returns the existing in-flight promise by default, so if a user runs a maintenance action while the initial Dreams load is still pending, the post-action await refreshAll() path reuses the pre-action request instead of fetching fresh state. In that startup/refresh overlap, the success toast is shown but diary/metrics can remain stale until a manual refresh. Please ensure post-mutation refreshes force a new fetch (or block actions while loading) so action results are reflected immediately.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08adb07d00

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2221 to +2224
const isConfiguredExternal = Boolean(pEntries[pluginId]);
const isInstalledExternal = installedExtensionIds.has(pluginId);
if (!isConfiguredExternal && !isInstalledExternal) {
console.log(`[sanitize] Removed missing external plugin from plugins.allow: ${pluginId}`);
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.

P1 Badge Preserve allowlisted plugins loaded from custom paths

The new plugins.allow pruning treats an external plugin as valid only when it has a plugins.entries[pluginId] block or a directory under ~/.openclaw/extensions, so plugins loaded via plugins.load.paths can now be removed as “missing” even when their path is valid. In setups that rely on path-loaded extensions with a restrictive allowlist, this sanitization will silently drop the allow entry and the plugin will be blocked on next Gateway start.

Useful? React with 👍 / 👎.

Comment on lines +420 to 422
onClick={() => void refreshAll({ force: true })}
disabled={!gatewayRunning}
className={QUIET_BUTTON_CLASS}
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.

P2 Badge Prevent overlapping forced Dreams refresh requests

This refresh button always triggers refreshAll({ force: true }) while remaining enabled during loading, which allows users to start multiple concurrent refresh RPCs. Because those requests resolve asynchronously and update the same state, an older request can finish after a newer one and overwrite the UI with stale diary/metrics data.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8c6368495

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +334 to +336
setDreaming((current) => ({ ...(current ?? {}), enabled }));
setLastActionMessage(message);
toast.success(message);
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.

P2 Badge Force a post-toggle Dreams refresh to avoid stale page state

After config.patch succeeds, the UI only flips dreaming.enabled locally and never re-reads doctor.memory.status / doctor.memory.dreamDiary. In the common case where enabling/disabling Dreams changes phase schedules, counts, or diary state asynchronously, users see a success toast but stale metrics and phase cards until they manually refresh. Triggering refreshAll({ force: true }) after a successful toggle would keep the native page consistent with Gateway state.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4596d2a4b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +683 to +686
const candidates = [
join(pluginPath, 'openclaw.plugin.json'),
join(dirname(pluginPath), 'openclaw.plugin.json'),
];
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.

P1 Badge Resolve loaded plugin manifests against config directory

The new allowlist-pruning path can silently drop valid external plugins when plugins.load/plugins.load.paths uses relative paths. readPluginManifestIdFromPath joins candidates directly from pluginPath, so relative values are resolved against the Electron process CWD instead of the OpenClaw config location; lookup then fails, discoverLoadedPluginIdsFromConfig misses the plugin ID, and the later plugins.allow cleanup removes it as “missing.” This breaks setups that rely on relative plugin load paths even though those paths are intentionally preserved elsewhere in sanitization.

Useful? React with 👍 / 👎.

@ashione ashione merged commit d47101a into main May 1, 2026
7 checks passed
@ashione ashione deleted the auto/dev-mode-dream branch May 1, 2026 07:26
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