Skip to content

[codex] Dreaming: surface memory wiki imports and palace#64505

Merged
mbelinky merged 5 commits into
mainfrom
codex/dreaming-memory-wiki-ui
Apr 11, 2026
Merged

[codex] Dreaming: surface memory wiki imports and palace#64505
mbelinky merged 5 commits into
mainfrom
codex/dreaming-memory-wiki-ui

Conversation

@mbelinky

Copy link
Copy Markdown
Contributor

What changed

This PR turns the Dreaming diary into the first usable memory-wiki observability surface.

It adds two new diary subtabs:

  • Imported Insights: topic-clustered imported ChatGPT chats, with synthesized summaries, candidate signals, correction signals, and click-through access to the full imported source page.
  • Memory Palace: a compiled view over wiki pages that actually contain claims, questions, contradictions, or real synthesis/entity/concept content.

It also replaces the dead sidebar path with an in-Dreaming full-page wiki viewer so imported sources and palace pages can be inspected directly from Dreaming.

Why

The previous import UI mostly surfaced metadata sludge and raw source titles. It did not give a useful view of what the system thought mattered, and the click-through path was effectively broken from Dreaming.

This gets us to a better intermediate state:

  • imports are visible as synthesized candidate material instead of just import logs
  • the raw source remains inspectable on demand
  • the memory palace view is honest about whether compiled memory pages actually exist

Current limitation

This PR does not implement automatic promotion from imported chats into synthesis/entity/concept pages.

On the current prod dataset, Memory Palace is still empty because the vault contains sources/ and reports/, but no real promoted syntheses/, entities/, or concepts/ pages yet. This PR surfaces that state cleanly; a later PR should add the consolidation writer that drafts and applies those pages.

Validation

Ran:

  • OPENCLAW_LOCAL_CHECK=0 pnpm test -- extensions/memory-wiki/src/import-insights.test.ts extensions/memory-wiki/src/memory-palace.test.ts extensions/memory-wiki/src/gateway.test.ts ui/src/ui/controllers/dreaming.test.ts ui/src/ui/views/dreaming.test.ts
  • OPENCLAW_LOCAL_CHECK=0 pnpm build
  • OPENCLAW_LOCAL_CHECK=0 pnpm ui:build

Also deployed the resulting bundle to jpclawhq prod and verified the new Dreaming asset hashes were live.

@mbelinky
mbelinky force-pushed the codex/dreaming-memory-wiki-ui branch from bc5ddf6 to 03d6946 Compare April 11, 2026 04:59
@mbelinky
mbelinky marked this pull request as ready for review April 11, 2026 05:01
@mbelinky
mbelinky force-pushed the codex/dreaming-memory-wiki-ui branch from 03d6946 to 12d5e37 Compare April 11, 2026 05:02
@aisle-research-bot

aisle-research-bot Bot commented Apr 11, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

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

# Severity Title
1 🟠 High Path traversal via unvalidated ChatGPT import runId allows arbitrary file read and rollback file write/delete
2 🟠 High Path traversal / arbitrary file read via untrusted digest pagePath in getMemoryWikiPage
3 🟡 Medium Unhandled RangeError in isoFromUnix allows malformed ChatGPT export timestamps to crash import (DoS)
4 🟡 Medium Unbounded wiki.get lineCount enables resource exhaustion (DoS) via large page parsing and response payloads
5 🟡 Medium Gateway method wiki.importRuns discloses local filesystem paths (exportPath/sourcePath/pagePaths) to operator.read clients
6 🟡 Medium Prototype pollution vector via YAML frontmatter parsing and object spread
1. 🟠 Path traversal via unvalidated ChatGPT import `runId` allows arbitrary file read and rollback file write/delete
Property Value
Severity High
CWE CWE-22
Location extensions/memory-wiki/src/chatgpt-import.ts:656-658

Description

rollbackChatGptImportRun reads an import-run record by interpolating the caller-supplied runId into a path joined under the .openclaw-wiki/import-runs directory.

  • runId is taken directly from the CLI argument (wiki chatgpt rollback <run-id>) and passed into readImportRunRecord without validation.
  • resolveImportRunPath uses path.join(importRunsDir, ${runId}.json). If runId contains ../ segments (or absolute paths), path.join will normalize the result and can escape the intended directory.
  • The parsed JSON record is then trusted to drive filesystem operations:
    • record.createdPaths entries are joined with vaultRoot and removed via fs.rm.
    • record.updatedPaths[].snapshotPath is joined with runDir and read.
    • record.updatedPaths[].path is joined with vaultRoot and written.

This means a crafted runId can cause arbitrary file read (read any *.json file reachable by traversal) and, if the attacker can point to a JSON file they control, can escalate to arbitrary file delete/write by supplying traversal payloads in createdPaths, updatedPaths[].path, and updatedPaths[].snapshotPath.

Vulnerable code:

function resolveImportRunPath(vaultRoot: string, runId: string): string {
  return path.join(resolveImportRunsDir(vaultRoot), `${runId}.json`);
}
...
const record = await readImportRunRecord(params.config.vault.path, params.runId);
...
await fs.rm(path.join(params.config.vault.path, relativePath), { force: true })
...
const snapshotPath = path.join(runDir, entry.snapshotPath);
const targetPath = path.join(params.config.vault.path, entry.path);

Recommendation

  1. Validate runId against a strict allowlist (it is generated as chatgpt- + 12 hex chars):
const RUN_ID_RE = /^chatgpt-[a-f0-9]{12}$/;
if (!RUN_ID_RE.test(runId)) {
  throw new Error("Invalid run id");
}
  1. Enforce directory containment when resolving paths (defense-in-depth). For example:
function safeJoin(baseDir: string, rel: string): string {
  const target = path.resolve(baseDir, rel);
  const base = path.resolve(baseDir) + path.sep;
  if (!target.startsWith(base)) throw new Error("Path traversal");
  return target;
}

function resolveImportRunPath(vaultRoot: string, runId: string): string {
  const dir = resolveImportRunsDir(vaultRoot);
  return safeJoin(dir, `${runId}.json`);
}
  1. When consuming the JSON record during rollback, validate and constrain createdPaths, updatedPaths[].path, and updatedPaths[].snapshotPath to ensure they cannot escape their intended directories (vault root / run dir).
2. 🟠 Path traversal / arbitrary file read via untrusted digest pagePath in getMemoryWikiPage
Property Value
Severity High
CWE CWE-22
Location extensions/memory-wiki/src/query.ts:119-129

Description

getMemoryWikiPage() allows a lookup of the form claim:<id> to resolve to a pagePath taken from the on-disk claims digest (.openclaw-wiki/cache/claims.jsonl). That pagePath is then passed into readQueryableWikiPagesByPaths(), which blindly path.join()s it with the vault root and reads it.

Because readQueryableWikiPagesByPaths() does not validate that the resulting path stays within the vault root, a malicious/poisoned digest entry with a pagePath such as ../../../../etc/passwd (or an absolute path) would cause the backend to read arbitrary files when a client requests wiki.get for that claim.

Vulnerable flow:

  • Input: RPC wiki.get lookup (attacker-controlled)
  • Pivot: claims.jsonl pagePath (untrusted file content)
  • Sink: fs.readFile(path.join(rootDir, relativePath)) without containment checks

Vulnerable code:

// getMemoryWikiPage
const digestClaimPagePath = digest ? resolveDigestClaimLookup(digest, params.lookup) : null;
...
await readQueryableWikiPagesByPaths(effectiveConfig.vault.path, [digestClaimPagePath])// readQueryableWikiPagesByPaths
const absolutePath = path.join(rootDir, relativePath);
const raw = await fs.readFile(absolutePath, "utf8");

Recommendation

Treat any path coming from digests (or any other non-hardcoded source) as untrusted, and enforce strict containment within the vault and expected subdirectories.

Suggested fix: resolve and validate before reading.

function resolveVaultPath(rootDir: string, rel: string): string {
  if (!rel || path.isAbsolute(rel)) throw new Error("invalid path");// normalize and prevent traversal
  const resolved = path.resolve(rootDir, rel);
  const normalizedRoot = rootDir.endsWith(path.sep) ? rootDir : rootDir + path.sep;
  if (!resolved.startsWith(normalizedRoot)) throw new Error("path escapes vault");
  return resolved;
}// in readQueryableWikiPagesByPaths
const absolutePath = resolveVaultPath(rootDir, relativePath);

Additionally, consider rejecting any digest pagePath that is not under one of the allowed QUERY_DIRS and not ending in .md.

3. 🟡 Unhandled RangeError in isoFromUnix allows malformed ChatGPT export timestamps to crash import (DoS)
Property Value
Severity Medium
CWE CWE-248
Location extensions/memory-wiki/src/chatgpt-import.ts:196-205

Description

isoFromUnix converts create_time / update_time values from a ChatGPT export into ISO strings via new Date(numeric * 1000).toISOString().

  • Number.isFinite(numeric) filters out NaN/Infinity, but does not prevent extremely large/small finite numbers.
  • For out-of-range timestamps, new Date(...) produces an Invalid Date, and toISOString() throws RangeError: Invalid time value.
  • This exception is not caught in toConversationRecord / importChatGptConversations; it occurs while mapping all conversations, so a single malformed conversation entry can abort the entire import run.

Vulnerable code:

const numeric = Number(raw);
if (!Number.isFinite(numeric)) {
  return undefined;
}
return new Date(numeric * 1000).toISOString();

This is reachable with an untrusted or corrupted conversations.json export (local file input), and results in a reliable import-time crash (denial of service).

Recommendation

Harden timestamp parsing by validating/clamping the supported range and/or catching RangeError from toISOString().

Example safe implementation:

function isoFromUnix(raw: unknown): string | undefined {
  if (typeof raw !== "number" && typeof raw !== "string") return undefined;
  const numeric = Number(raw);
  if (!Number.isFinite(numeric)) return undefined;// Optional: clamp to reasonable unix seconds range (e.g., 1970..2100)
  if (numeric < 0 || numeric > 4102444800) return undefined;

  const ms = numeric * 1000;
  const date = new Date(ms);
  try {
    return date.toISOString();
  } catch {
    return undefined;
  }
}

Also consider wrapping record parsing so one bad conversation cannot abort the whole import (skip and log).

4. 🟡 Unbounded wiki.get lineCount enables resource exhaustion (DoS) via large page parsing and response payloads
Property Value
Severity Medium
CWE CWE-400
Location extensions/memory-wiki/src/query.ts:694-717

Description

The wiki.get implementation allows callers to request arbitrarily large lineCount values and performs work proportional to the entire page size before slicing, enabling resource exhaustion.

  • Input: lineCount and fromLine are taken from gateway params and only normalized with Math.max(1, …) (no upper bound).
  • Work amplification: for wiki corpus pages, the code calls parseWikiMarkdown(page.raw) and then parsed.body.split(...), which processes the whole document regardless of lineCount.
  • Output amplification: the server returns slice.join("\n") up to lineCount lines. The UI now hard-codes lineCount: 5000 when opening a page, increasing default payload size.

An authenticated caller (scope operator.read) can repeatedly request very large lineCount values or target extremely large imported pages (e.g., transcripts) to consume CPU/memory and bandwidth on the gateway.

Recommendation

Enforce strict server-side limits and avoid parsing/splitting the entire document when only a window of lines is needed.

  1. Clamp lineCount (and fromLine) to a reasonable maximum:
const MAX_LINE_COUNT = 500; // or lower
const fromLine = Math.max(1, Math.floor(params.fromLine ?? 1));
const requested = Math.max(1, Math.floor(params.lineCount ?? 200));
const lineCount = Math.min(requested, MAX_LINE_COUNT);
  1. Consider early truncation strategies:
  • Store pre-split lines or an index in the compiled vault.
  • If operating on raw markdown, avoid full parseWikiMarkdown for windowed reads; stream/scan until you reach fromLine + lineCount.
  1. Add gateway validation (in gateway.ts) so abusive values are rejected before deeper processing, and optionally rate-limit wiki.get calls.
5. 🟡 Gateway method wiki.importRuns discloses local filesystem paths (exportPath/sourcePath/pagePaths) to operator.read clients
Property Value
Severity Medium
CWE CWE-200
Location extensions/memory-wiki/src/import-runs.ts:84-98

Description

The wiki.importRuns gateway method returns import-run metadata parsed from JSON files, including absolute local filesystem paths.

  • extensions/memory-wiki/src/gateway.ts registers wiki.importRuns with { scope: READ_SCOPE } (operator.read). Any client with read access can call it.
  • listMemoryWikiImportRuns() returns exportPath and sourcePath (likely absolute paths such as /Users/<name>/...) and pagePaths derived from created/updated file paths.
  • These values reveal sensitive host information (usernames, directory structure, vault layout, mounted volumes) that is not required for most UI display.

Vulnerable code:

return {
  runId,
  importType,
  appliedAt,
  exportPath,
  sourcePath,
  ...
  pagePaths,
  samplePaths: pagePaths.slice(0, 5),
};

If the gateway is reachable by any remote operator client (e.g., paired device/browser UI), this is an information disclosure risk.

Recommendation

Minimize/redact sensitive path data returned over the gateway:

  • Prefer returning relative paths (e.g., relative to the vault root) or just basenames.
  • Alternatively, omit exportPath/sourcePath entirely from the gateway response and keep them only in local logs.
  • If paths are needed for power users, guard them behind a stricter scope (e.g., operator.admin) or a dedicated capability flag.

Example (redact to basenames and make page paths vault-relative):

import path from "node:path";

function redactPath(p: string): string {
  return path.basename(p);
}// when building response
return {
  ...,
  exportPath: redactPath(exportPath),
  sourcePath: redactPath(sourcePath),
  pagePaths: pagePaths.map((p) => p.replace(/^.*?\/vault\//, "")),
};

(Use the actual vault-root prefix rather than the placeholder above.)

6. 🟡 Prototype pollution vector via YAML frontmatter parsing and object spread
Property Value
Severity Medium
CWE CWE-1321
Location extensions/memory-wiki/src/markdown.ts:77-89

Description

parseWikiMarkdown parses YAML frontmatter from wiki markdown using YAML.parse() and returns the resulting object directly. Other code later spreads this untrusted object into new objects.

If an attacker can place/modify markdown files in the vault (e.g., via import/sync), they can include YAML keys such as __proto__, constructor, or prototype to manipulate the prototype of the parsed frontmatter object and/or of objects created via spread.

Why this is risky:

  • YAML.parse() produces ordinary JS objects; assigning __proto__ can invoke the __proto__ setter on Object.prototype (engine-dependent), potentially changing the prototype of the target object (prototype pollution).
  • The code later does ...parsed.frontmatter in multiple places (e.g., apply.ts, compile.ts). If parsed.frontmatter contains poisoned keys, the resulting objects may have attacker-controlled prototypes/properties, which can lead to logic bypasses, crashes, or unexpected behavior when properties are read.

Vulnerable code:

const parsed = YAML.parse(match[1]) as unknown;
return {
  frontmatter:
    parsed && typeof parsed === "object" && !Array.isArray(parsed)
      ? (parsed as Record<string, unknown>)
      : {},
  body: content.slice(match[0].length),
};

And later usage (example):

frontmatter: {
  ...parsed.frontmatter,
  pageType: "synthesis",// ...
}

Recommendation

Harden frontmatter parsing by sanitizing keys and constructing frontmatter with a null prototype, or by whitelisting expected fields.

Example mitigation (key sanitization + null-prototype):

const UNSAFE_KEYS = new Set(["__proto__", "prototype", "constructor"]);

export function parseWikiMarkdown(content: string): ParsedWikiMarkdown {
  const match = content.match(FRONTMATTER_PATTERN);
  if (!match) return { frontmatter: Object.create(null), body: content };

  const parsed = YAML.parse(match[1]) as unknown;
  const frontmatter = Object.create(null) as Record<string, unknown>;

  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
    for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
      if (UNSAFE_KEYS.has(key)) continue;
      frontmatter[key] = value;
    }
  }

  return { frontmatter, body: content.slice(match[0].length) };
}

Additionally:

  • Consider validating frontmatter against a schema (e.g., zod) and only keeping known fields.
  • Avoid spreading untrusted objects (...parsed.frontmatter) into other objects unless sanitized first.

Analyzed PR: #64505 at commit 12d5e37

Last updated on: 2026-04-11T05:05:03Z

@mbelinky
mbelinky merged commit 64693d2 into main Apr 11, 2026
9 checks passed
@mbelinky
mbelinky deleted the codex/dreaming-memory-wiki-ui branch April 11, 2026 05:04
@mbelinky

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Thanks @mbelinky!

@greptile-apps

greptile-apps Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds two new Dreaming diary subtabs — Imported Insights (topic-clustered ChatGPT import pages with synthesized signals) and Memory Palace (compiled view of pages with claims/questions/contradictions) — plus an in-Dreaming full-page wiki viewer replacing the broken sidebar path. New backend modules (import-insights.ts, memory-palace.ts) and two new gateway methods (wiki.importInsights, wiki.palace) back the UI, with corresponding tests. All remaining findings are P2 style fixes.

Confidence Score: 5/5

Safe to merge; all findings are minor style issues with no impact on correctness or data integrity.

No P0/P1 issues. The three inline comments are all P2: duplicate array entries that are dead code, a trivially wrong ternary that still produces the right output, and a double function call that is inefficient but not incorrect. Logic, normalization, and gateway wiring are solid and well-tested.

No files require special attention.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/memory-wiki/src/import-insights.ts
Line: 214-223

Comment:
**Duplicate entries in `correctionPatterns`**

`"you're right"` and `"let's reset"` each appear twice in the array. Since `.some()` short-circuits on the first match, the second occurrence of each is dead code.

```suggestion
  const correctionPatterns = [
    "you're right",
    "bad assumption",
    "let's reset",
    "does not exist anymore",
    "that was a bad assumption",
    "what actually works today",
  ];
```

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

---

This is a comment left during a code review.
Path: ui/src/ui/controllers/dreaming.ts
Line: 442

Comment:
**Dead ternary — both branches return `"chatgpt"`**

`record?.sourceType === "chatgpt" ? "chatgpt" : "chatgpt"` always evaluates to `"chatgpt"`, so the condition is silently ignored. If the gateway ever sends an unexpected `sourceType` the value will still pass through unchecked.

```suggestion
    sourceType: "chatgpt",
```

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

---

This is a comment left during a code review.
Path: extensions/memory-wiki/src/memory-palace.ts
Line: 112

Comment:
**`extractSnippet` called twice**

`extractSnippet(parsed.body)` is called once for the truthiness check and again to produce the value, parsing the body string twice per page. A local variable avoids the redundant work.

Or more readably, hoist it before the spread:

```ts
const snippet = extractSnippet(parsed.body);
// …then in the object:
...(snippet ? { snippet } : {}),
```

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

Reviews (1): Last reviewed commit: "Changelog: add dreaming memory wiki entr..." | Re-trigger Greptile

Comment on lines +214 to +223
const correctionPatterns = [
"you're right",
"you’re right",
"bad assumption",
"let's reset",
"let’s reset",
"does not exist anymore",
"that was a bad assumption",
"what actually works today",
];

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 Duplicate entries in correctionPatterns

"you're right" and "let's reset" each appear twice in the array. Since .some() short-circuits on the first match, the second occurrence of each is dead code.

Suggested change
const correctionPatterns = [
"you're right",
"you’re right",
"bad assumption",
"let's reset",
"let’s reset",
"does not exist anymore",
"that was a bad assumption",
"what actually works today",
];
const correctionPatterns = [
"you're right",
"bad assumption",
"let's reset",
"does not exist anymore",
"that was a bad assumption",
"what actually works today",
];
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/memory-wiki/src/import-insights.ts
Line: 214-223

Comment:
**Duplicate entries in `correctionPatterns`**

`"you're right"` and `"let's reset"` each appear twice in the array. Since `.some()` short-circuits on the first match, the second occurrence of each is dead code.

```suggestion
  const correctionPatterns = [
    "you're right",
    "bad assumption",
    "let's reset",
    "does not exist anymore",
    "that was a bad assumption",
    "what actually works today",
  ];
```

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

.filter((entry): entry is WikiImportInsightCluster => entry !== null)
: [];
return {
sourceType: record?.sourceType === "chatgpt" ? "chatgpt" : "chatgpt",

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 Dead ternary — both branches return "chatgpt"

record?.sourceType === "chatgpt" ? "chatgpt" : "chatgpt" always evaluates to "chatgpt", so the condition is silently ignored. If the gateway ever sends an unexpected sourceType the value will still pass through unchecked.

Suggested change
sourceType: record?.sourceType === "chatgpt" ? "chatgpt" : "chatgpt",
sourceType: "chatgpt",
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/controllers/dreaming.ts
Line: 442

Comment:
**Dead ternary — both branches return `"chatgpt"`**

`record?.sourceType === "chatgpt" ? "chatgpt" : "chatgpt"` always evaluates to `"chatgpt"`, so the condition is silently ignored. If the gateway ever sends an unexpected `sourceType` the value will still pass through unchecked.

```suggestion
    sourceType: "chatgpt",
```

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

claims: page.claims.map((claim) => claim.text).slice(0, 3),
questions: page.questions.slice(0, 3),
contradictions: page.contradictions.slice(0, 3),
...(extractSnippet(parsed.body) ? { snippet: extractSnippet(parsed.body) } : {}),

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 extractSnippet called twice

extractSnippet(parsed.body) is called once for the truthiness check and again to produce the value, parsing the body string twice per page. A local variable avoids the redundant work.

Or more readably, hoist it before the spread:

const snippet = extractSnippet(parsed.body);
// …then in the object:
...(snippet ? { snippet } : {}),
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/memory-wiki/src/memory-palace.ts
Line: 112

Comment:
**`extractSnippet` called twice**

`extractSnippet(parsed.body)` is called once for the truthiness check and again to produce the value, parsing the body string twice per page. A local variable avoids the redundant work.

Or more readably, hoist it before the spread:

```ts
const snippet = extractSnippet(parsed.body);
// …then in the object:
...(snippet ? { snippet } : {}),
```

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 12d5e37222

ℹ️ 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 +1300 to +1304
if (diaryError) {
return html`
<section class="dreams-diary">
<div class="dreams-diary__error">${diaryError}</div>
</section>

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 Keep diary subtab controls visible on load errors

When the active diary subtab has an error (wikiImportInsightsError or wikiMemoryPalaceError), this early return renders only the error block and removes the subtab/header controls, so users cannot switch back to Dreams or trigger a tab-specific reload from the UI. A single transient gateway failure on Imported Insights/Memory Palace can therefore strand the Diary view in an unrecoverable state until a full app reload resets module state.

Useful? React with 👍 / 👎.

Comment thread ui/src/ui/app-render.ts
Comment on lines +431 to +435
void Promise.all([
loadDreamingStatus(state),
loadDreamDiary(state),
loadWikiImportInsights(state),
loadWikiMemoryPalace(state),

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 Avoid running two full wiki syncs on each Dreams refresh

This refresh path launches loadWikiImportInsights and loadWikiMemoryPalace in parallel, but both gateway methods (wiki.importInsights and wiki.palace) call syncImportedSourcesIfNeeded before responding. That means every Dreams refresh performs the same imported-source sync/index work twice, increasing latency and filesystem churn for users with larger vaults.

Useful? React with 👍 / 👎.

lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
)

Merged via squash.

Prepared head SHA: 12d5e37
Co-authored-by: mbelinky <[email protected]>
Co-authored-by: mbelinky <[email protected]>
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: 12d5e37
Co-authored-by: mbelinky <[email protected]>
Co-authored-by: mbelinky <[email protected]>
Reviewed-by: @mbelinky
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
)

Merged via squash.

Prepared head SHA: 12d5e37
Co-authored-by: mbelinky <[email protected]>
Co-authored-by: mbelinky <[email protected]>
Reviewed-by: @mbelinky
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
)

Merged via squash.

Prepared head SHA: 12d5e37
Co-authored-by: mbelinky <[email protected]>
Co-authored-by: mbelinky <[email protected]>
Reviewed-by: @mbelinky
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
)

Merged via squash.

Prepared head SHA: 12d5e37
Co-authored-by: mbelinky <[email protected]>
Co-authored-by: mbelinky <[email protected]>
Reviewed-by: @mbelinky
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant