pi-ui-extend 0.1.63 → 0.1.65

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.
package/README.md CHANGED
@@ -193,7 +193,7 @@ Type `/` to open the command picker. Commands with arguments can also be typed d
193
193
  | `/new_tab` | Start a new session in a new tab. |
194
194
  | `/compact [instructions]` | Compact context with optional instructions. |
195
195
  | `/reload` | Reload keybindings, extensions, skills, prompts, and themes. |
196
- | `/update` | Check for Pix updates; install from the shell with `pix update`. |
196
+ | `/update` | Check Pix and global Pi compatibility; install from the shell with `pix update`. |
197
197
  | `/changelog` | Show the changelog for Pi packages. |
198
198
  | `/quit`, `/exit` | Exit Pix. |
199
199
 
@@ -220,7 +220,9 @@ Force reinstall:
220
220
  pix update --force
221
221
  ```
222
222
 
223
- `pix update` updates the Pix npm package, pinned Pi SDK dependencies, renderer-owned extensions, and the bundled `pi-tools-suite`. On the next startup, Pix refreshes the extension symlink in `~/.pi/agent/extensions/pi-tools-suite`.
223
+ `pix update` updates the Pix npm package, then installs the global `pi` CLI at the exact Pi SDK version pinned by the updated Pix package. It also updates renderer-owned extensions and the bundled `pi-tools-suite`. On the next startup, Pix refreshes the extension symlink in `~/.pi/agent/extensions/pi-tools-suite`.
224
+
225
+ `pix update --check` reports both the Pix release status and whether global Pi in the same package-manager prefix matches Pix. `pix update --force` reinstalls both packages. If the active `pi` command comes from a different package-manager prefix, update that installation separately.
224
226
 
225
227
  Update checks are disabled by any of these environment variables:
226
228
 
@@ -228,11 +230,10 @@ Update checks are disabled by any of these environment variables:
228
230
  - `PI_SKIP_VERSION_CHECK=1`
229
231
  - `PIX_SKIP_VERSION_CHECK=1`
230
232
 
231
- If Pi packages are installed separately and managed by Pi itself, update them separately:
233
+ Pi-managed extension packages remain separate from the global CLI synchronization:
232
234
 
233
235
  ```bash
234
236
  pi update --extensions
235
- pi update
236
237
  ```
237
238
 
238
239
  ## Configuration
@@ -28,6 +28,14 @@ export type PixSelfUpdateCommand = {
28
28
  args: string[];
29
29
  display: string;
30
30
  };
31
+ export type GlobalPiCheckStatus = "current" | "mismatched" | "missing" | "unavailable";
32
+ export type GlobalPiCheckResult = {
33
+ status: GlobalPiCheckStatus;
34
+ targetVersion?: string;
35
+ currentVersion?: string;
36
+ packageRoot?: string;
37
+ reason?: string;
38
+ };
31
39
  export type PixUpdateCheckOptions = {
32
40
  timeoutMs?: number;
33
41
  packageRoot?: string;
@@ -41,10 +49,14 @@ export declare function parsePixUpdateArgs(argv: readonly string[]): PixUpdateCl
41
49
  export declare function getPixPackageVersion(packageRoot?: string): string;
42
50
  export declare function checkPixUpdate(options?: PixUpdateCheckOptions): Promise<PixUpdateCheckResult>;
43
51
  export declare function checkPiUpdate(options?: PiUpdateCheckOptions): Promise<PixUpdateCheckResult>;
52
+ export declare function getPixPinnedPiVersion(packageRoot?: string): string | undefined;
53
+ export declare function checkGlobalPiInstall(pixPackageRoot?: string): GlobalPiCheckResult;
44
54
  export declare function formatPixUpdateCheck(result: PixUpdateCheckResult): string;
55
+ export declare function formatGlobalPiCheck(result: GlobalPiCheckResult): string;
45
56
  export declare function formatPixStartupUpdateDialog(result: PixUpdateCheckResult): string;
46
57
  export declare function formatPiStartupUpdateToast(result: PixUpdateCheckResult): string;
47
58
  export declare function getPixSelfUpdateCommand(packageName: string, latestVersion?: string, packageRoot?: string): PixSelfUpdateCommand | undefined;
59
+ export declare function getGlobalPiUpdateCommand(targetVersion: string, pixPackageRoot?: string): PixSelfUpdateCommand | undefined;
48
60
  export declare function runPixUpdateCli(argv?: readonly string[]): Promise<number>;
49
61
  declare function runCommand(command: PixSelfUpdateCommand): Promise<void>;
50
62
  export {};
@@ -17,11 +17,11 @@ export function setPixUpdateTestDeps(overrides) {
17
17
  export function pixUpdateUsage() {
18
18
  return `Usage: pix update [--check] [--force]
19
19
 
20
- Check for or install the latest published Pix package.
20
+ Check for or install the latest published Pix package and synchronize the global Pi CLI.
21
21
 
22
22
  Options:
23
- --check Only check for an available update
24
- --force Reinstall even when Pix appears up to date
23
+ --check Only check Pix and global Pi; do not install anything
24
+ --force Reinstall Pix and its matching global Pi version
25
25
  -h, --help Show this help
26
26
 
27
27
  Inside the TUI, /update performs the same non-mutating check.
@@ -61,6 +61,58 @@ export async function checkPiUpdate(options = {}) {
61
61
  const packageInfo = readPackageInfo(packageRoot, PI_PACKAGE_NAME);
62
62
  return await checkPackageUpdate(packageInfo, options);
63
63
  }
64
+ export function getPixPinnedPiVersion(packageRoot = readPixPackageInfo().packageRoot) {
65
+ const raw = readPackageJson(packageRoot);
66
+ const dependencies = isRecord(raw.dependencies) ? raw.dependencies : undefined;
67
+ const version = dependencies?.[PI_PACKAGE_NAME];
68
+ if (typeof version !== "string")
69
+ return undefined;
70
+ const trimmedVersion = version.trim();
71
+ return parsePackageVersion(trimmedVersion) ? trimmedVersion : undefined;
72
+ }
73
+ export function checkGlobalPiInstall(pixPackageRoot = readPixPackageInfo().packageRoot) {
74
+ let targetVersion;
75
+ try {
76
+ targetVersion = getPixPinnedPiVersion(pixPackageRoot);
77
+ }
78
+ catch (error) {
79
+ return {
80
+ status: "unavailable",
81
+ reason: error instanceof Error ? error.message : String(error),
82
+ };
83
+ }
84
+ if (!targetVersion) {
85
+ return { status: "unavailable", reason: `Pix does not declare a pinned ${PI_PACKAGE_NAME} dependency` };
86
+ }
87
+ const packageRoot = getGlobalPiPackageRoot(pixPackageRoot);
88
+ if (!packageRoot) {
89
+ return {
90
+ status: "unavailable",
91
+ targetVersion,
92
+ reason: "Pix is not installed under a global node_modules prefix",
93
+ };
94
+ }
95
+ const packageJsonPath = join(packageRoot, "package.json");
96
+ if (!existsSync(packageJsonPath))
97
+ return { status: "missing", targetVersion, packageRoot };
98
+ try {
99
+ const packageInfo = readPackageInfo(packageRoot, PI_PACKAGE_NAME);
100
+ return {
101
+ status: packageVersionsEqual(packageInfo.version, targetVersion) ? "current" : "mismatched",
102
+ targetVersion,
103
+ currentVersion: packageInfo.version,
104
+ packageRoot,
105
+ };
106
+ }
107
+ catch (error) {
108
+ return {
109
+ status: "unavailable",
110
+ targetVersion,
111
+ packageRoot,
112
+ reason: error instanceof Error ? error.message : String(error),
113
+ };
114
+ }
115
+ }
64
116
  async function checkPackageUpdate(packageInfo, options) {
65
117
  const base = {
66
118
  packageName: packageInfo.name,
@@ -124,7 +176,31 @@ export function formatPixUpdateCheck(result) {
124
176
  lines.push("run: pix update --force to try reinstalling anyway");
125
177
  break;
126
178
  }
127
- lines.push("scope: Pix package, renderer extensions, bundled skills copied into ~/.agents/skills, and the pi-tools-suite payload linked into ~/.pi/agent/extensions");
179
+ lines.push("scope: Pix package, matching global Pi CLI, renderer extensions, bundled skills copied into ~/.agents/skills, and the pi-tools-suite payload linked into ~/.pi/agent/extensions");
180
+ return lines.join("\n");
181
+ }
182
+ export function formatGlobalPiCheck(result) {
183
+ const lines = [
184
+ "Global Pi compatibility",
185
+ ...(result.currentVersion ? [`current: ${PI_PACKAGE_NAME} v${result.currentVersion}`] : []),
186
+ ...(result.targetVersion ? [`required by Pix: ${PI_PACKAGE_NAME} v${result.targetVersion}`] : []),
187
+ ];
188
+ switch (result.status) {
189
+ case "current":
190
+ lines.push("status: compatible");
191
+ break;
192
+ case "mismatched":
193
+ lines.push("status: version mismatch");
194
+ lines.push("run: pix update");
195
+ break;
196
+ case "missing":
197
+ lines.push("status: global Pi is not installed in Pix's package-manager prefix");
198
+ lines.push("run: pix update");
199
+ break;
200
+ case "unavailable":
201
+ lines.push(`status: unable to check${result.reason ? ` (${result.reason})` : ""}`);
202
+ break;
203
+ }
128
204
  return lines.join("\n");
129
205
  }
130
206
  export function formatPixStartupUpdateDialog(result) {
@@ -134,7 +210,7 @@ export function formatPixStartupUpdateDialog(result) {
134
210
  ...(result.latestVersion ? [`latest: ${result.latestVersion}`] : []),
135
211
  "",
136
212
  "Pix includes the pinned Pi SDK/dependencies used by this renderer.",
137
- "Updating only the global `pi` CLI is not enough for Pix.",
213
+ "`pix update` also synchronizes the global `pi` CLI to that pinned version.",
138
214
  "",
139
215
  "To update:",
140
216
  "1. Exit Pix.",
@@ -149,9 +225,15 @@ export function formatPiStartupUpdateToast(result) {
149
225
  : `Pi update detected; Pix bundles Pi ${result.currentVersion}. Waiting for a matching Pix update.`;
150
226
  }
151
227
  export function getPixSelfUpdateCommand(packageName, latestVersion, packageRoot = readPixPackageInfo().packageRoot) {
228
+ return getGlobalPackageUpdateCommand(packageName, latestVersion, packageRoot);
229
+ }
230
+ export function getGlobalPiUpdateCommand(targetVersion, pixPackageRoot = readPixPackageInfo().packageRoot) {
231
+ return getGlobalPackageUpdateCommand(PI_PACKAGE_NAME, targetVersion, pixPackageRoot);
232
+ }
233
+ function getGlobalPackageUpdateCommand(packageName, version, packageRoot) {
152
234
  if (!packageRootLooksPackageManaged(packageRoot))
153
235
  return undefined;
154
- const installSpec = latestVersion ? `${packageName}@${latestVersion}` : packageName;
236
+ const installSpec = version ? `${packageName}@${version}` : packageName;
155
237
  const method = detectInstallMethod(packageRoot);
156
238
  const commandParts = method === "npm" ? configuredNpmCommand() ?? ["npm"] : undefined;
157
239
  switch (method) {
@@ -184,26 +266,58 @@ export async function runPixUpdateCli(argv = process.argv.slice(2)) {
184
266
  }
185
267
  const check = await pixUpdateDeps.checkPixUpdate();
186
268
  console.log(formatPixUpdateCheck(check));
269
+ let globalPiCheck = checkGlobalPiInstall(check.packageRoot);
270
+ console.log(`\n${formatGlobalPiCheck(globalPiCheck)}`);
187
271
  if (options.checkOnly)
188
- return check.status === "unavailable" ? 1 : 0;
189
- if (check.status === "current" && !options.force)
190
- return 0;
272
+ return check.status === "unavailable" || globalPiCheck.status === "unavailable" ? 1 : 0;
191
273
  if ((check.status === "skipped" || check.status === "unavailable") && !options.force)
192
274
  return 1;
193
- const command = getPixSelfUpdateCommand(check.packageName, check.latestVersion, check.packageRoot);
194
- if (!command) {
195
- console.error(`pix cannot self-update this installation. ${sourceCheckoutUpdateHint()}`);
275
+ const shouldUpdatePix = options.force || check.status !== "current";
276
+ if (shouldUpdatePix) {
277
+ const command = getPixSelfUpdateCommand(check.packageName, check.latestVersion, check.packageRoot);
278
+ if (!command) {
279
+ console.error(`pix cannot self-update this installation. ${sourceCheckoutUpdateHint()}`);
280
+ return 1;
281
+ }
282
+ console.log(`Updating Pix with ${command.display}...`);
283
+ try {
284
+ await pixUpdateDeps.runCommand(command);
285
+ console.log("Updated Pix.");
286
+ }
287
+ catch (error) {
288
+ console.error(`Pix update failed: ${error instanceof Error ? error.message : String(error)}`);
289
+ console.error(`Try running manually: ${command.display}`);
290
+ return 1;
291
+ }
292
+ // npm may have replaced Pix's package.json, so refresh the required Pi pin.
293
+ globalPiCheck = checkGlobalPiInstall(check.packageRoot);
294
+ console.log(`\n${formatGlobalPiCheck(globalPiCheck)}`);
295
+ }
296
+ if (globalPiCheck.status === "current" && !options.force) {
297
+ if (shouldUpdatePix)
298
+ console.log("Updated Pix and verified the matching global Pi CLI. Restart any running pix/pi sessions.");
299
+ return 0;
300
+ }
301
+ if (!globalPiCheck.targetVersion) {
302
+ console.error(`Cannot update global Pi: ${globalPiCheck.reason ?? "Pix's pinned Pi version is unavailable"}`);
303
+ return 1;
304
+ }
305
+ const piCommand = getGlobalPiUpdateCommand(globalPiCheck.targetVersion, check.packageRoot);
306
+ if (!piCommand) {
307
+ console.error(`Cannot update global Pi for this Pix installation. ${sourceCheckoutUpdateHint()}`);
196
308
  return 1;
197
309
  }
198
- console.log(`Updating Pix with ${command.display}...`);
310
+ console.log(`Updating global Pi with ${piCommand.display}...`);
199
311
  try {
200
- await pixUpdateDeps.runCommand(command);
201
- console.log("Updated Pix. Restart any running pix sessions.");
312
+ await pixUpdateDeps.runCommand(piCommand);
313
+ const successMessage = shouldUpdatePix ? "Updated Pix and global Pi." : "Updated global Pi to match Pix.";
314
+ console.log(`${successMessage} Restart any running pix/pi sessions.`);
202
315
  return 0;
203
316
  }
204
317
  catch (error) {
205
- console.error(`Pix update failed: ${error instanceof Error ? error.message : String(error)}`);
206
- console.error(`Try running manually: ${command.display}`);
318
+ const failureContext = shouldUpdatePix ? " after Pix update" : "";
319
+ console.error(`Global Pi update failed${failureContext}: ${error instanceof Error ? error.message : String(error)}`);
320
+ console.error(`Try running manually: ${piCommand.display}`);
207
321
  return 1;
208
322
  }
209
323
  }
@@ -211,8 +325,7 @@ function readPixPackageInfo(packageRoot = findPixPackageRoot()) {
211
325
  return readPackageInfo(packageRoot, "pi-ui-extend");
212
326
  }
213
327
  function readPackageInfo(packageRoot, fallbackName) {
214
- const packageJsonPath = join(packageRoot, "package.json");
215
- const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
328
+ const raw = readPackageJson(packageRoot);
216
329
  const name = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : fallbackName;
217
330
  const version = typeof raw.version === "string" && raw.version.trim() ? raw.version.trim() : "0.0.0";
218
331
  return {
@@ -222,6 +335,21 @@ function readPackageInfo(packageRoot, fallbackName) {
222
335
  packageRoot,
223
336
  };
224
337
  }
338
+ function readPackageJson(packageRoot) {
339
+ return JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
340
+ }
341
+ function isRecord(value) {
342
+ return typeof value === "object" && value !== null && !Array.isArray(value);
343
+ }
344
+ function getGlobalPiPackageRoot(pixPackageRoot) {
345
+ const normalized = pixPackageRoot.replace(/\\/g, "/");
346
+ const marker = "/node_modules/";
347
+ const markerIndex = normalized.toLowerCase().indexOf(marker);
348
+ if (markerIndex < 0)
349
+ return undefined;
350
+ const nodeModulesRoot = normalized.slice(0, markerIndex + marker.length - 1);
351
+ return join(nodeModulesRoot, ...PI_PACKAGE_NAME.split("/"));
352
+ }
225
353
  function findPixPackageRoot() {
226
354
  let currentDir = dirname(fileURLToPath(import.meta.url));
227
355
  while (true) {
@@ -328,6 +456,10 @@ function isNewerPackageVersion(candidateVersion, currentVersion) {
328
456
  return comparison > 0;
329
457
  return candidateVersion.trim() !== currentVersion.trim();
330
458
  }
459
+ function packageVersionsEqual(leftVersion, rightVersion) {
460
+ const comparison = comparePackageVersions(leftVersion, rightVersion);
461
+ return comparison === undefined ? leftVersion.trim() === rightVersion.trim() : comparison === 0;
462
+ }
331
463
  function comparePackageVersions(leftVersion, rightVersion) {
332
464
  const left = parsePackageVersion(leftVersion);
333
465
  const right = parsePackageVersion(rightVersion);
@@ -141,7 +141,7 @@ export function createSlashCommands(actions, host) {
141
141
  },
142
142
  {
143
143
  name: "update",
144
- description: "Check for Pix package updates",
144
+ description: "Check Pix and global Pi updates",
145
145
  kind: "builtin",
146
146
  keywords: ["upgrade", "version", "release", "external"],
147
147
  allowArguments: true,
@@ -8,7 +8,7 @@ import { createId } from "../id.js";
8
8
  import { runProcess } from "../process.js";
9
9
  import { copyTextToClipboard } from "../screen/clipboard.js";
10
10
  import { formatAccountUsageReport, queryAccountUsageReport } from "../model/model-usage-status.js";
11
- import { checkPixUpdate, formatPixUpdateCheck, parsePixUpdateArgs, pixUpdateUsage } from "../cli/update.js";
11
+ import { checkGlobalPiInstall, checkPixUpdate, formatGlobalPiCheck, formatPixUpdateCheck, parsePixUpdateArgs, pixUpdateUsage, } from "../cli/update.js";
12
12
  import { createStartupInfoMessage } from "../cli/startup-info.js";
13
13
  import { getCompleteSessionStats } from "../session/session-stats.js";
14
14
  import { loadSessionTitleConfig } from "../../bundled-extensions/session-title/config.js";
@@ -223,13 +223,18 @@ export class SessionCommandActions {
223
223
  this.host.setStatus("checking updates");
224
224
  this.host.render();
225
225
  const result = await checkPixUpdate();
226
+ const globalPiResult = checkGlobalPiInstall(result.packageRoot);
226
227
  const forceHint = options.force ? "\n\n/update is check-only. To force a reinstall, run `pix update --force` in your shell and restart Pix." : "";
227
- this.host.addEntry({ id: createId("system"), kind: "system", text: `${formatPixUpdateCheck(result)}${forceHint}` });
228
+ this.host.addEntry({
229
+ id: createId("system"),
230
+ kind: "system",
231
+ text: `${formatPixUpdateCheck(result)}\n\n${formatGlobalPiCheck(globalPiResult)}${forceHint}`,
232
+ });
228
233
  this.host.setSessionStatus(runtime.session);
229
- if (result.status === "newer")
230
- this.host.toast.info("Pix update available");
231
- else if (result.status === "current")
232
- this.host.toast.success("Pix is up to date");
234
+ if (result.status === "newer" || globalPiResult.status === "mismatched" || globalPiResult.status === "missing")
235
+ this.host.toast.info("Pix or global Pi update available");
236
+ else if (result.status === "current" && globalPiResult.status === "current")
237
+ this.host.toast.success("Pix and global Pi are up to date");
233
238
  else
234
239
  this.host.toast.warning("Pix update check incomplete");
235
240
  }
@@ -1,7 +1,7 @@
1
1
  import type { ResolvedToolRule } from "../config.js";
2
2
  export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
3
3
  export declare const THINKING_MENU_MAX_ROWS: number;
4
- export declare const PI_FAVORITE_MODEL_REFS: readonly ["amazon-bedrock/us.anthropic.claude-opus-4-6-v1", "anthropic/claude-opus-4-8", "openai/gpt-5.4", "azure-openai-responses/gpt-5.4", "openai-codex/gpt-5.6-sol", "deepseek/deepseek-v4-pro", "google/gemini-3.1-pro-preview", "google-vertex/gemini-3.1-pro-preview", "github-copilot/gpt-5.4", "openrouter/moonshotai/kimi-k2.6", "vercel-ai-gateway/zai/glm-5.2", "xai/grok-4.20-0309-reasoning", "groq/openai/gpt-oss-120b", "cerebras/zai-glm-4.7", "zai/glm-5.2", "mistral/devstral-medium-latest", "minimax/MiniMax-M2.7", "minimax-cn/MiniMax-M2.7", "moonshotai/kimi-k2.6", "moonshotai-cn/kimi-k2.6", "huggingface/moonshotai/Kimi-K2.6", "fireworks/accounts/fireworks/models/kimi-k2p6", "together/moonshotai/Kimi-K2.6", "opencode/kimi-k2.6", "opencode-go/kimi-k2.6", "kimi-coding/kimi-for-coding", "cloudflare-workers-ai/@cf/moonshotai/kimi-k2.6", "cloudflare-ai-gateway/workers-ai/@cf/moonshotai/kimi-k2.6", "xiaomi/mimo-v2.5-pro", "xiaomi-token-plan-cn/mimo-v2.5-pro", "xiaomi-token-plan-ams/mimo-v2.5-pro", "xiaomi-token-plan-sgp/mimo-v2.5-pro"];
4
+ export declare const PI_FAVORITE_MODEL_REFS: readonly ["amazon-bedrock/us.anthropic.claude-opus-4-6-v1", "anthropic/claude-opus-4-8", "openai/gpt-5.4", "azure-openai-responses/gpt-5.4", "openai-codex/gpt-5.6-sol", "deepseek/deepseek-v4-pro", "google/gemini-3.1-pro-preview", "google-vertex/gemini-3.1-pro-preview", "github-copilot/gpt-5.4", "openrouter/moonshotai/kimi-k2.6", "vercel-ai-gateway/zai/glm-5.2", "xai/grok-4.5", "groq/openai/gpt-oss-120b", "cerebras/zai-glm-4.7", "zai/glm-5.2", "mistral/devstral-medium-latest", "minimax/MiniMax-M2.7", "minimax-cn/MiniMax-M2.7", "moonshotai/kimi-k2.6", "moonshotai-cn/kimi-k2.6", "huggingface/moonshotai/Kimi-K2.6", "fireworks/accounts/fireworks/models/kimi-k2p6", "together/moonshotai/Kimi-K2.6", "opencode/kimi-k2.6", "opencode-go/kimi-k2.6", "kimi-coding/kimi-for-coding", "cloudflare-workers-ai/@cf/moonshotai/kimi-k2.6", "cloudflare-ai-gateway/workers-ai/@cf/moonshotai/kimi-k2.6", "xiaomi/mimo-v2.5-pro", "xiaomi-token-plan-cn/mimo-v2.5-pro", "xiaomi-token-plan-ams/mimo-v2.5-pro", "xiaomi-token-plan-sgp/mimo-v2.5-pro"];
5
5
  export declare const SLASH_COMMAND_MENU_MAX_ROWS = 6;
6
6
  export declare const RESUME_MENU_MAX_ROWS = 20;
7
7
  export declare const RESUME_MENU_INITIAL_SESSION_ROWS = 30;
@@ -13,7 +13,7 @@ export const PI_FAVORITE_MODEL_REFS = [
13
13
  "github-copilot/gpt-5.4",
14
14
  "openrouter/moonshotai/kimi-k2.6",
15
15
  "vercel-ai-gateway/zai/glm-5.2",
16
- "xai/grok-4.20-0309-reasoning",
16
+ "xai/grok-4.5",
17
17
  "groq/openai/gpt-oss-120b",
18
18
  "cerebras/zai-glm-4.7",
19
19
  "zai/glm-5.2",
package/docs/release.md CHANGED
@@ -72,10 +72,12 @@ Some modules have optional runtime dependencies or host services:
72
72
 
73
73
  ## Update UX
74
74
 
75
- - `/update` inside Pix performs a non-mutating npm latest-version check and tells the user what to run.
76
- - `pix update --check` performs the same check without a TTY.
77
- - `pix update` updates package-manager installs of Pix and therefore also updates the `external/pi-tools-suite` payload. The next Pix startup refreshes the user extension link.
75
+ - `/update` inside Pix performs a non-mutating Pix update check and reports whether the global Pi package in the same package-manager prefix matches Pix's pinned Pi SDK version.
76
+ - `pix update --check` performs the same compatibility check without a TTY and never mutates either package.
77
+ - `pix update` first updates a package-manager installation of Pix when needed, then installs the global `@earendil-works/pi-coding-agent` at the exact version pinned by the resulting Pix package. This keeps the shared `pi-tools-suite` host ABI aligned. The next Pix startup refreshes the user extension link.
78
+ - `pix update --force` reinstalls both Pix and its matching global Pi version.
79
+ - If the Pix update fails, Pi is not changed. If Pix is updated successfully (or is already current) but the Pi install fails, the command exits unsuccessfully and prints the exact Pi install command for recovery.
78
80
  - Source checkouts are intentionally not self-mutated; update them with `git pull`, `npm install --ignore-scripts`, `npm run build:pix`, and `npm run link:pix`.
79
- - Separately installed Pi packages are updated by Pi itself with `pi update --extensions` or `pi update`.
81
+ - A `pi` executable installed under a different package-manager prefix is outside `pix update`'s scope and must be updated separately.
80
82
 
81
83
  Update checks respect `PI_OFFLINE=1`, `PI_SKIP_VERSION_CHECK=1`, and `PIX_SKIP_VERSION_CHECK=1`.
@@ -43,9 +43,9 @@
43
43
  "vscode-languageserver-protocol": "^3.17.5"
44
44
  },
45
45
  "peerDependencies": {
46
- "@earendil-works/pi-ai": "0.80.9",
47
- "@earendil-works/pi-coding-agent": "0.80.9",
48
- "@earendil-works/pi-tui": "0.80.9",
46
+ "@earendil-works/pi-ai": "0.80.10",
47
+ "@earendil-works/pi-coding-agent": "0.80.10",
48
+ "@earendil-works/pi-tui": "0.80.10",
49
49
  "typebox": "*"
50
50
  },
51
51
  "devDependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ui-extend",
3
- "version": "0.1.63",
3
+ "version": "0.1.65",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -65,9 +65,9 @@
65
65
  "prepublishOnly": "npm run check && npm run build:pix && npm run generate-schemas"
66
66
  },
67
67
  "dependencies": {
68
- "@earendil-works/pi-ai": "0.80.9",
69
- "@earendil-works/pi-coding-agent": "0.80.9",
70
- "@earendil-works/pi-tui": "0.80.9",
68
+ "@earendil-works/pi-ai": "0.80.10",
69
+ "@earendil-works/pi-coding-agent": "0.80.10",
70
+ "@earendil-works/pi-tui": "0.80.10",
71
71
  "@mariozechner/clipboard": "^0.3.9",
72
72
  "jsonc-parser": "3.3.1",
73
73
  "typebox": "1.1.38",