From 902b45955cb8861e279e3c965c776ed6ffa0598c Mon Sep 17 00:00:00 2001 From: xingleiwu Date: Mon, 14 Sep 2026 05:53:42 +0800 Subject: [PATCH] =?UTF-8?q?feat(pi.workspace-file-guard):=200.2.7=20?= =?UTF-8?q?=E6=94=B9=E5=90=8D=E4=B8=BA=E3=80=8CC=E7=9B=98=E9=98=B2?= =?UTF-8?q?=E5=9E=83=E5=9C=BE=E3=80=8D=EF=BC=8C=E5=9E=83=E5=9C=BE=E6=94=B9?= =?UTF-8?q?=E6=94=BE=E5=88=B0=20Temp/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 市场名称改为更礼貌的「C盘防垃圾」 - 项目垃圾倾倒目录从 .tmp 改为 $project/Temp/ - 工作区落在 Temp 里时回退到拥有它的项目根 - 拒绝把桌面、系统临时目录、AppData、Windows 等当作项目根 - 用 LF 源码打包,保证 CI compare_package_to_source 字节一致 --- catalog.json | 245 +++++------------- packages/pi.workspace-file-guard-0.2.7.piplug | Bin 0 -> 42134 bytes plugins/pi.workspace-file-guard/README.md | 10 +- plugins/pi.workspace-file-guard/guard.js | 105 +++++++- plugins/pi.workspace-file-guard/main.js | 148 ++++++----- plugins/pi.workspace-file-guard/manifest.json | 85 ++++-- .../references/denied-paths.md | 8 +- .../skills/workspace-file-guard.md | 43 +-- tests/workspace-file-guard-guard.test.js | 36 ++- tests/workspace-file-guard-main.test.js | 2 +- 10 files changed, 368 insertions(+), 314 deletions(-) create mode 100644 packages/pi.workspace-file-guard-0.2.7.piplug diff --git a/catalog.json b/catalog.json index 1ff631e..bcd040f 100644 --- a/catalog.json +++ b/catalog.json @@ -2,7 +2,7 @@ "schemaVersion": 1, "providerId": "official", "name": "PI-Desktop Official Plugins", - "updatedAt": "2026-09-13T13:55:42Z", + "updatedAt": "2026-09-13T21:50:52Z", "homepage": "https://github.com/vastsa/pi-desktop-plugins", "plugins": [ { @@ -35,7 +35,7 @@ "versions": [ { "version": "0.3.3", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.3.3: fills the v3 panel surface, improves responsive spacing and focus states, and keeps the host window-control capsule synchronized with theme changes. Release 0.3.2: migrates the panel to v3 paint-through chrome so top-band controls remain clickable while blank space remains draggable. Release 0.3.1: refreshes the panel surface to match PI-Desktop's compact neutral design system.", "minPiDesktop": ">=0.2.0", "shasum": "6c3d3fcded92d15ab78552671fcac4687e26324d8ac6ed5df5452dffb153ee4b", @@ -81,7 +81,7 @@ "versions": [ { "version": "0.2.3", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.2.3: makes the editor use the full panel height with a stable responsive action row and synchronized host capsule colors. Release 0.2.2: migrates the panel to v3 paint-through chrome so top-band controls remain clickable while blank space remains draggable. Release 0.2.1: refreshes the notes panel controls, editor surface, focus states, and responsive spacing.", "minPiDesktop": ">=0.2.0", "shasum": "7a094cba0dc998ec4d628b4abfe731b7fd44a9af79f89e5e99ad370832d83a65", @@ -133,7 +133,7 @@ "versions": [ { "version": "0.2.3", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.2.3: lets the summary output fill the remaining panel height, keeps its internal scroll local, and synchronizes the host capsule with theme changes. Release 0.2.2: migrates the panel to v3 paint-through chrome so top-band controls remain clickable while blank space remains draggable. Release 0.2.1: refreshes the summary panel hierarchy, cards, controls, and narrow-window layout. Initial practical template: workspace inventory, README preview, copy summary, agent tool.", "minPiDesktop": ">=0.2.0", "shasum": "41d951ab4d95ead69f4f9a7d6fb0ba18a560185919fca7ce076c13e8c4d84711", @@ -150,76 +150,6 @@ } ] }, - { - "id": "io.github.muzimu217.deps-audit", - "name": "Deps Audit", - "description": "\u4f9d\u8d56\u6f0f\u6d1e\u626b\u63cf\uff1a\u5524\u8d77 osv-scanner \u626b\u63cf\u5de5\u4f5c\u533a\uff0c\u5217\u51fa OSV \u6570\u636e\u5e93\u4e2d\u7684\u4f9d\u8d56\u6f0f\u6d1e\uff0c\u8ba9 Agent \u7ed9\u51fa\u5347\u7ea7\u6216\u4fee\u590d patch\u3002", - "i18n": { - "en": { - "name": "Deps Audit", - "description": "Dependency vulnerability audit: invoke osv-scanner over the workspace, list known OSV matches, and let the Agent propose a fix or upgrade.", - "safetyNotes": "Reads only the workspace-root dependency manifests listed in the declared fs.read scope (package.json, lockfiles, requirements.txt, Cargo.toml/lock, go.mod/sum, pom.xml, composer.json/lock, Gemfile/lock, pyproject.toml) through the host fs gateway, stages sanitized copies in a throwaway temp directory, and spawns the local osv-scanner binary against that directory \u2014 the spawned binary never reads the workspace directly and contacts the OSV database over the network (declared High-risk capability). Staging copies are deleted after each scan. Nothing in the workspace is ever written." - }, - "zh-CN": { - "name": "\u4f9d\u8d56\u5ba1\u8ba1", - "description": "\u4f9d\u8d56\u6f0f\u6d1e\u626b\u63cf\uff1a\u5524\u8d77 osv-scanner \u626b\u63cf\u5de5\u4f5c\u533a\uff0c\u5217\u51fa OSV \u6570\u636e\u5e93\u4e2d\u7684\u4f9d\u8d56\u6f0f\u6d1e\uff0c\u8ba9 Agent \u7ed9\u51fa\u5347\u7ea7\u6216\u4fee\u590d patch\u3002", - "safetyNotes": "Reads only the workspace-root dependency manifests listed in the declared fs.read scope (package.json, lockfiles, requirements.txt, Cargo.toml/lock, go.mod/sum, pom.xml, composer.json/lock, Gemfile/lock, pyproject.toml) through the host fs gateway, stages sanitized copies in a throwaway temp directory, and spawns the local osv-scanner binary against that directory \u2014 the spawned binary never reads the workspace directly and contacts the OSV database over the network (declared High-risk capability). Staging copies are deleted after each scan. Nothing in the workspace is ever written." - } - }, - "author": "muzimu217", - "categories": [ - "security", - "developer-tools", - "audit" - ], - "verified": true, - "downloads": 0, - "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/io.github.muzimu217.deps-audit", - "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# Deps Audit \u2014 io.github.muzimu217.deps-audit\n\n\u4f9d\u8d56\u6f0f\u6d1e\u626b\u63cf\uff1a\u628a\u5de5\u4f5c\u533a\u4ea4\u7ed9 [osv-scanner](https://github.com/google/osv-scanner)\uff0c\n\u628a\u7ed3\u679c\u4ee5 OSV \u6570\u636e\u5e93\u7684\u5206\u7c7b\u4e0e\u4e25\u91cd\u5ea6\u5c55\u793a\u5728\u5de5\u4f5c\u9762\u677f\u91cc\uff1b\u9009\u4e2d\u4e00\u6761\uff0cAgent \u7ed9\u51fa**\u6700\u5c0f\u5347\u7ea7\u6216\u4fee\u590d\u65b9\u6848**\n\uff08\u4e0d\u4f1a\u81ea\u52a8\u6539\u4efb\u4f55\u6587\u4ef6\uff0c\u5fc5\u987b\u4f60\u786e\u8ba4\uff09\u3002\n\n## \u5b89\u5168\u6a21\u578b\uff08\u5a01\u80c1\u6a21\u578b\uff09\n\nDeps Audit \u89e6\u53ca\u4e24\u7c7b\u9ad8\u6743\u80fd\u529b\uff1a**\u539f\u751f\u8fdb\u7a0b\u6267\u884c**\uff08osv-scanner\uff09\u4e0e**\u7f51\u7edc**\uff08osv-scanner\n\u81ea\u884c\u8bbf\u95ee OSV \u6570\u636e\u5e93\uff09\u3002\u6309\u4ed3\u5e93 SECURITY.md \u8fd9\u662f High \u98ce\u9669\u6863\uff0c\u63d2\u4ef6\u7684\u7ea6\u675f\u8bbe\u8ba1\uff1a\n\n1. **\u5de5\u4f5c\u533a\u8bfb\u53d6\u53ea\u8d70\u5bbf\u4e3b\u7f51\u5173**\uff1a\u6e05\u5355\u6587\u4ef6\u901a\u8fc7 `pi.fs.readText` \u8bfb\u53d6\uff0c\u4f5c\u7528\u57df\u5728\n manifest \u7684 `fs.read` \u58f0\u660e\u91cc\u9010\u6587\u4ef6\u5217\u51fa\uff08package.json\u3001\u5404\u8bed\u8a00\u9501\u6587\u4ef6\u7b49\uff09\uff0c\n \u5de5\u4f5c\u533a\u5176\u4f59\u5185\u5bb9\u5bf9\u63d2\u4ef6\u4e0d\u53ef\u89c1\u3002\n2. **\u539f\u751f\u4e8c\u8fdb\u5236\u6c38\u4e0d\u76f4\u63a5\u63a5\u89e6\u5de5\u4f5c\u533a**\uff1a\u8bfb\u53d6\u5230\u7684\u6e05\u5355\u5185\u5bb9\u4ee5\u51c0\u5316\u526f\u672c\u5f62\u5f0f\u5199\u5165\u4e00\u6b21\u6027\n \u4e34\u65f6\u76ee\u5f55\uff0cosv-scanner \u53ea\u88ab\u5141\u8bb8\u626b\u63cf\u8be5\u76ee\u5f55\uff1b\u626b\u63cf\u7ed3\u675f\u540e\u526f\u672c\u5373\u88ab\u5220\u9664\u3002\n3. **\u7f51\u7edc\u8fb9\u754c**\uff1a\u63d2\u4ef6\u8fdb\u7a0b\u81ea\u8eab\u96f6\u7f51\u7edc\u8bf7\u6c42\uff1b\u5bf9 OSV \u6570\u636e\u5e93\u7684\u8bbf\u95ee\u7531 osv-scanner\n \u4e8c\u8fdb\u5236\u81ea\u884c\u5b8c\u6210\uff08\u8fd9\u662f\u5b83\u4f5c\u4e3a\u626b\u63cf\u5668\u7684\u6838\u5fc3\u529f\u80fd\uff09\u3002\n4. **\u53ea\u8bfb\u627f\u8bfa**\uff1a\u5de5\u4f5c\u533a\u6c38\u4e0d\u88ab\u5199\u5165\uff1b\u9009\u4e2d\u6f0f\u6d1e\u540e\u300c\u8bf7 Agent \u4fee\u590d\u300d\u6c38\u8fdc\u9700\u8981\u7528\u6237\n \u663e\u5f0f\u53d1\u8d77\uff0c\u63d2\u4ef6\u53ea\u751f\u6210\u8bf7\u6c42\u6587\u672c\u3002\n5. **\u5931\u8d25\u53ef\u89c1**\uff1a\u4e8c\u8fdb\u5236\u7f3a\u5931/\u635f\u574f\u3001\u626b\u63cf\u8d85\u65f6\u3001\u975e\u96f6\u9000\u51fa\u3001\u8f93\u51fa\u4e0d\u53ef\u89e3\u6790\u90fd\u6709\u660e\u786e\u7684\n \u7ed3\u6784\u5316\u9519\u8bef\u4e0e\u6d4b\u8bd5\u8986\u76d6\uff0c\u4e0d\u4f1a\u9759\u9ed8\u541e\u6389\u3002\n\n## \u4e3a\u4ec0\u4e48\u9700\u8981\u8fd9\u4e2a\u63d2\u4ef6\n\nPI-Desktop \u7684 `pi.advisor` \u5df2\u7ecf\u5728\u505a\"second opinion reviewer\"\uff0c\u4f46**\u6ca1\u6709\u63d2\u4ef6\u505a\"\u628a\u5de5\u4f5c\u533a\n\u4ea4\u7ed9\u4e00\u4e2a\u771f\u5b9e\u7684\u4f9d\u8d56\u626b\u63cf\u5668\uff0c\u518d\u7528 Agent \u89e3\u8bfb\u7ed3\u679c\"\u8fd9\u4e00\u6bb5**\u3002OSV.dev \u662f Google \u7ef4\u62a4\u7684\u5f00\u653e\u6f0f\u6d1e\n\u6570\u636e\u5e93\uff0c\u8986\u76d6 npm / PyPI / crates.io / Go / Maven / Composer / RubyGems\uff0c\u4e14 osv-scanner \u662f\nApache-2.0 \u7684\u7eaf\u672c\u5730 CLI\u2014\u2014\u975e\u5e38\u9002\u5408\u4f5c\u4e3a\"\u5b89\u5168\u4fa7\"\u8f93\u5165\u3002\n\n## \u5b89\u88c5\n\nDeps Audit **\u4e0d\u5f3a\u4f9d\u8d56** osv-scanner \u4e8c\u8fdb\u5236\u5b58\u5728\uff1b\u5982\u679c\u6ca1\u88c5\uff0c\u5b83\u4f1a\u7ed9\u51fa\u660e\u786e\u6307\u5f15\uff08\u8be6\u89c1\n\u6545\u969c\u6392\u67e5\uff09\u3002\u6700\u7a33\u7684\u5b89\u88c5\u65b9\u5f0f\uff1a\n\n```bash\n# \u65b9\u5f0f 1: Homebrew (macOS / Linux)\nbrew install osv-scanner\n\n# \u65b9\u5f0f 2: Go\ngo install github.com/google/osv-scanner/v2/cmd/osv-scanner@latest\n\n# \u65b9\u5f0f 3: GitHub release\uff08\u6ce8\u610f macOS \u9700 ad-hoc \u7b7e\u540d\u6216\u4e0b\u8f7d\u672a\u538b\u7f29\u7684 brew bottle\uff09\n# https://github.com/google/osv-scanner/releases\n```\n\n## \u4f7f\u7528\n\n\u6253\u5f00 PI-Desktop\uff0c\u5728\u5de5\u4f5c\u9762\u677f\u91cc\u70b9 **Deps Audit**\uff08\u76fe\u724c\u56fe\u6807\uff09\uff0c\u6216\uff1a\n\n- **\u547d\u4ee4\u9762\u677f**\uff08`Cmd+K` / `Ctrl+K`\uff09\uff1a\n - `Deps Audit: Open Work-Panel View` \u2014 \u6253\u5f00\u9762\u677f\n - `Deps Audit: Scan Workspace Now` \u2014 \u7acb\u5373\u626b\u63cf\n- **Agent \u5de5\u5177**\uff1a`deps_audit_run` \u2014 Agent \u5728\u9700\u8981\u65f6\u53ef\u4ee5\u4e3b\u52a8\u8c03\u8d77\u626b\u63cf\n\n## \u5de5\u4f5c\u6d41\u7a0b\n\n1. \u6253\u5f00\u89c6\u56fe\uff0c\u70b9\u51fb\u300c\u626b\u63cf\u300d\n2. \u63d2\u4ef6 spawn \u4f60\u672c\u5730\u7684 `osv-scanner` \u626b\u63cf\u5de5\u4f5c\u533a\u6839\u4e0b\u7684 manifest\uff08`package.json`\u3001\n `requirements.txt`\u3001`Cargo.toml` \u7b49\uff09\n3. osv-scanner \u62c9\u53d6 OSV \u6570\u636e\u5e93\uff08**\u5b83**\u505a\u7684\u7f51\u7edc\u8bf7\u6c42\uff0c**\u63d2\u4ef6\u672c\u8eab\u4e0d\u8054\u7f51**\uff09\uff0c\u8fd4\u56de\u7ed3\u6784\u5316 JSON\n4. \u63d2\u4ef6\u89e3\u6790\u540e\u6309\u4e25\u91cd\u5ea6\uff08Critical \u2192 High \u2192 Medium \u2192 Low\uff09\u5c55\u793a\u5728\u5de5\u4f5c\u9762\u677f\n5. \u9009\u4e2d\u4e00\u6761 \u2192 \u70b9\u51fb\u300c\u590d\u5236\u7ed9 Agent \u8be2\u95ee\u4fee\u590d\u5efa\u8bae\u300d\u2192 \u6587\u672c\u91cc\u5305\u542b\u6f0f\u6d1e\u6458\u8981\u3001\u56fa\u5b9a\u7248\u672c\u3001advisory \u94fe\u63a5\n6. \u7c98\u5230 PI-Desktop \u5bf9\u8bdd\u6846 \u2192 Agent \u5148\u89e3\u91ca\u98ce\u9669\uff0c\u7ed9\u51fa\u6700\u5c0f\u5347\u7ea7\u65b9\u6848\uff0c**\u7b49\u4f60\u786e\u8ba4**\u624d\u6539\u6587\u4ef6\n\n## \u6743\u9650\u8bf4\u660e\n\n| \u6743\u9650 | \u7528\u9014 |\n| --- | --- |\n| `ui.panel` / `ui.view` | \u5de5\u4f5c\u9762\u677f\u89c6\u56fe |\n| `fs.read` | \u7ecf\u5bbf\u4e3b\u7f51\u5173\u8bfb\u53d6\u5de5\u4f5c\u533a\u6839\u76ee\u5f55\u7684\u4f9d\u8d56\u6e05\u5355\uff08\u9010\u6587\u4ef6\u5217\u5728 manifest \u7684 `fs.read` \u4f5c\u7528\u57df\u91cc\uff09\uff0c\u7528\u4e8e\u751f\u6210\u51c0\u5316\u526f\u672c |\n| `clipboard.write` | \u300c\u590d\u5236\u7ed9 Agent\u300d\u7ecf\u5bbf\u4e3b\u526a\u8d34\u677f\u6865\u5199\u5165 |\n| `agent.tool.register` | \u6ce8\u518c `deps_audit_run` \u5de5\u5177\uff08risk: high \u2014\u2014 \u539f\u751f\u6267\u884c + \u8054\u7f51\uff09 |\n\n**\u4e0d**\u58f0\u660e\u3001\u4e5f**\u4e0d**\u4f7f\u7528\u7684\uff1a\n- `agent.complete` / `models.list` \u2014\u2014 \u4fee\u590d\u5efa\u8bae\u7531\u4f60\u5728\u5bf9\u8bdd\u91cc\u5411 Agent \u53d1\u8d77\uff0c\u63d2\u4ef6\u4e0d\u8c03\u7528\u6a21\u578b\u3002\n- `fs.write` / `fs.delete` \u2014\u2014 \u5de5\u4f5c\u533a\u6c38\u4e0d\u88ab\u5199\u5165\u6216\u5220\u9664\u3002\n- `net.fetch` \u2014\u2014 \u63d2\u4ef6\u8fdb\u7a0b\u81ea\u8eab\u96f6\u7f51\u7edc\u8bf7\u6c42\uff1bOSV \u6570\u636e\u5e93\u7531 osv-scanner \u4e8c\u8fdb\u5236\u81ea\u884c\u62c9\u53d6\n \uff08\u8be5\u8054\u7f51\u884c\u4e3a\u5c5e\u4e8e SECURITY.md High \u6863\u7684\u539f\u751f\u6267\u884c\u80fd\u529b\uff0c\u5df2\u5728\u5b89\u5168\u6a21\u578b\u5c0f\u8282\u58f0\u660e\uff09\u3002\n\n## \u652f\u6301\u7684 manifest\n\n`package.json` / `package-lock.json` / `yarn.lock` / `pnpm-lock.yaml` /\n`requirements.txt` / `pyproject.toml` / `Pipfile` /\n`Cargo.toml` / `Cargo.lock` / `go.mod` / `go.sum` /\n`pom.xml` / `composer.json` / `composer.lock` / `Gemfile` / `Gemfile.lock`\n\nAgent \u5de5\u5177 `deps_audit_run` \u53ef\u901a\u8fc7 `manifests` \u53c2\u6570\u6536\u7a84\u8303\u56f4\u3002\n\n## \u8bbe\u7f6e\n\n- `scannerPath` \u2014 `osv-scanner` \u4e8c\u8fdb\u5236\u8def\u5f84\u6216 PATH \u4e2d\u7684\u540d\u5b57\uff08\u9ed8\u8ba4 `osv-scanner`\uff09\n- `severityMin` \u2014 \u4e25\u91cd\u5ea6\u8fc7\u6ee4\uff08`low` / `medium` / `high` / `critical`\uff0c\u9ed8\u8ba4 `low`\uff09\n\n## \u6545\u969c\u6392\u67e5\n\n**\u75c7\u72b6**\uff1a\u626b\u63cf\u540e\u72b6\u6001\u6761\u663e\u793a\"\u51fa\u9519\"\u4e14\u9762\u677f\u9876\u90e8\u7ea2\u8272 banner\n\n\u6700\u5e38\u89c1\u539f\u56e0\uff1a\n\n1. **\u672a\u5b89\u88c5 osv-scanner** \u2192 \u6309\u4e0a\u9762\"\u5b89\u88c5\"\u5c0f\u8282\u88c5\u4e00\u4e2a\uff0c\u6216\u5728\u8bbe\u7f6e\u91cc\u6539 `scannerPath` \u6307\u5411\n \u4f60\u81ea\u5df1\u88c5\u7684\u4e8c\u8fdb\u5236\u3002\n2. **\u8d85\u65f6**\uff08>120 \u79d2\uff09\u2192 \u4ed3\u5e93\u5f88\u5927\u3001\u4f9d\u8d56\u5f88\u591a\u3001\u6216 OSV \u6570\u636e\u5e93\u4e0b\u8f7d\u6162\u3002\u53ef\u624b\u52a8\u5148\u8dd1\n `osv-scanner scan source --format json .` \u770b\u8017\u65f6\u3002\n3. **JSON \u89e3\u6790\u5931\u8d25** \u2192 \u6781\u5c11\u89c1\uff0c\u8bf4\u660e osv-scanner \u8f93\u51fa\u4e86\u4e0d\u517c\u5bb9\u7684\u7248\u672c\u3002\u8bf7\u628a stderr \u8d34\u5230\n issue \u91cc\u3002\n\n## \u8bbe\u8ba1\u9009\u62e9\n\n- **\u4e3a\u4ec0\u4e48\u6e05\u5355\u8981\u5148\u590d\u5236\u5230\u4e34\u65f6\u76ee\u5f55\u518d\u626b**\uff1fosv-scanner \u662f\u539f\u751f\u4e8c\u8fdb\u5236\uff0c\u6309 SECURITY.md \u5c5e\u4e8e\n High \u98ce\u9669\u80fd\u529b\u3002\u8ba9\u5b83\u53ea\u8bfb\u53d6\u63d2\u4ef6\u7ecf\u5bbf\u4e3b\u7f51\u5173\u8bfb\u5230\u7684\u6e05\u5355\u526f\u672c\uff08\u4e00\u6b21\u6027\u4e34\u65f6\u76ee\u5f55\u3001\u626b\u63cf\u540e\u5373\u5220\uff09\uff0c\n \u88ab\u62c9\u8d77\u7684\u4e8c\u8fdb\u5236\u5c31\u6c38\u8fdc\u4e0d\u4f1a\u76f4\u63a5\u89e6\u78b0\u5de5\u4f5c\u533a\u2014\u2014\u8fb9\u754c\u5148\u5728\u63d2\u4ef6\u4fa7\u5b88\u4f4f\uff0c\u5bbf\u4e3b\u7f51\u5173\u662f\u7b2c\u4e8c\u9053\u9501\u3002\n- **\u4e3a\u4ec0\u4e48\u662f\"\u590d\u5236\u7ed9 Agent\"\u800c\u4e0d\u662f\u4e00\u952e fix**\uff1f\u5347\u7ea7\u4f9d\u8d56\u662f\u9ad8\u98ce\u9669\u64cd\u4f5c\uff08\u7834\u574f\u6027\u53d8\u66f4\u3001lock \u91cd\u751f\u3001\n \u5f71\u54cd\u4e0b\u6e38\uff09\u3002\u8ba9 Agent \u5148\u89e3\u91ca\u3001\u518d\u7ed9\u65b9\u6848\u3001\u6700\u540e\u7531\u4f60\u70b9\u5934\uff0c\u662f\u6700\u4e0d\u5bb9\u6613\u51fa\u4e8b\u7684\u4eba\u673a\u534f\u4f5c\u3002\n- **\u4e3a\u4ec0\u4e48 `deps_audit_run` \u662f high-risk**\uff1f\u5b83\u4f1a\u62c9\u8d77\u672c\u673a osv-scanner \u4e8c\u8fdb\u5236\uff08\u539f\u751f\u6267\u884c\uff09\uff0c\n \u4e14 osv-scanner \u4f1a\u8054\u7f51\u8bbf\u95ee OSV \u6570\u636e\u5e93\u3002\u5b81\u53ef\u8ba9\u7528\u6237\u5728\u6388\u6743\u65f6\u591a\u770b\u4e00\u773c\u3002\n\n## \u5f00\u53d1\n\n```bash\n# \u5728 PI-Desktop \u4ed3\u5e93\u5185\u6821\u9a8c\ncd ~/dev/pi-desktop\nenv -u NODE_OPTIONS -u PYTHONPATH ./node_modules/.bin/pi-plugin check \\\n ~/dev/pi-desktop-plugin-lab/deps-audit\n\n# \u8dd1\u6d4b\u8bd5\nnode --test test/*.test.mjs\n```\n\n## License\n\nMIT\n", - "safetyNotes": "\u53ea\u7ecf\u5bbf\u4e3b fs \u7f51\u5173\u8bfb\u53d6\u58f0\u660e\u4f5c\u7528\u57df\u5185\u7684\u5de5\u4f5c\u533a\u6839\u76ee\u5f55\u4f9d\u8d56\u6e05\u5355\uff08package.json\u3001\u5404\u8bed\u8a00\u9501\u6587\u4ef6\u7b49\uff09\uff0c\u628a\u51c0\u5316\u526f\u672c\u653e\u5165\u4e00\u6b21\u6027\u4e34\u65f6\u76ee\u5f55\uff0c\u518d\u5bf9\u4e34\u65f6\u76ee\u5f55\u8fd0\u884c\u672c\u673a osv-scanner \u4e8c\u8fdb\u5236\u2014\u2014\u88ab\u62c9\u8d77\u7684\u4e8c\u8fdb\u5236\u7edd\u4e0d\u76f4\u63a5\u8bfb\u53d6\u5de5\u4f5c\u533a\uff0c\u4e14\u4f1a\u8054\u7f51\u8bbf\u95ee OSV \u6570\u636e\u5e93\uff08\u5df2\u58f0\u660e High \u98ce\u9669\u80fd\u529b\uff09\u3002\u4e34\u65f6\u526f\u672c\u5728\u6bcf\u6b21\u626b\u63cf\u540e\u5220\u9664\uff1b\u5de5\u4f5c\u533a\u6c38\u4e0d\u88ab\u5199\u5165\u3002", - "versions": [ - { - "version": "0.2.0", - "publishedAt": "2026-09-12T17:13:25Z", - "changelog": "0.2.0\uff1a\u6309\u7ef4\u62a4\u8005\u8bc4\u5ba1\u91cd\u505a\uff08#20\uff09\u3002\u4fee\u590d\u63d2\u4ef6\u751f\u547d\u5468\u671f\uff08onLoad \u6539\u7528\u5bbf\u4e3b\u6ce8\u5165\u7684 globalThis.pi\uff0c\u539f\u5b9e\u73b0\u56e0\u7f3a\u53c2\u800c\u4ece\u4e0d\u6ce8\u518c\uff09\uff1b\u626b\u63cf\u9762\u677f\u6539\u7ecf\u5bbf\u4e3b API \u89e3\u6790\u5f53\u524d\u5de5\u4f5c\u533a\u4e0e\u8bbe\u7f6e\uff08\u4e0d\u518d\u8bef\u626b\u63d2\u4ef6\u8fdb\u7a0b\u76ee\u5f55\uff09\uff1b\u6e05\u5355\u6587\u4ef6\u6539\u7ecf fs.read \u6743\u9650\u7f51\u5173\u8bfb\u53d6\uff0c\u51c0\u5316\u526f\u672c\u6682\u5b58\u4e00\u6b21\u6027\u4e34\u65f6\u76ee\u5f55\u540e\u518d\u4ea4\u7ed9 osv-scanner\uff08\u539f\u751f\u4e8c\u8fdb\u5236\u4e0e\u7f51\u7edc\u80fd\u529b\u6309 SECURITY.md \u58f0\u660e\u4e3a High \u98ce\u9669\uff0c\u9644\u8d1f\u9762\u8def\u5f84\u6d4b\u8bd5\uff09\uff1bosv-scanner \u547d\u4ee4\u6539\u4e3a v2 \u6b63\u786e\u7528\u6cd5\uff08scan source --format json --recursive\uff09\uff1b\u526a\u8d34\u677f\u590d\u5236\u6539\u8d70\u5bbf\u4e3b clipboard.write \u6865\uff1bPATH \u67e5\u627e\u517c\u5bb9 Windows\uff08where.exe\uff09\uff1b\u9762\u677f\u7b26\u5408 v3 chrome \u5951\u7ea6\u30020.1.0\uff1a\u9996\u4e2a\u516c\u5f00\u7248\u672c\u3002", - "minPiDesktop": ">=0.14.3", - "shasum": "9df6675b676b9b731124ea696ed9480c1e16e98548d823e408616c2c5bb8b1f2", - "url": "packages/io.github.muzimu217.deps-audit-0.2.0.piplug", - "sizeBytes": 82410, - "permissions": [ - "ui.panel", - "ui.view", - "fs.read", - "clipboard.write", - "agent.tool.register" - ], - "fs": { - "read": { - "root": "workspace", - "scope": [ - "package.json", - "package-lock.json", - "yarn.lock", - "pnpm-lock.yaml", - "requirements.txt", - "pyproject.toml", - "Pipfile", - "Cargo.toml", - "Cargo.lock", - "go.mod", - "go.sum", - "pom.xml", - "composer.json", - "composer.lock", - "Gemfile", - "Gemfile.lock" - ] - } - } - } - ] - }, { "id": "io.github.muzimu217.session-import", "name": "Universal Session Import", @@ -246,20 +176,21 @@ "downloads": 0, "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/io.github.muzimu217.session-import", "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# Universal Session Import\uff08\u4e00\u4f53\u5316\u4f1a\u8bdd\u5bfc\u5165\uff09\n\nPI-Desktop \u63d2\u4ef6\uff1a**\u626b\u63cf\u672c\u673a\u5b89\u88c5\u7684\u7f16\u7a0b\u5de5\u5177\uff0c\u628a\u5b83\u4eec\uff08ZCode\u3001WorkBuddy\u3001Claude Code\u3001Codex\u3001OpenCode\u3001Pi\uff09\u7684\u672c\u5730\u4f1a\u8bdd\u7edf\u4e00\u5bfc\u5165 PI-Desktop\u3002**\n\n![scan sources](docs/screenshots/01-scan-sources.png)\n\n## \u4f7f\u7528\u6d41\u7a0b\n\n### 1. \u626b\u63cf\u672c\u673a\u5de5\u5177\n\n\u6253\u5f00\u9762\u677f\u70b9\u51fb\u300c\u626b\u63cf\u672c\u673a\u5de5\u5177\u300d\uff0c\u63d2\u4ef6\u5e76\u884c\u63a2\u6d4b\u516d\u4e2a\u6765\u6e90\uff0c\u5b9e\u65f6\u663e\u793a\u5404\u81ea\u68c0\u6d4b\u5230\u7684\u4f1a\u8bdd\u6570\uff08\u672a\u5b89\u88c5\u7684\u5de5\u5177\u663e\u793a\u300c\u672a\u68c0\u6d4b\u5230\u300d\uff09\u3002\n\n### 2. \u9009\u62e9\u6765\u6e90\uff0c\u6d4f\u89c8\u4f1a\u8bdd\n\n\u70b9\u51fb\u68c0\u6d4b\u5230\u7684\u5de5\u5177\u5361\u7247\uff0c\u6309\u9879\u76ee\u5206\u7ec4\u8f7d\u5165\u8be5\u6765\u6e90\u7684\u4f1a\u8bdd\u5217\u8868\uff08\u652f\u6301\u641c\u7d22\u3001\u6574\u7ec4\u5168\u9009\uff09\uff1a\n\n![session list](docs/screenshots/02-session-list.png)\n\n### 3. \u9884\u89c8\u5bf9\u8bdd\n\n\u70b9\u4efb\u610f\u4f1a\u8bdd\u5373\u53ef\u6309\u539f\u59cb\u987a\u5e8f\u8fd8\u539f\u5b8c\u6574\u5bf9\u8bdd\u2014\u2014\u7528\u6237\u6d88\u606f\u3001\u52a9\u624b\u56de\u590d\u3001\u5de5\u5177\u8c03\u7528\uff08\u53c2\u6570 + \u7ed3\u679c\u6298\u53e0\u5c55\u793a\uff0c\u9519\u8bef\u6807\u7ea2\uff09\uff1a\n\n![preview](docs/screenshots/03-preview.png)\n\n### 4. \u5bfc\u5165\u4e3a\u4f1a\u8bdd\n\n\u52fe\u9009\u4f1a\u8bdd\uff08\u652f\u6301\u6574\u7ec4\u5168\u9009\uff09\u2192\u300c\u5bfc\u5165\u4e3a\u4f1a\u8bdd\u300d\uff0c\u901a\u8fc7\u5bbf\u4e3b `session.import` \u901a\u9053\u5199\u5165 PI-Desktop \u4f1a\u8bdd\u5e93\uff1a\n\n![import status](docs/screenshots/04-import-status.png)\n\n\u5bfc\u5165\u7684\u4f1a\u8bdd\u6309**\u539f\u59cb\u5de5\u4f5c\u76ee\u5f55**\u5f52\u5c5e\u9879\u76ee\uff1a\u8be5\u9879\u76ee\u5df2\u5728 PI-Desktop \u6253\u5f00\u65f6**\u7acb\u523b\u5c55\u5f00\u53ef\u89c1**\uff1b\u672a\u6253\u5f00\u7684\u9879\u76ee\u4e5f\u4f1a\u81ea\u52a8\u52a0\u5165\u5de6\u4fa7\u9879\u76ee\u5217\u8868\u5e76\u5c55\u5f00\uff1a\n\n![sidebar auto expand](docs/screenshots/05-sidebar-auto-expand.png)\n\n![sidebar codex](docs/screenshots/06-sidebar-codex.png)\n\n\u91cd\u590d\u5bfc\u5165\u81ea\u52a8\u8df3\u8fc7\uff08\u5e42\u7b49 id\uff1a`import-<\u6765\u6e90>-<\u5916\u90e8\u4f1a\u8bdd id>`\uff09\u3002\n\n## \u6765\u6e90\u4e0e\u7279\u6b8a\u5904\u7406\n\n| \u6765\u6e90 | \u6570\u636e\u4f4d\u7f6e | \u7279\u6b8a\u5904\u7406 |\n| --- | --- | --- |\n| ZCode | `~/.zcode/cli/db/db.sqlite` | `node:sqlite` \u53ea\u8bfb\uff1b\u8fc7\u6ee4 `subagent_child` \u5185\u90e8\u4f1a\u8bdd\u4e0e `synthetic` \u6ce8\u5165\u6587\u672c\uff1b\u5de5\u5177\u8c03\u7528\u6309\u5b58\u50a8\u987a\u5e8f\u8fd8\u539f |\n| WorkBuddy | `~/.workbuddy/projects/**/*.jsonl` | \u5265\u79bb ``/`` \u6ce8\u5165\u5757\uff1b`function_call` \u6309 `callId` \u914d\u5bf9\uff1b\u5916\u7f6e\u5927\u7ed3\u679c\u5b89\u5168\u56de\u8bfb\uff1b`ai-title` \u4f18\u5148 |\n| Claude Code | `~/.claude/projects/**/*.jsonl` | \u8fc7\u6ee4 sidechain \u4e0e\u5408\u6210\u7528\u6237\u884c\uff1b`tool_use`/`tool_result` \u914d\u5bf9 |\n| Codex | `~/.codex/sessions/**/*.jsonl` | \u517c\u5bb9\u65b0\u65e7\u4e24\u79cd\u683c\u5f0f\uff1b\u8fc7\u6ee4 `# AGENTS.md` \u7b49\u5408\u6210\u884c |\n| OpenCode | `~/.local/share/opencode/opencode.db` | `node:sqlite` \u53ea\u8bfb\uff1bsession\u2192message\u2192part \u4e09\u5c42\u8fd8\u539f\uff08OpenCode v1.x SQLite\uff09 |\n| Pi | `~/.pi/agent/sessions/**/*.jsonl` | `toolCall`/`toolResult` \u914d\u5bf9\uff1b`session_info.name` \u4f18\u5148 |\n\n## \u81ea\u5b9a\u4e49\u6765\u6e90\uff08\u65e0\u9700\u6539\u4ee3\u7801\uff09\n\n\u5185\u7f6e 6 \u4e2a\u6765\u6e90\u4e4b\u5916\uff0c\u4f60\u53ef\u4ee5\u5728**\u5f53\u524d\u5de5\u4f5c\u533a**\u653e\u4e00\u4efd\u7eaf JSON\uff0c\u63cf\u8ff0\u81ea\u5df1\u7684\u5de5\u5177\uff1a\n\n```\ndocs/session-import-sources.json\n```\n\n\u5185\u7f6e\u9a71\u52a8\u8986\u76d6\u4e09\u7c7b\u78c1\u76d8\u683c\u5f0f\uff0c\u7edd\u5927\u591a\u6570\u5de5\u5177\u90fd\u80fd\u843d\u5728\u5176\u4e2d\u4e00\u4e2a\u4e0a\uff1a\n\n| driver | \u9002\u7528 | \u5185\u7f6e\u4f7f\u7528\u8005 |\n| --- | --- | --- |\n| `jsonl-transcript` | \u4e00\u884c\u4e00\u6761\u8bb0\u5f55\u7684 JSONL \u5bf9\u8bdd\u6587\u4ef6 | Claude Code\u3001Codex\u3001WorkBuddy\u3001Pi |\n| `sqlite-session` | SQLite\uff1a`session \u2192 message \u2192 part` \u4e09\u5c42\uff08\u6216 session+message \u4e24\u5c42\uff09 | ZCode\u3001OpenCode |\n| `json-tree` | \u4e00\u4e2a JSON \u6587\u4ef6\u5373\u4e00\u4e2a\u4f1a\u8bdd | \u65e7\u7248 OpenCode / Claude \u5e03\u5c40 |\n\n\u9762\u677f\u300c\u81ea\u5b9a\u4e49\u6765\u6e90 \u2192 \u91cd\u65b0\u52a0\u8f7d\u300d\u5373\u53ef\u70ed\u52a0\u8f7d\uff0c\u65b0\u6765\u6e90\u5e26 `\u81ea\u5b9a\u4e49` \u6807\u7b7e\u51fa\u73b0\u3002\u5b8c\u6574\u5b57\u6bb5\u89c1\n[`docs/CUSTOM-SOURCES.md`](docs/CUSTOM-SOURCES.md)\uff0c\u91cc\u9762\u6709\u53ef\u76f4\u63a5\u590d\u5236\u7684\u4e09\u4e2a driver \u793a\u4f8b\u3002\n\n> **\u5b89\u5168\u8fb9\u754c**\uff1a\u914d\u7f6e**\u53ea\u5141\u8bb8\u7eaf\u6570\u636e**\u3002\u4efb\u4f55 `eval` / `code` / `require` / `transform` / `script`\n> \u4e4b\u7c7b\u7684\u952e\uff08\u4efb\u610f\u5c42\u7ea7\uff09\u90fd\u4f1a\u88ab\u62d2\u7edd\u2014\u2014\u63d2\u4ef6\u5bf9\u7528\u6237\u4e3b\u76ee\u5f55\u6709\u8bfb\u6743\u9650\uff0c\u5141\u8bb8\u914d\u7f6e\u643a\u5e26\u4ee3\u7801\u7b49\u540c\u4e8e\u4efb\u610f\u4ee3\u7801\u6267\u884c\u3002\n> \u6570\u636e\u6839\u76ee\u5f55\u4e5f\u4e0d\u63a5\u53d7 `/` \u6216\u6574\u4e2a home\u3002\n\n## \u6743\u9650\n\n| \u6743\u9650 | \u7528\u9014 |\n| --- | --- |\n| `ui.panel` / `ui.view` | \u5bfc\u5165\u9762\u677f\u4e0e\u300c\u4f1a\u8bdd\u7194\u7089\u300d\u5de5\u4f5c\u9762\u677f\u89c6\u56fe |\n| `session.read` / `session.read.own` | \u8bfb\u56de\u672c\u63d2\u4ef6\u5bfc\u5165\u8fc7\u7684\u4f1a\u8bdd\uff0c\u4f9b\u7194\u7089\u84b8\u998f |\n| `session.import` | \u628a\u9009\u4e2d\u7684\u4f1a\u8bdd\u5199\u5165 PI-Desktop \u4f1a\u8bdd\u5e93 |\n| `project.create` | \u6309\u4f1a\u8bdd\u7684 `projectPath` \u5e42\u7b49\u89e3\u6790 / \u7ed1\u5b9a projectId\uff08\u65e0\u6b64\u80fd\u529b\u7684\u5bbf\u4e3b\u9000\u56de\u672a\u7ed1\u5b9a\u5bfc\u5165\uff09 |\n| `agent.complete` / `models.list` | \u8c03\u7528\u5bbf\u4e3b\u6a21\u578b\u505a\u84b8\u998f\uff08\u4f7f\u7528\u5bbf\u4e3b\u51ed\u636e\u4e0e\u989d\u5ea6\uff0c\u63d2\u4ef6\u4e0d\u63a5\u89e6 API Key\uff09 |\n| `fs.read` | \u53ea\u8bfb\u5404\u5de5\u5177\u7684\u672c\u5730\u4f1a\u8bdd\u6570\u636e\uff08`.jsonl` / SQLite \u7684 `readOnly` \u6a21\u5f0f\uff09\uff1b\u5e76\u8bfb\u53d6\u5de5\u4f5c\u533a `docs/session-import-sources.json` \u91cc\u7684\u81ea\u5b9a\u4e49\u6765\u6e90\u914d\u7f6e |\n| `fs.write` | **\u4ec5**\u7528\u4e8e\u4fdd\u5b58\u84b8\u998f\u7ed3\u679c\uff0c\u8303\u56f4\u9650\u5b9a\u5728\u5de5\u4f5c\u533a\u5185\u7684 `AGENTS.md`\u3001`*.md`\u3001`docs/**`\u3001`.agents/skills/**` |\n\n\u8bfb\u53d6\u5404\u5de5\u5177\u672c\u5730\u6570\u636e\u7531\u63d2\u4ef6\u8fdb\u7a0b**\u53ea\u8bfb**\u5b8c\u6210\uff08`node:sqlite` \u7684 `readOnly` \u6a21\u5f0f\uff0c\u6216\u76f4\u63a5\u8bfb\u53d6\n`.jsonl`\uff09\u3002**\u5bfc\u5165**\u7ecf\u7531\u5bbf\u4e3b `session.import` \u901a\u9053\u5b8c\u6210\uff08\u8be5\u901a\u9053\u4e3a\u63d2\u4ef6\u5bbf\u4e3b\u65b0\u589e\u7684\u5e95\u5c42 API\n\u63d0\u6848\uff0c\u89c1 [PI-Desktop#134](https://github.com/vastsa/PI-Desktop/issues/134)\uff09\u3002\n\n\u63d2\u4ef6\u4e0d\u53d1\u8d77\u4efb\u4f55\u7f51\u7edc\u8bf7\u6c42\u3001\u65e0\u9065\u6d4b\u4e0a\u62a5\uff1b\u7194\u7089\u8c03\u7528\u8d70\u5bbf\u4e3b `pi.agent.complete`\uff0c\u51ed\u636e\u4fdd\u7559\u5728\nElectron \u4e3b\u8fdb\u7a0b\u3002\n\n## \u5f00\u53d1\n\n```bash\n# \u5728 PI-Desktop \u4ed3\u5e93\u5185\u6821\u9a8c\u4e0e\u6253\u5305\npnpm --filter @pi-desktop/plugin-devkit... build\nnode packages/plugin-devkit/dist/cli.js check /absolute/path/to/pi-desktop-session-import\nnode packages/plugin-devkit/dist/cli.js pack /absolute/path/to/pi-desktop-session-import\n```\n\n\u5728 PI-Desktop \u4e2d\uff1a\u63d2\u4ef6\u9875 \u2192 Load development plugin \u2192 \u9009\u62e9\u672c\u76ee\u5f55\u3002\n\n## License\n\nMIT\n", + "readmeMarkdown": "# Universal Session Import\uff08\u4e00\u4f53\u5316\u4f1a\u8bdd\u5bfc\u5165\uff09\n\nPI-Desktop \u63d2\u4ef6\uff1a**\u626b\u63cf\u672c\u673a\u5b89\u88c5\u7684\u7f16\u7a0b\u5de5\u5177\uff0c\u628a\u5b83\u4eec\uff08ZCode\u3001WorkBuddy\u3001Claude Code\u3001Codex\u3001OpenCode\u3001Pi\uff09\u7684\u672c\u5730\u4f1a\u8bdd\u7edf\u4e00\u5bfc\u5165 PI-Desktop\u3002**\n\n![scan sources](docs/screenshots/01-scan-sources.png)\n\n## \u4f7f\u7528\u6d41\u7a0b\n\n### 1. \u626b\u63cf\u672c\u673a\u5de5\u5177\n\n\u6253\u5f00\u9762\u677f\u70b9\u51fb\u300c\u626b\u63cf\u672c\u673a\u5de5\u5177\u300d\uff0c\u63d2\u4ef6\u5e76\u884c\u63a2\u6d4b\u516d\u4e2a\u6765\u6e90\uff0c\u5b9e\u65f6\u663e\u793a\u5404\u81ea\u68c0\u6d4b\u5230\u7684\u4f1a\u8bdd\u6570\uff08\u672a\u5b89\u88c5\u7684\u5de5\u5177\u663e\u793a\u300c\u672a\u68c0\u6d4b\u5230\u300d\uff09\u3002\n\n### 2. \u9009\u62e9\u6765\u6e90\uff0c\u6d4f\u89c8\u4f1a\u8bdd\n\n\u70b9\u51fb\u68c0\u6d4b\u5230\u7684\u5de5\u5177\u5361\u7247\uff0c\u6309\u9879\u76ee\u5206\u7ec4\u8f7d\u5165\u8be5\u6765\u6e90\u7684\u4f1a\u8bdd\u5217\u8868\uff08\u652f\u6301\u641c\u7d22\u3001\u6574\u7ec4\u5168\u9009\uff09\uff1a\n\n![session list](docs/screenshots/02-session-list.png)\n\n### 3. \u9884\u89c8\u5bf9\u8bdd\n\n\u70b9\u4efb\u610f\u4f1a\u8bdd\u5373\u53ef\u6309\u539f\u59cb\u987a\u5e8f\u8fd8\u539f\u5b8c\u6574\u5bf9\u8bdd\u2014\u2014\u7528\u6237\u6d88\u606f\u3001\u52a9\u624b\u56de\u590d\u3001\u5de5\u5177\u8c03\u7528\uff08\u53c2\u6570 + \u7ed3\u679c\u6298\u53e0\u5c55\u793a\uff0c\u9519\u8bef\u6807\u7ea2\uff09\uff1a\n\n![preview](docs/screenshots/03-preview.png)\n\n### 4. \u5bfc\u5165\u4e3a\u4f1a\u8bdd\n\n\u52fe\u9009\u4f1a\u8bdd\uff08\u652f\u6301\u6574\u7ec4\u5168\u9009\uff09\u2192\u300c\u5bfc\u5165\u4e3a\u4f1a\u8bdd\u300d\uff0c\u901a\u8fc7\u5bbf\u4e3b `session.import` \u901a\u9053\u5199\u5165 PI-Desktop \u4f1a\u8bdd\u5e93\uff1a\n\n![import status](docs/screenshots/04-import-status.png)\n\n\u5bfc\u5165\u7684\u4f1a\u8bdd\u6309**\u539f\u59cb\u5de5\u4f5c\u76ee\u5f55**\u5f52\u5c5e\u9879\u76ee\uff1a\u8be5\u9879\u76ee\u5df2\u5728 PI-Desktop \u6253\u5f00\u65f6**\u7acb\u523b\u5c55\u5f00\u53ef\u89c1**\uff1b\u672a\u6253\u5f00\u7684\u9879\u76ee\u4e5f\u4f1a\u81ea\u52a8\u52a0\u5165\u5de6\u4fa7\u9879\u76ee\u5217\u8868\u5e76\u5c55\u5f00\uff1a\n\n![sidebar auto expand](docs/screenshots/05-sidebar-auto-expand.png)\n\n![sidebar codex](docs/screenshots/06-sidebar-codex.png)\n\n\u91cd\u590d\u5bfc\u5165\u81ea\u52a8\u8df3\u8fc7\uff08\u5e42\u7b49 id\uff1a`import-<\u6765\u6e90>-<\u5916\u90e8\u4f1a\u8bdd id>`\uff09\u3002\n\n## \u6765\u6e90\u4e0e\u7279\u6b8a\u5904\u7406\n\n| \u6765\u6e90 | \u6570\u636e\u4f4d\u7f6e | \u7279\u6b8a\u5904\u7406 |\n| --- | --- | --- |\n| ZCode | `~/.zcode/cli/db/db.sqlite` | `node:sqlite` \u53ea\u8bfb\uff1b\u8fc7\u6ee4 `subagent_child` \u5185\u90e8\u4f1a\u8bdd\u4e0e `synthetic` \u6ce8\u5165\u6587\u672c\uff1b\u5de5\u5177\u8c03\u7528\u6309\u5b58\u50a8\u987a\u5e8f\u8fd8\u539f |\n| WorkBuddy | `~/.workbuddy/projects/**/*.jsonl` | \u5265\u79bb ``/`` \u6ce8\u5165\u5757\uff1b`function_call` \u6309 `callId` \u914d\u5bf9\uff1b\u5916\u7f6e\u5927\u7ed3\u679c\u5b89\u5168\u56de\u8bfb\uff1b`ai-title` \u4f18\u5148 |\n| Claude Code | `~/.claude/projects/**/*.jsonl` | \u8fc7\u6ee4 sidechain \u4e0e\u5408\u6210\u7528\u6237\u884c\uff1b`tool_use`/`tool_result` \u914d\u5bf9 |\n| Codex | `~/.codex/sessions/**/*.jsonl` | \u517c\u5bb9\u65b0\u65e7\u4e24\u79cd\u683c\u5f0f\uff1b\u8fc7\u6ee4 `# AGENTS.md` \u7b49\u5408\u6210\u884c |\n| OpenCode | `~/.local/share/opencode/opencode.db` | `node:sqlite` \u53ea\u8bfb\uff1bsession\u2192message\u2192part \u4e09\u5c42\u8fd8\u539f\uff08OpenCode v1.x SQLite\uff09 |\n| Pi | `~/.pi/agent/sessions/**/*.jsonl` | `toolCall`/`toolResult` \u914d\u5bf9\uff1b`session_info.name` \u4f18\u5148 |\n\n## \u81ea\u5b9a\u4e49\u6765\u6e90\uff08\u65e0\u9700\u6539\u4ee3\u7801\uff09\n\n\u5185\u7f6e 6 \u4e2a\u6765\u6e90\u4e4b\u5916\uff0c\u4f60\u53ef\u4ee5\u5728**\u5f53\u524d\u5de5\u4f5c\u533a**\u653e\u4e00\u4efd\u7eaf JSON\uff0c\u63cf\u8ff0\u81ea\u5df1\u7684\u5de5\u5177\uff1a\n\n```\ndocs/session-import-sources.json\n```\n\n\u5185\u7f6e\u9a71\u52a8\u8986\u76d6\u4e09\u7c7b\u78c1\u76d8\u683c\u5f0f\uff0c\u7edd\u5927\u591a\u6570\u5de5\u5177\u90fd\u80fd\u843d\u5728\u5176\u4e2d\u4e00\u4e2a\u4e0a\uff1a\n\n| driver | \u9002\u7528 | \u5185\u7f6e\u4f7f\u7528\u8005 |\n| --- | --- | --- |\n| `jsonl-transcript` | \u4e00\u884c\u4e00\u6761\u8bb0\u5f55\u7684 JSONL \u5bf9\u8bdd\u6587\u4ef6 | Claude Code\u3001Codex\u3001WorkBuddy\u3001Pi |\n| `sqlite-session` | SQLite\uff1a`session \u2192 message \u2192 part` \u4e09\u5c42\uff08\u6216 session+message \u4e24\u5c42\uff09 | ZCode\u3001OpenCode |\n| `json-tree` | \u4e00\u4e2a JSON \u6587\u4ef6\u5373\u4e00\u4e2a\u4f1a\u8bdd | \u65e7\u7248 OpenCode / Claude \u5e03\u5c40 |\n\n\u9762\u677f\u300c\u81ea\u5b9a\u4e49\u6765\u6e90 \u2192 \u91cd\u65b0\u52a0\u8f7d\u300d\u5373\u53ef\u70ed\u52a0\u8f7d\uff0c\u65b0\u6765\u6e90\u5e26 `\u81ea\u5b9a\u4e49` \u6807\u7b7e\u51fa\u73b0\u3002\u5b8c\u6574\u5b57\u6bb5\u89c1\n[`docs/CUSTOM-SOURCES.md`](docs/CUSTOM-SOURCES.md)\uff0c\u91cc\u9762\u6709\u53ef\u76f4\u63a5\u590d\u5236\u7684\u4e09\u4e2a driver \u793a\u4f8b\u3002\n\n> **\u5b89\u5168\u8fb9\u754c**\uff1a\u914d\u7f6e**\u53ea\u5141\u8bb8\u7eaf\u6570\u636e**\u3002\u4efb\u4f55 `eval` / `code` / `require` / `transform` / `script`\n> \u4e4b\u7c7b\u7684\u952e\uff08\u4efb\u610f\u5c42\u7ea7\uff09\u90fd\u4f1a\u88ab\u62d2\u7edd\u2014\u2014\u63d2\u4ef6\u5bf9\u7528\u6237\u4e3b\u76ee\u5f55\u6709\u8bfb\u6743\u9650\uff0c\u5141\u8bb8\u914d\u7f6e\u643a\u5e26\u4ee3\u7801\u7b49\u540c\u4e8e\u4efb\u610f\u4ee3\u7801\u6267\u884c\u3002\n> \u6570\u636e\u6839\u76ee\u5f55\u4e5f\u4e0d\u63a5\u53d7 `/` \u6216\u6574\u4e2a home\u3002\n\n## \u6743\u9650\n\n| \u6743\u9650 | \u7528\u9014 |\n| --- | --- |\n| `ui.panel` / `ui.view` | \u5bfc\u5165\u9762\u677f\u4e0e\u300c\u4f1a\u8bdd\u7194\u7089\u300d\u5de5\u4f5c\u9762\u677f\u89c6\u56fe |\n| `notify` | \u626b\u63cf / \u5bfc\u5165\u5b8c\u6210\u6216\u5931\u8d25\u65f6\u53d1\u4e00\u6761\u901a\u77e5 |\n| `session.read` / `session.read.own` | \u8bfb\u56de\u672c\u63d2\u4ef6\u5bfc\u5165\u8fc7\u7684\u4f1a\u8bdd\uff0c\u4f9b\u7194\u7089\u84b8\u998f |\n| `session.import` | \u628a\u9009\u4e2d\u7684\u4f1a\u8bdd\u5199\u5165 PI-Desktop \u4f1a\u8bdd\u5e93 |\n| `project.create` | \u6309\u4f1a\u8bdd\u7684 `projectPath` \u5e42\u7b49\u89e3\u6790 / \u7ed1\u5b9a projectId\uff08\u65e0\u6b64\u80fd\u529b\u7684\u5bbf\u4e3b\u9000\u56de\u672a\u7ed1\u5b9a\u5bfc\u5165\uff09 |\n| `agent.complete` / `models.list` | \u8c03\u7528\u5bbf\u4e3b\u6a21\u578b\u505a\u84b8\u998f\uff08\u4f7f\u7528\u5bbf\u4e3b\u51ed\u636e\u4e0e\u989d\u5ea6\uff0c\u63d2\u4ef6\u4e0d\u63a5\u89e6 API Key\uff09 |\n| `fs.read` | \u53ea\u8bfb\u5404\u5de5\u5177\u7684\u672c\u5730\u4f1a\u8bdd\u6570\u636e\uff08`.jsonl` / SQLite \u7684 `readOnly` \u6a21\u5f0f\uff09\uff1b\u5e76\u8bfb\u53d6\u5de5\u4f5c\u533a `docs/session-import-sources.json` \u91cc\u7684\u81ea\u5b9a\u4e49\u6765\u6e90\u914d\u7f6e |\n| `fs.write` | **\u4ec5**\u7528\u4e8e\u4fdd\u5b58\u84b8\u998f\u7ed3\u679c\uff0c\u8303\u56f4\u9650\u5b9a\u5728\u5de5\u4f5c\u533a\u5185\u7684 `AGENTS.md`\u3001`*.md`\u3001`docs/**`\u3001`.agents/skills/**` |\n\n\u8bfb\u53d6\u5404\u5de5\u5177\u672c\u5730\u6570\u636e\u7531\u63d2\u4ef6\u8fdb\u7a0b**\u53ea\u8bfb**\u5b8c\u6210\uff08`node:sqlite` \u7684 `readOnly` \u6a21\u5f0f\uff0c\u6216\u76f4\u63a5\u8bfb\u53d6\n`.jsonl`\uff09\u3002**\u5bfc\u5165**\u7ecf\u7531\u5bbf\u4e3b `session.import` \u901a\u9053\u5b8c\u6210\uff08\u8be5\u901a\u9053\u4e3a\u63d2\u4ef6\u5bbf\u4e3b\u65b0\u589e\u7684\u5e95\u5c42 API\n\u63d0\u6848\uff0c\u89c1 [PI-Desktop#134](https://github.com/vastsa/PI-Desktop/issues/134)\uff09\u3002\n\n\u63d2\u4ef6\u4e0d\u53d1\u8d77\u4efb\u4f55\u7f51\u7edc\u8bf7\u6c42\u3001\u65e0\u9065\u6d4b\u4e0a\u62a5\uff1b\u7194\u7089\u8c03\u7528\u8d70\u5bbf\u4e3b `pi.agent.complete`\uff0c\u51ed\u636e\u4fdd\u7559\u5728\nElectron \u4e3b\u8fdb\u7a0b\u3002\n\n## \u5f00\u53d1\n\n```bash\n# \u5728 PI-Desktop \u4ed3\u5e93\u5185\u6821\u9a8c\u4e0e\u6253\u5305\npnpm --filter @pi-desktop/plugin-devkit... build\nnode packages/plugin-devkit/dist/cli.js check /absolute/path/to/pi-desktop-session-import\nnode packages/plugin-devkit/dist/cli.js pack /absolute/path/to/pi-desktop-session-import\n```\n\n\u5728 PI-Desktop \u4e2d\uff1a\u63d2\u4ef6\u9875 \u2192 Load development plugin \u2192 \u9009\u62e9\u672c\u76ee\u5f55\u3002\n\n## License\n\nMIT\n", "safetyNotes": "\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\u5404\u5de5\u5177\u7684\u672c\u5730\u4f1a\u8bdd\u6570\u636e\u5e93\uff1b\u4f1a\u8bdd\u5199\u5165\u8d70\u5bbf\u4e3b session \u5bfc\u5165\u63a5\u53e3\u3002\u7194\u7089\u4f7f\u7528\u5bbf\u4e3b\u81ea\u8eab\u989d\u5ea6\u8c03\u7528\u6a21\u578b\uff0c\u63d2\u4ef6\u4e0d\u63a5\u89e6 API Key\u3002fs.write \u4ec5\u7528\u4e8e\u4fdd\u5b58\u84b8\u998f\u7ed3\u679c\uff0c\u8303\u56f4\u9650\u5b9a\u5728\u5de5\u4f5c\u533a\u5185\u7684 AGENTS.md\u3001*.md\u3001docs/**\u3001.agents/skills/**\u3002\u4e0d\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\uff0c\u65e0\u9065\u6d4b\u3002 \u81ea\u5b9a\u4e49\u6765\u6e90\u914d\u7f6e\uff08\u5de5\u4f5c\u533a docs/session-import-sources.json\uff09\u53ea\u63a5\u53d7\u7eaf\u6570\u636e\uff0c\u63d2\u4ef6\u6c38\u4e0d\u6267\u884c\u5176\u4e2d\u7684\u4ee3\u7801\u3002", "versions": [ { - "version": "0.4.8", - "publishedAt": "2026-09-12T17:13:25Z", - "changelog": "Release 0.4.8\uff08\u5bfc\u5165\u884c\u4e3a\u4fee\u6b63\uff09\uff1a\u9ed8\u8ba4\u6309\u9879\u76ee\u5f52\u7ec4\u5bfc\u5165\u2014\u2014\u79fb\u9664\u65e0\u610f\u4e49\u7684\u300c\u5f52\u7ec4\u5230\u9879\u76ee\u300d\u52fe\u9009\u9879\uff08\u5bbf\u4e3b import_session \u53ea\u8981 project_path \u975e\u7a7a\u5373\u81ea\u52a8\u7ed1\u5b9a\u9879\u76ee\uff0c\u5ffd\u7565 projectId\uff0c\u6545\u8be5\u5f00\u5173\u662f\u7a7a\u64cd\u4f5c\uff09\uff1b\u65e0 projectPath \u7684\u4f1a\u8bdd\u56de\u843d\u72ec\u7acb\u300c\u4f1a\u8bdd\u300d\u5217\u8868\uff0c\u6c38\u4e0d\u4e22\u6570\u636e\u3002\u79fb\u9664\u5bfc\u5165\u5b8c\u6210\u540e\u7684\u300c\u4f1a\u8bdd\u7194\u7089\u300d\u539f\u751f\u901a\u77e5\uff08\u6587\u6848\u4e0d\u6e05\u6670\uff1b\u4f1a\u8bdd\u7194\u7089\u529f\u80fd\u4fdd\u7559\uff09\uff0cmanifest \u4e0d\u518d\u9700\u8981 notify \u6743\u9650\u3002\u4fdd\u7559 0.4.7 \u7684\u58f0\u660e\u5f0f\u683c\u5f0f\u9a71\u52a8\u5c42\u3001\u81ea\u5b9a\u4e49\u6765\u6e90\u4e0e\u5176\u5b89\u5168\u52a0\u56fa\uff08\u62d2\u7edd\u6587\u4ef6\u7cfb\u7edf\u6839/Windows \u76d8\u7b26\u6839\u3001extension \u5fc5\u987b\u4e3a\u771f\u540e\u7f00\u3001SQLite \u6807\u8bc6\u7b26\u5b57\u7b26\u96c6\u9650\u5236\u3001convert \u9650\u5236\u5728 spec \u6839\u5185\uff09\uff0c\u4ee5\u53ca 0.4.6 \u5065\u58ee\u6027\u52a0\u56fa\u3002\u57fa\u4e8e 0.4.7 \u4e4b\u4e0a\u53d1\u5e03\u3002", + "version": "0.4.7", + "publishedAt": "2026-09-11T18:47:58Z", + "changelog": "Release 0.4.7\uff08\u53ef\u6269\u5c55\u6765\u6e90\uff09\uff1a\u65b0\u589e\u58f0\u660e\u5f0f\u683c\u5f0f\u9a71\u52a8\u5c42\u2014\u2014jsonl-transcript / sqlite-session / json-tree \u4e09\u4e2a driver \u8986\u76d6\u300c\u4e00\u884c\u4e00\u6761 JSON\u300d\u300csession\u2192message\u2192part \u7684 SQLite\u300d\u300c\u5355\u6587\u4ef6\u5373\u4e00\u4f1a\u8bdd\u300d\u4e09\u7c7b\u78c1\u76d8\u683c\u5f0f\uff0c\u4efb\u4f55\u65b0\u6765\u6e90\u53ea\u9700\u914d\u7f6e\u3001\u65e0\u9700\u5199\u4ee3\u7801\uff1b\u7528\u6237\u53ef\u5728\u5de5\u4f5c\u533a docs/session-import-sources.json \u91cc\u63cf\u8ff0\u81ea\u5df1\u7684\u5de5\u5177\u5e76\u70ed\u52a0\u8f7d\uff08\u914d\u7f6e\u53ea\u63a5\u53d7\u7eaf\u6570\u636e\uff0c\u6c38\u4e0d\u6267\u884c\u4ee3\u7801\uff0c\u6570\u636e\u6839\u76ee\u5f55\u62d2\u7edd / \u4e0e\u6574\u4e2a home\uff09\u3002\u9a71\u52a8\u5c42\u5df2\u7528\u672c\u673a\u771f\u5b9e\u6570\u636e\u9010\u6761\u6bd4\u5bf9\u6821\u9a8c\uff1a1693 \u4e2a\u4f1a\u8bdd\u4e0e\u624b\u5199\u9002\u914d\u5668\u9010\u5b57\u8282\u4e00\u81f4\uff08Claude 61/61\u3001Codex 774/774\u3001WorkBuddy 159/159\u3001ZCode 70/70\u3001OpenCode 629/629\uff09\u3002\u5305\u542b 0.4.6 \u7684\u5065\u58ee\u6027\u52a0\u56fa\uff08\u770b\u95e8\u72d7\u8d85\u65f6\u3001\u6309 externalId \u53bb\u91cd\u5e76\u6807\u8bb0\u8d85\u5927\u4f1a\u8bdd\u3001\u5951\u7ea6\u622a\u65ad\u663e\u5f0f\u56de\u4f20 truncated\uff09\u3002\u57fa\u4e8e 0.4.6 \u4e4b\u4e0a\u53d1\u5e03\u3002", "minPiDesktop": ">=0.14.3", - "shasum": "ff32b931be2f9befeb3698746b7f11d7a37b51b742f4134cae1f7d0057121e7a", - "url": "packages/io.github.muzimu217.session-import-0.4.8.piplug", - "sizeBytes": 3551806, + "shasum": "4dbd73e4060c8ad92932962976d2fe22dd5fedd7dc4a64fee2d0a7a21c01423a", + "url": "packages/io.github.muzimu217.session-import-0.4.7.piplug", + "sizeBytes": 3553027, "permissions": [ "ui.panel", "ui.view", + "notify", "session.read", "session.read.own", "session.import", @@ -322,7 +253,7 @@ "versions": [ { "version": "0.1.5", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.1.5: reserves space for the host window-control capsule so top-right panel actions no longer overlap it. Release 0.1.4: gives the panel an explicit full-height page surface and keeps the host window-control capsule synchronized with live theme changes. Release 0.1.3: migrates the panel to v3 paint-through chrome so top-band controls remain clickable without the legacy 46px blank area. Release 0.1.2: refreshes the sticky-notes panel chrome, controls, focus states, dialogs, and compact responsive spacing. Release 0.1.1: adapts the panel to PI-Desktop's cross-platform 46px host drag band and minimal three-button window-control capsule. First release: multiple notes, Markdown preview/editing, task lists, highlights, image paste, and recycle bin.", "minPiDesktop": ">=0.7.1", "shasum": "816ea81e1b029f7534b0600feabcdf4b272f36b9082679bcad658888ae73fae5", @@ -368,7 +299,7 @@ "versions": [ { "version": "0.2.2", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.2.2: reserves the host capsule's right-side safe area in the toolbar and retints the capsule after live palette changes. Release 0.2.1: migrates the panel to v3 paint-through chrome and removes the duplicate 46px top inset; top-band controls remain clickable while blank space remains draggable. Release 0.2.0: \u652f\u6301\u526a\u8d34\u677f\u56fe\u7247\u91c7\u96c6\u4e0e\u6062\u590d\uff08\u5bbf\u4e3b getHistory \u53ef\u7528\u65f6\u81ea\u52a8\u542f\u7528\uff0c\u53ef\u5173\u95ed\uff09\uff1b\u65b0\u589e\u4fdd\u5b58\u56fe\u7247\u5f00\u5173\u3002Image capture & restore when the host exposes getHistory, with a save-images toggle.\nRelease 0.1.0: \u9996\u4e2a\u7248\u672c\u2014\u2014\u540e\u53f0\u91c7\u96c6\u526a\u8d34\u677f\u6587\u672c\u3001\u6309\u5929\u5f52\u6863\u4fdd\u7559 30 \u5929\u3001\u9762\u677f\u4e00\u952e\u6062\u590d/\u5220\u9664/\u6e05\u7a7a\u3001\u6682\u505c\u5f00\u5173\u4e0e\u8f6e\u8be2\u95f4\u9694\u53ef\u8c03\u3002Initial release \u2014 background clipboard capture, 30-day daily archives, one-click restore/delete/clear in a panel, pause toggle and configurable poll interval.", "minPiDesktop": ">=0.8.0", "shasum": "0c1dcc5504b964252b2d5f7660fd5be033185253ffd1a2cba1b95be6c0900cd4", @@ -387,17 +318,17 @@ { "id": "pi.file-manager", "name": "\u6587\u4ef6\u7ba1\u7406\u5668", - "description": "\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u4e2d\u6d4f\u89c8\u3001\u67e5\u770b\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\uff1a\u5b8c\u6574\u76ee\u5f55\u6811\uff08\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\uff09\u3001\u5de6\u53f3\u5206\u680f\u3001\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58\u3001Markdown \u9884\u89c8\u3001\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u67e5\u770b\u3001CSV/JSON \u7ed3\u6784\u5316\u67e5\u770b\uff0c\u4ee5\u53ca\u53f3\u952e\u65b0\u5efa\u3001\u91cd\u547d\u540d/\u79fb\u52a8\u3001\u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002", + "description": "\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u4e2d\u6d4f\u89c8\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\uff1a\u5b8c\u6574\u76ee\u5f55\u6811\uff08\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\uff09\u3001\u5de6\u53f3\u5206\u680f\u3001\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58\u3001Markdown \u9884\u89c8/\u7f16\u8f91\u5207\u6362\uff0c\u4ee5\u53ca\u53f3\u952e\u65b0\u5efa\u3001\u91cd\u547d\u540d/\u79fb\u52a8\u3001\u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002", "i18n": { "en": { "name": "File Manager", - "description": "Browse, view and edit the open project in the right work panel: a full directory tree with per-file-type icons, syntax-highlighted editing, a Markdown preview, image and media viewing, CSV/JSON structured views, read-only SQLite browsing with a SQL query box, a context menu for creating and renaming, and filename search.", - "safetyNotes": "Databases are opened strictly read-only (readOnly + PRAGMA query_only) and the query box only accepts single read-only statements, so a database can be browsed but never modified. Reads and writes files in the open project through Node's fs inside the plugin's own process \u2014 the host permission gateway does not mediate these calls, and the manifest cannot declare a whole-tree write. Access is confined to the project root by the plugin itself: resolved paths must stay inside the root (symlink and junction escapes are refused), credential paths (.env*, .ssh/, *.pem, .git/**) are refused, saves are atomic (temp file + rename), and overwriting a file changed outside the editor asks first. Images and media are read up to their own size limits (8 MiB / 24 MiB) and handed to the view as base64 data URIs; binaries such as zip or exe are never decoded, only reported as unsupported. No network access; the plugin data directory only holds settings and a write audit log." + "description": "Browse and edit the open project in the right work panel: a full directory tree with per-file-type icons, syntax-highlighted editing, a Markdown preview/edit toggle, a context menu for creating and renaming, and filename search.", + "safetyNotes": "Reads and writes files in the open project through Node's fs inside the plugin's own process \u2014 the host permission gateway does not mediate these calls, and the manifest cannot declare a whole-tree write. Access is confined to the project root by the plugin itself: resolved paths must stay inside the root (symlink and junction escapes are refused), credential paths (.env*, .ssh/, *.pem, .git/**) are refused, saves are atomic (temp file + rename), and overwriting a file changed outside the editor asks first. No network access; the plugin data directory only holds settings and a write audit log." }, "zh-CN": { "name": "\u6587\u4ef6\u7ba1\u7406\u5668", - "description": "\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u4e2d\u6d4f\u89c8\u3001\u67e5\u770b\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\uff1a\u5b8c\u6574\u76ee\u5f55\u6811\uff08\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\uff09\u3001\u5de6\u53f3\u5206\u680f\u3001\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58\u3001Markdown \u9884\u89c8\u3001\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u67e5\u770b\u3001CSV/JSON \u7ed3\u6784\u5316\u67e5\u770b\u3001SQLite \u53ea\u8bfb\u6d4f\u89c8\u4e0e SQL \u67e5\u8be2\uff0c\u4ee5\u53ca\u53f3\u952e\u65b0\u5efa\u3001\u91cd\u547d\u540d/\u79fb\u52a8\u3001\u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002", - "safetyNotes": "\u6570\u636e\u5e93\u4e00\u5f8b\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\uff08readOnly + PRAGMA query_only\uff09\uff0cSQL \u6846\u53ea\u63a5\u53d7\u5355\u6761\u53ea\u8bfb\u8bed\u53e5\uff0c\u56e0\u6b64\u53ea\u80fd\u6d4f\u89c8\u3001\u7edd\u65e0\u4fee\u6539\uff1b\u63d2\u4ef6\u5728\u81ea\u5df1\u7684\u8fdb\u7a0b\u5185\u901a\u8fc7 Node fs \u8bfb\u5199\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\u2014\u2014\u5bbf\u4e3b\u7684\u6743\u9650\u7f51\u5173\u4e0d\u4ecb\u5165\u8fd9\u4e9b\u8c03\u7528\uff0cmanifest \u4e5f\u65e0\u6cd5\u7533\u62a5\u300c\u6574\u6811\u5199\u5165\u300d\u3002\u8bbf\u95ee\u8303\u56f4\u7531\u63d2\u4ef6\u81ea\u8eab\u9650\u5b9a\u5728\u9879\u76ee\u6839\u76ee\u5f55\u5185\uff1a\u89e3\u6790\u540e\u7684\u8def\u5f84\u5fc5\u987b\u4ecd\u5728\u6839\u5185\uff08\u62d2\u7edd\u7b26\u53f7\u94fe\u63a5\u4e0e junction \u9003\u9038\uff09\u3001\u62d2\u7edd\u51ed\u636e\u7c7b\u8def\u5f84\uff08.env*\u3001.ssh/\u3001*.pem\u3001.git/**\uff09\u3001\u4fdd\u5b58\u91c7\u7528\u539f\u5b50\u5199\uff08\u4e34\u65f6\u6587\u4ef6 + \u91cd\u547d\u540d\uff09\u3001\u8986\u76d6\u5728\u7f16\u8f91\u5668\u5916\u88ab\u6539\u52a8\u8fc7\u7684\u6587\u4ef6\u524d\u4f1a\u5148\u8be2\u95ee\u3002\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u6309\u5404\u81ea\u4e0a\u9650\uff088 MiB / 24 MiB\uff09\u8bfb\u53d6\u540e\u4ee5 base64 data URI \u4ea4\u7ed9\u89c6\u56fe\uff1bzip\u3001exe \u8fd9\u7c7b\u4e8c\u8fdb\u5236\u53ea\u62a5\u300c\u4e0d\u652f\u6301\u9884\u89c8\u300d\uff0c\u4e0d\u505a\u4efb\u4f55\u89e3\u7801\u3002\u65e0\u7f51\u7edc\u8bbf\u95ee\uff1b\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u53ea\u4fdd\u5b58\u8bbe\u7f6e\u4e0e\u5199\u5165\u5ba1\u8ba1\u65e5\u5fd7\u3002" + "description": "\u5728\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u4e2d\u6d4f\u89c8\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\uff1a\u5b8c\u6574\u76ee\u5f55\u6811\uff08\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\uff09\u3001\u5de6\u53f3\u5206\u680f\u3001\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58\u3001Markdown \u9884\u89c8/\u7f16\u8f91\u5207\u6362\uff0c\u4ee5\u53ca\u53f3\u952e\u65b0\u5efa\u3001\u91cd\u547d\u540d/\u79fb\u52a8\u3001\u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002", + "safetyNotes": "\u63d2\u4ef6\u5728\u81ea\u5df1\u7684\u8fdb\u7a0b\u5185\u901a\u8fc7 Node fs \u8bfb\u5199\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\u2014\u2014\u5bbf\u4e3b\u7684\u6743\u9650\u7f51\u5173\u4e0d\u4ecb\u5165\u8fd9\u4e9b\u8c03\u7528\uff0cmanifest \u4e5f\u65e0\u6cd5\u7533\u62a5\u300c\u6574\u6811\u5199\u5165\u300d\u3002\u8bbf\u95ee\u8303\u56f4\u7531\u63d2\u4ef6\u81ea\u8eab\u9650\u5b9a\u5728\u9879\u76ee\u6839\u76ee\u5f55\u5185\uff1a\u89e3\u6790\u540e\u7684\u8def\u5f84\u5fc5\u987b\u4ecd\u5728\u6839\u5185\uff08\u62d2\u7edd\u7b26\u53f7\u94fe\u63a5\u4e0e junction \u9003\u9038\uff09\u3001\u62d2\u7edd\u51ed\u636e\u7c7b\u8def\u5f84\uff08.env*\u3001.ssh/\u3001*.pem\u3001.git/**\uff09\u3001\u4fdd\u5b58\u91c7\u7528\u539f\u5b50\u5199\uff08\u4e34\u65f6\u6587\u4ef6 + \u91cd\u547d\u540d\uff09\u3001\u8986\u76d6\u5728\u7f16\u8f91\u5668\u5916\u88ab\u6539\u52a8\u8fc7\u7684\u6587\u4ef6\u524d\u4f1a\u5148\u8be2\u95ee\u3002\u65e0\u7f51\u7edc\u8bbf\u95ee\uff1b\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u53ea\u4fdd\u5b58\u8bbe\u7f6e\u4e0e\u5199\u5165\u5ba1\u8ba1\u65e5\u5fd7\u3002" } }, "author": "Tioit-Wang", @@ -409,17 +340,17 @@ "downloads": 0, "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/pi.file-manager", "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# \u6587\u4ef6\u7ba1\u7406\u5668\uff08File Manager\uff09\n\n\u5728 PI-Desktop \u7684**\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f**\u91cc\u6d4f\u89c8\u3001\u67e5\u770b\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\uff1a\u5b8c\u6574\u76ee\u5f55\u6811\uff08\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\uff09\u3001\u5de6\u53f3\u5206\u680f\u3001\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58\u3001\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u67e5\u770b\u3001CSV/JSON \u7ed3\u6784\u5316\u67e5\u770b\uff0c\u4ee5\u53ca\u65b0\u5efa\u3001\u91cd\u547d\u540d/\u79fb\u52a8\u3001\u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002\n\n## \u529f\u80fd\n\n- **\u5b8c\u6574\u76ee\u5f55\u6811**\uff1a\u61d2\u52a0\u8f7d\u3001\u53ef\u6309\u5c42\u5c55\u5f00\u3001\u76ee\u5f55\u5728\u524d\u3002\u6bcf\u4e00\u884c\u7684\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\u2014\u2014\u6587\u4ef6\u5939\u3001\u4ee3\u7801\u3001JSON\u3001Markdown\u3001\u6837\u5f0f\u3001HTML/Vue/Svelte\u3001YAML/TOML\u3001Shell\u3001SQL\u3001\u56fe\u7247\u3001\u538b\u7f29\u5305\u3001\u5b57\u4f53\u3001\u9501\u6587\u4ef6\u7b49\u5404\u6709\u81ea\u5df1\u7684\u5b57\u5f62\u4e0e\u914d\u8272\uff1b`package.json`\u3001`Dockerfile`\u3001`LICENSE`\u3001`.gitignore` \u8fd9\u7c7b\u7279\u6b8a\u6587\u4ef6\u540d\u4f18\u5148\u4e8e\u6269\u5c55\u540d\u5224\u5b9a\u3002\n- **\u9009\u4e2d\u6001\u4e0e\u60ac\u505c\u6001\u660e\u786e\u533a\u5206**\uff1a\u60ac\u505c\u662f\u6de1\u6de1\u7684\u4e2d\u6027\u5e95\u8272\uff08\u53ea\u8868\u793a\u9f20\u6807\u4f4d\u7f6e\uff09\uff1b\u9009\u4e2d\u662f\u5f3a\u8c03\u8272\u5e95 + \u5de6\u4fa7\u5f3a\u8c03\u8272\u7ad6\u6761 + \u524d\u666f\u8272\u6587\u5b57 + \u4e2d\u7b49\u5b57\u91cd\uff0c\u9f20\u6807\u79fb\u5f00\u4e5f\u4fdd\u6301\uff0c\u60ac\u505c\u5230\u9009\u4e2d\u884c\u4e0a\u8fd8\u4f1a\u518d\u52a0\u6df1\u4e00\u6863\uff0c\u4e0d\u4f1a\u8ba9\u4eba\u8bef\u4ee5\u4e3a\u9009\u4e2d\u4e22\u4e86\u3002\n- **\u53f3\u952e\u83dc\u5355**\uff1a\u5728\u6587\u4ef6/\u6587\u4ef6\u5939\u4e0a\u53f3\u952e\u53ef\u65b0\u5efa\u6587\u4ef6\u3001\u65b0\u5efa\u6587\u4ef6\u5939\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u3001\u6253\u5f00\u3001\u5237\u65b0\uff1b\u5728\u5217\u8868\u7a7a\u767d\u5904\u53f3\u952e\u5219\u53ea\u63d0\u4f9b\u300c\u5728\u6b64\u65b0\u5efa\u300d\u4e0e\u5237\u65b0\u3002\u652f\u6301 \u2191\u2193 / Home / End / Enter / Esc\u3002\n- **\u5de6\u53f3\u5206\u680f**\uff1a\u5de6\u4fa7\u6587\u4ef6\u5217\u8868\uff0c\u53f3\u4fa7\u5185\u5bb9\u3002\u4e2d\u95f4\u5206\u9694\u6761\u53ef\u62d6\u62fd\uff0c\u5bbd\u5ea6\u4f1a\u8bb0\u4f4f\u3002\n- **\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91**\uff1aCodeMirror 6\uff0c\u884c\u53f7\u3001\u67e5\u627e\u66ff\u6362\u3001\u591a\u5149\u6807\u3001\u62ec\u53f7\u5339\u914d\u3001\u4ee3\u7801\u6298\u53e0\u3002\u6309\u6587\u4ef6\u540d\u52a0\u8f7d\u5bf9\u5e94\u8bed\u8a00\u7684\u8bed\u6cd5\u9ad8\u4eae\uff0c\u8986\u76d6 TypeScript/TSX\u3001JavaScript/JSX\u3001JSON\u3001Markdown\u3001CSS/SCSS/Sass/Less\u3001HTML\u3001Vue\u3001XML\u3001YAML\u3001TOML\u3001Properties\u3001Python\u3001Go\u3001Rust\u3001Java\u3001C/C++\u3001C#\u3001Kotlin\u3001Scala\u3001Dart\u3001Objective-C\u3001PHP\u3001Ruby\u3001Lua\u3001Shell\u3001PowerShell\u3001SQL\u3001Dockerfile\u3001Diff\u3002\u5168\u90e8\u968f\u5305\u5185\u7f6e\u3001\u79bb\u7ebf\u53ef\u7528\uff0c\u4e0d\u8bf7\u6c42\u7f51\u7edc\u3002`Ctrl/Cmd+S` \u6216\u5de5\u5177\u680f\u6309\u94ae\u4fdd\u5b58\uff1b**\u6ca1\u6709\u6539\u52a8\u65f6\u4e0d\u5199\u76d8**\uff0c\u4fdd\u5b58\u540e\u5149\u6807\u4e0e\u6eda\u52a8\u4f4d\u7f6e\u7559\u5728\u539f\u5904\uff08\u4e0d\u4f1a\u8df3\u56de\u5f00\u5934\uff09\uff0c\u754c\u9762\u663e\u793a\u7684\u59cb\u7ec8\u662f\u78c1\u76d8\u4e0a\u90a3\u4efd\u5185\u5bb9\u3002\u7126\u70b9\u4e0d\u5728\u7f16\u8f91\u5668\u91cc\uff08\u521a\u70b9\u8fc7\u5de5\u5177\u680f\u3001\u6216\u505c\u5728\u9884\u89c8 / \u8868\u683c / \u6811\u89c6\u56fe\uff09\u65f6 `Ctrl/Cmd+S` \u540c\u6837\u6709\u6548\u3002\n- **Markdown \u9884\u89c8 / \u7f16\u8f91\u5207\u6362**\uff1a\u6253\u5f00 `.md` / `.markdown` / `.mdx` \u65f6\uff0c\u5de5\u5177\u680f\u51fa\u73b0\u300c\u7f16\u8f91 / \u9884\u89c8\u300d\u5207\u6362\u3002\u9884\u89c8\u652f\u6301\u6807\u9898\u3001\u56f4\u680f\u4ee3\u7801\u5757\uff08\u5e26\u540c\u6837\u7684\u8bed\u6cd5\u9ad8\u4eae\uff09\u3001\u5f15\u7528\u3001\u5206\u9694\u7ebf\u3001\u6709\u5e8f/\u65e0\u5e8f/\u4efb\u52a1\u5217\u8868\uff08\u6309\u7f29\u8fdb\u5d4c\u5957\uff09\u3001\u8868\u683c\uff08\u542b\u5bf9\u9f50\uff09\u3001\u884c\u5185 code / \u7c97\u4f53 / \u659c\u4f53 / \u5220\u9664\u7ebf / \u94fe\u63a5 / \u56fe\u7247\u3002\u5207\u6362\u4f1a\u8bb0\u4f4f\u3002\n- **\u56fe\u7247\u67e5\u770b**\uff1apng / jpg / jpeg / gif / webp / avif / bmp / ico / svg\u3002\u9ed8\u8ba4\u9002\u5e94\u7a97\u53e3\uff0c\u53ef\u5207\u300c\u5b9e\u9645\u5927\u5c0f\u300d\uff1b\u5e95\u90e8\u663e\u793a\u50cf\u7d20\u5c3a\u5bf8\u4e0e\u6587\u4ef6\u4f53\u79ef\uff0c\u821e\u53f0\u94fa\u68cb\u76d8\u683c\uff0c\u900f\u660e\u533a\u57df\u4e00\u773c\u53ef\u89c1\u3002\n- **\u97f3\u89c6\u9891\u64ad\u653e**\uff1amp4 / m4v / mov / webm / ogv / mkv \u7528\u64ad\u653e\u5668\uff0cmp3 / m4a / aac / wav / flac / ogg / opus / weba \u7528\u97f3\u9891\u6761\u3002**\u4e0d\u81ea\u52a8\u64ad\u653e**\uff1b\u7f16\u7801\u6216\u5c01\u88c5\u4e0d\u88ab\u652f\u6301\u65f6\u7ed9\u660e\u786e\u63d0\u793a\uff0c\u800c\u4e0d\u662f\u7559\u4e00\u5757\u9ed1\u6846\u3002\n- **CSV / TSV \u8868\u683c\uff08\u5206\u9875\uff09**\uff1a\u6253\u5f00 `.csv` / `.tsv` \u5c31\u662f\u8868\u683c\uff0c\u9ed8\u8ba4**\u6bcf\u9875 1000 \u884c**\uff1b\u5e95\u90e8\u5de5\u5177\u6761\u53ef\u4ee5\u7ffb\u9875\uff08\u9996\u9875/\u4e0a\u4e00\u9875/\u4e0b\u4e00\u9875/\u672b\u9875\uff09\u3001\u770b\u300c\u5f53\u524d\u8303\u56f4 / \u603b\u884c\u6570\u300d\uff0c\u4e5f\u80fd\u6539\u6bcf\u9875\u884c\u6570\uff08100\u20135000\uff0c\u9009\u62e9\u4f1a\u8bb0\u4f4f\uff09\u3002\u9996\u884c\u5f53\u8868\u5934\u4e14\u5438\u9876\uff0c\u6700\u5de6\u4e00\u5217\u662f\u884c\u53f7\u4e14\u5438\u5de6\uff0c\u6574\u884c\u60ac\u505c\u9ad8\u4eae\uff0c\u6574\u5217\u90fd\u662f\u6570\u5b57\u65f6\u81ea\u52a8\u53f3\u5bf9\u9f50\uff0c\u88ab\u7701\u7565\u53f7\u622a\u65ad\u7684\u503c\u60ac\u505c\u53ef\u770b\u5168\u3002**\u70b9\u8868\u5934\u6392\u5e8f**\uff1a\u5347\u5e8f \u2192 \u964d\u5e8f \u2192 \u53d6\u6d88\uff08\u56de\u5230\u6587\u4ef6\u539f\u5e8f\uff09\uff1b\u6574\u5217\u90fd\u662f\u6570\u5b57\u6309\u6570\u503c\u6bd4\uff0c\u5426\u5219\u6309\u81ea\u7136\u5e8f\u6587\u672c\u6bd4\uff0c\u7a7a\u503c\u6c38\u8fdc\u6c89\u5e95\u3002\u89e3\u6790\u652f\u6301\u5f15\u53f7\u5305\u88f9\u3001`\"\"` \u8f6c\u4e49\u3001\u5b57\u6bb5\u5185\u6362\u884c\u3001CRLF \u4e0e\u53c2\u5dee\u7684\u884c\uff1b\u5217\u6570\u4e0a\u9650 60\u3001\u89e3\u6790\u4e0a\u9650 20 \u4e07\u884c\uff0c\u8d85\u51fa\u4f1a\u5728\u5e95\u90e8\u8bf4\u660e\u3002\u5de5\u5177\u680f\u53ef\u5207\u56de\u6e90\u7801\u7f16\u8f91\u3002\n- **JSON \u6298\u53e0\u6811**\uff1a`.json` / `.jsonc` / `.json5` \u53ef\u5207\u6811\u89c6\u56fe\uff0c\u9ed8\u8ba4\u5c55\u5f00\u4e24\u5c42\u3001\u5355\u8282\u70b9\u6700\u591a\u76f4\u63a5\u94fa 100 \u4e2a\u952e\uff0c\u957f\u5b57\u7b26\u4e32\u622a\u65ad\uff08\u5b8c\u6574\u503c\u5728\u60ac\u505c\u63d0\u793a\u91cc\uff09\u3002`//` \u6ce8\u91ca\u3001\u5c3e\u9017\u53f7\u8fd9\u7c7b\u975e\u4e25\u683c JSON \u4e0d\u4f1a\u70b8\u9762\u677f\uff0c\u53ea\u663e\u793a\u300c\u89e3\u6790\u5931\u8d25 + \u539f\u56e0\u300d\uff0c\u6e90\u7801\u89c6\u56fe\u7167\u5e38\u53ef\u7f16\u8f91\u3002\n- **SQLite \u6570\u636e\u5e93\uff08\u53ea\u8bfb\uff09**\uff1a`.db` / `.sqlite` / `.sqlite3` / `.db3` \u6253\u5f00\u5373\u7528\u2014\u2014\u9876\u90e8\u6982\u89c8\uff08\u4f53\u79ef\u3001\u9875\u5927\u5c0f \u00d7 \u9875\u6570\u3001\u7f16\u7801\u3001SQLite \u5e93\u7248\u672c\u3001WAL \u63d0\u793a\uff09\uff0c\u300c\u6d4f\u89c8\u300d\u9875\u7b7e\u91cc\u9009\u8868\u6216\u89c6\u56fe\u770b\u6570\u636e\uff08\u5206\u9875\u3001\u70b9\u8868\u5934\u6392\u5e8f\u3001\u6700\u5de6 `rowid`\u3001`NULL` \u7070\u663e\u3001BLOB \u53ea\u663e\u793a\u4f53\u79ef\uff09\u3001\u300c\u7ed3\u6784\u300d\u6309\u94ae\u770b\u5217\u4e0e\u7c7b\u578b/\u7d22\u5f15/\u89e6\u53d1\u5668/`CREATE` \u539f\u6587\uff0c\u4ee5\u53ca\u300cSQL\u300d\u9875\u7b7e\u91cc\u7684**\u53ea\u8bfb\u67e5\u8be2\u6846**\uff08`Ctrl/Cmd+Enter` \u8fd0\u884c\uff0c\u53ef\u9009\u884c\u6570\u4e0a\u9650\uff0c\u663e\u793a\u8017\u65f6\u4e0e\u622a\u65ad\u63d0\u793a\uff09\u3002\n \u8fd9\u662f\u63d2\u4ef6\u91cc**\u552f\u4e00\u80fd\u6253\u5f00\u5927\u6587\u4ef6**\u7684\u9884\u89c8\u7c7b\u578b\uff1a\u6570\u636e\u5e93\u7684\u5b57\u8282\u6839\u672c\u4e0d\u8fdb\u89c6\u56fe\uff0c\u4e3b\u8fdb\u7a0b\u6bcf\u6b21\u53ea\u53d6\u4e00\u9875\u3002\n- **\u4e8c\u8fdb\u5236\u8bf4\u6e05\u695a**\uff1azip / apk / exe \u8fd9\u7c7b\u6ca1\u6709\u53ef\u9884\u89c8\u5f62\u6001\u7684\u6587\u4ef6\uff0c\u63d0\u793a\u300c\u4e8c\u8fdb\u5236\u6587\u4ef6\uff08zip\u3001apk\u3001exe \u7b49\uff09\uff0c\u6682\u4e0d\u652f\u6301\u9884\u89c8\u300d\uff0c\u4e0d\u505a\u9b54\u6cd5\u8bc6\u522b\uff0c\u4e5f\u4e0d\u5047\u88c5\u80fd\u89e3\u538b\u3002\n- **\u6587\u4ef6\u64cd\u4f5c**\uff1a\u65b0\u5efa\u6587\u4ef6\u3001\u65b0\u5efa\u6587\u4ef6\u5939\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u5230\u6307\u5b9a\u76ee\u5f55\u3002\n- **\u6309\u6587\u4ef6\u540d\u641c\u7d22**\uff1a\u6574\u4e2a\u9879\u76ee\u8303\u56f4\u5185\u5206\u9875\u641c\u7d22\uff0c\u70b9\u51fb\u7ed3\u679c\u76f4\u63a5\u8df3\u8f6c\u5e76\u5c55\u5f00\u5230\u8be5\u6587\u4ef6\u3002\n- **\u5ffd\u7565\u89c4\u5219**\uff1a\u9879\u76ee\u91cc\u6709 `.gitignore` / `.ignore` \u5c31\u6309\u89c4\u5219\u9690\u85cf\u6761\u76ee\uff08\u53ef\u7528\u5de5\u5177\u680f\u7684\u773c\u775b\u6309\u94ae\u5207\u56de\u663e\u793a\uff09\uff1b**\u4e00\u4e2a\u89c4\u5219\u6587\u4ef6\u90fd\u6ca1\u6709\u65f6\uff0c\u76ee\u5f55\u6811\u5c55\u793a\u5168\u90e8\u6761\u76ee**\u3002\n- **\u8ddf\u968f\u5bbf\u4e3b\u5916\u89c2**\uff1a\u4eae/\u6697\u914d\u8272\u4e0e\u754c\u9762\u8bed\u8a00\uff08\u4e2d\u6587 / English\uff09\u8ddf\u968f PI-Desktop \u4e3b\u4f53\uff0c\u7f16\u8f91\u5668\u4e0e\u9884\u89c8\u7684\u9ad8\u4eae\u914d\u8272\u4e00\u5e76\u8ddf\u968f\u3002\n\n## \u5b89\u88c5\n\n\u5728 PI-Desktop \u7684 Plugins \u9875\u9762\uff1a\n\n1. **Load development plugin** \u2192 \u9009\u62e9\u672c\u76ee\u5f55\uff1b\u6216\n2. \u7528 `dist/pi.file-manager-0.3.0.piplug` \u8d70 **Install plugin package**\u3002\n\n\u88c5\u597d\u540e\u6253\u5f00\u4e00\u4e2a\u9879\u76ee\uff0c\u5728**\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u5934\u90e8\u7684\u5207\u6362\u83dc\u5355 \u2192 \u201cPlugin views / \u63d2\u4ef6\u89c6\u56fe\u201d** \u5206\u7ec4\u91cc\u70b9\u51fb\u300c\u6587\u4ef6\u7ba1\u7406\u5668\u300d\u3002\n\n> \u8fd9\u4e2a\u63d2\u4ef6\u6ca1\u6709\u547d\u4ee4\u9762\u677f\u5165\u53e3\uff0c\u4e5f\u4e0d\u6ce8\u518c\u9762\u677f\u7a97\u53e3\u2014\u2014\u5b83\u53ea\u63d0\u4f9b\u4e00\u4e2a\u505c\u9760\u5728\u53f3\u4fa7\u680f\u7684\u89c6\u56fe\uff08`contributes.views`\uff09\u3002\u5bbf\u4e3b\u6ca1\u6709\u63d0\u4f9b\u300c\u7528\u547d\u4ee4\u6253\u5f00\u89c6\u56fe\u300d\u7684\u901a\u9053\uff0c\u6240\u4ee5\u8fd9\u91cc\u4e5f\u4e0d\u58f0\u660e\u8bef\u5bfc\u6027\u7684\u547d\u4ee4\u3002\n\n## \u5f00\u53d1\n\n```bash\ncd views-src\npnpm install\npnpm typecheck\npnpm build # \u4ea7\u7269\u8f93\u51fa\u5230 ../views\uff08\u5165\u5e93\uff0c\u5bbf\u4e3b\u52a0\u8f7d views/index.html\uff09\n```\n\n`views-src` \u662f\u6e90\u7801\uff08React + TypeScript + Tailwind + CodeMirror 6\uff09\uff1b`views` \u662f\u6784\u5efa\u4ea7\u7269\uff0c\u76f4\u63a5\u5165\u5e93\u3002\u6784\u5efa\u4e3a **IIFE \u5355\u6587\u4ef6**\u5e76\u5185\u8054\u5168\u90e8\u52a8\u6001 import\u2014\u2014\u5bbf\u4e3b\u7684\u89c6\u56fe\u7528 `file://` \u52a0\u8f7d\u9875\u9762\uff0c`type=\"module\"` \u4e0e `crossorigin` \u4f1a\u88ab Chromium \u62e6\u6389\uff0c\u6240\u4ee5 `vite.config.ts` \u91cc\u6709\u4e00\u4e2a `fileProtocolCompat` \u63d2\u4ef6\u8d1f\u8d23\u6539\u5199 `index.html`\u3002\n\n`main.js` \u662f\u624b\u5199\u3001\u96f6\u4f9d\u8d56\u7684 CommonJS\uff0c\u63d2\u4ef6\u7684\u4f9d\u8d56\u4e0d\u4f1a\u88ab\u5b89\u88c5\uff0c\u6240\u4ee5\u4e0d\u8981\u5f80\u5b83\u91cc\u9762 `require` \u7b2c\u4e09\u65b9\u5305\u3002\n\n### \u6821\u9a8c\n\n```bash\ncd views-src\npnpm typecheck\npnpm verify # \u8bed\u6cd5\u9ad8\u4eae + Markdown \u9884\u89c8 + \u67e5\u770b\u5668\u7684\u79bb\u7ebf\u6821\u9a8c\n```\n\n`pnpm verify` \u8dd1\u4e09\u4e2a\u4e0d\u9700\u8981 DOM \u7684\u6821\u9a8c\u811a\u672c\uff0c\u7528\u4e8e\u8986\u76d6\u300c\u9759\u9ed8\u5931\u8d25\u300d\u7684\u4e09\u6761\u94fe\u8def\uff1a\n\n- **`verify-highlight.mjs`**\uff1a\u5bf9 17 \u79cd\u771f\u5b9e\u6587\u4ef6\u8d70\u5b8c\u6574\u7684\n `\u6587\u4ef6\u540d \u2192 \u8bed\u8a00\u89e3\u6790 \u2192 \u8f7d\u5165 \u2192 \u8bed\u6cd5\u6811 \u2192 \u9ad8\u4eae token` \u94fe\u8def\uff0c\u65ad\u8a00\u6bcf\u79cd\u90fd\u4ea7\u51fa\u8db3\u591f\u591a\u7684\n \u4e0d\u540c\u9ad8\u4eae class\uff0c\u5e76\u53cd\u5411\u65ad\u8a00 `.txt` / `.bin` / `.zip` / `.png` / `LICENSE` \u4e0d\u4f1a\u88ab\u8bef\u8ba4\u9886\u3002\n CodeMirror \u7684\u9ad8\u4eae\u662f\u300c\u89e3\u6790\u4e0d\u51fa\u6765\u5c31\u4ec0\u4e48\u90fd\u4e0d\u62a5\u300d\u7684\u5178\u578b\u2014\u2014\u53ea grep \u4ea7\u7269\u5b57\u7b26\u4e32\u4f1a\u6f0f\u6389\n \u8fd0\u884c\u65f6\u95ee\u9898\uff08\u672c\u63d2\u4ef6\u7b2c\u4e00\u7248\u5c31\u8e29\u8fc7\uff1a`basicSetup` \u81ea\u5e26\u7684 fallback \u9ad8\u4eae\u5668\u628a\u81ea\u5df1\u7684\u6837\u5f0f\u76d6\u4f4f\u4e86\uff09\u3002\n- **`verify-markdown.mjs`**\uff1a\u65ad\u8a00\u9884\u89c8\u771f\u5b9e\u4ea7\u51fa\u7684\u5143\u7d20\u6811\uff08\u6807\u9898/\u5217\u8868/\u8868\u683c/\u4efb\u52a1\u5217\u8868/\u5d4c\u5957\n \u5f3a\u8c03\uff09\uff0c\u94fe\u63a5\u534f\u8bae\u767d\u540d\u5355\uff0c\u4ee5\u53ca**\u4e0d\u5b58\u5728 `dangerouslySetInnerHTML`**\u3001\u539f\u59cb HTML \u88ab\u8f6c\u4e49\u3002\n \u5176\u4e2d\u4e00\u4e2a\u56de\u5f52\u7528\u4f8b\u4e13\u95e8\u76ef\u4f4f\u300c\u884c\u5185\u89e3\u6790\u9012\u5f52\u65f6\u5171\u4eab\u5e26 `g` \u7684\u6b63\u5219\u300d\u2014\u2014\u90a3\u4f1a\u8ba9\u9884\u89c8\u5361\u6b7b\u5e76\u5403\u5149\u5185\u5b58\u3002\n- **`verify-viewers.mjs`**\uff1a\u65ad\u8a00 CSV \u89e3\u6790\u7684 12 \u4e2a\u7528\u4f8b\uff08\u5f15\u53f7\u5305\u88f9\u3001`\"\"` \u8f6c\u4e49\u3001\u5b57\u6bb5\u5185\u6362\u884c\u3001\n CRLF\u3001\u53c2\u5dee\u7684\u884c\u3001\u622a\u65ad\u4e0e\u5217\u6570\u5c01\u9876\uff09\u3001\u5206\u9875\u5207\u7247\uff08\u9875\u7801\u8d8a\u754c\u5939\u7d27\u3001\u672b\u9875\u4e0d\u6ee1\u3001\u7a7a\u8868\u4e5f\u6709 1 \u9875\uff09\u3001\n \u6570\u5b57\u5217\u8bc6\u522b\u3001JSON \u5408\u6cd5/\u975e\u6cd5\u4e24\u6761\u8def\u5f84\uff0c\u4ee5\u53ca\u300c\u54ea\u4e2a\u6587\u4ef6\u6709\u54ea\u51e0\u79cd\u770b\u6cd5\u3001\u9ed8\u8ba4\u843d\u5728\u54ea\u4e00\u4fa7\u300d\u7684\u5224\u5b9a\u3002\n \u8868\u683c\u4e0e\u6811\u90fd\u662f\u300c\u628a\u6587\u4ef6\u5185\u5bb9\u53d8\u6210\u754c\u9762\u300d\u7684\u8def\u5f84\uff0c\u89e3\u6790\u5668\u9519\u4e86\u4e0d\u4f1a\u629b\u5f02\u5e38\u3001\u53ea\u4f1a\u9759\u9ed8\u663e\u793a\u9519\u3002\n\n\u5192\u70df\u6d4b\u8bd5\uff08\u5728\u4ed3\u5e93\u6839\u76ee\u5f55\u8fd0\u884c\uff09\uff1a\n\n```bash\nnode ../pi-file-manager-smoke-test.cjs\n```\n\n## \u6570\u636e\u4e0e\u5b89\u5168\n\n**\u8fd9\u4e2a\u63d2\u4ef6\u7528\u81ea\u5df1\u7684 Node `fs` \u8bfb\u5199\u5f53\u524d\u9879\u76ee\u91cc\u7684\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5bbf\u4e3b\u7684 `pi.fs` \u7f51\u5173\u3002**\n\n\u4e3a\u4ec0\u4e48\u5fc5\u987b\u8fd9\u6837\uff1a\u5bbf\u4e3b\u7684 `manifest.fs` \u5728\u8bed\u6cd5\u4e0a\u5c31**\u7981\u6b62\u6574\u6811\u5199\u5165**\uff08\u5199\u5165 scope \u4e0d\u80fd\u662f `**`\uff09\uff0c\u4efb\u4f55\u4e00\u4e2a\u80fd\u901a\u8fc7\u6821\u9a8c\u7684\u7a84 scope \u90fd\u4f1a\u8ba9\u300c\u4fdd\u5b58\u300d\u53d8\u6210\u6bcf\u6b21\u90fd\u5f39\u6743\u9650\u786e\u8ba4\uff1b\u800c\u4e14 `pi.fs.*` \u6ca1\u6709\u521b\u5efa/\u91cd\u547d\u540d/\u79fb\u52a8\uff0c`fs.glob` \u4e0e `fs.list` \u8fd8\u6709\u6761\u6570\u4e0a\u9650\u3001\u4f1a\u8df3\u8fc7 `node_modules`\u3001\u5c4f\u853d\u51ed\u636e\u8def\u5f84\u3002\u4e0e\u4e4b\u5bf9\u5e94\u7684\u4ee3\u4ef7\u662f\uff1a**\u5bbf\u4e3b\u7684\u6743\u9650\u7f51\u5173\u4e0d\u4ecb\u5165\u8fd9\u4e9b\u8c03\u7528**\uff0c\u6240\u4ee5\u5b89\u5168\u8d23\u4efb\u7531\u63d2\u4ef6\u81ea\u5df1\u627f\u62c5\u3002manifest \u91cc\u56e0\u6b64\u53ea\u7533\u62a5\u4e86 `ui.view`\uff0c\u6ca1\u6709\u7533\u62a5 `fs.read` / `fs.write`\u2014\u2014\u7533\u62a5\u4e86\u53cd\u800c\u662f\u8bef\u5bfc\uff08\u5199\u6743\u9650\u6839\u672c\u65e0\u6cd5\u8bda\u5b9e\u7533\u62a5\uff09\u3002\n\n\u63d2\u4ef6\u81ea\u5df1\u5b9e\u65bd\u7684\u5168\u90e8\u9650\u5236\uff1a\n\n| \u9650\u5236 | \u8bf4\u660e |\n|---|---|\n| \u8def\u5f84\u5305\u542b | \u53ea\u63a5\u53d7\u76f8\u5bf9\u9879\u76ee\u6839\u7684\u8def\u5f84\uff1b\u7edd\u5bf9\u8def\u5f84\u3001`..`\u3001\u4ee5\u53ca realpath \u540e\u843d\u5230\u6839\u76ee\u5f55\u4e4b\u5916\u7684**\u7b26\u53f7\u94fe\u63a5 / junction** \u4e00\u5f8b\u62d2\u7edd |\n| \u654f\u611f\u8def\u5f84 | `.env*`\u3001`.ssh`\u3001`.aws`\u3001`.gnupg`\u3001`.git/**`\u3001`*.pem`\u3001`*.key`\u3001`*.p12` \u7b49\u8bfb\u5199\u5168\u62d2\uff1b`node_modules` \u53ef\u8bfb\u4e0d\u53ef\u5199 |\n| \u539f\u5b50\u5199 | \u5148\u5199\u540c\u76ee\u5f55\u4e34\u65f6\u6587\u4ef6 \u2192 `fsync` \u2192 \u4fdd\u7559\u539f\u6587\u4ef6\u6743\u9650\u4f4d \u2192 `rename` \u8986\u76d6\uff0c\u4e2d\u65ad\u4e0d\u4f1a\u7559\u4e0b\u534a\u5199\u6587\u4ef6 |\n| \u51b2\u7a81\u68c0\u6d4b | \u4ee5 `mtimeMs` + \u6587\u4ef6\u5927\u5c0f\u4f5c\u4e3a\u4e50\u89c2\u9501\uff1b\u6587\u4ef6\u5728\u7f16\u8f91\u5668\u4e4b\u5916\u88ab\u6539\u52a8\u8fc7\u65f6**\u4e0d\u4f1a\u9759\u9ed8\u8986\u76d6**\uff0c\u4f1a\u5148\u5f39\u5bf9\u8bdd\u6846\u8ba9\u4f60\u9009\u62e9\u8986\u76d6 / \u653e\u5f03 / \u91cd\u65b0\u52a0\u8f7d |\n| \u5199\u5165\u5ba1\u8ba1 | \u6bcf\u6b21\u5199\u5165\u8ffd\u52a0\u4e00\u884c\u5230\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u7684 `write-audit.jsonl`\uff08\u7ea6 1 MiB \u540e\u8f6e\u8f6c\uff09\uff0c\u56e0\u4e3a\u5bbf\u4e3b\u5ba1\u8ba1\u4e0d\u5230\u8fd9\u6761\u8def\u5f84 |\n| \u6570\u636e\u5e93\u53ea\u8bfb | \u4ee5 `readOnly` \u6253\u5f00 + `PRAGMA query_only = 1`\uff08\u5b9e\u6d4b `DROP`/`INSERT` \u4f1a\u88ab SQLite \u81ea\u5df1\u62d2\u7edd\uff09\uff0c\u518d\u53e0\u4e00\u5c42\u8bed\u53e5\u767d\u540d\u5355\uff1a\u53ea\u653e\u884c `select` / `with` / `values` / `explain` \u4e0e\u53ea\u8bfb `pragma`\uff0c\u4e14\u5fc5\u987b\u662f**\u5355\u6761**\u8bed\u53e5\u2014\u2014`node:sqlite` \u7684 prepare \u5bf9\u591a\u8bed\u53e5\u662f\u653e\u884c\u7684\uff08\u5b9e\u6d4b `select 1; select 2` \u53ea\u6267\u884c\u7b2c\u4e00\u6761\u3001\u4e0d\u62a5\u9519\uff09\uff0c\u6240\u4ee5\u5fc5\u987b\u81ea\u5df1\u62e6\u3002\u8868\u540d/\u5217\u540d\u5148\u4e0e `sqlite_schema` \u6838\u5bf9\u518d\u62fc\u5f15\u53f7\uff0c\u7edd\u4e0d\u76f4\u63a5\u63d2\u503c |\n| \u4f53\u79ef\u4e0a\u9650 | \u6587\u672c\u9884\u89c8 2 MiB\u3001\u56fe\u7247 8 MiB\u3001\u97f3\u89c6\u9891 24 MiB\u3001\u5199\u5165 8 MiB\u3002\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u5355\u72ec\u8bbe\u9650\u662f\u56e0\u4e3a\u5b83\u4eec\u7684\u5b57\u8282\u8981\u4ee5 base64 \u968f\u54cd\u5e94\u53d1\u7ed9\u89c6\u56fe\uff08\u81a8\u80c0\u7ea6 1/3\uff09\uff1b\u8d85\u9650\u65f6\u63d0\u793a\u91cc\u4f1a\u5e26\u4e0a\u5177\u4f53\u4e0a\u9650 |\n\n\u884c\u4e3a\u4e0a\u7684\u4e24\u70b9\u8bf4\u660e\uff1a\n\n- `.git` \u76ee\u5f55**\u4e0d\u4f1a\u51fa\u73b0\u5728\u6811\u91cc**\uff08\u4f53\u91cf\u5de8\u5927\u4e14\u6c38\u8fdc\u65e0\u7528\uff09\u3002\n- \u5ffd\u7565\u89c4\u5219\u6765\u81ea `.gitignore` \u4e0e `.ignore`\uff08\u652f\u6301 `!` \u53d6\u53cd\u3001\u672b\u5c3e `/`\u3001\u524d\u5bfc `/` \u951a\u5b9a\u3001`*` / `?` / `**`\uff09\u3002\u8fd9\u662f gitignore \u7684\u4e00\u4e2a\u5b50\u96c6\uff0c\u4e0d\u652f\u6301 `\\` \u8f6c\u4e49\u548c `[a-z]` \u5b57\u7b26\u7c7b\uff1b\u504f\u5dee\u53ea\u5f71\u54cd\u300c\u663e\u4e0d\u663e\u793a\u300d\uff0c\u4e14\u968f\u65f6\u53ef\u4ee5\u7528\u5de5\u5177\u680f\u7684\u773c\u775b\u6309\u94ae\u7ffb\u76d8\u3002\n\n**Markdown \u9884\u89c8\u7684\u5b89\u5168\u505a\u6cd5**\uff1a\u9884\u89c8**\u4e0d\u4f7f\u7528** `dangerouslySetInnerHTML`\uff0c\u800c\u662f\u628a Markdown \u89e3\u6790\u6210 React \u5143\u7d20\u2014\u2014\u8282\u70b9\u7531 React \u8f6c\u4e49\uff0c\u7ed3\u6784\u4e0a\u4e0d\u5b58\u5728\u6ce8\u5165\u9762\uff0c\u56e0\u6b64\u4e5f\u4e0d\u9700\u8981\u989d\u5916\u7684 sanitizer\u3002\u539f\u56e0\u5f88\u76f4\u63a5\uff1a\u8fd9\u4e2a\u89c6\u56fe\u7684 bridge \u901a\u5411\u4e00\u4e2a\u80fd\u8bfb\u5199\u9879\u76ee\u6587\u4ef6\u7684\u63d2\u4ef6\u4e3b\u8fdb\u7a0b\uff0c\u9884\u89c8\u91cc\u7684 XSS \u5c31\u7b49\u4e8e\u4efb\u610f\u6587\u4ef6\u5199\u5165\u3002\u9884\u89c8\u4e2d\u7684\u94fe\u63a5\u4e5f\u4e0d\u4f1a\u5bfc\u822a\uff08\u70b9\u4e00\u4e0b\u5c31\u79bb\u5f00\u63d2\u4ef6\u9875\u9762\u56de\u4e0d\u6765\u4e86\uff09\uff0c\u70b9\u51fb\u53ea\u4f1a\u628a\u5730\u5740\u663e\u793a\u51fa\u6765\u3002\n\n**\u4e0d\u8bbf\u95ee\u7f51\u7edc**\uff1a\u6ca1\u6709 `net.domains`\uff0c\u8fd0\u884c\u65f6\u4e0d\u53d1\u8d77\u4efb\u4f55\u8bf7\u6c42\u3002\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u91cc\u53ea\u653e\u8bbe\u7f6e\uff08\u5206\u680f\u5bbd\u5ea6\u3001\u663e\u793a\u5f00\u5173\u3001Markdown \u9ed8\u8ba4\u89c6\u56fe\uff09\u548c\u4e0a\u9762\u90a3\u4efd\u5ba1\u8ba1\u65e5\u5fd7\u3002\n\n## \u5df2\u77e5\u9650\u5236\n\n- **\u4e0d\u5220\u9664\u6587\u4ef6/\u76ee\u5f55**\u3002\u5220\u9664\u662f\u7834\u574f\u6027\u64cd\u4f5c\uff0c\u800c\u4e14\u5bbf\u4e3b\u7684 `fs.remove` \u5e76\u6ca1\u6709\u5f00\u653e\u7ed9\u89c6\u56fe\u6865\uff0c\u53ea\u80fd\u8d70\u539f\u751f `rm`\u2014\u2014\u672c\u671f\u4e0d\u505a\u3002\n- **\u6ca1\u6709\u300c\u5728\u6587\u4ef6\u5939\u4e2d\u663e\u793a\u300d/\u300c\u7528\u7cfb\u7edf\u7a0b\u5e8f\u6253\u5f00\u300d**\uff1a\u8fd9\u4e24\u4e2a\u5bbf\u4e3b\u901a\u9053\u9700\u8981 `fs.read` \u6743\u9650\uff0c\u800c\u672c\u63d2\u4ef6\u6709\u610f\u4e0d\u7533\u62a5\u4efb\u4f55 fs \u6743\u9650\u3002\n- **Markdown \u9884\u89c8\u91cc\u7684\u56fe\u7247\u4ecd\u662f\u5360\u4f4d\u5757**\uff1a`![](path)` \u663e\u793a\u6210\u5e26\u6587\u4ef6\u540d\u7684\u5360\u4f4d\u7b26\u3002\u6587\u4ef6\u7ea7\u7684\u56fe\u7247\u67e5\u770b\u8d70 data URI \u5df2\u7ecf\u53ef\u7528\uff0c\u4f46\u9884\u89c8\u91cc\u7684\u56fe\u7247\u8981\u9010\u5f20\u6309\u76f8\u5bf9\u8def\u5f84\u53bb\u8bfb\uff0c\u672c\u8f6e\u6ca1\u505a\u3002\u539f\u56e0\u8fd8\u662f\u90a3\u6761\uff1a\u9762\u677f\u4ee5 `file://` \u52a0\u8f7d\uff0c\u76f8\u5bf9\u8def\u5f84\u6307\u5411\u89c6\u56fe\u81ea\u8eab\u800c\u4e0d\u662f\u9879\u76ee\u3002\n- **\u6587\u4ef6\u76d1\u542c**\uff1a\u5bbf\u4e3b\u6ca1\u6709\u300c\u63d2\u4ef6 \u2192 \u89c6\u56fe\u300d\u7684\u63a8\u9001\u901a\u9053\uff08\u89c6\u56fe\u53ea\u80fd\u53d1\u8d77\u8bf7\u6c42\u3001\u62ff\u54cd\u5e94\uff09\uff0c\u6240\u4ee5\u5916\u90e8\u6539\u52a8\u4e0d\u662f\u5b9e\u65f6\u7684\uff1b\u4fdd\u5b58\u540e\u4f1a\u5237\u65b0\u76ee\u5f55\uff0c\u5de5\u5177\u680f\u7684\u300c\u4ece\u78c1\u76d8\u91cd\u65b0\u52a0\u8f7d\u300d\u968f\u65f6\u53ef\u70b9\uff0c\u7528\u6765\u628a\u522b\u5904\u6539\u52a8\u62c9\u8fdb\u6765\uff08\u5f53\u524d\u6709\u672a\u4fdd\u5b58\u6539\u52a8\u65f6\u4f1a\u5148\u786e\u8ba4\uff09\u3002\n- **\u4e8c\u8fdb\u5236\u4e0d\u53ef\u9884\u89c8**\uff1azip / apk / exe / tiff \u53ea\u7ed9\u63d0\u793a\u2014\u2014\u4e0d\u89e3\u538b\u3001\u4e0d\u5217\u5f52\u6863\u5185\u5bb9\u3001\u4e0d\u505a\u5341\u516d\u8fdb\u5236\u67e5\u770b\u3002TIFF \u5355\u72ec\u8bf4\u660e\uff1aChromium \u89e3\u4e0d\u4e86\u5b83\uff0c\u6240\u4ee5\u6309\u4e8c\u8fdb\u5236\u5904\u7406\uff0c\u800c\u4e0d\u662f\u663e\u793a\u4e00\u5f20\u7834\u56fe\u3002\n- **\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u53ea\u8bfb**\uff1a\u53ea\u505a\u67e5\u770b\uff0c\u4e0d\u8fdb\u7f16\u8f91\u5668\u3001\u4e0d\u80fd\u6539\uff08\u4e0d\u5f71\u54cd\u5176\u5b83\u6587\u4ef6\u7684\u7f16\u8f91\uff09\u3002\n- **\u5927\u6587\u4ef6\u4e0d\u9884\u89c8**\uff1a\u56fe\u7247\u8d85\u8fc7 8 MiB\u3001\u97f3\u89c6\u9891\u8d85\u8fc7 24 MiB \u53ea\u63d0\u793a\u4e0a\u9650\u3002\n- **`.avi` \u8fd9\u7c7b\u6309\u4e8c\u8fdb\u5236\u5904\u7406**\uff08Chromium \u653e\u4e0d\u4e86\uff09\uff1b`.mkv` / `.mov` \u80fd\u4e0d\u80fd\u64ad\u653e\u53d6\u51b3\u4e8e\u91cc\u9762\u7684\u7f16\u7801\uff0c\u653e\u4e0d\u4e86\u4f1a\u660e\u786e\u63d0\u793a\u3002\n- **SQLite \u53ea\u8bfb**\uff1a\u4e0d\u5199\u5165\u3001\u4e0d VACUUM\u3001\u4e0d\u5efa `-shm`\u3002**WAL \u6a21\u5f0f\u4e0b\u5c1a\u672a\u5408\u5e76\u56de\u4e3b\u6587\u4ef6\u7684\u5185\u5bb9\u770b\u4e0d\u5230**\uff08\u9876\u90e8\u6709\u63d0\u793a\uff09\uff1b\u52a0\u5bc6\u5e93\uff08SQLCipher\uff09\u4e0e\u635f\u574f\u6587\u4ef6\u90fd\u660e\u786e\u62a5\u300c\u8bfb\u4e0d\u4e86\u300d\uff0c\u4e0d\u4f1a\u9759\u9ed8\u7a7a\u767d\u3002\n- **\u6570\u636e\u5e93\u6df1\u7ffb\u9875\u6709\u4e0a\u9650**\uff08OFFSET \u2264 10 \u4e07\u884c\uff09\uff1a`node:sqlite` \u662f\u540c\u6b65 API\u3001\u6ca1\u6709\u4e2d\u65ad\u63a5\u53e3\uff0c\u53ea\u80fd\u8ba9\u67e5\u8be2\u5929\u751f\u6709\u754c\u2014\u2014\u8981\u770b\u66f4\u8fdc\u5c31\u5728 SQL \u6846\u91cc\u52a0\u6761\u4ef6\u6536\u7a84\u3002\n- **\u8868\u6e05\u5355\u91cc\u7684\u884c\u6570\u662f\u4f30\u7b97**\uff08`max(rowid)`\uff09\uff1a\u7cbe\u786e `COUNT(*)` \u5728\u5927\u8868\u4e0a\u662f\u5168\u8868\u626b\u63cf\uff0c\u8bf7\u6309\u9700\u5728 SQL \u6846\u91cc\u6267\u884c\u3002\n- **\u9700\u8981\u5bbf\u4e3b\u8fd0\u884c\u65f6\u5e26 `node:sqlite`**\uff08Node \u2265 22.5\uff1b\u5f53\u524d\u5bbf\u4e3b Electron 43 / Node 24 \u6ee1\u8db3\uff09\u3002\u63a2\u6d4b\u4e0d\u5230\u65f6\u63d2\u4ef6\u4e0d\u4f1a\u5d29\uff0c\u53ea\u663e\u793a\u6982\u89c8\u5e76\u8bf4\u660e\u539f\u56e0\u3002\n\n## \u8bb8\u53ef\n\nMIT\u3002\n", - "safetyNotes": "\u63d2\u4ef6\u5728\u81ea\u5df1\u7684\u8fdb\u7a0b\u5185\u901a\u8fc7 Node fs \u8bfb\u5199\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\u2014\u2014\u5bbf\u4e3b\u7684\u6743\u9650\u7f51\u5173\u4e0d\u4ecb\u5165\u8fd9\u4e9b\u8c03\u7528\uff0cmanifest \u4e5f\u65e0\u6cd5\u7533\u62a5\u300c\u6574\u6811\u5199\u5165\u300d\u3002\u8bbf\u95ee\u8303\u56f4\u7531\u63d2\u4ef6\u81ea\u8eab\u9650\u5b9a\u5728\u9879\u76ee\u6839\u76ee\u5f55\u5185\uff1a\u89e3\u6790\u540e\u7684\u8def\u5f84\u5fc5\u987b\u4ecd\u5728\u6839\u5185\uff08\u62d2\u7edd\u7b26\u53f7\u94fe\u63a5\u4e0e junction \u9003\u9038\uff09\u3001\u62d2\u7edd\u51ed\u636e\u7c7b\u8def\u5f84\uff08.env*\u3001.ssh/\u3001*.pem\u3001.git/**\uff09\u3001\u4fdd\u5b58\u91c7\u7528\u539f\u5b50\u5199\uff08\u4e34\u65f6\u6587\u4ef6 + \u91cd\u547d\u540d\uff09\u3001\u8986\u76d6\u5728\u7f16\u8f91\u5668\u5916\u88ab\u6539\u52a8\u8fc7\u7684\u6587\u4ef6\u524d\u4f1a\u5148\u8be2\u95ee\u3002\u56fe\u7247\u4e0e\u97f3\u89c6\u9891\u6309\u5404\u81ea\u4e0a\u9650\uff088 MiB / 24 MiB\uff09\u8bfb\u53d6\u540e\u4ee5 base64 data URI \u4ea4\u7ed9\u89c6\u56fe\uff1b\u6570\u636e\u5e93\u4e00\u5f8b\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\uff08readOnly + PRAGMA query_only\uff09\uff0cSQL \u6846\u53ea\u63a5\u53d7\u5355\u6761\u53ea\u8bfb\u8bed\u53e5\uff0c\u53ea\u80fd\u6d4f\u89c8\u3001\u7edd\u65e0\u4fee\u6539\uff1bzip\u3001exe \u8fd9\u7c7b\u4e8c\u8fdb\u5236\u53ea\u62a5\u300c\u4e0d\u652f\u6301\u9884\u89c8\u300d\uff0c\u4e0d\u505a\u4efb\u4f55\u89e3\u7801\u3002\u65e0\u7f51\u7edc\u8bbf\u95ee\uff1b\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u53ea\u4fdd\u5b58\u8bbe\u7f6e\u4e0e\u5199\u5165\u5ba1\u8ba1\u65e5\u5fd7\u3002", + "readmeMarkdown": "# \u6587\u4ef6\u7ba1\u7406\u5668\uff08File Manager\uff09\n\n\u5728 PI-Desktop \u7684**\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f**\u91cc\u6d4f\u89c8\u5e76\u7f16\u8f91\u5f53\u524d\u9879\u76ee\u7684\u6587\u4ef6\u3002\u5b83\u4e0d\u662f\u5bbf\u4e3b\u5185\u7f6e\u300c\u6587\u4ef6\u300d\u89c6\u56fe\u7684\u66ff\u4ee3\u54c1\uff0c\u800c\u662f\u5e76\u5217\u7684\u4e00\u884c\uff1a\u5185\u7f6e\u89c6\u56fe\u53ea\u8bfb\uff0c\u8fd9\u4e00\u884c\u53ef\u7f16\u8f91\u3002\n\n\u6e90\u7801\u4ed3\u5e93\uff1a\n\n## \u4e3a\u4ec0\u4e48\u505a\u8fd9\u4e2a\n\n\u5bbf\u4e3b\u5185\u7f6e\u7684\u300c\u6587\u4ef6\u300d\u89c6\u56fe\u53ea\u80fd\u770b\u4e0d\u80fd\u6539\uff0c\u800c\u5bbf\u4e3b\u7684 `pi.fs` \u7f51\u5173\u5728\u8bed\u6cd5\u4e0a\u5c31**\u7981\u6b62\u6574\u6811\u5199\u5165**\uff08`manifest.fs` \u7684 write scope \u4e0d\u80fd\u662f `**`\uff09\uff0c\u4efb\u4f55\u4e00\u4e2a\u80fd\u901a\u8fc7\u6821\u9a8c\u7684\u7a84 scope \u90fd\u4f1a\u8ba9\u300c\u4fdd\u5b58\u300d\u53d8\u6210\u6bcf\u6b21\u90fd\u5f39\u6743\u9650\u786e\u8ba4\uff1b`pi.fs.*` \u4e5f\u6ca1\u6709\u521b\u5efa / \u91cd\u547d\u540d / \u79fb\u52a8\u80fd\u529b\u3002\n\n\u6240\u4ee5\u8fd9\u4e2a\u63d2\u4ef6\u5728\u81ea\u5df1\u7684\u8fdb\u7a0b\u91cc\u7528 Node `fs` \u8bfb\u5199\u5f53\u524d\u9879\u76ee\uff0c\u5e76**\u81ea\u5df1\u627f\u62c5\u5168\u90e8\u5b89\u5168\u8d23\u4efb**\uff08\u89c1\u4e0b\u9762\u7684\u300c\u5b89\u5168\u300d\u4e00\u8282\uff09\u3002\n\n## \u529f\u80fd\n\n- **\u5b8c\u6574\u76ee\u5f55\u6811**\uff1a\u61d2\u52a0\u8f7d\u3001\u76ee\u5f55\u4f18\u5148\u3001\u952e\u76d8\u5bfc\u822a\uff08\u2191\u2193 Home End \u2190\u2192 Enter\uff09\uff1b\u6bcf\u4e00\u884c\u7684\u56fe\u6807\u968f\u6587\u4ef6\u7c7b\u578b\u53d8\u5316\u2014\u2014\u6587\u4ef6\u5939\u3001\u4ee3\u7801\u3001JSON\u3001Markdown\u3001\u6837\u5f0f\u3001HTML/Vue/Svelte\u3001YAML/TOML\u3001Shell\u3001SQL\u3001\u56fe\u7247\u3001\u538b\u7f29\u5305\u3001\u5b57\u4f53\u3001\u9501\u6587\u4ef6\u7b49\u5404\u6709\u5b57\u5f62\u4e0e\u914d\u8272\uff0c`package.json` / `Dockerfile` / `LICENSE` / `.gitignore` \u8fd9\u7c7b\u7279\u6b8a\u6587\u4ef6\u540d\u4f18\u5148\u4e8e\u6269\u5c55\u540d\u5224\u5b9a\u3002\n- **\u9009\u4e2d\u6001\u4e0e\u60ac\u505c\u6001\u660e\u786e\u533a\u5206**\uff1a\u60ac\u505c\u662f\u6de1\u4e2d\u6027\u5e95\u8272\uff1b\u9009\u4e2d\u662f\u5f3a\u8c03\u8272\u5e95 + \u5de6\u4fa7\u5f3a\u8c03\u8272\u7ad6\u6761 + \u524d\u666f\u8272\u6587\u5b57 + \u4e2d\u7b49\u5b57\u91cd\uff0c\u9f20\u6807\u79fb\u5f00\u4e5f\u4fdd\u6301\u3002\n- **\u53f3\u952e\u83dc\u5355**\uff1a\u5728\u6587\u4ef6 / \u6587\u4ef6\u5939\u4e0a\u53f3\u952e\u53ef\u65b0\u5efa\u6587\u4ef6\u3001\u65b0\u5efa\u6587\u4ef6\u5939\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u3001\u6253\u5f00\u3001\u5237\u65b0\uff1b\u5217\u8868\u7a7a\u767d\u5904\u53f3\u952e\u63d0\u4f9b\u300c\u5728\u6b64\u65b0\u5efa\u300d\u4e0e\u5237\u65b0\u3002\n- **\u5de6\u53f3\u5206\u680f**\uff1a\u5de6\u4fa7\u6587\u4ef6\u5217\u8868\uff0c\u53f3\u4fa7\u5185\u5bb9\uff1b\u5206\u9694\u6761\u53ef\u62d6\u62fd\uff0c\u5bbd\u5ea6\u4f1a\u8bb0\u4f4f\u3002\n- **\u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91**\uff1aCodeMirror 6\uff0c\u884c\u53f7\u3001\u67e5\u627e\u66ff\u6362\u3001\u591a\u5149\u6807\u3001\u62ec\u53f7\u5339\u914d\u3001\u4ee3\u7801\u6298\u53e0\u3002\u6309\u6587\u4ef6\u540d\u52a0\u8f7d\u8bed\u6cd5\u9ad8\u4eae\uff0c\u8986\u76d6 TypeScript/TSX\u3001JavaScript/JSX\u3001JSON\u3001Markdown\u3001CSS/SCSS/Sass/Less\u3001HTML\u3001Vue\u3001XML\u3001YAML\u3001TOML\u3001Properties\u3001Python\u3001Go\u3001Rust\u3001Java\u3001C/C++\u3001C#\u3001Kotlin\u3001Scala\u3001Dart\u3001Objective-C\u3001PHP\u3001Ruby\u3001Lua\u3001Shell\u3001PowerShell\u3001SQL\u3001Dockerfile\u3001Diff\u3002\u5168\u90e8\u968f\u5305\u5185\u7f6e\u3001\u79bb\u7ebf\u53ef\u7528\u3002`Ctrl/Cmd+S` \u6216\u5de5\u5177\u680f\u6309\u94ae\u4fdd\u5b58\u3002\n- **Markdown \u9884\u89c8 / \u7f16\u8f91\u5207\u6362**\uff1a\u6253\u5f00 `.md` / `.markdown` / `.mdx` \u65f6\u5de5\u5177\u680f\u51fa\u73b0\u5207\u6362\u3002\u9884\u89c8\u652f\u6301\u6807\u9898\u3001\u56f4\u680f\u4ee3\u7801\u5757\uff08\u590d\u7528\u7f16\u8f91\u5668\u540c\u4e00\u5957\u9ad8\u4eae\uff09\u3001\u5f15\u7528\u3001\u5206\u9694\u7ebf\u3001\u6709\u5e8f/\u65e0\u5e8f/\u4efb\u52a1\u5217\u8868\uff08\u6309\u7f29\u8fdb\u5d4c\u5957\uff09\u3001\u8868\u683c\uff08\u542b\u5bf9\u9f50\uff09\u3001\u884c\u5185 code / \u7c97\u4f53 / \u659c\u4f53 / \u5220\u9664\u7ebf / \u94fe\u63a5 / \u56fe\u7247\uff1b\u5207\u6362\u4f1a\u8bb0\u4f4f\u3002\n- **\u6309\u6587\u4ef6\u540d\u641c\u7d22**\uff1a\u6574\u4e2a\u9879\u76ee\u8303\u56f4\u5185\u5206\u9875\u641c\u7d22\uff0c\u70b9\u51fb\u7ed3\u679c\u76f4\u63a5\u8df3\u8f6c\u5e76\u5c55\u5f00\u5b9a\u4f4d\u3002\n- **\u5ffd\u7565\u89c4\u5219**\uff1a\u9879\u76ee\u91cc\u6709 `.gitignore` / `.ignore` \u5c31\u6309\u89c4\u5219\u9690\u85cf\u6761\u76ee\uff08\u5de5\u5177\u680f\u773c\u775b\u6309\u94ae\u53ef\u5207\u56de\u663e\u793a\uff09\uff1b**\u4e00\u4e2a\u89c4\u5219\u6587\u4ef6\u90fd\u6ca1\u6709\u65f6\uff0c\u76ee\u5f55\u6811\u5c55\u793a\u5168\u90e8\u6761\u76ee**\u3002\n- **\u8ddf\u968f\u5bbf\u4e3b\u5916\u89c2**\uff1a\u4eae / \u6697\u914d\u8272\u4e0e\u754c\u9762\u8bed\u8a00\uff08\u4e2d\u6587 / English\uff09\u8ddf\u968f PI-Desktop \u4e3b\u4f53\uff0c\u7f16\u8f91\u5668\u4e0e\u9884\u89c8\u7684\u9ad8\u4eae\u914d\u8272\u4e00\u5e76\u8ddf\u968f\u3002\n\n## \u5b89\u88c5\n\n\u5728 PI-Desktop \u7684 **\u63d2\u4ef6 \u2192 \u5e02\u573a** \u4e2d\u5b89\u88c5\uff1b\u6216\u4e0b\u8f7d `packages/pi.file-manager-0.2.0.piplug` \u540e\u8d70 **Install plugin package**\u3002\n\n\u88c5\u597d\u540e\u6253\u5f00\u4e00\u4e2a\u9879\u76ee\uff0c\u5728**\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u5934\u90e8\u7684\u5207\u6362\u83dc\u5355 \u2192\u300cPlugin views\u300d\u5206\u7ec4**\u91cc\u70b9\u51fb\u300c\u6587\u4ef6\u7ba1\u7406\u5668\u300d\u3002\n\n> \u8fd9\u4e2a\u63d2\u4ef6\u6ca1\u6709\u547d\u4ee4\u9762\u677f\u5165\u53e3\uff0c\u4e5f\u4e0d\u6ce8\u518c\u72ec\u7acb\u9762\u677f\u7a97\u53e3\u2014\u2014\u5b83\u53ea\u63d0\u4f9b\u4e00\u4e2a\u505c\u9760\u5728\u53f3\u4fa7\u680f\u7684\u89c6\u56fe\uff08`contributes.views`\uff09\u3002\u5bbf\u4e3b\u6ca1\u6709\u63d0\u4f9b\u300c\u7528\u547d\u4ee4\u6253\u5f00\u89c6\u56fe\u300d\u7684\u901a\u9053\uff0c\u6240\u4ee5\u8fd9\u91cc\u4e5f\u4e0d\u58f0\u660e\u8bef\u5bfc\u6027\u7684\u547d\u4ee4\u3002\n\n## \u6743\u9650\n\n\u53ea\u7533\u62a5\u4e00\u9879\uff1a\n\n- `ui.view` \u2014\u2014 \u628a\u89c6\u56fe\u505c\u9760\u5230\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u3002\n\n**\u4e3a\u4ec0\u4e48\u6ca1\u6709\u7533\u62a5 `fs.read` / `fs.write`**\uff1a\u5bbf\u4e3b `manifest.fs` \u5728\u8bed\u6cd5\u4e0a\u65e0\u6cd5\u8868\u8fbe\u300c\u6574\u6811\u5199\u5165\u300d\uff0c\u4efb\u4f55\u4e00\u4e2a\u80fd\u901a\u8fc7\u6821\u9a8c\u7684\u7a84 scope \u90fd\u4f1a\u9020\u6210\u300c\u5199\u5165\u53d7\u9650\u300d\u7684\u5047\u8c61\uff0c\u6bd4\u4e0d\u7533\u62a5\u66f4\u5371\u9669\uff1b\u800c `fs.read` \u672c\u63d2\u4ef6\u4ece\u4e0d\u4f7f\u7528\uff08\u4e0d\u8c03\u7528\u4efb\u4f55 `pi.fs.*`\uff09\u3002\u771f\u5b9e\u89e6\u8fbe\u5199\u5728 `i18n.*.safetyNotes` \u4e0e\u672c\u6587\u4ef6\u7684\u300c\u5b89\u5168\u300d\u4e00\u8282\uff0c\u8fd9\u662f\u5f53\u524d\u552f\u4e00\u80fd\u8bda\u5b9e\u8868\u8fbe\u5b83\u7684\u4f4d\u7f6e\u3002\n\n\u65e0\u7f51\u7edc\uff1a`manifest.json` \u6ca1\u6709 `net.domains`\uff0c\u8fd0\u884c\u65f6\u4e0d\u53d1\u8d77\u4efb\u4f55\u8bf7\u6c42\u3002\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u53ea\u4fdd\u5b58\u8bbe\u7f6e\uff08\u5206\u680f\u5bbd\u5ea6\u3001\u663e\u793a\u5f00\u5173\u3001Markdown \u9ed8\u8ba4\u89c6\u56fe\uff09\u548c\u4e00\u4efd\u5199\u5165\u5ba1\u8ba1\u65e5\u5fd7\u3002\n\n## \u5b89\u5168\n\n\u6587\u4ef6\u8bfb\u5199**\u7531\u63d2\u4ef6\u81ea\u8eab**\u9650\u5b9a\u5728\u9879\u76ee\u6839\u76ee\u5f55\u5185\uff0c\u5bbf\u4e3b\u7684\u6743\u9650\u7f51\u5173\u4e0d\u4ecb\u5165\u8fd9\u4e9b\u8c03\u7528\u3002\u63d2\u4ef6\u5b9e\u65bd\u7684\u5168\u90e8\u9650\u5236\uff1a\n\n| \u9650\u5236 | \u8bf4\u660e |\n|---|---|\n| \u8def\u5f84\u5305\u542b | \u53ea\u63a5\u53d7\u76f8\u5bf9\u9879\u76ee\u6839\u7684\u8def\u5f84\uff1b\u7edd\u5bf9\u8def\u5f84\u3001`..`\u3001\u4ee5\u53ca realpath \u540e\u843d\u5230\u6839\u76ee\u5f55\u4e4b\u5916\u7684**\u7b26\u53f7\u94fe\u63a5 / junction** \u4e00\u5f8b\u62d2\u7edd |\n| \u654f\u611f\u8def\u5f84 | `.env*`\u3001`.ssh`\u3001`.aws`\u3001`.gnupg`\u3001`.git/**`\u3001`*.pem`\u3001`*.key`\u3001`*.p12` \u7b49\u8bfb\u5199\u5168\u62d2\uff1b`node_modules` \u53ef\u8bfb\u4e0d\u53ef\u5199 |\n| \u539f\u5b50\u5199 | \u5148\u5199\u540c\u76ee\u5f55\u4e34\u65f6\u6587\u4ef6 \u2192 `fsync` \u2192 \u4fdd\u7559\u539f\u6587\u4ef6\u6743\u9650\u4f4d \u2192 `rename` \u8986\u76d6\uff0c\u4e2d\u65ad\u4e0d\u4f1a\u7559\u4e0b\u534a\u5199\u6587\u4ef6 |\n| \u51b2\u7a81\u68c0\u6d4b | \u4ee5 `mtimeMs` + \u6587\u4ef6\u5927\u5c0f\u4f5c\u4e3a\u4e50\u89c2\u9501\uff1b\u6587\u4ef6\u5728\u7f16\u8f91\u5668\u4e4b\u5916\u88ab\u6539\u52a8\u8fc7\u65f6**\u4e0d\u4f1a\u9759\u9ed8\u8986\u76d6**\uff0c\u4f1a\u5148\u5f39\u5bf9\u8bdd\u6846\u8ba9\u7528\u6237\u9009\u62e9\u8986\u76d6 / \u653e\u5f03 / \u91cd\u65b0\u52a0\u8f7d |\n| \u5199\u5165\u5ba1\u8ba1 | \u6bcf\u6b21\u5199\u5165\u8ffd\u52a0\u4e00\u884c\u5230\u63d2\u4ef6\u6570\u636e\u76ee\u5f55\u7684 `write-audit.jsonl`\uff08\u7ea6 1 MiB \u540e\u8f6e\u8f6c\uff09\uff0c\u56e0\u4e3a\u5bbf\u4e3b\u5ba1\u8ba1\u4e0d\u5230\u8fd9\u6761\u8def\u5f84 |\n| \u4f53\u79ef\u4e0a\u9650 | \u9884\u89c8 2 MiB\u3001\u5199\u5165 8 MiB\uff1b\u4e8c\u8fdb\u5236\u6587\u4ef6\u4e0e\u56fe\u7247\u4e0d\u8fdb\u5165\u7f16\u8f91\u5668\uff0c\u53ea\u63d0\u793a |\n\nMarkdown \u9884\u89c8**\u4e0d\u4f7f\u7528** `dangerouslySetInnerHTML`\uff0c\u800c\u662f\u628a Markdown \u89e3\u6790\u6210 React \u5143\u7d20\u2014\u2014\u8282\u70b9\u7531 React \u8f6c\u4e49\uff0c\u7ed3\u6784\u4e0a\u4e0d\u5b58\u5728\u6ce8\u5165\u9762\uff0c\u56e0\u6b64\u4e5f\u4e0d\u9700\u8981\u989d\u5916\u7684 sanitizer\u3002\u9884\u89c8\u4e2d\u7684\u94fe\u63a5\u4e0d\u4f1a\u5bfc\u822a\uff08\u70b9\u4e00\u4e0b\u5c31\u79bb\u5f00\u63d2\u4ef6\u9875\u9762\u56de\u4e0d\u6765\u4e86\uff09\uff0c\u70b9\u51fb\u53ea\u4f1a\u628a\u5730\u5740\u663e\u793a\u51fa\u6765\u3002\n\n\u884c\u4e3a\u8bf4\u660e\uff1a`.git` \u76ee\u5f55\u4e0d\u4f1a\u51fa\u73b0\u5728\u6811\u91cc\uff1b\u5ffd\u7565\u89c4\u5219\u662f gitignore \u7684\u4e00\u4e2a\u5b50\u96c6\uff08\u652f\u6301 `!` \u53d6\u53cd\u3001\u672b\u5c3e `/`\u3001\u524d\u5bfc `/` \u951a\u5b9a\u3001`*` / `?` / `**`\uff0c\u4e0d\u652f\u6301 `\\` \u8f6c\u4e49\u4e0e `[a-z]` \u5b57\u7b26\u7c7b\uff09\uff0c\u504f\u5dee\u53ea\u5f71\u54cd\u300c\u663e\u4e0d\u663e\u793a\u300d\uff0c\u968f\u65f6\u53ef\u7528\u5de5\u5177\u680f\u7684\u773c\u775b\u6309\u94ae\u7ffb\u76d8\u3002\n\n## \u5df2\u77e5\u9650\u5236\n\n- **\u4e0d\u5220\u9664\u6587\u4ef6 / \u76ee\u5f55**\uff1a\u5220\u9664\u662f\u7834\u574f\u6027\u64cd\u4f5c\uff0c\u4e14\u5bbf\u4e3b\u7684 `fs.remove` \u5e76\u672a\u5f00\u653e\u7ed9\u89c6\u56fe\u6865\uff0c\u53ea\u80fd\u8d70\u539f\u751f `rm`\u2014\u2014\u672c\u671f\u4e0d\u505a\u3002\n- **\u6ca1\u6709\u300c\u5728\u6587\u4ef6\u5939\u4e2d\u663e\u793a\u300d/\u300c\u7528\u7cfb\u7edf\u7a0b\u5e8f\u6253\u5f00\u300d**\uff1a\u8fd9\u4e24\u4e2a\u5bbf\u4e3b\u901a\u9053\u9700\u8981 `fs.read` \u6743\u9650\uff0c\u800c\u672c\u63d2\u4ef6\u6709\u610f\u4e0d\u7533\u62a5\u4efb\u4f55 fs \u6743\u9650\u3002\n- **\u9884\u89c8\u91cc\u7684\u56fe\u7247\u4e0d\u52a0\u8f7d**\uff1a\u9762\u677f\u4ee5 `file://` \u52a0\u8f7d\uff0c\u76f8\u5bf9\u8def\u5f84\u6307\u5411\u89c6\u56fe\u81ea\u8eab\u800c\u4e0d\u662f\u9879\u76ee\uff0c\u56e0\u6b64\u56fe\u7247\u663e\u793a\u4e3a\u5e26\u6587\u4ef6\u540d\u7684\u5360\u4f4d\u5757\uff0c\u800c\u4e0d\u662f\u7834\u56fe\u3002\n- **\u6587\u4ef6\u76d1\u542c**\uff1a\u5bbf\u4e3b\u6ca1\u6709\u300c\u63d2\u4ef6 \u2192 \u89c6\u56fe\u300d\u7684\u63a8\u9001\u901a\u9053\uff08\u89c6\u56fe\u53ea\u80fd\u53d1\u8d77\u8bf7\u6c42\u3001\u62ff\u54cd\u5e94\uff09\uff0c\u5916\u90e8\u6539\u52a8\u4e0d\u662f\u5b9e\u65f6\u7684\uff1b\u4fdd\u5b58\u540e\u4f1a\u81ea\u52a8\u5237\u65b0\uff0c\u5de5\u5177\u680f\u4e5f\u6709\u624b\u52a8\u5237\u65b0\u3002\n- \u4e8c\u8fdb\u5236\u4e0e\u56fe\u7247\u4e0d\u53ef\u7f16\u8f91\uff0c\u4e5f\u4e0d\u505a\u56fe\u7247\u9884\u89c8\uff08\u4e0e\u5bbf\u4e3b\u5185\u7f6e\u7684\u300c\u6587\u4ef6\u300d\u89c6\u56fe\u4e00\u81f4\uff09\u3002\n\n## \u6784\u5efa\n\n\u672c\u76ee\u5f55\u53ea\u5305\u542b\u53ef\u76f4\u63a5\u8fd0\u884c\u7684\u4ea7\u7269\uff08`main.js` + `views/`\uff09\u3002\u89c6\u56fe\u6e90\u7801\uff08React + TypeScript + Tailwind + CodeMirror 6\uff09\u4e0e\u6784\u5efa\u811a\u672c\u5728\u6e90\u7801\u4ed3\u5e93\u7684 `views-src/`\uff1a\n\n```bash\ncd views-src\npnpm install\npnpm typecheck\npnpm verify # \u8bed\u6cd5\u9ad8\u4eae + Markdown \u9884\u89c8\u7684\u79bb\u7ebf\u6821\u9a8c\npnpm build # \u4ea7\u7269\u8f93\u51fa\u5230 ../views\n```\n\n## \u8bb8\u53ef\n\nMIT\u3002\n", + "safetyNotes": null, "versions": [ { - "version": "0.3.0", - "publishedAt": "2026-09-13T10:53:03Z", - "changelog": "Release 0.3.0\uff1a\u4ece\u300c\u53ea\u80fd\u7f16\u8f91\u6587\u672c\u300d\u6269\u5230\u300c\u770b\u5f97\u89c1\u5404\u79cd\u6587\u4ef6\u300d\u2014\u2014\u56fe\u7247\u67e5\u770b\uff08png/jpg/gif/webp/avif/bmp/ico/svg\uff0c\u9002\u5e94\u7a97\u53e3\u4e0e\u5b9e\u9645\u5927\u5c0f\u3001\u68cb\u76d8\u683c\u3001\u50cf\u7d20\u5c3a\u5bf8\u4e0e\u4f53\u79ef\uff09\u3001\u97f3\u89c6\u9891\u64ad\u653e\uff08mp4/mov/webm/mkv \u4e0e mp3/wav/flac/ogg \u7b49\uff0c\u4e0d\u81ea\u52a8\u64ad\u653e\u3001\u7f16\u7801\u4e0d\u652f\u6301\u65f6\u660e\u786e\u63d0\u793a\uff09\u3001CSV/TSV \u8868\u683c\uff08\u9ed8\u8ba4\u6bcf\u9875 1000 \u884c\u53ef\u8c03\u5e76\u8bb0\u4f4f\u3001\u70b9\u8868\u5934\u5347/\u964d/\u53d6\u6d88\u6392\u5e8f\u3001\u884c\u53f7\u5217\u4e0e\u8868\u5934\u53cc\u5411\u5438\u9876\u3001\u6570\u5b57\u53f3\u5bf9\u9f50\u3001\u60ac\u505c\u770b\u5168\u503c\uff09\u3001JSON \u6298\u53e0\u6811\uff0c\u4ee5\u53ca SQLite \u53ea\u8bfb\u6d4f\u89c8\u4e0e SQL \u67e5\u8be2\u6846\uff08readOnly + PRAGMA query_only + \u5355\u6761\u53ea\u8bfb\u8bed\u53e5\u767d\u540d\u5355\u4e09\u5c42\u53ea\u8bfb\uff0c\u5b57\u8282\u4e0d\u8fdb\u89c6\u56fe\uff0c\u53ef\u6253\u5f00\u51e0\u767e MB \u7684\u5e93\uff09\u3002\u4e8c\u8fdb\u5236\u6587\u4ef6\uff08zip/apk/exe \u7b49\uff09\u660e\u786e\u63d0\u793a\u4e0d\u652f\u6301\u9884\u89c8\u3002\u540c\u65f6\u4fee\u6389\u4fdd\u5b58\u94fe\u8def\u7684\u4e00\u4e2a\u4e25\u91cd\u7f3a\u9677\uff1a\u4fdd\u5b58\u6210\u529f\u540e\u7f16\u8f91\u5668\u6587\u6863\u4f1a\u88ab\u91cd\u88c5\u56de\u6253\u5f00\u65f6\u7684\u65e7\u5185\u5bb9\uff08\u73b0\u4ee5 loadToken \u533a\u5206\u300c\u4ece\u78c1\u76d8\u88c5\u8f7d\u300d\u4e0e\u300c\u4fdd\u5b58\u540e\u66f4\u65b0 mtime\u300d\uff09\uff0c\u5e76\u4fee\u6389\u300c\u6ca1\u6709\u6539\u52a8\u4e5f\u5199\u76d8\u300d\u300c\u8fde\u6309 Ctrl+S \u81ea\u5df1\u649e\u51fa\u51b2\u7a81\u300d\u300c\u4fdd\u5b58\u8fd4\u56de\u65f6\u7528\u6237\u5df2\u5207\u8d70\u6587\u4ef6\u300d\u300cCtrl+S \u7126\u70b9\u4e0d\u5728\u7f16\u8f91\u5668\u5c31\u5931\u6548\u300d\u7b49\u95ee\u9898\u3002Release 0.2.0\uff1a\u4fee\u590d\u4ee3\u7801\u6ca1\u6709\u8bed\u6cd5\u9ad8\u4eae\uff08\u53bb\u6389 basicSetup \u81ea\u5e26\u7684 fallback \u9ad8\u4eae\u5668\uff09\u3001\u8bed\u8a00\u89e3\u6790\u6539\u4e3a\u663e\u5f0f\u6ce8\u518c\u8868\u3001\u65b0\u589e\u53f3\u952e\u83dc\u5355\u4e0e Markdown \u9884\u89c8/\u7f16\u8f91\u5207\u6362\u3002Release 0.1.0\uff1a\u9996\u4e2a\u7248\u672c\uff0c\u53f3\u4fa7\u5de5\u4f5c\u9762\u677f\u91cc\u7684\u5b8c\u6574\u76ee\u5f55\u6811 + \u4ee3\u7801\u9ad8\u4eae\u7f16\u8f91\u4e0e\u4fdd\u5b58 + \u65b0\u5efa/\u91cd\u547d\u540d/\u79fb\u52a8 + \u6309\u6587\u4ef6\u540d\u641c\u7d22\u3002", + "version": "0.2.0", + "publishedAt": "2026-09-11T18:47:58Z", + "changelog": "Release 0.2.0", "minPiDesktop": ">=0.9.0", - "shasum": "88a5a41fa4e4e16fe8744d398941be0046b04659ffc2e60761ddd0abb1677803", - "url": "packages/pi.file-manager-0.3.0.piplug", - "sizeBytes": 1407619, + "shasum": "3ef1466d213558db20b46ab60407242ee37a12bdb3dc5fb7108e4704a7f50d0d", + "url": "packages/pi.file-manager-0.2.0.piplug", + "sizeBytes": 1342507, "permissions": [ "ui.view" ], @@ -457,7 +388,7 @@ "versions": [ { "version": "0.2.7", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.2.7: follow the app color mode only \u2014 never snap to the OS palette, which flashed when the two disagreed. Release 0.2.6: follows the app light/dark mode live in the work-panel view. Release 0.2.5: drop agent tools and the Git workflow skill \u2014 Git Lens is a human work-panel UI only. Release 0.2.5\uff1a\u53bb\u6389 AI \u5de5\u5177\u548c Git workflow skill\uff0cGit Lens \u53ea\u7ed9\u4eba\u7528\u3002 Release 0.2.4: command palette, toasts and the work-panel UI follow the app language (en / zh-CN) from the first paint. Release 0.2.3: compact work-panel UI \u2014 overview is a single count row; file/commit diffs open as a full-page sheet with Back. Release 0.2.0: docks only in the right work panel.", "minPiDesktop": ">=0.8.0", "shasum": "40babc1d5f59f221ca17f0299647053636d403fbf11c7dc97daab197a10dadf3", @@ -500,7 +431,7 @@ "versions": [ { "version": "0.1.1", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "0.1.1: docked work-panel chrome, fail-closed storage, namespaced commands, appearance adapter. 0.1.0: workspace-scoped goal pools, focus, regular and Sisyphus modes, task trees, completion evidence, pause/block/resume/archive lifecycle, bilingual dashboard, Agent tools, and host-owned completion audits.", "minPiDesktop": ">=0.13.11", "shasum": "f501107dcd2f444fab737c15ed81c257fd301a3f72318d2911d65c7149580615", @@ -549,7 +480,7 @@ "versions": [ { "version": "0.2.0", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.2.0\uff1a\u63d2\u4ef6 id \u5b9a\u7a3f pi.log-viewer\uff1b\u641c\u7d22\u4e0e\u6587\u672c\u8fc7\u6ee4\u5206\u79bb\uff08\u641c\u7d22\u9ad8\u4eae\u53ef\u8df3\u8f6c\uff0c\u8fc7\u6ee4\u53ea\u663e\u793a/\u9690\u85cf\u547d\u4e2d\uff09\uff1b\u8fc7\u6ee4\u89c6\u56fe\u865a\u62df\u6eda\u52a8\uff1b\u7b49\u7ea7\u914d\u8272\u8bbe\u7f6e\uff1b\u9489\u4f4f\u6700\u591a 5 \u884c\u5bf9\u6bd4\uff1b\u53f3\u952e\u300c\u6e05\u9664\u7b5b\u9009\u5e76\u8df3\u8f6c\u300d\uff1b\u7cfb\u7edf\u6587\u4ef6\u9009\u62e9\u5668\u6253\u5f00 .log/.txt\uff1b\u9996\u6b21\u6253\u5f00\u793a\u4f8b\u5f15\u5bfc\u65e5\u5fd7\uff1b\u4fee\u590d\u9759\u6001\u6587\u4ef6\u8bef\u62a5\u65b0\u589e\u3001\u9876\u90e8\u9996\u884c\u7a97\u53e3\u7a7a\u767d\u4e0e\u5e95\u90e8\u7559\u767d\u3002", "minPiDesktop": ">=0.14.3", "shasum": "43224cefed7fd52357d9a4a1094404edb13e3f14e60650c39107f9644838bf80", @@ -599,7 +530,7 @@ "versions": [ { "version": "0.5.0", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.5.0\uff1aAgent \u5de5\u5177\u6539\u4e3a\u300c\u9884\u89c8\u6a21\u5f0f\u6253\u5f00\u6587\u4ef6\u300d\u2014\u2014\u4ee5 preview_file \u53d6\u4ee3 open_file\uff1a\u6309\u7edd\u5bf9\u8def\u5f84\u4ee5\u53ea\u8bfb\u9884\u89c8\u6253\u5f00\u5355\u4e2a Markdown/\u6587\u672c\u6587\u4ef6\uff08\u672c\u5730 Node fs \u8bfb\u5199\uff0c\u65e0\u9700\u9009\u5b9a\u76ee\u5f55\u3001\u4efb\u610f\u8def\u5f84\u53ef\u7528\uff09\uff0c\u9762\u677f\u4e0d\u663e\u793a\u4fa7\u8fb9\u680f\uff0c\u53ea\u6709\u300c\u9884\u89c8 / \u7f16\u8f91\u300d\u4e24\u6001\uff0c\u7528\u6237\u70b9\u300c\u7f16\u8f91\u300d\u540e\u624d\u80fd\u4fee\u6539\u5e76\u81ea\u52a8\u5199\u56de\u539f\u6587\u4ef6\uff1b\u56e0\u6b64\u79fb\u9664 fs.read / fs.write \u6743\u9650\u4e0e manifest.fs \u58f0\u660e\u3002\u9762\u677f\u914d\u8272\u6539\u4e3a Typora Inkwell \u4e3b\u9898\uff08\u6d45\u8272\u67d4\u548c\u7070\u8c03 / \u9ed1\u591c\u6df1\u84dd\u4f4e\u9971\u548c\uff09\uff0c\u7f16\u8f91\u533a\u5bbd\u5ea6\u968f\u7a97\u53e3\u653e\u5bbd\uff08860 \u2192 1024 \u2192 1200\uff09\u3002\u4fee\u590d\u4ee3\u7801\u5757\u4e0e\u516c\u5f0f\u7684\u300c\u53cc\u5c42\u8fb9\u6846\u300d\uff08\u6539\u4e3a\u5355\u5c42\u5706\u89d2\u5bb9\u5668 + \u8bed\u8a00\u6807\u9898\u680f\uff09\u3001\u4ee3\u7801\u5757\u5728\u6d45\u8272\u4e3b\u9898\u4e0b\u88ab oneDark \u5f3a\u6491\u6df1\u8272\u914d\u8272\u3001Mermaid \u56fe\u8868\u4e0d\u968f\u4e3b\u9898\u5207\u6362\u3001\u4efb\u52a1\u5217\u8868\u52fe\u9009\u6846\u5bf9\u6bd4\u5ea6\u8fc7\u4f4e\u3001\u72b6\u6001\u680f\u6309\u94ae\u6ea2\u51fa 4px\uff1b\u516c\u5f0f\u4e0e Mermaid \u9ed8\u8ba4\u663e\u793a\u6e32\u67d3\u7ed3\u679c\uff08\u70b9\u300c\u7f16\u8f91\u300d\u770b\u6e90\u7801\uff09\u3001\u5757\u7ea7\u516c\u5f0f\u5c45\u4e2d\u3001\u53bb\u6389\u591a\u4f59\u7684\u300c\u9884\u89c8\u300d\u6807\u7b7e\uff1b\u4ee3\u7801\u5757\u6807\u9898\u680f\u4e0e\u8bed\u8a00\u4e0b\u62c9\u6536\u7d27\uff0849px \u2192 31px\uff0c\u7edf\u4e00 22px \u63a7\u4ef6\u4e0e\u6eda\u52a8\u6761\u6837\u5f0f\uff09\uff1b\u6e05\u7406 panel-polish.css \u4e2d\u4e00\u6279\u4ece\u672a\u751f\u6548\u7684\u9009\u62e9\u5668\uff08.sidebar-container / .editor-pane / .tab-button \u7b49\uff09\u3002Release 0.4.8\uff1a\u5408\u5e76\u5e02\u573a 0.4.7 \u57fa\u7ebf\u2014\u2014\u8fc1\u79fb v3 \u7a7f\u900f\u5f0f\u9876\u90e8 chrome\u3001panel-polish\u3001\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u5b9e\u65f6\u91cd\u7740\u8272\u4e0e pimd.theme.v1 \u4e3b\u9898\u955c\u50cf\u9884\u7ed8\uff1bmanifest \u589e\u8865 i18n \u53cc\u8bed\u5757\uff1b\u4fdd\u7559\u672c\u4ed3\u5e93\u72ec\u6709 open_file\uff08\u5bbf\u4e3b pi.fs \u6743\u9650\u7f51\u5173 + \u5355\u6587\u4ef6\u6a21\u5f0f\uff09\u4e0e\u9762\u677f\u4e2d\u82f1 i18n\u3002Release 0.4.7\uff1a\u5bbf\u4e3b\u9876\u90e8\u62d6\u62fd\u5e26\u6309\u9875\u9762\u5143\u7d20\u5207\u5206\uff0c\u63a7\u4ef6\u53ef\u70b9\u51fb\u3001\u7a7a\u767d\u5904\u53ef\u62d6\u62fd\uff1b\u9762\u677f\u6539\u4e3a v3 \u5168\u51fa\u8840\u5e03\u5c40\u3002Release 0.4.6\uff1a\u4fee\u590d v2 \u9762\u677f\u9876\u90e8\u5b89\u5168\u533a\u91cd\u590d\u7559\u767d\uff1b\u4fa7\u680f\u641c\u7d22\u4e0e\u7b14\u8bb0\u6807\u9898\u884c\u4ece\u5bbf\u4e3b 46px \u62d6\u62fd\u5e26\u4e0b\u6cbf\u76f4\u63a5\u5f00\u59cb\uff0c\u4fdd\u7559\u5bbf\u4e3b\u62d6\u62fd\u533a\u5e76\u6d88\u9664\u989d\u5916 8px \u9876\u90e8\u5185\u8fb9\u8ddd\uff1b\u540c\u65f6\u8ba9\u6839\u5e03\u5c40\u586b\u6ee1\u89c6\u53e3\uff0c\u907f\u514d\u5e95\u90e8\u51fa\u73b0\u5bf9\u5e94\u7a7a\u767d\u3002Release 0.4.5\uff1a\u538b\u7f29\u9762\u677f\u5185\u90e8\u7684\u5927\u95f4\u9699\u3002\u6839\u56e0\u662f Crepe \u81ea\u5e26\u4e3b\u9898\u5728 bundle \u4e2d\u6392\u5728\u5e94\u7528\u81ea\u5b9a\u4e49\u6837\u5f0f\u4e4b\u540e\uff0c\u5176 .ProseMirror { padding: 60px 120px } \u5728\u7ea7\u8054\u4e2d\u80dc\u51fa\u2014\u2014\u6b63\u6587\u7b2c\u4e00\u884c\u4e4b\u524d\u5b9e\u9645\u57ab\u4e86\u7ea6 190px\uff0846px \u62d6\u62fd\u5e26 + 53px \u6807\u9898\u884c + 60px Crepe \u5185\u8fb9\u8ddd + 28px \u9996\u4e2a\u6807\u9898\u5916\u8fb9\u8ddd\uff09\u3002\u73b0\u7531\u6700\u540e\u52a0\u8f7d\u7684 panel-polish.css \u91cd\u65b0\u58f0\u660e\u7d27\u51d1\u5185\u8fb9\u8ddd\uff08\u4e0a 12px\u3001\u968f\u5bbd\u81ea\u9002\u5e94\u3001\u5e95\u90e8 40vh \u6eda\u52a8\u4f59\u91cf\uff09\uff0c\u5e76\u53bb\u6389\u9996\u5757\u5143\u7d20\u7684\u5916\u8fb9\u8ddd\uff1b\u540c\u65f6\u6536\u7d27\u5404\u884c\u9ad8\uff1a\u4fa7\u680f\u641c\u7d22\u884c 49px\u219243px\u3001tabs \u884c 34px\u219230px\u3001\u7b14\u8bb0\u6807\u9898\u884c 53px\u219245px\uff1b\u4fa7\u680f\u7684 46px \u62d6\u62fd\u5e26\u533a\u57df\u6539\u7ed8\u4e3a\u4fa7\u680f\u5934\u90e8\u540c\u8272\uff0c\u4e0e\u641c\u7d22\u884c\u8fde\u6210\u4e00\u4f53\uff0c\u4e0d\u518d\u5448\u73b0\u4e3a\u7a7a\u6d1e\u3002Release 0.4.4\uff1a\u9762\u677f\u6539\u4e3a v2 \u5168\u51fa\u8840\u5e03\u5c40\uff0c\u5e76\u4fee\u590d\u4eae\u8272\u6a21\u5f0f\u4e0b\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u4e0d\u53ef\u89c1\u7684\u95ee\u9898\u3002(1) \u58f0\u660e pi-plugin-chrome=v2\uff0c\u5bbf\u4e3b\u4e0d\u518d\u5411 body \u6ce8\u5165 46px \u9876\u90e8\u5185\u8fb9\u8ddd\u2014\u2014\u5185\u5bb9\u76f4\u63a5\u9876\u5230\u7a97\u53e3\u4e0a\u6cbf\uff0c\u6eda\u52a8\u65f6\u4ece\u900f\u660e\u7684\u5bbf\u4e3b\u62d6\u62fd\u5e26\u4e0b\u65b9\u7a7f\u8fc7\uff08\u80f6\u56ca\u5373\u60ac\u6d6e\u5728\u5185\u5bb9\u4e4b\u4e0a\uff09\uff1b\u641c\u7d22\u6846\u3001tabs\u3001\u7b14\u8bb0\u6807\u9898\u884c\u7b49\u4ea4\u4e92\u884c\u56fa\u5b9a\u5728\u5e26\u4e0b\u6cbf\uff08top: var(--pi-plugin-titlebar-height, 46px)\uff09\u4e4b\u5916\uff0c\u56e0\u8be5\u533a\u57df\u4ec5\u4e3a\u62d6\u62fd\u533a\u3001\u4e0d\u63a5\u6536\u70b9\u51fb\u3002(2) \u5bbf\u4e3b\u53ea\u5728\u81ea\u5bb6\u5916\u89c2\u5e7f\u64ad\u65f6\u7ed9\u80f6\u56ca\u91cd\u65b0\u53d6\u8272\uff0c\u9762\u677f\u5185\u7c73\u767d/\u9ed1\u591c\u5207\u6362\u540e\u58a8\u8272\u505c\u7559\u5728\u65e7\u4e3b\u9898\u4e0a\uff0c\u4eae\u8272\u9875\u9762\u914d\u6d45\u8272\u58a8\u51e0\u4e4e\u4e0d\u53ef\u89c1\uff1b\u73b0\u7531\u6e32\u67d3\u7aef\u76d1\u542c data-theme \u53d8\u5316\uff0c\u5b9e\u65f6\u628a\u5f53\u524d\u8c03\u8272\u677f\u8986\u5199\u5230\u5bbf\u4e3b\u80f6\u56ca\u5143\u7d20\u7684\u4e24\u4e2a\u53d6\u8272\u53d8\u91cf\u4e0a\uff0c\u4efb\u4f55\u6765\u6e90\u7684\u4e3b\u9898\u5207\u6362\u80f6\u56ca\u90fd\u7acb\u5373\u91cd\u4e0a\u8272\u3002(3) body \u76f4\u63a5\u7740\u8272 rgb(var(--c-bg))/rgb(var(--c-ink))\uff0c\u5bbf\u4e3b\u4e00\u6b21\u6027\u53d6\u8272\u4e0e\u5b9e\u9645\u9875\u9762\u6c38\u8fdc\u4e00\u81f4\u3002Release 0.4.3\uff1a\u4fee\u590d\u5bbf\u4e3b\u5207\u6362\u5916\u89c2\u540e\u91cd\u5f00\u9762\u677f\u65f6\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u4ecd\u6309\u65e7\u914d\u8272\u7ed8\u5236\u800c\u4e0d\u53ef\u89c1\u7684\u95ee\u9898\u2014\u2014\u5bbf\u4e3b\u9a71\u52a8\u7684\u4e3b\u9898\u53d8\u66f4\u6b64\u524d\u53ea\u6539\u5199 data-theme\uff0cReact \u4e0d\u611f\u77e5\u3001pimd.theme.v1 \u955c\u50cf\u4e0d\u66f4\u65b0\uff0c\u4e0b\u6b21\u6253\u5f00\u5373\u6309\u8fc7\u671f\u4e3b\u9898\u9996\u7ed8\uff0c\u5bbf\u4e3b\u5728 DOMContentLoaded \u5bf9\u9875\u9762\u989c\u8272\u7684\u4e00\u6b21\u6027\u5feb\u7167\uff08\u80f6\u56ca\u53d6\u8272\uff09\u62ff\u5230\u9519\u8bef\u58a8\u8272\uff1b\u73b0\u7531\u5916\u89c2\u8fd0\u884c\u65f6\u5728\u6bcf\u6b21\u5b9e\u9645\u5e94\u7528\u7684\u4e3b\u9898\u53d8\u5316\u65f6\u628a\u771f\u5b9e\u4e3b\u9898\u5199\u56de\u955c\u50cf\uff0c\u9996\u5e27\u4e0e\u955c\u50cf\u6c38\u8fdc\u4e00\u81f4\u3002\u540c\u65f6\u538b\u7d27 46px \u5bbf\u4e3b\u62d6\u62fd\u5e26\u4e4b\u4e0b\u7684\u9996\u884c UI\uff1a\u4fa7\u680f\u5934\u90e8\u5185\u8fb9\u8ddd\u4e0e\u641c\u7d22\u6846\u9ad8\u5ea6\u6536\u7d27\u3001\u80cc\u666f\u6539\u7528\u9875\u9762\u5e95\u8272\uff0c\u7f16\u8f91\u5668\u9876\u680f\u6700\u5c0f\u9ad8\u5ea6 44px \u6536\u7a84\u4e3a 36px\uff0c\u6d88\u9664\u300c\u7a7a\u62d6\u62fd\u5e26 + \u9ad8\u5de5\u5177\u884c\u300d\u53e0\u6210\u53cc\u5c42\u5934\u90e8\u7684\u89c2\u611f\u3002Release 0.4.2\uff1a\u4fee\u590d\u6df1\u8272\u4e3b\u9898\u4e0b\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u8fd1\u4e4e\u4e0d\u53ef\u89c1\u7684\u95ee\u9898\u2014\u2014\u5bbf\u4e3b\u5728 DOMContentLoaded \u65f6\u5bf9\u9875\u9762\u989c\u8272\u505a\u5feb\u7167\u4e3a\u80f6\u56ca\u4e0a\u8272\uff0c\u800c\u6b64\u523b data-theme \u53ef\u80fd\u4ecd\u662f\u65e7\u503c/\u56de\u653e\u503c\uff1b\u73b0\u4e8e\u9996\u5e27\u524d\u4ece\u672c\u5730\u955c\u50cf\uff08pimd.theme.v1\uff09\u540c\u6b65\u6062\u590d\u5e94\u7528\u771f\u5b9e\u4e3b\u9898\uff0c\u4e3b\u9898\u53d8\u66f4\u65f6\u5b9e\u65f6\u5199\u56de\u955c\u50cf\uff0c\u521d\u59cb state \u4e5f\u8ddf\u968f\u5df2\u5e94\u7528\u7684 data-theme \u907f\u514d\u95ea\u5c4f\uff1b\u79fb\u9664\u5bf9\u5bbf\u4e3b\u4e0d\u5b58\u5728\u901a\u9053 appearance.sync \u7684\u65e0\u6548\u8c03\u7528\u3002Release 0.4.1\uff1a\u9002\u914d PI-Desktop \u8de8\u5e73\u53f0 46px \u4e3b\u673a\u62d6\u62fd\u5e26\u548c\u7b80\u7ea6\u4e09\u6309\u94ae\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\uff1bAgent \u5de5\u5177 open_file \u843d\u5730\uff08\u9700 agent.tool.register \u9ad8\u98ce\u9669\u6743\u9650\uff09\u2014\u2014Agent \u4f20\u5165\u5b8c\u6574\u7edd\u5bf9\u8def\u5f84\uff0c\u5373\u53ef\u5728\u9762\u677f\u5355\u6587\u4ef6\u6a21\u5f0f\u4e2d\u6253\u5f00\u8be5\u6587\u4ef6\u7f16\u8f91\uff08\u9690\u85cf\u7b14\u8bb0\u5217\u8868\uff0c\u4ec5\u663e\u793a\u5f53\u524d\u6587\u4ef6\uff0c\u65e0\u6cd5\u5207\u6362\u5176\u4ed6\u6587\u4ef6\uff09\uff0c\u7f16\u8f91\u7ecf 800ms \u9632\u6296\u81ea\u52a8\u4fdd\u5b58\u5199\u56de\u539f\u6587\u4ef6\uff08\u4fdd\u7559\u539f BOM\uff09\uff0c\u4ec5\u652f\u6301 .md/.markdown/.txt\u3001\u22645MB\u3001utf8 \u6587\u672c\uff08\u62d2\u7edd\u4e8c\u8fdb\u5236\uff09\uff0c\u9762\u677f 1s \u8f6e\u8be2\u62c9\u53d6\u5f85\u6253\u5f00\u6587\u4ef6\u3001\u5fc3\u8df3 60s \u8fc7\u671f\u540e\u53ef\u88ab\u65b0\u8c03\u7528\u63a5\u7ba1\u3001Plan \u6a21\u5f0f\u4e0d\u53ef\u7528\uff1b\u968f\u540e\u6587\u4ef6\u5185\u5bb9\u8bfb\u5199\u7531\u63d2\u4ef6\u8fdb\u7a0b\u5185 Node fs \u8fc1\u79fb\u81f3\u5bbf\u4e3b pi.fs \u6743\u9650\u7f51\u5173\uff08manifest.fs \u58f0\u660e userSelected \u6839\uff0c\u9996\u6b21\u8c03\u7528\u5f39\u51fa\u539f\u751f\u76ee\u5f55\u9009\u62e9\u5668\uff0c\u4ec5\u80fd\u6253\u5f00/\u5199\u56de\u7528\u6237\u9009\u5b9a\u76ee\u5f55\u5185\u7684\u6587\u4ef6\uff1b\u7f51\u5173\u8d1f\u8d23\u8d8a\u754c/\u7b26\u53f7\u94fe\u63a5/\u51ed\u636e\u8def\u5f84\u6821\u9a8c\u4e0e\u5ba1\u8ba1\uff09\uff1bmanifest.ui.title \u6539\u4e3a\u5bbf\u4e3b\u53cc\u8bed { en, \"zh-CN\" }\uff1b\u547d\u4ee4\u6807\u9898/\u9762\u677f\u6807\u9898/\u5de5\u5177\u63d0\u793a\u6309\u5bbf\u4e3b\u8bed\u8a00\uff08pi.app.getLocale\uff09\u5207\u6362\uff1b\u9762\u677f\u9ed8\u8ba4\u8ddf\u968f\u5bbf\u4e3b\u4e3b\u9898\uff08\u8bfb\u5bbf\u4e3b\u6ce8\u5165\u7684 data-theme\uff09\uff0c\u9762\u677f\u5185\u5207\u6362\u4fdd\u7559\u4e3a\u624b\u52a8\u8986\u76d6\uff08themeSource \u6301\u4e45\u5316\uff09\u3002Release 0.4.0\uff1a\u9762\u677f\u8ddf\u968f app \u4e3b\u4f53\u7684\u8bed\u8a00\u4e0e\u989c\u8272\u6a21\u5f0f\u2014\u2014\u5bbf\u4e3b\u5207\u6362\u4eae/\u6697\u6216\u8bed\u8a00\u65f6\uff0c\u7f16\u8f91\u5668\u4e0e\u754c\u9762\u914d\u8272\u5b9e\u65f6\u66f4\u65b0\uff08CSS \u7531 :root[data-theme=...] \u9a71\u52a8\uff0c\u914d\u5408\u5bbf\u4e3b app.getAppearance \u901a\u9053\u4e0e appearance:changed \u4e8b\u4ef6\uff09\uff1b\u672a\u624b\u52a8\u8986\u76d6\u4e3b\u9898\u65f6 settings.theme \u81ea\u52a8\u540c\u6b65\u4e3a\u5bbf\u4e3b base\uff0c\u9762\u677f\u5185\u7684\u7c73\u767d/\u9ed1\u591c\u5207\u6362\u4ecd\u53ef\u624b\u52a8\u8986\u76d6\uff08\u6b64\u540e\u4e0d\u518d\u88ab\u5bbf\u4e3b\u8986\u76d6\uff09\uff1b\u65e7\u7248\u5bbf\u4e3b\u81ea\u52a8\u964d\u7ea7\u4e3a\u9762\u677f\u81ea\u5e26\u7684\u4e3b\u9898\u8ddf\u968f\u3002Release 0.3.2\uff1a\u4ee3\u7801\u5757\u652f\u6301 Mermaid \u56fe\u8868\u5b9e\u65f6\u6e32\u67d3\uff08\u8f93\u5165 ```mermaid \u5373\u51fa\u56fe\u8868\uff0c\u6e90\u7801\u59cb\u7ec8\u53ef\u7f16\u8f91\u3001300ms \u9632\u6296\u968f\u660e\u6697\u4e3b\u9898\u5207\u6362\uff1bHTML/PNG \u5bfc\u51fa\u6e32\u67d3\u4e3a\u5185\u5d4c SVG\uff09\u3002Release 0.3.1\uff1a\u4fee\u590d LaTeX \u516c\u5f0f\u4f9d\u8d56 CodeMirror \u5bfc\u81f4\u7f16\u8f91\u5668\u65e0\u6cd5\u521d\u59cb\u5316\u7684\u95ee\u9898\uff1b\u4fee\u590d HTML/PNG \u5bfc\u51fa\u4e2d\u5757\u7ea7\u516c\u5f0f\u4e0e\u4ee3\u7801\u9ad8\u4eae\u7f3a\u5931\u7684\u95ee\u9898\uff08\u6539\u4e3a Markdown \u6e90\u7801\u7ecf\u7f16\u8f91\u5668 parser/serializer \u6e32\u67d3\uff09\uff1b\u65b0\u589e\u7c73\u767d\uff08\u9ed8\u8ba4\uff09/\u9ed1\u591c\u53cc\u4e3b\u9898\u4e0e\u72b6\u6001\u680f\u5207\u6362\u5f00\u5173\uff0c\u4e3b\u9898\u504f\u597d\u968f settings.json \u6301\u4e45\u5316\uff1b\u4ee3\u7801\u5757\u9884\u89c8\u5373\u6240\u5f97\uff08LaTeX \u76f4\u63a5\u663e\u793a KaTeX \u516c\u5f0f\u3001\u666e\u901a\u4ee3\u7801\u5757\u663e\u793a\u9ad8\u4eae\uff09\u3002Release 0.3.0\uff1a\u7f16\u8f91\u5668\u7531 Toast UI WYSIWYG\uff08\u5bcc\u6587\u672c+\u8865\u4e01\uff09\u66f4\u6362\u4e3a Milkdown Crepe\u2014\u2014\u771f\u6b63\u7684\u6240\u89c1\u5373\u6240\u5f97 Markdown \u7f16\u8f91\uff0c\u8f93\u5165\u8bed\u6cd5\u5373\u51fa\u6837\u5f0f\uff08\u542b\u4e2d\u6587\u8f93\u5165\u6cd5\uff09\u3001\u659c\u6760\u83dc\u5355/\u5757\u62d6\u62fd\u624b\u67c4\u3001\u56fe\u7247 data URL \u5185\u5d4c\u3001297 \u79cd\u8bed\u8a00 Prism \u9ad8\u4eae\u3002Release 0.2.0\uff1a\u5b8c\u6574 Markdown \u7b14\u8bb0\u5e94\u7528\uff08React + TypeScript + Tailwind \u91cd\u5199\u9762\u677f\uff09\u3002Release 0.1.0\uff1a\u6a21\u677f\u521d\u59cb\u7248\u672c\u3002", "minPiDesktop": ">=0.1.0", "shasum": "8289ee52d2cb8c1c91f5de3363140c0f8f7023ba420fda2b6649d95c9234cd6b", @@ -643,13 +574,13 @@ "safetyNotes": "Pure styling. The plugin contributes one global theme (CSS only) and a small info panel. No network, file, clipboard, or agent access.", "versions": [ { - "version": "1.0.4", - "publishedAt": "2026-09-12T17:13:25Z", - "changelog": "Release 1.0.4: fix invisible text inside dark user bubbles \u2014 filenames (file chips), image/command chips, text and code links, and inline code/code blocks now render in paper tones on the ink bubble (host 0.14.x class names). Release 1.0.3: add the Theme category tag for marketplace discovery. Release 1.0.2: add README screenshots (chat view and theme picker); force the warm code-block and inline-code palette against the host light-theme cascade (defensive specificity + !important). Release 1.0.1: fix parchment code-block and inline-code overrides against the host light-theme cascade. Release 1.0.0: first release. Warm parchment global theme built on the host design tokens: cream paper background with faint 22px grid, solid ink user bubbles with paper-colored text, soft paper assistant cards, warm code blocks and tables, monospace meta lines, and composer/message width alignment in both sidebar layouts.", + "version": "1.0.3", + "publishedAt": "2026-09-11T18:47:58Z", + "changelog": "Release 1.0.3: add the Theme category tag for marketplace discovery. Release 1.0.2: add README screenshots (chat view and theme picker); force the warm code-block and inline-code palette against the host light-theme cascade (defensive specificity + !important). Release 1.0.1: fix parchment code-block and inline-code overrides against the host light-theme cascade. Release 1.0.0: first release. Warm parchment global theme built on the host design tokens: cream paper background with faint 22px grid, solid ink user bubbles with paper-colored text, soft paper assistant cards, warm code blocks and tables, monospace meta lines, and composer/message width alignment in both sidebar layouts.", "minPiDesktop": ">=0.4.3", - "shasum": "11397e2ff5c7c245e8647c13ac8142bc545d9dd3b7922884f3ebd43aca7d0bb5", - "url": "packages/pi.parchment-1.0.4.piplug", - "sizeBytes": 351052, + "shasum": "52c664f5ce83480b6adbce993b20cd94031d6dd21c99bbacfeff96176bf6bb1a", + "url": "packages/pi.parchment-1.0.3.piplug", + "sizeBytes": 348211, "permissions": [ "ui.panel", "ui.theme" @@ -688,7 +619,7 @@ "versions": [ { "version": "0.3.3", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.3.3\uff1a\u8ba9\u8ba1\u7b97\u533a\u4e0e\u8349\u7a3f\u533a\u94fa\u6ee1\u9762\u677f\u5bbd\u5ea6\uff0c\u6d88\u9664\u5bbd\u7a97\u53e3\u53f3\u4fa7\u56fa\u5b9a\u5bbd\u5ea6\u7a7a\u767d\uff0c\u5e76\u5728\u4e3b\u9898\u53d8\u5316\u540e\u540c\u6b65\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u914d\u8272\u3002Release 0.3.2\uff1a\u8fc1\u79fb\u5230 v3 \u7a7f\u900f\u5f0f\u9876\u90e8 chrome\uff0c\u9876\u90e8\u63a7\u4ef6\u4fdd\u6301\u53ef\u70b9\u51fb\uff0c\u7a7a\u767d\u533a\u57df\u7ee7\u7eed\u53ef\u62d6\u62fd\u3002Release 0.3.1\uff1a\u9002\u914d PI-Desktop \u8de8\u5e73\u53f0 46px \u4e3b\u673a\u62d6\u62fd\u5e26\u548c\u7b80\u7ea6\u4e09\u6309\u94ae\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u3002Release 0.3.0\uff1a\u5916\u89c2\u8ddf\u968f app \u4e3b\u4f53\u2014\u2014\u9ed8\u8ba4\u8ddf\u968f\u5bbf\u4e3b\u4e3b\u9898\uff08app \u5207\u6362 light/dark \u5b9e\u65f6\u66f4\u65b0\uff0c\u65e0\u95ea\u5c4f\uff09\uff0c\u9762\u677f\u5185\u4fdd\u7559\u624b\u52a8\u4eae/\u6697\u5207\u6362\uff08\u8986\u76d6\u540e\u4e0d\u518d\u8ddf\u968f\uff0c\u53ef\u624b\u52a8\u6062\u590d\uff09\uff1b\u53ef\u89c1 chrome \u6587\u6848\uff08\u6807\u9898\u3001\u6309\u94ae\u3001toast\u3001\u5360\u4f4d\u63d0\u793a\u7b49\uff09\u652f\u6301 en/zh \u8ddf\u968f\u5bbf\u4e3b\u8bed\u8a00\u3002Release 0.2.0\uff1a\u91cd\u6784\u4e3a\u591a\u8349\u7a3f\u7a3f\u7eb8\uff08\u5e72\u51c0\u5229\u843d\u7684\u76f4\u89d2\u98ce\u683c\uff09\u2014\u2014\u5de6\u4fa7\u5f53\u524d\u8349\u7a3f\uff1a\u8f93\u5165\u884c\u5b9e\u65f6\u8ba1\u7b97 + \u672c\u7a3f\u5386\u53f2 + \u6bcf\u884c\u53ef\u7f16\u8f91\u5907\u6ce8 + \u6e05\u7a7a/\u590d\u5236\u4e3a\u56fe\u7247\uff1b\u53f3\u4fa7\u8349\u7a3f\u5217\u8868\uff1a\u65f6\u95f4\u547d\u540d\u65b0\u5efa\u3001\u70b9\u51fb\u5207\u6362\u3001\u7ba1\u7406\u6a21\u5f0f\u9010\u6761\u5220\u9664\u3002\u65e7\u7248\u5386\u53f2\u81ea\u52a8\u8fc1\u79fb\u3002", "minPiDesktop": ">=0.1.0", "shasum": "cd7510c2cd7b2271008605f86ce959da7da7e732ec9a8e21a3874d38699e0cb7", @@ -701,52 +632,6 @@ } ] }, - { - "id": "pi.session-orchestrator", - "name": "Session Orchestrator", - "description": "Coordinate durable PI-Desktop sessions with bidirectional messages, host-owned completion notifications, reliable results, and configured model selection.", - "i18n": { - "en": { - "name": "Session Orchestrator", - "description": "Create bounded sessions, discover existing Agent sessions, send messages in either direction using real Session IDs, receive automatic completion notifications, and inspect host-owned status and results.", - "safetyNotes": "This high-risk tool can create sessions, read session collaboration summaries and results, send messages that run the target Agent, and cancel collaboration work through desktop.control. Messages can address any existing Session ID and may consume configured model quota. The host binds the sender, preserves existing target configuration and permissions, labels session messages separately from user input, and bounds autonomous creation and callbacks. Plugin history never grants access. The plugin has no network permission and never deletes sessions or reads credentials." - }, - "zh-CN": { - "name": "Session Orchestrator \u4f1a\u8bdd\u7f16\u6392\u5668", - "description": "\u4f7f\u7528\u771f\u5b9e Session ID \u53d1\u73b0\u5e76\u901a\u4fe1\u72ec\u7acb Agent \u4f1a\u8bdd\uff0c\u521b\u5efa\u6709\u754c Worker\u3001\u53cc\u5411\u53d1\u9001\u4f1a\u8bdd\u6d88\u606f\uff0c\u81ea\u52a8\u63a5\u6536\u5b8c\u6210\u901a\u77e5\uff0c\u5e76\u67e5\u8be2\u5bbf\u4e3b\u8bb0\u5f55\u7684\u72b6\u6001\u548c\u6267\u884c\u7ed3\u679c\u3002", - "safetyNotes": "\u8fd9\u662f\u4e00\u4e2a\u9ad8\u98ce\u9669\u5de5\u5177\uff0c\u4f1a\u901a\u8fc7 desktop.control \u521b\u5efa\u4f1a\u8bdd\u3001\u8bfb\u53d6\u534f\u4f5c\u6458\u8981\u548c\u7ed3\u679c\u3001\u53d1\u9001\u6d88\u606f\u542f\u52a8\u76ee\u6807 Agent\uff0c\u4ee5\u53ca\u53d6\u6d88\u534f\u4f5c\u4efb\u52a1\u3002\u6d88\u606f\u53ef\u4ee5\u53d1\u7ed9\u4efb\u610f\u5df2\u5b58\u5728\u7684 Session ID\uff0c\u5e76\u53ef\u80fd\u6d88\u8017\u5df2\u914d\u7f6e\u6a21\u578b\u7684\u8c03\u7528\u989d\u5ea6\u3002\u5bbf\u4e3b\u7ed1\u5b9a\u771f\u5b9e\u53d1\u9001\u8005\u3001\u4fdd\u7559\u5df2\u6709\u76ee\u6807\u4f1a\u8bdd\u7684\u914d\u7f6e\u548c\u6743\u9650\u3001\u5c06\u4f1a\u8bdd\u6d88\u606f\u4e0e\u7528\u6237\u8f93\u5165\u533a\u5206\uff0c\u5e76\u9650\u5236\u81ea\u4e3b\u521b\u5efa\u548c\u81ea\u52a8\u56de\u8c03\u3002\u63d2\u4ef6\u5386\u53f2\u8bb0\u5f55\u4e0d\u6388\u4e88\u8bbf\u95ee\u6743\u9650\u3002\u63d2\u4ef6\u6ca1\u6709\u7f51\u7edc\u6743\u9650\uff0c\u4e0d\u5220\u9664\u4f1a\u8bdd\uff0c\u4e5f\u4e0d\u8bfb\u53d6\u51ed\u636e\u3002" - } - }, - "author": "PI-Desktop", - "categories": [ - "developer-tools", - "official" - ], - "verified": true, - "downloads": 0, - "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/pi.session-orchestrator", - "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# Session Orchestrator\n\nSession Orchestrator coordinates real PI-Desktop sessions through one\nhigh-risk Agent tool, `SessionTask`. Every session is addressed by its existing\ndurable `sessionId`; follow-up messages keep that session's context and model.\nThe host owns delivery, queue admission, execution state, results, and completion\nnotifications. The plugin does not infer success from assistant text.\n\n## A normal workflow\n\n1. Call `models` to inspect the user's ready configured models when a task needs\n a particular model. Then `spawn(task, title?, model?)` to create a worker.\n Keep the returned `sessionId` and delivery `messageId`.\n2. Work in parallel. By default the host sends a completion message back to the\n sending session when the target turn settles; repeated polling is unnecessary.\n3. Use `send(sessionId, message)` for follow-up work in the same session, or to\n communicate with any other existing session. Workers can reply to their\n initiating session and peers by their real Session IDs.\n4. Inspect `status` or `result` when needed. Pass `messageId` or `turnId` to\n retrieve one specific delivery instead of whichever message is latest.\n5. Review the actual result. `accept` optionally records that review for the\n exact completed message. `cancel` stops collaboration work and retains the\n durable session and history.\n\nA received message is explicitly identified as another session's communication,\nnot human input or new user authorization. Completion notices need no\nacknowledgement unless further work is necessary. Use\n`notifyOnCompletion: false` for informational messages to avoid unnecessary\nreturn messages. Host-generated completion notices never request another\nautomatic completion notice.\n\n## Actions\n\n| Action | Behavior |\n| --- | --- |\n| `spawn(task, title?, model?)` | Atomically creates a real worker and admits its first delivery through the host. |\n| `send(sessionId, message, kind?)` | Sends a task or message to an existing session, including a busy session's host queue. Does not reselect its model. |\n| `models()` | Lists ready model keys, aliases, reasoning metadata, AI-delegation eligibility, and the default. |\n| `status(sessionIds?)` | Reads host-owned live summaries; omission selects this caller's recent session references. |\n| `list()` | Reads a bounded host-backed directory of communicable Agent sessions, including independent top-level sessions. The response also retains a legacy `workers` field for recent-reference callers. |\n| `result(sessionId, messageId?, turnId?)` | Returns the host delivery and exact turn outcome. Failed or interrupted work is never accepted as a successful report. |\n| `wait(sessionIds, timeoutMs?)` | Explicit polling fallback, 25 seconds by default and at most 45 seconds. The entire read budget observes the deadline and cancellation. |\n| `supervise(sessionIds, message)` | Sends up to four follow-ups in parallel; returns successful receipts and any individual failures. |\n| `accept(sessionId|sessionIds, messageId?, note?)` | Stores review metadata keyed by the exact completed delivery. It never changes host execution state. |\n| `cancel(sessionId, messageId?)` | Cancels target collaboration work without deleting the session. |\n\n`result.ready` means the delivery has settled, including failure, cancellation,\nor interruption. Successful work requires `message.status === \"completed\"`;\nthe compatibility `worker.report` field is populated only for that outcome.\n\n`spawn` and `send` accept `notifyOnCompletion` (default true) and an optional\n`idempotencyKey` for retrying the same request. Use a different key for a new\nrequest. For batch supervision requiring retry identities, call `send` separately\nwith one key per target. Session identity and delivery identity have separate\npurposes: `messageId` names a ledger entry, not a second worker system.\n\n## Model selection\n\nAn omitted `model` first selects from ready bindings with\n`availableForSubagents: true`. A default within that set takes precedence;\notherwise the first configured eligible row provides a stable selection.\nOnly when that set is empty does the configured ready default apply. An empty\ncatalog or unavailable default produces a clear configuration error.\n\nThe spawn response records `requestedModel` and its selection policy; the\nactual session model is read from `status.modelKey`, including after an\nidempotent retry.\n\nAn explicit request resolves against existing model keys, IDs, aliases and\nnames. Matching handles case, spacing, punctuation, common English/Chinese\nfamily names, and supported reasoning/non-reasoning intent. Numeric version\norder is preserved. Multiple matches return bounded exact-key candidates;\nno match is an error. The plugin never invents a model ID or silently chooses\nan unrelated default. It does not rank model quality or cost from brand names;\nthe Parent can use `models` and the task requirements to make that decision.\n\nExisting-session `send` never changes provider, model, project, context, or\npermissions. New-session project and permission inheritance, effective thinking\nconfiguration, active-worker limits (four per creator, sixteen per plugin), and\nthe restriction on workers autonomously creating further workers are enforced\nby the host, using durable creation provenance.\n\n## State and recovery\n\nPI-Desktop's durable session communication ledger is authoritative. Status,\ncurrent task, sender, recent exchanges, and final outcome come directly from it.\nA callback is tied to the actual settled turn, retained on failure, and generated\nat most once. Restart follows the host's existing interruption fence; the\nplugin does not replay messages or start replacements during load.\n\nPrivate plugin settings retain at most 256 recent session references and 256\nmessage review notes. They contain no cached transcript, report, or execution\nstate. Reference eviction affects only recent-history discovery, never the\nability to address a known Session ID or the host's creation limits. Successful\nhost receipts remain available to the caller if optional history persistence\nfails; the response includes a warning.\n\nVersion 0.3 `workerSessionId`/`sessionId` records migrate to recent references.\nOld cached statuses, reports, rounds and acceptance markers are retired because\nthey cannot prove a host delivery's outcome. Existing sessions are preserved.\nLegacy `workerId`/`workerIds` arguments remain supported aliases; conflicting\naliases are rejected. Unloading cancels plugin reads and waits, unregisters the\ntool and command, and flushes metadata. Host-owned work and callbacks remain\nowned by the host.\n\n## Agents panel\n\nThe panel shows recent Session IDs, host status, creation/task source, and\nbounded recent exchanges. Open Session navigates explicitly; Stop calls the\nreviewed collaboration cancellation operation. Background refresh reads only\nbounded summaries every five seconds while the panel is visible. One missing\nor inaccessible session does not hide other references. Labels and previews\nare escaped before rendering, and asynchronous actions cannot be submitted\ntwice while pending.\n\n## Host compatibility and security\n\nThe manifest retains `engines.piDesktop >=0.14.7`, but version alone does not\nprove this additive capability exists. Each operation checks the host's reviewed\ncatalog for `session/collaboration/{spawn,send,list,status,result,cancel}`. An older\nhost receives an explicit update-required error; the plugin never falls back\nto untracked create/prompt calls or transcript inference. `session/open` is\nchecked independently.\n\n| Capability | Data and boundary |\n| --- | --- |\n| `desktop.control` | Creates sessions, exchanges messages, reads collaboration summaries/results, cancels work, and explicitly opens sessions. The host binds the sender to the current Agent tool invocation, enforces permissions and bounded creation, and labels provenance. Messages can consume configured model quota. |\n| `models.list` | Reads ready configured model identifiers, aliases, delegation flags and reasoning metadata; no credentials. |\n| `ui.panel` | Displays bounded summaries through the isolated plugin bridge; local Stop/Open actions remain host-authorized. |\n| Plugin settings | Stores only bounded recent references and review notes keyed by delivery identity. Never grants access or represents execution truth. |\n\nThe high-risk grant allows bidirectional communication with any existing\nsession. Message content is task data and cannot grant new permissions. The\nplugin has no direct network permission, never reads credentials or MCP tokens,\nnever executes downloaded code, and never deletes sessions. Host provider\nrequests continue to use the user's configured model and normal policy.\n", - "safetyNotes": "This high-risk tool can create sessions, read session collaboration summaries and results, send messages that run the target Agent, and cancel collaboration work through desktop.control. Messages can address any existing Session ID and may consume configured model quota. The host binds the sender, preserves existing target configuration and permissions, labels session messages separately from user input, and bounds autonomous creation and callbacks. Plugin history never grants access. The plugin has no network permission and never deletes sessions or reads credentials.", - "versions": [ - { - "version": "0.5.0", - "publishedAt": "2026-09-13T13:55:42Z", - "changelog": "Release 0.5.0: discovers existing independent Agent sessions through the host-backed list action while retaining legacy worker references and bidirectional messaging.\nRelease 0.4.0: moves delivery, completion callbacks and turn-bound results to the host; enables bidirectional messaging by real Session ID; resolves configured models by key, alias, family or reasoning intent; retains recent references without using them as authorization; fixes panel Stop and cancellable wait deadlines.", - "minPiDesktop": ">=0.14.7", - "shasum": "bd9fcf67ad5b3eff46e5ec20580cd1c6fd62c1e660f47efbadc4fd9311a7a504", - "url": "packages/pi.session-orchestrator-0.5.0.piplug", - "sizeBytes": 81273, - "permissions": [ - "ui.panel", - "agent.tool.register", - "desktop.control", - "models.list" - ], - "fs": {} - } - ] - }, { "id": "pi.ssh-manager", "name": "SSH Manager", @@ -772,17 +657,17 @@ "downloads": 0, "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/pi.ssh-manager", "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# SSH \u5728\u7ebf\u7ba1\u7406 \u00b7 SSH Manager\n\n`pi.ssh-manager` \u662f\u4e00\u4e2a\u672c\u5730\u4f18\u5148\u7684 SSH \u4e3b\u673a\u7ba1\u7406\u63d2\u4ef6\uff1a\u9762\u677f\u4fdd\u5b58\u4e3b\u673a\u8fde\u63a5\u5143\u6570\u636e\uff0c\n\u8ba4\u8bc1\u4ea4\u7ed9\u672c\u673a OpenSSH\u3001\u5df2\u6709\u7684 `~/.ssh/config`\u3001ssh-agent\u3001\u7528\u6237\u6307\u5b9a\u7684\u79c1\u94a5\u8def\u5f84\uff0c\u6216\u9762\u677f\u4e2d\n\u4e34\u65f6\u8f93\u5165\u7684\u5bc6\u7801\u3002\u6dfb\u52a0\u6216\u7f16\u8f91\u4e3b\u673a\u65f6\uff0c\u79c1\u94a5\u53ef\u4ee5\u624b\u52a8\u8f93\u5165\u8def\u5f84\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u300c\u9009\u62e9\u6587\u4ef6\u300d\uff1b\u63d2\u4ef6\u53ea\n\u4f7f\u7528 Electron \u63d0\u4f9b\u7684\u6587\u4ef6\u8def\u5f84\uff0c\u4ece\u4e0d\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002\n\u63d2\u4ef6\u628a\u6709\u9650\u65f6\u3001\u6709\u9650\u8f93\u51fa\u7684 SSH \u80fd\u529b\u63d0\u4f9b\u7ed9 PI-Desktop AI\u3002\n\n## \u80fd\u505a\u4ec0\u4e48\n\n- \u7ba1\u7406\u591a\u53f0 SSH \u4e3b\u673a\uff1a\u540d\u79f0\u3001\u4e3b\u673a\u3001\u7aef\u53e3\u3001\u7528\u6237\u540d\u3001\u79c1\u94a5\u8def\u5f84\u548c agent socket\u3002\n- \u4e00\u952e\u626b\u63cf\u5e76\u5bfc\u5165\u672c\u673a `~/.ssh/config`\uff08\u542b\u6709\u754c\u7684 `Include`\uff09\uff0c\u4fdd\u7559 Host \u522b\u540d\u4ee5\u7ee7\u7eed\u4f7f\u7528\u5b8c\u6574 OpenSSH \u914d\u7f6e\uff08\u5305\u62ec ProxyJump\uff09\u3002\u91cd\u590d\u626b\u63cf\u4f1a\u66f4\u65b0\u5df2\u6709\u5bfc\u5165\u9879\uff0c\u4e0d\u4f1a\u91cd\u590d\u521b\u5efa\u3002\u8fde\u63a5\u5931\u8d25\u4f1a\u4fdd\u7559 OpenSSH \u7684\u4f20\u8f93\u8bca\u65ad\uff08\u5305\u62ec Windows \u7684 banner exchange / connection refused\uff09\uff0c\u800c\u4e0d\u662f\u53ea\u663e\u793a\u7b3c\u7edf\u7684 exit 255\uff1bWindows \u4f1a\u7ee7\u627f SYSTEMROOT \u7b49\u7cfb\u7edf\u73af\u5883\u5e76\u67e5\u627e `ssh.exe`\u3002\n- \u5bfc\u5165\u81ea\u5b9a\u4e49\u914d\u7f6e\u6587\u4ef6\u65f6\u4f1a\u5728\u8fde\u63a5\u4e2d\u7ee7\u7eed\u4f7f\u7528\u8be5\u914d\u7f6e\u6587\u4ef6\uff1b\u7f16\u8f91\u5bfc\u5165\u4e3b\u673a\u7684\u5730\u5740\u3001\u7aef\u53e3\u3001\u7528\u6237\u540d\u6216\u5bc6\u94a5\u8def\u5f84\u540e\uff0c\u63d2\u4ef6\u4f1a\u81ea\u52a8\u89e3\u9664\u522b\u540d\u7ed1\u5b9a\u5e76\u6309\u8868\u5355\u4e2d\u7684\u663e\u5f0f\u503c\u8fde\u63a5\u3002\n- \u9ed8\u8ba4 `~/.ssh/config` \u4ecd\u6309\u666e\u901a OpenSSH \u65b9\u5f0f\u52a0\u8f7d\uff0c\u56e0\u6b64\u4e0d\u4f1a\u56e0\u663e\u5f0f `-F` \u800c\u8df3\u8fc7\u7cfb\u7edf\u7ea7 SSH \u914d\u7f6e\uff1bWindows \u5bc6\u7801 helper \u4e0d\u7ecf\u8fc7\u6279\u5904\u7406\u53d8\u91cf\u5c55\u5f00\uff0c\u5bc6\u7801\u4e2d\u7684\u547d\u4ee4\u7b26\u53f7\u4f1a\u539f\u6837\u4ea4\u7ed9 OpenSSH\u3002\n- \u9ed8\u8ba4\u4e25\u683c\u6821\u9a8c `known_hosts`\uff1b\u53ea\u6709\u7528\u6237\u663e\u5f0f\u9009\u62e9\u65f6\u624d\u4f7f\u7528 `accept-new`\u3002\n- \u5728\u9762\u677f\u4e2d\u6d4b\u8bd5\u8fde\u63a5\u3001\u6267\u884c\u4e00\u6b21\u6027\u547d\u4ee4\u3001\u67e5\u770b stdout/stderr\uff0c\u5e76\u5fd8\u8bb0\u903b\u8f91\u4f1a\u8bdd\u3002\n- \u5411 AI \u66b4\u9732\u56db\u4e2a\u5de5\u5177\uff1a\n - `plugin_pi_ssh_manager_ssh_list_hosts`\n - `plugin_pi_ssh_manager_ssh_connect`\n - `plugin_pi_ssh_manager_ssh_execute`\n - `plugin_pi_ssh_manager_ssh_disconnect`\n- \u9ed8\u8ba4\u53ea\u653e\u884c\u7ecf\u8fc7\u9759\u6001\u6821\u9a8c\u7684\u547d\u4ee4\uff1b\u9012\u5f52\u5220\u9664\u3001\u6587\u4ef6\u8986\u76d6\u3001\u78c1\u76d8\u5199\u5165\u3001\u6570\u636e\u5e93\u53d8\u66f4\u3001\u670d\u52a1/\u6743\u9650\u4fee\u6539\u3001\u5bb9\u5668\u5220\u9664\u3001\u91cd\u542f\u3001\u7f51\u7edc\u811a\u672c\u7ba1\u9053\u4ee5\u53ca shell \u94fe\u5f0f\u547d\u4ee4\u90fd\u4f1a\u88ab\u62e6\u622a\u3002\n- \u88ab\u62e6\u622a\u7684\u547d\u4ee4\u53ea\u6709\u5728 SSH \u7ba1\u7406\u9762\u677f\u52fe\u9009\u300c\u672c\u6b21\u5141\u8bb8\u6267\u884c\u88ab\u62e6\u622a\u7684\u5371\u9669\u6307\u4ee4\u300d\u540e\u624d\u4f1a\u653e\u884c\u4e00\u6b21\uff1bAI \u5de5\u5177\u4e0d\u80fd\u4f20\u5165\u6216\u4f2a\u9020\u8fd9\u4e2a\u6388\u6743\u3002\n\n## \u8ba4\u8bc1\u4e0e\u6570\u636e\u8fb9\u754c\n\n\u63d2\u4ef6\u4e0d\u4f1a\u6301\u4e45\u5316\u5bc6\u7801\u3001passphrase\u3001\u79c1\u94a5\u5185\u5bb9\u3001\u547d\u4ee4\u8f93\u51fa\u6216\u8fdc\u7a0b transcript\u3002\u9700\u8981\u5bc6\u7801\n\u8ba4\u8bc1\u65f6\uff0c\u53ef\u4ee5\u5728\u9762\u677f\u7684\u300c\u5bc6\u7801\uff08\u4e0d\u4fdd\u5b58\uff09\u300d\u8f93\u5165\u6846\u4e2d\u5f55\u5165\uff1b\u5bc6\u7801\u53ea\u5728\u5f53\u524d\u63d2\u4ef6\u8fdb\u7a0b\u5185\u4fdd\u5b58\n\u6700\u591a 30 \u5206\u949f\uff0c\u901a\u8fc7\u4e00\u6b21\u6027\u672c\u5730 IPC broker \u548c `SSH_ASKPASS` helper \u4ea4\u7ed9 OpenSSH\uff1b\u5bc6\u7801\u4e0d\u4f1a\u8fdb\u5165 `ssh` \u8fdb\u7a0b\u73af\u5883\uff0c\u907f\u514d\u88ab\u5bbd\u6cdb\u7684 `SendEnv` \u914d\u7f6e\u53d1\u9001\u5230\u8fdc\u7aef\u3002\u63d2\u4ef6\u91cd\u542f\u3001\u5378\u8f7d\u6216\n\u8d85\u65f6\u540e\u4f1a\u81ea\u52a8\u6e05\u9664\u3002AI \u5de5\u5177\u6c38\u8fdc\u4e0d\u4f1a\u63a5\u6536\u5bc6\u7801\u53c2\u6570\uff0c\u4f46\u53ef\u4ee5\u590d\u7528\u5f53\u524d\u5185\u5b58\u4e2d\u7684\u5bc6\u7801\u72b6\u6001\u3002\n\u8bf7\u4f18\u5148\u5728\u672c\u673a\u914d\u7f6e OpenSSH\uff1a\n\n```sshconfig\nHost production\n HostName server.example.com\n User deploy\n IdentityFile ~/.ssh/id_ed25519\n```\n\n\u7136\u540e\u5728\u9762\u677f\u4e2d\u628a `Host` \u586b\u4e3a `production`\uff0c\u6216\u76f4\u63a5\u586b\u5199\u5b9e\u9645\u4e3b\u673a\u540d\u3002\u9700\u8981\u4f7f\u7528\nssh-agent \u65f6\uff0c\u4f18\u5148\u8ba9 PI-Desktop \u7ee7\u627f\u6b63\u786e\u7684 `SSH_AUTH_SOCK`\uff0c\u4e5f\u53ef\u4ee5\u5728\u4e3b\u673a\u914d\u7f6e\u4e2d\n\u586b\u5199 agent socket \u8def\u5f84\u3002\u5e26 passphrase \u7684\u5bc6\u94a5\u5e94\u7531 ssh-agent \u6216\u7cfb\u7edf OpenSSH \u914d\u7f6e\n\u8d1f\u8d23\u89e3\u9501\uff1b\u63d2\u4ef6\u4e0d\u4f1a\u628a\u5b83\u4eec\u5199\u5165\u8bbe\u7f6e\u3002\n\n\u201c\u8fde\u63a5\u201d\u521b\u5efa\u7684\u662f\u63d2\u4ef6\u5185\u7684\u903b\u8f91\u4f1a\u8bdd\u3002\u6bcf\u6b21\u547d\u4ee4\u4ecd\u542f\u52a8\u4e00\u4e2a\u6709\u8d85\u65f6\u548c\u8f93\u51fa\u4e0a\u9650\u3001\u4e0d\u4f1a\u7ee7\u627f\u63d2\u4ef6\u6807\u51c6\u8f93\u5165\u7684\u672c\u673a\n`ssh` \u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u5728\u63d2\u4ef6\u8fdb\u7a0b\u91cc\u4fdd\u7559\u4e00\u4e2a\u53ef\u88ab\u540e\u53f0\u590d\u7528\u7684\u8fdc\u7a0b shell\u3002\n\n## Windows OpenSSH startup\n\nPI-Desktop passes a minimal environment to plugins. Windows OpenSSH requires\n`ProgramData` even for `ssh -V`; without it, it can exit 255 with no output before\nconnection diagnostics are initialized. The plugin preserves an inherited\n`ProgramData` (case-insensitive) or `ALLUSERSPROFILE`, and otherwise supplies\n`ProgramData` on the Windows system volume (normally `C:\\ProgramData`). It does\nnot copy unrelated environment variables or change host-key verification.\n\n## AI \u4f7f\u7528\u5efa\u8bae\n\nAI \u5e94\u5148\u8c03\u7528 `ssh_list_hosts`\uff0c\u518d\u4f7f\u7528\u7528\u6237\u786e\u8ba4\u8fc7\u7684 `profile_id` \u8fde\u63a5\u3002\u8fde\u63a5\u548c\u6267\u884c\n\u5747\u662f\u9ad8\u98ce\u9669\u5de5\u5177\uff0c\u4f1a\u7ecf\u8fc7 PI-Desktop \u7684\u5de5\u5177\u6743\u9650\u7b56\u7565\u3002AI \u4e0d\u5e94\u8981\u6c42\u7528\u6237\u628a\u5bc6\u7801\u3001\u79c1\u94a5\n\u6216 token \u7c98\u8d34\u5230\u5bf9\u8bdd\u4e2d\uff1b\u65b0\u4e3b\u673a\u5bc6\u94a5\u548c\u7834\u574f\u6027\u547d\u4ee4\u5fc5\u987b\u5148\u5411\u7528\u6237\u786e\u8ba4\u3002\u82e5\u547d\u4ee4\u88ab\u5b89\u5168\u8fc7\u6ee4\u5668\n\u62e6\u622a\uff0cAI \u53ea\u80fd\u63d0\u793a\u7528\u6237\u5728 SSH \u7ba1\u7406\u9762\u677f\u4e2d\u5ba1\u6838\u5e76\u52fe\u9009\u4e00\u6b21\u6027\u6388\u6743\uff0c\u4e0d\u80fd\u81ea\u884c\u7ed5\u8fc7\u8fc7\u6ee4\u5668\u3002\n\n## \u6743\u9650\n\n- `ui.panel`\uff1a\u6253\u5f00 SSH \u7ba1\u7406\u9762\u677f\u3002\n- `agent.tool.register`\uff1a\u6ce8\u518c AI SSH \u5de5\u5177\u3002\n- `agent.prompt.inject`\uff1a\u52a0\u8f7d\u5b89\u5168 SSH \u4f7f\u7528\u8bf4\u660e\u3002\n\n\u63d2\u4ef6\u53ea\u4f7f\u7528\u672c\u673a `ssh` \u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4e0d\u4f7f\u7528 `net.fetch`\uff0c\u4e5f\u4e0d\u628a\u51ed\u636e\u5199\u5165\u63d2\u4ef6\u8bbe\u7f6e\u3002\n\n## \u5f00\u53d1\u9a8c\u8bc1\n\n```bash\nnode --test tests/ssh-manager.test.mjs\npython3 scripts/pack_plugin.py plugins/pi.ssh-manager\npython3 scripts/rebuild_catalog.py\n```\n\n\u672c\u5730\u8fd0\u884c\u65f6\u8bf7\u5728 PI-Desktop \u4e2d\u9009\u62e9\u300c\u63d2\u4ef6 \u2192 \u52a0\u8f7d\u5f00\u53d1\u63d2\u4ef6\u300d\uff0c\u518d\u9009\u62e9\u672c\u76ee\u5f55\u3002\n", + "readmeMarkdown": "# SSH \u5728\u7ebf\u7ba1\u7406 \u00b7 SSH Manager\n\n`pi.ssh-manager` \u662f\u4e00\u4e2a\u672c\u5730\u4f18\u5148\u7684 SSH \u4e3b\u673a\u7ba1\u7406\u63d2\u4ef6\uff1a\u9762\u677f\u4fdd\u5b58\u4e3b\u673a\u8fde\u63a5\u5143\u6570\u636e\uff0c\n\u8ba4\u8bc1\u4ea4\u7ed9\u672c\u673a OpenSSH\u3001\u5df2\u6709\u7684 `~/.ssh/config`\u3001ssh-agent\u3001\u7528\u6237\u6307\u5b9a\u7684\u79c1\u94a5\u8def\u5f84\uff0c\u6216\u9762\u677f\u4e2d\n\u4e34\u65f6\u8f93\u5165\u7684\u5bc6\u7801\u3002\u6dfb\u52a0\u6216\u7f16\u8f91\u4e3b\u673a\u65f6\uff0c\u79c1\u94a5\u53ef\u4ee5\u624b\u52a8\u8f93\u5165\u8def\u5f84\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u300c\u9009\u62e9\u6587\u4ef6\u300d\uff1b\u63d2\u4ef6\u53ea\n\u4f7f\u7528 Electron \u63d0\u4f9b\u7684\u6587\u4ef6\u8def\u5f84\uff0c\u4ece\u4e0d\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002\n\u63d2\u4ef6\u628a\u6709\u9650\u65f6\u3001\u6709\u9650\u8f93\u51fa\u7684 SSH \u80fd\u529b\u63d0\u4f9b\u7ed9 PI-Desktop AI\u3002\n\n## \u80fd\u505a\u4ec0\u4e48\n\n- \u7ba1\u7406\u591a\u53f0 SSH \u4e3b\u673a\uff1a\u540d\u79f0\u3001\u4e3b\u673a\u3001\u7aef\u53e3\u3001\u7528\u6237\u540d\u3001\u79c1\u94a5\u8def\u5f84\u548c agent socket\u3002\n- \u4e00\u952e\u626b\u63cf\u5e76\u5bfc\u5165\u672c\u673a `~/.ssh/config`\uff08\u542b\u6709\u754c\u7684 `Include`\uff09\uff0c\u4fdd\u7559 Host \u522b\u540d\u4ee5\u7ee7\u7eed\u4f7f\u7528\u5b8c\u6574 OpenSSH \u914d\u7f6e\uff08\u5305\u62ec ProxyJump\uff09\u3002\u91cd\u590d\u626b\u63cf\u4f1a\u66f4\u65b0\u5df2\u6709\u5bfc\u5165\u9879\uff0c\u4e0d\u4f1a\u91cd\u590d\u521b\u5efa\u3002\u8fde\u63a5\u5931\u8d25\u4f1a\u5c55\u793a OpenSSH \u8bca\u65ad\u800c\u4e0d\u662f\u7b3c\u7edf\u7684 exit 255\uff1bWindows \u4f1a\u7ee7\u627f SYSTEMROOT \u7b49\u7cfb\u7edf\u73af\u5883\u5e76\u67e5\u627e `ssh.exe`\u3002\n- \u9ed8\u8ba4\u4e25\u683c\u6821\u9a8c `known_hosts`\uff1b\u53ea\u6709\u7528\u6237\u663e\u5f0f\u9009\u62e9\u65f6\u624d\u4f7f\u7528 `accept-new`\u3002\n- \u5728\u9762\u677f\u4e2d\u6d4b\u8bd5\u8fde\u63a5\u3001\u6267\u884c\u4e00\u6b21\u6027\u547d\u4ee4\u3001\u67e5\u770b stdout/stderr\uff0c\u5e76\u5fd8\u8bb0\u903b\u8f91\u4f1a\u8bdd\u3002\n- \u5411 AI \u66b4\u9732\u56db\u4e2a\u5de5\u5177\uff1a\n - `plugin_pi_ssh_manager_ssh_list_hosts`\n - `plugin_pi_ssh_manager_ssh_connect`\n - `plugin_pi_ssh_manager_ssh_execute`\n - `plugin_pi_ssh_manager_ssh_disconnect`\n- \u9ed8\u8ba4\u53ea\u653e\u884c\u7ecf\u8fc7\u9759\u6001\u6821\u9a8c\u7684\u547d\u4ee4\uff1b\u9012\u5f52\u5220\u9664\u3001\u6587\u4ef6\u8986\u76d6\u3001\u78c1\u76d8\u5199\u5165\u3001\u6570\u636e\u5e93\u53d8\u66f4\u3001\u670d\u52a1/\u6743\u9650\u4fee\u6539\u3001\u5bb9\u5668\u5220\u9664\u3001\u91cd\u542f\u3001\u7f51\u7edc\u811a\u672c\u7ba1\u9053\u4ee5\u53ca shell \u94fe\u5f0f\u547d\u4ee4\u90fd\u4f1a\u88ab\u62e6\u622a\u3002\n- \u88ab\u62e6\u622a\u7684\u547d\u4ee4\u53ea\u6709\u5728 SSH \u7ba1\u7406\u9762\u677f\u52fe\u9009\u300c\u672c\u6b21\u5141\u8bb8\u6267\u884c\u88ab\u62e6\u622a\u7684\u5371\u9669\u6307\u4ee4\u300d\u540e\u624d\u4f1a\u653e\u884c\u4e00\u6b21\uff1bAI \u5de5\u5177\u4e0d\u80fd\u4f20\u5165\u6216\u4f2a\u9020\u8fd9\u4e2a\u6388\u6743\u3002\n\n## \u8ba4\u8bc1\u4e0e\u6570\u636e\u8fb9\u754c\n\n\u63d2\u4ef6\u4e0d\u4f1a\u6301\u4e45\u5316\u5bc6\u7801\u3001passphrase\u3001\u79c1\u94a5\u5185\u5bb9\u3001\u547d\u4ee4\u8f93\u51fa\u6216\u8fdc\u7a0b transcript\u3002\u9700\u8981\u5bc6\u7801\n\u8ba4\u8bc1\u65f6\uff0c\u53ef\u4ee5\u5728\u9762\u677f\u7684\u300c\u5bc6\u7801\uff08\u4e0d\u4fdd\u5b58\uff09\u300d\u8f93\u5165\u6846\u4e2d\u5f55\u5165\uff1b\u5bc6\u7801\u53ea\u5728\u5f53\u524d\u63d2\u4ef6\u8fdb\u7a0b\u5185\u4fdd\u5b58\n\u6700\u591a 30 \u5206\u949f\uff0c\u901a\u8fc7\u4e00\u6b21\u6027 `SSH_ASKPASS` helper \u4ea4\u7ed9 OpenSSH\uff0c\u63d2\u4ef6\u91cd\u542f\u3001\u5378\u8f7d\u6216\n\u8d85\u65f6\u540e\u4f1a\u81ea\u52a8\u6e05\u9664\u3002AI \u5de5\u5177\u6c38\u8fdc\u4e0d\u4f1a\u63a5\u6536\u5bc6\u7801\u53c2\u6570\uff0c\u4f46\u53ef\u4ee5\u590d\u7528\u5f53\u524d\u5185\u5b58\u4e2d\u7684\u5bc6\u7801\u72b6\u6001\u3002\n\u8bf7\u4f18\u5148\u5728\u672c\u673a\u914d\u7f6e OpenSSH\uff1a\n\n```sshconfig\nHost production\n HostName server.example.com\n User deploy\n IdentityFile ~/.ssh/id_ed25519\n```\n\n\u7136\u540e\u5728\u9762\u677f\u4e2d\u628a `Host` \u586b\u4e3a `production`\uff0c\u6216\u76f4\u63a5\u586b\u5199\u5b9e\u9645\u4e3b\u673a\u540d\u3002\u9700\u8981\u4f7f\u7528\nssh-agent \u65f6\uff0c\u4f18\u5148\u8ba9 PI-Desktop \u7ee7\u627f\u6b63\u786e\u7684 `SSH_AUTH_SOCK`\uff0c\u4e5f\u53ef\u4ee5\u5728\u4e3b\u673a\u914d\u7f6e\u4e2d\n\u586b\u5199 agent socket \u8def\u5f84\u3002\u5e26 passphrase \u7684\u5bc6\u94a5\u5e94\u7531 ssh-agent \u6216\u7cfb\u7edf OpenSSH \u914d\u7f6e\n\u8d1f\u8d23\u89e3\u9501\uff1b\u63d2\u4ef6\u4e0d\u4f1a\u628a\u5b83\u4eec\u5199\u5165\u8bbe\u7f6e\u3002\n\n\u201c\u8fde\u63a5\u201d\u521b\u5efa\u7684\u662f\u63d2\u4ef6\u5185\u7684\u903b\u8f91\u4f1a\u8bdd\u3002\u6bcf\u6b21\u547d\u4ee4\u4ecd\u542f\u52a8\u4e00\u4e2a\u6709\u8d85\u65f6\u548c\u8f93\u51fa\u4e0a\u9650\u7684\u672c\u673a\n`ssh` \u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u5728\u63d2\u4ef6\u8fdb\u7a0b\u91cc\u4fdd\u7559\u4e00\u4e2a\u53ef\u88ab\u540e\u53f0\u590d\u7528\u7684\u8fdc\u7a0b shell\u3002\n\n## AI \u4f7f\u7528\u5efa\u8bae\n\nAI \u5e94\u5148\u8c03\u7528 `ssh_list_hosts`\uff0c\u518d\u4f7f\u7528\u7528\u6237\u786e\u8ba4\u8fc7\u7684 `profile_id` \u8fde\u63a5\u3002\u8fde\u63a5\u548c\u6267\u884c\n\u5747\u662f\u9ad8\u98ce\u9669\u5de5\u5177\uff0c\u4f1a\u7ecf\u8fc7 PI-Desktop \u7684\u5de5\u5177\u6743\u9650\u7b56\u7565\u3002AI \u4e0d\u5e94\u8981\u6c42\u7528\u6237\u628a\u5bc6\u7801\u3001\u79c1\u94a5\n\u6216 token \u7c98\u8d34\u5230\u5bf9\u8bdd\u4e2d\uff1b\u65b0\u4e3b\u673a\u5bc6\u94a5\u548c\u7834\u574f\u6027\u547d\u4ee4\u5fc5\u987b\u5148\u5411\u7528\u6237\u786e\u8ba4\u3002\u82e5\u547d\u4ee4\u88ab\u5b89\u5168\u8fc7\u6ee4\u5668\n\u62e6\u622a\uff0cAI \u53ea\u80fd\u63d0\u793a\u7528\u6237\u5728 SSH \u7ba1\u7406\u9762\u677f\u4e2d\u5ba1\u6838\u5e76\u52fe\u9009\u4e00\u6b21\u6027\u6388\u6743\uff0c\u4e0d\u80fd\u81ea\u884c\u7ed5\u8fc7\u8fc7\u6ee4\u5668\u3002\n\n## \u6743\u9650\n\n- `ui.panel`\uff1a\u6253\u5f00 SSH \u7ba1\u7406\u9762\u677f\u3002\n- `agent.tool.register`\uff1a\u6ce8\u518c AI SSH \u5de5\u5177\u3002\n- `agent.prompt.inject`\uff1a\u52a0\u8f7d\u5b89\u5168 SSH \u4f7f\u7528\u8bf4\u660e\u3002\n\n\u63d2\u4ef6\u53ea\u4f7f\u7528\u672c\u673a `ssh` \u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4e0d\u4f7f\u7528 `net.fetch`\uff0c\u4e5f\u4e0d\u628a\u51ed\u636e\u5199\u5165\u63d2\u4ef6\u8bbe\u7f6e\u3002\n\n## \u5f00\u53d1\u9a8c\u8bc1\n\n```bash\nnode --test tests/ssh-manager.test.mjs\npython3 scripts/pack_plugin.py plugins/pi.ssh-manager\npython3 scripts/rebuild_catalog.py\n```\n\n\u672c\u5730\u8fd0\u884c\u65f6\u8bf7\u5728 PI-Desktop \u4e2d\u9009\u62e9\u300c\u63d2\u4ef6 \u2192 \u52a0\u8f7d\u5f00\u53d1\u63d2\u4ef6\u300d\uff0c\u518d\u9009\u62e9\u672c\u76ee\u5f55\u3002\n", "safetyNotes": "SSH credentials are never persisted by this plugin. Passwords entered in the panel are held in memory for at most 30 minutes and private-key contents stay outside the plugin. Authentication is delegated to the local OpenSSH client. The panel stores only connection metadata in plugin settings; AI tools can connect to configured hosts and execute remote shell commands, so PI-Desktop's high-risk tool policy must remain enabled.", "versions": [ { - "version": "0.1.5", - "publishedAt": "2026-09-13T07:10:40Z", - "changelog": "Release 0.1.5: restores ProgramData in PI-Desktop's minimal Windows plugin environment so OpenSSH no longer exits 255 silently before connecting; adds a real OpenSSH startup regression test. Release 0.1.4: closes the askpass broker lifecycle boundary so an unload cannot start a new SSH child after the broker has been cleaned up. Release 0.1.3: keeps OpenSSH transport diagnostics visible on Windows instead of suppressing banner-exchange errors behind exit 255, preserves non-default config files for imported aliases without bypassing system config for the default file, detaches an alias when its explicit connection fields are edited, prevents one-shot commands from inheriting plugin stdin, passes special-character passwords through a one-shot local askpass broker without placing them in the ssh process environment, and preserves missing-client diagnostics through the panel bridge. Release 0.1.2: imports concrete hosts from the local OpenSSH config, preserves aliases for complete SSH behavior, adds identity-file selection, surfaces OpenSSH diagnostics instead of a bare exit 255, inherits Windows system environment so ssh.exe can run, and stops leftover ssh processes from throwing on quit. Release 0.1.1: strengthens destructive-command filtering and makes one-time dangerous-command approval available only from the SSH Manager panel. Release 0.1.0: adds local SSH host profiles, strict host-key verification, OpenSSH key/agent and transient password authentication, bounded remote command execution, a focused management panel, and an AI skill describing safe SSH workflows.", + "version": "0.1.2", + "publishedAt": "2026-09-11T18:47:58Z", + "changelog": "Release 0.1.2: imports concrete hosts from the local OpenSSH config, preserves aliases for complete SSH behavior, adds identity-file selection, surfaces OpenSSH diagnostics instead of a bare exit 255, inherits Windows system environment so ssh.exe can run, and stops leftover ssh processes from throwing on quit. Release 0.1.1: strengthens destructive-command filtering and makes one-time dangerous-command approval available only from the SSH Manager panel. Release 0.1.0: adds local SSH host profiles, strict host-key verification, OpenSSH key/agent and transient password authentication, bounded remote command execution, a focused management panel, and an AI skill describing safe SSH workflows.", "minPiDesktop": ">=0.2.9", - "shasum": "02dfeca1840ea9d8a572bc01a1913800bed68ee97b36a5a92ecd7f9fe9817067", - "url": "packages/pi.ssh-manager-0.1.5.piplug", - "sizeBytes": 146730, + "shasum": "6064c87b78b0b00aea4d28cdeb6ea4370cdd960396caf1884bb7af3f958c792d", + "url": "packages/pi.ssh-manager-0.1.2.piplug", + "sizeBytes": 134376, "permissions": [ "ui.panel", "agent.tool.register", @@ -822,7 +707,7 @@ "versions": [ { "version": "0.4.5", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "v0.4.5\uff1a\u4fee\u590d\u9762\u677f\u6eda\u52a8\u5bb9\u5668\u56fa\u5b9a\u5bbd\u5ea6\u5bfc\u81f4\u7684\u53f3\u4fa7\u5927\u9762\u79ef\u7a7a\u767d\uff0c\u6b63\u6587\u6eda\u52a8\u533a\u57df\u73b0\u5728\u968f\u7a97\u53e3\u5168\u5bbd\u4f38\u5c55\u3002v0.4.4\uff1a\u5bf9\u9f50 Markdown \u9762\u677f\u7684 v3 \u9876\u90e8\u5904\u7406\uff0c\u63d0\u524d\u7ed8\u5236 body/root \u80cc\u666f\u5e76\u540c\u6b65\u4e3b\u9898\u53d8\u5316\u5230\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\uff0c\u6d88\u9664\u9876\u90e8\u8272\u5e26\u7a7a\u9699\u548c\u80f6\u56ca\u914d\u8272\u4e0d\u5339\u914d\u3002v0.4.3\uff1a\u4fee\u590d v3 \u5168\u51fa\u8840\u5e03\u5c40\uff0c\u4fa7\u680f\u4e0e\u4e3b\u5185\u5bb9\u586b\u6ee1\u89c6\u53e3\uff0c\u5e76\u4e3a\u81ea\u5b9a\u4e49\u5bfc\u822a\u63a7\u4ef6\u8865\u9f50 no-drag \u6807\u8bb0\uff0c\u907f\u514d\u9876\u90e8\u62d6\u62fd\u5e26\u8986\u76d6\u9875\u9762\u4ea4\u4e92\u3002v0.4.2\uff1a\u8fc1\u79fb\u5230 v3 \u7a7f\u900f\u5f0f\u9876\u90e8 chrome\uff0c\u9876\u90e8\u63a7\u4ef6\u4fdd\u6301\u53ef\u70b9\u51fb\uff0c\u7a7a\u767d\u533a\u57df\u7ee7\u7eed\u53ef\u62d6\u62fd\u3002v0.4.1\uff1a\u9002\u914d PI-Desktop \u8de8\u5e73\u53f0 46px \u4e3b\u673a\u62d6\u62fd\u5e26\u548c\u7b80\u7ea6\u4e09\u6309\u94ae\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u3002v0.4.0\uff1a\u5916\u89c2\u8ddf\u968f app \u4e3b\u4f53\u2014\u2014\u9884\u7ed8\u6309\u300c\u5916\u89c2\u7f13\u5b58 \u2192 \u81ea\u5e26 sdm.settings.theme \u2192 \u7cfb\u7edf\u300d\u6062\u590d\u4e3b\u9898\u5e76\u540c\u6b65 data-lang/lang\uff0c\u8fd0\u884c\u65f6\u8ba2\u9605\u5bbf\u4e3b theme/locale \u5b9e\u65f6\u66f4\u65b0\uff08\u65e0\u95ea\u5c4f\uff09\uff1b\u9762\u677f\u5185\u624b\u52a8\u5207\u6362\u4e3b\u9898\u4ecd\u53ef\u7528\u3002v0.3.1\uff1a\u58f0\u660e manifest.net.domains \u7f51\u7edc\u767d\u540d\u5355\uff08\u4e91\u5382\u5546 API\u3001crt.sh\u3001\u901a\u77e5 Webhook\u3001ACME CA\uff09\uff0c\u4fee\u590d\u65b0\u7248\u5bbf\u4e3b egress \u7b56\u7565\u4e0b\u6240\u6709\u7f51\u7edc\u8bf7\u6c42\u88ab\u62d2\uff08plugin declares no manifest.net.domains; api.cloudflare.com is unreachable\uff09\u7684\u95ee\u9898\u3002v0.2.0\uff1a\u91cd\u6784\u4e3a\u5e72\u51c0\u5229\u843d\u7684\u76f4\u89d2\u98ce\u683c\uff08\u9ed1\u767d\u7070 + \u6a59\u8272\u5f3a\u8c03\u3001\u65e0\u5706\u89d2\u65e0\u6295\u5f71\u30011px \u7ec6\u7ebf\u5206\u9694\uff09\uff1b\u9ed8\u8ba4\u8ddf\u968f\u7cfb\u7edf\u6df1\u6d45\u6a21\u5f0f\uff0c\u4fa7\u8fb9\u680f\u53ef\u4e00\u952e\u5207\u6362\uff1b\u8fdb\u5165\u89e3\u6790\u8bb0\u5f55\u81ea\u52a8\u62c9\u53d6\u6570\u636e\uff1b\u5b50\u9875\u9762\u5bfc\u822a\u4fdd\u6301\u7236\u83dc\u5355\u9009\u4e2d\u6001\u3002", "minPiDesktop": ">=0.1.0", "shasum": "90142ee272408b952731aa00a7c5d37d1c37afd21e46113197872741c20f9f33", @@ -871,7 +756,7 @@ "versions": [ { "version": "0.1.6", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.1.6: on Windows, attach PowerShell to ConPTY inside the work panel instead of opening a separate console window. Release 0.1.5: follow the app color mode only \u2014 never snap to the OS palette, which flashed when the two disagreed. Release 0.1.4: follows the app light/dark mode live in the work-panel view, including the xterm canvas. Release 0.1.3: isolates PTY tabs per open project so switching workspaces cannot mix sessions. Release 0.1.2: docks only in the right work panel; the detached window is removed. Release 0.1.1: login-shell environment so GUI-launched sessions inherit PATH (pnpm, nvm, Homebrew, cargo, bun); denser Otty-like chrome with bottom tabs, find, and font-size controls. Release 0.1.0: first release. Multi-tab PTY sessions, cross-platform default shells (zsh / bash / PowerShell / optional Git Bash), theme and language following, and copy/paste.", "minPiDesktop": ">=0.8.0", "shasum": "e915e96f6895a3f3881314e29099ae3c59236e8e93e6f805f4ba6d3f14919c22", @@ -918,7 +803,7 @@ "versions": [ { "version": "0.6.5", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.6.5\uff1a\u5230\u671f\u63d0\u9192\u8fc1\u79fb\u5230\u5bbf\u4e3b\u6258\u7ba1\u540e\u53f0\u670d\u52a1\uff08contributes.services due-reminder + background.service \u6743\u9650\uff09\u2014\u2014\u9762\u677f\u5173\u95ed\u65f6\u63d2\u4ef6\u8fdb\u7a0b\u5e38\u9a7b\u8c03\u5ea6\uff0c\u5230\u671f\u4efb\u52a1\u7ecf\u539f\u751f\u7cfb\u7edf\u901a\u77e5\u63d0\u9192\uff08\u5bbf\u4e3b ADR 0074\uff0c\u65e0\u7a97\u53e3\u72b6\u6001\u9650\u5236\uff09\uff1b\u4e3b\u8fdb\u7a0b\u4e0e\u6e32\u67d3\u7aef\u5171\u7528 reminded \u5b57\u6bb5\u53bb\u91cd\uff0c\u4e0d\u91cd\u590d\u901a\u77e5\u3002Release 0.6.4\uff1av3 \u5934\u90e8\u5bf9\u9f50\u2014\u2014\u9996\u884c\u5934\u90e8\u8ba9\u51fa\u53f3\u4e0a\u89d2\u5bbf\u4e3b\u7a97\u53e3\u63a7\u5236\u80f6\u56ca 104px \u533a\u57df\uff0c\u65b0\u589e capsule-retint.js \u6309\u9762\u677f\u5b9e\u9645\u8c03\u8272\u677f\u5b9e\u65f6\u91cd\u7740\u8272\u80f6\u56ca\uff08\u4efb\u4f55\u6765\u6e90\u7684\u4e3b\u9898\u5207\u6362\u5747\u7acb\u5373\u751f\u6548\uff09\u3002Release 0.6.3\uff1a\u6e90\u7801\u4ed3\u5e93\u5bf9\u9f50\u5e02\u573a 0.6.2 \u57fa\u7ebf\uff08v3 \u7a7f\u900f\u5f0f\u9876\u90e8 chrome + panel-polish.css + i18n manifest \u53cc\u8bed\u5757\uff09\u3002Release 0.6.2\uff1a\u8fc1\u79fb\u5230 v3 \u7a7f\u900f\u5f0f\u9876\u90e8 chrome\uff0c\u9876\u90e8\u63a7\u4ef6\u4fdd\u6301\u53ef\u70b9\u51fb\uff0c\u7a7a\u767d\u533a\u57df\u7ee7\u7eed\u53ef\u62d6\u62fd\u3002Release 0.6.1\uff1a\u9002\u914d PI-Desktop \u8de8\u5e73\u53f0 46px \u4e3b\u673a\u62d6\u62fd\u5e26\u548c\u7b80\u7ea6\u4e09\u6309\u94ae\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u3002Release 0.6.0\uff1a\u9762\u677f\u8ddf\u968f app \u4e3b\u4f53\u7684\u8bed\u8a00\u4e0e\u989c\u8272\u6a21\u5f0f\u2014\u2014\u65b0\u589e\u6df1\u8272\u914d\u8272\uff08\u4fdd\u7559\u539f\u6d45\u8272\u89c2\u611f\uff09\uff0c\u5bbf\u4e3b\u5207\u6362\u4eae/\u6697\u65f6\u5b9e\u65f6\u6362\u80a4\uff1b\u53ef\u89c1\u6587\u6848\uff08\u6807\u9898/\u5360\u4f4d\u7b26/\u7b5b\u9009/\u8c61\u9650/\u6309\u94ae/\u7a7a\u6001/\u5230\u671f\u63d0\u793a/\u63d0\u9192\u7b49\uff09\u62bd\u6210\u4e2d\u82f1\u53cc\u8bed\u8868\uff0c\u6309 app \u8bed\u8a00\u5b9e\u65f6\u5207\u6362\uff1b\u65e7\u7248\u5bbf\u4e3b\u81ea\u52a8\u964d\u7ea7\uff08\u8ddf\u968f\u7cfb\u7edf\u504f\u597d + \u4e2d\u6587\u754c\u9762\uff09\u3002Release 0.1.0\uff1a\u9996\u4e2a\u7248\u672c\uff0c\u7b80\u5355\u5217\u8868\u5f85\u529e\u3002Release 0.2.0\uff1a\u65b0\u589e\u56db\u8c61\u9650\u77e9\u9635\u5e03\u5c40\uff08\u62d6\u62fd\u79fb\u52a8\u8c61\u9650\uff09\u3001\u53cc\u5e03\u5c40\u5207\u6362\u5e76\u8bb0\u4f4f\u3001\u7a97\u53e3 1000\u00d7700\u3002Release 0.3.0\uff1a\u4efb\u52a1\u53ef\u8bbe\u7f6e\u5230\u671f\u65f6\u95f4\u3001\u5230\u671f\u63d0\u9192\uff08\u4f4e\u5360\u7528\u5355\u5b9a\u65f6\u5668\u8c03\u5ea6\uff09\u3002Release 0.3.1\uff1a\u5230\u671f\u63d0\u9192\u5347\u7ea7\u4e3a\u539f\u751f\u7cfb\u7edf\u901a\u77e5\uff08ui.showNativeNotification\uff0c\u5bbf\u4e3b ADR 0074\uff09\u3002Release 0.4.0\uff1a\u63d2\u4ef6 id \u5b9a\u7a3f\u4e3a pi.todo\uff08\u5b98\u65b9 pi. \u524d\u7f00\uff09\u3002Release 0.5.0\uff1a\u6ce8\u518c agent \u5de5\u5177 todo_manage\uff08AI \u53ef\u7ba1\u7406\u5f85\u529e\uff1a\u67e5\u8be2/\u6dfb\u52a0/\u5927\u6bb5\u62c6\u5206/\u6a21\u7cca\u5b8c\u6210/\u5ef6\u671f/\u6e05\u7a7a\u8fc7\u671f/\u5220\u9664\uff09\uff1b\u6570\u636e\u8fc1\u79fb\u81f3\u63d2\u4ef6\u6570\u636e\u76ee\u5f55 settings.json\uff0c\u9762\u677f\u4e0e AI \u5171\u4eab\u540c\u4e00\u4efd\u6570\u636e\uff0c\u53cc\u5411\u540c\u6b65\u3002Release 0.5.1\uff1a\u8865\u4e01\u53d1\u5e03\uff0c\u65e0\u529f\u80fd\u53d8\u66f4\uff08\u540c\u6b65\u6e90\u7801\u4ed3\u5e93\u4e0e\u5e02\u573a\u7248\u672c\u53f7\uff09\u3002", "minPiDesktop": ">=0.1.0", "shasum": "25bda064f4d3daa8fbadc6dfc31c9d8b59664335756cf091d257791f0235b625", @@ -965,7 +850,7 @@ "versions": [ { "version": "0.4.8", - "publishedAt": "2026-09-12T17:13:25Z", + "publishedAt": "2026-09-11T18:47:58Z", "changelog": "Release 0.4.8: Fold PI-Desktop completed-turn totals from the host database into the dashboard, so subagent spend that never lands on parent message.usage still appears without double-counting transcript rows. Settings no longer has a Usage page; this panel is the heatmap. Release 0.4.8\uff1a\u628a\u5bbf\u4e3b\u5df2\u5b8c\u6210\u56de\u5408\u7684 token \u5408\u8ba1\u6298\u5165\u4eea\u8868\u76d8\uff0c\u8f6c\u5f55\u672c message.usage \u672a\u8ba1\u5165\u7684\u5b50\u667a\u80fd\u4f53\u7528\u91cf\u4f1a\u8865\u4e0a\u4e14\u4e0d\u4e0e JSONL \u91cd\u590d\u3002\u8bbe\u7f6e\u9875\u4e0d\u518d\u6709\u7528\u91cf\u5165\u53e3\uff0c\u70ed\u529b\u56fe\u4ee5\u672c\u9762\u677f\u4e3a\u51c6\u3002 Release 0.4.7: Fix the extra empty right-side rail on Windows by keeping the stable scrollbar gutter on the dashboard scroller instead of reserving it again on the root viewport. Release 0.4.7\uff1a\u4fee\u590d Windows \u53f3\u4fa7\u591a\u51fa\u7a7a\u767d\u4fa7\u680f\u7684\u95ee\u9898\uff1a\u4ec5\u5728\u4eea\u8868\u76d8\u6eda\u52a8\u5bb9\u5668\u4fdd\u7559\u7a33\u5b9a\u6eda\u52a8\u6761\u69fd\u4f4d\uff0c\u4e0d\u518d\u5728\u6839\u89c6\u53e3\u91cd\u590d\u9884\u7559\u3002 Release 0.4.6: Fix the titlebar's appearance and refresh buttons overlapping the host window-control capsule. The panel paints through the 46px band under v3 chrome, but the capsule still floats over the top-right corner, so both buttons sat under it and stopped being clickable. The titlebar now reserves the capsule's 104px corner (kept at narrow widths too, where the gutter override previously reset it), the appearance menu stays anchored to the buttons that open it, and a long title truncates instead of running under the reserve. Release 0.4.6\uff1a\u4fee\u590d\u6807\u9898\u680f\u7684\u5916\u89c2\u4e0e\u5237\u65b0\u6309\u94ae\u4e0e\u5bbf\u4e3b\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u91cd\u53e0\u7684\u95ee\u9898\u3002v3 chrome \u4e0b\u9762\u677f\u53ef\u7ed8\u5236\u5230 46px \u9876\u680f\uff0c\u4f46\u80f6\u56ca\u4ecd\u6d6e\u4e8e\u53f3\u4e0a\u89d2\uff0c\u5bfc\u81f4\u4e24\u4e2a\u6309\u94ae\u88ab\u906e\u6321\u4e14\u65e0\u6cd5\u70b9\u51fb\u3002\u6807\u9898\u680f\u73b0\u4e3a\u80f6\u56ca\u4fdd\u7559 104px \u53f3\u4fa7\u7a7a\u95f4\uff08\u7a84\u5bbd\u5ea6\u4e0b\u7684 gutter \u8986\u76d6\u6b64\u524d\u4f1a\u91cd\u7f6e\u8be5\u4fdd\u7559\u503c\uff0c\u73b0\u5df2\u4fdd\u7559\uff09\uff0c\u5916\u89c2\u83dc\u5355\u7ee7\u7eed\u5bf9\u9f50\u89e6\u53d1\u6309\u94ae\uff0c\u8fc7\u957f\u6807\u9898\u4ee5\u7701\u7565\u53f7\u622a\u65ad\u3002 Release 0.4.5: Migrates the panel to v3 paint-through chrome so top-band controls remain clickable while blank space remains draggable. Release 0.4.4: Fix the window-control capsule being drawn with default black-on-white colors on a panel's very first open \u2014 with no cached appearance, data-theme stayed unset until the host answered, so the host's one-shot color snapshot at DOMContentLoaded missed; boot now falls back to the OS palette synchronously while content stays cloaked. Also stop startAppearanceWatch from resetting the appearance fingerprint, which made every open-command run rewrite hostAppearance. Release 0.4.4\uff1a\u4fee\u590d\u9996\u6b21\u6253\u5f00\u9762\u677f\u65f6\u7a97\u53e3\u63a7\u5236\u80f6\u56ca\u914d\u8272\u9519\u8bef\u7684\u95ee\u9898\u2014\u2014\u65e0\u7f13\u5b58\u5916\u89c2\u65f6 data-theme \u672a\u8bbe\u7f6e\uff0c\u5bbf\u4e3b\u5728 DOMContentLoaded \u7684\u53d6\u8272\u5feb\u7167\u62ff\u5230\u6d4f\u89c8\u5668\u9ed8\u8ba4\u9ed1/\u767d\uff0c\u73b0\u540c\u6b65\u56de\u9000 OS \u914d\u8272\uff08\u5185\u5bb9\u4ecd\u6309 data-booting \u9690\u85cf\u81f3\u771f\u5b9e\u5916\u89c2\u5230\u8fbe\uff09\uff1b\u4fee\u590d startAppearanceWatch \u91cd\u7f6e\u5916\u89c2\u6307\u7eb9\u5bfc\u81f4\u6bcf\u6b21\u6253\u5f00\u547d\u4ee4\u90fd\u91cd\u590d\u5199\u5165 hostAppearance \u7684\u95ee\u9898\u3002 Release 0.4.3: Align the panel with PI-Desktop's cross-platform 46px host drag band and minimal three-button window-control capsule. Fixes two visible faults: elements toggled with the hidden attribute were being kept on screen by their own CSS display, so the loading skeleton stayed over real data, an empty chip strip and the custom date inputs were always drawn, and the last scan sentence lingered; and the from/to fields now always show the window the selected range covers, so picking 7D/90D/ALL keeps them in step and switching to Custom inherits what you were looking at. Includes 0.4.1's scan progress with a real file count, stale-scan recovery, visibility-based polling and debounced source watching, on top of 0.4.0's theme/language following, filters and streak layer.", "minPiDesktop": ">=0.2.9", "shasum": "220506deb22c680074fb65856ad0b769435246a7a850184e8226f602bc9eb427", @@ -981,18 +866,18 @@ }, { "id": "pi.workspace-file-guard", - "name": "Workspace File Guard", - "description": "Keep test, temp, scratch, log and cache files inside the current workspace or PI scratch. Works on any machine: Windows, macOS, Linux, any drive letter, any username.", + "name": "C盘防垃圾", + "description": "防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 Temp 或 scratch。", "i18n": { "en": { - "name": "Workspace File Guard", - "description": "Keep test, temp, scratch, log and cache files inside the current workspace or PI scratch. Never spill onto the system volume, Desktop, Downloads, Documents or system temp.", - "safetyNotes": "Behavioral confinement only. The plugin reads the local XDG user-dirs configuration to classify paths, injects agent rules, and does not write files or access the network." + "name": "Keep junk off C:", + "description": "Keep test, log, cache, and temp files out of the system drive, Desktop, and Downloads. Junk stays in the current project's Temp or scratch.", + "safetyNotes": "Behavioral confinement, not a disk lock. The plugin only classifies paths and injects agent rules. It does not change ACLs or use the network." }, "zh-CN": { - "name": "\u5de5\u4f5c\u533a\u6587\u4ef6\u62a4\u680f", - "description": "\u628a\u6d4b\u8bd5\u3001\u4e34\u65f6\u3001\u8349\u7a3f\u3001\u65e5\u5fd7\u3001\u7f13\u5b58\u7b49\u5783\u573e\u6587\u4ef6\u5173\u5728\u5f53\u524d\u5de5\u4f5c\u533a\u6216 PI scratch \u91cc\u3002\u4efb\u610f\u673a\u5668\u3001\u4efb\u610f\u76d8\u7b26\u3001\u4efb\u610f\u7528\u6237\u540d\u90fd\u53ef\u7528\uff0c\u4e0d\u5199\u6b7b C: \u6216\u672c\u673a\u8def\u5f84\u3002", - "safetyNotes": "\u8fd9\u662f\u884c\u4e3a\u7ea6\u675f\uff0c\u4e0d\u662f\u78c1\u76d8\u9501\u3002\u63d2\u4ef6\u4f1a\u8bfb\u53d6\u672c\u673a XDG \u7528\u6237\u76ee\u5f55\u914d\u7f6e\u6765\u5206\u7c7b\u8def\u5f84\uff0c\u6ce8\u5165 Agent \u89c4\u5219\uff0c\u4e0d\u5199\u5165\u6587\u4ef6\u3001\u4e0d\u6539 ACL\u3001\u4e0d\u8054\u7f51\u3002" + "name": "C盘防垃圾", + "description": "防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 Temp 或 scratch。", + "safetyNotes": "这是行为约束,不是磁盘锁。插件只分类路径并注入 Agent 规则,不改 ACL、不联网。" } }, "author": "xingleiwu", @@ -1003,17 +888,17 @@ "downloads": 0, "homepage": "https://github.com/vastsa/pi-desktop-plugins/tree/main/plugins/pi.workspace-file-guard", "repository": "https://github.com/vastsa/pi-desktop-plugins", - "readmeMarkdown": "# \u5de5\u4f5c\u533a\u6587\u4ef6\u62a4\u680f\n\n\u628a\u6d4b\u8bd5\u3001\u4e34\u65f6\u3001\u8349\u7a3f\u3001\u65e5\u5fd7\u3001\u7f13\u5b58\u7b49\u5783\u573e\u6587\u4ef6\u5173\u5728\u5f53\u524d\u5de5\u4f5c\u533a\u6216 PI scratch \u91cc\u3002\u8fd9\u662f\u884c\u4e3a\u7ea6\u675f\uff0c\u4e0d\u662f\u78c1\u76d8\u9501\u3002\n\n\u4fbf\u643a\u7684 PI-Desktop skill \u5305\uff1a\u542f\u7528\u4e00\u6b21\u540e\uff0c\u6bcf\u4e2a\u4f1a\u8bdd\u90fd\u4f1a\u6ce8\u5165\u89c4\u5219\u5e76\u6ce8\u518c\u5206\u7c7b\u5de5\u5177\u3002\u8def\u5f84\u6309\u5f53\u524d\u64cd\u4f5c\u7cfb\u7edf\u3001\u7528\u6237\u4e3b\u76ee\u5f55\u3001\u5de5\u4f5c\u533a\u548c\u73af\u5883\u53d8\u91cf\u89e3\u6790\uff0c\u4e0d\u5199\u6b7b `C:`\u3001\u7528\u6237\u540d\u6216\u67d0\u53f0\u673a\u5668\u7684\u76ee\u5f55\u3002\n\n## \u63d0\u4f9b\u4ec0\u4e48\n\n- Skill\uff1a`skills/workspace-file-guard.md`\uff08\u63d2\u4ef6\u542f\u7528\u671f\u95f4\u6ce8\u5165 Agent\uff09\n- \u5de5\u5177\uff1a`project_root` / `check_path` / `temp_env` / `tmp_layout`\n- \u62d2\u7edd\u6e05\u5355\uff1a`references/denied-paths.md`\n- \u5206\u7c7b\u5668\uff1a`guard.js`\n\n## \u6587\u4ef6\u8be5\u5199\u5230\u54ea\n\n| \u7c7b\u578b | \u4f4d\u7f6e |\n| --- | --- |\n| \u7528\u6237\u8981\u6c42\u4fdd\u7559\u7684\u6e90\u7801 | \u5de5\u4f5c\u533a\uff08`src/`\u3001`tests/` \u7b49\uff09 |\n| \u4e00\u6b21\u6027\u8349\u7a3f\u3001\u8f6c\u50a8\u3001\u65e5\u5fd7 | `$PI_SCRATCH_DIR` |\n| \u9879\u76ee\u672c\u5730\u7f13\u5b58 | `$project/.tmp/cache` |\n\n\u7981\u6b62\uff1a\u684c\u9762\u3001\u4e0b\u8f7d\u3001\u6587\u6863\u3001\u7cfb\u7edf\u4e34\u65f6\u76ee\u5f55\uff1b\u9879\u76ee\u5728\u5176\u4ed6\u76d8\u65f6\u7981\u6b62\u5199\u5230\u7cfb\u7edf\u76d8\uff1bProgram Files\u3001`/usr`\u3001`/Applications`\u3002\n\n## \u6743\u9650\n\n| \u6743\u9650 | \u7528\u9014 |\n| --- | --- |\n| `agent.prompt.inject` | \u6ce8\u5165\u62a4\u680f\u89c4\u5219\uff0c\u8ba9 Agent \u9ed8\u8ba4\u628a\u5783\u573e\u6587\u4ef6\u5173\u5728\u5de5\u4f5c\u533a / scratch |\n| `agent.tool.register` | \u6ce8\u518c\u8def\u5f84\u5206\u7c7b\u5de5\u5177\uff0c\u4f9b Agent \u5728\u5199\u6587\u4ef6\u524d\u67e5\u8be2 |\n\n\u4e0d\u7533\u8bf7 `fs.*` \u5bbf\u4e3b\u6587\u4ef6\u7cfb\u7edf\u6743\u9650\u3001\u7f51\u7edc\u3001\u526a\u8d34\u677f\u6216\u540e\u53f0\u670d\u52a1\u6743\u9650\u3002\u4e3a\u8bc6\u522b Linux/XDG \u81ea\u5b9a\u4e49\u7528\u6237\u76ee\u5f55\uff0c\u5206\u7c7b\u5668\u4f1a\u53ea\u8bfb\u672c\u673a `~/.config/user-dirs.dirs`\uff08\u82e5\u5b58\u5728\uff09\uff0c\u4e0d\u4f1a\u4e0a\u4f20\u6216\u8fd4\u56de\u8be5\u6587\u4ef6\u539f\u6587\u3002\u63d2\u4ef6\u672c\u8eab\u4e0d\u5199\u76d8\u3001\u4e0d\u6539 ACL\u3001\u4e0d\u8054\u7f51\uff1b\u771f\u6b63\u843d\u76d8\u7684\u4ecd\u662f Agent \u81ea\u5df1\u7684 Write / Bash\u3002\n\n## \u5b89\u88c5\n\n1. PI-Desktop \u2192 \u6269\u5c55 \u2192 \u5b89\u88c5\u63d2\u4ef6\u5305\uff0c\u9009\u62e9 `packages/pi.workspace-file-guard-0.2.5.piplug`\u3002\n2. \u82e5\u51fa\u73b0\u6743\u9650\u786e\u8ba4\uff0c\u52fe\u9009 `agent.prompt.inject` \u4e0e `agent.tool.register`\uff08\u5f53\u524d\u5bbf\u4e3b\u5bf9\u672c\u5730 `.piplug` \u53ef\u80fd\u6309\u6e05\u5355\u9759\u9ed8\u5168\u6388\uff09\u3002\n3. \u65b0\u5f00\u4e00\u4e2a Agent \u4f1a\u8bdd\uff0cskill \u624d\u4f1a\u6ce8\u5165\u3002\n\n\u4e5f\u53ef\u628a\u672c\u76ee\u5f55\u5f53\u4f5c\u5f00\u53d1\u63d2\u4ef6\u52a0\u8f7d\uff08\u4fdd\u5b58\u540e\u70ed\u91cd\u8f7d\uff09\u3002\u5f00\u53d1\u63d2\u4ef6\u6269\u6743\u540e\u8bf7\u91cd\u65b0\u300c\u52a0\u8f7d\u5f00\u53d1\u63d2\u4ef6\u300d\uff0c\u4e0d\u8981\u53ea\u70b9\u300c\u91cd\u65b0\u52a0\u8f7d\u300d\u3002\n\n## \u5f00\u53d1\u9a8c\u8bc1\n\n```bash\nnode tests/workspace-file-guard-guard.test.js\nnode tests/workspace-file-guard-main.test.js\npython scripts/pack_plugin.py plugins/pi.workspace-file-guard\npython scripts/rebuild_catalog.py\npython scripts/security_audit.py --check-packages\n```\n\n## \u80fd\u529b\u8fb9\u754c\n\n- \u4e0d\u662f\u4e8b\u540e\u6e05\u7406\u78c1\u76d8\u3002\n- \u4e0d\u662f\u8de8\u9879\u76ee\u8bbf\u95ee\u9694\u79bb\u3002\n- \u4e0d\u662f\u64cd\u4f5c\u7cfb\u7edf\u6c99\u7bb1\u3001BitLocker\u3001SIP \u6216\u6587\u4ef6\u5939 ACL\u3002\n- `root` \u8986\u76d6\u53ea\u5728\u7528\u6237\u660e\u786e\u9009\u62e9\u9879\u76ee\u6839\u65f6\u4f7f\u7528\uff1b\u5de5\u5177\u65e0\u6cd5\u9a8c\u8bc1\u8be5\u9009\u62e9\uff0c\u4e0d\u80fd\u628a\u5b83\u5f53\u6210\u5b89\u5168\u8fb9\u754c\u3002\n- `explicit` \u53ea\u662f\u6a21\u578b\u5bf9\u7528\u6237\u610f\u56fe\u7684\u58f0\u660e\uff1b\u684c\u9762\u3001\u4e0b\u8f7d\u3001\u6587\u6863\u548c\u7cfb\u7edf\u4e34\u65f6\u76ee\u5f55\u5373\u4f7f\u6807\u8bb0\u4e5f\u7981\u6b62\u3002\n\n## \u80fd\u529b / \u6570\u636e\u6d41\n\n| \u80fd\u529b | \u6570\u636e | \u65b9\u5411 |\n| --- | --- | --- |\n| `agent.prompt.inject` | \u672c\u63d2\u4ef6 `skills/workspace-file-guard.md` \u89c4\u5219\u6587\u672c | \u6ce8\u5165\u5f53\u524d\u4f1a\u8bdd\u7684\u7cfb\u7edf\u63d0\u793a\uff0c\u4e0d\u8bfb\u804a\u5929\u8bb0\u5f55 |\n| `agent.tool.register` | \u8c03\u7528\u53c2\u6570\u91cc\u7684\u8def\u5f84\u5b57\u7b26\u4e32\uff1b`pi.workspace.get()` \u7684\u5de5\u4f5c\u533a\u8def\u5f84\uff1b`PI_SCRATCH_DIR` / \u4e3b\u76ee\u5f55 / \u5e38\u89c1\u7cfb\u7edf\u76ee\u5f55 | \u53ea\u8fd4\u56de\u5206\u7c7b\u7ed3\u679c\u4e0e\u73af\u5883\u53d8\u91cf\u5efa\u8bae\uff0c\u4e0d\u5199\u76d8 |\n| \u6587\u4ef6\u7cfb\u7edf | \u672c\u673a `~/.config/user-dirs.dirs`\uff08\u82e5\u5b58\u5728\uff09 | \u4ec5\u7528\u4e8e\u8bc6\u522b XDG \u7528\u6237\u76ee\u5f55\uff0c\u4e0d\u4e0a\u4f20\u3001\u4e0d\u8fd4\u56de\u539f\u6587 |\n| \u7f51\u7edc / \u526a\u8d34\u677f / \u540e\u53f0\u670d\u52a1 | \u65e0 | \u4e0d\u7533\u8bf7\u3001\u4e0d\u4f7f\u7528 |\n\n\u5931\u8d25\u8def\u5f84\uff1a\u6ca1\u6709\u6253\u5f00\u5de5\u4f5c\u533a\u4e14\u672a\u4f20 `root` \u65f6\u5de5\u5177\u8fd4\u56de `ok: false`\uff0c\u4e0d\u4f1a\u56de\u9000\u5230\u63d2\u4ef6\u5b89\u88c5\u76ee\u5f55\u6216 cwd\u3002\u684c\u9762\u3001\u4e0b\u8f7d\u3001\u6587\u6863\u3001\u7cfb\u7edf\u4e34\u65f6\u76ee\u5f55\u5373\u4f7f `explicit=true` \u4e5f\u62d2\u7edd\u3002\n", - "safetyNotes": "Behavioral confinement only. The plugin reads the local XDG user-dirs configuration to classify paths, injects agent rules, and does not write files or access the network.", + "readmeMarkdown": "# C盘防垃圾\n\n防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 `Temp` 或 scratch。\n\n启用一次即可。路径按当前机器解析,不写死盘符或用户名。这是行为约束,不是磁盘锁。\n\n## 提供什么\n\n- Skill:`skills/workspace-file-guard.md`(插件启用期间注入 Agent)\n- 工具:`project_root` / `check_path` / `temp_env` / `tmp_layout`\n- 拒绝清单:`references/denied-paths.md`\n- 分类器:`guard.js`\n\n## 文件该写到哪\n\n| 类型 | 位置 |\n| --- | --- |\n| 用户要求保留的源码 | 工作区(`src/`、`tests/` 等) |\n| 一次性草稿、转储、日志 | `$PI_SCRATCH_DIR` |\n| 项目本地缓存 / 一次性测试 | `$project/Temp/` |\n\n禁止:桌面、下载、文档、系统临时目录;项目在其他盘时禁止写到系统盘;Program Files、`/usr`、`/Applications`。\n\n## 权限\n\n| 权限 | 用途 |\n| --- | --- |\n| `agent.prompt.inject` | 注入护栏规则,让 Agent 默认把垃圾文件关在工作区 / scratch |\n| `agent.tool.register` | 注册路径分类工具,供 Agent 在写文件前查询 |\n\n不申请 `fs.*` 宿主文件系统权限、网络、剪贴板或后台服务权限。为识别 Linux/XDG 自定义用户目录,分类器会只读本机 `~/.config/user-dirs.dirs`(若存在),不会上传或返回该文件原文。插件本身不写盘、不改 ACL、不联网;真正落盘的仍是 Agent 自己的 Write / Bash。\n\n## 安装\n\n1. PI-Desktop → 扩展 → 安装插件包,选择 `packages/pi.workspace-file-guard-0.2.7.piplug`。\n2. 若出现权限确认,勾选 `agent.prompt.inject` 与 `agent.tool.register`(当前宿主对本地 `.piplug` 可能按清单静默全授)。\n3. 新开一个 Agent 会话,skill 才会注入。\n\n也可把本目录当作开发插件加载(保存后热重载)。开发插件扩权后请重新「加载开发插件」,不要只点「重新加载」。\n\n## 开发验证\n\n```bash\nnode tests/workspace-file-guard-guard.test.js\nnode tests/workspace-file-guard-main.test.js\npython scripts/pack_plugin.py plugins/pi.workspace-file-guard\npython scripts/rebuild_catalog.py\npython scripts/security_audit.py --check-packages\n```\n\n## 能力边界\n\n- 不是事后清理磁盘。\n- 不是跨项目访问隔离。\n- 不是操作系统沙箱、BitLocker、SIP 或文件夹 ACL。\n- `root` 覆盖只在用户明确选择项目根时使用;工具无法验证该选择,不能把它当成安全边界。\n- `explicit` 只是模型对用户意图的声明;桌面、下载、文档和系统临时目录即使标记也禁止。\n\n## 能力 / 数据流\n\n| 能力 | 数据 | 方向 |\n| --- | --- | --- |\n| `agent.prompt.inject` | 本插件 `skills/workspace-file-guard.md` 规则文本 | 注入当前会话的系统提示,不读聊天记录 |\n| `agent.tool.register` | 调用参数里的路径字符串;`pi.workspace.get()` 的工作区路径;`PI_SCRATCH_DIR` / 主目录 / 常见系统目录 | 只返回分类结果与环境变量建议,不写盘 |\n| 文件系统 | 本机 `~/.config/user-dirs.dirs`(若存在) | 仅用于识别 XDG 用户目录,不上传、不返回原文 |\n| 网络 / 剪贴板 / 后台服务 | 无 | 不申请、不使用 |\n\n失败路径:没有打开工作区且未传 `root` 时工具返回 `ok: false`,不会回退到插件安装目录或 cwd。桌面、下载、文档、系统临时目录即使 `explicit=true` 也拒绝。\n", + "safetyNotes": "这是行为约束,不是磁盘锁。插件只分类路径并注入 Agent 规则,不改 ACL、不联网。", "versions": [ { - "version": "0.2.5", - "publishedAt": "2026-09-12T17:13:25Z", - "changelog": "0.2.5: Quote generated bash and PowerShell assignments safely, reject unsafe cmd values, enforce canonical root/scratch and symlink boundaries, include negative-path tests in CI, and sync the package. 0.2.4\uff1a\u8bf4\u660e\u6539\u4e3a\u4e2d\u6587\u30020.2.3\uff1a\u53bb\u6389 git/cwd \u4f5c\u4e3a\u9879\u76ee\u6839\u56de\u9000\uff1bcmd \u73af\u5883\u53d8\u91cf\u62d2\u7edd\u5185\u5d4c\u5f15\u53f7\uff1b\u8986\u76d6\u5de5\u4f5c\u533a API \u5931\u8d25\u4e0e explicit \u4e34\u65f6\u76ee\u5f55\u62d2\u7edd\u30020.2.2\uff1a\u76f8\u5bf9\u8def\u5f84\u76f8\u5bf9\u5de5\u4f5c\u533a\u89e3\u6790\u30020.2.1\uff1aexplicit \u76ee\u6807\u4e0e XDG_DOWNLOAD_DIR\u30020.2.0\uff1a\u8de8\u673a\u5668\u4fbf\u643a\u3002", + "version": "0.2.7", + "publishedAt": "2026-09-13T21:50:52Z", + "changelog": "0.2.7:市场名称改为「C盘防垃圾」;项目垃圾改放到 $project/Temp/;拒绝把 Temp 倾倒目录当项目根。 0.2.6:市场名称改为直白中文。 0.2.5: Quote generated bash and PowerShell assignments safely, reject unsafe cmd values, enforce canonical root/scratch and symlink boundaries, include negative-path tests in CI, and sync the package. 0.2.4:说明改为中文。0.2.3:去掉 git/cwd 作为项目根回退;cmd 环境变量拒绝内嵌引号;覆盖工作区 API 失败与 explicit 临时目录拒绝。0.2.2:相对路径相对工作区解析。0.2.1:explicit 目标与 XDG_DOWNLOAD_DIR。0.2.0:跨机器便携。", "minPiDesktop": ">=0.2.0", - "shasum": "3404330cda3d8fa51fb1bc8e8eefb97c0b3e589b58c2163901a9985ea0b040de", - "url": "packages/pi.workspace-file-guard-0.2.5.piplug", - "sizeBytes": 38271, + "shasum": "f4fb247dfd66ed63286a774bacbf77cfb42f231fe3ebf380b075534b0bb224d0", + "url": "packages/pi.workspace-file-guard-0.2.7.piplug", + "sizeBytes": 42134, "permissions": [ "agent.prompt.inject", "agent.tool.register" diff --git a/packages/pi.workspace-file-guard-0.2.7.piplug b/packages/pi.workspace-file-guard-0.2.7.piplug new file mode 100644 index 0000000000000000000000000000000000000000..7510f34899a94686b5d22f7698010611cf965d0d GIT binary patch literal 42134 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 literal 0 HcmV?d00001 diff --git a/plugins/pi.workspace-file-guard/README.md b/plugins/pi.workspace-file-guard/README.md index 88059ed..0dde73c 100644 --- a/plugins/pi.workspace-file-guard/README.md +++ b/plugins/pi.workspace-file-guard/README.md @@ -1,8 +1,8 @@ -# 工作区文件护栏 +# C盘防垃圾 -把测试、临时、草稿、日志、缓存等垃圾文件关在当前工作区或 PI scratch 里。这是行为约束,不是磁盘锁。 +防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 `Temp` 或 scratch。 -便携的 PI-Desktop skill 包:启用一次后,每个会话都会注入规则并注册分类工具。路径按当前操作系统、用户主目录、工作区和环境变量解析,不写死 `C:`、用户名或某台机器的目录。 +启用一次即可。路径按当前机器解析,不写死盘符或用户名。这是行为约束,不是磁盘锁。 ## 提供什么 @@ -17,7 +17,7 @@ | --- | --- | | 用户要求保留的源码 | 工作区(`src/`、`tests/` 等) | | 一次性草稿、转储、日志 | `$PI_SCRATCH_DIR` | -| 项目本地缓存 | `$project/.tmp/cache` | +| 项目本地缓存 / 一次性测试 | `$project/Temp/` | 禁止:桌面、下载、文档、系统临时目录;项目在其他盘时禁止写到系统盘;Program Files、`/usr`、`/Applications`。 @@ -32,7 +32,7 @@ ## 安装 -1. PI-Desktop → 扩展 → 安装插件包,选择 `packages/pi.workspace-file-guard-0.2.5.piplug`。 +1. PI-Desktop → 扩展 → 安装插件包,选择 `packages/pi.workspace-file-guard-0.2.7.piplug`。 2. 若出现权限确认,勾选 `agent.prompt.inject` 与 `agent.tool.register`(当前宿主对本地 `.piplug` 可能按清单静默全授)。 3. 新开一个 Agent 会话,skill 才会注入。 diff --git a/plugins/pi.workspace-file-guard/guard.js b/plugins/pi.workspace-file-guard/guard.js index 53afe07..e022a9d 100644 --- a/plugins/pi.workspace-file-guard/guard.js +++ b/plugins/pi.workspace-file-guard/guard.js @@ -4,7 +4,7 @@ const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); -const TMP_DIRNAME = ".tmp"; +const TMP_DIRNAME = "Temp"; const WIN = process.platform === "win32"; const CASE_INSENSITIVE = WIN || process.platform === "darwin"; @@ -283,28 +283,118 @@ function isFilesystemRoot(target) { return compareKey(resolved) === compareKey(path.parse(resolved).root); } +function isTempDumpName(target) { + return path.basename(resolvePath(target)).toLowerCase() === TMP_DIRNAME.toLowerCase(); +} + function isReservedRoot(target) { const resolved = resolvePath(target); - return junkRoots().some((junk) => { - const info = canonicalPath(junk); - return info.ok && compareKey(info.path) === compareKey(resolved); + if (isFilesystemRoot(resolved) || isTempDumpName(resolved)) return true; + const exact = uniquePaths([ + home(), + piHome(), + piAgentHome(), + codexHome(), + path.join(home(), ".codex"), + path.join(home(), "AppData"), + path.join(home(), "AppData", "Local"), + path.join(home(), "AppData", "Roaming"), + path.join(home(), "AppData", "LocalLow"), + process.env.LOCALAPPDATA, + process.env.APPDATA, + ]); + if (exact.some((item) => compareKey(item) === compareKey(resolved))) return true; + if ( + junkRoots().some((junk) => { + const info = canonicalPath(junk); + return info.ok && compareKey(info.path) === compareKey(resolved); + }) + ) { + return true; + } + const nested = uniquePaths([ + os.tmpdir(), + path.join(home(), "AppData", "Local", "Temp"), + process.env.TEMP, + process.env.TMP, + process.env.TMPDIR, + process.env.SystemRoot, + process.env.windir, + process.env.ProgramFiles, + process.env["ProgramFiles(x86)"], + process.env.ProgramW6432, + process.env.ProgramData, + path.join(piHome(), "logs"), + path.join(piHome(), "cache"), + path.join(codexHome(), "visualizations"), + path.join(codexHome(), "tmp"), + path.join(codexHome(), ".tmp"), + path.join(home(), ".codex", "visualizations"), + path.join(home(), ".codex", "tmp"), + path.join(home(), ".codex", ".tmp"), + ...(WIN + ? [] + : [ + "/tmp", + "/var/tmp", + "/var/cache", + "/var/log", + "/private/tmp", + "/private/var/tmp", + "/usr", + "/bin", + "/sbin", + "/etc", + "/opt", + "/System", + "/Library", + "/Applications", + ]), + ]); + return nested.some((root) => { + const info = canonicalPath(root); + if (!info.ok) return false; + return compareKey(info.path) === compareKey(resolved) || isRelativeTo(resolved, info.path); }); } +function owningProjectFromTemp(target) { + let current = resolvePath(target); + let found = null; + while (true) { + if (isTempDumpName(current)) { + const parent = path.dirname(current); + if (parent !== current && !isFilesystemRoot(parent)) { + const junkHit = junkRoots().some((junk) => { + const info = canonicalPath(junk); + return info.ok && (compareKey(info.path) === compareKey(current) || isRelativeTo(current, info.path)); + }); + if (!junkHit && !isReservedRoot(parent)) found = parent; + } + } + const next = path.dirname(current); + if (next === current) break; + current = next; + } + return found; +} + function validateProjectRoot(input) { const expanded = expandUser(input); if (!isAbsolutePath(expanded)) { return { ok: false, error: "project root must be an absolute path" }; } const resolved = resolvePath(expanded); - const info = canonicalPath(resolved); + const owner = owningProjectFromTemp(resolved); + const candidate = owner || resolved; + const info = canonicalPath(candidate); if (!info.ok || info.hadSymlink) { return { ok: false, error: "project root cannot be safely canonicalized" }; } if (isFilesystemRoot(info.path) || isReservedRoot(info.path)) { return { ok: false, error: "project root is a reserved system or junk directory" }; } - return { ok: true, projectRoot: resolved }; + return { ok: true, projectRoot: candidate }; } function safeScratchCandidate(input) { @@ -383,6 +473,7 @@ function envAssignments({ projectRoot, scratch } = {}) { TMP: ephemeral, TEMP: ephemeral, TMPDIR: ephemeral, + PYTHONDONTWRITEBYTECODE: "1", PYTHONPYCACHEPREFIX: path.join(ephemeral, "pycache"), PIP_CACHE_DIR: path.join(cache, "pip"), UV_CACHE_DIR: path.join(cache, "uv"), @@ -572,7 +663,9 @@ module.exports = { envAssignments, formatEnv, isRelativeTo, + isReservedRoot, junkRoots, + owningProjectFromTemp, resolvePath, resolveToolRoot, scratchRoot, diff --git a/plugins/pi.workspace-file-guard/main.js b/plugins/pi.workspace-file-guard/main.js index c45a92c..e1db117 100644 --- a/plugins/pi.workspace-file-guard/main.js +++ b/plugins/pi.workspace-file-guard/main.js @@ -100,84 +100,100 @@ async function toolTmpLayout(args) { scratch, layout: tmpLayout(projectRoot), hint: - "Create these folders only when needed. Put throwaway files in scratch; keep durable source in the project tree.", + "Create these folders only when needed. Put throwaway files in Temp or scratch; keep durable source in the project tree.", }); } async function onLoad() { const registered = []; try { - await pi.agent.registerTool({ - name: "project_root", - description: - "Resolve the active PI-Desktop workspace, PI scratch directory, and recommended .tmp layout. Fails if no workspace is open and root is omitted. Use before creating test/temp/scratch files.", - risk: "low", - schema: { - type: "object", - properties: { - root: { type: "string", description: "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." } + await pi.agent.registerTool({ + name: "project_root", + description: + "Resolve the active PI-Desktop workspace, PI scratch directory, and recommended Temp layout. Fails if no workspace is open and root is omitted. Use before creating test/temp/scratch files.", + risk: "low", + schema: { + type: "object", + properties: { + root: { + type: "string", + description: + "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection.", + }, + }, }, - }, - execute: (args) => toolProjectRoot(args), - }); - registered.push("project_root"); - - await pi.agent.registerTool({ - name: "check_path", - description: - "Classify whether a write path is allowed. Read allowed, not ok: ok=true only means classification succeeded. Relative paths are resolved against the workspace, not the plugin process cwd. allowed=false must be redirected into the workspace or PI scratch.", - risk: "low", - schema: { - type: "object", - properties: { - path: { type: "string", description: "Path that would be written" }, - root: { type: "string", description: "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." }, - explicit: { - type: "boolean", - description: - "Set true only when this turn's user message named this absolute destination. The tool cannot verify that; Desktop/Downloads/temp stay forbidden anyway.", + execute: (args) => toolProjectRoot(args), + }); + registered.push("project_root"); + + await pi.agent.registerTool({ + name: "check_path", + description: + "Classify whether a write path is allowed. Read allowed, not ok: ok=true only means classification succeeded. Relative paths are resolved against the workspace, not the plugin process cwd. allowed=false must be redirected into the workspace or PI scratch.", + risk: "low", + schema: { + type: "object", + properties: { + path: { type: "string", description: "Path that would be written" }, + root: { + type: "string", + description: + "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection.", + }, + explicit: { + type: "boolean", + description: + "Set true only when this turn's user message named this absolute destination. The tool cannot verify that; Desktop/Downloads/temp stay forbidden anyway.", + }, }, + required: ["path"], }, - required: ["path"], - }, - execute: (args) => toolCheckPath(args), - }); - registered.push("check_path"); - - await pi.agent.registerTool({ - name: "temp_env", - description: - "Return TMP/TEMP/cache environment assignments that keep tool junk inside the project .tmp and PI scratch. Fails if no workspace is open and root is omitted.", - risk: "low", - schema: { - type: "object", - properties: { - root: { type: "string", description: "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." }, - shell: { - type: "string", - enum: ["powershell", "cmd", "bash", "json"], - description: "Script dialect for the env assignments", + execute: (args) => toolCheckPath(args), + }); + registered.push("check_path"); + + await pi.agent.registerTool({ + name: "temp_env", + description: + "Return TMP/TEMP/cache environment assignments that keep tool junk inside the project Temp and PI scratch. Fails if no workspace is open and root is omitted.", + risk: "low", + schema: { + type: "object", + properties: { + root: { + type: "string", + description: + "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection.", + }, + shell: { + type: "string", + enum: ["powershell", "cmd", "bash", "json"], + description: "Script dialect for the env assignments", + }, }, }, - }, - execute: (args) => toolTempEnv(args), - }); - registered.push("temp_env"); - - await pi.agent.registerTool({ - name: "tmp_layout", - description: - "Return the recommended $project/.tmp/{tests,scripts,cache,out} layout without creating files. Fails if no workspace is open and root is omitted.", - risk: "low", - schema: { - type: "object", - properties: { - root: { type: "string", description: "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." } + execute: (args) => toolTempEnv(args), + }); + registered.push("temp_env"); + + await pi.agent.registerTool({ + name: "tmp_layout", + description: + "Return the recommended $project/Temp/{tests,scripts,cache,out} layout without creating files. Fails if no workspace is open and root is omitted.", + risk: "low", + schema: { + type: "object", + properties: { + root: { + type: "string", + description: + "Optional absolute project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection.", + }, + }, }, - }, - execute: (args) => toolTmpLayout(args), - }); - registered.push("tmp_layout"); + execute: (args) => toolTmpLayout(args), + }); + registered.push("tmp_layout"); } catch (error) { for (const name of registered.reverse()) { try { diff --git a/plugins/pi.workspace-file-guard/manifest.json b/plugins/pi.workspace-file-guard/manifest.json index 9af6537..efe6f93 100644 --- a/plugins/pi.workspace-file-guard/manifest.json +++ b/plugins/pi.workspace-file-guard/manifest.json @@ -1,34 +1,39 @@ { "schemaVersion": 1, "id": "pi.workspace-file-guard", - "name": "Workspace File Guard", - "version": "0.2.5", - "description": "Keep test, temp, scratch, log and cache files inside the current workspace or PI scratch. Works on any machine: Windows, macOS, Linux, any drive letter, any username.", + "name": "C盘防垃圾", + "version": "0.2.7", + "description": "防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 Temp 或 scratch。", "i18n": { "en": { - "name": "Workspace File Guard", - "description": "Keep test, temp, scratch, log and cache files inside the current workspace or PI scratch. Never spill onto the system volume, Desktop, Downloads, Documents or system temp.", - "safetyNotes": "Behavioral confinement only. The plugin reads the local XDG user-dirs configuration to classify paths, injects agent rules, and does not write files or access the network." + "name": "Keep junk off C:", + "description": "Keep test, log, cache, and temp files out of the system drive, Desktop, and Downloads. Junk stays in the current project's Temp or scratch.", + "safetyNotes": "Behavioral confinement, not a disk lock. The plugin only classifies paths and injects agent rules. It does not change ACLs or use the network." }, "zh-CN": { - "name": "工作区文件护栏", - "description": "把测试、临时、草稿、日志、缓存等垃圾文件关在当前工作区或 PI scratch 里。任意机器、任意盘符、任意用户名都可用,不写死 C: 或本机路径。", - "safetyNotes": "这是行为约束,不是磁盘锁。插件会读取本机 XDG 用户目录配置来分类路径,注入 Agent 规则,不写入文件、不改 ACL、不联网。" + "name": "C盘防垃圾", + "description": "防止模型把测试、日志、缓存、临时文件写到系统盘、桌面、下载。垃圾只待在当前项目的 Temp 或 scratch。", + "safetyNotes": "这是行为约束,不是磁盘锁。插件只分类路径并注入 Agent 规则,不改 ACL、不联网。" } }, "author": "xingleiwu", "main": "main.js", "contributes": { - "skills": ["skills/workspace-file-guard.md"], + "skills": [ + "skills/workspace-file-guard.md" + ], "agentTools": [ { "name": "project_root", - "description": "Resolve the open PI-Desktop workspace, PI scratch directory, and recommended .tmp layout. Fails if no workspace is open and root is omitted.", + "description": "Resolve the open PI-Desktop workspace, PI scratch directory, and recommended Temp layout. Fails if no workspace is open and root is omitted.", "risk": "low", "schema": { "type": "object", "properties": { - "root": { "type": "string", "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." } + "root": { + "type": "string", + "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." + } } } }, @@ -39,27 +44,43 @@ "schema": { "type": "object", "properties": { - "path": { "type": "string", "description": "Path that would be written" }, - "root": { "type": "string", "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." }, + "path": { + "type": "string", + "description": "Path that would be written" + }, + "root": { + "type": "string", + "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." + }, "explicit": { "type": "boolean", "description": "Set true only when the user clearly named this destination" } }, - "required": ["path"] + "required": [ + "path" + ] } }, { "name": "temp_env", - "description": "Return TMP/TEMP/cache environment assignments that keep tool junk inside the project .tmp and PI scratch.", + "description": "Return TMP/TEMP/cache environment assignments that keep tool junk inside the project Temp and PI scratch.", "risk": "low", "schema": { "type": "object", "properties": { - "root": { "type": "string", "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." }, + "root": { + "type": "string", + "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." + }, "shell": { "type": "string", - "enum": ["powershell", "cmd", "bash", "json"], + "enum": [ + "powershell", + "cmd", + "bash", + "json" + ], "description": "Script dialect for the env assignments. Defaults to PowerShell on Windows and bash elsewhere." } } @@ -67,21 +88,33 @@ }, { "name": "tmp_layout", - "description": "Return the recommended $project/.tmp/{tests,scripts,cache,out} layout without creating files.", + "description": "Return the recommended $project/Temp/{tests,scripts,cache,out} layout without creating files.", "risk": "low", "schema": { "type": "object", "properties": { - "root": { "type": "string", "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." } + "root": { + "type": "string", + "description": "Optional project root override; use only for a root explicitly selected by the user. The tool cannot verify that selection." + } } } } ] }, - "permissions": ["agent.prompt.inject", "agent.tool.register"], - "engines": { "piDesktop": ">=0.2.0" }, - "categories": ["productivity"], - "changelog": "0.2.5: Quote generated bash and PowerShell assignments safely, reject unsafe cmd values, enforce canonical root/scratch and symlink boundaries, include negative-path tests in CI, and sync the package. 0.2.4:说明改为中文。0.2.3:去掉 git/cwd 作为项目根回退;cmd 环境变量拒绝内嵌引号;覆盖工作区 API 失败与 explicit 临时目录拒绝。0.2.2:相对路径相对工作区解析。0.2.1:explicit 目标与 XDG_DOWNLOAD_DIR。0.2.0:跨机器便携。", - "safetyNotes": "Behavioral confinement only. The plugin reads the local XDG user-dirs configuration to classify paths, injects agent rules, and does not write files or access the network.", - "activationEvents": ["onStartup"] + "permissions": [ + "agent.prompt.inject", + "agent.tool.register" + ], + "engines": { + "piDesktop": ">=0.2.0" + }, + "categories": [ + "productivity" + ], + "changelog": "0.2.7:市场名称改为「C盘防垃圾」;项目垃圾改放到 $project/Temp/;拒绝把 Temp 倾倒目录当项目根。 0.2.6:市场名称改为直白中文。 0.2.5: Quote generated bash and PowerShell assignments safely, reject unsafe cmd values, enforce canonical root/scratch and symlink boundaries, include negative-path tests in CI, and sync the package. 0.2.4:说明改为中文。0.2.3:去掉 git/cwd 作为项目根回退;cmd 环境变量拒绝内嵌引号;覆盖工作区 API 失败与 explicit 临时目录拒绝。0.2.2:相对路径相对工作区解析。0.2.1:explicit 目标与 XDG_DOWNLOAD_DIR。0.2.0:跨机器便携。", + "safetyNotes": "这是行为约束,不是磁盘锁。插件只分类路径并注入 Agent 规则,不改 ACL、不联网。", + "activationEvents": [ + "onStartup" + ] } diff --git a/plugins/pi.workspace-file-guard/references/denied-paths.md b/plugins/pi.workspace-file-guard/references/denied-paths.md index 8062e75..bed1784 100644 --- a/plugins/pi.workspace-file-guard/references/denied-paths.md +++ b/plugins/pi.workspace-file-guard/references/denied-paths.md @@ -19,13 +19,13 @@ ## 不要用系统临时目录,改写到这里 -一次性文件用 `$PI_SCRATCH_DIR`;项目本地缓存用 `$project/.tmp` 或 `$project/.tmp/cache`: +一次性文件用 `$PI_SCRATCH_DIR`;项目本地缓存和一次性测试用 `$project/Temp` 或 `$project/Temp/cache`: | 工具 | 环境变量 / 参数 | | --- | --- | | 通用 | `TMP`、`TEMP`、`TMPDIR` | -| Python | `PYTHONPYCACHEPREFIX`、`PIP_CACHE_DIR`、`UV_CACHE_DIR` | -| pytest | `--basetemp .tmp/tests/pytest` | +| Python | `PYTHONPYCACHEPREFIX`、`PIP_CACHE_DIR`、`UV_CACHE_DIR`、`PYTHONDONTWRITEBYTECODE` | +| pytest | `--basetemp Temp/tests/pytest` | | Node / npm | `npm_config_cache`、`npm_config_tmp` | | pnpm | 只有确实需要本地 store 时才设 `PNPM_STORE_DIR` | | Go | `GOCACHE`、`GOTMPDIR` | @@ -47,3 +47,5 @@ 一次性文件始终允许:`$PI_SCRATCH_DIR`(会话草稿是 `~/.pi-desktop/scratch/` 时也算)。 不能当垃圾倾倒场:`~/.codex/tmp`、sessions、visualizations、`~/.pi-desktop/logs`。 + +不能当项目根:名为 `Temp` 的倾倒目录、桌面/下载本身、用户主目录、AppData、系统临时目录、Windows / Program Files。 diff --git a/plugins/pi.workspace-file-guard/skills/workspace-file-guard.md b/plugins/pi.workspace-file-guard/skills/workspace-file-guard.md index 17d5b37..3059315 100644 --- a/plugins/pi.workspace-file-guard/skills/workspace-file-guard.md +++ b/plugins/pi.workspace-file-guard/skills/workspace-file-guard.md @@ -3,47 +3,48 @@ name: workspace-file-guard description: 把测试文件、临时文件、草稿脚本、日志、转储、缓存和垃圾文件关在当前工作区或 PI scratch。创建文件、跑测试、生成产物、写辅助脚本、使用 TEMP/TMP/TMPDIR、下载缓存,或在 Windows / macOS / Linux 上工作时使用。不要把这些文件写到其他卷、工作区外的系统盘、桌面、下载、文档或系统临时目录。只读检查、用户明确要求的插件/skill 安装、以及用户本轮点名的外部目标不要套用本 skill。 --- -# 工作区文件护栏 +# C盘防垃圾 -把 Agent 产生的垃圾文件关在当前项目或 PI scratch 里。这是行为约束,不是操作系统锁。 +拦住 Agent 往系统盘、桌面、下载乱写测试/日志/缓存。垃圾只许待在当前项目的 `Temp` 或 PI scratch。这是行为约束,不是操作系统锁。 插件工具(宿主前缀 `plugin_pi_workspace_file_guard_`): -- `project_root` — 解析当前工作区 / PI scratch / `.tmp` 布局。未打开工作区且未传 `root` 时失败。 +- `project_root` — 解析当前工作区 / PI scratch / `Temp` 布局。未打开工作区且未传 `root` 时失败。 - `check_path` — 判断写入路径是否允许(`allowed=true|false`)。看 `allowed`,不要看 `ok`。相对路径相对工作区解析,不是插件进程 cwd。 - `temp_env` — TMP / TEMP / 缓存相关环境变量赋值 -- `tmp_layout` — 推荐的 `$project/.tmp/{tests,scripts,cache,out}` +- `tmp_layout` — 推荐的 `$project/Temp/{tests,scripts,cache,out}` 路径在当前机器上解析。不要假设 `C:`、`D:`、`/Users/foo` 或某个用户名。`check_path` / `temp_env` 永远不要把插件安装目录当成项目根。 ## 硬性规则 1. 先解析项目根,再把测试 / 临时 / 草稿 / 脚本 / 垃圾文件只写到该根目录下,或 `$PI_SCRATCH_DIR`。 -2. 不要写到其他卷。项目在 `D:` / `/data` / 其他盘时,不要在系统盘创建这些文件。 -3. 即使项目本身在系统盘,也只待在该项目文件夹内。不要溢到桌面、下载、文档、图片、系统临时目录或 AppData Local Temp。 -4. 不要把操作系统临时目录、Codex 可视化目录、`$CODEX_HOME/tmp`、`~/.pi-desktop/logs`、`~/.cache` 当作项目文件的倾倒场。 -5. 优先用相对项目根的路径。工具需要绝对路径时,从项目根或 `$PI_SCRATCH_DIR` 生成。 -6. 用户要求保留的正式源码放进项目树,不要放进 `.tmp`。一次性文件放 `.tmp` 或 PI scratch,用完可删。 +2. 优先倾倒场:`$project/Temp/`(`tests`、`scripts`、`cache`、`out`)。 +3. 不要写到其他卷。项目在 `D:` / `/data` / 其他盘时,不要在系统盘创建这些文件。 +4. 即使项目本身在系统盘,也只待在该项目文件夹内。不要溢到桌面、下载、文档、图片、系统临时目录或 AppData Local Temp。 +5. 不要把操作系统临时目录、Codex 可视化目录、`$CODEX_HOME/tmp`、`~/.pi-desktop/logs`、`~/.cache` 当作项目文件的倾倒场。 +6. 优先用相对项目根的路径。工具需要绝对路径时,从项目根或 `$PI_SCRATCH_DIR` 生成。 +7. 用户要求保留的正式源码放进项目树,不要放进 `Temp`。一次性文件放 `Temp` 或 PI scratch,用完可删。 命令会写到项目外时,停下来改路径。不要「就这一次」把测试文件丢到系统盘。 ## 项目根 -用当前用户项目,不要用 PI 内部目录。 +用当前用户项目,不要用 PI 内部目录。不要写死盘符或用户名。 优先级: 1. 用户点名的 `root` 参数。 -2. 已打开的 PI-Desktop 工作区(`pi.workspace.get()`)。 +2. 已打开的 PI-Desktop 工作区(`pi.workspace.get()`)。若工作区落在该项目的 `Temp` 倾倒目录里,回退到拥有它的项目根。 3. 两者都没有时工具失败。不要用插件进程 cwd、插件安装目录或猜出来的 git 根。 不要把下面这些当成垃圾文件的项目根: -- `~/.pi-desktop/logs/` -- `~/.pi-desktop/cache/` -- `~/.codex/visualizations/` -- `~/.codex/tmp/` +- 名为 `Temp` 的倾倒目录本身 +- 用户主目录、桌面、下载、文档、图片、音乐、视频 +- `~/.pi-desktop`、`~/.pi`、`~/.codex` 以及它们的 logs / cache / visualizations / tmp - 系统临时目录(`os.tmpdir()`、`%TEMP%`、`%TMP%`、`/tmp`、`/var/tmp`) +- Windows、Program Files、ProgramData,或 POSIX 的 `/usr`、`/etc`、`/Applications` 不确定时先调 `project_root`。 @@ -53,14 +54,14 @@ description: 把测试文件、临时文件、草稿脚本、日志、转储、 | --- | --- | | 用户要求保留的源码 | 工作区内的 `src/`、`tests/`、`scripts/` 等 | | 一次性脚本、转储、日志、截图 | `$PI_SCRATCH_DIR`(会话草稿目录) | -| 项目本地缓存 / pytest basetemp | `$project/.tmp/cache`、`$project/.tmp/tests` | +| 项目本地缓存 / pytest basetemp | `$project/Temp/cache`、`$project/Temp/tests` | -只在需要时创建 `$project/.tmp`(应被 gitignore)。布局: +只在需要时创建 `$project/Temp`(应被 gitignore)。布局: -- `.tmp/tests/` 一次性测试 -- `.tmp/scripts/` 一次性脚本 -- `.tmp/cache/` 下载和工具缓存 -- `.tmp/out/` 生成的转储、日志、截图 +- `Temp/tests/` 一次性测试 +- `Temp/scripts/` 一次性脚本 +- `Temp/cache/` 下载和工具缓存 +- `Temp/out/` 生成的转储、日志、截图 跑会认临时/缓存环境变量的工具前,先调 `temp_env` 并在该 shell 里应用。默认方言:Windows 用 PowerShell,其他系统用 bash。写之前用 `check_path` 检查;`allowed=false` 就必须改路径。 diff --git a/tests/workspace-file-guard-guard.test.js b/tests/workspace-file-guard-guard.test.js index 7cbf0b9..a1dfcbc 100644 --- a/tests/workspace-file-guard-guard.test.js +++ b/tests/workspace-file-guard-guard.test.js @@ -4,6 +4,7 @@ const fs = require("node:fs"); const os = require("node:os"); const path = require("node:path"); const { + TMP_DIRNAME, classify, defaultProjectRoot, defaultShell, @@ -45,8 +46,11 @@ try { "relative src must not resolve into the plugin directory" ); - const relativeTmp = classify(".tmp/out/log.txt", project, { scratch }); - assert(relativeTmp.allowed, "relative .tmp should stay inside the project"); + const relativeLegacyTmp = classify(".tmp/out/log.txt", project, { scratch }); + assert(relativeLegacyTmp.allowed, "legacy .tmp path inside the project should still be allowed"); + + const relativeTmp = classify("Temp/out/log.txt", project, { scratch }); + assert(relativeTmp.allowed, "relative Temp should stay inside the project"); const scratchFile = classify(path.join(scratch, "dump.txt"), project, { scratch }); assert(scratchFile.allowed, "PI scratch should be allowed"); @@ -94,9 +98,10 @@ try { ); assert(pluginsExplicit.allowed, "plugin install with explicit request should be allowed"); + assert(TMP_DIRNAME === "Temp", "dump directory must be Temp"); assert( - isRelativeTo(path.join(project, ".tmp", "out"), project), - ".tmp inside project should count as relative" + isRelativeTo(path.join(project, "Temp", "out"), project), + "Temp inside project should count as relative" ); assert(!isRelativeTo(systemTemp, project), "OS temp should not be relative to the project"); @@ -114,10 +119,29 @@ try { assert(withWorkspace.ok, "workspace should resolve"); assert(withWorkspace.projectRoot.toLowerCase() === resolvePath(project).toLowerCase(), "workspace root mismatch"); + const fromDump = resolveToolRoot({ workspace: path.join(project, "Temp", "out") }); + assert(fromDump.ok, "Temp dump should climb to the owning project"); + assert( + fromDump.projectRoot.toLowerCase() === resolvePath(project).toLowerCase(), + `Temp dump owner was ${fromDump.projectRoot}` + ); + + const reservedDump = resolveToolRoot({ workspace: path.join(project, "Temp") }); + assert(reservedDump.ok, "a Temp dump should resolve to its parent project"); + assert( + reservedDump.projectRoot.toLowerCase() === resolvePath(project).toLowerCase(), + "Temp dump must not remain the project root" + ); + + const reservedDesktop = resolveToolRoot({ workspace: path.join(home, "Desktop") }); + assert(!reservedDesktop.ok, "Desktop itself must not be a project root"); + + const reservedOsTemp = resolveToolRoot({ workspace: systemTemp }); + assert(!reservedOsTemp.ok, "OS temp must not be a project root"); const env = envAssignments({ projectRoot: project, scratch }); assert(env.TEMP === resolvePath(scratch), "TEMP should point at PI scratch"); - assert(String(env.PIP_CACHE_DIR).includes(".tmp"), "pip cache should stay in project .tmp"); - + assert(env.PYTHONDONTWRITEBYTECODE === "1", "python bytecode should be disabled"); + assert(String(env.PIP_CACHE_DIR).includes("Temp"), "pip cache should stay in project Temp"); const spaced = envAssignments({ projectRoot: win ? "D:\\My Project" : "/data/My Project", scratch: path.join(home, "scratch dir"), diff --git a/tests/workspace-file-guard-main.test.js b/tests/workspace-file-guard-main.test.js index 3670b48..b737b78 100644 --- a/tests/workspace-file-guard-main.test.js +++ b/tests/workspace-file-guard-main.test.js @@ -28,7 +28,7 @@ async function run() { const manifest = JSON.parse( fs.readFileSync(path.join(__dirname, "..", "plugins", "pi.workspace-file-guard", "manifest.json"), "utf8") ); - assert(manifest.version === "0.2.5", "manifest version must match the reviewed release"); + assert(manifest.version === "0.2.7", "manifest version must match the reviewed release"); assert( JSON.stringify(manifest.permissions) === JSON.stringify(["agent.prompt.inject", "agent.tool.register"]), "manifest permissions must remain minimal and exact"