pi-web-ui 0.64.0 → 0.64.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.
Files changed (45) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +504 -504
  3. package/README.zh-CN.md +427 -427
  4. package/bin/pi-web-ui.mjs +1809 -1809
  5. package/deploy/com.xingshuyin.pi-web-ui.plist +48 -48
  6. package/deploy/nginx-subpath.conf +88 -88
  7. package/deploy/pi-web-ui-task.xml +54 -54
  8. package/deploy/pi-web-ui.service +31 -31
  9. package/dist/server/agent-service.js +45 -22
  10. package/dist/server/attachments.js +16 -11
  11. package/dist/server/dsh/dsh-agent-service.js +27 -7
  12. package/dist/server/dsh/runtime/cordis.yml +1 -1
  13. package/dist/server/dsh/runtime/goal-rpc.mjs +645 -645
  14. package/dist/server/dsh/runtime/launcher.mjs +164 -164
  15. package/dist/server/dsh/runtime/override.patch.yml +71 -71
  16. package/dist/server/dsh/runtime/runtime-root.mjs +86 -86
  17. package/dist/server/files-service.js +235 -43
  18. package/dist/server/goal-service.js +4 -1
  19. package/dist/server/index.js +48 -13
  20. package/dist/server/marker-service.js +8 -3
  21. package/dist/server/markers/builtins/rename.js +3 -3
  22. package/dist/server/model-admin.js +12 -6
  23. package/dist/server/plugins.js +4 -4
  24. package/dist/server/slash-commands.js +3 -0
  25. package/dist/server/terminals.js +25 -15
  26. package/dist/server/vision-bridge.js +9 -9
  27. package/dist/server/webui-context.js +2 -2
  28. package/extensions/webui.ts +190 -190
  29. package/package.json +109 -109
  30. package/themes/cyberpunk.css +81 -81
  31. package/themes/dazzle.css +81 -81
  32. package/themes/md-preview.css +98 -98
  33. package/themes/white.css +160 -160
  34. package/web/dist/assets/TerminalPanel-BXISCcrQ.js +6 -0
  35. package/web/dist/assets/index-BxuvIAJQ.js +326 -0
  36. package/web/dist/assets/{index-CMgDryBL.css → index-DVnuQrK5.css} +1 -1
  37. package/web/dist/favicon.svg +8 -8
  38. package/web/dist/index.html +21 -21
  39. package/web/dist/manifest.webmanifest +50 -50
  40. package/web/dist/sw.js +126 -126
  41. package/web/public/favicon.svg +8 -8
  42. package/web/public/manifest.webmanifest +50 -50
  43. package/web/public/sw.js +126 -126
  44. package/web/dist/assets/TerminalPanel-DNkAT34Z.js +0 -2
  45. package/web/dist/assets/index-_1vyEugI.js +0 -326
@@ -1,5 +1,6 @@
1
1
  import { countLines, decodeText, looksLikeText, sniffImageMime } from "./text-sniff.js";
2
2
  import { saveUpload, uploadsRoot } from "./uploads.js";
3
+ import { isAbsoluteWirePath, wireToAbs } from "./files-service.js";
3
4
  import { buildVisionBridgePrompt, findVisionModels, transcribeImages } from "./vision-bridge.js";
4
5
  /** 跨快照的视觉转写缓存:批次 hash(名称 + base64 头 + 提示词)→ 转写文本。
5
6
  * 编辑重问重发相同图片不再重复耗视觉 token。进程级共享即可。 */
@@ -120,9 +121,11 @@ export async function buildAttachmentMessages(ctx, attachments) {
120
121
  const ext = extname(att.path).toLowerCase();
121
122
  if (!IMAGE_EXT.has(ext) || ext === ".svg")
122
123
  continue;
123
- const abs = resolve(root, att.path);
124
- const rawRel = relative(root, abs);
125
- if (rawRel.startsWith("..") || rawRel.includes(`${sep}..`))
124
+ // 机器浏览的绝对路径(盘符 / posix "/")允许在工作区之外。
125
+ const absPath = isAbsoluteWirePath(att.path);
126
+ const abs = absPath ? wireToAbs(att.path) : resolve(root, att.path);
127
+ const rawRel = absPath ? null : relative(root, abs);
128
+ if (!absPath && (rawRel.startsWith("..") || rawRel.includes(`${sep}..`)))
126
129
  continue;
127
130
  let st;
128
131
  try {
@@ -381,9 +384,10 @@ export async function buildAttachmentMessages(ctx, attachments) {
381
384
  pushUploadAside(att.name ?? basename(abs), abs.split(sep).join("/"), buf);
382
385
  continue;
383
386
  }
384
- const abs = resolve(root, att.path);
385
- const rawRel = relative(root, abs);
386
- if (rawRel.startsWith("..") || rawRel.includes(`${sep}..`)) {
387
+ const absPath = isAbsoluteWirePath(att.path);
388
+ const abs = absPath ? wireToAbs(att.path) : resolve(root, att.path);
389
+ const rawRel = absPath ? null : relative(root, abs);
390
+ if (!absPath && (rawRel.startsWith("..") || rawRel.includes(`${sep}..`))) {
387
391
  ctx.emit({
388
392
  type: "notice",
389
393
  level: "warning",
@@ -393,8 +397,9 @@ export async function buildAttachmentMessages(ctx, attachments) {
393
397
  continue;
394
398
  }
395
399
  // Normalize to forward slashes (relative() returns "\\" on Windows);
396
- // <file path> and details.path must use the wire format.
397
- const rel = rawRel.split(sep).join("/");
400
+ // <file path> and details.path must use the wire format. 机器浏览的绝对
401
+ // 路径直接按绝对路径引用(SDK 读文件工具接受绝对路径,与上传文件一致)。
402
+ const rel = absPath ? abs.split(sep).join("/") : rawRel.split(sep).join("/");
398
403
  let stat;
399
404
  try {
400
405
  stat = await fs.stat(abs);
@@ -449,9 +454,9 @@ export async function buildAttachmentMessages(ctx, attachments) {
449
454
  content: [
450
455
  {
451
456
  type: "text",
452
- text: `
453
- <vision-bridge>
454
- ${transcript}
457
+ text: `
458
+ <vision-bridge>
459
+ ${transcript}
455
460
  </vision-bridge>`,
456
461
  },
457
462
  ...(pathImg
@@ -1029,8 +1029,8 @@ export class DshClientSession {
1029
1029
  for (const sink of [...this.sinks])
1030
1030
  sink(msg);
1031
1031
  }
1032
- emitNotice(level, text) {
1033
- this.emit({ type: "notice", level, text });
1032
+ emitNotice(level, text, textEn) {
1033
+ this.emit({ type: "notice", level, text, textEn });
1034
1034
  }
1035
1035
  pushTerminals() {
1036
1036
  for (const conv of this.convs.values()) {
@@ -1308,6 +1308,9 @@ export class DshClientSession {
1308
1308
  text: hadGoal
1309
1309
  ? "已新建分支继续对话(DSH 引擎不支持原地续聊旧会话);原目标已随旧会话存档,如需继续请重新设置目标"
1310
1310
  : "已新建分支继续对话(DSH 引擎不支持原地续聊旧会话)",
1311
+ textEn: hadGoal
1312
+ ? "Started a branch to continue (DSH engine cannot resume an old session in place); the old goal was archived with it — set a new goal to continue"
1313
+ : "Started a branch to continue (DSH engine cannot resume an old session in place)",
1311
1314
  });
1312
1315
  return fork;
1313
1316
  }
@@ -1622,11 +1625,21 @@ export class DshClientSession {
1622
1625
  async dismissConversation(id) {
1623
1626
  const conv = this.convs.get(id);
1624
1627
  if (!conv) {
1625
- this.emit({ type: "notice", level: "warning", text: "该对话不存在或已关闭" });
1628
+ this.emit({
1629
+ type: "notice",
1630
+ level: "warning",
1631
+ text: "该对话不存在或已关闭",
1632
+ textEn: "This conversation does not exist or is already closed",
1633
+ });
1626
1634
  return;
1627
1635
  }
1628
1636
  if (id === this.activeId) {
1629
- this.emit({ type: "notice", level: "warning", text: "当前对话不能直接移出,请先切换到其他对话" });
1637
+ this.emit({
1638
+ type: "notice",
1639
+ level: "warning",
1640
+ text: "当前对话不能直接移出,请先切换到其他对话",
1641
+ textEn: "The active conversation cannot be removed directly — switch to another conversation first",
1642
+ });
1630
1643
  return;
1631
1644
  }
1632
1645
  if (!conv.listed) {
@@ -1638,11 +1651,17 @@ export class DshClientSession {
1638
1651
  type: "notice",
1639
1652
  level: "warning",
1640
1653
  text: `对话「${conv.title}」仍在运行中,请先等待结束或停止后再移出`,
1654
+ textEn: `Conversation "${conv.title}" is still running — wait for it to finish or press Stop before removing`,
1641
1655
  });
1642
1656
  return;
1643
1657
  }
1644
1658
  if (conv.terminals.list().length > 0) {
1645
- this.emit({ type: "notice", level: "warning", text: `对话「${conv.title}」还有未关闭的终端` });
1659
+ this.emit({
1660
+ type: "notice",
1661
+ level: "warning",
1662
+ text: `对话「${conv.title}」还有未关闭的终端,请先关闭终端后再移出`,
1663
+ textEn: `Conversation "${conv.title}" still has open terminals — close them before removing`,
1664
+ });
1646
1665
  return;
1647
1666
  }
1648
1667
  this.removeConversation(id);
@@ -2668,7 +2687,7 @@ export class DshClientSession {
2668
2687
  try {
2669
2688
  const result = await def.run(args, { clientId: this.clientId });
2670
2689
  if (typeof result === "string" && result.trim()) {
2671
- this.emit({ type: "notice", level: "info", text: result });
2690
+ this.emit({ type: "notice", level: "info", text: result, textEn: result });
2672
2691
  }
2673
2692
  }
2674
2693
  catch (err) {
@@ -2887,7 +2906,8 @@ export class DshClientSession {
2887
2906
  }
2888
2907
  async cloneProvider(_provider, reqId) {
2889
2908
  const error = "DSH 引擎不支持自定义 provider";
2890
- this.emit({ type: "notice", level: "error", text: error });
2909
+ const errorEn = "DSH engine does not support custom providers";
2910
+ this.emit({ type: "notice", level: "error", text: error, textEn: errorEn });
2891
2911
  this.emit({ type: "clone_provider_result", reqId, ok: false, error });
2892
2912
  }
2893
2913
  // -----------------------------------------------------------------------
@@ -1 +1 @@
1
- []
1
+ []