pi-ui-extend 0.1.64 → 0.1.66
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 +5 -4
- package/dist/app/cli/update.d.ts +12 -0
- package/dist/app/cli/update.js +151 -19
- package/dist/app/commands/command-registry.js +1 -1
- package/dist/app/commands/command-session-actions.js +11 -6
- package/docs/release.md +6 -4
- package/external/pi-tools-suite/src/config.ts +0 -43
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +0 -5
- package/external/pi-tools-suite/src/index.ts +0 -1
- package/package.json +1 -1
- package/external/pi-tools-suite/src/telegram-mirror/README.md +0 -203
- package/external/pi-tools-suite/src/telegram-mirror/bot.ts +0 -299
- package/external/pi-tools-suite/src/telegram-mirror/events.ts +0 -67
- package/external/pi-tools-suite/src/telegram-mirror/format.ts +0 -120
- package/external/pi-tools-suite/src/telegram-mirror/index.ts +0 -669
- package/external/pi-tools-suite/src/telegram-mirror/ipc.ts +0 -440
- package/external/pi-tools-suite/src/telegram-mirror/multiplexer.ts +0 -638
- package/external/pi-tools-suite/src/telegram-mirror/renderer.ts +0 -211
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
|
|
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,
|
|
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
|
-
|
|
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
|
package/dist/app/cli/update.d.ts
CHANGED
|
@@ -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 {};
|
package/dist/app/cli/update.js
CHANGED
|
@@ -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
|
|
24
|
-
--force Reinstall
|
|
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
|
-
"
|
|
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 =
|
|
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
|
|
194
|
-
if (
|
|
195
|
-
|
|
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
|
|
310
|
+
console.log(`Updating global Pi with ${piCommand.display}...`);
|
|
199
311
|
try {
|
|
200
|
-
await pixUpdateDeps.runCommand(
|
|
201
|
-
|
|
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
|
-
|
|
206
|
-
console.error(`
|
|
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
|
|
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
|
|
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({
|
|
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
|
|
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
|
}
|
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
|
|
76
|
-
- `pix update --check` performs the same check without a TTY.
|
|
77
|
-
- `pix update` updates package-manager
|
|
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
|
-
-
|
|
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`.
|
|
@@ -5,19 +5,12 @@ import { parse as parseJsonc } from "jsonc-parser";
|
|
|
5
5
|
|
|
6
6
|
import { DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC } from "./default-pi-tools-suite-config.js";
|
|
7
7
|
|
|
8
|
-
export interface TelegramMirrorConfig {
|
|
9
|
-
enabled: boolean;
|
|
10
|
-
botToken: string;
|
|
11
|
-
chatId: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
8
|
export interface PiToolsSuiteConfig {
|
|
15
9
|
enabled: boolean;
|
|
16
10
|
disabledModules: string[];
|
|
17
11
|
todoThinking: boolean;
|
|
18
12
|
/** Vision-capable model used by the coding-discipline lookup tool; unset disables lookup. */
|
|
19
13
|
lookupModel?: string;
|
|
20
|
-
telegramMirror?: TelegramMirrorConfig;
|
|
21
14
|
}
|
|
22
15
|
|
|
23
16
|
type MutableConfig = {
|
|
@@ -25,7 +18,6 @@ type MutableConfig = {
|
|
|
25
18
|
disabledModules: Set<string>;
|
|
26
19
|
todoThinking: boolean;
|
|
27
20
|
lookupModel: string | undefined;
|
|
28
|
-
telegramMirror: TelegramMirrorConfig | undefined;
|
|
29
21
|
};
|
|
30
22
|
|
|
31
23
|
type Env = Record<string, string | undefined>;
|
|
@@ -70,27 +62,6 @@ function normalizeLookupModel(raw: unknown): string | undefined {
|
|
|
70
62
|
return trimmed ? trimmed : undefined;
|
|
71
63
|
}
|
|
72
64
|
|
|
73
|
-
function normalizeTelegramMirror(raw: unknown): TelegramMirrorConfig | undefined {
|
|
74
|
-
if (!isRecord(raw)) return undefined;
|
|
75
|
-
const botToken = typeof raw.botToken === "string" ? raw.botToken.trim() : "";
|
|
76
|
-
if (!botToken) return undefined;
|
|
77
|
-
|
|
78
|
-
let chatId: number | undefined;
|
|
79
|
-
if (typeof raw.chatId === "number" && Number.isFinite(raw.chatId) && Number.isInteger(raw.chatId)) {
|
|
80
|
-
chatId = raw.chatId;
|
|
81
|
-
} else if (typeof raw.chatId === "string") {
|
|
82
|
-
const trimmed = raw.chatId.trim();
|
|
83
|
-
if (/^-?\d+$/.test(trimmed)) {
|
|
84
|
-
const parsed = Number(trimmed);
|
|
85
|
-
if (Number.isFinite(parsed) && Number.isInteger(parsed)) chatId = parsed;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (chatId === undefined) return undefined;
|
|
89
|
-
|
|
90
|
-
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : true;
|
|
91
|
-
return { enabled, botToken, chatId };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
65
|
function boolFromEnv(value: string | undefined): boolean | undefined {
|
|
95
66
|
if (value === undefined) return undefined;
|
|
96
67
|
const normalized = value.trim().toLowerCase();
|
|
@@ -165,9 +136,6 @@ function mergeConfigLayer(config: MutableConfig, raw: Record<string, unknown>, k
|
|
|
165
136
|
}
|
|
166
137
|
}
|
|
167
138
|
|
|
168
|
-
const telegramMirror = normalizeTelegramMirror(raw.telegramMirror);
|
|
169
|
-
if (telegramMirror) config.telegramMirror = telegramMirror;
|
|
170
|
-
|
|
171
139
|
return config;
|
|
172
140
|
}
|
|
173
141
|
|
|
@@ -210,7 +178,6 @@ export function loadPiToolsSuiteConfig(moduleNames: readonly string[], options:
|
|
|
210
178
|
disabledModules: new Set([...DEFAULT_DISABLED_MODULES].filter((name) => knownModules.has(name))),
|
|
211
179
|
todoThinking: false,
|
|
212
180
|
lookupModel: undefined,
|
|
213
|
-
telegramMirror: undefined,
|
|
214
181
|
};
|
|
215
182
|
const userConfigPath = getPiToolsSuiteUserConfigPath(options.homeDir);
|
|
216
183
|
|
|
@@ -230,15 +197,5 @@ export function loadPiToolsSuiteConfig(moduleNames: readonly string[], options:
|
|
|
230
197
|
disabledModules: [...config.disabledModules].sort(),
|
|
231
198
|
todoThinking: config.todoThinking,
|
|
232
199
|
...(config.lookupModel ? { lookupModel: config.lookupModel } : {}),
|
|
233
|
-
...(config.telegramMirror ? { telegramMirror: config.telegramMirror } : {}),
|
|
234
200
|
};
|
|
235
201
|
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Load only the telegram-mirror section from the pi-tools-suite config layers.
|
|
239
|
-
* Returns undefined when the section is missing or invalid (botToken empty /
|
|
240
|
-
* chatId non-integer).
|
|
241
|
-
*/
|
|
242
|
-
export function loadTelegramMirrorConfig(options: { cwd?: string; env?: Env; homeDir?: string } = {}): TelegramMirrorConfig | undefined {
|
|
243
|
-
return loadPiToolsSuiteConfig([], options).telegramMirror;
|
|
244
|
-
}
|
|
@@ -22,11 +22,6 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
|
|
|
22
22
|
// "balanced" — + restate-code + generic-explanation (default);
|
|
23
23
|
// "aggressive" — any non-valuable net-new comment.
|
|
24
24
|
"commentChecker": { "enabled": true, "strictness": "balanced" },
|
|
25
|
-
// "telegramMirror": {
|
|
26
|
-
// "enabled": true,
|
|
27
|
-
// "botToken": "123456789:ABCdef...",
|
|
28
|
-
// "chatId": 123456789
|
|
29
|
-
// },
|
|
30
25
|
"dcp": {
|
|
31
26
|
"enabled": true,
|
|
32
27
|
// Write a JSONL debug log of DCP context/prune/compress events to
|
|
@@ -26,7 +26,6 @@ export const MODULES: Array<{ name: string; load: () => Promise<ExtensionModule>
|
|
|
26
26
|
{ name: "dcp", load: () => import("./dcp/index") },
|
|
27
27
|
{ name: "prompt-commands", load: () => import("./prompt-commands/index") },
|
|
28
28
|
{ name: "skill-installer", load: () => import("./skill-installer/index") },
|
|
29
|
-
{ name: "telegram-mirror", load: () => import("./telegram-mirror/index") },
|
|
30
29
|
// Keep this last: its before_provider_request handler is the final payload
|
|
31
30
|
// sanitizer after DCP and any other provider-payload modifiers.
|
|
32
31
|
{ name: "codex-reasoning-fix", load: () => import("./codex-reasoning-fix/index") },
|