pi-web-ui 0.6.0 → 0.6.2
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/dist/server/agent-service.js +16 -5
- package/dist/server/index.js +11 -5
- package/package.json +1 -1
- package/web/dist/assets/{index-Bqsvd0gO.js → index-C24Ja_UP.js} +49 -49
- package/web/dist/assets/index-Lc62BKrm.css +41 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-CG0Zje9G.css +0 -41
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
13
|
import { existsSync, readFileSync, statSync, writeFileSync, mkdirSync, } from "node:fs";
|
|
14
|
-
import { dirname, join, resolve } from "node:path";
|
|
14
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
16
|
import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
17
17
|
import { serializeMessage, serializeStreamingMessage, } from "./serialize.js";
|
|
@@ -429,6 +429,18 @@ function extractPartialText(partial) {
|
|
|
429
429
|
}
|
|
430
430
|
return null;
|
|
431
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Resolve a workspace-relative path against a root, refusing traversal
|
|
434
|
+
* (".." escapes). Returns { abs, rel } — rel is normalized and slash-
|
|
435
|
+
* separated — or null when the path leaves the workspace.
|
|
436
|
+
*/
|
|
437
|
+
export function workspacePath(root, raw) {
|
|
438
|
+
const abs = resolve(root, raw);
|
|
439
|
+
const rel = relative(root, abs);
|
|
440
|
+
if (rel.startsWith("..") || rel.includes(`${sep}..`))
|
|
441
|
+
return null;
|
|
442
|
+
return { abs, rel };
|
|
443
|
+
}
|
|
432
444
|
/**
|
|
433
445
|
* Persists which workspace each browser client last used + which workspaces it
|
|
434
446
|
* has opened, so a server restart / page reload restores the same project and
|
|
@@ -1810,11 +1822,9 @@ export class ClientSession {
|
|
|
1810
1822
|
async readFile(relPath) {
|
|
1811
1823
|
try {
|
|
1812
1824
|
const fs = await import("node:fs/promises");
|
|
1813
|
-
const { resolve, sep, relative } = await import("node:path");
|
|
1814
1825
|
const root = resolve(this.cwd);
|
|
1815
|
-
const
|
|
1816
|
-
|
|
1817
|
-
if (rel.startsWith("..") || rel.includes(`${sep}..`)) {
|
|
1826
|
+
const wp = workspacePath(root, relPath);
|
|
1827
|
+
if (!wp) {
|
|
1818
1828
|
this.emit({
|
|
1819
1829
|
type: "notice",
|
|
1820
1830
|
level: "warning",
|
|
@@ -1822,6 +1832,7 @@ export class ClientSession {
|
|
|
1822
1832
|
});
|
|
1823
1833
|
return;
|
|
1824
1834
|
}
|
|
1835
|
+
const { abs, rel } = wp;
|
|
1825
1836
|
const stat = await fs.stat(abs);
|
|
1826
1837
|
if (!stat.isFile()) {
|
|
1827
1838
|
this.emit({
|
package/dist/server/index.js
CHANGED
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
import { existsSync } from "node:fs";
|
|
16
16
|
import { stat } from "node:fs/promises";
|
|
17
17
|
import { createServer } from "node:http";
|
|
18
|
-
import { basename, dirname, join,
|
|
18
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
20
|
import { randomUUID } from "node:crypto";
|
|
21
21
|
import express from "express";
|
|
22
22
|
import { WebSocket, WebSocketServer } from "ws";
|
|
23
23
|
import { VERSION } from "@earendil-works/pi-coding-agent";
|
|
24
|
-
import { AgentService, previewKind } from "./agent-service.js";
|
|
24
|
+
import { AgentService, previewKind, workspacePath } from "./agent-service.js";
|
|
25
25
|
const PORT = Number(process.env.PORT ?? 8787);
|
|
26
26
|
const CWD = resolve(process.env.PI_WEB_CWD ?? process.cwd());
|
|
27
27
|
const DATA_DIR = resolve(process.env.PI_WEB_DATA_DIR ?? join(CWD, ".pi-web"));
|
|
@@ -40,12 +40,18 @@ app.get("/api/health", (_req, res) => {
|
|
|
40
40
|
app.get("/api/file", async (req, res) => {
|
|
41
41
|
try {
|
|
42
42
|
const raw = typeof req.query.path === "string" ? req.query.path : "";
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// Resolve against the requesting client's workspace (the opened
|
|
44
|
+
// project), not the server's startup cwd — they can differ when the
|
|
45
|
+
// client switched projects or restored a previous workspace. Fall
|
|
46
|
+
// back to the server cwd for requests without a known client.
|
|
47
|
+
const cid = typeof req.query.clientId === "string" ? req.query.clientId : "";
|
|
48
|
+
const cs = cid ? service.get(cid) : undefined;
|
|
49
|
+
const wp = workspacePath(cs?.cwd ?? CWD, raw);
|
|
50
|
+
if (!wp) {
|
|
46
51
|
res.status(400).end("path outside workspace");
|
|
47
52
|
return;
|
|
48
53
|
}
|
|
54
|
+
const abs = wp.abs;
|
|
49
55
|
const name = basename(abs);
|
|
50
56
|
const kind = previewKind(name);
|
|
51
57
|
if (kind !== "image" && kind !== "video") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|