Skip to content

feat(ui): add dreaming diary controls and navigation#63298

Merged
mbelinky merged 2 commits intomainfrom
mariano/memory-diary-ui
Apr 8, 2026
Merged

feat(ui): add dreaming diary controls and navigation#63298
mbelinky merged 2 commits intomainfrom
mariano/memory-diary-ui

Conversation

@mbelinky
Copy link
Copy Markdown
Contributor

@mbelinky mbelinky commented Apr 8, 2026

Summary

  • Problem: the grounded diary/backfill lane was only inspectable via raw markdown and the existing Dreams UI made it hard to browse days, inspect grounded output, or trigger rebuild/reset flows.
  • Why it matters: we need a usable review surface before deciding which grounded candidate truths should feed the live dreaming evidence lane.
  • What changed: added diary navigation, three-column grounded diary presentation, scene-level backfill/reset controls, and the gateway doctor surface those controls need.
  • What did NOT change (scope boundary): this PR does not change grounded extraction logic and does not wire grounded candidates into live promotion.

Change Type (select all)

  • Feature
  • Bug fix
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • UI / DX
  • Memory / storage
  • Skills / tool execution
  • Auth / tokens
  • Integrations
  • API / contracts
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

  • Root cause: the backfill lane had no usable control surface or browseable diary presentation.
  • Missing detection / guardrail: we had no focused UI/controller tests for grounded diary actions and rendering.
  • Prior context (git blame, prior PR, issue, or refactor if known): UI follow-up on top of feat(memory): add grounded REM backfill lane #63273.
  • Why this regressed now: N/A
  • If unknown, what was ruled out: N/A

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server-methods/doctor.test.ts, ui/src/ui/controllers/dreaming.test.ts, ui/src/ui/views/dreaming.test.ts, ui/src/ui/navigation.browser.test.ts
  • Scenario the test should lock in: diary action RPCs, diary render layout/data, and browser navigation behavior.
  • Why this is the smallest reliable guardrail: these seams cover the full UI control loop without requiring a live gateway/browser E2E.
  • Existing test that already covers this (if any): N/A
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Dreams Diary gets a timeline/heatmap navigator and a three-column grounded layout.
  • Scene gets Backfill and Reset controls for the diary backfill lane.
  • grounded diary content is easier to inspect day by day.

Diagram (if applicable)

Before:
[user opens Dreams] -> [summary card + raw/weak diary inspection]

After:
[user opens Dreams] -> [timeline + heatmap + 3-column diary]
                     -> [Backfill / Reset controls]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) Yes
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) Yes
  • Data access scope changed? (Yes/No) Yes
  • If any Yes, explain risk + mitigation: the UI can now trigger grounded diary backfill/reset through the doctor gateway surface. The server-side actions remain workspace-local and marker-scoped; reset only removes backfilled diary entries.

Repro + Verification

Environment

  • OS: macOS authoring, mb-server for gates
  • Runtime/container: Node 22 / Vitest 4
  • Model/provider: N/A
  • Integration/channel (if any): Control UI / gateway doctor RPC
  • Relevant config (redacted): default memory workspace layout

Steps

  1. Open Dreams.
  2. Navigate the diary with the timeline/heatmap.
  3. Trigger Backfill and Reset from Scene.

Expected

  • diary renders in 3 columns with navigation
  • controls call the right gateway methods and reload state

Actual

  • Matches expected in focused UI/gateway tests.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: diary navigation/rendering, scene action control loop, doctor action endpoints.
  • Edge cases checked: loading state, navigation token warnings already covered by existing browser tests.
  • What you did not verify: manual screenshot attachment in this draft.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: UI and doctor action surface could drift from the grounded backfill lane if the CLI side changes later.
    • Mitigation: this PR is stacked directly on the backfill foundation PR and has focused controller/server tests for the action loop.

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 8, 2026

🔒 Aisle Security Analysis

We found 4 potential security issue(s) in this PR:

# Severity Title
1 🟠 High Sensitive memory snippets and absolute paths exposed via doctor.memory.status to READ-scope clients
2 🟠 High Symlink-following arbitrary file overwrite via DREAMS.md backfill/reset writes
3 🟠 High Symlink traversal enables arbitrary file read/write via dream diary backfill/reset
4 🟡 Medium Unbounded dream diary backfill can exhaust CPU/memory/disk (server-side DoS)
1. 🟠 Sensitive memory snippets and absolute paths exposed via `doctor.memory.status` to READ-scope clients
Property Value
Severity High
CWE CWE-200
Location src/gateway/server-methods/doctor.ts:396-418

Description

The doctor.memory.status handler now returns detailed lists of short-term memory store entries, including potentially sensitive snippet text and path values.

  • Input/source: loadDreamingStoreStats() reads the on-disk short-term memory store JSON and copies entry.snippet / entry.summary and entry.path into the response payload.
  • Exposure: doctor.memory.status is categorized under READ_SCOPE (see src/gateway/method-scopes.ts), so any client/token with read access can retrieve these details.
  • Impact: Memory snippets can contain PII/secrets (e.g., user preferences, names, travel details). Additionally, normalizeMemoryPath() does not strip absolute paths (it only normalizes slashes and removes leading ./), so if entry.path is absolute (or includes workspace prefixes), the response can leak filesystem layout.

Vulnerable code:

const snippet =
  normalizeTrimmedString(entry.snippet) ??
  normalizeTrimmedString(entry.summary) ??
  normalizeMemoryPath(entryPath);

const detail: DoctorMemoryDreamingEntryPayload = {
  key: entryKey,
  path: normalizeMemoryPath(entryPath),
  ...
  snippet,
};

This detail object is included in the doctor.memory.status response as dreaming.shortTermEntries, dreaming.signalEntries, and dreaming.promotedEntries.

Recommendation

Restrict or redact sensitive fields in doctor.memory.status.

Access control options

  • Move doctor.memory.status (or at least the entry lists) behind a stronger scope (e.g., ADMIN_SCOPE) or require an explicit privileged flag.
  • Alternatively, split into two methods: a low-privilege status endpoint (counts only) and a privileged endpoint for detailed entry inspection.

Data minimization/redaction

  • Do not return snippet by default. Return only counts + opaque IDs/keys.
  • If snippets are required for trusted admins, return a heavily redacted/preview form and ensure they cannot contain full raw memory text.

Path sanitization

  • Ensure returned paths are workspace-relative and never absolute. For example:
function toWorkspaceRelativePath(workspaceDir: string, entryPath: string): string {
  const rel = path.posix.normalize(entryPath.replaceAll("\\", "/"));
  const ws = workspaceDir.replaceAll("\\", "/");
  return rel.startsWith(ws + "/") ? rel.slice(ws.length + 1) : path.posix.basename(rel);
}

Also consider adding tests that an absolute entry.path does not leak in the API response.

2. 🟠 Symlink-following arbitrary file overwrite via DREAMS.md backfill/reset writes
Property Value
Severity High
CWE CWE-59
Location extensions/memory-core/src/dreaming-narrative.ts:275-315

Description

The new doctor endpoints call writeBackfillDiaryEntries / removeBackfillDiaryEntries, which write to a path resolved as ${workspaceDir}/DREAMS.md (or dreams.md). The implementation uses fs.writeFile() directly on that path without defending against symlinks.

If an attacker can create/replace DREAMS.md inside the workspace with a symlink to another file on the filesystem, triggering backfill/reset will overwrite the symlink target with attacker-influenced content.

  • Input/control: attacker-controlled workspace contents (ability to create DREAMS.md symlink) and the backfill/reset action.
  • Sink: fs.writeFile(dreamsPath, ...) follows symlinks.

Vulnerable code:

const dreamsPath = await resolveDreamsPath(params.workspaceDir);
...
await fs.writeFile(dreamsPath, updated, "utf-8");

Recommendation

Harden writes against symlink attacks and make updates atomic.

  • Open the file via a file descriptor with symlink-safe flags (platform permitting) and write through the fd.
  • Or write to a newly-created temp file in the same directory and rename() it into place, while verifying the target is a regular file.
  • Additionally, lstat() the target and refuse to write if it is a symlink.

Example (POSIX-focused) approach:

import { constants as fsConstants } from "node:fs";

const dreamsPath = await resolveDreamsPath(workspaceDir);
const st = await fs.lstat(dreamsPath).catch((e) => (e.code === "ENOENT" ? null : Promise.reject(e)));
if (st && !st.isFile()) throw new Error("Refusing to write non-regular DREAMS.md");
if (st && st.isSymbolicLink()) throw new Error("Refusing to follow symlink DREAMS.md");

const tmpPath = `${dreamsPath}.${process.pid}.tmp`;
await fs.writeFile(tmpPath, updated, { encoding: "utf-8", flag: "wx" });
await fs.rename(tmpPath, dreamsPath);

This prevents overwriting arbitrary symlink targets and reduces corruption risk from partial writes.

3. 🟠 Symlink traversal enables arbitrary file read/write via dream diary backfill/reset
Property Value
Severity High
CWE CWE-22
Location extensions/memory-core/src/rem-evidence.ts:1018-1054

Description

The dream diary backfill/reset flow follows symlinks within the workspace, allowing files outside workspaceDir to be read and/or overwritten.

Arbitrary file read (via previewGroundedRemMarkdown)

  • collectMarkdownFiles() uses fs.stat() (follows symlinks) and adds any resolved .md file.
  • previewGroundedRemMarkdown() then readFile()s those paths.
  • The gateway handler passes inputPaths built from workspaceDir/memory/*.md. If an attacker can place a symlink such as workspaceDir/memory/2026-02-19.md -> /etc/passwd (or any readable file), the code will read the target and include processed content in the preview/backfill output.

Arbitrary file write (via writeBackfillDiaryEntries / removeBackfillDiaryEntries)

  • resolveDreamsPath() constructs workspaceDir/DREAMS.md (or dreams.md) and later writeFile() is used.
  • If DREAMS.md is a symlink to an arbitrary path outside workspaceDir, backfill/reset will overwrite that external target.

Vulnerable code paths include:

// rem-evidence.ts
const stat = await fs.stat(resolved); // follows symlinks
...
const content = await fs.readFile(filePath, "utf-8");// dreaming-narrative.ts
const target = path.join(workspaceDir, name);
...
await fs.writeFile(dreamsPath, updated, "utf-8");

Recommendation

Constrain all reads/writes to real paths under workspaceDir and avoid following symlinks.

For reading input paths (backfill preview):

  • Use lstat() to detect symlinks and either skip them or resolve them safely.
  • Resolve realpath() and verify it is within workspaceDir before reading.

Example:

import fs from "node:fs/promises";
import path from "node:path";

async function assertInsideWorkspace(workspaceDir: string, candidate: string): Promise<string> {
  const wsReal = await fs.realpath(workspaceDir);
  const candReal = await fs.realpath(candidate);
  const rel = path.relative(wsReal, candReal);
  if (rel.startsWith("..") || path.isAbsolute(rel)) {
    throw new Error(`Path escapes workspace: ${candidate}`);
  }
  return candReal;
}

const st = await fs.lstat(resolved);
if (st.isSymbolicLink()) return; // or handle explicitly
const safePath = await assertInsideWorkspace(workspaceDir, resolved);
const content = await fs.readFile(safePath, "utf-8");

For writing DREAMS.md:

  • Before writing, lstat() the destination and refuse to write if it is a symlink.
  • Optionally, write to a temp file in the same directory and rename atomically.
const dreamsPath = await resolveDreamsPath(workspaceDir);
try {
  const st = await fs.lstat(dreamsPath);
  if (st.isSymbolicLink()) throw new Error("Refusing to write to symlinked DREAMS.md");
} catch (e) {
  if ((e as NodeJS.ErrnoException).code !== "ENOENT") throw e;
}
await fs.writeFile(dreamsPath, updated, "utf-8");
4. 🟡 Unbounded dream diary backfill can exhaust CPU/memory/disk (server-side DoS)
Property Value
Severity Medium
CWE CWE-400
Location src/gateway/server-methods/doctor.ts:847-878

Description

The doctor.memory.backfillDreamDiary handler performs an unbounded scan and render of all daily memory markdown files and then writes the rendered output into the dream diary, with no server-side limits.

  • listWorkspaceDailyFiles() enumerates every memory/YYYY-MM-DD.md file in the workspace.
  • The full list is passed to previewGroundedRemMarkdown(), which reads every file into memory and generates rendered markdown.
  • The rendered markdown is split/filtered and then persisted via writeBackfillDiaryEntries(), potentially creating very large output and repeatedly rewriting the dreams file.
  • The only apparent guard against repeated triggering is dreamDiaryActionLoading in the UI (client-side), which does not protect the server from repeated requests (e.g., via automation or another client).

Vulnerable code:

const sourceFiles = await listWorkspaceDailyFiles(memoryDir);
const grounded = await previewGroundedRemMarkdown({
  workspaceDir,
  inputPaths: sourceFiles,
});
...
const written = await writeBackfillDiaryEntries({
  workspaceDir,
  entries,
  timezone: remConfig.timezone,
});

Recommendation

Add server-side controls to cap work and prevent repeated expensive scans.

Suggested hardening (combine as appropriate):

  1. Limit number of files and/or date range processed per request.
const MAX_BACKFILL_FILES = 365; // or configurable
const sourceFilesAll = await listWorkspaceDailyFiles(memoryDir);
const sourceFiles = sourceFilesAll.slice(-MAX_BACKFILL_FILES);
  1. Enforce file size limits before reading/rendering.
const stat = await fs.stat(filePath);
if (stat.size > MAX_MD_BYTES) continue;
  1. Rate limit / lock the action server-side (per-workspace), so concurrent/repeated calls cannot overlap.

  2. Consider making the endpoint require an explicit, validated start/end parameter (or “last N days”) instead of scanning everything.

These measures reduce the risk of CPU/memory spikes and uncontrolled disk growth from large workspaces or repeated calls.


Analyzed PR: #63298 at commit 0a2ae66

Last updated on: 2026-04-08T18:36:05Z

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: XL maintainer Maintainer-authored PR labels Apr 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR adds grounded diary navigation and controls to the Dreams UI: a timeline/heatmap navigator, three-column structured diary layout, scene-level Backfill/Reset buttons, and the two new doctor.memory.backfillDreamDiary / doctor.memory.resetDreamDiary gateway handlers that power them. The scope is well-contained — grounded extraction logic and live promotion are explicitly not changed.

The only finding is a P2 style issue: doctor.test.ts mocks the private internal module paths (src/rem-evidence.js, src/dreaming-narrative.js) rather than the public api.js barrel that doctor.ts now imports from. This is noted inline.

Confidence Score: 5/5

Safe to merge — all findings are P2 style/boundary concerns with no functional impact.

The only finding is a test mock path that targets private extension internals instead of the public api.js barrel. This violates the repo boundary rule and should be fixed, but it does not affect runtime correctness or test reliability today since api.ts is a pure re-export. All other logic — gateway handlers, controller actions, diary parsing, navigation rendering — is correct and well-tested.

src/gateway/server-methods/doctor.test.ts — mock paths should be updated to target api.js.

Vulnerabilities

No security concerns identified. The new backfill and reset gateway methods operate on workspace-local diary files only, are not exposed to untrusted input, and do not introduce new auth surfaces or secrets handling.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/doctor.test.ts
Line: 39-46

Comment:
**Test mocks bypass the declared `api.js` boundary**

The tests mock the private internal modules `src/rem-evidence.js` and `src/dreaming-narrative.js`, but `doctor.ts` (updated in the second commit of this PR) now imports from `../../../extensions/memory-core/api.js`. Per the CLAUDE.md rule, "core tests must not deep-import bundled plugin internals such as a plugin's `src/**` files."

The tests still pass today only because `api.ts` is a pure re-export barrel. If the barrel ever adds wrapping, caching, or transformation, the mocks will silently continue targeting the wrong module. The mock paths should point to `../../../extensions/memory-core/api.js`:

```ts
vi.mock("../../../extensions/memory-core/api.js", () => ({
  previewGroundedRemMarkdown,
  writeBackfillDiaryEntries,
  removeBackfillDiaryEntries,
}));
```

**Context Used:** CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "ui: consume grounded diary helpers via m..." | Re-trigger Greptile

Comment on lines +39 to +46
vi.mock("../../../extensions/memory-core/src/rem-evidence.js", () => ({
previewGroundedRemMarkdown,
}));

vi.mock("../../../extensions/memory-core/src/dreaming-narrative.js", () => ({
writeBackfillDiaryEntries,
removeBackfillDiaryEntries,
}));
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 Test mocks bypass the declared api.js boundary

The tests mock the private internal modules src/rem-evidence.js and src/dreaming-narrative.js, but doctor.ts (updated in the second commit of this PR) now imports from ../../../extensions/memory-core/api.js. Per the CLAUDE.md rule, "core tests must not deep-import bundled plugin internals such as a plugin's src/** files."

The tests still pass today only because api.ts is a pure re-export barrel. If the barrel ever adds wrapping, caching, or transformation, the mocks will silently continue targeting the wrong module. The mock paths should point to ../../../extensions/memory-core/api.js:

vi.mock("../../../extensions/memory-core/api.js", () => ({
  previewGroundedRemMarkdown,
  writeBackfillDiaryEntries,
  removeBackfillDiaryEntries,
}));

Context Used: CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/doctor.test.ts
Line: 39-46

Comment:
**Test mocks bypass the declared `api.js` boundary**

The tests mock the private internal modules `src/rem-evidence.js` and `src/dreaming-narrative.js`, but `doctor.ts` (updated in the second commit of this PR) now imports from `../../../extensions/memory-core/api.js`. Per the CLAUDE.md rule, "core tests must not deep-import bundled plugin internals such as a plugin's `src/**` files."

The tests still pass today only because `api.ts` is a pure re-export barrel. If the barrel ever adds wrapping, caching, or transformation, the mocks will silently continue targeting the wrong module. The mock paths should point to `../../../extensions/memory-core/api.js`:

```ts
vi.mock("../../../extensions/memory-core/api.js", () => ({
  previewGroundedRemMarkdown,
  writeBackfillDiaryEntries,
  removeBackfillDiaryEntries,
}));
```

**Context Used:** CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@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: e8de688b95

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +140 to +143
return markdown
.split("\n")
.map((line) => line.trimEnd())
.filter((line, index, lines) => line.length > 0 || (index > 0 && lines[index - 1]?.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.

P1 Badge Normalize grounded diary headings before persisting entries

This helper writes grounded markdown lines verbatim, but previewGroundedRemMarkdown emits section headers like ## What Happened. The Dreams UI parser drops #-prefixed lines, so real backfilled entries lose their section markers and never render in the new structured three-panel layout. The CLI backfill path already normalizes these headings; this server method should do the same to keep diary rendering consistent.

Useful? React with 👍 / 👎.

Comment on lines +39 to +43
vi.mock("../../../extensions/memory-core/src/rem-evidence.js", () => ({
previewGroundedRemMarkdown,
}));

vi.mock("../../../extensions/memory-core/src/dreaming-narrative.js", () => ({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Mock memory-core through its public API seam

AGENTS.md (repo root) says core code/tests must not deep-import bundled plugin internals (src/**). This new mock block targets extensions/memory-core/src/... directly, coupling gateway tests to private plugin file layout and making unrelated plugin refactors break core tests. Mock the public extensions/memory-core/api.js surface instead.

Useful? React with 👍 / 👎.

@mbelinky mbelinky force-pushed the mariano/memory-diary-ui branch from e8de688 to 0a2ae66 Compare April 8, 2026 18:34
@mbelinky mbelinky merged commit 66b8248 into main Apr 8, 2026
7 checks passed
@mbelinky mbelinky deleted the mariano/memory-diary-ui branch April 8, 2026 18:34
@mbelinky
Copy link
Copy Markdown
Contributor Author

mbelinky commented Apr 8, 2026

Merged via squash.

Thanks @mbelinky!

Copy link
Copy Markdown

@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: 0a2ae66913

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +874 to +877
const written = await writeBackfillDiaryEntries({
workspaceDir,
entries,
timezone: remConfig.timezone,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Skip backfill write when no source memory files

doctor.memory.backfillDreamDiary always proceeds to writeBackfillDiaryEntries even if listWorkspaceDailyFiles returns no daily files, so entries can be empty here. writeBackfillDiaryEntries strips existing backfill blocks before rewriting, which means clicking Backfill with an empty/missing memory/ directory can silently delete previously backfilled diary entries instead of no-oping or reporting an error. Add an explicit empty-source guard before writing.

Useful? React with 👍 / 👎.

eleqtrizit pushed a commit that referenced this pull request Apr 8, 2026
Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
greidron added a commit to greidron/openclaw that referenced this pull request Apr 10, 2026
* release: mirror bundled channel deps at root (openclaw#63065)

Merged via squash.

Prepared head SHA: ac26799
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Reviewed-by: @scoootscooob

* fix(test): keep warn log capture under openclaw temp dir

* revert: undo background alive review findings fix

* feat: add qa character vibes eval

* test: stabilize plugin boundary invariants

* test: isolate agent gateway cli command mocks

* test: skip duplicate package boundary wrapper in ci

* test: fix postpublish verifier sidecar handling

* test: keep status tests off live usage probes

* auto-reply: type status auth overrides

* plugins: read contract inventory from manifests

* test: inline cli metadata channel fixture

* ci: skip duplicate full extension shard

* test: isolate discord directory live token env

* test: keep followup runner memory mock complete

* ci: split parallel full suite into leaf shards

* test: guard loader fixtures against broad sdk imports

* test: keep bundled channel entry smokes descriptor-only

* ci: reduce full suite test parallelism

* test: avoid bundled test api smokes in matrix and telegram

* test: keep discord and irc entry smokes descriptor-only

* test: keep web provider artifact coverage manifest-only

* test: keep provider policy artifact coverage narrow

* test: keep web provider artifact test in boundary

* test: keep status message tests off auth auto-detection

* status: avoid plugin lookup for direct channel model overrides

* channels: fast-path direct model override matches

* test: restore manifest-only web provider coverage

* fix: allow blank TLS manual port default (openclaw#63134) (thanks @Tyler-RNG)

* make port optional for TLS manual connections

* fix: restrict manual blank-port fallback to tls

* fix: allow blank TLS manual port default (openclaw#63134) (thanks @Tyler-RNG)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>

* test: fix full suite CI test isolation

* fix: align LLM idle timeout policy

* test: exercise models json file mode without provider discovery

* test: keep shared dm policy contract off channel facades

* test: keep web provider artifact test in boundary

* test: keep kilocode provider tests on plugin-owned helpers

* ci: restore sequential full suite tests

* test: keep public artifact coverage on cheap boundaries

* test: keep openclaw tools registration tests on a fast shell

* test: keep bundled metadata sidecar scan inventory-only

* docs(inferrs): fix Gemma model id from gg-hf-gg to google (openclaw#62586)

* fix: harden bundled plugin dependency release checks

* ci: isolate full suite leaf shards

* test: keep openclaw tools registration policy pure

* fix: support Codex CLI QA auth

* feat: add QA character eval reports

* docs: document QA character eval workflow

* refactor: dedupe media generation tool helpers

* refactor: dedupe internal helper glue

* refactor: dedupe shared helper branches

* refactor: dedupe browser navigation guard tests

* refactor: dedupe config and subagent tests

* refactor: dedupe test helpers and script warning filter

* refactor: dedupe plugin test harnesses

* refactor: dedupe media runtime test mocks

* refactor: dedupe plugin metadata test helpers

* refactor: dedupe firecrawl and directive helpers

* refactor: dedupe exec defaults tests

* refactor: dedupe approval runtime tests

* refactor: dedupe matrix exec approval tests

* refactor: dedupe telegram exec approval tests

* refactor: dedupe doctor codex oauth tests

* refactor: dedupe agent command test fixtures

* refactor: dedupe embedding provider test fixtures

* refactor: share html entity tool call decoding

* fix: keep minimax provider mocks package-local

* test: keep pdf and update-plan registration tests pure

* test: keep model reasoning override coverage on merge helpers

* fix: default OpenAI reasoning effort to high

* test: keep kimi implicit provider tests on provider catalog

* fix(build): prune stale bundled plugin node_modules

* fix(build): address bundled plugin prune review

* fix(build): honor postinstall disable flag

* test: keep chutes implicit provider tests on provider catalog

* fix(plugin-sdk): export channel plugin base

* docs: reorder changelog entries

* test: keep bundled web-search owner checks on public artifacts

* fix(build): keep tsdown prune best-effort

* test: trust gateway exec fixture node path

* fix: keep runtime task test harness behind task seams

* test: explain gateway exec fixture trust

* Reply: surface OAuth reauth failures (openclaw#63217)

Merged via squash.

Prepared head SHA: 68b7ffd
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* test: make character eval scenario natural

* feat: add character eval model options

* test: keep pi fs workspace tests on fs tool factories

* test: keep media runtime tests on same-directory provider mocks

* fix(android): auto-resume pairing approval

* fix(android): prefer bootstrap auth on qr pairing

* fix(android): reset auth on new setup codes

* fix(android): tighten pairing retry behavior

* fix(android): prefer stored device auth after pairing

* fix: restore android qr pairing flow (openclaw#63199)

* fix(auto-reply): strip leading NO_REPLY tokens to prevent silent-reply leak (openclaw#63068)

* fix(auto-reply): strip leading NO_REPLY tokens to prevent silent-reply leak

* fix(auto-reply): preserve substantive NO_REPLY leading text

* fix(agents): preserve ACP silent-prefix cumulative deltas

* fix(auto-reply): harden silent-token streaming paths

* fix(auto-reply): normalize glued silent tokens consistently

---------

Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>

* fix(gateway): clear auto-fallback model override on session reset (openclaw#63155)

* fix(gateway): clear auto-fallback model override on session reset

When `persistFallbackCandidateSelection()` writes a fallback provider
override with `authProfileOverrideSource: "auto"`, the override was
incorrectly preserved across `/reset` and `/new` commands. This caused
sessions to keep using the fallback provider even after the user changed
the agent config primary provider, because the session store override
takes precedence over the config default.

Now the override fields (`providerOverride`, `modelOverride`,
`authProfileOverride`, `authProfileOverrideSource`,
`authProfileOverrideCompactionCount`) are only carried forward when
`authProfileOverrideSource === "user"` (i.e. explicit `/model` command).
System-driven overrides are dropped on reset so the session picks up the
current config default.

Introduced in cb0a752 ("fix: preserve reset session behavior config")

* fix(gateway): preserve explicit reset model selection

* fix(gateway): track reset model override source

* fix(gateway): preserve legacy reset model overrides

* docs(changelog): add session reset merge note

---------

Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>

* test: stabilize ci test isolation

* test: isolate volcengine byteplus auth resolver imports

* fix: patch hono security advisories

* fix: pass system prompt to codex cli

* fix(plugins): prevent untrusted workspace plugins from hijacking bundled provider auth choices [AI] (openclaw#62368)

* fix: address issue

* fix: address review feedback

* docs(changelog): add onboarding auth-choice guard entry

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address PR review feedback

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: isolate provider runtime test mocks

* feat(plugins): support provider auth aliases

* feat(memory): add grounded REM backfill lane (openclaw#63273)

Merged via squash.

Prepared head SHA: 4450f25
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* feat(memory): harden grounded REM extraction (openclaw#63297)

Merged via squash.

Prepared head SHA: e188b7e
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* feat(ui): add dreaming diary controls and navigation (openclaw#63298)

Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* chore(ui): refresh zh-TW control ui locale

* chore(ui): refresh zh-CN control ui locale

* chore(ui): refresh pt-BR control ui locale

* chore(ui): refresh de control ui locale

* chore(ui): refresh es control ui locale

* chore(ui): refresh ko control ui locale

* chore(ui): refresh ja-JP control ui locale

* chore(ui): refresh fr control ui locale

* docs(matrix): tighten setup and config guidance

* chore(ui): refresh tr control ui locale

* chore(ui): refresh uk control ui locale

* chore(ui): refresh pl control ui locale

* chore(ui): refresh id control ui locale

* test: stabilize full-suite execution

* fix(matrix): contain sync outage failures (openclaw#62779)

Merged via squash.

Prepared head SHA: 901bb76
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* Align remote node exec event system messages with untrusted handling (openclaw#62659)

* fix(nodes): downgrade remote exec system events

* docs(changelog): add remote node exec event entry

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: reuse image generate tool imports

* test: reuse followup runner imports

* docs(config): tighten wording in reference

* test: harden provider mock isolation

* fix(memory): accept embedded dreaming heartbeat tokens

* test: harden Parallels macOS smoke fallback

* build: narrow plugin SDK declaration build

* fix(dotenv): block workspace runtime env vars (openclaw#62660)

* fix(dotenv): block workspace runtime env vars

Co-authored-by: zsx <git@zsxsoft.com>

* docs(changelog): add workspace dotenv runtime-control entry

* fix(dotenv): block workspace gateway port override

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>

* build: stage nostr runtime dependencies

* fix: load QA live provider overrides

* feat: parallelize character eval runs

* auth: avoid external cli sync on profile upsert

* test(doctor): mock memory-core runtime seam

* auth: persist explicit profile upserts directly

* Matrix: report startup failures as errors

* fix(browser): harden browser control override loading (openclaw#62663)

* fix(browser): harden browser control overrides

* fix(lint): prepare boundary artifacts for extension oxlint

* docs(changelog): add browser override hardening entry

* fix(lint): avoid duplicate boundary prep

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
Co-authored-by: Devin Robison <drobison00@users.noreply.github.com>

* test: reuse exec directive reply imports

* test: reuse verbose directive reply imports

* fix(browser): re-check interaction-driven navigations (openclaw#63226)

* fix(browser): guard interaction-driven navigations

* fix(browser): avoid rechecking unchanged interaction urls

* fix(browser): guard delayed interaction navigations

* fix(browser): guard interaction-driven navigations for full action duration

* fix(browser): avoid waiting on interaction grace timer

* fix(browser): ignore same-document hash-only URL changes in navigation guard

* fix(browser): dedupe interaction nav guards

* fix(browser): guard same-URL reloads in interaction navigation listeners

* docs(changelog): add interaction navigation guard entry

* fix(browser): drop duplicate ssrfPolicy props

* fix(browser): tighten interaction navigation guards

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>

* test: move directive state coverage to pure tests

* fix: enable thinking support for the ollama api (openclaw#62712)

Merged via squash.

Prepared head SHA: c0b9950
Co-authored-by: hoyyeva <63033505+hoyyeva@users.noreply.github.com>
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Reviewed-by: @BruceMacD

* Slack: treat ACP block text as visible output (openclaw#62858)

Merged via squash.

Prepared head SHA: 14f202e
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* fix: fail fast on qa live auth errors

* fix: fail fast across qa scenario wait paths

* test: cover qa scenario wait failure replies

* fix: sanitize qa missing-key replies

* test: cover sanitized qa missing-key replies

* fix: align qa wait cursor semantics

* test: cover mixed-traffic qa wait cursors

* fix: classify curated qa missing-key replies

* test: cover curated qa missing-key reply classification

* fix: harden qa missing-key provider messages

* test: cover unsafe qa missing-key providers

* docs(changelog): add qa auth fail-fast entry (openclaw#63333) (thanks @shakkernerd)

* fix(matrix/doctor): migrate legacy channels.matrix.dm.policy 'trusted' (fixes openclaw#62931) (openclaw#62942)

Merged via squash.

Prepared head SHA: d9f553b
Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* Memory/dreaming: feed grounded backfill into short-term promotion (openclaw#63370)

Merged via squash.

Prepared head SHA: 5dfe246
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* docs: update unreleased changelog

* fix(gateway): classify dream diary actions

* fix(memory): align dreaming status payloads

* Memory/dreaming: harden grounded backfill follow-ups

* test: reuse inline directive reply imports

* Docs/memory: explain grounded backfill flows

* fix(deps): patch basic-ftp advisory

* test: move inline directive collisions to pure tests

* Slack: dedupe partial streaming replies (openclaw#62859)

Merged via squash.

Prepared head SHA: cbecb50
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras

* test: replace exec directive e2e with pure coverage

* fix(plugins): keep test helpers out of contract barrels (openclaw#63311)

Merged via squash.

Prepared head SHA: 769e90c
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf

* test: move cron heartbeat delivery coverage below full turns

* fix: inter-session messages must not overwrite established external lastRoute (openclaw#58013)

Merged via squash.

Prepared head SHA: 820ea20
Co-authored-by: duqaXxX <12242811+duqaXxX@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* fix(gateway): suppress announce/reply skip chat leakage (openclaw#51739)

Merged via squash.

Prepared head SHA: 2f53f3b
Co-authored-by: Pinghuachiu <9033138+Pinghuachiu@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman

* Slack: key turn-local dedupe by dispatch kind

Scope Slack turn-local delivery dedupe by reply dispatch kind so identical tool and final payloads on the same thread do not collapse into one send.

Expose the existing dispatcher kind on the public reply-runtime seam and cover the Slack tracker and preview-fallback paths with regression tests.

* Dreaming: surface grounded scene lane (openclaw#63395)

Merged via squash.

Prepared head SHA: 0c7f586
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky

* test: avoid runtime auth overlays in failure-state coverage

* fix(ci): align ollama thinking expectations

* chore(ui): refresh zh-CN control ui locale

* chore(ui): refresh pt-BR control ui locale

* chore(ui): refresh zh-TW control ui locale

* chore(ui): refresh de control ui locale

* test(docker): reduce e2e log noise

* chore(ui): refresh es control ui locale

* chore(ui): refresh fr control ui locale

* chore(ui): refresh ja-JP control ui locale

* chore(ui): refresh ko control ui locale

* chore(ui): refresh uk control ui locale

* chore(ui): refresh id control ui locale

* chore(ui): refresh pl control ui locale

* chore(ui): refresh tr control ui locale

* fix: restore main ci

* fix(ci): drop silent history before truncation

* docs: reorder unreleased changelog

* test(docker): quiet success-path e2e logs

* style: sort session import

* build: mirror bundled plugin runtime deps

* plugins: load lightweight provider discovery entries

* ci: narrow Windows node test lane

* fix: filter provider auth aliases by plugin trust

* fix: surface delayed browser navigation blocks

* style: format memory and gateway touchups

* Delete docs/plans directory

Unused artifact

* test: avoid remote ollama timeout in api-key preservation coverage

* test: keep auth-choice default-model coverage on lightweight provider

* test: keep undefined-token auth-choice coverage generic

* fix: stabilize character eval and Qwen model routing

* test: keep agent command tests off external auth overlays

* fix openrouter model picker refs (openclaw#63416)

* fix openrouter model picker refs

Signed-off-by: sallyom <somalley@redhat.com>

* test(ui): cover openrouter slash-id /model resolution

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Vignesh Natarajan <vignesh.natarajan92@gmail.com>

* ci: stabilize macOS and transcript policy tests

* test: keep cli-provider agent command tests off external auth overlays

* chore(lint): clear extension lint regressions and add openclaw#63416 changelog

* test: update modelstudio catalog contract sentinel

* test: update character eval public panel

* fix: repair Windows dev-channel updater

* test: move copilot models-json injection coverage to plan tests

* plugin-sdk: split command status surface

* plugin-sdk: keep command status compatibility path light

* plugin-sdk: drop investigative weixin repro harness

* tests: document config mock choice for eager warmup

* fix: update command-status SDK baseline (openclaw#63174) (thanks @hxy91819)

* test: cap broad live model sweeps

* fix: drop raw gateway chat control replies

* test: make shared-token reload deterministic

* test: isolate agentic suite smoke tests

* test: replace models-config matrix with narrow coverage

* test: isolate onboard skills status mock

* plugins: add lightweight anthropic vertex discovery

* test: isolate model auth module state

* test: isolate subagent registry resume imports

* plugins: keep google provider policy lightweight

* test: keep ollama unreachable discovery on localhost

* test: mock auth profile external overlay in oauth tests

* auth: avoid plugin setup scans during common auth resolution

* fix(logging): break console/logger type cycle

* fix(config): stop owner-display barrel cycles

* fix(commands): split auth choice apply types

* fix(infra): extract exec approvals allowlist types

* fix(commands): split doctor prompt option types

* chore: prepare 2026.4.9-beta.1 release

* chore: refresh config schema version for 2026.4.9-beta.1

* chore: refresh plugin SDK API baseline

* test: run local full suite project shards in parallel

* wizard: add explicit skip option to plugin setup (openclaw#63436)

* Wizard: allow skipping plugin setup

* Agents: reset nodes tool test modules

* tests: reset discord native-command seams in model picker (openclaw#63267)

* ci: tolerate noisy npm pack json output

* test: isolate slack thread-ts recovery

* fix(msteams): isolate channel thread sessions by replyToId (openclaw#58615) (openclaw#62713)

* fix(msteams): isolate thread sessions by replyToId (openclaw#58615)

* fix(msteams): align thread ID extraction + fix test types

* fix(msteams): route thread replies to correct thread via replyToId (openclaw#58030) (openclaw#62715)

* fix(msteams): pin reply target at inbound time to prevent DM/channel leak (openclaw#54520) (openclaw#62716)

* test: keep local full suite serial by default

* chore: prepare 2026.4.9 stable release

* Agents: guard legacy pi transport override

* Agents: restore upstream pi runner sources

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: scoootscooob <zhentongfan@gmail.com>
Co-authored-by: scoootscooob <167050519+scoootscooob@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Nimrod Gutman <nimrod.gutman@gmail.com>
Co-authored-by: Tyler Warburton <Ethan.gold-Steinberg@protonmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Eric Curtin <eric.curtin@docker.com>
Co-authored-by: Mariano <mbelinky@gmail.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: Frank Yang <frank.ekn@gmail.com>
Co-authored-by: termtek <termtek@ubuntu.tail2b72cd.ts.net>
Co-authored-by: Pavan Kumar Gondhi <pgondhi@nvidia.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gustavo Madeira Santana <gumadeiras@gmail.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: Agustin Rivera <31522568+eleqtrizit@users.noreply.github.com>
Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison00@users.noreply.github.com>
Co-authored-by: Eva H <63033505+hoyyeva@users.noreply.github.com>
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Co-authored-by: Shakker <shakkerdroid@gmail.com>
Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: Altay <altay@uinaf.dev>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Co-authored-by: Accunza <12242811+duqaXxX@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: Pinghuachiu <9033138+Pinghuachiu@users.noreply.github.com>
Co-authored-by: Radek Sienkiewicz <mail@velvetshark.com>
Co-authored-by: Sally O'Malley <somalley@redhat.com>
Co-authored-by: Vignesh Natarajan <vignesh.natarajan92@gmail.com>
Co-authored-by: Mason Huang <masonxhuang@tencent.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: pashpashpash <nik@vault77.ai>
Co-authored-by: sudie-codes <suvenkat95@gmail.com>
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request Apr 27, 2026
Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Merged via squash.

Prepared head SHA: 0a2ae66
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant