feat: add SiYuan CLI (cli-anything-siyuan)#311
Conversation
Add SiYuan (思源笔记) CLI tool for managing notebooks, documents, blocks, and searching content via SiYuan HTTP API. - Full CLI with notebook/doc/block/search/tag/export commands - REPL mode with tab-completion - JSON output mode for agent consumption - 33 passing tests (18 unit + 15 CLI command tests) - Skill documentation for AI agent integration - Registry entries for CLI-Hub discovery Install: pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=siyuan/agent-harness
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f015c4e8a8
ℹ️ 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".
| return | ||
| sub = parts[1] | ||
| if sub == "insert" and len(parts) >= 4: | ||
| result = client.insert_block("markdown", parts[3], previous_id=parts[2] if len(parts) > 2 else "") |
There was a problem hiding this comment.
Pass parent ID to block insert in REPL
Update the REPL block insert path to pass the second argument as parent_id, not previous_id. The help text and command shape (block insert <parent> <data>) indicate users provide a parent block, but this call currently inserts relative to previousID, which places content in the wrong position (or fails when only a parent context is known).
Useful? React with 👍 / 👎.
| [[d.get("id", ""), d.get("name", ""), d.get("type", "")] | ||
| for d in docs]) |
There was a problem hiding this comment.
Normalize REPL doc list responses before rendering
The REPL doc list branch iterates docs as if it were a list of document objects, but SiYuan responses are often wrapped as a dict (e.g. with a files array, which the one-shot doc list command already handles). When that dict shape is returned, iteration yields keys (strings), so d.get(...) raises and the REPL command fails instead of listing documents.
Useful? React with 👍 / 👎.
| skin.table(["ID", "Content"], | ||
| [[r.get("id", ""), r.get("content", "")[:80]] for r in results]) |
There was a problem hiding this comment.
Normalize REPL search responses before table output
The REPL search handler assumes search_blocks returns a list, but SiYuan commonly returns a dict containing a blocks array (which the one-shot search command already normalizes). If the dict form is returned, iterating results yields string keys and r.get(...) crashes, so search in REPL breaks for real API responses.
Useful? React with 👍 / 👎.
| state = session.state | ||
|
|
||
| info = { | ||
| "connected": state.connected, |
There was a problem hiding this comment.
Report live connectivity in status output
Use a live connectivity value in status instead of session.state.connected. That session field is initialized to False and is never updated anywhere in this commit, so status reports connected: false even after successfully calling get_version(), which makes machine-readable status output inaccurate.
Useful? React with 👍 / 👎.
- REPL search: handle dict response (fixes KeyError when API returns {blocks: [...]})
- REPL doc list/tree: normalize dict responses before table output
- REPL block insert: use parent_id instead of previous_id
- status command: use live ping result instead of stale session state
|
@codex review |
- setup.py referenced tests/TEST.md which doesn't exist, causing package build warnings - SKILL.md test count was incorrect (18 unit → 12 unit)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a651bf39d0
ℹ️ 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".
|
|
||
| def _handle_repl_command(skin: Any, cmd: str) -> None: | ||
| """Parse and execute a REPL command.""" | ||
| parts = cmd.strip().split() |
There was a problem hiding this comment.
Parse REPL input with shell-style tokenization
The REPL parser uses cmd.strip().split(), which loses quoting and breaks multi-word arguments. As a result, commands that rely on positional tokens (for example block insert, block update, and doc create --md) only receive a fragment of the intended payload or include literal quote characters, so markdown with spaces is inserted/updated incorrectly. This is a functional data-loss bug for normal note content entered in REPL.
Useful? React with 👍 / 👎.
| url = f"{self.config.base_url}{endpoint}" | ||
| try: | ||
| resp = self._session.post(url, json=data or {}, timeout=30) | ||
| except requests.ConnectionError as e: |
There was a problem hiding this comment.
Catch request timeouts and transport errors uniformly
_post only converts requests.ConnectionError into SiYuanClientError, but other common transport failures (for example timeouts/read errors/SSL errors) bubble up as raw exceptions. In those cases callers that handle SiYuanClientError won't catch the failure, so users get unhandled errors instead of the intended CLI error message path.
Useful? React with 👍 / 👎.
- REPL: replace str.split() with shlex.split() to handle quoted multi-word arguments (fixes block insert/update with spaces) - Client: catch Timeout, SSL, and generic RequestException in addition to ConnectionError for better error messages
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9627bc6a4
ℹ️ 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".
| def create_notebook(self, name: str) -> dict[str, Any]: | ||
| return self._post("/api/notebook/createNotebook", {"name": name}) |
There was a problem hiding this comment.
Normalize createNotebook payload before returning
create_notebook() currently returns the raw data object from /api/notebook/createNotebook, but SiYuan’s API shape is {"notebook": {...}} for that endpoint. Downstream code paths (notebook create and REPL notebook creation) read nb["id"]/nb["name"] directly, so real API responses trigger a KeyError instead of creating and reporting the notebook.
Useful? React with 👍 / 👎.
| def block_insert(ctx: SiYuanContext, data: str, previous: str, parent: str, data_type: str): | ||
| """Insert a block.""" | ||
| result = ctx.client.insert_block(data_type, data, parent_id=parent, previous_id=previous) |
There was a problem hiding this comment.
Require an anchor for block insert
This command allows block insert <data> with both --parent and --previous empty, then calls insertBlock without any position anchor. The SiYuan API requires at least one of nextID, previousID, or parentID for /api/block/insertBlock, so the default invocation path fails at runtime unless users discover and pass extra flags.
Useful? React with 👍 / 👎.
- create_notebook: unwrap {notebook: {...}} response so callers
can access nb["id"] and nb["name"] directly
- block insert: require --parent or --previous, error if both empty
(SiYuan API requires at least one position anchor)
Add --next option for insertBlock anchor support. Validate that at least one anchor (--parent/--previous/--next) is provided. Add REPL usage error for missing anchor. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a06d2046e
ℹ️ 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".
| if user_input in ("quit", "exit", "q"): | ||
| break |
There was a problem hiding this comment.
Persist REPL session state before exit
The REPL loop breaks immediately on quit/exit/q without flushing the session, but multiple REPL commands call get_session().update(...) and only mark the state dirty. Because SessionManager persists changes only on flush()/save(), notebook/document context changes made during a REPL session are lost after exiting and are not available in the next run.
Useful? React with 👍 / 👎.
| config_file = Path.home() / ".siyuan-cli.json" | ||
|
|
||
| if config_file.is_file(): | ||
| data = json.loads(config_file.read_text(encoding="utf-8")) |
There was a problem hiding this comment.
Handle malformed config JSON without crashing
load_config() parses ~/.siyuan-cli.json with json.loads(...) and does not catch decode/read errors. If a user has an invalid or partially written config file, every CLI command crashes during startup instead of reporting a friendly config error or falling back to env/defaults, which effectively bricks the CLI until the file is manually fixed.
Useful? React with 👍 / 👎.
- Flush session state before REPL quit/exit/q so context is preserved - Gracefully handle malformed config JSON (fall back to env/defaults) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Thanks for the SiYuan harness. Before merge, please address the current functional review items and tighten the registry integration:
|
…urce - Remove siyuan entry from public_registry.json (in-repo harness should not be listed as a public CLI) - Sync skills/cli-anything-siyuan/SKILL.md from harness source via sync_root_skills.py Addresses yuh-yang review feedback.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1f81e99b3
ℹ️ 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".
| if user_input in ("quit", "exit", "q"): | ||
| ctx.session.flush() |
There was a problem hiding this comment.
Flush the REPL session via the context object
When a user exits the REPL with quit, exit, or q, ctx is the Click context and does not have a session attribute; the session manager is available as the local session variable or ctx.obj.session. Because this branch is outside the command handler's try, normal REPL exit raises AttributeError instead of saving dirty state and printing the goodbye message.
Useful? React with 👍 / 👎.
| try: | ||
| data = json.loads(config_file.read_text(encoding="utf-8")) | ||
| except (json.JSONDecodeError, OSError): | ||
| data = {} |
There was a problem hiding this comment.
Fall back to environment after invalid config
The current malformed-config handler avoids the JSON crash, but it sets data = {} and then immediately returns default host/port/token values from the file branch, so a user with a bad or partially written ~/.siyuan-cli.json cannot recover by setting SIYUAN_TOKEN/SIYUAN_HOST as documented. In that scenario the CLI silently drops the env credentials and continues unauthenticated/defaulted until the file is manually fixed.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c74c29723a
ℹ️ 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".
| @click.pass_obj | ||
| def notebook_list(ctx: SiYuanContext): | ||
| """List all notebooks.""" | ||
| notebooks = ctx.client.list_notebooks() |
There was a problem hiding this comment.
Convert API errors before leaving one-shot commands
When a one-shot command hits a normal SiYuan API failure such as a bad token or non-zero API code, _post() raises SiYuanClientError, but this command path has no handler and SiYuanClientError is not a Click exception. I verified the one-shot path with CliRunner: notebook list exits with the raw exception and no CLI error output, so users running documented commands get a traceback instead of the intended friendly error handling that the REPL already provides.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abcf19b5d9
ℹ️ 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".
| def doc_tree(ctx: SiYuanContext, notebook_id: str, path: str, depth: int): | ||
| """List document tree.""" | ||
| tree = ctx.client.list_doc_tree(notebook_id, path=path, max_depth=depth) | ||
| items = tree.get("tree", []) if isinstance(tree, dict) else tree |
There was a problem hiding this comment.
Read doc-tree entries from the files key
When SiYuan returns the documented /api/filetree/listDocTree shape, data is a dict containing a files array, not a tree array; I checked the filetree/listDocTree API docs/source links. In that common response path this line turns the result into [], so cli-anything-siyuan doc tree <notebook> reports an empty tree even when documents exist. The REPL branch has the same normalization pattern, so both paths should read files (and render the returned name field rather than title).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fe27d44825
ℹ️ 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".
| def get_tags(self) -> list[dict[str, Any]]: | ||
| return self._post("/api/tag/getTag", {}) |
There was a problem hiding this comment.
When a workspace has more tags than SiYuan's Conf.FileTree.MaxListCount, /api/tag/getTag stops building the response unless the request includes ignoreMaxListHint: true; this makes both tag list and --json tag list silently omit the remaining tags even though the command is documented as listing all tags. Pass that flag here before rendering the result so large/tag-heavy workspaces are complete.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a94fc1e4f0
ℹ️ 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".
| cli-anything-siyuan --json notebook list | ||
|
|
||
| # Create a document with Markdown | ||
| cli-anything-siyuan doc create nb1 /projects/new "## Title\n\nContent" |
There was a problem hiding this comment.
Put Markdown content behind --md in the skill example
When agents follow this skill example to create a document with initial content, Click receives the Markdown as a third positional argument even though doc create only declares notebook_id and path plus the --md option, so the command exits with an unexpected-extra-argument error before creating anything. Use the documented shape, e.g. doc create nb1 /projects/new --md ..., so the installed skill does not teach a failing workflow.
Useful? React with 👍 / 👎.
- notebook_open now looks up the notebook name via list_notebooks() and updates current_notebook_name to avoid stale display - tag list recursively prints child tags with indentation
_dev fallback in _resolve_cli now uses the package path (e.g. cli_anything.siyuan) which routes through __main__.py, instead of directly targeting the non-executable cli module.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5a51f8e7e
ℹ️ 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".
| if data is not None: | ||
| return SiYuanConfig( | ||
| host=data.get("host", "127.0.0.1"), | ||
| port=data.get("port", 6806), | ||
| token=data.get("token", ""), | ||
| ) |
There was a problem hiding this comment.
Honor environment overrides when config exists
When a valid ~/.siyuan-cli.json exists, this early return ignores SIYUAN_HOST, SIYUAN_PORT, and SIYUAN_TOKEN entirely. In environments where users rely on the documented env vars to override a stale local config or to supply a token that is omitted from the file, the CLI continues with the file/default credentials and fails to authenticate; read the file as defaults but apply env values before returning.
Useful? React with 👍 / 👎.
Env vars (SIYUAN_HOST/PORT/TOKEN) now take precedence over config file values, so CI/testing can override without modifying the config file.
Markdown with backticks, parentheses, quotes gets mangled by shell argument parsing. Now `--md -` reads from stdin, bypassing the shell: echo "## Title" | sy doc create nb1 /path --md -
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b7a067c59c
ℹ️ 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".
| if not md or md == "-": | ||
| md = click.get_text_stream("stdin").read() |
There was a problem hiding this comment.
Avoid blocking empty doc creation on stdin
When users follow the documented doc create <notebook-id> <path> form from an interactive shell and omit --md, this branch reads from stdin and waits for EOF instead of creating an empty document. SiYuan accepts an empty markdown value for this API, so only the explicit --md - case should consume stdin; otherwise the basic create command can appear hung.
Useful? React with 👍 / 👎.
PowerShell pipes text using system code page (e.g. GBK), then Python's
text-mode stdin reading may mangle CJK characters. Reading raw bytes
via sys.stdin.buffer.read() preserves the original bytes before any
encoding conversion, then decode('utf-8-sig') handles BOM + UTF-8.
Also fixed doc_create, block_insert, block_update to use the new
_read_stdin() helper instead of click.get_text_stream('stdin').
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f5124adce6
ℹ️ 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".
| def doc_tree(ctx: SiYuanContext, notebook_id: str, path: str, depth: int): | ||
| """List document tree.""" | ||
| tree = ctx.client.list_doc_tree(notebook_id, path=path, max_depth=depth) | ||
| items = tree.get("files", []) if isinstance(tree, dict) else tree |
There was a problem hiding this comment.
Support tree-shaped doc tree responses
When SiYuan returns /api/filetree/listDocTree data under the tree key, this normalization drops the entire result because it only accepts files from dict responses. I checked the SiYuan v3.4.2 kernel api/filetree.go, where listDocTree sets ret.Data = {"tree": doctree}, so cli-anything-siyuan doc tree ... will print no documents for those kernels even though the API succeeded; please accept both files and tree before falling back to an empty list.
Useful? React with 👍 / 👎.
SiYuan v3.4.2+ returns doc tree under 'tree' key instead of 'files'. Accept either before falling back to empty list.
|
Thanks for the fixes here. The important A few items still need cleanup before this can merge:
Focused SiYuan tests pass locally, but the root skill validation failure and unrelated diff make this not merge-ready yet. |
fix: address review feedback — doc create stdin, registry, drawio cleanup - doc create only reads stdin with --md - (not when --md is omitted) - registry.json source_url set to null (in-repo harness convention) - sync root skills/cli-anything-siyuan/SKILL.md with harness version - revert unrelated drawio border changes @
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 469ef1d91d
ℹ️ 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".
| for t in items: | ||
| indent = " " * t.get("depth", 0) | ||
| click.echo(f"{indent}{t.get('name', '')} ({t.get('id', '')})") |
There was a problem hiding this comment.
Traverse doc-tree children before rendering
When /api/filetree/listDocTree returns the tree-shaped response, nested documents are stored under each node's children field, but this text renderer only iterates the top-level items. In any notebook with documents inside subdocuments/folders, doc tree <notebook> omits all descendants even though the command is meant to show the full document tree; flatten or recursively print children here (and in the REPL path) before rendering.
Useful? React with 👍 / 👎.
fix: code quality — tty guard, refactor REPL, remove globals, stdin support - _read_stdin() checks isatty() before blocking, raises UsageError if no pipe - Split _handle_repl_command (200 lines) into _dispatch_repl + 6 sub-handlers - Remove module-level _config/_client/_session_mgr globals; use SiYuanContext - REPL block insert/update/prepend/append support "-" token for stdin - Remove unused SessionManager.auto_save decorator @
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3aaa0aa0e
ℹ️ 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".
| return self._post("/api/search/fullTextSearchBlock", {"query": query}) | ||
|
|
||
| def search_tag(self, tag: str = "") -> list[dict[str, Any]]: | ||
| return self._post("/api/search/searchTag", {"tag": tag}) |
There was a problem hiding this comment.
When callers use this client helper, SiYuan's searchTag handler reads the query from arg["k"] and returns a dict containing tags; sending tag leaves the required key unset, so real kernels fail before searching instead of returning matching tags. Use the k payload key and unwrap the returned tags array.
Useful? React with 👍 / 👎.
| data = self._post("/api/search/findReplace", { | ||
| "keyword": keyword, "replacement": replacement, | ||
| "notebookID": notebook_id, "path": path, "maxCount": max_count, | ||
| }) | ||
| return data.get("count", 0) |
There was a problem hiding this comment.
Use SiYuan's findReplace payload shape
When this helper is used, SiYuan's /api/search/findReplace handler expects k, r, and an ids array (plus the usual search filters), and successful calls return null data rather than a count object. This payload sends unrelated key names and then calls .get() on the null success data, so the method cannot perform a normal find/replace call against a real kernel.
Useful? React with 👍 / 👎.
fix: traverse doc-tree children recursively before rendering - Add _walk_tree() helper to flatten tree nodes recursively with depth - Use _walk_tree in both CLI doc tree and REPL doc tree handlers - Non-JSON output now shows all nested children with proper indentation - Update test to verify 3-level nested children all appear in output @
fix: disable proxy for SiYuan local HTTP client > requests respects system HTTP_PROXY/HTTPS_PROXY by default, which can intercept localhost connections and cause API 404s when a local proxy (e.g. Clash) is running. Set trust_env=False since SiYuan is always localhost — there is never a need to route through a proxy. @
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 22eeff4eba
ℹ️ 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".
| return self._post("/api/filetree/getIDsByHPath", {"notebook": notebook_id, "path": path}) | ||
|
|
||
| def list_docs_by_path(self, notebook_id: str, path: str) -> list[dict[str, Any]]: | ||
| return self._post("/api/filetree/listDocsByPath", {"notebook": notebook_id, "path": path}) |
There was a problem hiding this comment.
Request uncapped document listings
When a path contains more children than SiYuan's FileTree.MaxListCount, /api/filetree/listDocsByPath defaults to that cap unless maxListCount is supplied (with 0/negative disabling the cap). Because this helper sends only notebook and path, both doc list and the REPL doc list can silently render only the first capped subset while the command is described as listing the directory; pass maxListCount: 0 or expose a limit option for the list-all behavior.
Useful? React with 👍 / 👎.
| }) | ||
|
|
||
| def search_docs(self, keyword: str) -> list[dict[str, Any]]: | ||
| return self._post("/api/filetree/searchDocs", {"keyword": keyword}) |
There was a problem hiding this comment.
Send the document search term as k
When this public helper is used against SiYuan's /api/filetree/searchDocs, the kernel reads the search string from arg["k"]; sending keyword leaves the required key absent, so real kernels fail the request instead of returning matching documents. Use the payload key k here to make search_docs() usable.
Useful? React with 👍 / 👎.
|
Thanks for continuing to iterate on this. The earlier structural items are much closer, but the latest review round still shows several real SiYuan API-shape issues that should be fixed before merge:
Please add focused tests with mocked SiYuan responses for these API shapes. After that, please rerun the root skill validation as well. |
|
Thanks for the latest focused tests. I reran the SiYuan API-shape checks, and the earlier functional blockers now look addressed: doc tree recursion, uncapped One repo-integration blocker remains:
Please run |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59e9f7bc2d
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| user_input = skin.get_input( | ||
| pt_session, | ||
| project_name=state.current_doc_path or "", | ||
| modified=False, | ||
| context=ctx_str, | ||
| ) |
There was a problem hiding this comment.
Handle prompt interrupts before leaving REPL
When users exit the REPL with Ctrl-D or Ctrl-C, skin.get_input()/input() raises EOFError or KeyboardInterrupt here before the later quit branch and before the _dispatch_repl try, so the loop unwinds without obj.session.flush() or the goodbye path. In sessions where commands updated the current notebook/document, those dirty session changes are lost and users see an exception-style exit; catch these prompt interrupts and route them through the same flush/break path as quit.
Useful? React with 👍 / 👎.
Summary
Add SiYuan (思源笔记) CLI tool —
cli-anything-siyuan— for managing notebooks, documents, blocks, and searching content via the SiYuan HTTP API.Key features:
--jsonflag on all commands for machine/agent consumptionTest Status
33 tests passing (12 unit + 15 CLI command tests + 6 optional E2E tests against a live instance)
Installation
Documentation
skills/cli-anything-siyuan/SKILL.md— AI agent integration documentationsiyuan/agent-harness/SIYUAN.md— CLI reference and usage guideRegistry
Registered in both
registry.jsonandpublic_registry.jsonfor CLI-Hub discovery.