@pasko70/pibo 1.0.2 → 1.0.4

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.
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { existsSync, readFileSync, statSync } from "node:fs";
3
3
  import { extname, isAbsolute, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
4
5
  import { brotliCompressSync, gzipSync } from "node:zlib";
5
6
  import { PiboWebHttpError, readJsonBody, responseHtml, responseJson } from "../../web/http.js";
6
7
  import { ChatEventLog, createDefaultChatEventLog } from "./event-log.js";
@@ -22,7 +23,7 @@ export const CHAT_WEB_APP_NAME = "pibo.chat-web";
22
23
  export const CHAT_WEB_CHANNEL = "pibo.chat-web";
23
24
  export const CHAT_WEB_MOUNT_PATH = "/apps/chat";
24
25
  export const CHAT_WEB_API_PREFIX = "/api/chat";
25
- const CHAT_UI_DIST_DIR = resolve(process.cwd(), "dist/apps/chat-ui");
26
+ const CHAT_UI_DIST_DIR = resolve(fileURLToPath(new URL("../../../dist/apps/chat-ui", import.meta.url)));
26
27
  const compressedAssetCache = new Map();
27
28
  const TRACE_CACHE_MAX_ENTRIES = 128;
28
29
  function writeSse(controller, event, payload, id) {
@@ -49,6 +49,31 @@ function runBuffered(command, args, env = process.env) {
49
49
  });
50
50
  });
51
51
  }
52
+ function isRootUser() {
53
+ return typeof process.getuid === 'function' && process.getuid() === 0;
54
+ }
55
+ async function resolveUvCommand() {
56
+ const uv = await runBuffered('uv', ['--version']);
57
+ if (uv.ok)
58
+ return 'uv';
59
+ const localUv = join(homedir(), '.local', 'bin', 'uv');
60
+ if (existsSync(localUv)) {
61
+ const local = await runBuffered(localUv, ['--version']);
62
+ if (local.ok)
63
+ return localUv;
64
+ }
65
+ if (process.platform === 'linux' && isRootUser()) {
66
+ console.log('uv was not found on PATH. Installing uv automatically.');
67
+ await runInheritedCommand('sh', ['-c', 'curl -LsSf https://astral.sh/uv/install.sh | sh']);
68
+ const installed = await runBuffered(localUv, ['--version'], {
69
+ ...process.env,
70
+ PATH: `${join(homedir(), '.local', 'bin')}:${process.env.PATH ?? ''}`,
71
+ });
72
+ if (installed.ok)
73
+ return localUv;
74
+ }
75
+ return undefined;
76
+ }
52
77
  export function runInheritedCommand(command, args, env = process.env) {
53
78
  return new Promise((resolve, reject) => {
54
79
  console.log(`Running: ${command} ${args.join(' ')}`);
@@ -82,9 +107,10 @@ export function runInheritedCommand(command, args, env = process.env) {
82
107
  }
83
108
  export async function printToolPythonRuntimeDoctor(name, spec) {
84
109
  const paths = getToolPythonRuntimePaths(name, spec);
85
- const uv = await runBuffered('uv', ['--version']);
110
+ const uvCommand = await resolveUvCommand();
111
+ const uv = uvCommand ? await runBuffered(uvCommand, ['--version']) : { ok: false, output: 'missing' };
86
112
  const python = uv.ok
87
- ? await runBuffered('uv', ['python', 'find', spec.pythonVersion])
113
+ ? await runBuffered(uvCommand, ['python', 'find', spec.pythonVersion])
88
114
  : { ok: false, output: 'skipped because uv is missing' };
89
115
  console.log(`${name}`);
90
116
  console.log(` uv: ${uv.ok ? uv.output || 'ok' : `missing (${uv.output})`}`);
@@ -122,13 +148,13 @@ export async function printToolPythonRuntimeDoctor(name, spec) {
122
148
  }
123
149
  }
124
150
  export async function installToolPythonRuntime(name, spec) {
125
- const uv = await runBuffered('uv', ['--version']);
126
- if (!uv.ok) {
151
+ const uvCommand = await resolveUvCommand();
152
+ if (!uvCommand) {
127
153
  throw new Error(formatCliError({
128
154
  code: ErrorCode.CLIENT_ERROR,
129
155
  type: 'CLI_TOOL_UV_MISSING',
130
156
  message: 'uv was not found on PATH',
131
- details: uv.output,
157
+ details: 'spawn uv ENOENT',
132
158
  suggestion: 'Install uv first. macOS/Linux: curl -LsSf https://astral.sh/uv/install.sh | sh. Windows PowerShell: irm https://astral.sh/uv/install.ps1 | iex.',
133
159
  }));
134
160
  }
@@ -136,9 +162,9 @@ export async function installToolPythonRuntime(name, spec) {
136
162
  await mkdir(paths.rootDir, { recursive: true });
137
163
  await mkdir(paths.homeDir, { recursive: true });
138
164
  if (!existsSync(paths.venvDir)) {
139
- await runInheritedCommand('uv', ['venv', paths.venvDir, '--python', spec.pythonVersion]);
165
+ await runInheritedCommand(uvCommand, ['venv', paths.venvDir, '--python', spec.pythonVersion]);
140
166
  }
141
- await runInheritedCommand('uv', [
167
+ await runInheritedCommand(uvCommand, [
142
168
  'pip',
143
169
  'install',
144
170
  '--python',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pasko70/pibo",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "description": "Minimal TypeScript wrapper around Pi Coding Agent.",
6
6
  "files": [