fix: initialize and sync notebook config on startup
Publish to npm / publish (push) Successful in 29s
Publish to npm / publish (push) Successful in 29s
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
- **渐进式披露**:初始仅激活一个 `siyuan_discover` loader 工具(含连通性检查),其余 15 个工具按需增量加载,保持系统提示词前缀稳定
|
- **渐进式披露**:初始仅激活一个 `siyuan_discover` loader 工具(含连通性检查),其余 15 个工具按需增量加载,保持系统提示词前缀稳定
|
||||||
- **笔记本级 RWD 权限审计**:R 读 / W 写 / D 破坏性(rollback、move 移出、删除类),可自由组合;`NONE` = 禁止一切操作
|
- **笔记本级 RWD 权限审计**:R 读 / W 写 / D 破坏性(rollback、move 移出、删除类),可自由组合;`NONE` = 禁止一切操作
|
||||||
- 拒绝消息包含:目标笔记本(id+name)、需要的权限、缺失的权限、被拒绝的操作名
|
- 拒绝消息包含:目标笔记本(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"]`(禁止一切操作)
|
- `permissions`:`R`/`W`/`D` 自由组合,或 `["NONE"]`(禁止一切操作)
|
||||||
- `name` 仅做 human-readable,一切逻辑按 `id` 匹配
|
- `name` 仅做 human-readable,一切逻辑按 `id` 匹配
|
||||||
- 首次调用 `list_notebooks` 会把未记录的笔记本以 `["R"]` 补写进该文件
|
- Pi 启动时会创建该配置文件并同步笔记本;调用 `list_notebooks` 时也会再次同步。未记录的笔记本以 `["R"]` 补写,已有笔记本名称变化时更新 `name`
|
||||||
|
|
||||||
### 权限规则速查
|
### 权限规则速查
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "pi-siyuan",
|
"name": "pi-siyuan",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pi-siyuan",
|
"name": "pi-siyuan",
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"typebox": "1.3.7"
|
"typebox": "1.3.7"
|
||||||
|
|||||||
+3
-3
@@ -5,8 +5,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"typebox": "1.3.7"
|
"typebox": "1.3.7"
|
||||||
},
|
},
|
||||||
"version": "0.1.2",
|
"version": "0.1.3",
|
||||||
"description": "SiYuan Note extension for pi coding agent \u2014 HTTP API wrapper with notebook-level RWD permission auditing",
|
"description": "SiYuan Note extension for pi coding agent — HTTP API wrapper with notebook-level RWD permission auditing",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"pi-package",
|
"pi-package",
|
||||||
"pi-extension",
|
"pi-extension",
|
||||||
@@ -40,4 +40,4 @@
|
|||||||
"check": "node --experimental-strip-types --no-warnings src/audit.test.ts"
|
"check": "node --experimental-strip-types --no-warnings src/audit.test.ts"
|
||||||
},
|
},
|
||||||
"prepublishOnly": "node --experimental-strip-types --no-warnings src/audit.test.ts"
|
"prepublishOnly": "node --experimental-strip-types --no-warnings src/audit.test.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import assert from "node:assert";
|
import assert from "node:assert";
|
||||||
|
import { existsSync, rmSync } from "node:fs";
|
||||||
import {
|
import {
|
||||||
permsOf,
|
permsOf,
|
||||||
auditNotebook,
|
auditNotebook,
|
||||||
auditAny,
|
auditAny,
|
||||||
auditAll,
|
auditAll,
|
||||||
denyMessage,
|
denyMessage,
|
||||||
|
loadConfig,
|
||||||
syncNotebooks,
|
syncNotebooks,
|
||||||
} from "./audit.ts";
|
} from "./audit.ts";
|
||||||
|
|
||||||
@@ -87,6 +89,19 @@ assert.ok(
|
|||||||
assert.ok(msg.includes("get_document_content"), "含操作名");
|
assert.ok(msg.includes("get_document_content"), "含操作名");
|
||||||
assert.ok(/需要 R/.test(msg) && /缺失 R/.test(msg), "含需要/缺失权限");
|
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 条)— 用临时路径,不污染真实配置 ----
|
// ---- syncNotebooks(第 10 条)— 用临时路径,不污染真实配置 ----
|
||||||
const cfg: any = {
|
const cfg: any = {
|
||||||
apiUrl: "u",
|
apiUrl: "u",
|
||||||
|
|||||||
+9
-5
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
||||||
import { homedir } from "node:os";
|
import { homedir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { dirname, join } from "node:path";
|
||||||
import type { SiYuanClient } from "./siyuan-client.ts";
|
import type { SiYuanClient } from "./siyuan-client.ts";
|
||||||
|
|
||||||
export type Perm = "R" | "W" | "D";
|
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 } {
|
export function resolveConnection(): { apiUrl: string; token: string } {
|
||||||
@@ -121,9 +127,7 @@ export function syncNotebooks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function saveConfig(cfg: PiSiyuanConfig, cfgPath: string = CONFIG_PATH) {
|
export function saveConfig(cfg: PiSiyuanConfig, cfgPath: string = CONFIG_PATH) {
|
||||||
mkdirSync(join(homedir(), ".pi/agent/extensions/pi-siyuan"), {
|
mkdirSync(dirname(cfgPath), { recursive: true });
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -422,11 +422,16 @@ export default function siyuanExtension(pi: ExtensionAPI) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始只激活 loader(渐进式披露)
|
// 初始只激活 loader(渐进式披露),并同步笔记本权限配置
|
||||||
pi.on("session_start", () => {
|
pi.on("session_start", async () => {
|
||||||
const initial = pi
|
const initial = pi
|
||||||
.getActiveTools()
|
.getActiveTools()
|
||||||
.filter((name) => !SIYUAN_TOOL_NAMES.has(name));
|
.filter((name) => !SIYUAN_TOOL_NAMES.has(name));
|
||||||
pi.setActiveTools([...new Set([...initial, "siyuan_discover"])]);
|
pi.setActiveTools([...new Set([...initial, "siyuan_discover"])]);
|
||||||
|
try {
|
||||||
|
syncNotebooks(cfg, await client.lsNotebooks());
|
||||||
|
} catch {
|
||||||
|
// SiYuan 离线不应阻止 Pi 启动;工具调用时会返回连接错误
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user