larksuite / larksuite/cli

Windows lark-cli.cmd shim mangles multi-line markdown and '>' in --markdown args (routes to user identity / WinError path error)

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

Nobody has claimed this yet.

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

Description

Summary

On Windows, the lark-cli.cmd shim shipped with @larksuite/cli mangles arguments that contain newlines or >, which breaks the primary agent use-case of im +messages-send --markdown (multi-line, report-style markdown). A multi-line --markdown silently routes the request to the user identity (fails with token_missing even though --as bot was passed), and content with a line-leading > fails with a Windows path error. Both work perfectly when the same command is invoked through node run.js directly, which isolates the bug to the .cmd shim's argument re-passing — the core CLI binary is fine.

Repro

lark-cli 1.0.86, Windows 11, bot identity configured (user identity not logged in).

Case 1 — multi-line --markdown fails via .cmd, works via node run.js:

# via lark-cli.cmd → rc=3, routes to USER identity:
lark-cli.cmd im +messages-send --chat-id oc_xxx --markdown "line one
line two" --as bot

Actual error payload (verbatim):

{
  "ok": false,
  "identity": "user",
  "error": {
    "type": "authentication",
    "subtype": "token_missing",
    "message": "need_user_authorization (user: ou_9aaa070f0debd6a287298322cf962023)",
    "hint": "run `lark-cli auth login --scope \"im:message.send_as_user im:message\" --no-wait --json` ...",
    "user_open_id": "ou_9aaa070f0debd6a287298322cf962023"
  }
}
  • Single-line --markdown via .cmd → rc=0, "identity": "bot", sends fine.
  • Multi-line --markdown via node run.js → rc=0, "identity": "bot", sends fine (so the CLI logic itself handles multi-line correctly).

Case 2 — > inside content fails via .cmd, works via node run.js:

# via lark-cli.cmd → rc=1, WinError "The system cannot find the path specified."
lark-cli.cmd im +messages-send --chat-id oc_xxx \
  --content '{"zh_cn":{"content":[[{"tag":"md","text":"# 标题\n\n> 引用行\n\n**正文**"}]]}}' \
  --msg-type post --as bot

# via node run.js → rc=0, sends fine.
node node_modules/@larksuite/cli/scripts/run.js im +messages-send --chat-id oc_xxx \
  --content '{"zh_cn":{"content":[[{"tag":"md","text":"# 标题\n\n> 引用行\n\n**正文**"}]]}}' \
  --msg-type post --as bot

A mid-line > (e.g. l=64.67 > zg=63.30) works fine via .cmd; only a line-leading > (markdown blockquote) triggers the path error.

Why this is worse than a one-shot failure

  1. AI agents and report push scripts almost always send multi-line markdown (headers, blockquotes, bullet lists). The .cmd shim is what npm exposes as the default lark-cli entry on Windows (see node_modules/@larksuite/cli/scripts/run.js + lark-cli.cmd), so every script that does subprocess.run(["lark-cli", ...]) or shutil.which("lark-cli") lands on the broken .cmd.
  2. The failure is silent and misleading: it looks like an auth problem (need_user_authorization, hint to add im:message.send_as_user scope) when the user is trying to send as a bot that is already fully authorized. This sent us down a false "user auth missing" debugging path before we bisected to the wrapper.
  3. The blockquote case produces a confusing Windows path error for a pure-text payload, so even the manual --content workaround is non-obvious.

Root cause

The shim at node_modules/@larksuite/cli/lark-cli.cmd re-passes argv via %* into a second invocation:

endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & set PATHEXT=%PATHEXT:;.JS;=;% & "%_prog%"  "%dp0%\node_modules\@larksuite\cli\scripts\run.js" %*

cmd.exe's %* re-expansion loses the original argv quoting: embedded newlines break the argument (the CLI then sees a malformed flag set and falls back to its default user identity), and a line-leading > is treated as output redirection (WinError "The system cannot find the path specified"). The Go binary behind run.js has no such problem — proof is the node run.js control above.

Proposed fixes

(a) Stop re-parsing through %*. The .cmd shim should not reconstruct argv from %*. Preferred: keep the shim as a thin launcher that calls run.js with the exact same argv the shell received (e.g. forward args without re-expansion, or ship a small .exe/node launcher that does spawnSync(node, [runjs, ...process.argv.slice(2)])). This single change resolves both cases.

(b) Fall back loudly instead of silently. Independently of (a), when --as bot is passed but the request would use the user identity, error out with a clear "bot identity requested but user path taken" message rather than returning the confusing token_missing auth hint.

(a) alone is sufficient to unblock affected users.

Workaround (for affected users today)

On Windows, bypass the .cmd shim and call the underlying script with node directly:

node "$(npm root -g)/@larksuite/cli/scripts/run.js" im +messages-send \
  --chat-id oc_xxx --markdown "$(cat report.md)" --as bot

For the bundled-runtime case (e.g. inside Hermes): node <node-dir>/node_modules/@larksuite/cli/scripts/run.js ....

Environment

  • @larksuite/cli 1.0.86 (npm), Windows 11 x64
  • Invocation path: lark-cli.cmd shim → scripts/run.js → compiled Go binary (bin/lark-cli.exe)
  • Identity: bot configured and authorized; user identity intentionally not logged in
  • Feishu Open Platform (chat send via /open-apis/im/v1/messages)

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 lark-cli.cmd and compare its %* argument forwarding with scripts/run.js; reproduce both Windows cases using the .cmd shim and the direct node invocation. The fix is done when multiline --markdown and line-leading > content reach the bot identity without authentication or path errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.