@rexvane/piweb 0.3.20 → 0.3.21

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 (121) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -5
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +4 -4
  5. package/.next/react-loadable-manifest.json +4 -4
  6. package/.next/required-server-files.js +2 -1
  7. package/.next/required-server-files.json +2 -1
  8. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/server/app/api/agent/[id]/events/route.js +3 -3
  21. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  22. package/.next/server/app/api/agent/[id]/route.js +1 -1
  23. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  24. package/.next/server/app/api/agent/[id]/tree/route.js +1 -1
  25. package/.next/server/app/api/agent/[id]/tree/route.js.nft.json +1 -1
  26. package/.next/server/app/api/agent/new/route.js +1 -1
  27. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  28. package/.next/server/app/api/growth/route.js +1 -1
  29. package/.next/server/app/api/growth/route.js.nft.json +1 -1
  30. package/.next/server/app/api/models/route.js +1 -1
  31. package/.next/server/app/api/models/route.js.nft.json +1 -1
  32. package/.next/server/app/api/plugins/route.js +1 -1
  33. package/.next/server/app/api/plugins/route.js.nft.json +1 -1
  34. package/.next/server/app/api/prompts/route.js +1 -1
  35. package/.next/server/app/api/prompts/route.js.nft.json +1 -1
  36. package/.next/server/app/api/security/route.js +1 -1
  37. package/.next/server/app/api/security/route.js.nft.json +1 -1
  38. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  39. package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -1
  40. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  41. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  42. package/.next/server/app/api/sessions/route.js +1 -1
  43. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  44. package/.next/server/app/api/skills/route.js +2 -2
  45. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  46. package/.next/server/app/api/update/route.js +2 -2
  47. package/.next/server/app/api/update/route.js.nft.json +1 -1
  48. package/.next/server/app/api/version/route.js +1 -1
  49. package/.next/server/app/api/workspaces/route.js +1 -1
  50. package/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  51. package/.next/server/app/index.html +1 -1
  52. package/.next/server/app/index.rsc +4 -4
  53. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  54. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  55. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  56. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/login.html +1 -1
  58. package/.next/server/app/login.rsc +3 -3
  59. package/.next/server/app/login.segments/_full.segment.rsc +3 -3
  60. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  61. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -3
  62. package/.next/server/app/page.js +1 -1
  63. package/.next/server/app/page.js.nft.json +1 -1
  64. package/.next/server/app/page_client-reference-manifest.js +1 -1
  65. package/.next/server/app-paths-manifest.json +5 -5
  66. package/.next/server/chunks/421.js +1 -0
  67. package/.next/server/chunks/496.js +1 -1
  68. package/.next/server/chunks/662.js +2 -0
  69. package/.next/server/chunks/686.js +1 -1
  70. package/.next/server/chunks/807.js +1 -1
  71. package/.next/server/instrumentation.js +1 -1
  72. package/.next/server/instrumentation.js.nft.json +1 -1
  73. package/.next/server/middleware-build-manifest.js +1 -1
  74. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  75. package/.next/server/pages/404.html +1 -1
  76. package/.next/server/pages/500.html +1 -1
  77. package/.next/server/server-reference-manifest.json +1 -1
  78. package/.next/static/chunks/4686-882531aef1d2e250.js +1 -0
  79. package/.next/static/chunks/{4778.e4c9ed093a413bc4.js → 4778.305dc6abb9889627.js} +1 -1
  80. package/.next/static/chunks/839.bfd2db36483faa3e.js +1 -0
  81. package/.next/static/chunks/8552.25c39ef4c995eba0.js +1 -0
  82. package/.next/static/chunks/app/page-c04af72e549695bd.js +1 -0
  83. package/.next/static/chunks/{webpack-3614a8337843456b.js → webpack-9b4bb574e5817654.js} +1 -1
  84. package/.next/static/css/ea27b9e30f76303f.css +1 -0
  85. package/README.md +14 -5
  86. package/next.config.ts +4 -2
  87. package/package.json +1 -1
  88. package/scripts/release.mjs +1 -1
  89. package/src/app/api/agent/[id]/events/route.ts +42 -13
  90. package/src/app/api/update/route.ts +18 -2
  91. package/src/app/globals.css +89 -0
  92. package/src/components/AppShell.tsx +7 -3
  93. package/src/components/ChatInput.tsx +1 -0
  94. package/src/components/ChatWindow.tsx +105 -81
  95. package/src/components/ContextMeter.tsx +31 -0
  96. package/src/components/DrawerPanel.tsx +19 -26
  97. package/src/components/ExtensionUI.tsx +8 -2
  98. package/src/components/MarkdownBlock.tsx +333 -37
  99. package/src/components/SettingsPanel.tsx +122 -53
  100. package/src/components/chat/chat-scroll.ts +18 -0
  101. package/src/components/update/CopyCommand.tsx +34 -0
  102. package/src/components/update/UpdateNotice.tsx +130 -0
  103. package/src/components/update/update-store.ts +155 -0
  104. package/src/hooks/usePiWeb.ts +42 -25
  105. package/src/i18n.tsx +74 -4
  106. package/src/instrumentation-node.ts +3 -0
  107. package/src/lib/agent-manager.ts +100 -57
  108. package/src/lib/chat/event-stream.ts +113 -0
  109. package/src/lib/chat/stream-settings.ts +192 -0
  110. package/src/lib/types.ts +7 -0
  111. package/src/lib/update/startup-check.ts +117 -0
  112. package/src/lib/update-service.ts +23 -3
  113. package/.next/server/chunks/131.js +0 -1
  114. package/.next/server/chunks/243.js +0 -1
  115. package/.next/static/chunks/4686-b1e9fa876d0ea671.js +0 -1
  116. package/.next/static/chunks/839.d3fe337a9117c325.js +0 -1
  117. package/.next/static/chunks/8552.6bfe3e101250b20f.js +0 -1
  118. package/.next/static/chunks/app/page-2e425ef83fba0782.js +0 -1
  119. package/.next/static/css/7391c42e1ae617f9.css +0 -1
  120. /package/.next/static/{_Y3Lq0lI5RJ1tFSOnDi0L → sNX5GQkOWuK5YEID1hT-C}/_buildManifest.js +0 -0
  121. /package/.next/static/{_Y3Lq0lI5RJ1tFSOnDi0L → sNX5GQkOWuK5YEID1hT-C}/_ssgManifest.js +0 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * 启动时检查一次更新:PiWeb 和 pi 各查一次,结果留在内存里给设置页和右下角提示条用,
3
+ * 有新版本时在终端打一行。离线、registry 不通都不吭声——设置里还能手动检查。
4
+ *
5
+ * 状态挂 globalThis:instrumentation 和路由是不同的 bundle,模块级变量不共享(同 remote/supervisor)。
6
+ * 每次服务启动换一个 startId,页面据此做到「每次启动提醒一次」。
7
+ * 手动检查、更新成功后改写这份缓存:刷新页面不会又显示「更新到 vX」。
8
+ * PI_WEB_UPDATE_CHECK=0 关掉启动检查(不联网),设置里手动检查不受影响。
9
+ */
10
+ import { randomUUID } from "node:crypto";
11
+ import { checkForUpdate, type UpdateCheck, type UpdateTarget } from "../update-service";
12
+
13
+ /** 一项的结果:检查结果(更新过就带上 updatedTo),或检查失败的原因 */
14
+ export type StartupResult = (UpdateCheck & { updatedTo?: string }) | { error: string };
15
+
16
+ export interface StartupUpdates {
17
+ /** 本次服务启动的标识;关掉启动检查时为 null */
18
+ startId: string | null;
19
+ results: Partial<Record<UpdateTarget, StartupResult>>;
20
+ }
21
+
22
+ interface StartupState {
23
+ startId: string;
24
+ results: Partial<Record<UpdateTarget, StartupResult>>;
25
+ pending: Promise<void> | null;
26
+ started: boolean;
27
+ }
28
+
29
+ interface StartupOptions {
30
+ check?: (target: UpdateTarget) => Promise<UpdateCheck>;
31
+ log?: (line: string) => void;
32
+ env?: Record<string, string | undefined>;
33
+ }
34
+
35
+ const STATE_KEY = "piweb.update.startup";
36
+ const TARGETS: readonly UpdateTarget[] = ["piweb", "pi"];
37
+ const LABEL: Record<UpdateTarget, string> = { piweb: "PiWeb", pi: "Pi" };
38
+
39
+ function state(): StartupState {
40
+ const store = globalThis as Record<PropertyKey, unknown>;
41
+ const key = Symbol.for(STATE_KEY);
42
+ const existing = store[key] as StartupState | undefined;
43
+ if (existing) return existing;
44
+ const created: StartupState = { startId: randomUUID(), results: {}, pending: null, started: false };
45
+ store[key] = created;
46
+ return created;
47
+ }
48
+
49
+ export function startupCheckEnabled(env: Record<string, string | undefined> = process.env): boolean {
50
+ return env.PI_WEB_UPDATE_CHECK !== "0";
51
+ }
52
+
53
+ /** 终端里那一行;没有新版本时为 null */
54
+ export function updateNoticeLine(results: StartupUpdates["results"]): string | null {
55
+ const parts: string[] = [];
56
+ let manual: string | undefined;
57
+ for (const target of TARGETS) {
58
+ const result = results[target];
59
+ if (!result || "error" in result || !result.canUpdate) continue;
60
+ // Git 检出版本号没变、只是 main 上有新提交时,写提交数而不是「0.3.20 → 0.3.20」
61
+ parts.push(result.latest === result.current && result.behind ? `${LABEL[target]}(main 新增 ${result.behind} 个提交)` : `${LABEL[target]} ${result.current} → ${result.latest}`);
62
+ if (!result.selfUpdate && result.command) manual = result.command;
63
+ }
64
+ if (!parts.length) return null;
65
+ const line = `[更新] 有新版本:${parts.join("、")}。打开 设置 → 通用 点「更新」`;
66
+ return manual ? `${line};PiWeb 要先停掉 piweb 再运行:${manual}` : line;
67
+ }
68
+
69
+ /**
70
+ * 启动检查(只跑一次);返回检查完之后的状态快照。关掉时返回 null,不联网。
71
+ * instrumentation 在启动时调它,GET /api/update 也调它(页面先到时由页面触发,结果一样只查一次)。
72
+ */
73
+ export async function ensureStartupCheck({ check = checkForUpdate, log = console.log, env = process.env }: StartupOptions = {}): Promise<StartupUpdates | null> {
74
+ if (!startupCheckEnabled(env)) return null;
75
+ const current = state();
76
+ if (!current.started) {
77
+ current.started = true;
78
+ current.pending = (async () => {
79
+ await Promise.all(TARGETS.map(async (target) => {
80
+ try {
81
+ const result = await check(target);
82
+ // 检查期间已经手动更新过的项不覆盖
83
+ if (!current.results[target]) current.results[target] = result;
84
+ } catch (error) {
85
+ if (!current.results[target]) current.results[target] = { error: error instanceof Error ? error.message : String(error) };
86
+ }
87
+ }));
88
+ const line = updateNoticeLine(current.results);
89
+ if (line) log(line);
90
+ })();
91
+ }
92
+ await current.pending;
93
+ return snapshot();
94
+ }
95
+
96
+ function snapshot(): StartupUpdates {
97
+ const current = state();
98
+ return { startId: current.startId, results: { ...current.results } };
99
+ }
100
+
101
+ /** 手动检查的结果覆盖缓存 */
102
+ export function recordCheck(target: UpdateTarget, check: UpdateCheck): void {
103
+ state().results[target] = check;
104
+ }
105
+
106
+ /** 更新成功:记下装好的版本,页面刷新后显示「已更新,重启生效」而不是又让人更新一次 */
107
+ export function markUpdated(target: UpdateTarget, version: string): void {
108
+ const current = state();
109
+ const previous = current.results[target];
110
+ const base = previous && !("error" in previous) ? previous : { current: "", latest: version, canUpdate: false, selfUpdate: true };
111
+ current.results[target] = { ...base, latest: version || base.latest, canUpdate: false, updatedTo: version || base.latest };
112
+ }
113
+
114
+ /** 仅供测试:清掉挂在 globalThis 上的状态 */
115
+ export function resetStartupCheck(): void {
116
+ delete (globalThis as Record<PropertyKey, unknown>)[Symbol.for(STATE_KEY)];
117
+ }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import fs from "node:fs/promises";
7
7
  import path from "node:path";
8
- import { installPiUpdate, PI_PACKAGE, prepareRelease } from "../../scripts/release.mjs";
8
+ import { installPiUpdate, PI_AI_PACKAGE, PI_PACKAGE, prepareRelease } from "../../scripts/release.mjs";
9
9
  import { assertInstallation, readProductionBuild } from "../../scripts/build-output.mjs";
10
10
  import { runCommand } from "../../scripts/process-runner.mjs";
11
11
  import { isNewer } from "./semver";
@@ -153,14 +153,34 @@ export function createUpdateService({ root = APP_ROOT, run = runCommand, version
153
153
  return { ...readProductionBuild(installation, ".next"), version, needsRestart: true };
154
154
  }
155
155
 
156
+ /**
157
+ * 只换 npm 成品包里的 pi 依赖:成品包没有 devDependencies,跑不了 typecheck / 构建,也不需要——
158
+ * pi 两个包都在 serverExternalPackages 里,运行时从这里的 node_modules 加载,重启即用上新版。
159
+ * Windows 也能做:运行中的服务没加载 pi 的原生模块,pi 目录也不是服务的工作目录,不会 EBUSY。
160
+ * 图标不用同步:成品包自带 public/provider-icons,清单也和 pi 版本无关。
161
+ */
162
+ async function installPiIntoPackage(installation: string, assertIdle: () => Promise<void>): Promise<UpdateResult> {
163
+ await assertIdle();
164
+ await run("npm", ["install", "--save-exact", `${PI_PACKAGE}@latest`, `${PI_AI_PACKAGE}@latest`, "--omit=dev", "--no-audit", "--no-fund"], {
165
+ cwd: installation, env: commandEnv, timeoutMs: 600_000,
166
+ });
167
+ await assertIdle();
168
+ assertInstallation(installation);
169
+ const version = await readPackageVersion(path.join(installation, "node_modules", PI_PACKAGE, "package.json"));
170
+ return { ...readProductionBuild(installation, ".next"), version, needsRestart: true };
171
+ }
172
+
156
173
  async function runUpdate(target: UpdateTarget, { assertIdle = async () => {} }: { assertIdle?: () => Promise<void> } = {}): Promise<UpdateResult> {
157
174
  assertTarget(target);
158
175
  if (updateRunning) throw new UpdateBusyError("an update is already running");
159
176
  updateRunning = true;
160
177
  try {
161
178
  const installation = await checkedRoot();
162
- // npm 安装:装发布好的成品即可——不需要 Git,也不需要本地构建(成品包自带 .next)。
163
- if (target === "piweb" && isNpmInstall(installation)) return await installFromRegistry(installation, assertIdle);
179
+ // npm 安装:装发布好的成品即可——不需要 Git,也不需要本地构建(成品包自带 .next);
180
+ // 单独更新 pi 只换依赖,同样不重建。
181
+ if (isNpmInstall(installation)) {
182
+ return target === "piweb" ? await installFromRegistry(installation, assertIdle) : await installPiIntoPackage(installation, assertIdle);
183
+ }
164
184
  let version = "";
165
185
  const release = await prepareRelease({
166
186
  root: installation, env, run,
@@ -1 +0,0 @@
1
- "use strict";exports.id=131,exports.ids=[131],exports.modules={6512:(a,b,c)=>{c.d(b,{Kt:()=>f,W8:()=>e});let d=["off","minimal","low","medium","high","xhigh","max"];function e(a){return a.reasoning?d.filter(b=>{let c=a.thinkingLevelMap?.[b];return null!==c&&("xhigh"!==b&&"max"!==b||void 0!==c)}):["off"]}function f(a,b){let c=e(a);if(c.includes(b))return b;let f=d.indexOf(b);if(-1===f)return c[0]??"off";for(let a=f;a<d.length;a++){let b=d[a];if(c.includes(b))return b}for(let a=f-1;a>=0;a--){let b=d[a];if(c.includes(b))return b}return c[0]??"off"}}};