larksuite / larksuite/cli

docs +update --command str_replace parses Markdown inline syntax under --doc-format xml, unlike every other write path

Open
#2,405 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug domain/core domain/doc
Dominant language
Go
Stars
17.3k
Forks
1.4k
Avg merge
2d 4h
Merged PRs (30d)
105

Description

Bug Description

Under --doc-format xml (the default), docs +update --command str_replace interprets its --content as Lark-flavored Markdown: **text** is stored as a <b> node and `text` as a <code> node.

Every other write path using the very same --doc-format xmldocs +create, and docs +update with append, block_insert_after, block_replace — keeps those exact characters as literal text.

So the same flag value produces two opposite contracts depending on --command, and nothing in the CLI surface says so. --dry-run shows the CLI forwards --content verbatim with "format": "xml", so the divergence lives in how the str_replace command path processes the payload.

Environment

  • lark-cli version: 1.0.87
  • Installation method: npm i -g @larksuite/cli
  • OS: macOS
  • Identity: --as user

Reproduction

Placeholders below: <doc_token> is the created document token, <block_id> the id returned by docs +fetch --detail with-ids.

# 1. Create a document with the same inline markers in four containers
cat > repro.xml <<'EOF'
<title>xml inline markup repro</title>
<p>A1 **bold** and `code` here</p>
<table><tbody><tr><td><p>B1 **bold** and `code` here</p></td></tr></tbody></table>
<ol><li>C1 **bold** and `code` here</li></ol>
<p>E1 marker here</p>
EOF
lark-cli docs +create --as user --doc-format xml --content "@./repro.xml"

# 2. Append more of the same through the block paths
lark-cli docs +update --as user --doc "<doc_token>" --command append \
  --content '<p>F1 **bold** and `code` here</p>'
lark-cli docs +update --as user --doc "<doc_token>" --command block_insert_after \
  --block-id "<block_id>" --content '<p>H1 **bold** and `code` here</p>'

# 3. Write the identical characters through str_replace
lark-cli docs +update --as user --doc "<doc_token>" --command str_replace \
  --pattern 'E1 marker here' --content 'E1 **bold** and `code` here'

# 4. Read everything back in one call
lark-cli docs +fetch --as user --doc "<doc_token>" --doc-format xml --detail with-ids

Dry-run request for step 3

{
  "command": "str_replace",
  "content": "E1 **bold** and `code` here",
  "format": "xml",
  "pattern": "E1 marker here",
  "revision_id": -1
}

Actual result

docs +fetch --doc-format xml returns:

<p>A1 **bold** and `code` here</p>
<table>...<td><p>B1 **bold** and `code` here</p></td>...</table>
<ol><li>C1 **bold** and `code` here</li></ol>
<p>F1 **bold** and `code` here</p>
<p>H1 **bold** and `code` here</p>
<p>E1 <b>bold</b> and <code>code</code> here</p>   <!-- str_replace only -->
Write path (--doc-format xml) **bold** / `code`
docs +create literal text
docs +update --command append literal text
docs +update --command block_insert_after literal text
docs +update --command block_replace literal text
docs +update --command str_replace parsed into <b> / <code> nodes

The container does not matter: running str_replace over text that lives inside <li> or inside <td><p> converts the markers there too, so the split is purely per-command.

Backslash escaping confirms a Markdown inline parser is active on that path only:

lark-cli docs +update --as user --doc "<doc_token>" --command str_replace \
  --pattern 'G1 marker' --content 'G1 literal \*\*stars\*\* and \`ticks\`'
# fetch -> <p>G1 literal **stars** and `ticks`</p>   (backslashes consumed, no <b>)

Expected result

With --doc-format xml, all write commands treat --content as XML and store Markdown punctuation as literal text; inline styling comes from <b> / <code>. If str_replace must keep Markdown-style inline parsing, the CLI surface should say so and name the escape form.

Impact on agents

  1. Silent, undetectable corruption. An agent editing technical prose through str_replace — regex snippets, **kwargs, glob patterns, shell backticks, Python __init__ — gets bold/code nodes it never asked for. result is success and warnings is [], so nothing in the response reveals it.
  2. Content does not round-trip. docs +fetch --doc-format xml returns **bold** as literal text; feeding that same text back through str_replace turns it into <b>bold</b>. Fetch → edit → write is not idempotent.
  3. The documented contract points the other way. skills/lark-doc/references/lark-doc-md.md warns about the mirror case ("XML 标签会被解析并生效" under --doc-format markdown), but lark-doc-xml.md and lark-doc-update.md never mention Markdown, so an agent reasonably assumes XML mode is XML-only.

Suggestion

Preferred: make format: "xml" mean XML on the str_replace path too, so one flag has one contract.

If that is a deliberate server-side behavior, then document it where agents read: the str_replace row in skills/lark-doc/references/lark-doc-update.md, including the \* escape form. I am happy to send that documentation PR.

Related

  • #155 and #941 — over-escaping caused by escape rules lacking trigger context (Markdown path).
  • #1680 — str_replace and block_replace disagreeing about inline <code> nodes; same "two write paths, two contracts" family.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the documented references in skills/lark-doc/references/lark-doc-xml.md and lark-doc-update.md, then compare the str_replace command path with the other XML write paths using the supplied reproduction and dry-run request. Done means XML-mode str_replace has the same literal-text contract as the other write commands, or its Markdown parsing and escape form are explicitly documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, documentation
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.