Skip to content

fix(plugin): tolerate JSON5 comments when patching openclaw.json#1671

Open
Sanjays2402 wants to merge 2 commits intoMemTensor:mainfrom
Sanjays2402:fix/issue-1543
Open

fix(plugin): tolerate JSON5 comments when patching openclaw.json#1671
Sanjays2402 wants to merge 2 commits intoMemTensor:mainfrom
Sanjays2402:fix/issue-1543

Conversation

@Sanjays2402
Copy link
Copy Markdown

Summary

The MemOS plugin patcher for openclaw.json used JSON.parse, which rejects the JSON5 features (line/block comments, trailing commas) that openclaw.json legitimately uses. Any // comment in the file caused the warning observed in #1543:

memos-local: could not patch tools.allow: SyntaxError: Expected double-quoted property name in JSON at position 2222 (line 90 column 7)

…and left tools.allow un-patched, so group:plugins never made it into the user's config.

Fix

  • Adds a small parseJsonWithComments helper in apps/memos-local-openclaw/src/shared/json5-lite.ts that strips // line comments, /* */ block comments, and trailing commas (string-literal aware) before delegating to JSON.parse. ~90 LOC, no new runtime dependency.
  • Switches the openclaw.json read in the patcher (apps/memos-local-openclaw/index.ts) to use it.
  • Tweaks the patcher's writeback regex to accept the existing array's optional trailing comma (also legal JSON5), so that once the parse succeeds the textual edit still applies cleanly. The replacement always re-inserts a single comma so the output is normalised.

Comments are preserved on round-trip

The existing patcher already does a targeted regex replace on the original raw text rather than re-serialising via JSON.stringify, so the user's comments and formatting survive untouched. Verified end-to-end against the bug-report scenario:

{
  // OpenClaw configuration
  "tools": {
    "allow": [
      "task-cli",
      "summarizer",   // trailing comma was previously the second blocker
    ]
  },
}

Before: JSON.parse throws → could not patch tools.allow warning, no change written.
After: parse succeeds → group:plugins is appended → comments and trailing comma layout above the array remain intact.

Tests

Adds apps/memos-local-openclaw/tests/json5-lite.test.ts covering:

  • Plain JSON parses unchanged (regression).
  • // line comments are tolerated.
  • /* */ block comments are tolerated.
  • Trailing commas in arrays and objects are tolerated.
  • Comment-like sequences inside string literals are not stripped ("https://x/a//b", "/* not a comment */").
  • Escaped quotes inside strings are respected.
  • A realistic openclaw.json shape from the bug report parses correctly.
  • stripJsonComments preserves newlines so error-message line numbers stay aligned.

The tests follow the existing vitest style (e.g. tests/config.test.ts).

Scope

Deliberately tight: 3 files, +179 / −2. Only the openclaw.json read path and its companion writeback regex are touched. No other plugin behaviour changes.

Fixes #1543

The plugin's openclaw.json patcher used JSON.parse, which rejected the
JSON5 features (line/block comments, trailing commas) that openclaw.json
legitimately uses. With any '//' comment in the file the patch would
fail with a SyntaxError, leaving 'tools.allow' untouched and the user's
config unchanged (the warning observed in MemTensor#1543).

This change:

* Adds 'parseJsonWithComments' (under src/shared/json5-lite.ts), a
  small string-aware helper that strips line comments, block comments,
  and trailing commas before delegating to JSON.parse. No new runtime
  dependency.
* Switches the openclaw.json read in the patcher to use it.
* Tweaks the patcher's writeback regex to accept the existing array's
  optional trailing comma (also legal JSON5), so that even after the
  parse succeeds the textual edit still applies cleanly. The
  replacement always re-inserts a single comma, normalising output.

The writeback is a targeted regex edit against the original raw text,
not a full JSON re-serialisation, so any comments and original
formatting in the user's openclaw.json are preserved on round-trip.

Adds unit tests for the parser covering plain JSON, line/block
comments, trailing commas in arrays and objects, comment-like
sequences inside string literals, and escaped quotes.

Fixes MemTensor#1543
Copilot AI review requested due to automatic review settings May 9, 2026 19:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the memos-local OpenClaw plugin’s openclaw.json patcher to tolerate JSON5-style comments and trailing commas so it can reliably read and patch tools.allow (fixing the failure reported in #1543).

Changes:

  • Added a lightweight JSON5-tolerant preprocessor/parser (parseJsonWithComments) that strips line/block comments and trailing commas before delegating to JSON.parse.
  • Switched the patcher’s openclaw.json read path to use the new helper.
  • Adjusted the writeback regex to accept an optional trailing comma before the closing ].

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
apps/memos-local-openclaw/src/shared/json5-lite.ts Introduces a small comment/trailing-comma tolerant parsing shim used when reading openclaw.json.
apps/memos-local-openclaw/index.ts Uses the new parser for openclaw.json and broadens the patch regex to handle an optional trailing comma.
apps/memos-local-openclaw/tests/json5-lite.test.ts Adds unit tests covering comment/trailing-comma tolerance and basic string-literal safety cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/memos-local-openclaw/index.ts Outdated
Comment on lines 365 to 372
if (Array.isArray(allow) && allow.length > 0 && !allow.includes("group:plugins") && !allow.includes("*")) {
const lastEntry = JSON.stringify(allow[allow.length - 1]);
// Match the last entry + optional trailing comma (legal in JSON5)
// + closing `]`. The replacement always re-inserts a single comma.
const patched = raw.replace(
new RegExp(`(${lastEntry})(\\s*\\])`),
new RegExp(`(${lastEntry})\\s*,?(\\s*\\])`),
`$1,\n "group:plugins"$2`,
);
Comment thread apps/memos-local-openclaw/index.ts Outdated
Comment on lines 366 to 371
const lastEntry = JSON.stringify(allow[allow.length - 1]);
// Match the last entry + optional trailing comma (legal in JSON5)
// + closing `]`. The replacement always re-inserts a single comma.
const patched = raw.replace(
new RegExp(`(${lastEntry})(\\s*\\])`),
new RegExp(`(${lastEntry})\\s*,?(\\s*\\])`),
`$1,\n "group:plugins"$2`,
// Block comment: `/* … */`
if (ch === "/" && next === "*") {
i += 2;
while (i < n && !(text[i] === "*" && text[i + 1] === "/")) i += 1;
Comment on lines +87 to +91
// Strip trailing commas: `,` followed by optional whitespace and `]` or `}`.
// Run outside the per-char loop so it doesn't have to be string-aware itself
// (the prior pass already preserved string content).
return out.replace(/,(\s*[\]}])/g, "$1");
}
… preserve newlines in block comments

Address Copilot review on MemTensor#1671:
- index.ts: anchor the lastEntry-replacement regex to the tools.allow
  array span using brace/bracket matching, not the global file. This
  prevents accidental rewrites elsewhere in openclaw.json (e.g. when
  the same string is the last element of another array — the source
  of MemTensor#1377).
- index.ts: escape regex metacharacters in lastEntry before building
  the RegExp. Tool names with dots, parens, brackets etc. would have
  silently misbehaved.
- json5-lite.ts: rewrite as a single string-literal-aware state
  machine. Trailing-comma stripping no longer touches commas inside
  string values. Block comment stripping preserves the newline count
  so JSON.parse error line numbers continue to align with the source.
@Sanjays2402
Copy link
Copy Markdown
Author

Thanks — all four caught real issues, latest commit addresses them:

  • index.ts:372 (writeback scoping): Anchored the patch to the tools.allow array span using brace/bracket matching instead of a global text replace. This prevents the rewrite from straying into other arrays that happen to end with the same string — likely the root cause of fix: Title: memos-local-openclaw-plugin corrupts openclaw.json by inserting "group:plugins" into models[*].input #1377.
  • index.ts:371 (regex escaping): Added escapeRegExp and apply it to lastEntry before constructing the RegExp. Tool names containing ., +, ?, (, ), \\, etc. now behave correctly.
  • json5-lite.ts:78 (block-comment newlines): Block comments now emit one \n per newline they contained, so JSON.parse line numbers stay aligned with the source.
  • json5-lite.ts:91 (string-aware comma stripping): Refactored to a single string-literal-aware character scan. Trailing-comma stripping no longer touches commas inside string values.

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.

fix: MEMOS不支持JSON5格式的openclaw.json

2 participants