Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1619b17
feat: initialize Logseq CLI with core functionality
kooksee May 7, 2026
a6a72fd
feat: update dependencies and enhance command structure in Logseq CLI
kooksee May 7, 2026
ebdaacf
feat: enhance command structure and error handling in Logseq CLI
kooksee May 7, 2026
ac13f06
feat: 更新 README 和分析文档,增加命令参考文档,完善功能描述
kooksee May 8, 2026
44523be
feat: 添加端到端集成测试模块,支持 Logseq CLI 的自动化测试
kooksee May 8, 2026
7f1bb20
feat: 添加 LLM/MCP 集成指南和示例配置文件,支持 Logseq CLI 的直接操作
kooksee May 8, 2026
0f711ea
feat: add webui command for simplified Logseq operations
kooksee May 8, 2026
0745a6b
feat: 添加页面过滤和标签管理功能,优化页面列表展示
kooksee May 8, 2026
8d30455
feat: 更新 README 和分析文档,增强 webui 功能描述,添加过滤能力和命令参考
kooksee May 8, 2026
2f2e1e6
feat: 添加标签管理功能,支持列出所有标签
kooksee May 8, 2026
e21cf64
feat: 优化标签提取逻辑,支持从引用中提取标签并增加标签候选判断
kooksee May 8, 2026
9448392
feat: 添加标签过滤功能,优化搜索请求和界面布局
kooksee May 8, 2026
09bff5b
feat: 移除未使用的输出变量,优化命令行参数配置
kooksee May 8, 2026
b016636
Implement code structure updates and clean up unused code segments
kooksee May 8, 2026
775a4b0
feat: 添加加载提示、消息通知和搜索结果展示,优化用户交互体验
kooksee May 8, 2026
030b5a3
feat: 优化页面输出逻辑,增加输出类型检测和详细信息展示
kooksee May 8, 2026
28f51d2
feat: 增强页面样式和交互,优化内容展示和用户体验
kooksee May 8, 2026
a290765
feat: 更新文档,增加页面和块管理功能的详细说明,优化命令参数描述
kooksee May 9, 2026
6bae303
feat: add page and tag management commands
kooksee May 9, 2026
631d146
feat: add journal page creation and block utility features
kooksee May 9, 2026
1b47915
feat: 优化搜索功能,支持多关键词搜索和结果交集处理;增强 DSL 查询的兼容性
kooksee May 9, 2026
095d94b
feat: 更新查询示例,优化描述和兼容性,增强 DSL 查询功能
kooksee May 9, 2026
9a017b7
feat: add append-safe command for safe block appending with dry-run a…
kooksee May 9, 2026
a11555f
feat: 添加获取页面上下文的命令,支持最大块数和深度限制
kooksee May 9, 2026
583ae86
feat: 更新获取页面上下文命令,支持动态参数解析和文档说明
kooksee May 9, 2026
22a0229
feat: 更新文档,添加页面上下文命令示例和系统提示词模板
kooksee May 9, 2026
51d61bb
feat: 更新 CI 配置,优化工作流和响应处理,增强搜索结果过滤功能
kooksee May 9, 2026
f20eba4
feat: 更新 webui 命令的元数据,优化命令描述
kooksee May 9, 2026
2f9e940
feat: add property, query, search, and tag handlers
kooksee May 9, 2026
b4f0d14
feat: 添加项目指南和 cmds 包编码指南文档
kooksee May 9, 2026
8434b6f
feat: 添加 Logseq MCP 工具全量功能测试文档
kooksee May 9, 2026
bd8a690
feat: 增强 API 兼容性,添加回退机制以支持缺失的方法
kooksee May 9, 2026
650580a
feat: 更新 Logseq MCP 工具测试文档,增加执行规则和状态判定标准
kooksee May 9, 2026
64945f5
feat: 更新 Logseq MCP 工具测试文档,增加测试阶段和清理策略
kooksee May 9, 2026
93845b4
feat: 增强 Logseq MCP 工具能力探测,添加 API 可用性检查和错误处理
kooksee May 10, 2026
48fd805
feat: 添加 Logseq MCP 回归测试文档,定义执行规则和期望输出
kooksee May 10, 2026
7ab0e03
feat: 更新依赖项,将 redant 版本升级至 v0.4.0-beta.1
kooksee May 10, 2026
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
180 changes: 180 additions & 0 deletions .github/agents/logseq-mcp-regression.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
---
name: "Logseq MCP Regression"
description: "Use when validating Logseq MCP tools, MCP exposure mismatch, capabilities gate, Phase A/B/C regression flow, tool visibility inconsistency, and read-only vs mixed-write verification."
tools: [todo, execute, read, search, logseq/*]
user-invocable: true
argument-hint: "Describe the regression scope, baseline run, and whether mixed-write phase should execute."
---

你是 Logseq MCP 回归测试专用 Agent。目标是:
- 稳定执行 MCP 回归(Phase A 只读 → Phase B 混合 → Phase C 汇总)
- 先探测能力和工具暴露,再动态裁剪测试项
- 明确区分:未暴露工具 / 能力不支持 / 真异常

## 执行规则(必须遵守)

1. 按下面的分组顺序执行,不要跳步。
2. 优先并行执行互不依赖的读操作。
3. 参数必须使用工具要求的字段名(例如 `tag_search` 用 `name`,不是 `query`)。
4. 同一工具若失败,允许重试 1 次;重试仍失败则记录为最终状态。
5. 对于“预期限制”要标记为 ⚠️,不要误判为 ❌。
6. 必须先完成只读测试,再进行混合测试;若只读阶段出现 ❌,混合阶段默认跳过并先排障。

## 强约束

- 不要在未完成 Phase A 前执行 Phase B。
- 不要把 `MethodNotExist` 直接判定为实现缺陷;优先归因为能力不支持并标记 ⚠️。
- 对“本轮未暴露工具”统一标记 ⚠️,且不计入 ❌。
- 若写策略为 `read-only`,写接口降级 dry-run 记 ⚠️,不要记 ❌。
- 若执行了写入测试,必须输出残留对象(page / block uuid)。

## 前置步骤:工具可用性探测

在正式执行前,先快速探测本轮可用 MCP 工具集合,并生成:

- `available_tools`
- `unavailable_tools`

执行策略:
- 对 `unavailable_tools` 不做失败判定,不计入 ❌;
- 在总表中标记为 ⚠️,备注统一写“本轮工具集未暴露”;
- 统计时单独给出“有效测试覆盖率”(仅按 `available_tools` 计算)。

## 前置步骤:Capabilities 驱动门禁

读取 `capabilities get` 后,提取并缓存:

- `api.app_info.supported`
- `api.tag_search.supported`
- `api.property_list.supported`
- `api.property_get.supported`

动态执行规则:
- 若上述字段为 `false`,对应测试项直接标记 ⚠️("当前 Logseq 能力不可用"),不再执行且不计入 ❌;
- 若字段缺失(旧版 capabilities 输出),按“未知能力”处理:允许执行 1 次,失败后再判定;
- 若 `connection_info.tokenConfigured=false`,直接判定 Phase A 阻塞。

建议映射关系:
- `graph_app-info` ← `api.app_info.supported`
- `tag_search` ← `api.tag_search.supported`
- `property_list` ← `api.property_list.supported`
- `property_get/upsert/remove`(若执行)← `api.property_get.supported`

## 固定流程

1. 读取 `capabilities get`:
- 提取 `connection_info.tokenConfigured`
- 提取 `api.app_info/tag_search/property_list/property_get.supported`
2. 探测本轮工具暴露:生成 `available_tools` / `unavailable_tools`
3. 执行 Phase A(只读)并做门禁判定
4. 若 Phase A 无 ❌,执行 Phase B(混合)
5. 汇总 Phase C:
- 总表(✅/⚠️/❌)
- 写入链路通过率
- 有效测试覆盖率
- 与上轮对比(若有基线)

## 测试模式(完整流程)

### Phase A:只读基线测试(必跑)

- 目标:验证连接、查询、搜索、只读页面/块读取链路是否稳定。
- 范围:连接与图谱基础、页面操作、搜索与查询、标签与属性、Block 只读。
- 门禁:
- 若 `❌ = 0`,进入 Phase B。
- 若 `❌ > 0`,先输出失败归因与修复建议,再决定是否继续。

补充:
- 仅对 `available_tools` 做门禁判定;
- 若某关键项不可用(例如 `capabilities_get`),直接判定 Phase A 阻塞;
- 若 Capabilities 明确声明某能力不支持,则相关测试项按 ⚠️ 跳过,不作为失败。

### Phase B:混合测试(读 + 安全写)

- 目标:验证关键写路径与读回一致性(优先安全写接口)。
- 原则:
- 优先 `dry-run`,再最小写入验证;
- 若写策略为 `read-only` 且无法提升权限,标记 ⚠️ 并跳过写入;
- 测试数据使用固定前缀:`mcp-test-`;
- 若写接口可用但被策略降级为 dry-run,记为“受策略限制通过”(⚠️,非 ❌)。

建议最小写入用例(按顺序):
1. `mcp_logseq_page_append-safe`:`dry-run=true`,再 `confirm=true`。
2. `mcp_logseq_block_append`:在 `mcp-test-*` 页面追加 block。
3. `mcp_logseq_block_update`:更新刚写入的 block 内容。
4. `mcp_logseq_block_get`:读回核对内容一致性。
5. `mcp_logseq_block_remove`:删除测试 block(若支持)。

注意:
- 若 `page_append-safe` 目标页不存在,可先用 `block_append` 创建测试页后重试;
- 若 `block_remove` 不可用,允许保留残留并记录 UUID。

清理策略(best-effort):
- 优先删除测试 block;
- 无法删除时,至少在备注里记录残留对象(page / block uuid)。

### Phase C:完整回归结论

- 合并 Phase A + Phase B 结果,输出统一总表与趋势对比。
- 额外输出:
- 写入链路通过率(写入相关 ✅ / 总写入项)
- 是否存在残留测试数据
- 有效测试覆盖率(可用工具中已执行项 / 可用工具总数)

## 状态判定标准

- ✅ 正常返回,且结果结构符合预期
- ⚠️ 预期内限制(例如:未打开页面、未选择块、DSL 有能力限制、需要参数)
- ❌ 异常错误(需排查,可能是 API 版本限制、参数问题、CLI 实现问题或环境问题)

补充判定:
- 工具未暴露/不可调用:⚠️(不计入失败率)
- 策略限制导致仅 dry-run:⚠️(不计入实现失败)
- capabilities 明确不支持:⚠️(不计入实现失败)

## 输出格式(必须)

### 1) 结论摘要
- 一句话总览:`✅ x / ⚠️ y / ❌ z`
- 是否允许进入/完成混合测试

### 2) 当前轮次总表
| 功能 | 状态 | 备注 |

并给出:
- 写入链路通过率:`write_pass / write_total`(未执行写入则 N/A)
- 有效测试覆盖率:`executed_available / total_available`

### 3) 门禁快照
- tokenConfigured
- app_info/tag_search/property_list/property_get 支持状态
- 因门禁跳过项

### 4) 可用性探测
- available_tools
- unavailable_tools
- 未暴露数量

### 5) 混合测试与清理
- 写入链路通过率
- 残留对象列表(如有)

### 6) 差异对比
- 新增失败 / 已修复 / 状态变化

### 7) 本轮执行轨迹(简版)
- Phase A:通过 / 阻塞(原因)
- Phase B:已执行 / 跳过(原因)
- 清理结果:成功 / 部分成功 / 未执行

### 8) 失败归因模板(每个 ❌ 一条)
- 工具:
- 错误原文:
- 归因:`API 版本限制` / `参数问题` / `CLI 实现问题` / `环境问题`
- 建议修复:

## 失败归因优先级
1. 工具未暴露(会话层)
2. capability unavailable(API/图模式层)
3. 参数/调用错误(测试脚本层)
4. CLI 实现问题(代码层)
67 changes: 67 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 项目指南

## 架构

Logseq HTTP API 的 Go CLI 工具。单模块,三层结构:

| 层级 | 路径 | 职责 |
|------|------|------|
| CLI 命令 | `cmds/` | 按领域一个文件(`page.go`、`block.go`、`tag.go` 等) |
| SDK 客户端 | `pkg/logseq/` | HTTP JSON-RPC 客户端、类型定义、editor/app/tags/db API |
| WebUI | `internal/webui/` | 内嵌 SPA(`go:embed`),handler 按领域拆分文件 |

CLI 框架使用 **`github.com/pubgo/redant`**(非 cobra)。命令返回 `*redant.Command` 树。大多数使用 `ResponseHandler: redant.Unary(...)` 返回 `*llmEnvelope` 实现结构化 JSON 输出。

## 构建与测试

```sh
go build ./... # 编译
go test ./... -count=1 # 单元测试(不使用缓存)
golangci-lint run ./... # lint(配置:.golangci.yml)
go install -v . # 安装为 `logseq` 二进制
```

本地开发需要 `go.work` 引用 `../redant`。CI 会自动去除本地 replace 指令。

E2E 测试(`cmd/e2e/`)需要运行中的 Logseq 实例,不属于常规 `go test` 范围。

## 约定

### 命令结构

每个领域导出 `XxxCmd() *redant.Command`(公开),内部以私有函数定义子命令:

```go
func PageCmd() *redant.Command {
return &redant.Command{
Use: "page", Short: "...",
Children: []*redant.Command{pageListCmd(), pageGetCmd(), ...},
}
}
```

参数使用 `redant.ArgSet` / `redant.OptionSet`,不使用 cobra 风格的 flags。

### LLM 安全

写操作通过 `llm_safety.go` 中的 `ensureWriteAllowed()` 进行保护。相关环境变量:
- `LOGSEQ_LLM_WRITE_MODE`:`read-only`(默认)/ `confirm` / `direct`
- `LOGSEQ_LLM_REQUIRE_CONFIRM_FOR_DELETE`:`true`(默认)

### WebUI 处理器

Handler 文件按领域拆分:`handler_page.go`、`handler_block.go`、`handler_search.go` 等。核心基础设施(Server 结构体、路由、写入辅助函数)保留在 `server.go` 中。

### 测试

- 单元测试:与源码同包的 `_test.go` 文件
- 纯函数(解析、过滤、envelope 构造)必须有测试覆盖
- E2E 冒烟测试通过 `LOGSEQ_E2E=1` 环境变量控制

## 关键环境变量

| 变量 | 必需 | 默认值 | 用途 |
|------|------|--------|------|
| `LOGSEQ_API_TOKEN` | 是 | — | Logseq API Bearer 令牌 |
| `LOGSEQ_HOST` | 否 | `127.0.0.1` | API 主机地址 |
| `LOGSEQ_PORT` | 否 | `12315` | API 端口 |
119 changes: 119 additions & 0 deletions .github/instructions/cmds.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
applyTo: "cmds/**"
---

# cmds 包编码指南

## 命令结构

每个领域一个文件,导出 `XxxCmd() *redant.Command`,子命令用私有函数:

```go
func PageCmd() *redant.Command {
return &redant.Command{
Use: "page", Short: "页面管理",
Children: []*redant.Command{pageListCmd(), pageGetCmd()},
}
}

func pageListCmd() *redant.Command {
return &redant.Command{
Use: "list",
Short: "列出所有页面",
ResponseHandler: redant.Unary(func(ctx context.Context, inv *redant.Invocation) ([]logseq.Page, error) {
client := NewClient()
return client.GetAllPages(ctx)
}),
}
}
```

小型子命令可直接在 `Children` 内联定义,不必抽独立函数。

## 参数定义

位置参数用 `ArgSet`,标志参数用 `OptionSet`(闭包外声明变量,指针绑定):

```go
var sibling bool
return &redant.Command{
Args: redant.ArgSet{
{Name: "name", Required: true, Value: redant.StringOf(new(string)), Description: "页面名称"},
},
Options: redant.OptionSet{
{Flag: "sibling", Shorthand: "s", Description: "作为兄弟节点插入", Value: redant.BoolOf(&sibling)},
},
}
```

Value 构造器:`redant.StringOf(&s)`、`redant.BoolOf(&b)`。

## ResponseHandler 选择

- **主流**:`ResponseHandler: redant.Unary(...)` — 自动 JSON 序列化,返回结构体/slice/map/`*llmEnvelope` 均可
- **手动输出**:`Handler: func(ctx, inv) error` — 用于需要 `json.RawMessage` 或自定义格式的场景

## Client 获取

每个 handler 中调用 `client := NewClient()`,不复用全局实例。

## LLM Envelope(结构化输出)

需要结构化输出的命令返回 `*llmEnvelope`:

```go
start := time.Now()
// 业务逻辑...
return envelopeSuccess(start, data,
withCapabilityUsed("logseq.Editor.getPage"),
withHints("提示信息"),
), nil
```

错误时:

```go
return envelopeFailure(start, err, "BAD_REQUEST", "请提供页面名",
withCapabilityUsed("logseq.Editor.getPage"),
), nil
```

错误码:`SAFETY_BLOCKED`、`BAD_REQUEST`、`RESOURCE_NOT_FOUND`、`CAPABILITY_UNAVAILABLE`、`TIMEOUT`、`UPSTREAM_ERROR`。空字符串由 `classifyEnvelopeErrorCode(err)` 自动分类。

Option 函数:`withCapabilityUsed()`、`withHints()`、`withPageMeta(cursor, hasMore)`、`withFallbackUsed()`。

## LLM 写操作安全

写操作必须调用 `ensureWriteAllowed`,失败时返回 `SAFETY_BLOCKED` envelope:

```go
if err := ensureWriteAllowed("page.append-safe", dryRun, confirm, false); err != nil {
return envelopeFailure(start, err, "SAFETY_BLOCKED", "可先使用 --dry-run"), nil
}
```

- `action` 格式:`"domain.operation"`
- `dangerous=true` 用于删除操作
- 配合 `--dry-run` 和 `--confirm` OptionSet 标志

## 测试规范

- 文件:同包 `_test.go`(如 `llm_safety_test.go`)
- 风格:表驱动(table-driven)+ `t.Run` 子测试
- 范围:测试纯函数(解析、分类、构造、过滤),不测试需要 Logseq 实例的 handler
- 环境变量:用 `t.Setenv()` 隔离

## 常用 Import

```go
import (
"context"
"fmt"
"time"
"strings"
"encoding/json"

"github.com/pubgo/redant"
"github.com/pubgo/logseq-cli/pkg/logseq"
)
```
25 changes: 25 additions & 0 deletions .github/prompts/test-mcp-readonly.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
description: "运行 Logseq MCP 只读回归(Phase A smoke)"
agent: "Logseq MCP Regression"
---

# 测试 Logseq MCP(只读)

使用专用 Agent `Logseq MCP Regression` 执行只读回归(Phase A)。

## 默认参数

- scope: `readonly`
- mixed-write: `off`
- baseline: 可选(用于对比)

## 期望输出

1. 当前轮次总表(✅/⚠️/❌)
2. Capabilities 门禁快照与跳过项
3. 可用性探测(available/unavailable)
4. 有效测试覆盖率
5. 与上次结果对比(新增失败 / 已修复 / 状态变化)

> 规则细节统一维护在:
> `.github/agents/logseq-mcp-regression.agent.md`
Loading
Loading