pi-extmgr 0.1.14 → 0.1.16

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
@@ -1,12 +1,14 @@
1
1
  # pi-extmgr
2
2
 
3
- ![pi-extmgr banner](https://i.imgur.com/bVM7ZcO.png)
3
+ ![pi-extmgr banner](https://i.imgur.com/Ce513Br.png)
4
4
 
5
5
  [![CI](https://github.com/ayagmar/pi-extmgr/actions/workflows/ci.yml/badge.svg)](https://github.com/ayagmar/pi-extmgr/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
8
  A better way to manage Pi extensions. Browse, install, enable/disable, and remove extensions from one place.
9
9
 
10
+ **🌐 [pi-extmgr landing page](https://ayagmar.github.io/pi-extmgr)**
11
+
10
12
  ## Install
11
13
 
12
14
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-extmgr",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Enhanced UX for managing local Pi extensions and community packages",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -35,7 +35,7 @@
35
35
  "./src/index.ts"
36
36
  ],
37
37
  "video": "https://github.com/ayagmar/pi-extmgr/releases/download/demo/demo.mp4",
38
- "image": "https://i.imgur.com/bVM7ZcO.png"
38
+ "image": "https://i.imgur.com/Ce513Br.png"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@mariozechner/pi-coding-agent": "*",
@@ -66,5 +66,5 @@
66
66
  "bugs": {
67
67
  "url": "https://github.com/ayagmar/pi-extmgr/issues"
68
68
  },
69
- "homepage": "https://github.com/ayagmar/pi-extmgr/blob/master/README.md"
69
+ "homepage": "https://ayagmar.github.io/pi-extmgr"
70
70
  }
@@ -8,6 +8,7 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@mariozechner/pi-cod
8
8
  import { normalizePackageSource } from "../utils/format.js";
9
9
  import { clearSearchCache } from "./discovery.js";
10
10
  import { logPackageInstall } from "../utils/history.js";
11
+ import { clearUpdatesAvailable } from "../utils/settings.js";
11
12
  import { notify, error as notifyError, success } from "../utils/notify.js";
12
13
  import { confirmAction, confirmReload, showProgress } from "../utils/ui-helpers.js";
13
14
  import { tryOperation } from "../utils/mode.js";
@@ -126,6 +127,7 @@ export async function installPackage(
126
127
  clearSearchCache();
127
128
  logPackageInstall(pi, normalized, normalized, undefined, scope, true);
128
129
  success(ctx, `Installed ${normalized} (${scope})`);
130
+ clearUpdatesAvailable(pi, ctx);
129
131
 
130
132
  void updateExtmgrStatus(ctx, pi);
131
133
  await confirmReload(ctx, "Package installed.");
@@ -186,6 +188,7 @@ export async function installFromUrl(
186
188
  const { fileName: name, destPath } = result;
187
189
  logPackageInstall(pi, url, name, undefined, scope, true);
188
190
  success(ctx, `Installed ${name} to:\n${destPath}`);
191
+ clearUpdatesAvailable(pi, ctx);
189
192
  void updateExtmgrStatus(ctx, pi);
190
193
  await confirmReload(ctx, "Extension installed.");
191
194
  }
@@ -401,6 +404,7 @@ export async function installPackageLocally(
401
404
  clearSearchCache();
402
405
  logPackageInstall(pi, `npm:${packageName}`, packageName, version, scope, true);
403
406
  success(ctx, `Installed ${packageName}@${version} locally to:\n${destResult}/index.ts`);
407
+ clearUpdatesAvailable(pi, ctx);
404
408
  void updateExtmgrStatus(ctx, pi);
405
409
  await confirmReload(ctx, "Extension installed.");
406
410
  }
@@ -11,6 +11,7 @@ import {
11
11
  import { formatInstalledPackageLabel, formatBytes, parseNpmSource } from "../utils/format.js";
12
12
  import { getPackageSourceKind, splitGitRepoAndRef } from "../utils/package-source.js";
13
13
  import { logPackageUpdate, logPackageRemove } from "../utils/history.js";
14
+ import { clearUpdatesAvailable } from "../utils/settings.js";
14
15
  import { notify, error as notifyError, success } from "../utils/notify.js";
15
16
  import {
16
17
  confirmAction,
@@ -69,6 +70,7 @@ async function updatePackageInternal(
69
70
 
70
71
  logPackageUpdate(pi, source, source, undefined, true);
71
72
  success(ctx, `Updated ${source}`);
73
+ clearUpdatesAvailable(pi, ctx);
72
74
  void updateExtmgrStatus(ctx, pi);
73
75
 
74
76
  const reloaded = await confirmReload(ctx, "Package updated.");
@@ -97,6 +99,7 @@ async function updatePackagesInternal(
97
99
  }
98
100
 
99
101
  success(ctx, "Packages updated");
102
+ clearUpdatesAvailable(pi, ctx);
100
103
  void updateExtmgrStatus(ctx, pi);
101
104
 
102
105
  const reloaded = await confirmReload(ctx, "Packages updated.");
@@ -328,6 +331,9 @@ async function removePackageInternal(
328
331
  );
329
332
  notifyRemovalSummary(source, remaining, failures, ctx);
330
333
 
334
+ if (failures.length === 0) {
335
+ clearUpdatesAvailable(pi, ctx);
336
+ }
331
337
  void updateExtmgrStatus(ctx, pi);
332
338
 
333
339
  const restartRequested = await confirmRestart(
@@ -265,6 +265,23 @@ export function saveAutoUpdateConfig(pi: ExtensionAPI, config: Partial<AutoUpdat
265
265
  enqueueConfigWrite(fullConfig);
266
266
  }
267
267
 
268
+ /**
269
+ * Clear the updates available list after package mutations.
270
+ * Call this after install/update/remove to prevent stale update notifications.
271
+ */
272
+ export function clearUpdatesAvailable(
273
+ pi: ExtensionAPI,
274
+ ctx: ExtensionCommandContext | ExtensionContext
275
+ ): void {
276
+ const config = getAutoUpdateConfig(ctx);
277
+ if (config.updatesAvailable && config.updatesAvailable.length > 0) {
278
+ saveAutoUpdateConfig(pi, {
279
+ ...config,
280
+ updatesAvailable: [],
281
+ });
282
+ }
283
+ }
284
+
268
285
  /**
269
286
  * Parse duration string to milliseconds
270
287
  * Supports: 1h, 2h, 1d, 7d, 1m, 3m, etc.
@@ -8,7 +8,15 @@ import type {
8
8
  } from "@mariozechner/pi-coding-agent";
9
9
  import { getInstalledPackages } from "../packages/discovery.js";
10
10
  import { getAutoUpdateStatus } from "./auto-update.js";
11
- import { getAutoUpdateConfigAsync } from "./settings.js";
11
+ import { getAutoUpdateConfigAsync, saveAutoUpdateConfig } from "./settings.js";
12
+
13
+ function filterStaleUpdates(
14
+ knownUpdates: string[],
15
+ installedPackages: Awaited<ReturnType<typeof getInstalledPackages>>
16
+ ): string[] {
17
+ const installedNames = new Set(installedPackages.map((p) => p.name));
18
+ return knownUpdates.filter((name) => installedNames.has(name));
19
+ }
12
20
 
13
21
  export async function updateExtmgrStatus(
14
22
  ctx: ExtensionCommandContext | ExtensionContext,
@@ -32,9 +40,20 @@ export async function updateExtmgrStatus(
32
40
  statusParts.push(autoUpdateStatus);
33
41
  }
34
42
 
43
+ // Validate updates against actually installed packages (handles external pi update)
35
44
  const knownUpdates = autoUpdateConfig.updatesAvailable ?? [];
36
- if (knownUpdates.length > 0) {
37
- statusParts.push(`${knownUpdates.length} update${knownUpdates.length === 1 ? "" : "s"}`);
45
+ const validUpdates = filterStaleUpdates(knownUpdates, packages);
46
+
47
+ // If stale updates were filtered, persist the correction
48
+ if (validUpdates.length !== knownUpdates.length) {
49
+ saveAutoUpdateConfig(pi, {
50
+ ...autoUpdateConfig,
51
+ updatesAvailable: validUpdates,
52
+ });
53
+ }
54
+
55
+ if (validUpdates.length > 0) {
56
+ statusParts.push(`${validUpdates.length} update${validUpdates.length === 1 ? "" : "s"}`);
38
57
  }
39
58
 
40
59
  if (statusParts.length > 0) {