pi-web-ui 0.94.1 → 0.96.0
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/CHANGELOG.md +91 -2
- package/README.md +5 -6
- package/README.zh-CN.md +4 -5
- package/bin/pi-web-ui.mjs +910 -237
- package/dist/server/agent-service.js +2655 -231
- package/dist/server/approval-rules.js +596 -0
- package/dist/server/attachment-store.js +129 -0
- package/dist/server/attachments.js +92 -174
- package/dist/server/bg-servers.js +45 -7
- package/dist/server/claim-files-tool.js +4 -8
- package/dist/server/claim-store.js +4 -2
- package/dist/server/client-state.js +67 -14
- package/dist/server/compact-context-tool.js +126 -0
- package/dist/server/composer-drafts.js +9 -0
- package/dist/server/context-budget.js +317 -0
- package/dist/server/control-socket.js +57 -28
- package/dist/server/conversation-read-tool.js +7 -17
- package/dist/server/dangling-tools.js +229 -0
- package/dist/server/delegate-task.js +25 -28
- package/dist/server/dsh/dsh-agent-service.js +69 -66
- package/dist/server/edit-soft-tool.js +84 -16
- package/dist/server/eval-tool.js +588 -0
- package/dist/server/file-archives.js +16 -5
- package/dist/server/files-service.js +65 -18
- package/dist/server/goal-service.js +371 -77
- package/dist/server/hashline-engine.js +703 -0
- package/dist/server/host-guard.js +94 -0
- package/dist/server/host-metrics.js +26 -2
- package/dist/server/i18n.js +3 -3
- package/dist/server/index.js +456 -80
- package/dist/server/lsp-tool.js +1371 -0
- package/dist/server/mcp-bridge.js +47 -3
- package/dist/server/model-admin.js +112 -32
- package/dist/server/office-parse.js +375 -0
- package/dist/server/patch-tool.js +85 -0
- package/dist/server/permission-preset.js +25 -0
- package/dist/server/plan-manager.js +114 -0
- package/dist/server/plugin-api-catalog.js +296 -0
- package/dist/server/plugin-catalog-sync.js +36 -19
- package/dist/server/plugin-catalog.js +11 -4
- package/dist/server/plugin-facilities.js +92 -21
- package/dist/server/plugin-install-spec.js +196 -0
- package/dist/server/plugin-installer.js +73 -0
- package/dist/server/plugin-llm.js +71 -65
- package/dist/server/plugin-manifest-validate.js +305 -0
- package/dist/server/plugin-project.js +117 -13
- package/dist/server/plugin-tool-guard.js +120 -0
- package/dist/server/plugin-updater.js +115 -12
- package/dist/server/plugins.js +950 -205
- package/dist/server/present-files-tool.js +9 -12
- package/dist/server/process-utils.js +16 -6
- package/dist/server/prompt-composer.js +9 -0
- package/dist/server/protocol-version.js +1 -1
- package/dist/server/read-tool.js +69 -30
- package/dist/server/resolve-global-sdk.js +30 -16
- package/dist/server/schedule-agent-tool.js +12 -15
- package/dist/server/scheduler-tasks.js +6 -0
- package/dist/server/sdk-origin.js +18 -2
- package/dist/server/serialize.js +111 -14
- package/dist/server/settings-service.js +112 -3
- package/dist/server/skill-tool.js +5 -7
- package/dist/server/subagent-templates.js +51 -0
- package/dist/server/subagents.js +83 -66
- package/dist/server/terminals.js +248 -81
- package/dist/server/tool-approval.js +84 -0
- package/dist/server/tool-manager.js +237 -12
- package/dist/server/tool-overrides.js +59 -0
- package/dist/server/update-check.js +28 -1
- package/dist/server/uploads.js +17 -2
- package/dist/server/wait-subscription-scan.js +18 -21
- package/dist/server/workspace-snapshot.js +113 -0
- package/dist/server/ws-client-id.js +29 -0
- package/dist/server/ws-pending-queue.js +60 -0
- package/extensions/webui.ts +60 -2
- package/package.json +5 -3
- package/plugin-sdk/README.md +25 -0
- package/plugin-sdk/index.d.ts +31 -38
- package/plugin-sdk/index.mjs +35 -19
- package/plugins/catalog.json +40 -0
- package/themes/aetheris.css +457 -0
- package/themes/ayu-light.css +6 -6
- package/themes/catppuccin-latte.css +6 -6
- package/themes/claude-code-dark.css +144 -0
- package/themes/codex.css +6 -6
- package/themes/everforest-light.css +6 -6
- package/themes/geist.css +6 -6
- package/themes/gruvbox-light.css +6 -6
- package/themes/kanagawa-lotus.css +6 -6
- package/themes/rose-pine-dawn.css +6 -6
- package/themes/solarized-light.css +6 -6
- package/themes/vs-code-dark.css +146 -0
- package/themes/zhupi-dark.css +658 -0
- package/themes/zhupi.css +711 -0
- package/web/dist/assets/{TerminalPanel-MVoxpJOA.js → TerminalPanel-DDChcYOh.js} +1 -1
- package/web/dist/assets/index-Do9RgJC3.js +366 -0
- package/web/dist/assets/index-DryOsILO.css +1 -0
- package/web/dist/assets/{markdown-eUQn_o9D.js → markdown-DXwnfD9T.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/index-B3S9MxnN.css +0 -1
- package/web/dist/assets/index-DVLrHI2E.js +0 -364
|
@@ -11,6 +11,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, cpSync, write
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { execFile } from "node:child_process";
|
|
13
13
|
import { pick } from "./i18n.js";
|
|
14
|
+
import { parseInstallSpec, manifestCandidateUrls } from "./plugin-install-spec.js";
|
|
14
15
|
const PLUGIN_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
15
16
|
/** 保留的备份份数(超出删除最旧的)。 */
|
|
16
17
|
export const BACKUP_KEEP = 3;
|
|
@@ -150,10 +151,66 @@ export async function resolveRemoteSha(spec, exec = execGit) {
|
|
|
150
151
|
const sha = res.stdout.match(/^([0-9a-f]{40,64})\s+HEAD/m)?.[1] ?? null;
|
|
151
152
|
return sha ? sha.slice(0, 12) : null;
|
|
152
153
|
}
|
|
153
|
-
/**
|
|
154
|
+
/** 简易数字 semver 比较:>0 代表 a 比 b 新。 */
|
|
155
|
+
export function compareVersions(a, b) {
|
|
156
|
+
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
157
|
+
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|
|
158
|
+
for (let i = 0; i < 3; i++) {
|
|
159
|
+
const x = pa[i] ?? 0;
|
|
160
|
+
const y = pb[i] ?? 0;
|
|
161
|
+
if (x !== y)
|
|
162
|
+
return x - y;
|
|
163
|
+
}
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
/** 判断某个插件是否属于随包维护的内置插件(官方插件)。 */
|
|
167
|
+
export function isBuiltinPlugin(id, source, builtinCatalogPath) {
|
|
168
|
+
if (source && /xing-shuyin\/pi-web-ui\/plugins\//i.test(source))
|
|
169
|
+
return true;
|
|
170
|
+
if (builtinCatalogPath && existsSync(builtinCatalogPath)) {
|
|
171
|
+
try {
|
|
172
|
+
const raw = JSON.parse(readFileSync(builtinCatalogPath, "utf8"));
|
|
173
|
+
if (Array.isArray(raw)) {
|
|
174
|
+
return raw.some((e) => e?.id === id);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
/* ignore parse errors */
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
/** 探测远端 manifest 中的版本号(通过 raw.githubusercontent.com 或注入的 fetcher)。 */
|
|
184
|
+
async function fetchRemoteVersion(source, fetcher) {
|
|
185
|
+
const spec = parseInstallSpec(source);
|
|
186
|
+
const urls = manifestCandidateUrls(spec);
|
|
187
|
+
if (urls.length === 0)
|
|
188
|
+
return null;
|
|
189
|
+
const fetchImpl = fetcher ?? (typeof fetch === "function" ? fetch : null);
|
|
190
|
+
if (!fetchImpl)
|
|
191
|
+
return null;
|
|
192
|
+
for (const url of urls) {
|
|
193
|
+
try {
|
|
194
|
+
const ctrl = new AbortController();
|
|
195
|
+
const timer = setTimeout(() => ctrl.abort(), 6000);
|
|
196
|
+
const res = await fetchImpl(url, { signal: ctrl.signal }).finally(() => clearTimeout(timer));
|
|
197
|
+
if (!res.ok)
|
|
198
|
+
continue;
|
|
199
|
+
const data = (await res.json());
|
|
200
|
+
if (typeof data?.version === "string" && data.version.trim()) {
|
|
201
|
+
return data.version.trim();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// 单个 URL 失败继续尝试下一个候选
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
/** 扫描全部已装插件,对比本地 sha/version 与远端 sha/version,报告更新状态。 */
|
|
154
211
|
export async function checkPluginUpdates(dataDir, exec = execGit,
|
|
155
212
|
/** error 字段文案语言(默认英文);调用方可传 () => getLang() 实现跟随。 */
|
|
156
|
-
lang) {
|
|
213
|
+
lang, opts) {
|
|
157
214
|
const l = lang?.() ?? "en";
|
|
158
215
|
const pluginsDir = join(dataDir, "plugins");
|
|
159
216
|
let names = [];
|
|
@@ -180,6 +237,42 @@ lang) {
|
|
|
180
237
|
catch {
|
|
181
238
|
localSha = null; // 无 sha 记录 → 保守认为可更新(不知道装了哪个版本)
|
|
182
239
|
}
|
|
240
|
+
let name;
|
|
241
|
+
let version;
|
|
242
|
+
try {
|
|
243
|
+
const m = JSON.parse(readFileSync(join(dir, "manifest.json"), "utf8"));
|
|
244
|
+
name = m.name;
|
|
245
|
+
version = m.version;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
/* 坏 manifest:仍报告 */
|
|
249
|
+
}
|
|
250
|
+
const builtin = isBuiltinPlugin(n, source, opts?.builtinCatalogPath);
|
|
251
|
+
let latestVersion = null;
|
|
252
|
+
// 本地开发模式下,如果宿主包自带 plugins/<id>/manifest.json,可直接读本地最新版本号
|
|
253
|
+
if (opts?.pkgRoot) {
|
|
254
|
+
const localPkgManifest = join(opts.pkgRoot, "plugins", n, "manifest.json");
|
|
255
|
+
if (existsSync(localPkgManifest)) {
|
|
256
|
+
try {
|
|
257
|
+
const rawPkg = JSON.parse(readFileSync(localPkgManifest, "utf8"));
|
|
258
|
+
if (typeof rawPkg?.version === "string" && rawPkg.version.trim()) {
|
|
259
|
+
latestVersion = rawPkg.version.trim();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
/* ignore */
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// 若本地未取到最新版本号,则尝试通过 fetcher 探测远端 manifest.json
|
|
268
|
+
if (!latestVersion) {
|
|
269
|
+
try {
|
|
270
|
+
latestVersion = await fetchRemoteVersion(source, opts?.fetcher);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
latestVersion = null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
183
276
|
let remoteSha = null;
|
|
184
277
|
let error;
|
|
185
278
|
try {
|
|
@@ -189,27 +282,37 @@ lang) {
|
|
|
189
282
|
error = err instanceof Error ? err.message : String(err);
|
|
190
283
|
remoteSha = null;
|
|
191
284
|
}
|
|
192
|
-
if (!remoteSha && !error)
|
|
285
|
+
if (!remoteSha && !latestVersion && !error)
|
|
193
286
|
error = pick(l, "无法检查(非 git 源或 git 不可用)", "Cannot check (non-git source or git unavailable)", "pluginupdate.cannot.check");
|
|
194
|
-
let
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
287
|
+
let updatable = false;
|
|
288
|
+
if (latestVersion && version) {
|
|
289
|
+
const cmp = compareVersions(latestVersion, version);
|
|
290
|
+
if (cmp > 0) {
|
|
291
|
+
updatable = true;
|
|
292
|
+
}
|
|
293
|
+
else if (cmp === 0 && remoteSha && localSha) {
|
|
294
|
+
updatable = localSha !== remoteSha;
|
|
295
|
+
}
|
|
296
|
+
else if (cmp === 0 && remoteSha && !localSha) {
|
|
297
|
+
updatable = true;
|
|
298
|
+
}
|
|
200
299
|
}
|
|
201
|
-
|
|
202
|
-
|
|
300
|
+
else if (remoteSha) {
|
|
301
|
+
updatable = !localSha || localSha !== remoteSha;
|
|
302
|
+
}
|
|
303
|
+
else if (latestVersion && !version) {
|
|
304
|
+
updatable = true;
|
|
203
305
|
}
|
|
204
|
-
const updatable = !!remoteSha && (!localSha || localSha !== remoteSha);
|
|
205
306
|
out.push({
|
|
206
307
|
id: n,
|
|
207
308
|
name,
|
|
208
309
|
version,
|
|
310
|
+
latestVersion,
|
|
209
311
|
source,
|
|
210
312
|
localSha,
|
|
211
313
|
remoteSha,
|
|
212
314
|
updatable,
|
|
315
|
+
builtin,
|
|
213
316
|
error,
|
|
214
317
|
});
|
|
215
318
|
}
|