Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude/skills/write-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ deterministic waits (`poll("cdb")`, `armDiagnostics`) over sleeping.

## Known pitfalls (each cost a real debugging session)

- JS numbers mangle 64-bit values: cache.json dep hashes and agentic
symbolIds need `JSON.rawJSON`/BigInt-reviver round trips (see
persistent_cache.test.ts, agentic/rpc.ts).
- JS numbers mangle 64-bit values: cache.json dep hashes need
`JSON.rawJSON`/BigInt-reviver round trips (see persistent_cache.test.ts);
`clice query` answers carry symbol ids as `#<hex>` strings for this reason.
- Python-style truthiness does not port: `expect([]).toBeFalsy()` fails —
assert `length` explicitly.
- LSP positions are UTF-16 code units; ASCII fixtures keep them equal to
Expand Down
2 changes: 2 additions & 0 deletions docs/en/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

**Usage**: `clice index [--workspace <dir>] [--configuration <tag>] [--workers <n>]`

One process writes the index of a workspace at a time. While an editor session has the workspace open, its server holds that role, so `clice index` asks the server to run the sweep and waits for the result instead of starting a worker pool of its own; the summary says so. A lock held by a process that cannot be asked (another `clice index`, a server of a different clice build, or one whose configuration keeps background indexing off) makes the command fail with the holder named — rerun it when that process is done.

The run is resumable: interrupting it with Ctrl-C saves the progress made so far, and the next invocation continues where it left off. Progress is also saved every five minutes, so a crash loses at most that much work. While it runs, a progress line goes to stderr every ten seconds whatever the log level; the final summary on stdout counts the indexed units, the file shards and symbols produced, lists every unit that failed to index, and names the session log directory. The exit code is 0 for a complete index, 1 when some units failed or part of the index could not be persisted, and 130 when interrupted.

## Inspecting the index
Expand Down
6 changes: 3 additions & 3 deletions docs/en/cli/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ clice is one binary. Editors launch `clice serve` and talk to it over LSP; the o
| `index` | Index a workspace ahead of time so the server starts warm. | [index](./index.md) |
| `format` | Format the workspace's files with clang-format. | [format](./format.md) |
| `inspect` | Run one feature on source files and print the raw result as JSON. | |
| `query` | Query symbol information from a running server. | |
| `query` | Ask the persisted index about symbols, references, call graphs and files. | [query](./query.md) |
| `doc` | Extract documentation data from a project. Not implemented yet. | |

`inspect` and `query` work today but have no page yet; their options are documented by `clice <command> --help`.
`inspect` works today but has no page yet; its options are documented by `clice inspect --help`.

`serve`, `index`, `lint`, `format` and `inspect` take `--configuration <tag>` to pin the build configuration for the run, over the selection persisted from the editor; see [switching configurations](../guide/configuration.md#switching-configurations).
`serve`, `index`, `lint`, `format`, `inspect` and `query` take `--configuration <tag>` to pin the build configuration for the run, over the selection persisted from the editor; see [switching configurations](../guide/configuration.md#switching-configurations).
25 changes: 25 additions & 0 deletions docs/en/cli/query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Query

## Overview

`clice query` asks the persisted index a structured question and prints the answer as JSON on stdout — for scripts and coding agents that want the facts a language server has without speaking LSP. It reads the index straight from disk, the same index `clice index` builds and an editor session keeps up to date, so it works while the editor is open and needs no server when it is not.

**Usage**: `clice query --method <question> [--workspace <dir>] [--configuration <tag>] [--fresh] [question options]`

## Questions

- `symbolSearch --query <text> [--limit <n>] [--kind <Kind,...>]` lists the symbols whose name contains the text, best matches first, with their kind, file, line and id.
- `definition`, `readSymbol`, `references [--include-declaration]`, `callGraph [--direction callers|callees|both]` and `typeHierarchy [--direction supertypes|subtypes|both]` answer about one symbol, named by `--name <name>` (optionally narrowed with `--path`), by `--symbol <id>` (the `#<hex>` id an earlier answer carried) or by `--path <file> --line <n>` (the symbol defined on that line). An ambiguous name lists the candidates' count and asks for an id.
- `documentSymbols --path <file>` is the file's outline.
- `compileCommand --path <file>` is the command the editor would compile the file with, and where it came from: the file's own database entry, a host source for a header, a rule's default command, a command inferred from a nearby unit, or the fallback.
- `projectFiles [--filter all|source|header|module]` lists the build's files; `fileDeps --path <file> [--direction includes|includers|both] [--depth <n>]` and `impactAnalysis --path <file>` follow the include graph.

Paths are workspace-relative or absolute in questions, absolute in answers; lines are 1-based.

## Answers

Every answer is one JSON object: `{"result": ..., "stale": [...]}` on success, `{"error": "...", "stale": [...]}` with exit code 1 when the question cannot be answered (an unknown symbol, a file that does not exist, an invalid option).

`stale` lists the files whose rows the answer had to leave out because their content on disk no longer matches what was indexed — the positions the index holds for them would point into text that moved. A file that changed only because a header it includes changed keeps answering from its last rows. A symbol whose definition sits in a stale file is reported as not found, with the file named, so a reader can tell "does not exist" from "not indexed yet". Only files the answer consulted are checked: a symbol added to a file after it was indexed is simply absent, since no row leads to that file — `--fresh` is the way to ask about the current disk. The index never sees unsaved editor buffers: the disk is the truth it describes.

`--fresh` brings the index up to date with the disk before answering: while an editor session has the workspace open, its server runs the sweep; otherwise the command runs the indexer itself, building the index from nothing when there is none yet. Either way only the units whose inputs changed are recompiled. Without `--fresh` a workspace with no index answers with an error.
4 changes: 2 additions & 2 deletions docs/en/design/multi-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ clice solves the above problems through a multi-process architecture: each compi
```text
Master Process (MasterServer)
├── Event loop (kota)
├── LSP / Agentic protocol handling
├── LSP / control protocol handling
├── State management (workspace, sessions, invalidation)
├── Compile scheduling (task graph: PCH / PCM / AST / TU-run families)
├── Background indexing (index store + pump)
Expand All @@ -43,7 +43,7 @@ All worker processes communicate with the master process via stdin/stdout pipes,

The master process is the system's coordinator, running a single-threaded event loop. It performs no CPU-intensive compilation work — all compilation is delegated to worker processes. The master process is responsible for:

- Receiving and routing LSP / Agentic requests
- Receiving and routing LSP / control requests
- Managing global state (Workspace, Session mappings)
- Scheduling compilation tasks and background indexing
- Monitoring worker process health
Expand Down
5 changes: 3 additions & 2 deletions docs/en/design/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ The task-graph engine that decides what gets built, when, and shares the results

The language server's core runtime, responsible for assembling all the layers above into a runnable service.

**`protocol/`** — Protocol definitions. Describes the message formats for communication between the master process and worker processes, as well as between the server and clients. Includes Worker protocol (compilation/query/build requests), LSP extension protocol (compilation context switching, etc.), and the agentic protocol for AI agents.
**`protocol/`** — Protocol definitions. Describes the message formats for communication between the master process and worker processes, as well as between the server and clients. Includes Worker protocol (compilation/query/build requests), LSP extension protocol (compilation context switching, etc.), and the control protocol through which `clice index` and `clice query --fresh` ask a running server to index.

**`state/`** — Document state and the invalidation machinery.

Expand All @@ -132,7 +132,8 @@ The language server's core runtime, responsible for assembling all the layers ab
**`transport/`** — Protocol endpoints driving the server.

- `MasterServer`: The composition root. Owns the workspace, sessions, worker pool, and all services above, and executes the `Invalidator`'s effects through its single dispatch entry point
- `LSPClient` / `AgentClient`: Request handlers for the LSP protocol and agentic protocol
- `LSPClient`: Request handlers for the LSP protocol
- The control channel: a loopback listener the server opens while it holds the workspace's index writer lock, recorded next to the lock for the command-line tools to find

See [Multi-process Architecture](multi-process.md).

Expand Down
1 change: 1 addition & 0 deletions docs/en/sidebar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ cli:
items:
- overview
- index
- query
- lint
- format

Expand Down
1 change: 1 addition & 0 deletions docs/meta/translations/cli/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{ "kind": "heading", "en": "7337f3d0aa29e9a8", "zh": "a166cd4942b3a912" },
{ "kind": "paragraph", "en": "ddb01ca63c20a4d5", "zh": "4f0b62347ff57d0b" },
{ "kind": "paragraph", "en": "884a22f58cdae0f1", "zh": "62a1eaa1f18a598e" },
{ "kind": "paragraph", "en": "daf48506adf45ed8", "zh": "ebca673b185a96f0" },
{ "kind": "paragraph", "en": "dc04fe115ba93d6b", "zh": "9534fd5df5218867" },
{ "kind": "heading", "en": "2d181775bd4e2abd", "zh": "ef909755906689d8" },
{ "kind": "paragraph", "en": "b97b36fff7bd8b5d", "zh": "4d30b3f7fa3c5e09" },
Expand Down
6 changes: 3 additions & 3 deletions docs/meta/translations/cli/overview.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
{ "kind": "tableRow", "en": "6ed5693a71d780eb", "zh": "c898fa09173c5e7a" },
{ "kind": "tableRow", "en": "7e124da9853015e9", "zh": "3f205740f63dbb12" },
{ "kind": "tableRow", "en": "03031de584747d59", "zh": "367302913a714653" },
{ "kind": "tableRow", "en": "0fadff32c7d880f8", "zh": "1df15afe49fec514" },
{ "kind": "tableRow", "en": "c7621dc48e91774f", "zh": "91681e4e58aeb9a5" },
{ "kind": "tableRow", "en": "ca92c3c40ac852c7", "zh": "d6f33f9693c842b2" },
{ "kind": "paragraph", "en": "82a345954a3191b1", "zh": "c386fdd91b4cc37f" },
{ "kind": "paragraph", "en": "fdeda0132e3605bf", "zh": "f7e2c6d876aa2139" }
{ "kind": "paragraph", "en": "f2a1606ab6533abd", "zh": "4e841509cbac6ee3" },
{ "kind": "paragraph", "en": "cbc9d9dc4c500bfa", "zh": "1b12afda97cfe0ac" }
]
}
20 changes: 20 additions & 0 deletions docs/meta/translations/cli/query.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": 1,
"pairs": [
{ "kind": "heading", "en": "c05e6cc250e1d4f7", "zh": "ffb3ca340da04ecb" },
{ "kind": "heading", "en": "7337f3d0aa29e9a8", "zh": "a166cd4942b3a912" },
{ "kind": "paragraph", "en": "f35437c27adf3821", "zh": "16ea52d3b9a7f9a4" },
{ "kind": "paragraph", "en": "d128dce79df52ac3", "zh": "84de8ae4c68a2b36" },
{ "kind": "heading", "en": "60cc6f1a0163ec5d", "zh": "6781f7f87e7fa047" },
{ "kind": "listItem", "en": "bc687ed58faed913", "zh": "5737530d56dba633" },
{ "kind": "listItem", "en": "da7a9a9791549c58", "zh": "5f06891ac7ed9414" },
{ "kind": "listItem", "en": "0ffde3e2fabbd72b", "zh": "8cfd5784041411c2" },
{ "kind": "listItem", "en": "ad17bf9b38cd770a", "zh": "92e5164908fd7b9b" },
{ "kind": "listItem", "en": "acbd88ed0c007026", "zh": "bf5aed2e1d886dd5" },
{ "kind": "paragraph", "en": "b89e65ba74943648", "zh": "4c107b60f387e9a8" },
{ "kind": "heading", "en": "870bc5c04ef997f1", "zh": "f219309b5b6840a5" },
{ "kind": "paragraph", "en": "5eacf2b3a2311cc4", "zh": "a5d4cb60134c4f66" },
{ "kind": "paragraph", "en": "9d87812d2918ad0c", "zh": "b0f8261197133901" },
{ "kind": "paragraph", "en": "892260c25a40ad3d", "zh": "d985b4dd5ea54e89" }
]
}
2 changes: 1 addition & 1 deletion docs/meta/translations/design/multi-process.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
{ "kind": "paragraph", "en": "1521a5db3ea4d3ee", "zh": "75bb6afbcff5f07d" },
{ "kind": "heading", "en": "ed17f49db7d1ba07", "zh": "074ba96dac479282" },
{ "kind": "paragraph", "en": "96f127caa735c3fd", "zh": "ed1228d3f24c0979" },
{ "kind": "listItem", "en": "000708b6b74b3509", "zh": "a096202a84afaa56" },
{ "kind": "listItem", "en": "6b40a002aa365244", "zh": "53ee16282a844543" },
{ "kind": "listItem", "en": "953e38409e737e70", "zh": "b3ec528d46170418" },
{ "kind": "listItem", "en": "159473989d0077a6", "zh": "4fdc1f26d3037af1" },
{ "kind": "listItem", "en": "0b8e125f976bd567", "zh": "83ebf559e6c199e8" },
Expand Down
5 changes: 3 additions & 2 deletions docs/meta/translations/design/overview.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
{ "kind": "listItem", "en": "ca21bc3d5f10891b", "zh": "098e45183db129e4" },
{ "kind": "heading", "en": "ef79bd3bd0ff8ab9", "zh": "2c24bd057049dc14" },
{ "kind": "paragraph", "en": "84320fc0225a53f2", "zh": "8cc86a25b439f041" },
{ "kind": "paragraph", "en": "b87d437bd02c326c", "zh": "bd2384ba75dae114" },
{ "kind": "paragraph", "en": "7f6eafcb967d37f9", "zh": "fc41b32d76a12cb8" },
{ "kind": "paragraph", "en": "8e482fc2c21656bc", "zh": "1df88c59a9c9096f" },
{ "kind": "listItem", "en": "2bb5be5b7ba62316", "zh": "83cfca23c2c54c07" },
{ "kind": "listItem", "en": "a762b21116bf3468", "zh": "e84a9457307e4cf0" },
Expand All @@ -84,7 +84,8 @@
{ "kind": "listItem", "en": "5c9265ca6f5aec00", "zh": "6273023c02c0049e" },
{ "kind": "paragraph", "en": "ae345e395fb7f593", "zh": "73f7dff161bd1c71" },
{ "kind": "listItem", "en": "7808e6bdc3e7f8d6", "zh": "e98ce3a984fcf83e" },
{ "kind": "listItem", "en": "18fef004b4d6b980", "zh": "5923668fdd5a2b8f" },
{ "kind": "listItem", "en": "25f3d197a72d72ad", "zh": "993aaee6a6eebc37" },
{ "kind": "listItem", "en": "555847643812de6f", "zh": "8f5b985ec83c8fb8" },
{ "kind": "paragraph", "en": "5378d4be3591fb34", "zh": "594b885daff16a89" },
{ "kind": "heading", "en": "e90aadccddb76f3b", "zh": "79a561a47efdf1fc" },
{ "kind": "paragraph", "en": "923048f19f0dd39c", "zh": "51c813cd272ab1c6" },
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

**用法**:`clice index [--workspace <dir>] [--configuration <tag>] [--workers <n>]`

同一时刻只有一个进程为工作区写索引。编辑器会话打开着工作区时,这个角色由它的服务器担任,因此 `clice index` 会请服务器执行这轮索引并等待结果,而不是自己启动一个 worker 池;摘要中会说明这一点。若锁被一个无法请求的进程持有(另一个 `clice index`、另一个 clice 构建的服务器,或配置里关闭了后台索引的服务器),命令会失败并给出持有者——等那个进程结束后再重新运行。

索引构建可在中断后继续:按 Ctrl-C 中断会保存当前进度,下次执行时会从中断处继续。每五分钟也会保存一次进度,因此崩溃最多只会损失五分钟的工作。运行期间,无论日志级别如何,每十秒都会向 stderr 输出一行进度;最终在 stdout 输出的摘要会统计已建立索引的翻译单元数、生成的文件分片数和符号数,列出所有索引构建失败的翻译单元,并给出会话日志目录。索引完整时退出码为 0,部分翻译单元索引失败或部分索引无法持久化时为 1,中断时为 130。

## 查看索引
Expand Down
6 changes: 3 additions & 3 deletions docs/zh/cli/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ clice 只有一个二进制。编辑器启动 `clice serve` 并通过 LSP 与它
| `index` | 提前为工作区建立索引,让服务器热启动。 | [index](./index.md) |
| `format` | 用 clang-format 格式化工作区中的文件。 | [format](./format.md) |
| `inspect` | 对源文件运行某一项功能,把原始结果打印成 JSON。 | |
| `query` | 向运行中的服务器查询符号信息。 | |
| `query` | 向持久化索引查询符号、引用、调用图和文件。 | [query](./query.md) |
| `doc` | 从项目中提取文档数据。尚未实现。 | |

`inspect` 和 `query` 现在已可使用但还没有页面,选项通过 `clice <command> --help` 查看。
`inspect` 现在已可使用但还没有页面,选项通过 `clice inspect --help` 查看。

`serve`、`index`、`lint`、`format` 和 `inspect` 都接受 `--configuration <tag>`,为本次运行固定构建配置,其优先级高于编辑器持久化的选择;参见[切换配置](../guide/configuration.md#switching-configurations)。
`serve`、`index`、`lint`、`format`、`inspect` 和 `query` 都接受 `--configuration <tag>`,为本次运行固定构建配置,其优先级高于编辑器持久化的选择;参见[切换配置](../guide/configuration.md#switching-configurations)。
Loading
Loading