pi-webapp 0.1.5 → 0.1.6
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 +3 -1
- package/README.zh-CN.md +3 -1
- package/bin/pi-webapp.mjs +62 -1
- package/dist/extension.js +6 -6
- package/package.json +2 -2
- package/web/dist/assets/app.js +43 -43
- package/web/dist/assets/style.css +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ npx pi-webapp
|
|
|
16
16
|
|
|
17
17
|
This starts Pi in the background and opens the default browser on a local graphical desktop, leaving the terminal free. If Pi is missing, the launcher installs the official `@earendil-works/pi-coding-agent` package with npm. An existing Pi installation must be version 0.87.1 or later. The launcher does not replace an older installation automatically. Running the launcher again reopens the existing server. Remote or headless sessions print the address instead; set `PI_WEBAPP_AUTO_OPEN=0` to disable automatic opening.
|
|
18
18
|
|
|
19
|
+
In Settings → General → App updates, the web page checks npm for a newer `pi-webapp` release. When started by the background launcher from an npm package, **Update and restart** installs the verified release under Pi's `pi-web/releases/` data directory, restarts the server, and reloads the same browser address. Wait for any active reply to finish first. If the new version cannot start, the launcher restores the previous service. This works for both `npx` and global-command launches; later launches select the managed release automatically. It does not change the npm global installation. Source checkouts and `/web` pages opened from an existing Pi terminal show version information but cannot restart from the web page. If the service does not return, run `pi-webapp status` and check `~/.pi/agent/pi-web/launcher.log`.
|
|
20
|
+
|
|
19
21
|
Use `npx pi-webapp status` to show the address and `npx pi-webapp stop` to stop the background service. After a global install, use `pi-webapp status` and `pi-webapp stop`.
|
|
20
22
|
|
|
21
23
|
You can also install the launcher globally:
|
|
@@ -66,7 +68,7 @@ The source lives in `extension/`, `shared/`, and `web/src/`. The npm package con
|
|
|
66
68
|
|
|
67
69
|
`npm publish` runs the checks, tests, and production build. The `pi-package` keyword makes the published npm package eligible for the [Pi package catalog](https://pi.dev/packages); catalog updates may lag behind npm.
|
|
68
70
|
|
|
69
|
-
GitHub Actions runs `check`, `test`, and `build` on pull requests to `main`. A push to `main` repeats those checks
|
|
71
|
+
GitHub Actions runs `check`, `test`, and `build` on pull requests to `main`. A push to `main` repeats those checks, chooses the next patch version from the source version and npm `latest`, then commits the updated `package.json` and `package-lock.json` to `main` before publishing. The release commit uses the workflow's `GITHUB_TOKEN` and does not start another workflow run. To start a new minor or major series, raise the version in both package files in the pull request. Each release also updates the package's `pi.image` URL to its own version. The repository must allow the workflow to push to `main` for publishing to proceed.
|
|
70
72
|
|
|
71
73
|
Before the first automated release, configure npm Trusted Publishing for the `pi-webapp` package: GitHub owner `chengzhiyi`, repository `pi-webapp`, workflow filename `ci.yml`, no environment, and allow direct `npm publish`. This workflow uses GitHub's OIDC identity and does not need an npm token. Keep the package's repository URL in `package.json` aligned with the GitHub repository.
|
|
72
74
|
|
package/README.zh-CN.md
CHANGED
|
@@ -16,6 +16,8 @@ npx pi-webapp
|
|
|
16
16
|
|
|
17
17
|
该命令会在后台启动 Pi,并在本地图形桌面用默认浏览器打开网页,终端可继续使用。若未找到 Pi,会自动通过 npm 安装官方 `@earendil-works/pi-coding-agent`。已有 Pi 需要 0.87.1 或更新版本;启动器不会自动覆盖旧版本。再次运行启动命令会重新打开已有服务。远程或无图形界面时只显示地址;设置 `PI_WEBAPP_AUTO_OPEN=0` 可关闭自动打开。
|
|
18
18
|
|
|
19
|
+
网页的「设置 → 通用设置 → 应用更新」会检查 npm 上的 `pi-webapp` 新版本。通过 npm 包的后台启动器运行时,点击「升级并重启」会先将新版安装并校验到 Pi 数据目录的 `pi-web/releases/`,然后重启服务,网页会在原地址重新加载。请先等待当前回复结束。若新版无法启动,启动器会恢复旧版服务。`npx` 和全局命令启动均可使用;后续启动会自动选用已安装的新版。此操作不会改动 npm 全局安装。源码目录运行和已有 Pi 终端中的 `/web` 页面可以查看版本,但不能从网页重启。若服务未恢复,可运行 `pi-webapp status` 并查看 `~/.pi/agent/pi-web/launcher.log`。
|
|
20
|
+
|
|
19
21
|
可用 `npx pi-webapp status` 查看地址,用 `npx pi-webapp stop` 停止后台服务。全局安装后可直接运行 `pi-webapp status` 和 `pi-webapp stop`。
|
|
20
22
|
|
|
21
23
|
也可以将启动器安装为全局命令:
|
|
@@ -66,7 +68,7 @@ npm run stop
|
|
|
66
68
|
|
|
67
69
|
`npm publish` 会运行检查、测试和生产构建。`pi-package` 关键词使发布到 npm 的软件包有资格进入 [Pi 软件包目录](https://pi.dev/packages);目录更新可能晚于 npm。
|
|
68
70
|
|
|
69
|
-
GitHub Actions 会在针对 `main` 的拉取请求中运行 `check`、`test` 和 `build`。代码推送到 `main`
|
|
71
|
+
GitHub Actions 会在针对 `main` 的拉取请求中运行 `check`、`test` 和 `build`。代码推送到 `main` 后会再次运行这些检查,根据源码版本和 npm `latest` 版本确定下一个补丁版本,先将更新后的 `package.json` 和 `package-lock.json` 提交回 `main`,再发布到 npm。版本同步提交使用工作流的 `GITHUB_TOKEN`,不会再次触发工作流。如需开始新的次版本或主版本,请在拉取请求中同步提高两个包文件的版本。每次发布也会将包内 `pi.image` 的地址更新为该版本。仓库必须允许工作流推送到 `main`,发布才能继续。
|
|
70
72
|
|
|
71
73
|
首次自动发布前,请在 npm 的 `pi-webapp` 包设置中配置 Trusted Publishing:GitHub 所有者为 `chengzhiyi`,仓库为 `pi-webapp`,工作流文件名为 `ci.yml`,不设置环境,并允许直接执行 `npm publish`。工作流通过 GitHub OIDC 认证,无需 npm token。`package.json` 中的仓库地址应与 GitHub 仓库保持一致。
|
|
72
74
|
|
package/bin/pi-webapp.mjs
CHANGED
|
@@ -15,6 +15,8 @@ const extension = fileURLToPath(new URL("../dist/extension.js", import.meta.url)
|
|
|
15
15
|
const agentDir = resolve((process.env.PI_CODING_AGENT_DIR ?? join(homedir(), ".pi", "agent")).replace(/^~(?=$|[\\/])/, homedir()));
|
|
16
16
|
const statePath = join(agentDir, "pi-web", "launcher.json");
|
|
17
17
|
const stopPath = join(agentDir, "pi-web", "launcher.stop");
|
|
18
|
+
const restartPath = join(agentDir, "pi-web", "launcher.restart");
|
|
19
|
+
const updatePath = join(agentDir, "pi-web", "update.json");
|
|
18
20
|
const logPath = join(agentDir, "pi-web", "launcher.log");
|
|
19
21
|
|
|
20
22
|
function versionParts(value) {
|
|
@@ -112,7 +114,7 @@ async function serve(pi, args) {
|
|
|
112
114
|
} finally { await lock?.close().catch(() => {}); }
|
|
113
115
|
|
|
114
116
|
const child = spawn(pi, ["--mode", "rpc", "-e", extension, ...args], {
|
|
115
|
-
cwd: process.cwd(), env: { ...process.env, PI_WEBAPP_AUTO_OPEN: "0" }, stdio: ["pipe", "pipe", "pipe"],
|
|
117
|
+
cwd: process.cwd(), env: { ...process.env, PI_WEBAPP_AUTO_OPEN: "0", PI_WEBAPP_LAUNCHER_NONCE: nonce }, stdio: ["pipe", "pipe", "pipe"],
|
|
116
118
|
});
|
|
117
119
|
child.stderr?.pipe(process.stderr, { end: false });
|
|
118
120
|
let ready = false;
|
|
@@ -121,6 +123,8 @@ async function serve(pi, args) {
|
|
|
121
123
|
let closed = false;
|
|
122
124
|
let stateWrite = Promise.resolve();
|
|
123
125
|
let stopping = false;
|
|
126
|
+
let restartRequest = null;
|
|
127
|
+
let runningUrl = null;
|
|
124
128
|
let buffer = "";
|
|
125
129
|
let killTimer;
|
|
126
130
|
const shutdown = () => {
|
|
@@ -140,6 +144,15 @@ async function serve(pi, args) {
|
|
|
140
144
|
const stopTimer = setInterval(async () => {
|
|
141
145
|
try { if ((await readFile(stopPath, "utf8")).trim() === nonce) shutdown(); }
|
|
142
146
|
catch { /* No stop request. */ }
|
|
147
|
+
if (stopping) return;
|
|
148
|
+
try {
|
|
149
|
+
const request = JSON.parse(await readFile(restartPath, "utf8"));
|
|
150
|
+
const prepared = JSON.parse(await readFile(updatePath, "utf8"));
|
|
151
|
+
if (request.nonce === nonce && request.launcher === prepared.launcher && existsSync(request.launcher)) {
|
|
152
|
+
restartRequest = request;
|
|
153
|
+
shutdown();
|
|
154
|
+
}
|
|
155
|
+
} catch { /* No valid restart request. */ }
|
|
143
156
|
}, 400);
|
|
144
157
|
process.on("SIGTERM", shutdown);
|
|
145
158
|
process.on("SIGINT", shutdown);
|
|
@@ -175,6 +188,7 @@ async function serve(pi, args) {
|
|
|
175
188
|
try { url = new URL(record.message.slice("pi-webapp: ".length)); }
|
|
176
189
|
catch { continue; }
|
|
177
190
|
if (url.hostname !== "127.0.0.1" || !url.hash) continue;
|
|
191
|
+
runningUrl = url.href;
|
|
178
192
|
opening = true;
|
|
179
193
|
stateWrite = saveState({ pid: process.pid, piPid: child.pid, nonce, cwd: process.cwd(), url: url.href })
|
|
180
194
|
.then(() => {
|
|
@@ -206,6 +220,42 @@ async function serve(pi, args) {
|
|
|
206
220
|
try { if (JSON.parse(await readFile(statePath, "utf8")).nonce === nonce) await unlink(statePath); }
|
|
207
221
|
catch { /* Already removed. */ }
|
|
208
222
|
}
|
|
223
|
+
if (restartRequest && runningUrl) {
|
|
224
|
+
await unlink(restartPath).catch(() => {});
|
|
225
|
+
const oldUrl = new URL(runningUrl);
|
|
226
|
+
const fd = openSync(logPath, "a", 0o600);
|
|
227
|
+
const restartEnv = { ...process.env, PI_WEBAPP_AUTO_OPEN: "0", PI_WEBAPP_RESTART_PORT: oldUrl.port, PI_WEBAPP_RESTART_TOKEN: oldUrl.hash.slice(1) };
|
|
228
|
+
try {
|
|
229
|
+
const runLauncher = (path) => new Promise((resolveExit) => {
|
|
230
|
+
const next = spawnNode(process.execPath, [path, "start", ...args], { cwd: process.cwd(), env: restartEnv, stdio: ["ignore", fd, fd] });
|
|
231
|
+
next.once("error", () => resolveExit(1));
|
|
232
|
+
next.once("exit", (code) => resolveExit(code ?? 1));
|
|
233
|
+
});
|
|
234
|
+
if (await runLauncher(restartRequest.launcher) !== 0) {
|
|
235
|
+
await clearManagedLauncher(restartRequest.launcher);
|
|
236
|
+
console.error("pi-webapp: 新版启动失败,正在恢复旧版服务");
|
|
237
|
+
if (await runLauncher(launcher) !== 0) console.error(`pi-webapp: 旧版恢复失败。日志:${logPath}`);
|
|
238
|
+
}
|
|
239
|
+
} finally { closeSync(fd); }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function clearManagedLauncher(path) {
|
|
244
|
+
try {
|
|
245
|
+
if (JSON.parse(await readFile(updatePath, "utf8")).launcher === path) await unlink(updatePath);
|
|
246
|
+
} catch { /* No matching managed release. */ }
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async function managedLauncher() {
|
|
250
|
+
try {
|
|
251
|
+
if (existsSync(fileURLToPath(new URL("../.git", import.meta.url)))) return null;
|
|
252
|
+
const update = JSON.parse(await readFile(updatePath, "utf8"));
|
|
253
|
+
const current = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
|
|
254
|
+
if (!/^\d+\.\d+\.\d+$/.test(update.version) || !/^\d+\.\d+\.\d+$/.test(current.version)) return null;
|
|
255
|
+
if (!compatible(versionParts(update.version), versionParts(current.version))) return null;
|
|
256
|
+
if (update.version === current.version || !existsSync(update.launcher)) return null;
|
|
257
|
+
return update.launcher;
|
|
258
|
+
} catch { return null; }
|
|
209
259
|
}
|
|
210
260
|
|
|
211
261
|
async function start(args) {
|
|
@@ -215,6 +265,17 @@ async function start(args) {
|
|
|
215
265
|
if (existing.url) await openPageIfLocal(existing.url);
|
|
216
266
|
return;
|
|
217
267
|
}
|
|
268
|
+
const managed = await managedLauncher();
|
|
269
|
+
if (managed) {
|
|
270
|
+
const next = spawnNode(process.execPath, [managed, "start", ...args], { cwd: process.cwd(), env: process.env, stdio: "inherit" });
|
|
271
|
+
const code = await new Promise((resolveExit, rejectExit) => { next.once("error", rejectExit); next.once("exit", (status) => resolveExit(status)); });
|
|
272
|
+
if (code !== 0) {
|
|
273
|
+
await clearManagedLauncher(managed);
|
|
274
|
+
console.error(`pi-webapp: 新版启动失败(代码 ${code ?? "未知"}),正在恢复当前安装`);
|
|
275
|
+
await start(args);
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
218
279
|
const nodeVersion = versionParts(process.versions.node);
|
|
219
280
|
if (!nodeVersion || !compatible(nodeVersion, [22, 19, 0])) throw new Error("需要 Node.js 22.19 或更新版本。");
|
|
220
281
|
if (!existsSync(extension)) throw new Error("找不到构建后的扩展。请先运行 npm run build。");
|
package/dist/extension.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{dirname as
|
|
2
|
-
`,{mode:p,flag:"wx"}),await
|
|
3
|
-
`,{mode:
|
|
4
|
-
`),
|
|
1
|
+
import{dirname as wr,join as q,resolve as Ue}from"node:path";import{realpath as J}from"node:fs/promises";import{fileURLToPath as hr}from"node:url";import{DefaultPackageManager as Be,getAgentDir as N,ModelRuntime as yr,SessionManager as Oe,SettingsManager as vr}from"@earendil-works/pi-coding-agent";import{getSupportedThinkingLevels as kr}from"@earendil-works/pi-ai";import{randomBytes as Vt,timingSafeEqual as Ut}from"node:crypto";import{readFile as Bt}from"node:fs/promises";import{createServer as Ot}from"node:http";import{join as Dt}from"node:path";import{mkdir as He,opendir as Ge,stat as ze}from"node:fs/promises";import{homedir as Ke}from"node:os";import{basename as Ye,dirname as te,join as re,posix as Xe,resolve as ie,win32 as Ze}from"node:path";function se(t){return process.platform==="win32"?Ze.isAbsolute(t)&&/^(?:[A-Za-z]:[\\/]|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)/.test(t):Xe.isAbsolute(t)}function Qe(t,e,r){if(t.length===r&&e.name.localeCompare(t[t.length-1].name)>=0)return!0;let i=0,n=t.length;for(;i<n;){let p=i+n>>>1;e.name.localeCompare(t[p].name)<0?n=p:i=p+1}return t.splice(i,0,e),t.length<=r?!1:(t.pop(),!0)}async function ne(t){if(t!==void 0&&!se(t))throw new Error("\u76EE\u5F55\u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");let e=Ke(),r=ie(t??e),i=[];for(let a=r;;a=te(a)){let u=te(a);if(i.unshift({name:u===a?a:Ye(a),path:a,hidden:!1}),u===a)break}let n=[],p=!1,o=await Ge(r);for await(let a of o)!a.isDirectory()&&!a.isSymbolicLink()||Qe(n,{name:a.name,isDirectory:a.isDirectory(),isSymbolicLink:a.isSymbolicLink()},1001)&&(p=!0);let l=[];for(let a of n){let u=re(r,a.name);if(!a.isDirectory&&a.isSymbolicLink)try{if(!(await ze(u)).isDirectory())continue}catch{continue}if(l.length===1e3){p=!0;break}l.push({name:a.name,path:u,hidden:a.name.startsWith(".")})}return{path:r,home:e,crumbs:i,entries:l,truncated:p}}async function oe(t,e){if(!se(t))throw new Error("\u7236\u76EE\u5F55\u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");if(!e.trim()||e==="."||e===".."||/[/\\]/.test(e))throw new Error("\u6587\u4EF6\u5939\u540D\u79F0\u65E0\u6548");let r=re(ie(t),e);return await He(r),r}import{execFile as qe}from"node:child_process";import{accessSync as et,constants as tt}from"node:fs";import{delimiter as rt,join as it}from"node:path";var st=(t,e,r)=>new Promise((i,n)=>{qe(t,[...e],{encoding:"utf8",signal:r,windowsHide:!0},(p,o,l)=>{p?n(Object.assign(new Error(p.message,{cause:p}),{code:p.code,stdout:o,stderr:l})):i({stdout:o,stderr:l})})});function nt(t){for(let e of(t??"").split(rt))if(e)for(let r of["zenity","kdialog"])try{return et(it(e,r),tt.X_OK),!0}catch{}return!1}function ae(t=process.platform,e=process.env){return e.SSH_CONNECTION||e.SSH_TTY?"browse":t==="darwin"||t==="linux"&&(e.DISPLAY||e.WAYLAND_DISPLAY)&&nt(e.PATH)?"native":"browse"}function L(t){if(!(typeof t!="object"||t===null||!("code"in t)))return typeof t.code=="string"||typeof t.code=="number"?t.code:void 0}function ot(t){return typeof t=="object"&&t!==null&&"stderr"in t&&typeof t.stderr=="string"?t.stderr:""}function H(t){return t.replace(/[\r\n]+$/,"")||null}async function ce(t,e=process.platform,r=st){if(e==="darwin")try{let i=await r("osascript",["-e",'set selectedFolder to choose folder with prompt "Select Workspace Directory"',"-e","POSIX path of selectedFolder"],t);return H(i.stdout)}catch(i){if(!t.aborted&&L(i)===1&&/(?:User canceled|-128)/i.test(ot(i)))return null;throw i}if(e==="linux"){try{return H((await r("zenity",["--file-selection","--directory","--title=Select Workspace Directory"],t)).stdout)}catch(i){if(t.aborted)throw i;if(L(i)===1)return null;if(L(i)!=="ENOENT")throw i}try{return H((await r("kdialog",["--getexistingdirectory",".","--title","Select Workspace Directory"],t)).stdout)}catch(i){if(t.aborted)throw i;if(L(i)===1)return null;throw i}}throw new Error(`\u5F53\u524D\u7CFB\u7EDF\u4E0D\u652F\u6301\u672C\u5730\u76EE\u5F55\u9009\u62E9\u5668\uFF1A${e}`)}import{createHash as at,randomUUID as ct}from"node:crypto";import{mkdir as lt,readFile as dt,writeFile as pt}from"node:fs/promises";import{join as le}from"node:path";import{getAgentDir as ut}from"@earendil-works/pi-coding-agent";var _=20*1024*1024,de=20,mt=/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])$/iu;function ft(t){let e=t.indexOf("."),r=(e<0?t:t.slice(0,e)).replace(/[. ]+$/u,"");return mt.test(r)}function gt(t,e){let r=0,i="";for(let n of Buffer.from(t).toString("utf8")){let p=Buffer.byteLength(n);if(r+p>e)break;i+=n,r+=p}return i}function wt(t){if(t===void 0)return"file";let r=t.slice(Math.max(t.lastIndexOf("/"),t.lastIndexOf("\\"))+1).replace(/[\u0000-\u001f\u007f]/g,"").replace(/[<>:"|?*]/g,"_").trim().replace(/[. ]+$/u,"");return ft(r)&&(r=`_${r}`),r=gt(r,255).replace(/[. ]+$/u,""),r===""||r==="."||r===".."?"file":r}function ht(t){return t.length>=8&&t.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10]))?"image/png":t.length>=3&&t.subarray(0,3).equals(Buffer.from([255,216,255]))?"image/jpeg":t.length>=6&&["GIF87a","GIF89a"].includes(t.toString("ascii",0,6))?"image/gif":t.length>=12&&t.toString("ascii",0,4)==="RIFF"&&t.toString("ascii",8,12)==="WEBP"?"image/webp":null}async function pe(t,e,r,i){if(i.byteLength===0||i.byteLength>_)throw new Error("\u6587\u4EF6\u4E3A\u7A7A\u6216\u8D85\u8FC7 20 MB");let n=wt(e),p=at("sha256").update(i).digest("hex"),o=le(ut(),"pi-web","attachments",p);await lt(o,{recursive:!0});let l=le(o,n);try{await pt(l,i,{flag:"wx",mode:384})}catch(a){if(!(a instanceof Error&&"code"in a&&a.code==="EEXIST"))throw a}return{id:ct(),name:n,bytes:i.byteLength,path:l,mediaType:ht(i)??r.replace(/^image\//,"application/"),sessionId:t}}async function ue(t){return{type:"image",data:(await dt(t.path)).toString("base64"),mimeType:t.mediaType}}import{randomBytes as yt}from"node:crypto";function me(t,e,r){return t!=="openai-codex"||e!=="oauth"?r:{...r,prompt:i=>i.type==="select"&&i.options.some(n=>n.id==="browser")&&i.options.some(n=>n.id==="device_code")?Promise.resolve("browser"):r.prompt(i)}}var V=class{flows=new Map;start(e,r,i,n){let p=this.getActive();if(p){if(p.providerId===e&&p.method===r&&n===void 0)return p;throw new Error("\u5176\u4ED6\u63D0\u4F9B\u65B9\u7684\u767B\u5F55\u6B63\u5728\u8FDB\u884C\uFF0C\u8BF7\u5148\u5B8C\u6210\u6216\u53D6\u6D88\u5F53\u524D\u767B\u5F55")}this.flows.clear();let o=yt(18).toString("base64url"),l={view:{id:o,providerId:e,method:r,status:"running"},controller:new AbortController};return this.flows.set(o,l),i(e,r,{signal:l.controller.signal,notify:a=>{l.view={...l.view,event:a,...a.type==="auth_url"||a.type==="device_code"?{authorization:a}:{}}},prompt:a=>{if(a.type==="secret"&&n!==void 0){let u=n;return n=void 0,Promise.resolve(u)}return new Promise((u,h)=>{let{signal:y,...b}=a;l.answer=u,l.reject=h,l.view={...l.view,status:"waiting",prompt:b},y?.aborted?h(new Error("\u767B\u5F55\u8F93\u5165\u5DF2\u53D6\u6D88")):y?.addEventListener("abort",()=>h(new Error("\u767B\u5F55\u8F93\u5165\u5DF2\u53D6\u6D88")),{once:!0})})}}).then(()=>{l.view.status!=="cancelled"&&(l.view={id:o,providerId:e,method:r,status:"done"})}).catch(()=>{l.view.status!=="cancelled"&&(l.view={id:o,providerId:e,method:r,status:"error",error:"\u767B\u5F55\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u63D0\u4F9B\u65B9\u63D0\u793A\u5E76\u91CD\u8BD5\u3002"})}),{...l.view}}get(e){let r=this.flows.get(e)?.view;return r?{...r}:void 0}getActive(){let e=[...this.flows.values()].find(({view:r})=>r.status==="running"||r.status==="waiting")?.view;return e?{...e}:void 0}respond(e,r){let i=this.flows.get(e);if(!i?.answer||i.view.status!=="waiting"||i.view.prompt?.type==="select"&&!i.view.prompt.options.some(p=>p.id===r))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(r),!0}cancel(e){let r=this.flows.get(e);return!r||r.view.status==="done"||r.view.status==="error"?!1:(r.view={...r.view,status:"cancelled",prompt:void 0},r.controller.abort(),r.reject?.(new Error("\u767B\u5F55\u5DF2\u53D6\u6D88")),r.answer=void 0,r.reject=void 0,!0)}close(){for(let e of this.flows.keys())this.cancel(e);this.flows.clear()}};import{randomBytes as vt}from"node:crypto";import{readFile as kt,rename as bt,rm as Pt,stat as St,writeFile as xt,mkdir as Et}from"node:fs/promises";import{dirname as It}from"node:path";var Ct=["openai-completions","openai-responses","anthropic-messages"];function G(t){if(!t||typeof t!="object")return!1;let e=t;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||!Ct.includes(e.api)||typeof e.baseUrl!="string"||e.baseUrl.length>2048)return!1;try{let r=new URL(e.baseUrl);return(r.protocol==="https:"||r.protocol==="http:")&&!!r.hostname&&!r.username&&!r.password&&!r.hash}catch{return!1}}async function fe(t,e){if(!G(e))throw new Error("\u81EA\u5B9A\u4E49\u63D0\u4F9B\u65B9\u540D\u79F0\u3001\u5730\u5740\u6216\u6A21\u578B\u65E0\u6548");let r;try{r=await kt(t,"utf8")}catch(l){if(l.code!=="ENOENT")throw l}let i;if(r===void 0)i={providers:{}};else{try{i=JSON.parse(r)}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 Et(It(t),{recursive:!0});let p=r===void 0?384:(await St(t)).mode&511,o=`${t}.pi-web-${vt(6).toString("hex")}.tmp`;try{await xt(o,`${JSON.stringify(n,null,2)}
|
|
2
|
+
`,{mode:p,flag:"wx"}),await bt(o,t)}finally{await Pt(o,{force:!0})}}import{randomBytes as Mt}from"node:crypto";import{mkdir as At,readFile as Tt,rename as Nt,rm as Rt,stat as Wt,writeFile as jt}from"node:fs/promises";import{dirname as Lt}from"node:path";function ge(t){if(!t||t.length>2048)return!1;try{let e=new URL(t);return(e.protocol==="https:"||e.protocol==="http:")&&!!e.hostname&&!e.username&&!e.password&&!e.search&&!e.hash}catch{return!1}}function we(t){if(!t||typeof t!="object")return!1;let e=t;return e.action==="save"?(e.originalId===void 0||typeof e.originalId=="string")&&he(e.model):e.action==="base_url"?e.baseUrl===null||typeof e.baseUrl=="string"&&ge(e.baseUrl):e.action==="remove"&&typeof e.id=="string"&&e.id.length>0&&e.id.length<=200}function he(t){if(!t||typeof t!="object")return!1;let e=t;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 r of[e.contextWindow,e.maxTokens])if(r!==void 0&&(!Number.isSafeInteger(r)||r<=0))return!1;return e.input===void 0||Array.isArray(e.input)&&e.input.length>0&&e.input.every(r=>r==="text"||r==="image")&&new Set(e.input).size===e.input.length}async function ye(t){let e;try{e=await Tt(t,"utf8")}catch(i){if(i.code!=="ENOENT")throw i}if(e===void 0)return{config:{providers:{}}};let r;try{r=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(!r||typeof r!="object"||!r.providers||typeof r.providers!="object"||Array.isArray(r.providers))throw new Error("models.json \u7ED3\u6784\u65E0\u6548");return{config:r,existing:e}}async function _t(t,e,r){await At(Lt(t),{recursive:!0});let i=r===void 0?384:(await Wt(t)).mode&511,n=`${t}.pi-web-${Mt(6).toString("hex")}.tmp`;try{await jt(n,`${JSON.stringify(e,null,2)}
|
|
3
|
+
`,{mode:i,flag:"wx"}),await Nt(n,t)}finally{await Rt(n,{force:!0})}}async function ve(t,e,r){if(!r.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:i}=await ye(t),n=i.providers[e],p=new Set(n?.models?.map(o=>o.id)??[]);return{providerId:e,baseUrl:n?.baseUrl,models:r.getModels(e).map(o=>({id:o.id,name:o.name,contextWindow:o.contextWindow,maxTokens:o.maxTokens,input:[...o.input],source:p.has(o.id)?"custom":"builtin",overridden:!!n?.modelOverrides?.[o.id]}))}}async function ke(t,e,r,i){if(!i.getProvider(e))throw new Error("\u63D0\u4F9B\u65B9\u4E0D\u5B58\u5728");let{config:n,existing:p}=await ye(t),o={...n.providers[e]??{}},l=[...o.models??[]],a={...o.modelOverrides??{}};if(r.action==="base_url"){if(r.baseUrl!==null&&!ge(r.baseUrl))throw new Error("API \u5730\u5740\u65E0\u6548");r.baseUrl===null?delete o.baseUrl:o.baseUrl=r.baseUrl}else if(r.action==="save"){if(!he(r.model))throw new Error("\u6A21\u578B\u53C2\u6570\u65E0\u6548");let u={id:r.model.id.trim(),...r.model.name===void 0?{}:{name:r.model.name},...r.model.contextWindow===void 0?{}:{contextWindow:r.model.contextWindow},...r.model.maxTokens===void 0?{}:{maxTokens:r.model.maxTokens},...r.model.input===void 0?{}:{input:r.model.input}},h=r.originalId,y=h===void 0?-1:l.findIndex(b=>b.id===h);if(h===void 0&&(l.some(b=>b.id===u.id)||i.getModel(e,u.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");if(y>=0){if(u.id!==h&&(l.some(g=>g.id===u.id)||i.getModel(e,u.id)))throw new Error("\u6A21\u578B ID \u5DF2\u5B58\u5728");let b={...l[y],...u};for(let g of["name","contextWindow","maxTokens","input"])u[g]===void 0&&delete b[g];l[y]=b}else if(h!==void 0&&i.getModel(e,h)){if(u.id!==h)throw new Error("\u5185\u7F6E\u6A21\u578B ID \u4E0D\u53EF\u4FEE\u6539");let{id:b,...g}=u;a[h]={...a[h],...g};for(let d of["name","contextWindow","maxTokens","input"])u[d]===void 0&&delete a[h][d]}else{if(h!==void 0)throw new Error("\u6A21\u578B\u4E0D\u5B58\u5728");l.push(u)}}else{let u=l.findIndex(h=>h.id===r.id);if(u>=0)l.splice(u,1);else if(Object.hasOwn(a,r.id))delete a[r.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?o.models=l:delete o.models,Object.keys(a).length?o.modelOverrides=a:delete o.modelOverrides,Object.keys(o).length?n.providers[e]=o:delete n.providers[e],await _t(t,n,p)}function be(t){return/^(?:npm:|git:|https?:\/\/|ssh:\/\/|git@)/i.test(t.trim())}var $t={"/":{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 m(t,e,r){t.writeHead(e,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),t.end(JSON.stringify(r))}function Ft(t,e){let r=t.headers.authorization;if(typeof r!="string"||!r.startsWith("Bearer "))return!1;let i=Buffer.from(r.slice(7),"utf8");return i.length===e.length&&Ut(i,e)}async function Jt(t){let e=0,r=[];for await(let i of t){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");r.push(n)}return JSON.parse(Buffer.concat(r).toString("utf8"))}async function Ht(t){let e=0,r=[];for await(let i of t){let n=Buffer.isBuffer(i)?i:Buffer.from(i);if(e+=n.length,e>_)throw new Error("\u6587\u4EF6\u8D85\u8FC7 20 MB");r.push(n)}return Buffer.concat(r)}async function Gt(t,e=0){await new Promise((i,n)=>{t.once("error",n),t.listen(e,"127.0.0.1",()=>{t.off("error",n),i()})});let r=t.address();if(r===null||typeof r=="string")throw new Error("\u65E0\u6CD5\u786E\u5B9A\u76D1\u542C\u7AEF\u53E3");return r.port}async function Pe(t,e){let r=process.env.PI_WEBAPP_RESTART_TOKEN,i=r&&/^[A-Za-z0-9_-]{32}$/.test(r)?r:Vt(24).toString("base64url"),n=Buffer.from(i),p=ae(),o=new Set,l=new Map,a=new V,u="",h=Ot(async(g,d)=>{d.setHeader("X-Content-Type-Options","nosniff"),d.setHeader("Referrer-Policy","no-referrer"),d.setHeader("Content-Security-Policy","default-src 'self'; script-src 'self'; style-src 'self'; connect-src 'self'; img-src 'self' data: blob:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'");let f;try{f=new URL(g.url??"/",u).pathname}catch{m(d,400,{error:"\u8BF7\u6C42\u5730\u5740\u65E0\u6548"});return}let W=$t[f];if(g.method==="GET"&&W){try{let c=await Bt(Dt(e,W.path));d.writeHead(200,{"Content-Type":W.type,"Cache-Control":"no-store"}),d.end(c)}catch{m(d,500,{error:"\u9875\u9762\u6587\u4EF6\u4E0D\u53EF\u7528"})}return}if(!f.startsWith("/api/")){m(d,404,{error:"\u672A\u627E\u5230"});return}if(!Ft(g,n)){m(d,401,{error:"\u8BBF\u95EE\u4EE4\u724C\u65E0\u6548"});return}if(g.method==="GET"&&f==="/api/update/version"){try{m(d,200,{current:await t.selfUpdate?.runningVersion()??null})}catch(c){m(d,503,{error:c instanceof Error?c.message:"\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C"})}return}if(g.method==="GET"&&f==="/api/update"){try{m(d,200,await t.selfUpdate?.check()??{canRestart:!1,reason:"\u5F53\u524D\u6269\u5C55\u4E0D\u652F\u6301\u5728\u7EBF\u5347\u7EA7"})}catch(c){m(d,503,{error:c instanceof Error?c.message:"\u68C0\u67E5\u66F4\u65B0\u5931\u8D25"})}return}if(g.method==="GET"&&f==="/api/image"){let c=new URL(g.url??f,u),w=c.searchParams.get("sessionId")??"",k=c.searchParams.get("messageId")??"",v=Number(c.searchParams.get("index"));if(!w||w!==t.snapshot().sessionId||!k||!Number.isInteger(v)||v<0||v>100){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u56FE\u7247\u5730\u5740\u65E0\u6548"});return}let A=t.image?.(w,k,v);if(!A||!["image/png","image/jpeg","image/webp","image/gif"].includes(A.mimeType)){m(d,404,{error:"\u56FE\u7247\u4E0D\u53EF\u7528"});return}d.writeHead(200,{"Content-Type":A.mimeType,"Cache-Control":"private, no-store"}),d.end(A.data);return}if(g.method==="POST"&&f==="/api/attachment"){if(g.headers.origin!==void 0&&g.headers.origin!==u){m(d,403,{error:"\u6765\u6E90\u4E0D\u5339\u914D"});return}let c=new URL(g.url??f,u),w=c.searchParams.get("sessionId"),k=c.searchParams.get("name");try{if(!w||!k||k.length>1024||w!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u6587\u4EF6\u540D\u65E0\u6548"});return}if(Number(g.headers["content-length"]??0)>_){m(d,413,{error:"\u6587\u4EF6\u8D85\u8FC7 20 MB"});return}let v=await pe(w,k,g.headers["content-type"]??"application/octet-stream",await Ht(g));if(w!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}l.set(v.id,v),m(d,201,{id:v.id,name:v.name,bytes:v.bytes})}catch(v){m(d,400,{error:v instanceof Error?v.message:"\u4E0A\u4F20\u5931\u8D25"})}return}if(g.method==="GET"&&f==="/api/session"){try{m(d,200,t.snapshot())}catch{m(d,503,{error:"\u5F53\u524D\u4F1A\u8BDD\u4E0D\u53EF\u7528"})}return}if(g.method==="GET"&&f==="/api/providers"){try{m(d,200,await t.providers?.()??[])}catch{m(d,503,{error:"\u6A21\u578B\u63D0\u4F9B\u65B9\u4E0D\u53EF\u7528"})}return}if(g.method==="GET"&&f==="/api/provider/models"){let c=new URL(g.url??f,u).searchParams.get("providerId")??"";try{if(!c||!t.providerModels){m(d,400,{error:"\u63D0\u4F9B\u65B9\u65E0\u6548"});return}m(d,200,await t.providerModels(c))}catch(w){m(d,400,{error:w instanceof Error?w.message:"\u6A21\u578B\u76EE\u5F55\u4E0D\u53EF\u7528"})}return}if(g.method==="GET"&&f==="/api/provider/login/active"){m(d,200,{active:a.getActive()??null});return}if(g.method==="GET"&&f==="/api/provider/login"){let c=new URL(g.url??f,u).searchParams.get("id")??"",w=a.get(c);m(d,w?200:404,w??{error:"\u767B\u5F55\u6D41\u7A0B\u4E0D\u5B58\u5728"});return}if(g.method==="GET"&&(f==="/api/models"||f==="/api/config"||f==="/api/workspaces"||f==="/api/commands")){try{m(d,200,f==="/api/models"?await t.models():f==="/api/config"?await t.config():f==="/api/commands"?t.commands?.()??[]:await t.workspaces())}catch{m(d,503,{error:"Pi \u914D\u7F6E\u4E0D\u53EF\u7528"})}return}if(g.method==="GET"&&f==="/api/directory/capability"){m(d,200,{kind:p});return}if(g.method==="GET"&&f==="/api/events"){let c;try{c=t.snapshot()}catch{m(d,503,{error:"\u5F53\u524D\u4F1A\u8BDD\u4E0D\u53EF\u7528"});return}d.writeHead(200,{"Content-Type":"application/x-ndjson; charset=utf-8","Cache-Control":"no-store",Connection:"keep-alive","X-Accel-Buffering":"no"}),o.add(d),d.write(`${JSON.stringify({type:"snapshot",session:c})}
|
|
4
|
+
`),d.on("close",()=>o.delete(d));return}if(g.method==="POST"&&["/api/update","/api/message","/api/attachment/remove","/api/abort","/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(f)){if(g.headers.origin!==void 0&&g.headers.origin!==u){m(d,403,{error:"\u6765\u6E90\u4E0D\u5339\u914D"});return}if(!g.headers["content-type"]?.startsWith("application/json")){m(d,415,{error:"\u9700\u8981 JSON \u8BF7\u6C42"});return}try{let c=await Jt(g);if(typeof c!="object"||c===null||!("sessionId"in c)||typeof c.sessionId!="string"){m(d,400,{error:"\u7F3A\u5C11\u4F1A\u8BDD\u6807\u8BC6"});return}if(f==="/api/update"){if(c.sessionId!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!t.snapshot().idle){m(d,409,{error:"\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u540E\u518D\u5347\u7EA7"});return}if(!t.selfUpdate){m(d,409,{error:"\u5F53\u524D\u6269\u5C55\u4E0D\u652F\u6301\u5728\u7EBF\u5347\u7EA7"});return}let w=await t.selfUpdate.prepare();m(d,202,{accepted:!0,version:w.version}),setTimeout(()=>{t.selfUpdate?.requestRestart(w).catch(k=>console.error("pi-webapp restart:",k))},500).unref();return}if(f==="/api/provider/custom"){if(c.sessionId!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("provider"in c)||!G(c.provider)||!t.addCustomProvider){m(d,400,{error:"\u81EA\u5B9A\u4E49\u63D0\u4F9B\u65B9\u65E0\u6548"});return}await t.addCustomProvider(c.sessionId,c.provider),m(d,201,{accepted:!0});return}if(f==="/api/provider/models"||f==="/api/provider/logout"){if(c.sessionId!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(!("providerId"in c)||typeof c.providerId!="string"){m(d,400,{error:"\u63D0\u4F9B\u65B9\u65E0\u6548"});return}if(f==="/api/provider/models"){if(!("change"in c)||!we(c.change)||!t.updateProviderModel){m(d,400,{error:"\u6A21\u578B\u53C2\u6570\u65E0\u6548"});return}await t.updateProviderModel(c.sessionId,c.providerId,c.change)}else{if(!t.logoutProvider){m(d,400,{error:"\u65E0\u6CD5\u79FB\u9664\u8BA4\u8BC1"});return}await t.logoutProvider(c.sessionId,c.providerId)}m(d,200,{accepted:!0});return}if(f.startsWith("/api/provider/login")){if(c.sessionId!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362"});return}if(f==="/api/provider/login"){if(!("providerId"in c)||typeof c.providerId!="string"||!("method"in c)||c.method!=="api_key"&&c.method!=="oauth"||!t.loginProvider||!t.providers){m(d,400,{error:"\u767B\u5F55\u65B9\u5F0F\u65E0\u6548"});return}if(!(await t.providers()).some(A=>A.id===c.providerId&&A.methods.includes(c.method))){m(d,400,{error:"\u63D0\u4F9B\u65B9\u4E0D\u652F\u6301\u6B64\u767B\u5F55\u65B9\u5F0F"});return}let k="initialSecret"in c?c.initialSecret:void 0;if(k!==void 0&&(c.method!=="api_key"||typeof k!="string"||!k.trim()||k.length>16384)){m(d,400,{error:"API Key \u65E0\u6548"});return}let v=a.start(c.providerId,c.method,t.loginProvider,k);m(d,202,{id:v.id});return}if(!("id"in c)||typeof c.id!="string"){m(d,400,{error:"\u767B\u5F55\u6D41\u7A0B\u65E0\u6548"});return}if(f==="/api/provider/login/cancel"){m(d,a.cancel(c.id)?202:404,{accepted:!0});return}if(!("value"in c)||typeof c.value!="string"||c.value.length>16384||!a.respond(c.id,c.value)){m(d,400,{error:"\u767B\u5F55\u8F93\u5165\u65E0\u6548"});return}m(d,202,{accepted:!0});return}if(f==="/api/attachment/remove"){if(!("id"in c)||typeof c.id!="string"||c.sessionId!==t.snapshot().sessionId){m(d,409,{error:"\u4F1A\u8BDD\u5DF2\u5207\u6362\u6216\u9644\u4EF6\u65E0\u6548"});return}l.get(c.id)?.sessionId===c.sessionId&&l.delete(c.id),m(d,202,{accepted:!0});return}if(f==="/api/directory/pick"){if(p!=="native"){m(d,409,{error:"\u672C\u5730\u76EE\u5F55\u9009\u62E9\u5668\u4E0D\u53EF\u7528"});return}let w=new AbortController;d.once("close",()=>w.abort()),m(d,200,{path:await ce(w.signal)});return}if(f==="/api/directory/list"){if("path"in c&&(typeof c.path!="string"||c.path.length>4096)){m(d,400,{error:"\u76EE\u5F55\u8DEF\u5F84\u65E0\u6548"});return}m(d,200,await ne("path"in c?c.path:void 0));return}if(f==="/api/directory/create"){if(!("path"in c)||typeof c.path!="string"||c.path.length>4096||!("name"in c)||typeof c.name!="string"||c.name.length>255){m(d,400,{error:"\u6587\u4EF6\u5939\u540D\u79F0\u6216\u8DEF\u5F84\u65E0\u6548"});return}m(d,200,{path:await oe(c.path,c.name)});return}if(f==="/api/workspace/add"){if(!("path"in c)||typeof c.path!="string"||c.path.length>4096||!("create"in c)||typeof c.create!="boolean"){m(d,400,{error:"\u5DE5\u4F5C\u533A\u8DEF\u5F84\u65E0\u6548"});return}await t.addWorkspace(c.path,c.create),m(d,202,{accepted:!0});return}if(f==="/api/workspace/select"||f==="/api/workspace/remove"||f==="/api/workspace/new-session"){if(!("id"in c)||typeof c.id!="string"){m(d,400,{error:"\u5DE5\u4F5C\u533A\u65E0\u6548"});return}f==="/api/workspace/select"?await t.selectWorkspace(c.id):f==="/api/workspace/new-session"?await t.newSessionInWorkspace(c.id):await t.removeWorkspace(c.id),m(d,202,{accepted:!0});return}if(f==="/api/session/select"){if(!("workspaceId"in c)||typeof c.workspaceId!="string"||!("id"in c)||typeof c.id!="string"||!("path"in c)||typeof c.path!="string"){m(d,400,{error:"\u4F1A\u8BDD\u65E0\u6548"});return}await t.selectSession(c.workspaceId,c.id,c.path),m(d,202,{accepted:!0});return}if(f==="/api/thinking-level"){if(!("level"in c)||typeof c.level!="string"){m(d,400,{error:"\u63A8\u7406\u5F3A\u5EA6\u65E0\u6548"});return}await t.setThinkingLevel(c.sessionId,c.level)}else if(f==="/api/model"){if(!("provider"in c)||typeof c.provider!="string"||!("id"in c)||typeof c.id!="string"){m(d,400,{error:"\u6A21\u578B\u65E0\u6548"});return}await t.setModel(c.sessionId,c.provider,c.id)}else if(f==="/api/config"){let w=c;if(!["packages","extensions","skills"].includes(w.kind)||!["global","project"].includes(w.scope)||!["add","remove"].includes(w.action)||typeof w.value!="string"||!w.value.trim()||w.value.length>2048){m(d,400,{error:"\u914D\u7F6E\u9879\u65E0\u6548"});return}if(w.action==="add"&&w.kind!=="packages"&&be(w.value)){m(d,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}m(d,200,await t.updateConfig(w));return}else if(f==="/api/message"){let w="attachments"in c?c.attachments:[];if(!Array.isArray(w)||w.length>de||w.some(S=>typeof S!="string")||new Set(w).size!==w.length){m(d,400,{error:"\u9644\u4EF6\u65E0\u6548\u6216\u8FC7\u591A"});return}let k=w.map(S=>l.get(S));if(k.some(S=>!S||S.sessionId!==c.sessionId)){m(d,400,{error:"\u9644\u4EF6\u4E0D\u53EF\u7528"});return}if(!("text"in c)||typeof c.text!="string"||!c.text.trim()&&w.length===0||c.text.length>32e3){m(d,400,{error:"\u6D88\u606F\u65E0\u6548\u6216\u8FC7\u957F"});return}let v=k,A=[c.text.trim(),...v.map(S=>`\u9644\u4EF6 ${JSON.stringify(S.name)}\uFF1A${S.path}`)].filter(Boolean).join(`
|
|
5
5
|
|
|
6
|
-
`),
|
|
7
|
-
`;for(let f of p)f.write(c)},async close(){l.close();for(let g of p)g.end();p.clear(),await new Promise((g,c)=>u.close(f=>f?c(f):g()))}}}import{getSupportedThinkingLevels as Vt}from"@earendil-works/pi-ai";function he(t){let e=[],i=t;for(;;){let r=/(^|\n\n)附件 ("(?:\\.|[^"\\])*"):([^\n]+)$/u.exec(i);if(!r||!/[\\/]pi-web[\\/]attachments[\\/][a-f0-9]{64}[\\/]/u.test(r[3]))break;let n;try{n=JSON.parse(r[2])}catch{break}e.unshift({name:n,image:/\.(?:png|jpe?g|webp|gif)$/iu.test(n)}),i=i.slice(0,r.index)}return{text:i,attachments:e}}function M(t){return typeof t=="string"?[{kind:"text",text:t}]:t.flatMap(e=>e.type==="text"?[{kind:"text",text:e.text}]:e.type==="thinking"?[{kind:"thinking",text:e.thinking}]:e.type==="image"?[{kind:"image",text:"\u56FE\u7247\u9644\u4EF6"}]:e.type==="toolCall"?[{kind:"toolCall",text:JSON.stringify(e.arguments??{}),toolName:e.name,toolCallId:e.id}]:[])}function $(t){if(t.type==="custom_message")return t.display?{id:t.id,role:"notice",timestamp:t.timestamp,blocks:M(t.content)}:null;if(t.type!=="message")return null;let{message:e}=t;return e.role==="user"||e.role==="assistant"?{id:t.id,role:e.role,timestamp:t.timestamp,blocks:M(e.content),...e.role==="assistant"?{...e.stopReason==="error"&&e.errorMessage?{error:e.errorMessage}:{},usage:{input:e.usage.input,output:e.usage.output,cacheRead:e.usage.cacheRead,cacheWrite:e.usage.cacheWrite,...e.usage.reasoning===void 0?{}:{reasoning:e.usage.reasoning},totalTokens:e.usage.totalTokens,cost:e.usage.cost.total},model:`${e.provider}/${e.model}`}:{}}:e.role==="toolResult"?{id:t.id,role:"tool",timestamp:t.timestamp,blocks:M(e.content),isError:e.isError,toolCallId:e.toolCallId,toolName:e.toolName}:null}function F(t,e){let i=t?.trim();if(i)return i;let r=e.find(p=>p.role==="user"),n=he(r?.blocks.find(p=>p.kind==="text")?.text??"").text.replace(/\s+/g," ").trim();return n?n.slice(0,50):"\u5F53\u524D\u4F1A\u8BDD"}function ye(t,e){let i=t.sessionManager.getBranch().flatMap(r=>{let n=$(r);return n?[n]:[]});return{schemaVersion:1,sessionId:t.sessionManager.getSessionId(),cwd:t.cwd,name:F(e,i),model:t.model?`${t.model.provider}/${t.model.id}`:null,thinkingLevel:t.thinkingLevel??null,thinkingLevels:t.model?Vt(t.model):["off"],idle:t.isIdle(),contextUsage:t.getContextUsage()??null,messages:i}}import{randomUUID as H}from"node:crypto";import{mkdir as ve,readFile as _t,realpath as ke,rename as Bt,rm as Ot,stat as be,writeFile as Ut}from"node:fs/promises";import{basename as Pe,dirname as Dt,isAbsolute as Se,join as $t}from"node:path";var R=class{items=[];hiddenPaths=[];mutationChain=Promise.resolve();file;constructor(e){this.file=e}async load(){try{let e=JSON.parse(await _t(this.file,"utf8")),i,r=[];if(Array.isArray(e)?i=e:e&&typeof e=="object"&&"version"in e&&e.version===2&&"items"in e&&"hiddenPaths"in e&&(i=e.items,r=e.hiddenPaths),!Array.isArray(i)||!Array.isArray(r))throw new Error("\u5DE5\u4F5C\u533A\u8BB0\u5F55\u65E0\u6548");this.items=i.filter(n=>typeof n=="object"&&n!==null&&typeof n.id=="string"&&typeof n.path=="string"&&typeof n.title=="string"),this.hiddenPaths=r.filter(n=>typeof n=="string")}catch(e){if(e.code!=="ENOENT")throw e}}list(){return[...this.items]}get(e){return this.items.find(i=>i.id===e)}async add(e,i=!1){if(!Se(e)||e.includes("\0"))throw new Error("\u8BF7\u8F93\u5165\u5B8C\u6574\u7684\u76EE\u5F55\u8DEF\u5F84");i&&await ve(e,{recursive:!0});let r=await ke(e);if(!(await be(r)).isDirectory())throw new Error("\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55");return this.mutate(async()=>{let n=this.hiddenPaths.filter(a=>a!==r),p=this.items.find(a=>a.path===r);if(p)return n.length!==this.hiddenPaths.length&&(await this.save(this.items,n),this.hiddenPaths=n),p;let o={id:H(),path:r,title:Pe(r)||r},l=[o,...this.items];return await this.save(l,n),this.items=l,this.hiddenPaths=n,o})}async discover(e){let i=(await Promise.all([...new Set(e)].filter(Se).map(async r=>{try{let n=await ke(r);return(await be(n)).isDirectory()?n:null}catch{return null}}))).filter(r=>r!==null);await this.mutate(async()=>{let r=new Set([...this.items.map(o=>o.path),...this.hiddenPaths]),n=[];for(let o of i)r.has(o)||(r.add(o),n.push({id:H(),path:o,title:Pe(o)||o}));if(n.length===0)return;let p=[...this.items,...n];await this.save(p,this.hiddenPaths),this.items=p})}async remove(e){await this.mutate(async()=>{let i=this.get(e);if(!i)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");let r=this.items.filter(p=>p.id!==e),n=[...new Set([...this.hiddenPaths,i.path])];await this.save(r,n),this.items=r,this.hiddenPaths=n})}mutate(e){let i=this.mutationChain.then(e,e);return this.mutationChain=i.then(()=>{},()=>{}),i}async save(e,i){await ve(Dt(this.file),{recursive:!0});let r=`${this.file}.${H()}.tmp`;try{await Ut(r,JSON.stringify({version:2,items:e,hiddenPaths:i},null,2),{mode:384}),await Bt(r,this.file)}catch(n){throw await Ot(r,{force:!0}),n}}};function xe(t){return $t(t,"pi-web","workspaces.json")}import{createAgentSession as Ht,DefaultResourceLoader as Jt,getAgentDir as Gt,SessionManager as V}from"@earendil-works/pi-coding-agent";import{realpath as Ee}from"node:fs/promises";import{realpath as Ie}from"node:fs/promises";import{SessionManager as Ft}from"@earendil-works/pi-coding-agent";async function W(t,e){let i=await Ie(t),r=e??await Ft.listAll(),n=await Promise.all(r.map(async p=>p.cwd!==""&&await Ie(p.cwd).catch(()=>null)===i));return r.filter((p,o)=>n[o])}var _=class{active=null;detach=null;cwd=null;lastStreamAt=0;publish;fallbackModel;constructor(e,i){this.publish=e,this.fallbackModel=i}get session(){return this.active}get path(){return this.cwd}async open(e,i){if(this.active&&!this.active.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u5DE5\u4F5C\u533A");let r=await Ee(e),n;if(i==="new")n=V.create(r);else if(i==="continue"){let a=(await W(r))[0];n=a?V.open(a.path):V.create(r)}else n=V.open(i.sessionFile);if(await Ee(n.getCwd())!==r)throw new Error("\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u8BE5\u5DE5\u4F5C\u533A");let p=n.buildSessionProjection().model?void 0:this.active?.model??this.fallbackModel(),o=new Jt({cwd:r,agentDir:Gt(),noExtensions:!0});await o.reload();let{session:l}=await Ht({cwd:r,sessionManager:n,model:p,resourceLoader:o});this.detach?.(),this.active?.dispose(),this.active=l,this.cwd=r,this.detach=l.subscribe(a=>{if(a.type==="message_update"&&a.message.role==="assistant"){let u=Date.now();u-this.lastStreamAt>=60&&(this.lastStreamAt=u,this.publish({type:"stream",message:{id:"stream",role:"assistant",timestamp:new Date(a.message.timestamp).toISOString(),blocks:M(a.message.content)}}))}(a.type==="message_end"||a.type==="agent_start"||a.type==="agent_settled"||a.type==="session_info_changed")&&(a.type==="message_end"&&a.message.role==="assistant"&&this.publish({type:"stream",message:null}),this.publish({type:"snapshot",session:this.snapshot()}))}),this.publish({type:"stream",message:null}),this.publish({type:"snapshot",session:this.snapshot()})}snapshot(){let e=this.active;if(!e||!this.cwd)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u5DE5\u4F5C\u533A\u4F1A\u8BDD");let i=e.sessionManager.getBranch().flatMap(r=>{let n=$(r);return n?[n]:[]});return{schemaVersion:1,sessionId:e.sessionManager.getSessionId(),cwd:this.cwd,name:F(e.sessionManager.getSessionName(),i),model:e.model?`${e.model.provider}/${e.model.id}`:null,thinkingLevel:e.thinkingLevel,thinkingLevels:e.getAvailableThinkingLevels(),idle:e.isIdle,contextUsage:e.getContextUsage()??null,messages:i}}async send(e,i=[]){if(!this.active||!this.active.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let r=this.active,n=!1,p,o,l=new Promise((a,u)=>{p=a,o=u});r.prompt(e,{images:i,preflightResult:a=>{a&&(n=!0,p())}}).then(()=>{n||p()}).catch(a=>{n?this.publish({type:"error",message:a instanceof Error?a.message:"Pi \u8BF7\u6C42\u5931\u8D25"}):o(a)}),await l}async stop(){await this.active?.abort()}async models(){return(await this.active?.modelRuntime.getAvailable()??[]).map(i=>({provider:i.provider,id:i.id,name:i.name}))}async setModel(e,i){if(!this.active||!this.active.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let r=this.active.modelRuntime.getModel(e,i);if(!r)throw new Error("\u6A21\u578B\u4E0D\u53EF\u7528");await this.active.setModel(r),this.publish({type:"snapshot",session:this.snapshot()})}dispose(){this.detach?.(),this.active?.dispose(),this.detach=null,this.active=null,this.cwd=null}};import{basename as J,dirname as Kt}from"node:path";function Ce(t,e){let i=r=>e[r].map(n=>({name:r==="skills"&&J(n.path).toLowerCase()==="skill.md"?J(Kt(n.path)):J(n.path),path:n.path,source:n.metadata.source,scope:n.metadata.scope,enabled:n.enabled}));return{packages:t.map(r=>({name:r.source,path:r.installedPath??"",source:r.source,scope:r.scope,enabled:!!r.installedPath})),extensions:i("extensions"),skills:i("skills")}}import{execFile as zt}from"node:child_process";var Yt=(t,e)=>new Promise((i,r)=>{zt(t,[...e],{windowsHide:!0},n=>{n?r(n):i()})});async function G(t,e=process.platform,i=process.env,r=Yt){if(i.SSH_CONNECTION||i.SSH_TTY||i.SSH_CLIENT||e==="linux"&&!i.DISPLAY&&!i.WAYLAND_DISPLAY)return!1;let n=e==="darwin"?"open":e==="linux"?"xdg-open":e==="win32"?"explorer.exe":null;return n===null?!1:(await r(n,[t]),!0)}var ii=Qt(Xt(Zt(import.meta.url)),"../web/dist"),ri=Symbol.for("pi-web.bridge-state"),s=globalThis[ri]??={bridge:null,current:null,commandContext:null,pi:null,replacementContext:null,replacementSessionId:null,lastStreamAt:0,workspaces:null,workspaceSessions:null,selected:"tui",activeWorkspaceId:null,autoOpened:!1},si=null;function ni(){return si??=qt.create({refreshOnCreate:!1})}var B=new Map;async function A(){let t=await ni(),e=s.selected==="tui"?s.current?.modelRegistry:void 0,i=new Set(e?.getRegisteredProviderIds()??[]);for(let r of B.keys())i.has(r)||(t.unregisterProvider(r),B.delete(r));for(let r of i){let n=e?.getRegisteredNativeProvider(r),p=e?.getRegisteredProviderConfig(r),o=n??p;!o||B.get(r)===o||(n?t.registerNativeProvider(n):p&&t.registerProvider(r,p),B.set(r,o))}return await t.refresh({allowNetwork:!1}),t}function k(){if(s.selected==="sdk")return s.workspaceSessions?.snapshot()??(()=>{throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD")})();if(s.current===null)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");return ye(s.current,s.current.sessionManager.getSessionName())}function S(t){if(k().sessionId!==t)throw new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362")}async function Te(){let t=s.workspaces?.list()??[],e=k(),i=await O(e.cwd).catch(()=>e.cwd),r=await Ae.listAll(),n=(await Promise.all(t.map(async p=>{let l=(await W(p.path,r).catch(()=>[])).map(a=>({id:a.id,workspaceId:p.id,path:a.path,name:a.name||a.firstMessage?.slice(0,50)||"\u5F53\u524D\u4F1A\u8BDD",modified:a.modified.toISOString()}));return p.path===i&&!l.some(a=>a.id===e.sessionId)&&l.unshift({id:e.sessionId,workspaceId:p.id,path:null,name:e.name,modified:new Date().toISOString()}),l}))).flat();return{items:t,activeId:s.activeWorkspaceId,sessions:n}}async function I(){s.bridge&&s.bridge.publish({type:"workspaces",value:await Te()})}async function z(t,e=!1){let i=s.workspaces?.get(t);if(!i)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");if(await O(i.path),!e&&s.current&&i.path===await O(s.current.cwd)){if(s.selected==="sdk"&&s.workspaceSessions?.session&&!s.workspaceSessions.session.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u5DE5\u4F5C\u533A");s.selected="tui",s.activeWorkspaceId=t,s.bridge?.publish({type:"stream",message:null}),s.bridge?.publish({type:"snapshot",session:k()})}else{if(!s.workspaceSessions)throw new Error("Pi \u5DE5\u4F5C\u533A\u670D\u52A1\u4E0D\u53EF\u7528");await s.workspaceSessions.open(i.path,e?"new":"continue"),s.selected="sdk",s.activeWorkspaceId=t,s.bridge?.publish({type:"snapshot",session:k()})}await I()}function x(t){let e=s.current;if(e===null||e.sessionManager.getSessionId()!==t)throw new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362");return e}function P(t){s.current=t,s.selected==="tui"&&s.bridge?.publish({type:"snapshot",session:k()})}function We(){if(s.current===null)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");let t=s.selected==="sdk"?s.workspaceSessions?.path:s.current.cwd;if(!t)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u5DE5\u4F5C\u533A");let e=s.selected==="tui"?s.current.isProjectTrusted():s.workspaceSessions?.session?.settingsManager.isProjectTrusted()??!1;return ei.create(t,void 0,{projectTrusted:e})}async function Le(){let t=We(),e=n=>({packages:(n.packages??[]).map(p=>typeof p=="string"?p:p.source),extensions:n.extensions??[],skills:n.skills??[]}),i=new Me({cwd:k().cwd,agentDir:T(),settingsManager:t}),r=Ce(i.listConfiguredPackages(),await i.resolve(async()=>"skip"));return{projectTrusted:t.isProjectTrusted(),global:e(t.getGlobalSettings()),project:e(t.getProjectSettings()),installed:r}}async function oi(t){S(t.sessionId);let e=s.selected==="tui"?x(t.sessionId):null;if(e?!e.isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let i=We();if(t.scope==="project"&&!i.isProjectTrusted())throw new Error("\u5F53\u524D\u9879\u76EE\u5C1A\u672A\u53D7\u4FE1\u4EFB\uFF0C\u65E0\u6CD5\u4FEE\u6539\u9879\u76EE\u8BBE\u7F6E");let r=t.value.trim(),n=t.scope==="project"?i.getProjectSettings():i.getGlobalSettings();if(t.kind==="packages"){let p=new Me({cwd:k().cwd,agentDir:T(),settingsManager:i});t.action==="add"?await p.installAndPersist(r,{local:t.scope==="project"}):await p.removeAndPersist(r,{local:t.scope==="project"})}else if(t.kind==="extensions"){let p=n.extensions??[],o=t.action==="add"?[...new Set([...p,r])]:p.filter(l=>l!==r);t.scope==="project"?i.setProjectExtensionPaths(o):i.setExtensionPaths(o)}else{let p=n.skills??[],o=t.action==="add"?[...new Set([...p,r])]:p.filter(l=>l!==r);t.scope==="project"?i.setProjectSkillPaths(o):i.setSkillPaths(o)}return await i.flush(),s.selected==="tui"?(s.commandContext&&await s.commandContext.reload(),s.current&&P(s.current)):(await s.workspaceSessions?.session?.resourceLoader.reload(),s.workspaceSessions?.session?.refreshContext()),await Le()}function ai(t,e=G){s.pi=t,t.on("session_start",(r,n)=>{s.replacementSessionId!==n.sessionManager.getSessionId()&&(s.replacementContext=null,s.replacementSessionId=null),P(n),s.selected==="tui"&&s.workspaces&&s.workspaces.add(n.cwd).then(async p=>{s.selected!=="tui"||s.current?.sessionManager.getSessionId()!==n.sessionManager.getSessionId()||(s.activeWorkspaceId=p.id,await I())}).catch(p=>{s.bridge?.publish({type:"error",message:p instanceof Error?p.message:"\u65E0\u6CD5\u6CE8\u518C\u5F53\u524D\u5DE5\u4F5C\u533A"})}),process.env.PI_WEBAPP_AUTO_OPEN==="1"&&n.mode==="tui"&&!s.autoOpened&&(s.autoOpened=!0,i(n).catch(p=>{n.ui.notify(p instanceof Error?p.message:"Web \u542F\u52A8\u5931\u8D25","error")}))}),t.on("agent_start",(r,n)=>P(n)),t.on("agent_end",(r,n)=>P(n)),t.on("agent_settled",(r,n)=>P(n)),t.on("model_select",(r,n)=>P(n)),t.on("thinking_level_select",(r,n)=>P(n)),t.on("message_end",(r,n)=>{s.selected==="tui"&&r.message.role==="assistant"&&s.bridge?.publish({type:"stream",message:null}),P(n),s.selected==="tui"&&I()}),t.on("session_info_changed",(r,n)=>P(n)),t.on("message_update",(r,n)=>{if(s.current=n,s.selected!=="tui"||r.message.role!=="assistant"||s.bridge===null)return;let p=Date.now();p-s.lastStreamAt<60||(s.lastStreamAt=p,s.bridge.publish({type:"stream",message:{id:"stream",role:"assistant",timestamp:new Date(r.message.timestamp).toISOString(),blocks:M(r.message.content)}}))}),t.on("session_shutdown",r=>{if(s.current=null,r.reason==="new"||r.reason==="resume"||r.reason==="fork")return;let n=s.bridge;s.bridge=null,s.commandContext=null,s.replacementContext=null,s.replacementSessionId=null,s.pi=null,s.workspaceSessions?.dispose(),s.workspaceSessions=null,s.selected="tui",s.activeWorkspaceId=null,s.autoOpened=!1,n&&n.close()});let i=async r=>{s.current=r,s.commandContext="newSession"in r?r:null,s.pi=t,s.workspaces===null&&(s.workspaces=new R(xe(T())),await s.workspaces.load());try{await s.workspaces.discover((await Ae.listAll()).map(o=>o.cwd))}catch(o){r.ui.notify(`\u65E0\u6CD5\u8BFB\u53D6\u90E8\u5206 Pi \u5386\u53F2\u5DE5\u4F5C\u533A\uFF1A${o instanceof Error?o.message:String(o)}`,"warning")}let n=await s.workspaces.add(r.cwd);if(s.selected==="tui"&&(s.activeWorkspaceId=n.id),s.bridge&&s.bridge.protocolVersion!==3){let o=s.bridge;s.bridge=null,await o.close()}s.bridge===null&&(s.workspaceSessions=new _(o=>{s.selected==="sdk"&&(s.bridge?.publish(o),o.type==="snapshot"&&o.session.idle&&I())},()=>s.current?.model),s.bridge=await we({snapshot:k,image(o,l,a){S(o);let h=(s.selected==="sdk"?s.workspaceSessions?.session?.sessionManager.getBranch():s.current?.sessionManager.getBranch())?.find(c=>c.id===l);if(h?.type!=="message"||h.message.role!=="user"||!Array.isArray(h.message.content))return null;let g=h.message.content[a];return g?.type!=="image"?null:{data:Buffer.from(g.data,"base64"),mimeType:g.mimeType}},async workspaces(){return Te()},async addWorkspace(o,l){let a=await s.workspaces.add(o,l);try{await z(a.id,!0)}catch(u){throw await I(),u}},async selectWorkspace(o){await z(o)},async newSessionInWorkspace(o){await z(o,!0)},async removeWorkspace(o){if(o===s.activeWorkspaceId)throw new Error("\u8BF7\u5148\u5207\u6362\u5230\u5176\u4ED6\u5DE5\u4F5C\u533A");await s.workspaces.remove(o),await I()},async selectSession(o,l,a){let u=s.workspaces?.get(o);if(!u)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");if(l===s.current?.sessionManager.getSessionId()&&u.path===await O(s.current.cwd)){if(s.selected==="sdk"&&s.workspaceSessions?.session&&!s.workspaceSessions.session.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u4F1A\u8BDD");s.selected="tui",s.activeWorkspaceId=o,s.bridge?.publish({type:"snapshot",session:k()})}else{if(s.selected==="sdk"&&s.workspaceSessions?.session?.sessionManager.getSessionId()===l&&s.workspaceSessions.path===u.path)return;if(!(await W(u.path)).some(g=>g.id===l&&g.path===a))throw new Error("\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u8BE5\u5DE5\u4F5C\u533A");await s.workspaceSessions.open(u.path,{sessionFile:a}),s.selected="sdk",s.activeWorkspaceId=o,s.bridge?.publish({type:"snapshot",session:k()})}await I()},async models(){if(s.selected==="sdk")return s.workspaceSessions?.models()??[];let o=s.current;if(!o)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");let l=o.scopedModels?.map(a=>`${a.model.provider}/${a.model.id}`)??[];return o.modelRegistry.getAvailable().filter(a=>l.length===0||l.includes(`${a.provider}/${a.id}`)).map(a=>({provider:a.provider,id:a.id,name:a.name}))},async providers(){let o=await A(),l=new Set((await o.listCredentials()).map(a=>a.providerId));return o.getProviders().map(a=>({id:a.id,name:a.name,configured:o.getProviderAuthStatus(a.id).configured,storedCredential:l.has(a.id),methods:[a.auth.apiKey?.login?"api_key":null,a.auth.oauth?"oauth":null].filter(u=>u!==null)}))},async providerModels(o){let l=await A();return me(K(T(),"models.json"),o,l)},async updateProviderModel(o,l,a){if(S(o),s.selected==="tui"?!x(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let u=k().model;if(a.action==="remove"&&u===`${l}/${a.id}`)throw new Error("\u8BF7\u5148\u5207\u6362\u5F53\u524D\u4F7F\u7528\u7684\u6A21\u578B");if(a.action==="save"&&a.originalId&&a.originalId!==a.model.id&&u===`${l}/${a.originalId}`)throw new Error("\u8BF7\u5148\u5207\u6362\u5F53\u524D\u4F7F\u7528\u7684\u6A21\u578B");let h=await A();await fe(K(T(),"models.json"),l,a,h),await h.refresh({providers:[l],allowNetwork:!1}),await s.current?.modelRegistry.refresh({providers:[l],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[l],allowNetwork:!1});let g=a.action==="save"?a.model.id:a.action==="base_url"&&u?.startsWith(`${l}/`)?u.slice(l.length+1):null;if(g&&u===`${l}/${g}`)if(s.selected==="sdk")try{await s.workspaceSessions.setModel(l,g)}catch{throw new Error("\u6A21\u578B\u5DF2\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u8BE5\u6A21\u578B\u4EE5\u5E94\u7528\u65B0\u53C2\u6570")}else{let c=x(o),f=c.modelRegistry.find(l,g);if(!f||!s.pi||!await s.pi.setModel(f))throw new Error("\u6A21\u578B\u5DF2\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u8BE5\u6A21\u578B\u4EE5\u5E94\u7528\u65B0\u53C2\u6570");P(c)}},async logoutProvider(o,l){if(S(o),s.selected==="tui"?!x(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let a=await A();if(!(await a.listCredentials()).some(u=>u.providerId===l))throw new Error("\u8BE5\u63D0\u4F9B\u65B9\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1");await a.logout(l),await s.current?.modelRegistry.refresh({providers:[l],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[l],allowNetwork:!1})},async loginProvider(o,l,a){let u=await A();await u.login(o,l,ae(o,l,a)),await u.refresh({providers:[o],allowNetwork:!1}),await s.current?.modelRegistry.refresh({providers:[o],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[o],allowNetwork:!1})},async addCustomProvider(o,l){if(S(o),s.selected==="tui"?!x(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let a=await A();if(a.getProvider(l.id))throw new Error("\u63D0\u4F9B\u65B9\u5DF2\u5B58\u5728");await de(K(T(),"models.json"),l),await a.refresh({allowNetwork:!1}),await s.current?.modelRegistry.refresh({allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({allowNetwork:!1})},commands(){return s.selected==="tui"?(s.pi?.getCommands()??[]).filter(o=>o.name!=="web").map(o=>({name:o.name,description:o.description})):[]},async compact(o){if(S(o),s.selected==="sdk"){let a=s.workspaceSessions?.session;if(!a||!a.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");await a.compact(),s.bridge?.publish({type:"snapshot",session:k()});return}let l=x(o);if(!l.isIdle())throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");l.compact()},async setModel(o,l,a){if(S(o),s.selected==="sdk"){await s.workspaceSessions.setModel(l,a);return}let u=x(o);if(!u.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let h=u.modelRegistry.find(l,a);if(!h||!u.modelRegistry.getAvailable().some(g=>g.provider===l&&g.id===a))throw new Error("\u6A21\u578B\u4E0D\u53EF\u7528");if(!s.pi||!await s.pi.setModel(h))throw new Error("\u6A21\u578B\u63D0\u4F9B\u65B9\u672A\u914D\u7F6E\u8BA4\u8BC1");P(u)},async setThinkingLevel(o,l){if(S(o),!["off","minimal","low","medium","high","xhigh"].includes(l))throw new Error("\u63A8\u7406\u5F3A\u5EA6\u65E0\u6548");if(s.selected==="sdk"){let h=s.workspaceSessions?.session;if(!h||!h.isIdle||!h.getAvailableThinkingLevels().includes(l))throw new Error("\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u6B64\u63A8\u7406\u5F3A\u5EA6");h.setThinkingLevel(l),s.bridge?.publish({type:"snapshot",session:k()});return}let u=x(o);if(!u.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(!u.model||!ti(u.model).includes(l))throw new Error("\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u6B64\u63A8\u7406\u5F3A\u5EA6");if(!s.pi)throw new Error("Pi \u4F1A\u8BDD\u4E0D\u53EF\u7528");s.pi.setThinkingLevel(l),P(u)},config:Le,updateConfig:oi,async send(o,l,a=[]){if(S(o),s.selected==="sdk"){await s.workspaceSessions.send(l,a);return}if(!x(o).isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(s.replacementContext!==null&&s.replacementSessionId===o){await s.replacementContext.sendUserMessage(a.length?[{type:"text",text:l},...a]:l,{expandPromptTemplates:!0});return}if(s.pi===null)throw new Error("Pi \u4F1A\u8BDD\u4E0D\u53EF\u7528");s.pi.sendUserMessage(a.length?[{type:"text",text:l},...a]:l,{expandPromptTemplates:!0})},abort(o){S(o),s.selected==="sdk"?s.workspaceSessions.stop():x(o).abort()},async newSession(o){if(S(o),s.selected==="sdk"){let u=s.workspaces?.get(s.activeWorkspaceId??"");if(!u)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");await s.workspaceSessions.open(u.path,"new"),await I();return}let l=x(o);if(!l.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(s.commandContext===null){await s.workspaceSessions.open(l.cwd,"new"),s.selected="sdk",s.bridge?.publish({type:"snapshot",session:k()}),await I();return}if((await s.commandContext.newSession({withSession:async u=>{s.commandContext=u,s.replacementContext=u,s.replacementSessionId=u.sessionManager.getSessionId(),s.current=u}})).cancelled)throw new Error("\u65B0\u4F1A\u8BDD\u5DF2\u53D6\u6D88");await I()}},ii));let p=await e(s.bridge.url).catch(()=>!1);r.ui.notify(`pi-webapp: ${s.bridge.url}`,p?"info":"warning"),r.ui.setStatus("pi-webapp","Web \u5DF2\u542F\u52A8 \xB7 /web \u91CD\u65B0\u6253\u5F00")};t.registerCommand("web",{description:"Open the current Pi session in a local web interface",handler:async(r,n)=>i(n)})}export{ai as default};
|
|
6
|
+
`),Je=await Promise.all(v.filter(S=>["image/png","image/jpeg","image/webp","image/gif"].includes(S.mediaType)).map(ue));await t.send(c.sessionId,A,Je);for(let S of w)l.delete(S)}else if(f==="/api/compact"){if(!t.compact)throw new Error("\u5F53\u524D\u4F1A\u8BDD\u4E0D\u652F\u6301\u538B\u7F29");await t.compact(c.sessionId)}else f==="/api/abort"?t.abort(c.sessionId):await t.newSession(c.sessionId);m(d,202,{accepted:!0})}catch(c){let w=c instanceof Error?c.message:"\u8BF7\u6C42\u5931\u8D25";m(d,w==="\u4F1A\u8BDD\u5DF2\u5207\u6362"?409:400,{error:w})}return}m(d,404,{error:"\u672A\u627E\u5230"})}),y=Number(process.env.PI_WEBAPP_RESTART_PORT);return u=`http://127.0.0.1:${await Gt(h,Number.isInteger(y)&&y>0&&y<65536&&r===i?y:0)}`,{protocolVersion:4,url:`${u}/#${i}`,publish(g){if(g.type==="snapshot")for(let[f,W]of l)W.sessionId!==g.session.sessionId&&l.delete(f);let d=`${JSON.stringify(g)}
|
|
7
|
+
`;for(let f of o)f.write(d)},async close(){a.close();for(let g of o)g.end();o.clear(),await new Promise((g,d)=>h.close(f=>f?d(f):g()))}}}import{getSupportedThinkingLevels as zt}from"@earendil-works/pi-ai";function Se(t){let e=[],r=t;for(;;){let i=/(^|\n\n)附件 ("(?:\\.|[^"\\])*"):([^\n]+)$/u.exec(r);if(!i||!/[\\/]pi-web[\\/]attachments[\\/][a-f0-9]{64}[\\/]/u.test(i[3]))break;let n;try{n=JSON.parse(i[2])}catch{break}e.unshift({name:n,image:/\.(?:png|jpe?g|webp|gif)$/iu.test(n)}),r=r.slice(0,i.index)}return{text:r,attachments:e}}function T(t){return typeof t=="string"?[{kind:"text",text:t}]:t.flatMap(e=>e.type==="text"?[{kind:"text",text:e.text}]:e.type==="thinking"?[{kind:"thinking",text:e.thinking}]:e.type==="image"?[{kind:"image",text:"\u56FE\u7247\u9644\u4EF6"}]:e.type==="toolCall"?[{kind:"toolCall",text:JSON.stringify(e.arguments??{}),toolName:e.name,toolCallId:e.id}]:[])}function z(t){if(t.type==="custom_message")return t.display?{id:t.id,role:"notice",timestamp:t.timestamp,blocks:T(t.content)}:null;if(t.type!=="message")return null;let{message:e}=t;return e.role==="user"||e.role==="assistant"?{id:t.id,role:e.role,timestamp:t.timestamp,blocks:T(e.content),...e.role==="assistant"?{...e.stopReason==="error"&&e.errorMessage?{error:e.errorMessage}:{},usage:{input:e.usage.input,output:e.usage.output,cacheRead:e.usage.cacheRead,cacheWrite:e.usage.cacheWrite,...e.usage.reasoning===void 0?{}:{reasoning:e.usage.reasoning},totalTokens:e.usage.totalTokens,cost:e.usage.cost.total},model:`${e.provider}/${e.model}`}:{}}:e.role==="toolResult"?{id:t.id,role:"tool",timestamp:t.timestamp,blocks:T(e.content),isError:e.isError,toolCallId:e.toolCallId,toolName:e.toolName}:null}function K(t,e){let r=t?.trim();if(r)return r;let i=e.find(p=>p.role==="user"),n=Se(i?.blocks.find(p=>p.kind==="text")?.text??"").text.replace(/\s+/g," ").trim();return n?n.slice(0,50):"\u5F53\u524D\u4F1A\u8BDD"}function xe(t,e){let r=t.sessionManager.getBranch().flatMap(i=>{let n=z(i);return n?[n]:[]});return{schemaVersion:1,sessionId:t.sessionManager.getSessionId(),cwd:t.cwd,name:K(e,r),model:t.model?`${t.model.provider}/${t.model.id}`:null,thinkingLevel:t.thinkingLevel??null,thinkingLevels:t.model?zt(t.model):["off"],idle:t.isIdle(),contextUsage:t.getContextUsage()??null,messages:r}}import{randomUUID as Y}from"node:crypto";import{mkdir as Ee,readFile as Kt,realpath as Ie,rename as Yt,rm as Xt,stat as Ce,writeFile as Zt}from"node:fs/promises";import{basename as Me,dirname as Qt,isAbsolute as Ae,join as qt}from"node:path";var U=class{items=[];hiddenPaths=[];mutationChain=Promise.resolve();file;constructor(e){this.file=e}async load(){try{let e=JSON.parse(await Kt(this.file,"utf8")),r,i=[];if(Array.isArray(e)?r=e:e&&typeof e=="object"&&"version"in e&&e.version===2&&"items"in e&&"hiddenPaths"in e&&(r=e.items,i=e.hiddenPaths),!Array.isArray(r)||!Array.isArray(i))throw new Error("\u5DE5\u4F5C\u533A\u8BB0\u5F55\u65E0\u6548");this.items=r.filter(n=>typeof n=="object"&&n!==null&&typeof n.id=="string"&&typeof n.path=="string"&&typeof n.title=="string"),this.hiddenPaths=i.filter(n=>typeof n=="string")}catch(e){if(e.code!=="ENOENT")throw e}}list(){return[...this.items]}get(e){return this.items.find(r=>r.id===e)}async add(e,r=!1){if(!Ae(e)||e.includes("\0"))throw new Error("\u8BF7\u8F93\u5165\u5B8C\u6574\u7684\u76EE\u5F55\u8DEF\u5F84");r&&await Ee(e,{recursive:!0});let i=await Ie(e);if(!(await Ce(i)).isDirectory())throw new Error("\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55");return this.mutate(async()=>{let n=this.hiddenPaths.filter(a=>a!==i),p=this.items.find(a=>a.path===i);if(p)return n.length!==this.hiddenPaths.length&&(await this.save(this.items,n),this.hiddenPaths=n),p;let o={id:Y(),path:i,title:Me(i)||i},l=[o,...this.items];return await this.save(l,n),this.items=l,this.hiddenPaths=n,o})}async discover(e){let r=(await Promise.all([...new Set(e)].filter(Ae).map(async i=>{try{let n=await Ie(i);return(await Ce(n)).isDirectory()?n:null}catch{return null}}))).filter(i=>i!==null);await this.mutate(async()=>{let i=new Set([...this.items.map(o=>o.path),...this.hiddenPaths]),n=[];for(let o of r)i.has(o)||(i.add(o),n.push({id:Y(),path:o,title:Me(o)||o}));if(n.length===0)return;let p=[...this.items,...n];await this.save(p,this.hiddenPaths),this.items=p})}async remove(e){await this.mutate(async()=>{let r=this.get(e);if(!r)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");let i=this.items.filter(p=>p.id!==e),n=[...new Set([...this.hiddenPaths,r.path])];await this.save(i,n),this.items=i,this.hiddenPaths=n})}mutate(e){let r=this.mutationChain.then(e,e);return this.mutationChain=r.then(()=>{},()=>{}),r}async save(e,r){await Ee(Qt(this.file),{recursive:!0});let i=`${this.file}.${Y()}.tmp`;try{await Zt(i,JSON.stringify({version:2,items:e,hiddenPaths:r},null,2),{mode:384}),await Yt(i,this.file)}catch(n){throw await Xt(i,{force:!0}),n}}};function Te(t){return qt(t,"pi-web","workspaces.json")}import{createAgentSession as tr,DefaultResourceLoader as rr,getAgentDir as ir,SessionManager as B}from"@earendil-works/pi-coding-agent";import{realpath as Re}from"node:fs/promises";import{realpath as Ne}from"node:fs/promises";import{SessionManager as er}from"@earendil-works/pi-coding-agent";async function j(t,e){let r=await Ne(t),i=e??await er.listAll(),n=await Promise.all(i.map(async p=>p.cwd!==""&&await Ne(p.cwd).catch(()=>null)===r));return i.filter((p,o)=>n[o])}var O=class{active=null;detach=null;cwd=null;lastStreamAt=0;publish;fallbackModel;constructor(e,r){this.publish=e,this.fallbackModel=r}get session(){return this.active}get path(){return this.cwd}async open(e,r){if(this.active&&!this.active.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u5DE5\u4F5C\u533A");let i=await Re(e),n;if(r==="new")n=B.create(i);else if(r==="continue"){let a=(await j(i))[0];n=a?B.open(a.path):B.create(i)}else n=B.open(r.sessionFile);if(await Re(n.getCwd())!==i)throw new Error("\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u8BE5\u5DE5\u4F5C\u533A");let p=n.buildSessionProjection().model?void 0:this.active?.model??this.fallbackModel(),o=new rr({cwd:i,agentDir:ir(),noExtensions:!0});await o.reload();let{session:l}=await tr({cwd:i,sessionManager:n,model:p,resourceLoader:o});this.detach?.(),this.active?.dispose(),this.active=l,this.cwd=i,this.detach=l.subscribe(a=>{if(a.type==="message_update"&&a.message.role==="assistant"){let u=Date.now();u-this.lastStreamAt>=60&&(this.lastStreamAt=u,this.publish({type:"stream",message:{id:"stream",role:"assistant",timestamp:new Date(a.message.timestamp).toISOString(),blocks:T(a.message.content)}}))}(a.type==="message_end"||a.type==="agent_start"||a.type==="agent_settled"||a.type==="session_info_changed")&&(a.type==="message_end"&&a.message.role==="assistant"&&this.publish({type:"stream",message:null}),this.publish({type:"snapshot",session:this.snapshot()}))}),this.publish({type:"stream",message:null}),this.publish({type:"snapshot",session:this.snapshot()})}snapshot(){let e=this.active;if(!e||!this.cwd)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u5DE5\u4F5C\u533A\u4F1A\u8BDD");let r=e.sessionManager.getBranch().flatMap(i=>{let n=z(i);return n?[n]:[]});return{schemaVersion:1,sessionId:e.sessionManager.getSessionId(),cwd:this.cwd,name:K(e.sessionManager.getSessionName(),r),model:e.model?`${e.model.provider}/${e.model.id}`:null,thinkingLevel:e.thinkingLevel,thinkingLevels:e.getAvailableThinkingLevels(),idle:e.isIdle,contextUsage:e.getContextUsage()??null,messages:r}}async send(e,r=[]){if(!this.active||!this.active.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let i=this.active,n=!1,p,o,l=new Promise((a,u)=>{p=a,o=u});i.prompt(e,{images:r,preflightResult:a=>{a&&(n=!0,p())}}).then(()=>{n||p()}).catch(a=>{n?this.publish({type:"error",message:a instanceof Error?a.message:"Pi \u8BF7\u6C42\u5931\u8D25"}):o(a)}),await l}async stop(){await this.active?.abort()}async models(){return(await this.active?.modelRuntime.getAvailable()??[]).map(r=>({provider:r.provider,id:r.id,name:r.name}))}async setModel(e,r){if(!this.active||!this.active.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let i=this.active.modelRuntime.getModel(e,r);if(!i)throw new Error("\u6A21\u578B\u4E0D\u53EF\u7528");await this.active.setModel(i),this.publish({type:"snapshot",session:this.snapshot()})}dispose(){this.detach?.(),this.active?.dispose(),this.detach=null,this.active=null,this.cwd=null}};import{basename as X,dirname as sr}from"node:path";function We(t,e){let r=i=>e[i].map(n=>({name:i==="skills"&&X(n.path).toLowerCase()==="skill.md"?X(sr(n.path)):X(n.path),path:n.path,source:n.metadata.source,scope:n.metadata.scope,enabled:n.enabled}));return{packages:t.map(i=>({name:i.source,path:i.installedPath??"",source:i.source,scope:i.scope,enabled:!!i.installedPath})),extensions:r("extensions"),skills:r("skills")}}import{execFile as nr}from"node:child_process";var or=(t,e)=>new Promise((r,i)=>{nr(t,[...e],{windowsHide:!0},n=>{n?i(n):r()})});async function Z(t,e=process.platform,r=process.env,i=or){if(r.SSH_CONNECTION||r.SSH_TTY||r.SSH_CLIENT||e==="linux"&&!r.DISPLAY&&!r.WAYLAND_DISPLAY)return!1;let n=e==="darwin"?"open":e==="linux"?"xdg-open":e==="win32"?"explorer.exe":null;return n===null?!1:(await i(n,[t]),!0)}import{execFile as ar}from"node:child_process";import{randomUUID as cr}from"node:crypto";import{existsSync as je}from"node:fs";import{access as lr,mkdir as dr,readFile as Le,rename as pr,rm as Q,writeFile as _e}from"node:fs/promises";import{join as x}from"node:path";import{promisify as ur}from"node:util";var mr=ur(ar),D=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/;function fr(t,e){let r=D.exec(t),i=D.exec(e);if(!r||!i)throw new Error("\u7248\u672C\u53F7\u65E0\u6548");for(let n=1;n<=3;n++){let p=Number(r[n])-Number(i[n]);if(p)return p}return!r[4]&&i[4]?1:r[4]&&!i[4]?-1:(r[4]??"").localeCompare(i[4]??"",void 0,{numeric:!0})}async function gr(t){try{let{stdout:e}=await mr("npm",t,{timeout:18e4,maxBuffer:1048576,encoding:"utf8"});return e}catch(e){let r=e;throw new Error(r.stderr?.trim()||r.message)}}var $=class{agentDir;packageRoot;launcherNonce;runNpm;preparing=!1;restartPending=!1;constructor(e){this.agentDir=e.agentDir,this.packageRoot=e.packageRoot,this.launcherNonce=e.launcherNonce,this.runNpm=e.runNpm??gr}async current(){let e=JSON.parse(await Le(x(this.packageRoot,"package.json"),"utf8"));if(e.name!=="pi-webapp"||typeof e.version!="string"||!D.test(e.version))throw new Error("\u5F53\u524D pi-webapp \u7248\u672C\u65E0\u6548");return e.version}async runningVersion(){return this.current()}async check(){let e=await this.current(),r=je(x(this.packageRoot,".git")),i={current:e,latest:null,available:!1,canRestart:!!this.launcherNonce&&!r};r?i.reason="\u5F53\u524D\u4ECE\u6E90\u7801\u76EE\u5F55\u8FD0\u884C\u3002\u7F51\u9875\u5347\u7EA7\u4EC5\u652F\u6301 npm \u5B89\u88C5\u7684\u7248\u672C\uFF0C\u4EE5\u514D\u8986\u76D6\u672C\u5730\u4EE3\u7801\u3002":i.canRestart||(i.reason="\u5F53\u524D\u9875\u9762\u7531 Pi \u7EC8\u7AEF\u6253\u5F00\uFF0C\u65E0\u6CD5\u4ECE\u7F51\u9875\u81EA\u52A8\u91CD\u542F Pi\uFF1B\u8BF7\u4F7F\u7528 pi-webapp \u542F\u52A8\u5668\u3002");try{let n=JSON.parse((await this.runNpm(["view","pi-webapp","dist-tags.latest","--json","--prefer-online"])).trim());if(typeof n!="string"||!D.test(n))throw new Error("npm \u8FD4\u56DE\u7684\u7248\u672C\u53F7\u65E0\u6548");i.latest=n,i.available=fr(n,e)>0}catch(n){throw new Error(`\u68C0\u67E5 npm \u66F4\u65B0\u5931\u8D25\uFF1A${n instanceof Error?n.message:String(n)}`)}return i}async prepare(){if(!this.launcherNonce)throw new Error("\u5F53\u524D\u9875\u9762\u65E0\u6CD5\u81EA\u52A8\u91CD\u542F Pi");if(je(x(this.packageRoot,".git")))throw new Error("\u6E90\u7801\u76EE\u5F55\u4E0D\u80FD\u901A\u8FC7\u7F51\u9875\u5347\u7EA7");if(this.restartPending)throw new Error("\u5347\u7EA7\u5DF2\u5B8C\u6210\uFF0C\u6B63\u5728\u91CD\u542F");if(this.preparing)throw new Error("\u5347\u7EA7\u6B63\u5728\u8FDB\u884C\u4E2D");this.preparing=!0;try{let e=await this.check();if(!e.available||!e.latest)throw new Error("\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C");let r=x(this.agentDir,"pi-web","releases",e.latest);await Q(r,{recursive:!0,force:!0}),await dr(r,{recursive:!0});try{await this.runNpm(["install",`pi-webapp@${e.latest}`,"--prefix",r,"--ignore-scripts","--no-save","--no-audit","--no-fund"]);let i=x(r,"node_modules","pi-webapp"),n=JSON.parse(await Le(x(i,"package.json"),"utf8"));if(n.name!=="pi-webapp"||n.version!==e.latest)throw new Error("\u4E0B\u8F7D\u7684\u5305\u4E0E\u76EE\u6807\u7248\u672C\u4E0D\u7B26");let p=x(i,"bin","pi-webapp.mjs");await Promise.all([p,x(i,"dist","extension.js"),x(i,"web","dist","index.html")].map(a=>lr(a)));let o=x(this.agentDir,"pi-web"),l=x(o,`update.${cr()}.tmp`);try{await _e(l,JSON.stringify({version:e.latest,launcher:p}),{mode:384}),await pr(l,x(o,"update.json"))}finally{await Q(l,{force:!0})}return this.restartPending=!0,{version:e.latest,launcher:p}}catch(i){throw await Q(r,{recursive:!0,force:!0}),i}}finally{this.preparing=!1}}async requestRestart(e){if(!this.launcherNonce)throw new Error("\u5F53\u524D\u9875\u9762\u65E0\u6CD5\u81EA\u52A8\u91CD\u542F Pi");try{await _e(x(this.agentDir,"pi-web","launcher.restart"),JSON.stringify({nonce:this.launcherNonce,launcher:e.launcher}),{mode:384})}catch(r){throw this.restartPending=!1,r}}};var Ve=Ue(wr(hr(import.meta.url)),"../web/dist"),br=Symbol.for("pi-web.bridge-state"),s=globalThis[br]??={bridge:null,current:null,commandContext:null,pi:null,replacementContext:null,replacementSessionId:null,lastStreamAt:0,workspaces:null,workspaceSessions:null,selected:"tui",activeWorkspaceId:null,autoOpened:!1},Pr=null;function Sr(){return Pr??=yr.create({refreshOnCreate:!1})}var F=new Map;async function R(){let t=await Sr(),e=s.selected==="tui"?s.current?.modelRegistry:void 0,r=new Set(e?.getRegisteredProviderIds()??[]);for(let i of F.keys())r.has(i)||(t.unregisterProvider(i),F.delete(i));for(let i of r){let n=e?.getRegisteredNativeProvider(i),p=e?.getRegisteredProviderConfig(i),o=n??p;!o||F.get(i)===o||(n?t.registerNativeProvider(n):p&&t.registerProvider(i,p),F.set(i,o))}return await t.refresh({allowNetwork:!1}),t}function P(){if(s.selected==="sdk")return s.workspaceSessions?.snapshot()??(()=>{throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD")})();if(s.current===null)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");return xe(s.current,s.current.sessionManager.getSessionName())}function I(t){if(P().sessionId!==t)throw new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362")}async function De(){let t=s.workspaces?.list()??[],e=P(),r=await J(e.cwd).catch(()=>e.cwd),i=await Oe.listAll(),n=(await Promise.all(t.map(async p=>{let l=(await j(p.path,i).catch(()=>[])).map(a=>({id:a.id,workspaceId:p.id,path:a.path,name:a.name||a.firstMessage?.slice(0,50)||"\u5F53\u524D\u4F1A\u8BDD",modified:a.modified.toISOString()}));return p.path===r&&!l.some(a=>a.id===e.sessionId)&&l.unshift({id:e.sessionId,workspaceId:p.id,path:null,name:e.name,modified:new Date().toISOString()}),l}))).flat();return{items:t,activeId:s.activeWorkspaceId,sessions:n}}async function M(){s.bridge&&s.bridge.publish({type:"workspaces",value:await De()})}async function ee(t,e=!1){let r=s.workspaces?.get(t);if(!r)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");if(await J(r.path),!e&&s.current&&r.path===await J(s.current.cwd)){if(s.selected==="sdk"&&s.workspaceSessions?.session&&!s.workspaceSessions.session.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u5DE5\u4F5C\u533A");s.selected="tui",s.activeWorkspaceId=t,s.bridge?.publish({type:"stream",message:null}),s.bridge?.publish({type:"snapshot",session:P()})}else{if(!s.workspaceSessions)throw new Error("Pi \u5DE5\u4F5C\u533A\u670D\u52A1\u4E0D\u53EF\u7528");await s.workspaceSessions.open(r.path,e?"new":"continue"),s.selected="sdk",s.activeWorkspaceId=t,s.bridge?.publish({type:"snapshot",session:P()})}await M()}function C(t){let e=s.current;if(e===null||e.sessionManager.getSessionId()!==t)throw new Error("\u4F1A\u8BDD\u5DF2\u5207\u6362");return e}function E(t){s.current=t,s.selected==="tui"&&s.bridge?.publish({type:"snapshot",session:P()})}function $e(){if(s.current===null)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");let t=s.selected==="sdk"?s.workspaceSessions?.path:s.current.cwd;if(!t)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u5DE5\u4F5C\u533A");let e=s.selected==="tui"?s.current.isProjectTrusted():s.workspaceSessions?.session?.settingsManager.isProjectTrusted()??!1;return vr.create(t,void 0,{projectTrusted:e})}async function Fe(){let t=$e(),e=n=>({packages:(n.packages??[]).map(p=>typeof p=="string"?p:p.source),extensions:n.extensions??[],skills:n.skills??[]}),r=new Be({cwd:P().cwd,agentDir:N(),settingsManager:t}),i=We(r.listConfiguredPackages(),await r.resolve(async()=>"skip"));return{projectTrusted:t.isProjectTrusted(),global:e(t.getGlobalSettings()),project:e(t.getProjectSettings()),installed:i}}async function xr(t){I(t.sessionId);let e=s.selected==="tui"?C(t.sessionId):null;if(e?!e.isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let r=$e();if(t.scope==="project"&&!r.isProjectTrusted())throw new Error("\u5F53\u524D\u9879\u76EE\u5C1A\u672A\u53D7\u4FE1\u4EFB\uFF0C\u65E0\u6CD5\u4FEE\u6539\u9879\u76EE\u8BBE\u7F6E");let i=t.value.trim(),n=t.scope==="project"?r.getProjectSettings():r.getGlobalSettings();if(t.kind==="packages"){let p=new Be({cwd:P().cwd,agentDir:N(),settingsManager:r});t.action==="add"?await p.installAndPersist(i,{local:t.scope==="project"}):await p.removeAndPersist(i,{local:t.scope==="project"})}else if(t.kind==="extensions"){let p=n.extensions??[],o=t.action==="add"?[...new Set([...p,i])]:p.filter(l=>l!==i);t.scope==="project"?r.setProjectExtensionPaths(o):r.setExtensionPaths(o)}else{let p=n.skills??[],o=t.action==="add"?[...new Set([...p,i])]:p.filter(l=>l!==i);t.scope==="project"?r.setProjectSkillPaths(o):r.setSkillPaths(o)}return await r.flush(),s.selected==="tui"?(s.commandContext&&await s.commandContext.reload(),s.current&&E(s.current)):(await s.workspaceSessions?.session?.resourceLoader.reload(),s.workspaceSessions?.session?.refreshContext()),await Fe()}function Er(t,e=Z){s.pi=t,t.on("session_start",(i,n)=>{s.replacementSessionId!==n.sessionManager.getSessionId()&&(s.replacementContext=null,s.replacementSessionId=null),E(n),s.selected==="tui"&&s.workspaces&&s.workspaces.add(n.cwd).then(async p=>{s.selected!=="tui"||s.current?.sessionManager.getSessionId()!==n.sessionManager.getSessionId()||(s.activeWorkspaceId=p.id,await M())}).catch(p=>{s.bridge?.publish({type:"error",message:p instanceof Error?p.message:"\u65E0\u6CD5\u6CE8\u518C\u5F53\u524D\u5DE5\u4F5C\u533A"})}),process.env.PI_WEBAPP_AUTO_OPEN==="1"&&n.mode==="tui"&&!s.autoOpened&&(s.autoOpened=!0,r(n).catch(p=>{n.ui.notify(p instanceof Error?p.message:"Web \u542F\u52A8\u5931\u8D25","error")}))}),t.on("agent_start",(i,n)=>E(n)),t.on("agent_end",(i,n)=>E(n)),t.on("agent_settled",(i,n)=>E(n)),t.on("model_select",(i,n)=>E(n)),t.on("thinking_level_select",(i,n)=>E(n)),t.on("message_end",(i,n)=>{s.selected==="tui"&&i.message.role==="assistant"&&s.bridge?.publish({type:"stream",message:null}),E(n),s.selected==="tui"&&M()}),t.on("session_info_changed",(i,n)=>E(n)),t.on("message_update",(i,n)=>{if(s.current=n,s.selected!=="tui"||i.message.role!=="assistant"||s.bridge===null)return;let p=Date.now();p-s.lastStreamAt<60||(s.lastStreamAt=p,s.bridge.publish({type:"stream",message:{id:"stream",role:"assistant",timestamp:new Date(i.message.timestamp).toISOString(),blocks:T(i.message.content)}}))}),t.on("session_shutdown",i=>{if(s.current=null,i.reason==="new"||i.reason==="resume"||i.reason==="fork")return;let n=s.bridge;s.bridge=null,s.commandContext=null,s.replacementContext=null,s.replacementSessionId=null,s.pi=null,s.workspaceSessions?.dispose(),s.workspaceSessions=null,s.selected="tui",s.activeWorkspaceId=null,s.autoOpened=!1,n&&n.close()});let r=async i=>{s.current=i,s.commandContext="newSession"in i?i:null,s.pi=t,s.workspaces===null&&(s.workspaces=new U(Te(N())),await s.workspaces.load());try{await s.workspaces.discover((await Oe.listAll()).map(o=>o.cwd))}catch(o){i.ui.notify(`\u65E0\u6CD5\u8BFB\u53D6\u90E8\u5206 Pi \u5386\u53F2\u5DE5\u4F5C\u533A\uFF1A${o instanceof Error?o.message:String(o)}`,"warning")}let n=await s.workspaces.add(i.cwd);if(s.selected==="tui"&&(s.activeWorkspaceId=n.id),s.bridge&&s.bridge.protocolVersion!==4){let o=s.bridge;s.bridge=null,await o.close()}s.bridge===null&&(s.workspaceSessions=new O(o=>{s.selected==="sdk"&&(s.bridge?.publish(o),o.type==="snapshot"&&o.session.idle&&M())},()=>s.current?.model),s.bridge=await Pe({selfUpdate:new $({agentDir:N(),packageRoot:Ue(Ve,"../.."),launcherNonce:process.env.PI_WEBAPP_LAUNCHER_NONCE}),snapshot:P,image(o,l,a){I(o);let h=(s.selected==="sdk"?s.workspaceSessions?.session?.sessionManager.getBranch():s.current?.sessionManager.getBranch())?.find(b=>b.id===l);if(h?.type!=="message"||h.message.role!=="user"||!Array.isArray(h.message.content))return null;let y=h.message.content[a];return y?.type!=="image"?null:{data:Buffer.from(y.data,"base64"),mimeType:y.mimeType}},async workspaces(){return De()},async addWorkspace(o,l){let a=await s.workspaces.add(o,l);try{await ee(a.id,!0)}catch(u){throw await M(),u}},async selectWorkspace(o){await ee(o)},async newSessionInWorkspace(o){await ee(o,!0)},async removeWorkspace(o){if(o===s.activeWorkspaceId)throw new Error("\u8BF7\u5148\u5207\u6362\u5230\u5176\u4ED6\u5DE5\u4F5C\u533A");await s.workspaces.remove(o),await M()},async selectSession(o,l,a){let u=s.workspaces?.get(o);if(!u)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");if(l===s.current?.sessionManager.getSessionId()&&u.path===await J(s.current.cwd)){if(s.selected==="sdk"&&s.workspaceSessions?.session&&!s.workspaceSessions.session.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u518D\u5207\u6362\u4F1A\u8BDD");s.selected="tui",s.activeWorkspaceId=o,s.bridge?.publish({type:"snapshot",session:P()})}else{if(s.selected==="sdk"&&s.workspaceSessions?.session?.sessionManager.getSessionId()===l&&s.workspaceSessions.path===u.path)return;if(!(await j(u.path)).some(y=>y.id===l&&y.path===a))throw new Error("\u4F1A\u8BDD\u4E0D\u5C5E\u4E8E\u8BE5\u5DE5\u4F5C\u533A");await s.workspaceSessions.open(u.path,{sessionFile:a}),s.selected="sdk",s.activeWorkspaceId=o,s.bridge?.publish({type:"snapshot",session:P()})}await M()},async models(){if(s.selected==="sdk")return s.workspaceSessions?.models()??[];let o=s.current;if(!o)throw new Error("\u6CA1\u6709\u6D3B\u52A8\u4F1A\u8BDD");let l=o.scopedModels?.map(a=>`${a.model.provider}/${a.model.id}`)??[];return o.modelRegistry.getAvailable().filter(a=>l.length===0||l.includes(`${a.provider}/${a.id}`)).map(a=>({provider:a.provider,id:a.id,name:a.name}))},async providers(){let o=await R(),l=new Set((await o.listCredentials()).map(a=>a.providerId));return o.getProviders().map(a=>({id:a.id,name:a.name,configured:o.getProviderAuthStatus(a.id).configured,storedCredential:l.has(a.id),methods:[a.auth.apiKey?.login?"api_key":null,a.auth.oauth?"oauth":null].filter(u=>u!==null)}))},async providerModels(o){let l=await R();return ve(q(N(),"models.json"),o,l)},async updateProviderModel(o,l,a){if(I(o),s.selected==="tui"?!C(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let u=P().model;if(a.action==="remove"&&u===`${l}/${a.id}`)throw new Error("\u8BF7\u5148\u5207\u6362\u5F53\u524D\u4F7F\u7528\u7684\u6A21\u578B");if(a.action==="save"&&a.originalId&&a.originalId!==a.model.id&&u===`${l}/${a.originalId}`)throw new Error("\u8BF7\u5148\u5207\u6362\u5F53\u524D\u4F7F\u7528\u7684\u6A21\u578B");let h=await R();await ke(q(N(),"models.json"),l,a,h),await h.refresh({providers:[l],allowNetwork:!1}),await s.current?.modelRegistry.refresh({providers:[l],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[l],allowNetwork:!1});let y=a.action==="save"?a.model.id:a.action==="base_url"&&u?.startsWith(`${l}/`)?u.slice(l.length+1):null;if(y&&u===`${l}/${y}`)if(s.selected==="sdk")try{await s.workspaceSessions.setModel(l,y)}catch{throw new Error("\u6A21\u578B\u5DF2\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u8BE5\u6A21\u578B\u4EE5\u5E94\u7528\u65B0\u53C2\u6570")}else{let b=C(o),g=b.modelRegistry.find(l,y);if(!g||!s.pi||!await s.pi.setModel(g))throw new Error("\u6A21\u578B\u5DF2\u4FDD\u5B58\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u8BE5\u6A21\u578B\u4EE5\u5E94\u7528\u65B0\u53C2\u6570");E(b)}},async logoutProvider(o,l){if(I(o),s.selected==="tui"?!C(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let a=await R();if(!(await a.listCredentials()).some(u=>u.providerId===l))throw new Error("\u8BE5\u63D0\u4F9B\u65B9\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1");await a.logout(l),await s.current?.modelRegistry.refresh({providers:[l],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[l],allowNetwork:!1})},async loginProvider(o,l,a){let u=await R();await u.login(o,l,me(o,l,a)),await u.refresh({providers:[o],allowNetwork:!1}),await s.current?.modelRegistry.refresh({providers:[o],allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({providers:[o],allowNetwork:!1})},async addCustomProvider(o,l){if(I(o),s.selected==="tui"?!C(o).isIdle():!s.workspaceSessions?.session?.isIdle)throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let a=await R();if(a.getProvider(l.id))throw new Error("\u63D0\u4F9B\u65B9\u5DF2\u5B58\u5728");await fe(q(N(),"models.json"),l),await a.refresh({allowNetwork:!1}),await s.current?.modelRegistry.refresh({allowNetwork:!1}),await s.workspaceSessions?.session?.modelRuntime.refresh({allowNetwork:!1})},commands(){return s.selected==="tui"?(s.pi?.getCommands()??[]).filter(o=>o.name!=="web").map(o=>({name:o.name,description:o.description})):[]},async compact(o){if(I(o),s.selected==="sdk"){let a=s.workspaceSessions?.session;if(!a||!a.isIdle)throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");await a.compact(),s.bridge?.publish({type:"snapshot",session:P()});return}let l=C(o);if(!l.isIdle())throw new Error("\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");l.compact()},async setModel(o,l,a){if(I(o),s.selected==="sdk"){await s.workspaceSessions.setModel(l,a);return}let u=C(o);if(!u.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");let h=u.modelRegistry.find(l,a);if(!h||!u.modelRegistry.getAvailable().some(y=>y.provider===l&&y.id===a))throw new Error("\u6A21\u578B\u4E0D\u53EF\u7528");if(!s.pi||!await s.pi.setModel(h))throw new Error("\u6A21\u578B\u63D0\u4F9B\u65B9\u672A\u914D\u7F6E\u8BA4\u8BC1");E(u)},async setThinkingLevel(o,l){if(I(o),!["off","minimal","low","medium","high","xhigh"].includes(l))throw new Error("\u63A8\u7406\u5F3A\u5EA6\u65E0\u6548");if(s.selected==="sdk"){let h=s.workspaceSessions?.session;if(!h||!h.isIdle||!h.getAvailableThinkingLevels().includes(l))throw new Error("\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u6B64\u63A8\u7406\u5F3A\u5EA6");h.setThinkingLevel(l),s.bridge?.publish({type:"snapshot",session:P()});return}let u=C(o);if(!u.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(!u.model||!kr(u.model).includes(l))throw new Error("\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u6B64\u63A8\u7406\u5F3A\u5EA6");if(!s.pi)throw new Error("Pi \u4F1A\u8BDD\u4E0D\u53EF\u7528");s.pi.setThinkingLevel(l),E(u)},config:Fe,updateConfig:xr,async send(o,l,a=[]){if(I(o),s.selected==="sdk"){await s.workspaceSessions.send(l,a);return}if(!C(o).isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(s.replacementContext!==null&&s.replacementSessionId===o){await s.replacementContext.sendUserMessage(a.length?[{type:"text",text:l},...a]:l,{expandPromptTemplates:!0});return}if(s.pi===null)throw new Error("Pi \u4F1A\u8BDD\u4E0D\u53EF\u7528");s.pi.sendUserMessage(a.length?[{type:"text",text:l},...a]:l,{expandPromptTemplates:!0})},abort(o){I(o),s.selected==="sdk"?s.workspaceSessions.stop():C(o).abort()},async newSession(o){if(I(o),s.selected==="sdk"){let u=s.workspaces?.get(s.activeWorkspaceId??"");if(!u)throw new Error("\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728");await s.workspaceSessions.open(u.path,"new"),await M();return}let l=C(o);if(!l.isIdle())throw new Error("Pi \u6B63\u5728\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u56DE\u590D\u7ED3\u675F");if(s.commandContext===null){await s.workspaceSessions.open(l.cwd,"new"),s.selected="sdk",s.bridge?.publish({type:"snapshot",session:P()}),await M();return}if((await s.commandContext.newSession({withSession:async u=>{s.commandContext=u,s.replacementContext=u,s.replacementSessionId=u.sessionManager.getSessionId(),s.current=u}})).cancelled)throw new Error("\u65B0\u4F1A\u8BDD\u5DF2\u53D6\u6D88");await M()}},Ve));let p=await e(s.bridge.url).catch(()=>!1);i.ui.notify(`pi-webapp: ${s.bridge.url}`,p?"info":"warning"),i.ui.setStatus("pi-webapp","Web \u5DF2\u542F\u52A8 \xB7 /web \u91CD\u65B0\u6253\u5F00")};t.registerCommand("web",{description:"Open the current Pi session in a local web interface",handler:async(i,n)=>r(n)})}export{Er as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-webapp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
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.6/assets/cover-webapp.png",
|
|
19
19
|
"extensions": [
|
|
20
20
|
"./dist/extension.js"
|
|
21
21
|
]
|