@rexvane/piweb 0.3.16 → 0.3.18

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 (288) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -11
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +6 -6
  5. package/.next/react-loadable-manifest.json +4 -16
  6. package/.next/required-server-files.js +1 -3
  7. package/.next/required-server-files.json +1 -3
  8. package/.next/routes-manifest.json +0 -20
  9. package/.next/server/app/_global-error/page.js +2 -2
  10. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +4 -7
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -5
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  23. package/.next/server/app/api/agent/[id]/events/route.js +2 -2
  24. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  25. package/.next/server/app/api/agent/[id]/route.js +1 -1
  26. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  27. package/.next/server/app/api/agent/[id]/tree/route.js +1 -1
  28. package/.next/server/app/api/agent/[id]/tree/route.js.nft.json +1 -1
  29. package/.next/server/app/api/agent/new/route.js +1 -1
  30. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  31. package/.next/server/app/api/config/route.js +1 -1
  32. package/.next/server/app/api/config/route.js.nft.json +1 -1
  33. package/.next/server/app/api/files/route.js +1 -1
  34. package/.next/server/app/api/files/route.js.nft.json +1 -1
  35. package/.next/server/app/api/git/route.js +2 -2
  36. package/.next/server/app/api/git/route.js.nft.json +1 -1
  37. package/.next/server/app/api/growth/route.js +1 -1
  38. package/.next/server/app/api/growth/route.js.nft.json +1 -1
  39. package/.next/server/app/api/health/route.js +1 -1
  40. package/.next/server/app/api/models/route.js +1 -1
  41. package/.next/server/app/api/models/route.js.nft.json +1 -1
  42. package/.next/server/app/api/pi-settings/route.js +1 -1
  43. package/.next/server/app/api/pi-settings/route.js.nft.json +1 -1
  44. package/.next/server/app/api/plugins/route.js +1 -1
  45. package/.next/server/app/api/plugins/route.js.nft.json +1 -1
  46. package/.next/server/app/api/prompts/route.js +1 -1
  47. package/.next/server/app/api/prompts/route.js.nft.json +1 -1
  48. package/.next/server/app/api/security/route.js +1 -1
  49. package/.next/server/app/api/security/route.js.nft.json +1 -1
  50. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  51. package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -1
  52. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  53. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  54. package/.next/server/app/api/sessions/import/route.js +3 -3
  55. package/.next/server/app/api/sessions/import/route.js.nft.json +1 -1
  56. package/.next/server/app/api/sessions/route.js +1 -1
  57. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  58. package/.next/server/app/api/skills/route.js +2 -2
  59. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  60. package/.next/server/app/api/update/route.js +2 -2
  61. package/.next/server/app/api/update/route.js.nft.json +1 -1
  62. package/.next/server/app/api/version/route.js +1 -1
  63. package/.next/server/app/api/version/route.js.nft.json +1 -1
  64. package/.next/server/app/api/web-auth/route.js +1 -1
  65. package/.next/server/app/api/workspaces/route.js +1 -1
  66. package/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  67. package/.next/server/app/icon.svg/route.js +1 -1
  68. package/.next/server/app/index.html +1 -1
  69. package/.next/server/app/index.rsc +6 -9
  70. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -7
  71. package/.next/server/app/index.segments/_full.segment.rsc +6 -9
  72. package/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  73. package/.next/server/app/login/page.js +1 -1
  74. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/login.html +1 -1
  76. package/.next/server/app/login.rsc +5 -8
  77. package/.next/server/app/login.segments/_full.segment.rsc +5 -8
  78. package/.next/server/app/login.segments/_tree.segment.rsc +2 -5
  79. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -6
  80. package/.next/server/app/page.js +1 -1
  81. package/.next/server/app/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app-paths-manifest.json +8 -11
  83. package/.next/server/chunks/496.js +1 -1
  84. package/.next/server/chunks/532.js +1 -1
  85. package/.next/server/chunks/686.js +4 -8
  86. package/.next/server/middleware-build-manifest.js +1 -1
  87. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  88. package/.next/server/pages/404.html +1 -1
  89. package/.next/server/pages/500.html +1 -1
  90. package/.next/server/server-reference-manifest.json +1 -1
  91. package/.next/static/chunks/2608.ec8ff1f5767c9056.js +1 -0
  92. package/.next/static/chunks/2716.93be8ad5c970c516.js +1 -0
  93. package/.next/static/chunks/4632.112d2e893d48d188.js +1 -0
  94. package/.next/static/chunks/4673.c1fb1580efc6ace7.js +1 -0
  95. package/.next/static/chunks/4686-f4a037d609cea3f2.js +1 -0
  96. package/.next/static/chunks/app/_global-error/page-f77e9ede9808b18e.js +1 -0
  97. package/.next/static/chunks/app/api/agent/[id]/events/route-f77e9ede9808b18e.js +1 -0
  98. package/.next/static/chunks/app/api/agent/[id]/route-f77e9ede9808b18e.js +1 -0
  99. package/.next/static/chunks/app/api/agent/[id]/tree/route-f77e9ede9808b18e.js +1 -0
  100. package/.next/static/chunks/app/api/agent/new/route-f77e9ede9808b18e.js +1 -0
  101. package/.next/static/chunks/app/api/config/route-f77e9ede9808b18e.js +1 -0
  102. package/.next/static/chunks/app/api/files/route-f77e9ede9808b18e.js +1 -0
  103. package/.next/static/chunks/app/api/git/route-f77e9ede9808b18e.js +1 -0
  104. package/.next/static/chunks/app/api/growth/route-f77e9ede9808b18e.js +1 -0
  105. package/.next/static/chunks/app/api/health/route-f77e9ede9808b18e.js +1 -0
  106. package/.next/static/chunks/app/api/models/route-f77e9ede9808b18e.js +1 -0
  107. package/.next/static/chunks/app/api/pi-settings/route-f77e9ede9808b18e.js +1 -0
  108. package/.next/static/chunks/app/api/plugins/route-f77e9ede9808b18e.js +1 -0
  109. package/.next/static/chunks/app/api/prompts/route-f77e9ede9808b18e.js +1 -0
  110. package/.next/static/chunks/app/api/security/route-f77e9ede9808b18e.js +1 -0
  111. package/.next/static/chunks/app/api/sessions/[id]/export/route-f77e9ede9808b18e.js +1 -0
  112. package/.next/static/chunks/app/api/sessions/[id]/route-f77e9ede9808b18e.js +1 -0
  113. package/.next/static/chunks/app/api/sessions/import/route-f77e9ede9808b18e.js +1 -0
  114. package/.next/static/chunks/app/api/sessions/route-f77e9ede9808b18e.js +1 -0
  115. package/.next/static/chunks/app/api/skills/route-f77e9ede9808b18e.js +1 -0
  116. package/.next/static/chunks/app/api/update/route-f77e9ede9808b18e.js +1 -0
  117. package/.next/static/chunks/app/api/version/route-f77e9ede9808b18e.js +1 -0
  118. package/.next/static/chunks/app/api/web-auth/route-f77e9ede9808b18e.js +1 -0
  119. package/.next/static/chunks/app/api/workspaces/route-f77e9ede9808b18e.js +1 -0
  120. package/.next/static/chunks/app/page-b51087831582ee37.js +1 -0
  121. package/.next/static/chunks/next/dist/client/components/builtin/app-error-f77e9ede9808b18e.js +1 -0
  122. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-f77e9ede9808b18e.js +1 -0
  123. package/.next/static/chunks/next/dist/client/components/builtin/not-found-f77e9ede9808b18e.js +1 -0
  124. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-f77e9ede9808b18e.js +1 -0
  125. package/.next/static/chunks/webpack-c31263fd83d75ce6.js +1 -0
  126. package/.next/static/css/0cd968b9b62035b5.css +1 -0
  127. package/.next/static/en03hnPiuro0rnf8QkFEe/_buildManifest.js +1 -0
  128. package/.next/types/routes.d.ts +1 -4
  129. package/.next/types/validator.ts +0 -27
  130. package/README.md +17 -29
  131. package/assets/archive.jpg +0 -0
  132. package/assets/growth-1.jpg +0 -0
  133. package/assets/growth-2.jpg +0 -0
  134. package/assets/import.jpg +0 -0
  135. package/assets/main.jpg +0 -0
  136. package/assets/outline.jpg +0 -0
  137. package/assets/prompts-1.jpg +0 -0
  138. package/assets/prompts-2.jpg +0 -0
  139. package/assets/providers-1.jpg +0 -0
  140. package/assets/providers-2.jpg +0 -0
  141. package/assets/providers-3.jpg +0 -0
  142. package/assets/trace-1.jpg +0 -0
  143. package/assets/trace-2.png +0 -0
  144. package/assets/trace-3.png +0 -0
  145. package/assets/trace-4.png +0 -0
  146. package/assets/viewer-1.jpg +0 -0
  147. package/assets/viewer-2.jpg +0 -0
  148. package/bin/pi.js +50 -0
  149. package/next.config.ts +32 -7
  150. package/package.json +4 -9
  151. package/scripts/launcher.mjs +1 -1
  152. package/scripts/pick-folder.ps1 +2 -11
  153. package/scripts/release.mjs +31 -11
  154. package/scripts/verify-package.mjs +0 -53
  155. package/src/app/api/config/route.ts +1 -4
  156. package/src/app/api/growth/route.ts +14 -14
  157. package/src/app/api/models/route.ts +2 -1
  158. package/src/app/api/security/route.ts +3 -8
  159. package/src/app/api/update/route.ts +2 -8
  160. package/src/app/globals.css +92 -777
  161. package/src/app/layout.tsx +6 -13
  162. package/src/components/AppShell.tsx +229 -521
  163. package/src/components/ChatInput.tsx +26 -153
  164. package/src/components/ChatWindow.tsx +231 -51
  165. package/src/components/ContextMeter.tsx +17 -11
  166. package/src/components/FileViewer.tsx +11 -10
  167. package/src/components/GitPanel.tsx +11 -13
  168. package/src/components/ModelSelector.tsx +6 -19
  169. package/src/components/PiMark.tsx +38 -5
  170. package/src/components/ProjectPanel.tsx +111 -95
  171. package/src/components/PromptPanel.tsx +51 -132
  172. package/src/components/SessionImportSection.tsx +37 -53
  173. package/src/components/SessionSidebar.tsx +57 -159
  174. package/src/components/SettingsPanel.tsx +193 -330
  175. package/src/components/icons.tsx +0 -23
  176. package/src/hooks/useGrowth.ts +123 -156
  177. package/src/hooks/usePiWeb.ts +15 -122
  178. package/src/i18n.tsx +42 -98
  179. package/src/lib/agent-manager.ts +21 -187
  180. package/src/lib/command-validation.ts +1 -9
  181. package/src/lib/growth-service.ts +390 -166
  182. package/src/lib/growth-tracker.ts +64 -264
  183. package/src/lib/growth-turns.ts +31 -1
  184. package/src/lib/models/model-scope.ts +15 -0
  185. package/src/lib/models-service.ts +16 -0
  186. package/src/lib/pi-settings.ts +7 -0
  187. package/src/lib/pi.ts +2 -3
  188. package/src/lib/session-import/claude.ts +2 -13
  189. package/src/lib/session-import/codex.ts +8 -44
  190. package/src/lib/session-import/files.ts +0 -14
  191. package/src/lib/session-import/grok.ts +24 -54
  192. package/src/lib/session-import/index.ts +0 -5
  193. package/src/lib/session-import/types.ts +0 -12
  194. package/src/lib/session-import/writer.ts +3 -8
  195. package/src/lib/skills-service.ts +9 -16
  196. package/src/lib/theme.ts +1 -68
  197. package/src/lib/trajectory.ts +0 -1
  198. package/src/lib/types.ts +27 -36
  199. package/tsconfig.json +2 -1
  200. package/.next/server/app/api/swarm/[id]/route.js +0 -1
  201. package/.next/server/app/api/swarm/[id]/route.js.nft.json +0 -1
  202. package/.next/server/app/api/swarm/[id]/route_client-reference-manifest.js +0 -1
  203. package/.next/server/app/api/swarm/route.js +0 -1
  204. package/.next/server/app/api/swarm/route.js.nft.json +0 -1
  205. package/.next/server/app/api/swarm/route_client-reference-manifest.js +0 -1
  206. package/.next/server/app/api/tests/route.js +0 -2
  207. package/.next/server/app/api/tests/route.js.nft.json +0 -1
  208. package/.next/server/app/api/tests/route_client-reference-manifest.js +0 -1
  209. package/.next/server/chunks/757.js +0 -1
  210. package/.next/server/chunks/775.js +0 -3
  211. package/.next/static/0t1jBUAuVaTFTXxRyIo3q/_buildManifest.js +0 -1
  212. package/.next/static/chunks/2608.43c58236c9cce8e6.js +0 -1
  213. package/.next/static/chunks/2716.4ec42df1d51354c9.js +0 -1
  214. package/.next/static/chunks/4632.62139b565b657aac.js +0 -1
  215. package/.next/static/chunks/4673.7796104395deb8d7.js +0 -1
  216. package/.next/static/chunks/4686-17f21a006739a596.js +0 -1
  217. package/.next/static/chunks/7577.10af9bb661652da8.js +0 -1
  218. package/.next/static/chunks/8866.38ec4ac4ee5a1b74.js +0 -1
  219. package/.next/static/chunks/app/_global-error/page-5148173b3f55e415.js +0 -1
  220. package/.next/static/chunks/app/api/agent/[id]/events/route-5148173b3f55e415.js +0 -1
  221. package/.next/static/chunks/app/api/agent/[id]/route-5148173b3f55e415.js +0 -1
  222. package/.next/static/chunks/app/api/agent/[id]/tree/route-5148173b3f55e415.js +0 -1
  223. package/.next/static/chunks/app/api/agent/new/route-5148173b3f55e415.js +0 -1
  224. package/.next/static/chunks/app/api/config/route-5148173b3f55e415.js +0 -1
  225. package/.next/static/chunks/app/api/files/route-5148173b3f55e415.js +0 -1
  226. package/.next/static/chunks/app/api/git/route-5148173b3f55e415.js +0 -1
  227. package/.next/static/chunks/app/api/growth/route-5148173b3f55e415.js +0 -1
  228. package/.next/static/chunks/app/api/health/route-5148173b3f55e415.js +0 -1
  229. package/.next/static/chunks/app/api/models/route-5148173b3f55e415.js +0 -1
  230. package/.next/static/chunks/app/api/pi-settings/route-5148173b3f55e415.js +0 -1
  231. package/.next/static/chunks/app/api/plugins/route-5148173b3f55e415.js +0 -1
  232. package/.next/static/chunks/app/api/prompts/route-5148173b3f55e415.js +0 -1
  233. package/.next/static/chunks/app/api/security/route-5148173b3f55e415.js +0 -1
  234. package/.next/static/chunks/app/api/sessions/[id]/export/route-5148173b3f55e415.js +0 -1
  235. package/.next/static/chunks/app/api/sessions/[id]/route-5148173b3f55e415.js +0 -1
  236. package/.next/static/chunks/app/api/sessions/import/route-5148173b3f55e415.js +0 -1
  237. package/.next/static/chunks/app/api/sessions/route-5148173b3f55e415.js +0 -1
  238. package/.next/static/chunks/app/api/skills/route-5148173b3f55e415.js +0 -1
  239. package/.next/static/chunks/app/api/swarm/[id]/route-5148173b3f55e415.js +0 -1
  240. package/.next/static/chunks/app/api/swarm/route-5148173b3f55e415.js +0 -1
  241. package/.next/static/chunks/app/api/tests/route-5148173b3f55e415.js +0 -1
  242. package/.next/static/chunks/app/api/update/route-5148173b3f55e415.js +0 -1
  243. package/.next/static/chunks/app/api/version/route-5148173b3f55e415.js +0 -1
  244. package/.next/static/chunks/app/api/web-auth/route-5148173b3f55e415.js +0 -1
  245. package/.next/static/chunks/app/api/workspaces/route-5148173b3f55e415.js +0 -1
  246. package/.next/static/chunks/app/page-14379b8060d5cf07.js +0 -1
  247. package/.next/static/chunks/next/dist/client/components/builtin/app-error-5148173b3f55e415.js +0 -1
  248. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-5148173b3f55e415.js +0 -1
  249. package/.next/static/chunks/next/dist/client/components/builtin/not-found-5148173b3f55e415.js +0 -1
  250. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-5148173b3f55e415.js +0 -1
  251. package/.next/static/chunks/webpack-d1a69ad9edb38b11.js +0 -1
  252. package/.next/static/css/d0a0162cb481abe8.css +0 -1
  253. package/.next/types/app/api/swarm/[id]/route.ts +0 -353
  254. package/.next/types/app/api/swarm/route.ts +0 -353
  255. package/.next/types/app/api/tests/route.ts +0 -353
  256. package/assets/archive.png +0 -0
  257. package/assets/growth-1.png +0 -0
  258. package/assets/growth-2.png +0 -0
  259. package/assets/import.png +0 -0
  260. package/assets/main.png +0 -0
  261. package/assets/outline.png +0 -0
  262. package/assets/prompts-1.png +0 -0
  263. package/assets/prompts-2.png +0 -0
  264. package/assets/providers-1.png +0 -0
  265. package/assets/providers-2.png +0 -0
  266. package/assets/providers-3.png +0 -0
  267. package/assets/trace-1.png +0 -0
  268. package/assets/viewer-1.png +0 -0
  269. package/assets/viewer-2.png +0 -0
  270. package/scripts/managed-niubash-assets.mjs +0 -146
  271. package/scripts/prepare-niubash-packages.mjs +0 -182
  272. package/scripts/run-test-file.mjs +0 -34
  273. package/scripts/smoke-managed-niubash.mjs +0 -62
  274. package/scripts/verify-release-config.mjs +0 -24
  275. package/src/app/api/swarm/[id]/route.ts +0 -28
  276. package/src/app/api/swarm/route.ts +0 -24
  277. package/src/app/api/tests/route.ts +0 -27
  278. package/src/components/SwarmCoordinatorPod.tsx +0 -1021
  279. package/src/components/TestInspectorPod.tsx +0 -549
  280. package/src/lib/delegation.ts +0 -93
  281. package/src/lib/growth-rounds.ts +0 -84
  282. package/src/lib/managed-niubash.ts +0 -231
  283. package/src/lib/runtime-activity.ts +0 -27
  284. package/src/lib/session-import/lock.ts +0 -25
  285. package/src/lib/swarm-service.ts +0 -371
  286. package/src/lib/test-run-service.ts +0 -122
  287. package/src/lib/workflow.ts +0 -55
  288. /package/.next/static/{0t1jBUAuVaTFTXxRyIo3q → en03hnPiuro0rnf8QkFEe}/_ssgManifest.js +0 -0
@@ -1,182 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Build the Windows-only npm packages from pinned official niubash portable
4
- * archives. Nothing is downloaded on macOS/Linux user installs: this runs only
5
- * in PiWeb's release workflow (or explicitly by a maintainer).
6
- */
7
- import fs from "node:fs";
8
- import os from "node:os";
9
- import path from "node:path";
10
- import { spawnSync } from "node:child_process";
11
- import { fileURLToPath } from "node:url";
12
- import {
13
- MANAGED_NIUBASH_ASSETS,
14
- NIUBASH_LICENSES,
15
- NIUBASH_REPOSITORY,
16
- NIUBASH_TAG,
17
- listFiles,
18
- niubashAssetUrl,
19
- sha256,
20
- sha256File,
21
- validateManagedNiubashPackage,
22
- } from "./managed-niubash-assets.mjs";
23
- import { isMainModule } from "./entrypoint.mjs";
24
-
25
- const DEFAULT_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
26
-
27
- async function download(url, expectedSha256) {
28
- let lastError;
29
- for (let attempt = 1; attempt <= 3; attempt += 1) {
30
- try {
31
- const response = await fetch(url, {
32
- headers: { "user-agent": "PiWeb managed-niubash packager" },
33
- signal: AbortSignal.timeout(120_000),
34
- });
35
- if (!response.ok) throw new Error(`HTTP ${response.status} ${response.statusText}`);
36
- const data = Buffer.from(await response.arrayBuffer());
37
- const actual = sha256(data);
38
- if (actual !== expectedSha256) throw new Error(`SHA-256 mismatch: expected ${expectedSha256}, got ${actual}`);
39
- return data;
40
- } catch (error) {
41
- lastError = error;
42
- if (attempt < 3) await new Promise((resolve) => setTimeout(resolve, attempt * 1000));
43
- }
44
- }
45
- throw new Error(`failed to download ${url}: ${lastError instanceof Error ? lastError.message : lastError}`);
46
- }
47
-
48
- function extractZip(archive, destination) {
49
- fs.mkdirSync(destination, { recursive: true });
50
- let result;
51
- if (process.platform === "win32") {
52
- result = spawnSync("powershell.exe", [
53
- "-NoProfile",
54
- "-NonInteractive",
55
- "-Command",
56
- "Expand-Archive -LiteralPath $env:PIWEB_NIUBASH_ARCHIVE -DestinationPath $env:PIWEB_NIUBASH_DESTINATION -Force",
57
- ], {
58
- encoding: "utf8",
59
- env: { ...process.env, PIWEB_NIUBASH_ARCHIVE: archive, PIWEB_NIUBASH_DESTINATION: destination },
60
- });
61
- } else {
62
- result = spawnSync("unzip", ["-q", "-o", archive, "-d", destination], { encoding: "utf8" });
63
- if (result.error?.code === "ENOENT") {
64
- result = spawnSync("python3", ["-m", "zipfile", "-e", archive, destination], { encoding: "utf8" });
65
- }
66
- }
67
- if (result.error) throw new Error(`cannot extract ${path.basename(archive)}: ${result.error.message}`);
68
- if (result.status !== 0) throw new Error(`cannot extract ${path.basename(archive)}: ${result.stderr || result.stdout}`);
69
- }
70
-
71
- async function replaceDirectory(source, destination) {
72
- fs.rmSync(destination, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
73
- for (let attempt = 1; ; attempt += 1) {
74
- try {
75
- fs.renameSync(source, destination);
76
- return;
77
- } catch (error) {
78
- // Windows:刚写入几百个文件时,Defender/索引器会短暂持有句柄,目录 rename 报 EPERM。
79
- // 先退避重试,仍不行就退化成复制(读通常是被允许的)。
80
- if (!["EPERM", "EBUSY", "EACCES"].includes(error?.code)) throw error;
81
- if (attempt >= 5) {
82
- fs.cpSync(source, destination, { recursive: true });
83
- fs.rmSync(source, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
84
- return;
85
- }
86
- await new Promise((resolve) => setTimeout(resolve, attempt * 250));
87
- }
88
- }
89
- }
90
-
91
- function extractedPortableRoot(destination) {
92
- const entries = fs.readdirSync(destination, { withFileTypes: true }).filter((entry) => entry.name !== "__MACOSX");
93
- if (entries.length !== 1 || !entries[0].isDirectory()) throw new Error("niubash archive must contain exactly one top-level directory");
94
- return path.join(destination, entries[0].name);
95
- }
96
-
97
- async function prepareLicenses(root, packageRoot) {
98
- const destination = path.join(packageRoot, "licenses");
99
- const staging = path.join(packageRoot, `.licenses-${process.pid}`);
100
- fs.rmSync(staging, { recursive: true, force: true });
101
- fs.mkdirSync(staging, { recursive: true });
102
- try {
103
- for (const license of NIUBASH_LICENSES) {
104
- const source = path.join(root, "third-party", "managed-niubash", "licenses", license.filename);
105
- if (sha256File(source) !== license.sha256) throw new Error(`license source failed integrity check: ${license.filename}`);
106
- fs.copyFileSync(source, path.join(staging, license.filename));
107
- }
108
- await replaceDirectory(staging, destination);
109
- } finally {
110
- fs.rmSync(staging, { recursive: true, force: true });
111
- }
112
- }
113
-
114
- async function prepareAsset(root, asset, log) {
115
- const packageRoot = path.join(root, "platform-packages", asset.directory);
116
- if (!fs.existsSync(path.join(packageRoot, "package.json"))) throw new Error(`missing platform package skeleton: ${packageRoot}`);
117
- const temporary = fs.mkdtempSync(path.join(os.tmpdir(), `piweb-niubash-${asset.arch}-`));
118
- const archive = path.join(temporary, asset.asset);
119
- const extracted = path.join(temporary, "extracted");
120
- const staging = path.join(packageRoot, `.runtime-${process.pid}`);
121
- try {
122
- log(`[piweb] Downloading ${asset.asset} ...`);
123
- fs.writeFileSync(archive, await download(niubashAssetUrl(asset), asset.sha256));
124
- extractZip(archive, extracted);
125
- const source = extractedPortableRoot(extracted);
126
- for (const required of ["niu.exe", "winuxcmd", "bundles"]) {
127
- if (!fs.existsSync(path.join(source, required))) throw new Error(`${asset.asset} is missing ${required}`);
128
- }
129
-
130
- fs.rmSync(staging, { recursive: true, force: true });
131
- fs.cpSync(source, staging, { recursive: true });
132
- await replaceDirectory(staging, path.join(packageRoot, "runtime"));
133
- const runtime = path.join(packageRoot, "runtime");
134
-
135
- const files = {};
136
- for (const relative of listFiles(runtime)) files[relative] = sha256File(path.join(runtime, ...relative.split("/")));
137
- fs.writeFileSync(path.join(packageRoot, "runtime-manifest.json"), `${JSON.stringify({
138
- schema: 1,
139
- source: { repository: NIUBASH_REPOSITORY, tag: NIUBASH_TAG, asset: asset.asset, sha256: asset.sha256 },
140
- files,
141
- }, null, 2)}\n`);
142
- await prepareLicenses(root, packageRoot);
143
- const checked = validateManagedNiubashPackage(packageRoot, asset, { allowExtraRuntimeFiles: false });
144
- log(`[piweb] Prepared ${asset.packageName}: ${checked.files} runtime files.`);
145
- return checked;
146
- } finally {
147
- fs.rmSync(staging, { recursive: true, force: true });
148
- fs.rmSync(temporary, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
149
- }
150
- }
151
-
152
- function selectAssets(args) {
153
- if (args.length === 0) return Object.values(MANAGED_NIUBASH_ASSETS);
154
- if (args.length === 1 && args[0] === "--current") {
155
- if (process.platform !== "win32" || !(process.arch in MANAGED_NIUBASH_ASSETS)) {
156
- throw new Error(`--current requires Windows x64/ARM64 (got ${process.platform}/${process.arch})`);
157
- }
158
- return [MANAGED_NIUBASH_ASSETS[process.arch]];
159
- }
160
- if (args.length === 1 && args[0].startsWith("--arch=")) {
161
- const arch = args[0].slice("--arch=".length);
162
- const asset = MANAGED_NIUBASH_ASSETS[arch];
163
- if (!asset) throw new Error(`unsupported niubash architecture: ${arch}`);
164
- return [asset];
165
- }
166
- throw new Error("Usage: node scripts/prepare-niubash-packages.mjs [--current|--arch=x64|--arch=arm64]");
167
- }
168
-
169
- export async function prepareManagedNiubashPackages(root = DEFAULT_ROOT, { args = [], log = console.log } = {}) {
170
- const results = [];
171
- for (const asset of selectAssets(args)) results.push(await prepareAsset(root, asset, log));
172
- return results;
173
- }
174
-
175
- if (isMainModule(import.meta.url)) {
176
- try {
177
- await prepareManagedNiubashPackages(DEFAULT_ROOT, { args: process.argv.slice(2) });
178
- } catch (error) {
179
- console.error(`[piweb] ${error instanceof Error ? error.message : error}`);
180
- process.exitCode = 1;
181
- }
182
- }
@@ -1,34 +0,0 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import { pathToFileURL } from "node:url";
4
-
5
- const [cwd, selected, reportFile] = process.argv.slice(2);
6
- let runner;
7
- try {
8
- if (!cwd || !selected || !reportFile) throw new Error("expected workspace, test file and report path");
9
- const api = await import(pathToFileURL(path.join(cwd, "node_modules/vitest/dist/node.js")).href);
10
- const options = { root: cwd, run: true, watch: false, reporters: ["json"], outputFile: reportFile };
11
- runner = Number(api.version.split(".")[0]) >= 5
12
- ? await api.createVitest(options)
13
- : await api.createVitest("test", options);
14
- if (typeof runner.globTestSpecifications !== "function" || typeof runner.runTestSpecifications !== "function") {
15
- throw new Error("this Vitest version does not support exact test specifications");
16
- }
17
- const canonical = (file) => process.platform === "win32" ? file.toLowerCase() : file;
18
- const target = canonical(await fs.realpath(selected));
19
- const specs = await runner.globTestSpecifications();
20
- const exact = [];
21
- for (const spec of specs) {
22
- if (canonical(await fs.realpath(spec.moduleId)) === target) exact.push(spec);
23
- }
24
- if (!exact.length) throw new Error("selected file is excluded by the workspace Vitest configuration");
25
- // Discovery is read-only; only exact specifications are handed to the executor.
26
- if (typeof runner.standalone === "function") await runner.standalone();
27
- else await runner.init();
28
- await runner.runTestSpecifications(exact);
29
- } catch (error) {
30
- console.error(error instanceof Error ? error.message : String(error));
31
- process.exitCode = 1;
32
- } finally {
33
- await runner?.close();
34
- }
@@ -1,62 +0,0 @@
1
- #!/usr/bin/env node
2
- /** Native smoke test. Run on both windows-latest (x64) and windows-11-arm. */
3
- import assert from "node:assert/strict";
4
- import path from "node:path";
5
- import { spawnSync } from "node:child_process";
6
- import { createRequire } from "node:module";
7
- import { fileURLToPath } from "node:url";
8
- import { createLocalBashOperations } from "@earendil-works/pi-coding-agent";
9
- import { MANAGED_NIUBASH_ASSETS, validateManagedNiubashPackage } from "./managed-niubash-assets.mjs";
10
-
11
- const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
12
- if (process.platform !== "win32" || !(process.arch in MANAGED_NIUBASH_ASSETS)) {
13
- throw new Error(`managed niubash smoke test requires Windows x64/ARM64 (got ${process.platform}/${process.arch})`);
14
- }
15
- const asset = MANAGED_NIUBASH_ASSETS[process.arch];
16
- const packageRoot = path.join(root, "platform-packages", asset.directory);
17
- validateManagedNiubashPackage(packageRoot, asset, { allowExtraRuntimeFiles: false });
18
- const require = createRequire(path.join(root, "package.json"));
19
- const runtime = require(path.join(packageRoot, "index.cjs"));
20
- assert.equal(runtime.packageName, asset.packageName);
21
- assert.equal(runtime.arch, process.arch);
22
-
23
- const version = spawnSync(runtime.shellPath, ["--version"], { encoding: "utf8", windowsHide: true });
24
- assert.equal(version.status, 0, version.stderr);
25
- assert.match(version.stdout, /Niubash 1\.1\.4/);
26
- assert.match(version.stdout, /rubash\s+git 8b81c7501646/);
27
- assert.match(version.stdout, /winuxcmd WinuxCmd 1\.0\.8/);
28
-
29
- const operations = createLocalBashOperations({ shellPath: runtime.shellPath });
30
- async function execute(command, options = {}) {
31
- const chunks = [];
32
- const result = await operations.exec(command, process.cwd(), {
33
- onData: (data) => chunks.push(data),
34
- ...options,
35
- });
36
- return { exitCode: result.exitCode, output: Buffer.concat(chunks).toString("utf8") };
37
- }
38
-
39
- const empty = await execute("");
40
- assert.equal(empty.exitCode, 0);
41
- assert.equal(empty.output, "");
42
-
43
- const pwd = await execute("pwd");
44
- assert.equal(pwd.exitCode, 0);
45
- assert.equal(path.resolve(pwd.output.trim().replaceAll("/", path.sep)).toLowerCase(), path.resolve(process.cwd()).toLowerCase());
46
-
47
- const quoted = await execute(`node -e "console.log(JSON.stringify(process.argv.slice(1)))" 'a b' '' 'c"d' 'e\\f'`);
48
- assert.equal(quoted.exitCode, 0, quoted.output);
49
- assert.deepEqual(JSON.parse(quoted.output.trim()), ["a b", "", "c\"d", "e\\f"]);
50
-
51
- const shellQuotedCwd = process.cwd().replaceAll("'", `'"'"'`);
52
- const windowsPath = await execute(`cd '${shellQuotedCwd}' && pwd`);
53
- assert.equal(windowsPath.exitCode, 0, windowsPath.output);
54
- assert.equal(path.resolve(windowsPath.output.trim().replaceAll("/", path.sep)).toLowerCase(), path.resolve(process.cwd()).toLowerCase());
55
-
56
- await assert.rejects(() => execute("sleep 5", { timeout: 0.1 }), /timeout/);
57
- const controller = new AbortController();
58
- const aborted = execute("sleep 5", { signal: controller.signal });
59
- setTimeout(() => controller.abort(), 100);
60
- await assert.rejects(() => aborted, /aborted/);
61
-
62
- console.log(`[piweb] Managed niubash ${process.arch} smoke test passed (${version.stdout.split(/\r?\n/, 1)[0]}).`);
@@ -1,24 +0,0 @@
1
- import path from "node:path";
2
- import { createRequire } from "node:module";
3
- import { pathToFileURL } from "node:url";
4
- import { assertInstallation, resolveBuildOutput, RELEASES_DIR } from "./build-output.mjs";
5
- import { isMainModule } from "./entrypoint.mjs";
6
-
7
- /** Run in a fresh process after install/pull so cached Next config cannot be reused. */
8
- export async function verifyReleaseConfig(root = process.cwd(), env = process.env) {
9
- const installation = assertInstallation(root);
10
- const buildDir = resolveBuildOutput(installation, env.PIWEB_BUILD_DIR);
11
- if (!buildDir.startsWith(`${RELEASES_DIR}/`)) throw new Error("release requires an isolated build output");
12
- const requireFromInstall = createRequire(path.join(installation, "package.json"));
13
- const module = await import(pathToFileURL(requireFromInstall.resolve("next/dist/server/config.js")).href);
14
- const loadConfig = typeof module.default === "function" ? module.default : module.default.default;
15
- const { PHASE_PRODUCTION_BUILD } = requireFromInstall("next/constants");
16
- const config = await loadConfig(PHASE_PRODUCTION_BUILD, installation, { silent: true });
17
- if (config.distDir !== buildDir || config.typescript?.tsconfigPath !== `${RELEASES_DIR}/tsconfig.json` || config.typescript?.ignoreBuildErrors) {
18
- throw new Error("Next config does not honor the isolated release directory/typecheck; refusing to build over the serving output");
19
- }
20
- }
21
-
22
- if (isMainModule(import.meta.url)) {
23
- await verifyReleaseConfig();
24
- }
@@ -1,28 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { BoundaryError } from "@/lib/path-security";
3
- import { acceptSwarmTask, cancelSwarm, getSwarm } from "@/lib/swarm-service";
4
-
5
- export const dynamic = "force-dynamic";
6
-
7
- export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
8
- try {
9
- return NextResponse.json({ success: true, data: await getSwarm((await params).id) });
10
- } catch (error) {
11
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof BoundaryError ? 400 : 500 });
12
- }
13
- }
14
-
15
- export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
16
- try {
17
- const body = await req.json();
18
- const id = (await params).id;
19
- const data = body?.action === "cancel"
20
- ? await cancelSwarm(id, body?.cwd)
21
- : body?.action === "accept"
22
- ? await acceptSwarmTask(id, body?.index, body?.cwd)
23
- : (() => { throw new BoundaryError("invalid swarm action"); })();
24
- return NextResponse.json({ success: true, data });
25
- } catch (error) {
26
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof BoundaryError || error instanceof SyntaxError ? 400 : 500 });
27
- }
28
- }
@@ -1,24 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { BoundaryError } from "@/lib/path-security";
3
- import { listSwarms, startSwarm } from "@/lib/swarm-service";
4
- import { RuntimeBusyError } from "@/lib/runtime-activity";
5
-
6
- export const dynamic = "force-dynamic";
7
-
8
- export async function GET(req: Request) {
9
- try {
10
- const cwd = new URL(req.url).searchParams.get("cwd");
11
- return NextResponse.json({ success: true, data: await listSwarms(cwd) });
12
- } catch (error) {
13
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof BoundaryError ? 400 : 500 });
14
- }
15
- }
16
-
17
- export async function POST(req: Request) {
18
- try {
19
- const body = await req.json();
20
- return NextResponse.json({ success: true, data: await startSwarm(body?.cwd, body?.tasks) }, { status: 202 });
21
- } catch (error) {
22
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof RuntimeBusyError ? 409 : error instanceof BoundaryError || error instanceof SyntaxError ? 400 : 500 });
23
- }
24
- }
@@ -1,27 +0,0 @@
1
- import { NextResponse } from "next/server";
2
- import { BoundaryError } from "@/lib/path-security";
3
- import { listTestFiles, readTestFile, runTestFile } from "@/lib/test-run-service";
4
- import { RuntimeBusyError } from "@/lib/runtime-activity";
5
-
6
- export const dynamic = "force-dynamic";
7
-
8
- export async function GET(req: Request) {
9
- try {
10
- const params = new URL(req.url).searchParams;
11
- const cwd = params.get("cwd");
12
- const file = params.get("file");
13
- const data = file ? await readTestFile(cwd, file) : { files: await listTestFiles(cwd), runner: "vitest" };
14
- return NextResponse.json({ success: true, data });
15
- } catch (error) {
16
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof BoundaryError ? 400 : 500 });
17
- }
18
- }
19
-
20
- export async function POST(req: Request) {
21
- try {
22
- const body = await req.json();
23
- return NextResponse.json({ success: true, data: await runTestFile(body?.cwd, body?.file) });
24
- } catch (error) {
25
- return NextResponse.json({ success: false, error: String((error as Error).message ?? error) }, { status: error instanceof RuntimeBusyError ? 409 : error instanceof BoundaryError || error instanceof SyntaxError ? 400 : 500 });
26
- }
27
- }