diff --git a/README.md b/README.md index 099356b..b956055 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ - **渐进式披露**:初始仅激活一个 `siyuan_discover` loader 工具(含连通性检查),其余 15 个工具按需增量加载,保持系统提示词前缀稳定 - **笔记本级 RWD 权限审计**:R 读 / W 写 / D 破坏性(rollback、move 移出、删除类),可自由组合;`NONE` = 禁止一切操作 - 拒绝消息包含:目标笔记本(id+name)、需要的权限、缺失的权限、被拒绝的操作名 -- 新笔记本自动以 `R` 权限同步进配置文件(发现入口 `list_notebooks`,审计豁免) +- Pi 启动及调用 `list_notebooks` 时自动同步笔记本;新笔记本以 `R` 权限写入配置文件(审计豁免) - 连接信息:环境变量优先,配置文件兜底 ## 安装 @@ -64,7 +64,7 @@ export SIYUAN_TOKEN="your-api-token" # SiYuan 设置 → 关于 - `permissions`:`R`/`W`/`D` 自由组合,或 `["NONE"]`(禁止一切操作) - `name` 仅做 human-readable,一切逻辑按 `id` 匹配 -- 首次调用 `list_notebooks` 会把未记录的笔记本以 `["R"]` 补写进该文件 +- Pi 启动时会创建该配置文件并同步笔记本;调用 `list_notebooks` 时也会再次同步。未记录的笔记本以 `["R"]` 补写,已有笔记本名称变化时更新 `name` ### 权限规则速查 diff --git a/package-lock.json b/package-lock.json index d0e36c5..bfbd71d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pi-siyuan", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pi-siyuan", - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "dependencies": { "typebox": "1.3.7" diff --git a/package.json b/package.json index cd4bb52..e4685bb 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "dependencies": { "typebox": "1.3.7" }, - "version": "0.1.2", - "description": "SiYuan Note extension for pi coding agent \u2014 HTTP API wrapper with notebook-level RWD permission auditing", + "version": "0.1.3", + "description": "SiYuan Note extension for pi coding agent — HTTP API wrapper with notebook-level RWD permission auditing", "keywords": [ "pi-package", "pi-extension", @@ -40,4 +40,4 @@ "check": "node --experimental-strip-types --no-warnings src/audit.test.ts" }, "prepublishOnly": "node --experimental-strip-types --no-warnings src/audit.test.ts" -} \ No newline at end of file +} diff --git a/src/audit.test.ts b/src/audit.test.ts index e954bd4..54a800a 100644 --- a/src/audit.test.ts +++ b/src/audit.test.ts @@ -4,12 +4,14 @@ */ import assert from "node:assert"; +import { existsSync, rmSync } from "node:fs"; import { permsOf, auditNotebook, auditAny, auditAll, denyMessage, + loadConfig, syncNotebooks, } from "./audit.ts"; @@ -87,6 +89,19 @@ assert.ok( assert.ok(msg.includes("get_document_content"), "含操作名"); assert.ok(/需要 R/.test(msg) && /缺失 R/.test(msg), "含需要/缺失权限"); +// ---- 配置首次加载自动初始化 ---- +const initDir = "/tmp/pi-siyuan-audit-test"; +const initPath = `${initDir}/nested/config.json`; +rmSync(initDir, { recursive: true, force: true }); +const initialized = loadConfig(initPath); +assert.equal(existsSync(initPath), true, "配置文件应在首次加载时创建"); +assert.deepEqual(initialized, { + apiUrl: "http://127.0.0.1:6806", + token: "", + notebooks: [], +}); +rmSync(initDir, { recursive: true, force: true }); + // ---- syncNotebooks(第 10 条)— 用临时路径,不污染真实配置 ---- const cfg: any = { apiUrl: "u", diff --git a/src/audit.ts b/src/audit.ts index 8b01d4e..716af84 100644 --- a/src/audit.ts +++ b/src/audit.ts @@ -5,7 +5,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; -import { join } from "node:path"; +import { dirname, join } from "node:path"; import type { SiYuanClient } from "./siyuan-client.ts"; export type Perm = "R" | "W" | "D"; @@ -86,7 +86,13 @@ export function loadConfig(cfgPath: string = CONFIG_PATH): PiSiyuanConfig { // 损坏则重建 } } - return { apiUrl: "", token: "", notebooks: [] }; + const cfg = { + apiUrl: "http://127.0.0.1:6806", + token: "", + notebooks: [], + }; + saveConfig(cfg, cfgPath); + return cfg; } export function resolveConnection(): { apiUrl: string; token: string } { @@ -121,9 +127,7 @@ export function syncNotebooks( } export function saveConfig(cfg: PiSiyuanConfig, cfgPath: string = CONFIG_PATH) { - mkdirSync(join(homedir(), ".pi/agent/extensions/pi-siyuan"), { - recursive: true, - }); + mkdirSync(dirname(cfgPath), { recursive: true }); writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n"); } diff --git a/src/index.ts b/src/index.ts index 6e48427..c6cde0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -422,11 +422,16 @@ export default function siyuanExtension(pi: ExtensionAPI) { }, }); - // 初始只激活 loader(渐进式披露) - pi.on("session_start", () => { + // 初始只激活 loader(渐进式披露),并同步笔记本权限配置 + pi.on("session_start", async () => { const initial = pi .getActiveTools() .filter((name) => !SIYUAN_TOOL_NAMES.has(name)); pi.setActiveTools([...new Set([...initial, "siyuan_discover"])]); + try { + syncNotebooks(cfg, await client.lsNotebooks()); + } catch { + // SiYuan 离线不应阻止 Pi 启动;工具调用时会返回连接错误 + } }); }