@pixelbyte-software/pixcode 1.54.7 → 1.54.9

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 (290) hide show
  1. package/CODE_OF_CONDUCT.md +41 -41
  2. package/CONTRIBUTING.md +155 -155
  3. package/LICENSE +718 -718
  4. package/README.de.md +169 -169
  5. package/README.ja.md +167 -167
  6. package/README.ko.md +167 -167
  7. package/README.md +418 -418
  8. package/README.ru.md +169 -169
  9. package/README.tr.md +298 -298
  10. package/README.zh-CN.md +167 -167
  11. package/SECURITY.md +46 -46
  12. package/dist/api-automation.html +110 -110
  13. package/dist/api-docs.html +548 -548
  14. package/dist/assets/{index-D-4VRH1a.js → index-Bm6uAqKU.js} +186 -184
  15. package/dist/assets/index-Dz1luE0u.css +32 -0
  16. package/dist/clear-cache.html +85 -85
  17. package/dist/convert-icons.md +52 -52
  18. package/dist/docs.html +308 -308
  19. package/dist/features.html +133 -133
  20. package/dist/generate-icons.js +48 -48
  21. package/dist/humans.txt +15 -15
  22. package/dist/icons/codex-white.svg +3 -3
  23. package/dist/icons/codex.svg +3 -3
  24. package/dist/icons/cursor-white.svg +11 -11
  25. package/dist/icons/qwen-logo.svg +14 -14
  26. package/dist/index.html +59 -59
  27. package/dist/landing.html +268 -268
  28. package/dist/llms-full.txt +119 -119
  29. package/dist/llms.txt +53 -53
  30. package/dist/manifest.json +60 -60
  31. package/dist/openapi.yaml +1696 -1696
  32. package/dist/orchestration.html +125 -125
  33. package/dist/robots.txt +4 -4
  34. package/dist/site.css +692 -692
  35. package/dist/sitemap.xml +51 -51
  36. package/dist/sw.js +132 -132
  37. package/dist-server/server/cli.js +100 -100
  38. package/dist-server/server/daemon/manager.js +33 -33
  39. package/dist-server/server/daemon-manager.js +64 -64
  40. package/dist-server/server/index.js +148 -14
  41. package/dist-server/server/index.js.map +1 -1
  42. package/dist-server/server/projects.js +16 -6
  43. package/dist-server/server/projects.js.map +1 -1
  44. package/dist-server/server/routes/auth.js +17 -5
  45. package/dist-server/server/routes/auth.js.map +1 -1
  46. package/dist-server/server/routes/commands.js +25 -25
  47. package/dist-server/server/routes/git.js +17 -17
  48. package/dist-server/server/routes/live-view.js +46 -46
  49. package/dist-server/server/services/public-api-manifest.js +51 -51
  50. package/package.json +224 -224
  51. package/scripts/fix-node-pty.js +67 -67
  52. package/scripts/github/create-v1.38-issues.mjs +351 -351
  53. package/scripts/github/create-vscode-workbench-issues.mjs +121 -121
  54. package/scripts/smoke/backend-resource-bounds.mjs +152 -152
  55. package/scripts/smoke/changes-panel-layout.mjs +48 -48
  56. package/scripts/smoke/chat-composer-fixed-layout.mjs +55 -55
  57. package/scripts/smoke/chat-message-timeline-order.mjs +41 -41
  58. package/scripts/smoke/chat-realtime-hydration.mjs +44 -44
  59. package/scripts/smoke/chat-session-provider-pools.mjs +35 -35
  60. package/scripts/smoke/chat-session-state.mjs +19 -19
  61. package/scripts/smoke/code-editor-theme.mjs +55 -55
  62. package/scripts/smoke/code-editor-vscode-engine.mjs +91 -91
  63. package/scripts/smoke/command-center-agent-writes.mjs +79 -79
  64. package/scripts/smoke/command-center-non-git.mjs +46 -46
  65. package/scripts/smoke/context-packet.mjs +43 -43
  66. package/scripts/smoke/control-room-ux-redesign.mjs +91 -91
  67. package/scripts/smoke/daemon-entrypoint.mjs +20 -20
  68. package/scripts/smoke/default-landing-routing.mjs +33 -33
  69. package/scripts/smoke/desktop-native-notifications.mjs +30 -30
  70. package/scripts/smoke/desktop-tray-icon.mjs +33 -33
  71. package/scripts/smoke/discord-release-workflow.mjs +24 -24
  72. package/scripts/smoke/git-install-update.mjs +255 -255
  73. package/scripts/smoke/handoff-artifact-protocol.mjs +50 -50
  74. package/scripts/smoke/live-view-diagnostics.mjs +53 -53
  75. package/scripts/smoke/live-view-environment.mjs +92 -92
  76. package/scripts/smoke/live-view-integration.mjs +450 -450
  77. package/scripts/smoke/mac-desktop-runtime.mjs +37 -37
  78. package/scripts/smoke/mobile-tunnel-guidance.mjs +29 -29
  79. package/scripts/smoke/mobile-ux.mjs +76 -76
  80. package/scripts/smoke/model-registry.mjs +36 -36
  81. package/scripts/smoke/multi-project-ui.mjs +45 -45
  82. package/scripts/smoke/multi-worker-slots.mjs +42 -42
  83. package/scripts/smoke/notification-center.mjs +87 -87
  84. package/scripts/smoke/notification-inapp-preference.mjs +23 -23
  85. package/scripts/smoke/notification-taxonomy.mjs +58 -58
  86. package/scripts/smoke/orchestration-api.mjs +172 -172
  87. package/scripts/smoke/orchestration-execution-dashboard.mjs +33 -33
  88. package/scripts/smoke/orchestration-live-run.mjs +176 -176
  89. package/scripts/smoke/orchestration-mobile-scroll.mjs +29 -29
  90. package/scripts/smoke/orchestration-model-sync.mjs +30 -30
  91. package/scripts/smoke/orchestration-permission-fallback.mjs +34 -34
  92. package/scripts/smoke/orchestration-runtime-guards.mjs +48 -48
  93. package/scripts/smoke/orchestration-user-facing-output.mjs +25 -25
  94. package/scripts/smoke/permission-policy.mjs +50 -50
  95. package/scripts/smoke/pixcode-workbench-1-48.mjs +167 -167
  96. package/scripts/smoke/provider-models-opencode-live.mjs +66 -66
  97. package/scripts/smoke/provider-rest-api.mjs +124 -124
  98. package/scripts/smoke/provider-selection-status.mjs +52 -52
  99. package/scripts/smoke/run-state-refresh.mjs +52 -52
  100. package/scripts/smoke/runtime-manager.mjs +99 -99
  101. package/scripts/smoke/shell-manual-disconnect.mjs +30 -30
  102. package/scripts/smoke/side-panel-editor-layout.mjs +34 -34
  103. package/scripts/smoke/static-root-routing.mjs +21 -21
  104. package/scripts/smoke/strict-handoff-compact.mjs +60 -60
  105. package/scripts/smoke/taskmaster-config.mjs +24 -24
  106. package/scripts/smoke/taskmaster-execution-telegram.mjs +3 -3
  107. package/scripts/smoke/taskmaster-onboarding.mjs +3 -3
  108. package/scripts/smoke/taskmaster-run-graph.mjs +3 -3
  109. package/scripts/smoke/telegram-control.mjs +331 -331
  110. package/scripts/smoke/tunnel-persistence.mjs +56 -56
  111. package/scripts/smoke/update-issue-progress.mjs +69 -69
  112. package/scripts/smoke/update-ux.mjs +55 -55
  113. package/scripts/smoke/v138-completion.mjs +132 -132
  114. package/scripts/smoke/v138-desktop-release-hardening.mjs +69 -69
  115. package/scripts/smoke/v138-diagnostics.mjs +63 -63
  116. package/scripts/smoke/v138-issue-planner.mjs +33 -33
  117. package/scripts/smoke/v143-remote-control.mjs +76 -76
  118. package/scripts/smoke/v144-production-loop.mjs +47 -47
  119. package/scripts/smoke/v145-platformization.mjs +46 -46
  120. package/scripts/smoke/v146-control-room-ui.mjs +150 -150
  121. package/scripts/smoke/version-modal-autoshow.mjs +29 -29
  122. package/scripts/smoke/vscode-workbench-layout.mjs +63 -63
  123. package/scripts/smoke/vscode-workbench-polish.mjs +461 -461
  124. package/scripts/smoke/workflow-fallback-replay.mjs +56 -56
  125. package/scripts/smoke/workflow-templates.mjs +43 -43
  126. package/scripts/smoke/workflow-trace-timeline.mjs +46 -46
  127. package/scripts/update-git-install.mjs +298 -298
  128. package/server/claude-sdk.js +927 -927
  129. package/server/cli.js +1106 -1106
  130. package/server/constants/config.js +4 -4
  131. package/server/cursor-cli.js +344 -344
  132. package/server/daemon/manager.js +563 -563
  133. package/server/daemon-manager.js +964 -964
  134. package/server/database/db.js +988 -988
  135. package/server/database/json-store.js +197 -197
  136. package/server/gemini-cli.js +550 -550
  137. package/server/gemini-response-handler.js +79 -79
  138. package/server/index.js +5659 -5529
  139. package/server/load-env.js +35 -35
  140. package/server/middleware/account-lockout.js +112 -112
  141. package/server/middleware/auth.js +277 -277
  142. package/server/middleware/rate-limiter.js +87 -87
  143. package/server/modules/orchestration/a2a/adapter-registry.ts +108 -108
  144. package/server/modules/orchestration/a2a/adapters/abstract-a2a.adapter.ts +63 -63
  145. package/server/modules/orchestration/a2a/adapters/claude-code.adapter.ts +286 -286
  146. package/server/modules/orchestration/a2a/adapters/codex.adapter.ts +244 -244
  147. package/server/modules/orchestration/a2a/adapters/cursor.adapter.ts +249 -249
  148. package/server/modules/orchestration/a2a/adapters/gemini.adapter.ts +248 -248
  149. package/server/modules/orchestration/a2a/adapters/json-event.adapter.test.ts +60 -60
  150. package/server/modules/orchestration/a2a/adapters/json-event.adapter.ts +101 -101
  151. package/server/modules/orchestration/a2a/adapters/opencode.adapter.ts +248 -248
  152. package/server/modules/orchestration/a2a/adapters/qwen.adapter.ts +248 -248
  153. package/server/modules/orchestration/a2a/agent-card.ts +55 -55
  154. package/server/modules/orchestration/a2a/auth.middleware.ts +29 -29
  155. package/server/modules/orchestration/a2a/bus.ts +46 -46
  156. package/server/modules/orchestration/a2a/routes.ts +586 -586
  157. package/server/modules/orchestration/a2a/task-dispatcher.ts +345 -345
  158. package/server/modules/orchestration/a2a/task-store.ts +178 -178
  159. package/server/modules/orchestration/a2a/types.ts +126 -126
  160. package/server/modules/orchestration/a2a/validator.ts +113 -113
  161. package/server/modules/orchestration/index.ts +99 -99
  162. package/server/modules/orchestration/preview/port-watcher.ts +112 -112
  163. package/server/modules/orchestration/preview/preview-proxy.ts +60 -60
  164. package/server/modules/orchestration/preview/types.ts +19 -19
  165. package/server/modules/orchestration/security/permission-policy.ts +401 -401
  166. package/server/modules/orchestration/tasks/orchestration-task-store.ts +41 -41
  167. package/server/modules/orchestration/tasks/orchestration-task.routes.ts +81 -81
  168. package/server/modules/orchestration/tasks/orchestration-task.service.ts +201 -201
  169. package/server/modules/orchestration/tasks/orchestration-task.types.ts +40 -40
  170. package/server/modules/orchestration/tasks/task-run-graph.ts +155 -155
  171. package/server/modules/orchestration/workflows/approval-queue.ts +106 -106
  172. package/server/modules/orchestration/workflows/built-in-workflows.ts +127 -127
  173. package/server/modules/orchestration/workflows/context-packet.ts +186 -186
  174. package/server/modules/orchestration/workflows/handoff-artifact.ts +175 -175
  175. package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -161
  176. package/server/modules/orchestration/workflows/workflow-replay.ts +254 -254
  177. package/server/modules/orchestration/workflows/workflow-runner.ts +2062 -2062
  178. package/server/modules/orchestration/workflows/workflow-store.ts +97 -97
  179. package/server/modules/orchestration/workflows/workflow-templates.ts +272 -272
  180. package/server/modules/orchestration/workflows/workflow-trace.ts +424 -424
  181. package/server/modules/orchestration/workflows/workflow.routes.ts +586 -586
  182. package/server/modules/orchestration/workflows/workflow.types.ts +111 -111
  183. package/server/modules/orchestration/workflows/workspace-target.ts +122 -122
  184. package/server/modules/orchestration/workspace/docker-workspace.ts +136 -136
  185. package/server/modules/orchestration/workspace/path-safety.ts +55 -55
  186. package/server/modules/orchestration/workspace/types.ts +52 -52
  187. package/server/modules/orchestration/workspace/workspace-manager.ts +102 -102
  188. package/server/modules/orchestration/workspace/worktree-workspace.ts +126 -126
  189. package/server/modules/providers/index.ts +2 -2
  190. package/server/modules/providers/list/claude/claude-auth.provider.ts +146 -146
  191. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
  192. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -306
  193. package/server/modules/providers/list/claude/claude.provider.ts +15 -15
  194. package/server/modules/providers/list/codex/codex-auth.provider.ts +117 -117
  195. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
  196. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -319
  197. package/server/modules/providers/list/codex/codex.provider.ts +15 -15
  198. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +147 -147
  199. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
  200. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -421
  201. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -15
  202. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +173 -173
  203. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -110
  204. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -227
  205. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -15
  206. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +131 -131
  207. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +286 -286
  208. package/server/modules/providers/list/qwen/qwen-auth.provider.ts +146 -146
  209. package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +265 -265
  210. package/server/modules/providers/provider.registry.ts +40 -40
  211. package/server/modules/providers/provider.routes.ts +982 -982
  212. package/server/modules/providers/services/mcp.service.ts +86 -86
  213. package/server/modules/providers/services/provider-auth.service.ts +26 -26
  214. package/server/modules/providers/services/sessions.service.ts +45 -45
  215. package/server/modules/providers/shared/base/abstract.provider.ts +20 -20
  216. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
  217. package/server/modules/providers/tests/mcp.test.ts +293 -293
  218. package/server/openai-codex.js +468 -468
  219. package/server/opencode-cli.js +491 -491
  220. package/server/opencode-response-handler.js +111 -111
  221. package/server/projects.js +3135 -3125
  222. package/server/qwen-code-cli.js +410 -410
  223. package/server/routes/agent.js +1451 -1451
  224. package/server/routes/auth.js +298 -286
  225. package/server/routes/codex.js +20 -20
  226. package/server/routes/commands.js +581 -581
  227. package/server/routes/cursor.js +61 -61
  228. package/server/routes/diagnostics.js +44 -44
  229. package/server/routes/gemini.js +25 -25
  230. package/server/routes/git.js +1822 -1822
  231. package/server/routes/live-view.js +434 -434
  232. package/server/routes/mcp-utils.js +13 -13
  233. package/server/routes/messages.js +97 -97
  234. package/server/routes/network.js +143 -143
  235. package/server/routes/platformization.js +231 -231
  236. package/server/routes/plugins.js +690 -690
  237. package/server/routes/production-agent-loop.js +90 -90
  238. package/server/routes/projects.js +918 -918
  239. package/server/routes/public-api.js +34 -34
  240. package/server/routes/qwen.js +27 -27
  241. package/server/routes/remote.js +56 -56
  242. package/server/routes/settings.js +321 -321
  243. package/server/routes/telegram.js +163 -163
  244. package/server/routes/user.js +125 -125
  245. package/server/routes/webhooks.js +63 -63
  246. package/server/services/control-room.js +102 -102
  247. package/server/services/diagnostics.js +165 -165
  248. package/server/services/external-access.js +403 -403
  249. package/server/services/install-jobs.js +715 -715
  250. package/server/services/live-view.js +956 -956
  251. package/server/services/managed-runtimes.js +493 -493
  252. package/server/services/model-registry.js +144 -144
  253. package/server/services/notification-orchestrator.js +365 -365
  254. package/server/services/notification-taxonomy.js +204 -204
  255. package/server/services/platformization.js +1052 -1052
  256. package/server/services/production-agent-loop.js +248 -248
  257. package/server/services/provider-cli-versions.js +149 -149
  258. package/server/services/provider-credentials.js +189 -189
  259. package/server/services/provider-models.js +396 -396
  260. package/server/services/public-api-manifest.js +181 -181
  261. package/server/services/qr-login.js +126 -126
  262. package/server/services/remote-connection.js +127 -127
  263. package/server/services/runtime-manager.js +323 -323
  264. package/server/services/startup-update.js +259 -259
  265. package/server/services/telegram/bot.js +393 -393
  266. package/server/services/telegram/control-center.js +2453 -2453
  267. package/server/services/telegram/telegram-gateway.js +314 -314
  268. package/server/services/telegram/telegram-http-client.js +201 -201
  269. package/server/services/telegram/translations.js +470 -470
  270. package/server/services/webhooks.js +216 -216
  271. package/server/sessionManager.js +225 -225
  272. package/server/setup-wizard.js +283 -283
  273. package/server/shared/interfaces.ts +54 -54
  274. package/server/shared/types.ts +172 -172
  275. package/server/shared/utils.ts +193 -193
  276. package/server/tsconfig.json +36 -36
  277. package/server/utils/colors.js +21 -21
  278. package/server/utils/commandParser.js +305 -305
  279. package/server/utils/frontmatter.js +18 -18
  280. package/server/utils/gitConfig.js +34 -34
  281. package/server/utils/plugin-loader.js +461 -461
  282. package/server/utils/plugin-process-manager.js +185 -185
  283. package/server/utils/port-access.js +227 -227
  284. package/server/utils/runtime-paths.js +37 -37
  285. package/server/utils/security-log.js +84 -84
  286. package/server/utils/url-detection.js +71 -71
  287. package/server/vite-daemon.js +79 -79
  288. package/shared/modelConstants.js +161 -161
  289. package/shared/networkHosts.js +22 -22
  290. package/dist/assets/index-DvudRU5X.css +0 -32
@@ -221,22 +221,22 @@ function buildDaemonServiceUnit({ appRoot, serverPort, databasePath, nodeExecPat
221
221
  nodeExecPath,
222
222
  cliEntry,
223
223
  });
224
- return `[Unit]
225
- Description=Pixcode Server
226
- After=network.target
227
-
228
- [Service]
229
- Type=simple
230
- WorkingDirectory=${appRoot}
231
- ExecStart=${execStart}
232
- Environment=HOST=0.0.0.0
233
- Environment=CI=true
234
- Environment=PIXCODE_DAEMON_MANAGED=1
235
- Restart=always
236
- RestartSec=2
237
-
238
- [Install]
239
- WantedBy=default.target
224
+ return `[Unit]
225
+ Description=Pixcode Server
226
+ After=network.target
227
+
228
+ [Service]
229
+ Type=simple
230
+ WorkingDirectory=${appRoot}
231
+ ExecStart=${execStart}
232
+ Environment=HOST=0.0.0.0
233
+ Environment=CI=true
234
+ Environment=PIXCODE_DAEMON_MANAGED=1
235
+ Restart=always
236
+ RestartSec=2
237
+
238
+ [Install]
239
+ WantedBy=default.target
240
240
  `;
241
241
  }
242
242
  function resolveFrontendDaemonEntry(appRoot, cliEntry) {
@@ -277,22 +277,22 @@ function buildFrontendDaemonServiceUnit({ appRoot, frontendPort, nodeExecPath, c
277
277
  nodeExecPath,
278
278
  cliEntry,
279
279
  });
280
- return `[Unit]
281
- Description=Pixcode Frontend (Vite Dev Server)
282
- After=network.target
283
-
284
- [Service]
285
- Type=simple
286
- WorkingDirectory=${appRoot}
287
- ExecStart=${execStart}
288
- Environment=HOST=0.0.0.0
289
- Environment=CI=true
290
- Environment=PIXCODE_DAEMON_MANAGED=1
291
- Restart=always
292
- RestartSec=2
293
-
294
- [Install]
295
- WantedBy=default.target
280
+ return `[Unit]
281
+ Description=Pixcode Frontend (Vite Dev Server)
282
+ After=network.target
283
+
284
+ [Service]
285
+ Type=simple
286
+ WorkingDirectory=${appRoot}
287
+ ExecStart=${execStart}
288
+ Environment=HOST=0.0.0.0
289
+ Environment=CI=true
290
+ Environment=PIXCODE_DAEMON_MANAGED=1
291
+ Restart=always
292
+ RestartSec=2
293
+
294
+ [Install]
295
+ WantedBy=default.target
296
296
  `;
297
297
  }
298
298
  function normalizeState(value) {
@@ -489,38 +489,38 @@ function showDaemonHelp(c, context = {}) {
489
489
  const statusExample = buildDaemonCliCommand({ subcommand: 'status', mode: 'system' }, context);
490
490
  const doctorExample = buildDaemonCliCommand({ subcommand: 'doctor', mode: 'auto' }, context);
491
491
  const logsExample = buildDaemonCliCommand({ subcommand: 'logs', mode: 'system' }, context);
492
- console.log(`
493
- ${c.bright('Pixcode Daemon')} - Persistent Linux service manager
494
-
495
- Usage:
496
- ${usagePrefix} daemon [subcommand] [options]
497
-
498
- Subcommands:
499
- ${c.bright('install')} Install/update unit, reload daemon, enable and start now
500
- ${c.bright('start')} Start the service
501
- ${c.bright('stop')} Stop the service (temporary; auto-start remains enabled)
502
- ${c.bright('restart')} Restart the service
503
- ${c.bright('status')} Show active/enabled state
504
- ${c.bright('logs')} Show recent service logs
505
- ${c.bright('enable')} Enable auto-start at boot
506
- ${c.bright('disable')} Disable auto-start at boot
507
- ${c.bright('uninstall')} Stop, disable, and remove the service unit
508
- ${c.bright('doctor')} Run diagnostics (bus, linger, units, state, port, logs)
509
- ${c.bright('help')} Show this help
510
-
511
- Options:
512
- -p, --port <port> Set service server port (default: 3001)
513
- --frontend-port <port> Start a separate frontend Vite service on this port (legacy/dev)
514
- --single-port, --no-frontend
515
- Serve the built UI from the backend port only (default)
516
- -m, --mode <mode> Service mode: user | system | auto (default: system)
517
- --database-path <path> Set service database path
518
-
519
- Examples:
520
- $ ${installExample}
521
- $ ${statusExample}
522
- $ ${doctorExample}
523
- $ ${logsExample}
492
+ console.log(`
493
+ ${c.bright('Pixcode Daemon')} - Persistent Linux service manager
494
+
495
+ Usage:
496
+ ${usagePrefix} daemon [subcommand] [options]
497
+
498
+ Subcommands:
499
+ ${c.bright('install')} Install/update unit, reload daemon, enable and start now
500
+ ${c.bright('start')} Start the service
501
+ ${c.bright('stop')} Stop the service (temporary; auto-start remains enabled)
502
+ ${c.bright('restart')} Restart the service
503
+ ${c.bright('status')} Show active/enabled state
504
+ ${c.bright('logs')} Show recent service logs
505
+ ${c.bright('enable')} Enable auto-start at boot
506
+ ${c.bright('disable')} Disable auto-start at boot
507
+ ${c.bright('uninstall')} Stop, disable, and remove the service unit
508
+ ${c.bright('doctor')} Run diagnostics (bus, linger, units, state, port, logs)
509
+ ${c.bright('help')} Show this help
510
+
511
+ Options:
512
+ -p, --port <port> Set service server port (default: 3001)
513
+ --frontend-port <port> Start a separate frontend Vite service on this port (legacy/dev)
514
+ --single-port, --no-frontend
515
+ Serve the built UI from the backend port only (default)
516
+ -m, --mode <mode> Service mode: user | system | auto (default: system)
517
+ --database-path <path> Set service database path
518
+
519
+ Examples:
520
+ $ ${installExample}
521
+ $ ${statusExample}
522
+ $ ${doctorExample}
523
+ $ ${logsExample}
524
524
  `);
525
525
  }
526
526
  export function hasInstalledDaemonUnit() {
@@ -453,10 +453,20 @@ async function runRuntimeDirUpdateJob(job, runtimeDir, latestVersion, tarballUrl
453
453
  });
454
454
  return latestVersion;
455
455
  }
456
+ function isNodeVersionSupported() {
457
+ const match = process.version?.match(/^v(\d+)\./);
458
+ if (!match)
459
+ return true; // can't detect, assume ok
460
+ return parseInt(match[1], 10) >= 20;
461
+ }
456
462
  async function runCommandUpdateJob(job, updateCommand, updateCwd) {
457
- appendUpdateJobLog(job, 'meta', `Running: ${updateCommand}\n`);
458
- await new Promise((resolve, reject) => {
459
- const child = spawn(updateCommand, {
463
+ if (!isNodeVersionSupported()) {
464
+ const msg = `Node.js ${process.version} is too old. Pixcode requires Node.js 20+. Please upgrade Node.js first.\n`;
465
+ appendUpdateJobLog(job, 'stderr', msg);
466
+ throw new Error(msg.trim());
467
+ }
468
+ const runCommand = (cmd) => new Promise((resolve, reject) => {
469
+ const child = spawn(cmd, {
460
470
  cwd: updateCwd,
461
471
  env: process.env,
462
472
  shell: true,
@@ -468,15 +478,43 @@ async function runCommandUpdateJob(job, updateCommand, updateCwd) {
468
478
  }
469
479
  catch { /* noop */ }
470
480
  child.stdout?.on('data', (data) => appendUpdateJobLog(job, 'stdout', data.toString()));
471
- child.stderr?.on('data', (data) => appendUpdateJobLog(job, 'stderr', data.toString()));
481
+ let stderrBuf = '';
482
+ child.stderr?.on('data', (data) => {
483
+ const chunk = data.toString();
484
+ stderrBuf += chunk;
485
+ appendUpdateJobLog(job, 'stderr', chunk);
486
+ });
472
487
  child.on('error', reject);
473
488
  child.on('close', (code) => {
474
489
  if (code === 0)
475
490
  resolve();
476
491
  else
477
- reject(new Error(`Update command exited with code ${code}`));
492
+ reject({ code, stderr: stderrBuf });
478
493
  });
479
494
  });
495
+ appendUpdateJobLog(job, 'meta', `Running: ${updateCommand}\n`);
496
+ try {
497
+ await runCommand(updateCommand);
498
+ }
499
+ catch (err) {
500
+ // On Linux/macOS, retry with sudo if the initial attempt failed with EACCES.
501
+ // npm install -g needs write access to /usr/local/lib/node_modules/,
502
+ // which the running user may not have.
503
+ if (process.platform !== 'win32' && (err.stderr?.includes('EACCES') || err.stderr?.includes('permission denied'))) {
504
+ const sudoCmd = `sudo -n ${updateCommand}`;
505
+ appendUpdateJobLog(job, 'meta', `Permission denied. Retrying with sudo...\n`);
506
+ try {
507
+ await runCommand(sudoCmd);
508
+ return;
509
+ }
510
+ catch (sudoErr) {
511
+ appendUpdateJobLog(job, 'stderr', `Sudo update also failed: ${sudoErr.stderr || sudoErr.code}\n`);
512
+ appendUpdateJobLog(job, 'meta', 'Tip: Run the update manually with: sudo npm install -g @pixelbyte-software/pixcode@latest\n');
513
+ throw new Error(`Update command exited with code ${err.code}`);
514
+ }
515
+ }
516
+ throw new Error(`Update command exited with code ${err.code}`);
517
+ }
480
518
  }
481
519
  function readCurrentPackageVersion() {
482
520
  try {
@@ -1070,6 +1108,10 @@ const FILE_TREE_MAX_ITEMS = Number.parseInt(process.env.PIXCODE_FILE_TREE_MAX_IT
1070
1108
  const FILE_TREE_MAX_DIRECTORIES = Number.parseInt(process.env.PIXCODE_FILE_TREE_MAX_DIRECTORIES || '', 10) || 1200;
1071
1109
  const FILE_TREE_SCAN_MAX_MS = Number.parseInt(process.env.PIXCODE_FILE_TREE_SCAN_MAX_MS || '', 10) || 4000;
1072
1110
  const FILE_TREE_MAX_ENTRIES_PER_DIRECTORY = Number.parseInt(process.env.PIXCODE_FILE_TREE_MAX_ENTRIES_PER_DIRECTORY || '', 10) || 1500;
1111
+ const FILE_TREE_MAX_DEPTH_DEFAULT = 5; // was 10, reduced to avoid deep traversal on huge projects
1112
+ const FILE_TREE_CACHE_TTL_MS = 3000; // short-lived cache for rapid successive requests
1113
+ const FILE_TREE_CACHE_MAX_ENTRIES = 50;
1114
+ const fileTreeCache = new Map();
1073
1115
  const FILE_TREE_EXCLUDED_ENTRY_NAMES = new Set([
1074
1116
  '.cache',
1075
1117
  '.git',
@@ -1606,6 +1648,7 @@ app.get('/health', (req, res) => {
1606
1648
  timestamp: new Date().toISOString(),
1607
1649
  installMode,
1608
1650
  version: SERVER_VERSION,
1651
+ nodeVersion: process.version,
1609
1652
  pendingRestart: updateState.pendingRestart,
1610
1653
  lastAppliedUpdate: updateState.lastAppliedUpdate,
1611
1654
  });
@@ -2319,6 +2362,14 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
2319
2362
  console.warn('[update] Registry precheck failed:', (err && err.message) || err);
2320
2363
  }
2321
2364
  }
2365
+ // Check Node.js version before starting update
2366
+ if (!isNodeVersionSupported()) {
2367
+ send('log', { stream: 'stderr', chunk: `Node.js ${process.version} is too old. Pixcode requires Node.js 20+.\n` });
2368
+ send('log', { stream: 'meta', chunk: 'Please upgrade Node.js and try again.\n' });
2369
+ send('done', { success: false, error: `Node.js ${process.version} is too old. Pixcode requires Node.js 20+. Please upgrade Node.js first.` });
2370
+ endStream();
2371
+ return;
2372
+ }
2322
2373
  send('log', { stream: 'meta', chunk: `Running: ${updateCommandLabel}\n` });
2323
2374
  // Cross-platform shell invocation. `detached: true` + `unref()` below
2324
2375
  // means the install child survives if this server process gets killed
@@ -2327,7 +2378,7 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
2327
2378
  // can segfault or the supervisor kills it). Without detachment, a
2328
2379
  // killed parent tears down the npm child too and users end up with
2329
2380
  // a half-installed package and no server at all.
2330
- const child = spawn(updateCommand, {
2381
+ let child = spawn(updateCommand, {
2331
2382
  cwd: updateCwd,
2332
2383
  env: process.env,
2333
2384
  shell: true,
@@ -2353,7 +2404,9 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
2353
2404
  child.stdout?.on('data', (data) => {
2354
2405
  send('log', { stream: 'stdout', chunk: data.toString() });
2355
2406
  });
2407
+ let stderrBuf = '';
2356
2408
  child.stderr?.on('data', (data) => {
2409
+ stderrBuf += data.toString();
2357
2410
  send('log', { stream: 'stderr', chunk: data.toString() });
2358
2411
  });
2359
2412
  child.on('error', (error) => {
@@ -2363,7 +2416,7 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
2363
2416
  send('done', { success: false, error: error.message });
2364
2417
  endStream();
2365
2418
  });
2366
- child.on('close', (code) => {
2419
+ child.on('close', async (code) => {
2367
2420
  if (ended)
2368
2421
  return;
2369
2422
  if (clientAborted) {
@@ -2376,13 +2429,61 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
2376
2429
  version: SERVER_VERSION,
2377
2430
  message: 'Update completed. Restart the server to apply changes.',
2378
2431
  });
2432
+ endStream();
2433
+ return;
2379
2434
  }
2380
- else {
2381
- send('done', {
2382
- success: false,
2383
- error: `Update command exited with code ${code}`,
2384
- });
2435
+ // On Linux/macOS, retry with sudo on EACCES (npm install -g permission error)
2436
+ if (code !== 0 && process.platform !== 'win32' && (stderrBuf.includes('EACCES') || stderrBuf.includes('permission denied'))) {
2437
+ const sudoCmd = `sudo -n ${updateCommand}`;
2438
+ send('log', { stream: 'meta', chunk: 'Permission denied. Retrying with sudo...\n' });
2439
+ try {
2440
+ await new Promise((resolveSudo, rejectSudo) => {
2441
+ let sudoEnded = false;
2442
+ const sudoChild = spawn(sudoCmd, {
2443
+ cwd: updateCwd,
2444
+ env: process.env,
2445
+ shell: true,
2446
+ detached: true,
2447
+ stdio: ['ignore', 'pipe', 'pipe'],
2448
+ });
2449
+ try {
2450
+ sudoChild.unref();
2451
+ }
2452
+ catch { /* noop */ }
2453
+ sudoChild.stdout?.on('data', (d) => send('log', { stream: 'stdout', chunk: d.toString() }));
2454
+ let sudoStderr = '';
2455
+ sudoChild.stderr?.on('data', (d) => { sudoStderr += d.toString(); send('log', { stream: 'stderr', chunk: d.toString() }); });
2456
+ sudoChild.on('error', (e) => { if (!sudoEnded) {
2457
+ sudoEnded = true;
2458
+ rejectSudo(e);
2459
+ } });
2460
+ sudoChild.on('close', (sudoCode) => {
2461
+ if (sudoEnded)
2462
+ return;
2463
+ sudoEnded = true;
2464
+ if (sudoCode === 0)
2465
+ resolveSudo();
2466
+ else
2467
+ rejectSudo(new Error(`Sudo update exited with code ${sudoCode}`));
2468
+ });
2469
+ });
2470
+ send('done', {
2471
+ success: true,
2472
+ version: SERVER_VERSION,
2473
+ message: 'Update completed (with sudo). Restart the server to apply changes.',
2474
+ });
2475
+ endStream();
2476
+ return;
2477
+ }
2478
+ catch (sudoErr) {
2479
+ send('log', { stream: 'stderr', chunk: `Sudo update failed: ${sudoErr.message}\n` });
2480
+ send('log', { stream: 'meta', chunk: 'Tip: Run the update manually with: sudo npm install -g @pixelbyte-software/pixcode@latest\n' });
2481
+ }
2385
2482
  }
2483
+ send('done', {
2484
+ success: false,
2485
+ error: `Update command exited with code ${code}`,
2486
+ });
2386
2487
  endStream();
2387
2488
  });
2388
2489
  });
@@ -2867,7 +2968,7 @@ app.get('/api/projects/:projectName/files', authenticateToken, requireProjectAcc
2867
2968
  catch (e) {
2868
2969
  return res.status(404).json({ error: `Project path not found: ${actualPath}` });
2869
2970
  }
2870
- const files = await getFileTree(actualPath, 10, 0, true);
2971
+ const files = await getFileTree(actualPath, FILE_TREE_MAX_DEPTH_DEFAULT, 0, true);
2871
2972
  res.json(filterFileTreeForUser(files, req.user, {
2872
2973
  name: req.params.projectName,
2873
2974
  projectName: req.params.projectName,
@@ -4697,6 +4798,26 @@ function permToRwx(perm) {
4697
4798
  const x = perm & 1 ? 'x' : '-';
4698
4799
  return r + w + x;
4699
4800
  }
4801
+ // File tree result cache (keyed by path:depth:showHidden, TTL 3s)
4802
+ function readFileTreeCache(cacheKey) {
4803
+ const entry = fileTreeCache.get(cacheKey);
4804
+ if (!entry || entry.expiresAt <= Date.now()) {
4805
+ if (entry)
4806
+ fileTreeCache.delete(cacheKey);
4807
+ // Prune stale entries
4808
+ if (fileTreeCache.size > FILE_TREE_CACHE_MAX_ENTRIES) {
4809
+ const keys = [...fileTreeCache.keys()];
4810
+ for (const k of keys.slice(0, keys.length - FILE_TREE_CACHE_MAX_ENTRIES)) {
4811
+ fileTreeCache.delete(k);
4812
+ }
4813
+ }
4814
+ return undefined;
4815
+ }
4816
+ return entry.tree;
4817
+ }
4818
+ function writeFileTreeCache(cacheKey, tree) {
4819
+ fileTreeCache.set(cacheKey, { tree, expiresAt: Date.now() + FILE_TREE_CACHE_TTL_MS });
4820
+ }
4700
4821
  function createFileTreeScanContext() {
4701
4822
  return {
4702
4823
  startedAt: Date.now(),
@@ -4752,6 +4873,13 @@ async function readDirectoryEntriesBounded(dirPath, context) {
4752
4873
  return entries;
4753
4874
  }
4754
4875
  async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden = true, scanContext = null) {
4876
+ // Check cache on top-level call
4877
+ if (currentDepth === 0 && !scanContext) {
4878
+ const cacheKey = `${path.resolve(dirPath)}:${maxDepth}:${showHidden}`;
4879
+ const cached = readFileTreeCache(cacheKey);
4880
+ if (cached)
4881
+ return cached;
4882
+ }
4755
4883
  const context = scanContext || createFileTreeScanContext();
4756
4884
  const items = [];
4757
4885
  if (!hasFileTreeBudget(context)) {
@@ -4798,12 +4926,18 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
4798
4926
  }
4799
4927
  items.push(item);
4800
4928
  }
4801
- return items.sort((a, b) => {
4929
+ const sorted = items.sort((a, b) => {
4802
4930
  if (a.type !== b.type) {
4803
4931
  return a.type === 'directory' ? -1 : 1;
4804
4932
  }
4805
4933
  return a.name.localeCompare(b.name);
4806
4934
  });
4935
+ // Store in cache on top-level call
4936
+ if (currentDepth === 0 && !scanContext) {
4937
+ const cacheKey = `${path.resolve(dirPath)}:${maxDepth}:${showHidden}`;
4938
+ writeFileTreeCache(cacheKey, sorted);
4939
+ }
4940
+ return sorted;
4807
4941
  }
4808
4942
  const SERVER_PORT = process.env.SERVER_PORT || 3001;
4809
4943
  const HOST = process.env.HOST || '0.0.0.0';