pi-webapp 0.1.22 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/README.zh-CN.md +12 -5
- package/dist/extension.js +2 -2
- package/package.json +2 -2
- package/web/dist/.vite/manifest.json +23 -23
- package/web/dist/assets/{app-D54rSb9U.js → app-C-H5rHq5.js} +94 -94
- package/web/dist/assets/app.js +2 -2
- package/web/dist/assets/{graphql-DSgZM88T.js → graphql-R1M_bSpj.js} +1 -1
- package/web/dist/assets/{http-BnatDCTa.js → http-L5EnyzVP.js} +1 -1
- package/web/dist/assets/{php-C7wdcWqa.js → php-xdHBwAuB.js} +1 -1
- package/web/dist/assets/{plugin-CDXXKG8W.js → plugin-CYps5zpH.js} +1 -1
- package/web/dist/assets/{plugin-U9RqGH7R.js → plugin-DCamQdiP.js} +1 -1
- package/web/dist/assets/{plugin-DuICpslz.js → plugin-DtJl1c8o.js} +1 -1
- package/web/dist/assets/{rst-DXm1XNUD.js → rst-D5vBXrc7.js} +1 -1
- package/web/dist/assets/{ruby-BM86KL0M.js → ruby-CB8CtpFl.js} +1 -1
- package/web/dist/assets/style.css +1 -1
- package/web/dist/assets/{svelte-Dizghd7i.js → svelte-qWxX2efJ.js} +1 -1
- package/web/dist/assets/{vue-DJuuwuj_.js → vue-CTcHoOmv.js} +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
## Download pi desktop
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**⬇ Test release · v0.1.21 / desktop build 6 · bundled Pi 1.3.0**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| Your computer | Download |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| macOS · Apple Silicon (M-series, arm64) | [Download DMG](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-mac-arm64.dmg) |
|
|
12
|
+
| macOS · Intel (x64) | [Download DMG](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-mac-x64.dmg) |
|
|
13
|
+
| Windows · x64 | [Download EXE installer](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-win-x64.exe) |
|
|
14
|
+
| Linux · x64 | [Download AppImage](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-linux-x86_64.AppImage) |
|
|
10
15
|
|
|
11
|
-
[Release notes
|
|
16
|
+
[Release notes](https://github.com/chengzhiyi/pi-webapp/releases/tag/desktop-v0.1.21-b6) · [SHA-256 checksums](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/SHA256SUMS) · [Runtime/source metadata](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/desktop-release.json) · [Previous build 5](https://github.com/chengzhiyi/pi-webapp/releases/tag/desktop-v0.1.20-b5) · [Use Web/npm instead](#install-and-open)
|
|
12
17
|
|
|
13
|
-
>
|
|
18
|
+
> **Install:** macOS: open the DMG and drag **pi.app** into Applications. Windows: run the EXE installer. Linux: make the AppImage executable, then run it; use `--appimage-extract-and-run` if FUSE is unavailable. Node and pinned Pi **1.3.0** are bundled; no separate installation is required. Configure your model account in Settings. Quit the old desktop before replacing it; a reused external Web service keeps its own Pi version and is never automatically stopped or upgraded.
|
|
19
|
+
>
|
|
20
|
+
> **Unsigned test build:** macOS is not notarized; Windows may show an unknown-publisher warning. Only proceed if you trust the source; never globally disable system security. Installer-payload smoke tests passed on all four targets, not every Linux distribution or real model-provider login. Windows ARM/Linux ARM are not included. Desktop automatic updates are not provided in this build.
|
|
14
21
|
|
|
15
22
|

|
|
16
23
|
|
|
@@ -57,7 +64,7 @@ In Pi, enter `/web` to open the interface in your default browser. Pi also print
|
|
|
57
64
|
- In **Git changes → Changes**, use each file’s **+ / −** button to stage or unstage it, use the fixed bottom composer to commit only the staged index (Ctrl/Cmd+Enter is supported), and click the branch name to search/switch local branches or open **New branch**. The file list scrolls independently; full repository metadata is available on the short repository name’s tooltip. Drafts stay with each chat’s Git tab. Commits and branch switches require a root workspace; switching also requires a clean working tree, including untracked files. Writes require all known chats using the worktree to be idle, reject stale snapshots, and honor Git hooks/signing. Conflicts, active Git operations, locks and occupied worktree branches block incompatible writes. Failed or unconfirmed operations retain drafts and never retry automatically. Changes are shared by chats using the same worktree. No fetch/push, forced switch, stash or discard is performed.
|
|
58
65
|
- In **Git changes → History**, browse commits alongside their branch/merge graph, with HEAD, local branch, remote-tracking branch and tag labels. Load history 50 commits at a time; a ref change resets pagination to prevent mixed histories. Open commit details for the full message, author/committer, timestamps, parents and changed files, then preview a read-only file diff alongside the same commit file list without opening another tab. Merge details let you select the parent to compare against; root commits compare against an empty tree. The graph shows repository-wide metadata while commit files and diffs stay within the session directory. Graph selection and loaded history remain with each chat’s Git tab until the page reloads. Remote labels use local refs without fetching.
|
|
59
66
|
- Attach up to 20 files of 20 MB each by selecting, dropping, or pasting them. Images show previews and are also sent as Pi image content.
|
|
60
|
-
- Open Plugins
|
|
67
|
+
- Open Plugins directly below New session in the sidebar to inspect and switch the bundled Git, Files and Terminal capabilities. Switches are global, persist locally, and require every chat to be idle. Disabling closes related tabs and blocks backend requests; Terminal asks for confirmation before ending all service-owned terminals. External Pi Web runtimes remain managed through Packages & extensions rather than a misleading UI-only switch.
|
|
61
68
|
- Manage appearance, Pi packages, extensions, skills, and models from the settings panel. The Models page can add models, edit display names, context windows, output limits, and input types, and restore built-in defaults; changes are saved to Pi's `models.json`. Browser sign-in opens the provider's authorization page automatically; manual code entry remains available when a callback cannot reach Pi. Stored provider credentials can also be removed there. Credentials stay in Pi's local `auth.json` and are never returned to the browser.
|
|
62
69
|
|
|
63
70
|
If you enter `/web` manually in a Pi terminal, that terminal session stays synchronized with the browser. With the launcher, Pi runs in the background. Sessions opened in other workspaces use the Pi SDK and load that workspace's skills and project context. They load enabled Web plugin Pi entries explicitly while keeping other Pi extensions isolated from the parent bridge.
|
package/README.zh-CN.md
CHANGED
|
@@ -4,13 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
## 下载 pi 桌面版
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**⬇ 测试版 · v0.1.21 / 桌面构建 6 · 内置 Pi 1.3.0**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| 你的电脑 | 下载安装包 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| macOS · Apple 芯片(M 系列,arm64) | [下载 DMG](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-mac-arm64.dmg) |
|
|
12
|
+
| macOS · Intel 芯片(x64) | [下载 DMG](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-mac-x64.dmg) |
|
|
13
|
+
| Windows · x64 | [下载 EXE 安装程序](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-win-x64.exe) |
|
|
14
|
+
| Linux · x64 | [下载 AppImage](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/pi-0.1.21-desktop.6-linux-x86_64.AppImage) |
|
|
10
15
|
|
|
11
|
-
[
|
|
16
|
+
[版本说明](https://github.com/chengzhiyi/pi-webapp/releases/tag/desktop-v0.1.21-b6) · [SHA-256 校验和](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/SHA256SUMS) · [运行时与源码元数据](https://github.com/chengzhiyi/pi-webapp/releases/download/desktop-v0.1.21-b6/desktop-release.json) · [旧构建 5(保留回退)](https://github.com/chengzhiyi/pi-webapp/releases/tag/desktop-v0.1.20-b5) · [改用 Web/npm 方式](#安装与打开)
|
|
12
17
|
|
|
13
|
-
> 打开 DMG,将 **pi.app**
|
|
18
|
+
> **安装:** macOS 打开 DMG,将 **pi.app** 拖入“应用程序”;Windows 运行 EXE 安装程序;Linux 为 AppImage 添加可执行权限后运行,缺少 FUSE 时可加 `--appimage-extract-and-run`。已内置 Node 和锁定版本的 Pi **1.3.0**,无需另装;首次使用在设置中配置模型账户。替换前先退出旧桌面。复用外部 Web 后台时,其 Pi 仍保持原版本,不会自动停止或升级。
|
|
19
|
+
>
|
|
20
|
+
> **未签名测试版:** macOS 未公证,Windows 可能提示未知发布者;仅在确认来源可信后按单个应用的系统提示处理,不要全局关闭系统安全保护。四种实际安装包均通过原生运行冒烟,但不代表已测试所有 Linux 发行版或真实模型账户登录。不含 Windows ARM/Linux ARM;本构建尚无桌面自动更新。
|
|
14
21
|
|
|
15
22
|

|
|
16
23
|
|
|
@@ -57,7 +64,7 @@ pi
|
|
|
57
64
|
- 在「Git 改动 → 改动」中,用文件右侧的 **+ / −** 逐文件暂存或取消暂存;底部固定提交栏仅提交暂存区内容(支持 Ctrl/Cmd+Enter);点击顶部分支名称,可搜索和切换本地分支,选择「新建分支」才展开创建表单。文件列表独立滚动,仓库完整信息通过短名称的悬停提示查看。草稿随各聊天的 Git 标签保留。提交和切换分支要求仓库根目录工作区,切换还要求整个工作树干净(包括未跟踪文件)。写操作要求共用工作树的已知聊天均为空闲,并校验状态快照,遵守 Git hooks 与签名配置。冲突、未完成的 Git 操作、锁及其他工作树占用的分支会阻止相应操作。失败或结果不明时保留草稿,不自动重试。同一工作树的改动由多个聊天共享。不执行 fetch/push、强制切换、stash 或丢弃改动。
|
|
58
65
|
- 在「Git 改动 → 历史」中浏览提交及其分支、合并关系图,显示 HEAD、本地分支、远端跟踪分支和标签。历史每次加载 50 条;引用变化时重新加载首页,避免分页混入不同版本的历史。点击提交查看完整说明、作者与提交者、时间、父提交及改动文件,再点击文件在当前提交详情内预览只读差异,保留文件列表,不再新建差异标签。合并提交可选择比较的父提交,根提交与空目录比较。关系图展示整个仓库的提交元数据,提交文件和差异仍限制在当前会话目录内。历史选中项与已加载页随各聊天的 Git 标签保留,网页刷新后重置。远端标签仅使用本地记录,不发起拉取。
|
|
59
66
|
- 通过选择、拖放或粘贴附加文件,最多 20 个,每个不超过 20 MB。图片会显示预览,并作为 Pi 图片内容发送。
|
|
60
|
-
-
|
|
67
|
+
- 从侧栏「新会话」下方的「插件」入口管理内置 Git、文件和终端。支持列表/详情、搜索、真实启停和全局持久化;所有聊天空闲后才可切换。停用会关闭相关标签并阻止后端请求,停用终端需确认并结束此服务的全部终端。外部 Pi Web 插件展示运行时归属,仍通过「包与扩展」管理,不提供只隐藏 UI 的假开关。
|
|
61
68
|
- 在设置面板中管理外观、Pi 软件包、扩展、技能和模型。模型页可添加模型、编辑显示名称、上下文窗口、最大输出 token 数和输入类型,或恢复内置模型的默认参数;配置写入 Pi 的 `models.json`。网页登录会自动打开提供方授权页;当回调无法到达 Pi 时,仍可手动粘贴授权码。已保存的提供方认证可在这里移除。凭据保留在 Pi 本地的 `auth.json`,不会返回给浏览器。
|
|
62
69
|
|
|
63
70
|
如果通过 Pi 终端手动输入 `/web`,该终端会话会与浏览器保持同步。使用启动器时,Pi 在后台运行。在其他工作区打开的会话使用 Pi SDK,并加载该工作区的技能和项目上下文;已启用的 Web 插件 Pi 入口会显式加载,其他普通 Pi 扩展仍与主会话隔离。
|
package/dist/extension.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(){try{var r=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},e=new r.Error().stack;e&&(r._sentryDebugIds=r._sentryDebugIds||{},r._sentryDebugIds[e]="456337da-7ef2-4728-a06e-2fbd3027f1d1",r._sentryDebugIdIdentifier="sentry-dbid-456337da-7ef2-4728-a06e-2fbd3027f1d1")}catch{}})();import{delimiter as Do,dirname as Oo,join as Xe,resolve as Ct}from"node:path";import{realpathSync as gi,watch as Fo}from"node:fs";import{fileURLToPath as Bo}from"node:url";import{DefaultPackageManager as yi,getAgentDir as ae,ModelRuntime as $o,SessionManager as bi,SettingsManager as jo,VERSION as Ye}from"@earendil-works/pi-coding-agent";import{getSupportedThinkingLevels as Lo}from"@earendil-works/pi-ai";import{randomBytes as jr,randomUUID as pt,timingSafeEqual as ms}from"node:crypto";import{readFile as gs,readdir as hs}from"node:fs/promises";import{createServer as ws}from"node:http";import{join as ut}from"node:path";import{getAgentDir as ys}from"@earendil-works/pi-coding-agent";import{isAbsolute as tn,relative as rn}from"node:path";var de={git:"@pi-webapp/git",files:"@pi-webapp/files",terminal:"@pi-webapp/terminal"};var _t={id:de.git,kind:"builtin",version:"1.0.0",name:{zh:"Git",en:"Git"},description:{zh:"\u5BA1\u9605\u5DE5\u4F5C\u533A\u6539\u52A8\u4E0E\u63D0\u4EA4\u5386\u53F2\uFF0C\u6682\u5B58\u6587\u4EF6\u3001\u63D0\u4EA4\u5E76\u7BA1\u7406\u672C\u5730\u5206\u652F\u3002",en:"Review workspace changes and history, stage files, commit and manage local branches."}};import{execFile as Si}from"node:child_process";import{realpath as xi}from"node:fs/promises";import{isAbsolute as Tt,relative as Ii,sep as Ci,win32 as _i}from"node:path";var P=class extends Error{status;reason;constructor(e,t=400,i="git_failed"){super(e),this.name="WorkspaceGitError",this.status=t,this.reason=i}};function T(r,e,t=2*1024*1024,i={}){let n=Object.fromEntries(Object.entries(process.env).filter(([s])=>!s.startsWith("GIT_")));return new Promise((s,a)=>{let l,p=Si("git",["--no-pager","--literal-pathspecs","-c","core.fsmonitor=false",...e],{cwd:r,env:{...n,LC_ALL:"C",GIT_OPTIONAL_LOCKS:"0",GIT_TERMINAL_PROMPT:"0",GIT_NO_REPLACE_OBJECTS:"1"},encoding:"utf8",timeout:i.write?3e4:1e4,maxBuffer:t,windowsHide:!0},(h,u,c)=>{if(!h){if(l){a(new P("Git \u8F93\u5165\u4F20\u8F93\u5931\u8D25\uFF0C\u64CD\u4F5C\u7ED3\u679C\u672A\u786E\u8BA4\uFF0C\u8BF7\u5237\u65B0\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\uFF1B\u4E0D\u8981\u81EA\u52A8\u91CD\u8BD5",503,i.write?"outcome_unknown":"git_failed"));return}s(u);return}if(i.write){let m=h.killed||h.code==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?"outcome_unknown":/index\.lock|cannot lock ref|could not lock/i.test(c)?"index_locked":/already exists/i.test(c)?"branch_exists":/already checked out|used by worktree/i.test(c)?"branch_in_use":/would be overwritten|local changes/i.test(c)?"dirty_worktree":/identity unknown|unable to auto-detect email|empty ident/i.test(c)?"identity_missing":"git_failed";a(new P("Git \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u5237\u65B0\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\u3001\u8EAB\u4EFD\u6216 hooks \u914D\u7F6E",m==="outcome_unknown"?503:409,m));return}let f=h.code;f==="ENOENT"?a(new P("Git \u672A\u5B89\u88C5\u6216\u5DE5\u4F5C\u533A\u4E0D\u53EF\u7528",503)):f==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?a(new P("Git \u8F93\u51FA\u8FC7\u5927\uFF0C\u8BF7\u7F29\u5C0F\u8BFB\u53D6\u8303\u56F4",413)):/not a git repository/.test(c)?a(new P("\u5F53\u524D\u76EE\u5F55\u4E0D\u662F Git \u4ED3\u5E93",404)):a(new P(h.killed?"Git \u8BFB\u53D6\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5":"Git \u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\u548C\u76EE\u5F55\u6743\u9650",503))});p.stdin?.on("error",h=>{l=h}),i.input!==void 0&&p.stdin?.end(i.input)})}async function X(r){let e=await xi(r),t;try{t=(await T(e,["rev-parse","--show-toplevel"])).replace(/\n$/,"")}catch(n){if(n instanceof P&&n.status===404)return{kind:"not-repository"};if(n instanceof P&&n.message==="Git \u672A\u5B89\u88C5\u6216\u5DE5\u4F5C\u533A\u4E0D\u53EF\u7528")return{kind:"unavailable"};throw n}let i=Ii(t,e).split(Ci).join("/");if(i===".."||i.startsWith("../")||Tt(i))throw new P("\u4ED3\u5E93\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);return{kind:"repository",cwd:e,root:t,scope:i?`${i}/`:""}}function te(r){if(typeof r!="string"||!r||r.length>4096||r.includes("\0")||r.includes("\\")||Tt(r)||_i.isAbsolute(r)||r.split("/").some(e=>!e||e==="."||e===".."))throw new P("\u5DE5\u4F5C\u533A\u6587\u4EF6\u8DEF\u5F84\u65E0\u6548",403)}import{createHash as Vi}from"node:crypto";import{lstat as it,realpath as Gt}from"node:fs/promises";import{dirname as Lt,isAbsolute as Ui,relative as zi,resolve as ve}from"node:path";import{lstat as ji}from"node:fs/promises";import{resolve as Li}from"node:path";import{constants as et}from"node:fs";import{open as Ti,opendir as Mi,realpath as Mt,stat as Wt}from"node:fs/promises";import{isAbsolute as Nt,relative as Ai,resolve as Ri,sep as Wi,win32 as Ni}from"node:path";var Di=1e3,Oi=512*1024,Fi=8*1024*1024,At=1e4,Bi=new Intl.Collator("en",{numeric:!0,sensitivity:"base"}),W=class extends Error{status;constructor(e,t=400){super(e),this.name="WorkspaceFileError",this.status=t}};function Rt(r,e){let t=Ai(r,e);return t!==".."&&!t.startsWith(`..${Wi}`)&&!Nt(t)}async function tt(r,e){if(typeof e!="string"||e.length>4096||e.includes("\0")||e.includes("\\")||Nt(e)||Ni.isAbsolute(e))throw new W("\u5DE5\u4F5C\u533A\u6587\u4EF6\u8DEF\u5F84\u65E0\u6548");let t=await Mt(r),i=Ri(t,e);if(!Rt(t,i))throw new W("\u6587\u4EF6\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);let n=await Mt(i);if(!Rt(t,n))throw new W("\u6587\u4EF6\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);return n}async function Dt(r){try{return await r()}catch(e){if(e instanceof W)throw e;let t=e.code;throw t==="ENOENT"||t==="ENOTDIR"?new W("\u6587\u4EF6\u6216\u76EE\u5F55\u5DF2\u4E0D\u5B58\u5728",404):t==="EACCES"||t==="EPERM"?new W("\u6CA1\u6709\u6743\u9650\u8BFB\u53D6\u6587\u4EF6\u6216\u76EE\u5F55",403):e}}async function Ot(r,e){return Dt(async()=>{let t=await tt(r,e),i=[],n=!1;for await(let s of await Mi(t)){if(i.length===Di){n=!0;break}let a=e?`${e}/${s.name}`:s.name,l=s.isDirectory()?"directory":s.isFile()?"file":"other";if(s.isSymbolicLink())try{let p=await Wt(await tt(r,a));l=p.isDirectory()?"directory":p.isFile()?"file":"other"}catch{}i.push({name:s.name,path:a,kind:l})}return i.sort((s,a)=>+(a.kind==="directory")-+(s.kind==="directory")||Bi.compare(s.name,a.name)||s.name.localeCompare(a.name)),{path:e,entries:i,truncated:n}})}function $i(r){if(r.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])))return"image/png";if(r[0]===255&&r[1]===216&&r[2]===255)return"image/jpeg";if(["GIF87a","GIF89a"].includes(r.subarray(0,6).toString("ascii")))return"image/gif";if(r.subarray(0,4).toString("ascii")==="RIFF"&&r.subarray(8,12).toString("ascii")==="WEBP")return"image/webp"}async function be(r,e){return Dt(async()=>{let t=await tt(r,e);if(!(await Wt(t)).isFile())throw new W("\u8FD9\u4E0D\u662F\u53EF\u9884\u89C8\u7684\u666E\u901A\u6587\u4EF6");let i=await Ti(t,et.O_RDONLY|et.O_NONBLOCK|(et.O_NOFOLLOW??0));try{let n=await i.stat();if(!n.isFile())throw new W("\u8FD9\u4E0D\u662F\u53EF\u9884\u89C8\u7684\u666E\u901A\u6587\u4EF6");let s={path:e,size:n.size},a=Buffer.alloc(16);await i.read(a,0,a.length,0);let l=$i(a),p=l?Fi:Oi;if(n.size>p)return{...s,kind:"too-large",limit:p,unit:"bytes"};let h=Buffer.alloc(Math.min(n.size+1,p+1)),u=0;for(;u<h.length;){let{bytesRead:m}=await i.read(h,u,h.length-u,u);if(!m)break;u+=m}if(u>n.size)throw new W("\u6587\u4EF6\u6B63\u5728\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6",409);let c=h.subarray(0,u);if(l)return{...s,kind:"image",mimeType:l,data:c.toString("base64")};if(c.some(m=>m===0||m<32&&![9,10,12,13,27].includes(m)))return{...s,kind:"unsupported"};let f=1;for(let m=0;m<c.length-1;m++)if(c[m]===10&&++f>At)return{...s,kind:"too-large",limit:At,unit:"lines"};try{return{...s,kind:"text",text:new TextDecoder("utf-8",{fatal:!0}).decode(c)}}catch{return{...s,kind:"unsupported"}}}finally{await i.close()}})}var Gi=1e3,Ft=512*1024,Bt=1e4;function $t(r,e){return e.startsWith(r)&&e.slice(r.length)||void 0}async function pe(r){let e=await X(r);if(e.kind!=="repository")return e;let{root:t,scope:i}=e,n=await T(e.cwd,["status","--porcelain=v2","--branch","-z","--untracked-files=all","--","."]),s={kind:"repository",root:t,scope:i,branch:null,head:null,upstream:null,ahead:null,behind:null,entries:[],truncated:!1},a=n.split("\0");for(let l=0;l<a.length;l++){let p=a[l];if(p.startsWith("# branch.oid ")){let I=p.slice(13);s.head=I==="(initial)"?null:I;continue}if(p.startsWith("# branch.head ")){let I=p.slice(14);s.branch=I==="(detached)"?null:I;continue}if(p.startsWith("# branch.upstream ")){s.upstream=p.slice(18);continue}if(p.startsWith("# branch.ab ")){let I=p.match(/\+(\d+) -(\d+)/);I&&(s.ahead=Number(I[1]),s.behind=Number(I[2]));continue}let h=p[0];if(!["1","2","u","?"].includes(h??""))continue;let u=h==="?"?1:h==="1"?8:h==="2"?9:10,c=0;for(let I=0;I<u;I++)c=p.indexOf(" ",c)+1;let f=$t(i,p.slice(c)),m=h==="2"?a[++l]:void 0;if(!f)continue;if(s.entries.length===Gi){s.truncated=!0;continue}let g=p.slice(0,c).split(" "),E={path:f,index:h==="?"?"?":g[1][0],worktree:h==="?"?"?":g[1][1],conflict:h==="u",untracked:h==="?",submodule:h!=="?"&&g[2]!=="N..."},x=m===void 0?void 0:$t(i,m);x&&(E.originalPath=x),s.entries.push(E)}return s}async function jt(r,e,t){if(te(e),!["staged","unstaged","untracked"].includes(t))throw new P("Git \u5DEE\u5F02\u8303\u56F4\u65E0\u6548");let i=await pe(r);if(i.kind!=="repository")throw new P("\u5F53\u524D\u5DE5\u4F5C\u533A\u6CA1\u6709\u53EF\u8BFB\u53D6\u7684 Git \u4ED3\u5E93",404);let n={path:e,area:t},s=i.entries.find(l=>l.path===e);if(!s)return{...n,kind:"empty"};if(s.conflict)return{...n,kind:"conflict"};if(s.submodule)return{...n,kind:"submodule"};if(t==="untracked"){if(!s.untracked)return{...n,kind:"empty"};if(!(await ji(Li(r,e))).isFile())return{...n,kind:"unsupported"};let l=await be(r,e);if(l.kind==="too-large")return{...n,kind:"too-large"};if(l.kind!=="text")return{...n,kind:"binary"};if(!l.text)return{...n,kind:"empty"};let p=l.text.split(`
|
|
1
|
+
(function(){try{var r=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},e=new r.Error().stack;e&&(r._sentryDebugIds=r._sentryDebugIds||{},r._sentryDebugIds[e]="0228111b-cb58-4780-8e74-42614f215f44",r._sentryDebugIdIdentifier="sentry-dbid-0228111b-cb58-4780-8e74-42614f215f44")}catch{}})();import{delimiter as Do,dirname as Oo,join as Xe,resolve as Ct}from"node:path";import{realpathSync as gi,watch as Fo}from"node:fs";import{fileURLToPath as Bo}from"node:url";import{DefaultPackageManager as yi,getAgentDir as ae,ModelRuntime as $o,SessionManager as bi,SettingsManager as jo,VERSION as Ye}from"@earendil-works/pi-coding-agent";import{getSupportedThinkingLevels as Lo}from"@earendil-works/pi-ai";import{randomBytes as jr,randomUUID as pt,timingSafeEqual as ms}from"node:crypto";import{readFile as gs,readdir as hs}from"node:fs/promises";import{createServer as ws}from"node:http";import{join as ut}from"node:path";import{getAgentDir as ys}from"@earendil-works/pi-coding-agent";import{isAbsolute as tn,relative as rn}from"node:path";var de={git:"@pi-webapp/git",files:"@pi-webapp/files",terminal:"@pi-webapp/terminal"};var _t={id:de.git,kind:"builtin",version:"1.0.0",name:{zh:"Git",en:"Git"},description:{zh:"\u5BA1\u9605\u5DE5\u4F5C\u533A\u6539\u52A8\u4E0E\u63D0\u4EA4\u5386\u53F2\uFF0C\u6682\u5B58\u6587\u4EF6\u3001\u63D0\u4EA4\u5E76\u7BA1\u7406\u672C\u5730\u5206\u652F\u3002",en:"Review workspace changes and history, stage files, commit and manage local branches."}};import{execFile as Si}from"node:child_process";import{realpath as xi}from"node:fs/promises";import{isAbsolute as Tt,relative as Ii,sep as Ci,win32 as _i}from"node:path";var P=class extends Error{status;reason;constructor(e,t=400,i="git_failed"){super(e),this.name="WorkspaceGitError",this.status=t,this.reason=i}};function T(r,e,t=2*1024*1024,i={}){let n=Object.fromEntries(Object.entries(process.env).filter(([s])=>!s.startsWith("GIT_")));return new Promise((s,a)=>{let l,p=Si("git",["--no-pager","--literal-pathspecs","-c","core.fsmonitor=false",...e],{cwd:r,env:{...n,LC_ALL:"C",GIT_OPTIONAL_LOCKS:"0",GIT_TERMINAL_PROMPT:"0",GIT_NO_REPLACE_OBJECTS:"1"},encoding:"utf8",timeout:i.write?3e4:1e4,maxBuffer:t,windowsHide:!0},(h,u,c)=>{if(!h){if(l){a(new P("Git \u8F93\u5165\u4F20\u8F93\u5931\u8D25\uFF0C\u64CD\u4F5C\u7ED3\u679C\u672A\u786E\u8BA4\uFF0C\u8BF7\u5237\u65B0\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\uFF1B\u4E0D\u8981\u81EA\u52A8\u91CD\u8BD5",503,i.write?"outcome_unknown":"git_failed"));return}s(u);return}if(i.write){let m=h.killed||h.code==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?"outcome_unknown":/index\.lock|cannot lock ref|could not lock/i.test(c)?"index_locked":/already exists/i.test(c)?"branch_exists":/already checked out|used by worktree/i.test(c)?"branch_in_use":/would be overwritten|local changes/i.test(c)?"dirty_worktree":/identity unknown|unable to auto-detect email|empty ident/i.test(c)?"identity_missing":"git_failed";a(new P("Git \u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u5237\u65B0\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\u3001\u8EAB\u4EFD\u6216 hooks \u914D\u7F6E",m==="outcome_unknown"?503:409,m));return}let f=h.code;f==="ENOENT"?a(new P("Git \u672A\u5B89\u88C5\u6216\u5DE5\u4F5C\u533A\u4E0D\u53EF\u7528",503)):f==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER"?a(new P("Git \u8F93\u51FA\u8FC7\u5927\uFF0C\u8BF7\u7F29\u5C0F\u8BFB\u53D6\u8303\u56F4",413)):/not a git repository/.test(c)?a(new P("\u5F53\u524D\u76EE\u5F55\u4E0D\u662F Git \u4ED3\u5E93",404)):a(new P(h.killed?"Git \u8BFB\u53D6\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5":"Git \u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001\u548C\u76EE\u5F55\u6743\u9650",503))});p.stdin?.on("error",h=>{l=h}),i.input!==void 0&&p.stdin?.end(i.input)})}async function X(r){let e=await xi(r),t;try{t=(await T(e,["rev-parse","--show-toplevel"])).replace(/\n$/,"")}catch(n){if(n instanceof P&&n.status===404)return{kind:"not-repository"};if(n instanceof P&&n.message==="Git \u672A\u5B89\u88C5\u6216\u5DE5\u4F5C\u533A\u4E0D\u53EF\u7528")return{kind:"unavailable"};throw n}let i=Ii(t,e).split(Ci).join("/");if(i===".."||i.startsWith("../")||Tt(i))throw new P("\u4ED3\u5E93\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);return{kind:"repository",cwd:e,root:t,scope:i?`${i}/`:""}}function te(r){if(typeof r!="string"||!r||r.length>4096||r.includes("\0")||r.includes("\\")||Tt(r)||_i.isAbsolute(r)||r.split("/").some(e=>!e||e==="."||e===".."))throw new P("\u5DE5\u4F5C\u533A\u6587\u4EF6\u8DEF\u5F84\u65E0\u6548",403)}import{createHash as Vi}from"node:crypto";import{lstat as it,realpath as Gt}from"node:fs/promises";import{dirname as Lt,isAbsolute as Ui,relative as zi,resolve as ve}from"node:path";import{lstat as ji}from"node:fs/promises";import{resolve as Li}from"node:path";import{constants as et}from"node:fs";import{open as Ti,opendir as Mi,realpath as Mt,stat as Wt}from"node:fs/promises";import{isAbsolute as Nt,relative as Ai,resolve as Ri,sep as Wi,win32 as Ni}from"node:path";var Di=1e3,Oi=512*1024,Fi=8*1024*1024,At=1e4,Bi=new Intl.Collator("en",{numeric:!0,sensitivity:"base"}),W=class extends Error{status;constructor(e,t=400){super(e),this.name="WorkspaceFileError",this.status=t}};function Rt(r,e){let t=Ai(r,e);return t!==".."&&!t.startsWith(`..${Wi}`)&&!Nt(t)}async function tt(r,e){if(typeof e!="string"||e.length>4096||e.includes("\0")||e.includes("\\")||Nt(e)||Ni.isAbsolute(e))throw new W("\u5DE5\u4F5C\u533A\u6587\u4EF6\u8DEF\u5F84\u65E0\u6548");let t=await Mt(r),i=Ri(t,e);if(!Rt(t,i))throw new W("\u6587\u4EF6\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);let n=await Mt(i);if(!Rt(t,n))throw new W("\u6587\u4EF6\u4F4D\u4E8E\u5DE5\u4F5C\u533A\u4E4B\u5916",403);return n}async function Dt(r){try{return await r()}catch(e){if(e instanceof W)throw e;let t=e.code;throw t==="ENOENT"||t==="ENOTDIR"?new W("\u6587\u4EF6\u6216\u76EE\u5F55\u5DF2\u4E0D\u5B58\u5728",404):t==="EACCES"||t==="EPERM"?new W("\u6CA1\u6709\u6743\u9650\u8BFB\u53D6\u6587\u4EF6\u6216\u76EE\u5F55",403):e}}async function Ot(r,e){return Dt(async()=>{let t=await tt(r,e),i=[],n=!1;for await(let s of await Mi(t)){if(i.length===Di){n=!0;break}let a=e?`${e}/${s.name}`:s.name,l=s.isDirectory()?"directory":s.isFile()?"file":"other";if(s.isSymbolicLink())try{let p=await Wt(await tt(r,a));l=p.isDirectory()?"directory":p.isFile()?"file":"other"}catch{}i.push({name:s.name,path:a,kind:l})}return i.sort((s,a)=>+(a.kind==="directory")-+(s.kind==="directory")||Bi.compare(s.name,a.name)||s.name.localeCompare(a.name)),{path:e,entries:i,truncated:n}})}function $i(r){if(r.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])))return"image/png";if(r[0]===255&&r[1]===216&&r[2]===255)return"image/jpeg";if(["GIF87a","GIF89a"].includes(r.subarray(0,6).toString("ascii")))return"image/gif";if(r.subarray(0,4).toString("ascii")==="RIFF"&&r.subarray(8,12).toString("ascii")==="WEBP")return"image/webp"}async function be(r,e){return Dt(async()=>{let t=await tt(r,e);if(!(await Wt(t)).isFile())throw new W("\u8FD9\u4E0D\u662F\u53EF\u9884\u89C8\u7684\u666E\u901A\u6587\u4EF6");let i=await Ti(t,et.O_RDONLY|et.O_NONBLOCK|(et.O_NOFOLLOW??0));try{let n=await i.stat();if(!n.isFile())throw new W("\u8FD9\u4E0D\u662F\u53EF\u9884\u89C8\u7684\u666E\u901A\u6587\u4EF6");let s={path:e,size:n.size},a=Buffer.alloc(16);await i.read(a,0,a.length,0);let l=$i(a),p=l?Fi:Oi;if(n.size>p)return{...s,kind:"too-large",limit:p,unit:"bytes"};let h=Buffer.alloc(Math.min(n.size+1,p+1)),u=0;for(;u<h.length;){let{bytesRead:m}=await i.read(h,u,h.length-u,u);if(!m)break;u+=m}if(u>n.size)throw new W("\u6587\u4EF6\u6B63\u5728\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6",409);let c=h.subarray(0,u);if(l)return{...s,kind:"image",mimeType:l,data:c.toString("base64")};if(c.some(m=>m===0||m<32&&![9,10,12,13,27].includes(m)))return{...s,kind:"unsupported"};let f=1;for(let m=0;m<c.length-1;m++)if(c[m]===10&&++f>At)return{...s,kind:"too-large",limit:At,unit:"lines"};try{return{...s,kind:"text",text:new TextDecoder("utf-8",{fatal:!0}).decode(c)}}catch{return{...s,kind:"unsupported"}}}finally{await i.close()}})}var Gi=1e3,Ft=512*1024,Bt=1e4;function $t(r,e){return e.startsWith(r)&&e.slice(r.length)||void 0}async function pe(r){let e=await X(r);if(e.kind!=="repository")return e;let{root:t,scope:i}=e,n=await T(e.cwd,["status","--porcelain=v2","--branch","-z","--untracked-files=all","--","."]),s={kind:"repository",root:t,scope:i,branch:null,head:null,upstream:null,ahead:null,behind:null,entries:[],truncated:!1},a=n.split("\0");for(let l=0;l<a.length;l++){let p=a[l];if(p.startsWith("# branch.oid ")){let I=p.slice(13);s.head=I==="(initial)"?null:I;continue}if(p.startsWith("# branch.head ")){let I=p.slice(14);s.branch=I==="(detached)"?null:I;continue}if(p.startsWith("# branch.upstream ")){s.upstream=p.slice(18);continue}if(p.startsWith("# branch.ab ")){let I=p.match(/\+(\d+) -(\d+)/);I&&(s.ahead=Number(I[1]),s.behind=Number(I[2]));continue}let h=p[0];if(!["1","2","u","?"].includes(h??""))continue;let u=h==="?"?1:h==="1"?8:h==="2"?9:10,c=0;for(let I=0;I<u;I++)c=p.indexOf(" ",c)+1;let f=$t(i,p.slice(c)),m=h==="2"?a[++l]:void 0;if(!f)continue;if(s.entries.length===Gi){s.truncated=!0;continue}let g=p.slice(0,c).split(" "),E={path:f,index:h==="?"?"?":g[1][0],worktree:h==="?"?"?":g[1][1],conflict:h==="u",untracked:h==="?",submodule:h!=="?"&&g[2]!=="N..."},x=m===void 0?void 0:$t(i,m);x&&(E.originalPath=x),s.entries.push(E)}return s}async function jt(r,e,t){if(te(e),!["staged","unstaged","untracked"].includes(t))throw new P("Git \u5DEE\u5F02\u8303\u56F4\u65E0\u6548");let i=await pe(r);if(i.kind!=="repository")throw new P("\u5F53\u524D\u5DE5\u4F5C\u533A\u6CA1\u6709\u53EF\u8BFB\u53D6\u7684 Git \u4ED3\u5E93",404);let n={path:e,area:t},s=i.entries.find(l=>l.path===e);if(!s)return{...n,kind:"empty"};if(s.conflict)return{...n,kind:"conflict"};if(s.submodule)return{...n,kind:"submodule"};if(t==="untracked"){if(!s.untracked)return{...n,kind:"empty"};if(!(await ji(Li(r,e))).isFile())return{...n,kind:"unsupported"};let l=await be(r,e);if(l.kind==="too-large")return{...n,kind:"too-large"};if(l.kind!=="text")return{...n,kind:"binary"};if(!l.text)return{...n,kind:"empty"};let p=l.text.split(`
|
|
2
2
|
`),h=p.at(-1)==="";h&&p.pop();let u=`--- /dev/null
|
|
3
3
|
+++ b/${e.replace(/[\r\n]/g," ")}
|
|
4
4
|
@@ -0,0 +1,${p.length} @@
|
|
@@ -25,7 +25,7 @@ ${h.stack.split(`
|
|
|
25
25
|
`).slice(1).join(`
|
|
26
26
|
`)}`);let c=this.reportError(u,{...s,stage:"provider_login"});p.view={id:l,providerId:e,method:t,status:"error",error:"\u767B\u5F55\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u63D0\u4F9B\u65B9\u63D0\u793A\u5E76\u91CD\u8BD5\u3002",errorId:c}}}),{...p.view}}get(e){let t=this.flows.get(e)?.view;return t?{...t}:void 0}getActive(){let e=[...this.flows.values()].find(({view:t})=>t.status==="running"||t.status==="waiting")?.view;return e?{...e}:void 0}respond(e,t){let i=this.flows.get(e);if(!i?.answer||i.view.status!=="waiting"||i.view.prompt?.type==="select"&&!i.view.prompt.options.some(s=>s.id===t))return!1;let n=i.answer;return i.answer=void 0,i.reject=void 0,i.view={...i.view,status:"running",prompt:void 0},n(t),!0}cancel(e){let t=this.flows.get(e);return!t||t.view.status==="done"||t.view.status==="error"?!1:(t.view={...t.view,status:"cancelled",prompt:void 0},t.controller.abort(),t.reject?.(new Error("\u767B\u5F55\u5DF2\u53D6\u6D88")),t.answer=void 0,t.reject=void 0,!0)}close(){for(let e of this.flows.keys())this.cancel(e);this.flows.clear()}};import{randomBytes as Un}from"node:crypto";import{readFile as zn,rename as Hn,rm as Jn,stat as qn,writeFile as Kn,mkdir as Xn}from"node:fs/promises";import{dirname as Yn}from"node:path";var Zn=["openai-completions","openai-responses","anthropic-messages"];function dt(r){if(!r||typeof r!="object")return!1;let e=r;if(typeof e.id!="string"||!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(e.id)||typeof e.name!="string"||!e.name.trim()||e.name.length>100||typeof e.modelId!="string"||!e.modelId.trim()||e.modelId.length>200||!Zn.includes(e.api)||typeof e.baseUrl!="string"||e.baseUrl.length>2048)return!1;try{let t=new URL(e.baseUrl);return(t.protocol==="https:"||t.protocol==="http:")&&!!t.hostname&&!t.username&&!t.password&&!t.hash}catch{return!1}}async function Mr(r,e){if(!dt(e))throw new Error("\u81EA\u5B9A\u4E49\u63D0\u4F9B\u65B9\u540D\u79F0\u3001\u5730\u5740\u6216\u6A21\u578B\u65E0\u6548");let t;try{t=await zn(r,"utf8")}catch(l){if(l.code!=="ENOENT")throw l}let i;if(t===void 0)i={providers:{}};else{try{i=JSON.parse(t)}catch{throw new Error("models.json \u542B\u6CE8\u91CA\u6216\u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u624B\u52A8\u6DFB\u52A0\u63D0\u4F9B\u65B9")}if(!i||typeof i!="object"||!i.providers||typeof i.providers!="object"||Array.isArray(i.providers))throw new Error("models.json \u7ED3\u6784\u65E0\u6548")}if(Object.hasOwn(i.providers,e.id))throw new Error("\u63D0\u4F9B\u65B9\u5DF2\u5B58\u5728");let n={...i,providers:{...i.providers,[e.id]:{name:e.name.trim(),baseUrl:e.baseUrl,api:e.api,models:[{id:e.modelId.trim()}]}}};await Xn(Yn(r),{recursive:!0});let s=t===void 0?384:(await qn(r)).mode&511,a=`${r}.pi-web-${Un(6).toString("hex")}.tmp`;try{await Kn(a,`${JSON.stringify(n,null,2)}
|
|
27
27
|
`,{mode:s,flag:"wx"}),await Hn(a,r)}finally{await Jn(a,{force:!0})}}import{randomBytes as Qn}from"node:crypto";import{mkdir as es,readFile as ts,rename as rs,rm as is,stat as ns,writeFile as ss}from"node:fs/promises";import{dirname as os}from"node:path";function Ar(r){if(!r||r.length>2048)return!1;try{let e=new URL(r);return(e.protocol==="https:"||e.protocol==="http:")&&!!e.hostname&&!e.username&&!e.password&&!e.search&&!e.hash}catch{return!1}}function Rr(r){if(!r||typeof r!="object")return!1;let e=r;return e.action==="save"?(e.originalId===void 0||typeof e.originalId=="string")&&Wr(e.model):e.action==="base_url"?e.baseUrl===null||typeof e.baseUrl=="string"&&Ar(e.baseUrl):e.action==="remove"&&typeof e.id=="string"&&e.id.length>0&&e.id.length<=200}function Wr(r){if(!r||typeof r!="object")return!1;let e=r;if(typeof e.id!="string"||!e.id.trim()||e.id.length>200||e.name!==void 0&&(typeof e.name!="string"||!e.name.trim()||e.name.length>200))return!1;for(let t of[e.contextWindow,e.maxTokens])if(t!==void 0&&(!Number.isSafeInteger(t)||t<=0))return!1;return e.input===void 0||Array.isArray(e.input)&&e.input.length>0&&e.input.every(t=>t==="text"||t==="image")&&new Set(e.input).size===e.input.length}async function Nr(r){let e;try{e=await ts(r,"utf8")}catch(i){if(i.code!=="ENOENT")throw i}if(e===void 0)return{config:{providers:{}}};let t;try{t=JSON.parse(e)}catch{throw new Error("models.json \u542B\u6CE8\u91CA\u6216\u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u624B\u52A8\u4FEE\u6539")}if(!t||typeof t!="object"||!t.providers||typeof t.providers!="object"||Array.isArray(t.providers))throw new Error("models.json \u7ED3\u6784\u65E0\u6548");return{config:t,existing:e}}async function as(r,e,t){await es(os(r),{recursive:!0});let i=t===void 0?384:(await ns(r)).mode&511,n=`${r}.pi-web-${Qn(6).toString("hex")}.tmp`;try{await ss(n,`${JSON.stringify(e,null,2)}
|
|
28
|
-
`,{mode:i,flag:"wx"}),await rs(n,r)}finally{await is(n,{force:!0})}}async function Dr(r,e,t){if(!t.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:i}=await Nr(r),n=i.providers[e],s=new Set(n?.models?.map(a=>a.id)??[]);return{providerId:e,baseUrl:n?.baseUrl,models:t.getModels(e).map(a=>({id:a.id,name:a.name,contextWindow:a.contextWindow,maxTokens:a.maxTokens,input:[...a.input],source:s.has(a.id)?"custom":"builtin",overridden:!!n?.modelOverrides?.[a.id]}))}}async function Or(r,e,t,i){if(!i.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:n,existing:s}=await Nr(r),a={...n.providers[e]??{}},l=[...a.models??[]],p={...a.modelOverrides??{}};if(t.action==="base_url"){if(t.baseUrl!==null&&!Ar(t.baseUrl))throw new Error("API \u5730\u5740\u65E0\u6548");t.baseUrl===null?delete a.baseUrl:a.baseUrl=t.baseUrl}else if(t.action==="save"){if(!Wr(t.model))throw new Error("\u6A21\u578B\u53C2\u6570\u65E0\u6548");let h={id:t.model.id.trim(),...t.model.name===void 0?{}:{name:t.model.name},...t.model.contextWindow===void 0?{}:{contextWindow:t.model.contextWindow},...t.model.maxTokens===void 0?{}:{maxTokens:t.model.maxTokens},...t.model.input===void 0?{}:{input:t.model.input}},u=t.originalId,c=u===void 0?-1:l.findIndex(f=>f.id===u);if(u===void 0&&(l.some(f=>f.id===h.id)||i.getModel(e,h.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");if(c>=0){if(h.id!==u&&(l.some(m=>m.id===h.id)||i.getModel(e,h.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");let f={...l[c],...h};for(let m of["name","contextWindow","maxTokens","input"])h[m]===void 0&&delete f[m];l[c]=f}else if(u!==void 0&&i.getModel(e,u)){if(h.id!==u)throw new Error("\u5185\u7F6E\u6A21\u578B ID \u4E0D\u53EF\u4FEE\u6539");let{id:f,...m}=h;p[u]={...p[u],...m};for(let g of["name","contextWindow","maxTokens","input"])h[g]===void 0&&delete p[u][g]}else{if(u!==void 0)throw new Error("\u6A21\u578B\u4E0D\u5B58\u5728");l.push(h)}}else{let h=l.findIndex(u=>u.id===t.id);if(h>=0)l.splice(h,1);else if(Object.hasOwn(p,t.id))delete p[t.id];else throw new Error("\u53EA\u80FD\u79FB\u9664\u81EA\u5B9A\u4E49\u6A21\u578B\u6216\u6062\u590D\u5DF2\u4FEE\u6539\u7684\u5185\u7F6E\u6A21\u578B")}l.length?a.models=l:delete a.models,Object.keys(p).length?a.modelOverrides=p:delete a.modelOverrides,Object.keys(a).length?n.providers[e]=a:delete n.providers[e],await as(r,n,s)}function Fr(r){return/^(?:npm:|git:|https?:\/\/|ssh:\/\/|git@)/i.test(r.trim())}import{randomBytes as Br,createHash as cs}from"node:crypto";import{fileURLToPath as ls}from"node:url";var Be="pi-webapp@0.1.
|
|
28
|
+
`,{mode:i,flag:"wx"}),await rs(n,r)}finally{await is(n,{force:!0})}}async function Dr(r,e,t){if(!t.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:i}=await Nr(r),n=i.providers[e],s=new Set(n?.models?.map(a=>a.id)??[]);return{providerId:e,baseUrl:n?.baseUrl,models:t.getModels(e).map(a=>({id:a.id,name:a.name,contextWindow:a.contextWindow,maxTokens:a.maxTokens,input:[...a.input],source:s.has(a.id)?"custom":"builtin",overridden:!!n?.modelOverrides?.[a.id]}))}}async function Or(r,e,t,i){if(!i.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:n,existing:s}=await Nr(r),a={...n.providers[e]??{}},l=[...a.models??[]],p={...a.modelOverrides??{}};if(t.action==="base_url"){if(t.baseUrl!==null&&!Ar(t.baseUrl))throw new Error("API \u5730\u5740\u65E0\u6548");t.baseUrl===null?delete a.baseUrl:a.baseUrl=t.baseUrl}else if(t.action==="save"){if(!Wr(t.model))throw new Error("\u6A21\u578B\u53C2\u6570\u65E0\u6548");let h={id:t.model.id.trim(),...t.model.name===void 0?{}:{name:t.model.name},...t.model.contextWindow===void 0?{}:{contextWindow:t.model.contextWindow},...t.model.maxTokens===void 0?{}:{maxTokens:t.model.maxTokens},...t.model.input===void 0?{}:{input:t.model.input}},u=t.originalId,c=u===void 0?-1:l.findIndex(f=>f.id===u);if(u===void 0&&(l.some(f=>f.id===h.id)||i.getModel(e,h.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");if(c>=0){if(h.id!==u&&(l.some(m=>m.id===h.id)||i.getModel(e,h.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");let f={...l[c],...h};for(let m of["name","contextWindow","maxTokens","input"])h[m]===void 0&&delete f[m];l[c]=f}else if(u!==void 0&&i.getModel(e,u)){if(h.id!==u)throw new Error("\u5185\u7F6E\u6A21\u578B ID \u4E0D\u53EF\u4FEE\u6539");let{id:f,...m}=h;p[u]={...p[u],...m};for(let g of["name","contextWindow","maxTokens","input"])h[g]===void 0&&delete p[u][g]}else{if(u!==void 0)throw new Error("\u6A21\u578B\u4E0D\u5B58\u5728");l.push(h)}}else{let h=l.findIndex(u=>u.id===t.id);if(h>=0)l.splice(h,1);else if(Object.hasOwn(p,t.id))delete p[t.id];else throw new Error("\u53EA\u80FD\u79FB\u9664\u81EA\u5B9A\u4E49\u6A21\u578B\u6216\u6062\u590D\u5DF2\u4FEE\u6539\u7684\u5185\u7F6E\u6A21\u578B")}l.length?a.models=l:delete a.models,Object.keys(p).length?a.modelOverrides=p:delete a.modelOverrides,Object.keys(a).length?n.providers[e]=a:delete n.providers[e],await as(r,n,s)}function Fr(r){return/^(?:npm:|git:|https?:\/\/|ssh:\/\/|git@)/i.test(r.trim())}import{randomBytes as Br,createHash as cs}from"node:crypto";import{fileURLToPath as ls}from"node:url";var Be="pi-webapp@0.1.23+1664a9ed3950b02e5082",K="1664a9ed3950b02e5082";var ds="https://070c0b7c5ac18d940c294e63ecfa0793@o4506663318716416.ingest.us.sentry.io/4512191040716800";function ps(r=process.env,e=console.warn){let t=i=>{let n={enabled:!1,environment:r.PI_WEB_SENTRY_ENVIRONMENT||"production",release:Be,buildId:K},s=r[`PI_WEB_SENTRY_${i}_DSN`]??r.PI_WEB_SENTRY_DSN??ds;if(r.PI_WEB_SENTRY_ENABLED==="false"||!s)return n;try{let a=new URL(s);if(a.protocol!=="https:"||!/^[\w-]+$/.test(a.username)||a.password||a.search||a.hash||!/\/(?:[\w-]+\/)*\d+$/.test(a.pathname))throw new Error;return{...n,enabled:!0,dsn:s}}catch{return e(`pi-webapp: invalid ${i.toLowerCase()} Sentry DSN; error reporting disabled for this side.`),n}};return{browser:t("BROWSER"),node:t("NODE")}}var Z=class{config;ready;reporter;client;salt=Br(16);breadcrumbs=new Ee;seen=new WeakSet;early=[];state={nodeVersion:process.version,platform:process.platform};fatal;closed=!1;failed=!1;get enabled(){return this.config.node.enabled&&!this.closed&&!this.failed}constructor(e={}){if(this.config=ps(e.env),!this.config.node.enabled){this.ready=Promise.resolve();return}if(e.monitor!==!1){let t=ls(import.meta.url).replace(/\\/g,"/"),i=t.lastIndexOf("/src/"),n=i>=0?t.slice(0,i+5):t.slice(0,t.lastIndexOf("/")+1);this.fatal=s=>{s.stack?.replace(/\\/g,"/").includes(t.endsWith("extension.js")?t:n)&&this.capture(s,{stage:"fatal"})},process.on("uncaughtExceptionMonitor",this.fatal)}this.ready=import("@sentry/node").then(t=>{if(!this.closed){this.client=new t.NodeClient({...this.config.node,dist:K,integrations:[],transport:e.transport??(i=>or(t.createTransport,i)),stackParser:t.defaultStackParser,beforeSend:sr,sendClientReports:!1,dataCollection:{...rr,httpBodies:[]},includeServerName:!1,enableRuntimeChannelInjection:!1,beforeSendLog:()=>null,beforeSendMetric:()=>null,enableOpenTelemetrySetup:!1,maxBreadcrumbs:100}),this.reporter=new Me(this.client,"node",K,t,this.breadcrumbs),this.reporter.setState(this.state);for(let i of this.early)this.reporter.capture(i.error,i.context,i.eventId)}}).catch(()=>{this.failed=!0,console.warn("pi-webapp: Sentry initialization failed; error reporting disabled.")}).finally(()=>{this.early=[]})}capture(e,t={}){try{if(!this.enabled||re(e))return;if(typeof e=="object"&&e!==null){if(this.seen.has(e))return;this.seen.add(e)}if(this.reporter)return this.reporter.capture(e,t);if(this.early.length>=20)return;let i=Br(16).toString("hex");return this.early.push({error:ue(e),context:q(t),eventId:i}),i}catch{return}}setState(e){this.state=q({...this.state,...e}),this.reporter?.setState(this.state)}breadcrumb(e,t={}){this.enabled&&this.breadcrumbs.add(e,t)}session(e){return cs("sha256").update(this.salt).update(e).digest("hex").slice(0,16)}async flush(e=3e3){await this.ready;try{return this.enabled&&!!await this.client?.flush(e)}catch{return!1}}async close(){let e=performance.now(),t;try{await Promise.race([this.ready,new Promise(i=>{t=setTimeout(i,500)})])}finally{clearTimeout(t),this.closed=!0,this.fatal&&process.off("uncaughtExceptionMonitor",this.fatal)}try{await this.client?.close(Math.max(1,500-(performance.now()-e)))}catch{}}};import{VERSION as bs}from"@earendil-works/pi-coding-agent";import{readFile as us}from"node:fs/promises";import{join as fs}from"node:path";async function $r(r){try{let e=JSON.parse(await us(fs(r,".vite/manifest.json"),"utf8"));if(!e||typeof e!="object")return{};let t=new Set;for(let n of Object.values(e))if(!(!n||typeof n!="object"))for(let s of[n.file,...Array.isArray(n.css)?n.css:[],...Array.isArray(n.assets)?n.assets:[]])typeof s=="string"&&/^assets\/[\w.-]+\.(?:js|css|woff2?|ttf|png|jpe?g|svg|webp)$/.test(s)&&t.add(s);let i={js:"text/javascript; charset=utf-8",css:"text/css; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf"};return Object.fromEntries([...t].map(n=>[`/${n}`,{path:n,type:i[n.split(".").pop()]}]))}catch{return{}}}var vs={"/":{path:"index.html",type:"text/html; charset=utf-8"},"/assets/app.js":{path:"assets/app.js",type:"text/javascript; charset=utf-8"},"/assets/style.css":{path:"assets/style.css",type:"text/css; charset=utf-8"}};function y(r,e,t){typeof t=="object"&&t!==null&&"error"in t&&(t={errorCode:e>=500?"server_error":"validation_error",...t,requestId:r.getHeader("X-Request-ID"),operationId:r.getHeader("X-Operation-ID")}),r.writeHead(e,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),r.end(JSON.stringify(t))}function ks(r,e){let t=r.headers.authorization;if(typeof t!="string"||!t.startsWith("Bearer "))return!1;let i=Buffer.from(t.slice(7),"utf8");return i.length===e.length&&ms(i,e)}async function Es(r){let e=0,t=[];for await(let i of r){let n=Buffer.isBuffer(i)?i:Buffer.from(i);if(e+=n.length,e>64*1024)throw new Error("\u8BF7\u6C42\u5185\u5BB9\u8FC7\u5927");t.push(n)}return JSON.parse(Buffer.concat(t).toString("utf8"))}async function Ps(r){let e=0,t=[];for await(let i of r){let n=Buffer.isBuffer(i)?i:Buffer.from(i);if(e+=n.length,e>Oe)throw new Error("\u6587\u4EF6\u8D85\u8FC7 20 MB");t.push(n)}return Buffer.concat(t)}async function Ss(r,e=0){await new Promise((i,n)=>{r.once("error",n),r.listen(e,"127.0.0.1",()=>{r.off("error",n),i()})});let t=r.address();if(t===null||typeof t=="string")throw new Error("\u65E0\u6CD5\u786E\u5B9A\u76D1\u542C\u7AEF\u53E3");return t.port}async function Lr(r,e,t=new Z,i={}){t.setState({piVersion:bs});let n=process.env.PI_WEBAPP_RESTART_TOKEN,s=n&&/^[A-Za-z0-9_-]{32}$/.test(n)?n:jr(24).toString("base64url"),a=Buffer.from(s),l=Pr(),p=new Set,h=new We(i.pluginSettingsFile??ut(ys(),"pi-web","plugins.json"));try{await h.load()}catch(b){throw await t.close(),b}let u=new Ne(gr(),h),c=async()=>await r.plugins?.()??{plugins:[],errors:[]},f=()=>({type:"plugin_state",disabled:u.plugins.filter(b=>!h.enabled(b.metadata.id)).map(b=>b.metadata.id)}),m=()=>{for(let b of p)b.write(`${JSON.stringify(f())}
|
|
29
29
|
`)},g=new Map,E=new Fe((b,w)=>t.capture(b,w)),x=b=>t.setState({nodeVersion:process.version,platform:process.platform,session:t.session(b.sessionId),idle:b.idle,model:b.model,thinkingLevel:b.thinkingLevel,messageCount:b.messages.length}),I="",J=!1,Q={...vs,...await $r(e)};for(let b of await hs(ut(e,"assets")).catch(()=>[])){let w=/^[\w.-]+\.(js|css|woff2?|ttf)$/.exec(b);if(!w)continue;let U={js:"text/javascript; charset=utf-8",css:"text/css; charset=utf-8",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf"};Q[`/assets/${b}`]={path:`assets/${b}`,type:U[w[1]]}}let ce=ws(async(b,w)=>{let U=jr(18).toString("base64"),le=j=>typeof j=="string"&&/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(j),we=le(b.headers["x-request-id"])?b.headers["x-request-id"]:pt(),B={requestId:we,operationId:le(b.headers["x-operation-id"])?b.headers["x-operation-id"]:void 0};w.setHeader("X-Request-ID",we),B.operationId&&w.setHeader("X-Operation-ID",B.operationId);let k="/",Pi=performance.now(),$=(j,d,v)=>{let C=!re(j)&&ir(k)?Y(j,"Agent or provider operation failed"):j,A=t.capture(C,{...B,route:k,method:b.method,status:d,stage:"http"});y(w,d,{error:v,errorId:A,errorReported:t.enabled,errorCode:re(j)?"validation_error":"unexpected_error"})};w.once("finish",()=>{k.startsWith("/api/telemetry/")||t.breadcrumb("request",{...B,route:k,method:b.method,status:w.statusCode,durationMs:Math.round(performance.now()-Pi)})});try{w.setHeader("X-Content-Type-Options","nosniff"),w.setHeader("Referrer-Policy","no-referrer"),w.setHeader("Content-Security-Policy",`default-src 'self'; script-src 'self'; style-src 'self' 'nonce-${U}'; style-src-attr 'unsafe-inline'; font-src 'self' data:; connect-src 'self'${t.config.browser.dsn?` ${new URL(t.config.browser.dsn).origin}`:""}; img-src 'self' data: blob:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'`);try{k=new URL(b.url??"/",I).pathname}catch{y(w,400,{error:"\u8BF7\u6C42\u5730\u5740\u65E0\u6548"});return}let j=Q[k];if(b.method==="GET"&&j){try{let d=await gs(ut(e,j.path));w.writeHead(200,{"Content-Type":j.type,"Cache-Control":"no-store"}),w.end(k==="/"?d.toString("utf8").replace("<head>",`<head><meta name="pi-style-nonce" content="${U}">`):d)}catch(d){$(d,500,"\u9875\u9762\u6587\u4EF6\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k.startsWith("/plugins/")){try{let d=await r.pluginAsset?.(b.url??k);if(!d){y(w,404,{error:"\u63D2\u4EF6\u8D44\u6E90\u4E0D\u5B58\u5728"});return}w.writeHead(200,{"Content-Type":d.type,"Cache-Control":"no-store"}),w.end(d.bytes)}catch(d){$(d,404,"\u63D2\u4EF6\u8D44\u6E90\u4E0D\u53EF\u7528")}return}if(!k.startsWith("/api/")){y(w,404,{error:"\u672A\u627E\u5230"});return}if(!ks(b,a)){y(w,401,{error:"\u8BBF\u95EE\u4EE4\u724C\u65E0\u6548"});return}if(b.method==="GET"&&k==="/api/telemetry/config"){y(w,200,t.config.browser);return}if(b.method==="GET"&&k==="/api/update/version"){try{y(w,200,{current:await r.selfUpdate?.runningVersion()??null})}catch(d){$(d,503,d instanceof Error?d.message:"\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C")}return}if(b.method==="GET"&&k==="/api/update"){try{y(w,200,await r.selfUpdate?.check()??{canRestart:!1,reason:"\u5F53\u524D\u6269\u5C55\u4E0D\u652F\u6301\u5728\u7EBF\u5347\u7EA7"})}catch(d){$(d,503,d instanceof Error?d.message:"\u68C0\u67E5\u66F4\u65B0\u5931\u8D25")}return}if(b.method==="GET"&&k==="/api/image"){let d=new URL(b.url??k,I),v=d.searchParams.get("sessionId")??"",_=d.searchParams.get("messageId")??"",C=Number(d.searchParams.get("index"));if(!v||v!==r.snapshot().sessionId||!_||!Number.isInteger(C)||C<0||C>100){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u56FE\u7247\u5730\u5740\u65E0\u6548"});return}let A=r.image?.(v,_,C);if(!A||!["image/png","image/jpeg","image/webp","image/gif"].includes(A.mimeType)){y(w,404,{error:"\u56FE\u7247\u4E0D\u53EF\u7528"});return}w.writeHead(200,{"Content-Type":A.mimeType,"Cache-Control":"private, no-store"}),w.end(A.data);return}if(b.method==="POST"&&k==="/api/attachment"){if(b.headers.origin!==void 0&&b.headers.origin!==I){y(w,403,{error:"\u6765\u6E90\u4E0D\u5339\u914D"});return}let d=new URL(b.url??k,I),v=d.searchParams.get("sessionId"),_=d.searchParams.get("name");try{if(!v||!_||_.length>1024||v!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u6587\u4EF6\u540D\u65E0\u6548"});return}if(Number(b.headers["content-length"]??0)>Oe){y(w,413,{error:"\u6587\u4EF6\u8D85\u8FC7 20 MB"});return}let C=await Cr(v,_,b.headers["content-type"]??"application/octet-stream",await Ps(b));if(v!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}g.set(C.id,C),y(w,201,{id:C.id,name:C.name,bytes:C.bytes})}catch(C){$(C,400,C instanceof Error?C.message:"\u4E0A\u4F20\u5931\u8D25")}return}if(b.method==="GET"&&k==="/api/session"){try{let d=r.snapshot();x(d),y(w,200,d)}catch(d){$(d,503,"\u5F53\u524D\u4F1A\u8BDD\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/plugin-management"){try{y(w,200,u.inventory(await c()))}catch(d){$(d,503,"\u63D2\u4EF6\u76EE\u5F55\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/plugins"){try{y(w,200,u.catalog(await c()))}catch(d){$(d,503,"\u63D2\u4EF6\u76EE\u5F55\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/providers"){try{y(w,200,await r.providers?.()??[])}catch(d){$(d,503,"\u6A21\u578B\u63D0\u4F9B\u65B9\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/provider/models"){let d=new URL(b.url??k,I).searchParams.get("providerId")??"";try{if(!d||!r.providerModels){y(w,400,{error:"\u63D0\u4F9B\u65B9\u65E0\u6548"});return}y(w,200,await r.providerModels(d))}catch(v){$(v,400,v instanceof Error?v.message:"\u6A21\u578B\u76EE\u5F55\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/provider/login/active"){y(w,200,{active:E.getActive()??null});return}if(b.method==="GET"&&k==="/api/provider/login"){let d=new URL(b.url??k,I).searchParams.get("id")??"",v=E.get(d);y(w,v?200:404,v??{error:"\u767B\u5F55\u6D41\u7A0B\u4E0D\u5B58\u5728"});return}if(b.method==="GET"&&(k==="/api/models"||k==="/api/config"||k==="/api/workspaces"||k==="/api/commands")){try{y(w,200,k==="/api/models"?await r.models():k==="/api/config"?await r.config():k==="/api/commands"?r.commands?.()??[]:await r.workspaces())}catch(d){$(d,503,"Pi \u914D\u7F6E\u4E0D\u53EF\u7528")}return}if(b.method==="GET"&&k==="/api/directory/capability"){y(w,200,{kind:l});return}if(b.method==="GET"&&k==="/api/events"){let d;try{d=r.snapshot(),x(d)}catch(v){$(v,503,"\u5F53\u524D\u4F1A\u8BDD\u4E0D\u53EF\u7528");return}w.writeHead(200,{"Content-Type":"application/x-ndjson; charset=utf-8","Cache-Control":"no-store",Connection:"keep-alive","X-Accel-Buffering":"no"}),p.add(w),w.write(`${JSON.stringify({type:"snapshot",session:d})}
|
|
30
30
|
`),w.on("close",()=>p.delete(w));return}if(b.method==="POST"&&[...u.routes,"/api/plugin-management","/api/plugin-interaction","/api/plugin-action","/api/update","/api/message","/api/attachment/remove","/api/abort","/api/resume","/api/compact","/api/new-session","/api/model","/api/thinking-level","/api/config","/api/provider/login","/api/provider/login/respond","/api/provider/login/cancel","/api/provider/custom","/api/provider/models","/api/provider/logout","/api/workspace/add","/api/workspace/select","/api/workspace/new-session","/api/workspace/remove","/api/session/select","/api/directory/list","/api/directory/create","/api/directory/pick"].includes(k)){if(b.headers.origin!==void 0&&b.headers.origin!==I){y(w,403,{error:"\u6765\u6E90\u4E0D\u5339\u914D"});return}if(!b.headers["content-type"]?.startsWith("application/json")){y(w,415,{error:"\u9700\u8981 JSON \u8BF7\u6C42"});return}try{let d;try{d=await Es(b)}catch(v){if(v instanceof SyntaxError||re(v)){y(w,400,{error:"\u8BF7\u6C42\u5185\u5BB9\u65E0\u6548"});return}throw v}if(typeof d!="object"||d===null||!("sessionId"in d)||typeof d.sessionId!="string"){y(w,400,{error:"\u7F3A\u5C11\u4F1A\u8BDD\u6807\u8BC6"});return}if(k==="/api/plugin-management"){let v=d;if(typeof v.id!="string"||v.id.length>200||typeof v.enabled!="boolean"||typeof v.expected!="string"){y(w,400,{error:"\u63D2\u4EF6\u5F00\u5173\u53C2\u6570\u65E0\u6548"});return}let _=()=>{if(r.snapshot().sessionId!==d.sessionId)throw new N("\u4F1A\u8BDD\u5DF2\u5207\u6362");if(!r.snapshot().idle||(r.busyGitWorkspaces?.()??[]).length)throw new N("\u8BF7\u7B49\u5F85\u6240\u6709\u804A\u5929\u7A7A\u95F2\u540E\u4FEE\u6539\u5168\u5C40\u63D2\u4EF6\u5F00\u5173")};try{await u.toggle(v.id,v.enabled,v.expected,_),y(w,200,u.inventory(await c()))}catch(C){if(C instanceof N)y(w,C.status,{error:C.message});else throw C}finally{m()}return}if(u.mutating&&k!=="/api/abort"){y(w,409,{error:"\u63D2\u4EF6\u914D\u7F6E\u6B63\u5728\u4FDD\u5B58\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"});return}if(await u.dispatch({path:k,body:d,res:w,snapshot:()=>r.snapshot(),busyWorkspaces:()=>r.busyGitWorkspaces?.()??[],json:(v,_)=>y(w,v,_)}))return;if(k==="/api/plugin-interaction"){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("pluginId"in d)||typeof d.pluginId!="string"||d.pluginId.length>200||!("requestId"in d)||typeof d.requestId!="string"||d.requestId.length>200||!r.resolvePluginInteraction||!("value"in d)){y(w,400,{error:"\u63D2\u4EF6\u4EA4\u4E92\u54CD\u5E94\u65E0\u6548"});return}await u.coordinateStart(r.snapshot().cwd,async()=>r.resolvePluginInteraction(d.sessionId,d.pluginId,d.requestId,d.value)),y(w,200,{accepted:!0});return}if(k==="/api/plugin-action"){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("pluginId"in d)||typeof d.pluginId!="string"||d.pluginId.length>200||!("action"in d)||typeof d.action!="string"||d.action.length>100){y(w,400,{error:"\u63D2\u4EF6\u52A8\u4F5C\u65E0\u6548"});return}if(u.plugins.some(C=>C.metadata.id===d.pluginId)){let C=u.actionRoute(d.pluginId,d.action);if(!C){y(w,400,{error:"\u63D2\u4EF6\u52A8\u4F5C\u4E0D\u5B58\u5728"});return}let A="input"in d?d.input:{};if(!A||typeof A!="object"||Array.isArray(A)){y(w,400,{error:"\u63D2\u4EF6\u52A8\u4F5C\u53C2\u6570\u65E0\u6548"});return}await u.dispatch({path:C,body:{...A,sessionId:d.sessionId},res:w,snapshot:()=>r.snapshot(),busyWorkspaces:()=>r.busyGitWorkspaces?.()??[],json:(ye,R)=>y(w,ye,ye>=200&&ye<300?{value:R}:R)});return}if(!r.invokePluginAction){y(w,400,{error:"\u63D2\u4EF6\u52A8\u4F5C\u4E0D\u53EF\u7528"});return}let _=await u.coordinateStart(r.snapshot().cwd,async()=>r.invokePluginAction(d.sessionId,d.pluginId,d.action,"input"in d?d.input:void 0));y(w,200,{value:_});return}if(k==="/api/update"){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!r.snapshot().idle){y(w,409,{error:"\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u540E\u518D\u5347\u7EA7"});return}if(!r.selfUpdate){y(w,409,{error:"\u5F53\u524D\u6269\u5C55\u4E0D\u652F\u6301\u5728\u7EBF\u5347\u7EA7"});return}let v=await r.selfUpdate.prepare();J=!0,y(w,202,{accepted:!0,version:v.version}),setTimeout(()=>{r.selfUpdate?.requestRestart(v).catch(_=>{J=!1,t.capture(_,{stage:"restart"}),console.error("pi-webapp restart:",_)})},500).unref();return}if(k==="/api/provider/custom"){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("provider"in d)||!dt(d.provider)||!r.addCustomProvider){y(w,400,{error:"\u81EA\u5B9A\u4E49\u63D0\u4F9B\u65B9\u65E0\u6548"});return}await r.addCustomProvider(d.sessionId,d.provider),y(w,201,{accepted:!0});return}if(k==="/api/provider/models"||k==="/api/provider/logout"){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("providerId"in d)||typeof d.providerId!="string"){y(w,400,{error:"\u63D0\u4F9B\u65B9\u65E0\u6548"});return}if(k==="/api/provider/models"){if(!("change"in d)||!Rr(d.change)||!r.updateProviderModel){y(w,400,{error:"\u6A21\u578B\u53C2\u6570\u65E0\u6548"});return}await r.updateProviderModel(d.sessionId,d.providerId,d.change)}else{if(!r.logoutProvider){y(w,400,{error:"\u65E0\u6CD5\u79FB\u9664\u8BA4\u8BC1"});return}await r.logoutProvider(d.sessionId,d.providerId)}y(w,200,{accepted:!0});return}if(k.startsWith("/api/provider/login")){if(d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(k==="/api/provider/login"){if(!("providerId"in d)||typeof d.providerId!="string"||!("method"in d)||d.method!=="api_key"&&d.method!=="oauth"||!r.loginProvider||!r.providers){y(w,400,{error:"\u767B\u5F55\u65B9\u5F0F\u65E0\u6548"});return}if(!(await r.providers()).some(A=>A.id===d.providerId&&A.methods.includes(d.method))){y(w,400,{error:"\u63D0\u4F9B\u65B9\u4E0D\u652F\u6301\u6B64\u767B\u5F55\u65B9\u5F0F"});return}let _="initialSecret"in d?d.initialSecret:void 0;if(_!==void 0&&(d.method!=="api_key"||typeof _!="string"||!_.trim()||_.length>16384)){y(w,400,{error:"API Key \u65E0\u6548"});return}let C=E.start(d.providerId,d.method,r.loginProvider,_,B);y(w,202,{id:C.id});return}if(!("id"in d)||typeof d.id!="string"){y(w,400,{error:"\u767B\u5F55\u6D41\u7A0B\u65E0\u6548"});return}if(k==="/api/provider/login/cancel"){y(w,E.cancel(d.id)?202:404,{accepted:!0});return}if(!("value"in d)||typeof d.value!="string"||d.value.length>16384||!E.respond(d.id,d.value)){y(w,400,{error:"\u767B\u5F55\u8F93\u5165\u65E0\u6548"});return}y(w,202,{accepted:!0});return}if(k==="/api/attachment/remove"){if(!("id"in d)||typeof d.id!="string"||d.sessionId!==r.snapshot().sessionId){y(w,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u9644\u4EF6\u65E0\u6548"});return}g.get(d.id)?.sessionId===d.sessionId&&g.delete(d.id),y(w,202,{accepted:!0});return}if(k==="/api/directory/pick"){if(l!=="native"){y(w,409,{error:"\u672C\u5730\u76EE\u5F55\u9009\u62E9\u5668\u4E0D\u53EF\u7528"});return}let v=new AbortController;w.once("close",()=>v.abort()),y(w,200,{path:await Sr(v.signal)});return}if(k==="/api/directory/list"){if("path"in d&&(typeof d.path!="string"||d.path.length>4096)){y(w,400,{error:"\u76EE\u5F55\u8DEF\u5F84\u65E0\u6548"});return}y(w,200,await kr("path"in d?d.path:void 0));return}if(k==="/api/directory/create"){if(!("path"in d)||typeof d.path!="string"||d.path.length>4096||!("name"in d)||typeof d.name!="string"||d.name.length>255){y(w,400,{error:"\u6587\u4EF6\u5939\u540D\u79F0\u6216\u8DEF\u5F84\u65E0\u6548"});return}y(w,200,{path:await Er(d.path,d.name)});return}if(k==="/api/workspace/add"){if(!("path"in d)||typeof d.path!="string"||d.path.length>4096||!("create"in d)||typeof d.create!="boolean"){y(w,400,{error:"\u5DE5\u4F5C\u533A\u8DEF\u5F84\u65E0\u6548"});return}await r.addWorkspace(d.path,d.create),y(w,202,{accepted:!0});return}if(k==="/api/workspace/select"||k==="/api/workspace/remove"||k==="/api/workspace/new-session"){if(!("id"in d)||typeof d.id!="string"){y(w,400,{error:"\u5DE5\u4F5C\u533A\u65E0\u6548"});return}k==="/api/workspace/select"?await r.selectWorkspace(d.id):k==="/api/workspace/new-session"?await r.newSessionInWorkspace(d.id):await r.removeWorkspace(d.id),y(w,202,{accepted:!0});return}if(k==="/api/session/select"){if(!("workspaceId"in d)||typeof d.workspaceId!="string"||!("id"in d)||typeof d.id!="string"||!("path"in d)||typeof d.path!="string"){y(w,400,{error:"\u4F1A\u8BDD\u65E0\u6548"});return}await r.selectSession(d.workspaceId,d.id,d.path),y(w,202,{accepted:!0});return}if(k==="/api/thinking-level"){if(!("level"in d)||typeof d.level!="string"){y(w,400,{error:"\u63A8\u7406\u5F3A\u5EA6\u65E0\u6548"});return}await r.setThinkingLevel(d.sessionId,d.level)}else if(k==="/api/model"){if(!("provider"in d)||typeof d.provider!="string"||!("id"in d)||typeof d.id!="string"){y(w,400,{error:"\u6A21\u578B\u65E0\u6548"});return}await r.setModel(d.sessionId,d.provider,d.id)}else if(k==="/api/config"){let v=d;if(!["packages","extensions","skills"].includes(v.kind)||!["global","project"].includes(v.scope)||!["add","remove"].includes(v.action)||typeof v.value!="string"||!v.value.trim()||v.value.length>2048){y(w,400,{error:"\u914D\u7F6E\u9879\u65E0\u6548"});return}if(v.action==="add"&&v.kind!=="packages"&&Fr(v.value)){y(w,400,{error:"npm \u6216 Git \u6765\u6E90\u8BF7\u5728\u300C\u5305\u300D\u4E2D\u6DFB\u52A0\uFF1B\u6269\u5C55\u548C\u6280\u80FD\u53EA\u63A5\u53D7\u6587\u4EF6\u6216\u76EE\u5F55\u8DEF\u5F84"});return}y(w,200,await r.updateConfig(v));return}else if(k==="/api/message"){let v="attachments"in d?d.attachments:[];if(!Array.isArray(v)||v.length>Ir||v.some(R=>typeof R!="string")||new Set(v).size!==v.length){y(w,400,{error:"\u9644\u4EF6\u65E0\u6548\u6216\u8FC7\u591A"});return}let _=v.map(R=>g.get(R));if(_.some(R=>!R||R.sessionId!==d.sessionId)){y(w,400,{error:"\u9644\u4EF6\u4E0D\u53EF\u7528"});return}if(!("text"in d)||typeof d.text!="string"||!d.text.trim()&&v.length===0||d.text.length>32e3){y(w,400,{error:"\u6D88\u606F\u65E0\u6548\u6216\u8FC7\u957F"});return}let C=_,A=[d.text.trim(),...C.map(R=>`\u9644\u4EF6 ${JSON.stringify(R.name)}\uFF1A${R.path}`)].filter(Boolean).join(`
|
|
31
31
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-webapp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A browser interface for Pi with live chat, workspaces, models, and attachments",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"pi-webapp": "./bin/pi-webapp.mjs"
|
|
16
16
|
},
|
|
17
17
|
"pi": {
|
|
18
|
-
"image": "https://cdn.jsdelivr.net/npm/pi-webapp@0.1.
|
|
18
|
+
"image": "https://cdn.jsdelivr.net/npm/pi-webapp@0.1.23/assets/cover-webapp.png",
|
|
19
19
|
"extensions": [
|
|
20
20
|
"./dist/extension.js"
|
|
21
21
|
]
|
|
@@ -122,13 +122,13 @@
|
|
|
122
122
|
"isDynamicEntry": true
|
|
123
123
|
},
|
|
124
124
|
"../../node_modules/@shikijs/langs/dist/graphql.mjs": {
|
|
125
|
-
"file": "assets/graphql-
|
|
125
|
+
"file": "assets/graphql-R1M_bSpj.js",
|
|
126
126
|
"name": "graphql",
|
|
127
127
|
"src": "../../node_modules/@shikijs/langs/dist/graphql.mjs",
|
|
128
128
|
"isDynamicEntry": true,
|
|
129
129
|
"imports": [
|
|
130
130
|
"_javascript-D_ijBMSX.js",
|
|
131
|
-
"_app-
|
|
131
|
+
"_app-C-H5rHq5.js",
|
|
132
132
|
"index.html"
|
|
133
133
|
]
|
|
134
134
|
},
|
|
@@ -161,12 +161,12 @@
|
|
|
161
161
|
]
|
|
162
162
|
},
|
|
163
163
|
"../../node_modules/@shikijs/langs/dist/http.mjs": {
|
|
164
|
-
"file": "assets/http-
|
|
164
|
+
"file": "assets/http-L5EnyzVP.js",
|
|
165
165
|
"name": "http",
|
|
166
166
|
"src": "../../node_modules/@shikijs/langs/dist/http.mjs",
|
|
167
167
|
"isDynamicEntry": true,
|
|
168
168
|
"imports": [
|
|
169
|
-
"_app-
|
|
169
|
+
"_app-C-H5rHq5.js",
|
|
170
170
|
"../../node_modules/@shikijs/langs/dist/xml.mjs",
|
|
171
171
|
"../../node_modules/@shikijs/langs/dist/graphql.mjs",
|
|
172
172
|
"index.html",
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
]
|
|
276
276
|
},
|
|
277
277
|
"../../node_modules/@shikijs/langs/dist/php.mjs": {
|
|
278
|
-
"file": "assets/php-
|
|
278
|
+
"file": "assets/php-xdHBwAuB.js",
|
|
279
279
|
"name": "php",
|
|
280
280
|
"src": "../../node_modules/@shikijs/langs/dist/php.mjs",
|
|
281
281
|
"isDynamicEntry": true,
|
|
@@ -284,7 +284,7 @@
|
|
|
284
284
|
"../../node_modules/@shikijs/langs/dist/xml.mjs",
|
|
285
285
|
"../../node_modules/@shikijs/langs/dist/sql.mjs",
|
|
286
286
|
"_javascript-D_ijBMSX.js",
|
|
287
|
-
"_app-
|
|
287
|
+
"_app-C-H5rHq5.js",
|
|
288
288
|
"../../node_modules/@shikijs/langs/dist/css.mjs",
|
|
289
289
|
"../../node_modules/@shikijs/langs/dist/java.mjs",
|
|
290
290
|
"index.html"
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
"isDynamicEntry": true
|
|
316
316
|
},
|
|
317
317
|
"../../node_modules/@shikijs/langs/dist/rst.mjs": {
|
|
318
|
-
"file": "assets/rst-
|
|
318
|
+
"file": "assets/rst-D5vBXrc7.js",
|
|
319
319
|
"name": "rst",
|
|
320
320
|
"src": "../../node_modules/@shikijs/langs/dist/rst.mjs",
|
|
321
321
|
"isDynamicEntry": true,
|
|
@@ -324,7 +324,7 @@
|
|
|
324
324
|
"../../node_modules/@shikijs/langs/dist/cpp.mjs",
|
|
325
325
|
"../../node_modules/@shikijs/langs/dist/python.mjs",
|
|
326
326
|
"_javascript-D_ijBMSX.js",
|
|
327
|
-
"_app-
|
|
327
|
+
"_app-C-H5rHq5.js",
|
|
328
328
|
"../../node_modules/@shikijs/langs/dist/yaml.mjs",
|
|
329
329
|
"../../node_modules/@shikijs/langs/dist/cmake.mjs",
|
|
330
330
|
"../../node_modules/@shikijs/langs/dist/ruby.mjs",
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
]
|
|
341
341
|
},
|
|
342
342
|
"../../node_modules/@shikijs/langs/dist/ruby.mjs": {
|
|
343
|
-
"file": "assets/ruby-
|
|
343
|
+
"file": "assets/ruby-CB8CtpFl.js",
|
|
344
344
|
"name": "ruby",
|
|
345
345
|
"src": "../../node_modules/@shikijs/langs/dist/ruby.mjs",
|
|
346
346
|
"isDynamicEntry": true,
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
"../../node_modules/@shikijs/langs/dist/graphql.mjs",
|
|
354
354
|
"../../node_modules/@shikijs/langs/dist/cpp.mjs",
|
|
355
355
|
"../../node_modules/@shikijs/langs/dist/c.mjs",
|
|
356
|
-
"_app-
|
|
356
|
+
"_app-C-H5rHq5.js",
|
|
357
357
|
"../../node_modules/@shikijs/langs/dist/lua.mjs",
|
|
358
358
|
"../../node_modules/@shikijs/langs/dist/yaml.mjs",
|
|
359
359
|
"../../node_modules/@shikijs/langs/dist/java.mjs",
|
|
@@ -388,13 +388,13 @@
|
|
|
388
388
|
"isDynamicEntry": true
|
|
389
389
|
},
|
|
390
390
|
"../../node_modules/@shikijs/langs/dist/svelte.mjs": {
|
|
391
|
-
"file": "assets/svelte-
|
|
391
|
+
"file": "assets/svelte-qWxX2efJ.js",
|
|
392
392
|
"name": "svelte",
|
|
393
393
|
"src": "../../node_modules/@shikijs/langs/dist/svelte.mjs",
|
|
394
394
|
"isDynamicEntry": true,
|
|
395
395
|
"imports": [
|
|
396
396
|
"_javascript-D_ijBMSX.js",
|
|
397
|
-
"_app-
|
|
397
|
+
"_app-C-H5rHq5.js",
|
|
398
398
|
"../../node_modules/@shikijs/langs/dist/css.mjs",
|
|
399
399
|
"index.html"
|
|
400
400
|
]
|
|
@@ -430,14 +430,14 @@
|
|
|
430
430
|
"isDynamicEntry": true
|
|
431
431
|
},
|
|
432
432
|
"../../node_modules/@shikijs/langs/dist/vue.mjs": {
|
|
433
|
-
"file": "assets/vue-
|
|
433
|
+
"file": "assets/vue-CTcHoOmv.js",
|
|
434
434
|
"name": "vue",
|
|
435
435
|
"src": "../../node_modules/@shikijs/langs/dist/vue.mjs",
|
|
436
436
|
"isDynamicEntry": true,
|
|
437
437
|
"imports": [
|
|
438
438
|
"../../node_modules/@shikijs/langs/dist/css.mjs",
|
|
439
439
|
"_javascript-D_ijBMSX.js",
|
|
440
|
-
"_app-
|
|
440
|
+
"_app-C-H5rHq5.js",
|
|
441
441
|
"../../node_modules/@shikijs/langs/dist/html.mjs",
|
|
442
442
|
"_html-derivative-C2Epw9Yg.js",
|
|
443
443
|
"index.html"
|
|
@@ -704,37 +704,37 @@
|
|
|
704
704
|
]
|
|
705
705
|
},
|
|
706
706
|
"../../src/plugins/builtin/files/client/plugin.tsx": {
|
|
707
|
-
"file": "assets/plugin-
|
|
707
|
+
"file": "assets/plugin-DtJl1c8o.js",
|
|
708
708
|
"name": "plugin",
|
|
709
709
|
"src": "../../src/plugins/builtin/files/client/plugin.tsx",
|
|
710
710
|
"isDynamicEntry": true,
|
|
711
711
|
"imports": [
|
|
712
|
-
"_app-
|
|
712
|
+
"_app-C-H5rHq5.js",
|
|
713
713
|
"index.html"
|
|
714
714
|
]
|
|
715
715
|
},
|
|
716
716
|
"../../src/plugins/builtin/git/client/plugin.tsx": {
|
|
717
|
-
"file": "assets/plugin-
|
|
717
|
+
"file": "assets/plugin-DCamQdiP.js",
|
|
718
718
|
"name": "plugin",
|
|
719
719
|
"src": "../../src/plugins/builtin/git/client/plugin.tsx",
|
|
720
720
|
"isDynamicEntry": true,
|
|
721
721
|
"imports": [
|
|
722
|
-
"_app-
|
|
722
|
+
"_app-C-H5rHq5.js",
|
|
723
723
|
"index.html"
|
|
724
724
|
]
|
|
725
725
|
},
|
|
726
726
|
"../../src/plugins/builtin/terminal/client/plugin.tsx": {
|
|
727
|
-
"file": "assets/plugin-
|
|
727
|
+
"file": "assets/plugin-CYps5zpH.js",
|
|
728
728
|
"name": "plugin",
|
|
729
729
|
"src": "../../src/plugins/builtin/terminal/client/plugin.tsx",
|
|
730
730
|
"isDynamicEntry": true,
|
|
731
731
|
"imports": [
|
|
732
|
-
"_app-
|
|
732
|
+
"_app-C-H5rHq5.js",
|
|
733
733
|
"index.html"
|
|
734
734
|
]
|
|
735
735
|
},
|
|
736
|
-
"_app-
|
|
737
|
-
"file": "assets/app-
|
|
736
|
+
"_app-C-H5rHq5.js": {
|
|
737
|
+
"file": "assets/app-C-H5rHq5.js",
|
|
738
738
|
"name": "app",
|
|
739
739
|
"isDynamicEntry": true,
|
|
740
740
|
"imports": [
|
|
@@ -882,7 +882,7 @@
|
|
|
882
882
|
"isEntry": true,
|
|
883
883
|
"dynamicImports": [
|
|
884
884
|
"../../src/host/client/telemetry-client.ts",
|
|
885
|
-
"_app-
|
|
885
|
+
"_app-C-H5rHq5.js"
|
|
886
886
|
]
|
|
887
887
|
},
|
|
888
888
|
"style.css": {
|