pi-extmgr 0.1.27 → 0.1.28
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 +4 -3
- package/package.json +13 -16
- package/src/commands/auto-update.ts +4 -4
- package/src/commands/cache.ts +1 -1
- package/src/commands/history.ts +3 -3
- package/src/commands/install.ts +2 -2
- package/src/commands/registry.ts +7 -7
- package/src/commands/types.ts +1 -1
- package/src/extensions/discovery.ts +4 -3
- package/src/index.ts +15 -15
- package/src/packages/catalog.ts +9 -8
- package/src/packages/discovery.ts +22 -19
- package/src/packages/extensions.ts +10 -5
- package/src/packages/install.ts +19 -18
- package/src/packages/management.ts +53 -27
- package/src/types/index.ts +16 -9
- package/src/ui/async-task.ts +101 -65
- package/src/ui/footer.ts +4 -8
- package/src/ui/help.ts +2 -2
- package/src/ui/package-config.ts +36 -48
- package/src/ui/remote.ts +14 -11
- package/src/ui/theme.ts +2 -2
- package/src/ui/unified.ts +64 -82
- package/src/utils/auto-update.ts +10 -10
- package/src/utils/cache.ts +3 -3
- package/src/utils/command.ts +1 -1
- package/src/utils/format.ts +4 -3
- package/src/utils/history.ts +4 -2
- package/src/utils/mode.ts +1 -1
- package/src/utils/notify.ts +1 -1
- package/src/utils/npm-exec.ts +1 -1
- package/src/utils/package-source.ts +33 -2
- package/src/utils/retry.ts +1 -1
- package/src/utils/settings.ts +17 -8
- package/src/utils/status.ts +12 -10
- package/src/utils/ui-helpers.ts +2 -2
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
[](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
|
+
Built on top of Pi's native package install, update, and config flows, so extmgr stays aligned with current upstream behavior.
|
|
9
10
|
|
|
10
11
|
**🌐 [pi-extmgr landing page](https://ayagmar.github.io/pi-extmgr)**
|
|
11
12
|
|
|
@@ -15,9 +16,9 @@ A better way to manage Pi extensions. Browse, install, enable/disable, and remov
|
|
|
15
16
|
pi install npm:pi-extmgr
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
If Pi is already running, use `/reload`.
|
|
19
20
|
|
|
20
|
-
Requires Node.js `>=22
|
|
21
|
+
Requires Node.js `>=22`.
|
|
21
22
|
|
|
22
23
|
## Features
|
|
23
24
|
|
|
@@ -155,7 +156,7 @@ Examples:
|
|
|
155
156
|
|
|
156
157
|
- **Staged local changes**: Toggle local extensions on/off, then press `S` to apply all at once.
|
|
157
158
|
- **Package extension config**: Select a package and press `c` (or Enter/A → Configure) to enable/disable individual package entrypoints.
|
|
158
|
-
- After saving package extension config,
|
|
159
|
+
- After saving package extension config, run /reload to apply changes.
|
|
159
160
|
- **Two install modes**:
|
|
160
161
|
- **Managed** (npm): Auto-updates with `pi update`, stored in pi's package cache, supports Pi package manifest/convention loading
|
|
161
162
|
- **Local** (standalone): Copies to `~/.pi/agent/extensions/{package}/`, so it only accepts runnable standalone layouts (manifest-declared/root entrypoints), requires `tar` on `PATH`, and rejects packages whose runtime `dependencies` are not already bundled with the package contents
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extmgr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"description": "Enhanced UX for managing local Pi extensions and community packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
-
"lint": "
|
|
23
|
-
"lint:fix": "
|
|
24
|
-
"format": "
|
|
25
|
-
"format:check": "
|
|
22
|
+
"lint": "biome lint . --error-on-warnings",
|
|
23
|
+
"lint:fix": "biome check --write .",
|
|
24
|
+
"format": "biome format --write .",
|
|
25
|
+
"format:check": "biome format .",
|
|
26
26
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
27
27
|
"smoke-test": "node --import=tsx ./scripts/smoke-test.mjs",
|
|
28
28
|
"test": "node --import=tsx --test ./test/*.test.ts",
|
|
29
|
-
"check": "
|
|
29
|
+
"check": "tsc --noEmit -p tsconfig.json && node --import=tsx ./scripts/smoke-test.mjs && node --import=tsx --test ./test/*.test.ts && pnpm run lint && pnpm run format:check",
|
|
30
30
|
"prepublishOnly": "pnpm run check",
|
|
31
31
|
"prepare": "husky"
|
|
32
32
|
},
|
|
@@ -42,22 +42,19 @@
|
|
|
42
42
|
"@mariozechner/pi-tui": "*"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"@mariozechner/pi-
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"@typescript-eslint/parser": "^8.42.0",
|
|
50
|
-
"eslint": "^9.38.0",
|
|
51
|
-
"eslint-config-prettier": "^10.1.8",
|
|
45
|
+
"@biomejs/biome": "^2.4.9",
|
|
46
|
+
"@mariozechner/pi-coding-agent": "^0.63.1",
|
|
47
|
+
"@mariozechner/pi-tui": "^0.63.1",
|
|
48
|
+
"@types/node": "^22.19.10",
|
|
52
49
|
"husky": "^9.1.7",
|
|
53
|
-
"
|
|
54
|
-
"tsx": "^4.19.3",
|
|
50
|
+
"tsx": "^4.21.0",
|
|
55
51
|
"typescript": "^5.9.3"
|
|
56
52
|
},
|
|
57
53
|
"author": "ayagmar",
|
|
58
54
|
"license": "MIT",
|
|
55
|
+
"packageManager": "pnpm@10.33.0",
|
|
59
56
|
"engines": {
|
|
60
|
-
"node": ">=22
|
|
57
|
+
"node": ">=22"
|
|
61
58
|
},
|
|
62
59
|
"repository": {
|
|
63
60
|
"type": "git",
|
package/src/commands/cache.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ExtensionAPI, type ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { clearSearchCache } from "../packages/discovery.js";
|
|
3
3
|
import { clearRemotePackageInfoCache } from "../ui/remote.js";
|
|
4
4
|
import { clearCache } from "../utils/cache.js";
|
package/src/commands/history.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ExtensionAPI, type ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import {
|
|
3
|
+
type ChangeAction,
|
|
3
4
|
formatChangeEntry,
|
|
5
|
+
type HistoryFilters,
|
|
4
6
|
queryGlobalHistory,
|
|
5
7
|
querySessionChanges,
|
|
6
|
-
type ChangeAction,
|
|
7
|
-
type HistoryFilters,
|
|
8
8
|
} from "../utils/history.js";
|
|
9
9
|
import { notify } from "../utils/notify.js";
|
|
10
10
|
import { formatListOutput } from "../utils/ui-helpers.js";
|
package/src/commands/install.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
1
|
+
import { type ExtensionAPI, type ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { type InstallScope, installPackage } from "../packages/install.js";
|
|
3
3
|
import { notify } from "../utils/notify.js";
|
|
4
4
|
|
|
5
5
|
export const INSTALL_USAGE = "Usage: /extensions install <source> [--project|--global]";
|
package/src/commands/registry.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
3
|
-
import { showInteractive, showInstalledPackagesLegacy, showListOnly } from "../ui/unified.js";
|
|
4
|
-
import { showRemote } from "../ui/remote.js";
|
|
1
|
+
import { type ExtensionAPI, type ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import { type AutocompleteItem } from "@mariozechner/pi-tui";
|
|
5
3
|
import {
|
|
6
4
|
promptRemove,
|
|
7
5
|
removePackage,
|
|
@@ -9,12 +7,14 @@ import {
|
|
|
9
7
|
updatePackage,
|
|
10
8
|
updatePackages,
|
|
11
9
|
} from "../packages/management.js";
|
|
10
|
+
import { showRemote } from "../ui/remote.js";
|
|
11
|
+
import { showInstalledPackagesLegacy, showInteractive, showListOnly } from "../ui/unified.js";
|
|
12
12
|
import { notify } from "../utils/notify.js";
|
|
13
|
-
import { handleInstallSubcommand, INSTALL_USAGE } from "./install.js";
|
|
14
|
-
import { handleHistorySubcommand } from "./history.js";
|
|
15
13
|
import { handleAutoUpdateSubcommand } from "./auto-update.js";
|
|
16
14
|
import { clearMetadataCacheCommand } from "./cache.js";
|
|
17
|
-
import
|
|
15
|
+
import { handleHistorySubcommand } from "./history.js";
|
|
16
|
+
import { handleInstallSubcommand, INSTALL_USAGE } from "./install.js";
|
|
17
|
+
import { type CommandDefinition, type CommandId } from "./types.js";
|
|
18
18
|
|
|
19
19
|
const REMOVE_USAGE = "Usage: /extensions remove <npm:package|git:url|path>";
|
|
20
20
|
|
package/src/commands/types.ts
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
* This module handles discovery and management of local Pi extensions
|
|
5
5
|
* in both global (~/.pi/agent/extensions) and project (.pi/extensions) scopes.
|
|
6
6
|
*/
|
|
7
|
+
|
|
8
|
+
import { type Dirent } from "node:fs";
|
|
7
9
|
import { readdir, rename, rm } from "node:fs/promises";
|
|
8
|
-
import { basename, dirname, join, relative } from "node:path";
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
|
-
import
|
|
11
|
-
import type { ExtensionEntry, Scope, State } from "../types/index.js";
|
|
11
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
12
12
|
import { DISABLED_SUFFIX } from "../constants.js";
|
|
13
|
+
import { type ExtensionEntry, type Scope, type State } from "../types/index.js";
|
|
13
14
|
import { fileExists, readSummary } from "../utils/fs.js";
|
|
14
15
|
|
|
15
16
|
interface RootConfig {
|
package/src/index.ts
CHANGED
|
@@ -3,21 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Entry point - exports the main extension function
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
ExtensionAPI,
|
|
8
|
-
ExtensionCommandContext,
|
|
9
|
-
ExtensionContext,
|
|
10
|
-
} from "@mariozechner/pi-coding-agent";
|
|
11
|
-
import { isPackageSource } from "./utils/format.js";
|
|
12
|
-
import { installPackage } from "./packages/install.js";
|
|
13
|
-
import { tokenizeArgs } from "./utils/command.js";
|
|
14
|
-
import { updateExtmgrStatus } from "./utils/status.js";
|
|
15
6
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type
|
|
19
|
-
} from "
|
|
20
|
-
import {
|
|
7
|
+
type ExtensionAPI,
|
|
8
|
+
type ExtensionCommandContext,
|
|
9
|
+
type ExtensionContext,
|
|
10
|
+
} from "@mariozechner/pi-coding-agent";
|
|
11
|
+
import { createAutoUpdateNotificationHandler } from "./commands/auto-update.js";
|
|
21
12
|
import {
|
|
22
13
|
getExtensionsAutocompleteItems,
|
|
23
14
|
resolveCommand,
|
|
@@ -25,7 +16,16 @@ import {
|
|
|
25
16
|
showNonInteractiveHelp,
|
|
26
17
|
showUnknownCommandMessage,
|
|
27
18
|
} from "./commands/registry.js";
|
|
28
|
-
import {
|
|
19
|
+
import { installPackage } from "./packages/install.js";
|
|
20
|
+
import {
|
|
21
|
+
type ContextProvider,
|
|
22
|
+
startAutoUpdateTimer,
|
|
23
|
+
stopAutoUpdateTimer,
|
|
24
|
+
} from "./utils/auto-update.js";
|
|
25
|
+
import { tokenizeArgs } from "./utils/command.js";
|
|
26
|
+
import { isPackageSource } from "./utils/format.js";
|
|
27
|
+
import { getAutoUpdateConfig, hydrateAutoUpdateConfig } from "./utils/settings.js";
|
|
28
|
+
import { updateExtmgrStatus } from "./utils/status.js";
|
|
29
29
|
|
|
30
30
|
async function executeExtensionsCommand(
|
|
31
31
|
args: string,
|
package/src/packages/catalog.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DefaultPackageManager,
|
|
3
3
|
getAgentDir,
|
|
4
|
-
SettingsManager,
|
|
5
4
|
type PackageSource,
|
|
6
5
|
type ProgressEvent,
|
|
6
|
+
SettingsManager,
|
|
7
7
|
} from "@mariozechner/pi-coding-agent";
|
|
8
|
-
import type
|
|
8
|
+
import { type InstalledPackage, type Scope } from "../types/index.js";
|
|
9
9
|
import { normalizePackageIdentity, parsePackageNameAndVersion } from "../utils/package-source.js";
|
|
10
10
|
|
|
11
11
|
type PiScope = "user" | "project";
|
|
@@ -57,14 +57,15 @@ function createPackageRecord(
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
function dedupeInstalledPackages(packages: InstalledPackage[]): InstalledPackage[] {
|
|
60
|
+
function dedupeInstalledPackages(packages: InstalledPackage[], cwd: string): InstalledPackage[] {
|
|
61
61
|
const byIdentity = new Map<string, InstalledPackage>();
|
|
62
62
|
|
|
63
63
|
for (const pkg of packages) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
pkg.resolvedPath ? { resolvedPath: pkg.resolvedPath } :
|
|
67
|
-
|
|
64
|
+
const baseCwd = pkg.scope === "project" ? cwd : getAgentDir();
|
|
65
|
+
const identity = normalizePackageIdentity(pkg.source, {
|
|
66
|
+
...(pkg.resolvedPath ? { resolvedPath: pkg.resolvedPath } : {}),
|
|
67
|
+
cwd: baseCwd,
|
|
68
|
+
});
|
|
68
69
|
|
|
69
70
|
if (!byIdentity.has(identity)) {
|
|
70
71
|
byIdentity.set(identity, pkg);
|
|
@@ -97,7 +98,7 @@ function createDefaultPackageCatalog(cwd: string): PackageCatalog {
|
|
|
97
98
|
|
|
98
99
|
const installed = [...projectPackages, ...globalPackages];
|
|
99
100
|
return Promise.resolve(
|
|
100
|
-
options?.dedupe === false ? installed : dedupeInstalledPackages(installed)
|
|
101
|
+
options?.dedupe === false ? installed : dedupeInstalledPackages(installed, cwd)
|
|
101
102
|
);
|
|
102
103
|
},
|
|
103
104
|
|
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import
|
|
7
|
-
ExtensionAPI,
|
|
8
|
-
ExtensionCommandContext,
|
|
9
|
-
ExtensionContext,
|
|
6
|
+
import {
|
|
7
|
+
type ExtensionAPI,
|
|
8
|
+
type ExtensionCommandContext,
|
|
9
|
+
type ExtensionContext,
|
|
10
|
+
getAgentDir,
|
|
10
11
|
} from "@mariozechner/pi-coding-agent";
|
|
11
|
-
import type { InstalledPackage, NpmPackage, SearchCache } from "../types/index.js";
|
|
12
12
|
import { CACHE_TTL, TIMEOUTS } from "../constants.js";
|
|
13
|
-
import {
|
|
13
|
+
import { type InstalledPackage, type NpmPackage, type SearchCache } from "../types/index.js";
|
|
14
14
|
import { parseNpmSource } from "../utils/format.js";
|
|
15
|
+
import { readSummary } from "../utils/fs.js";
|
|
16
|
+
import { fetchWithTimeout } from "../utils/network.js";
|
|
17
|
+
import { execNpm } from "../utils/npm-exec.js";
|
|
15
18
|
import { normalizePackageIdentity } from "../utils/package-source.js";
|
|
16
19
|
import { getPackageCatalog } from "./catalog.js";
|
|
17
|
-
import { execNpm } from "../utils/npm-exec.js";
|
|
18
|
-
import { fetchWithTimeout } from "../utils/network.js";
|
|
19
20
|
|
|
20
21
|
const NPM_SEARCH_API = "https://registry.npmjs.org/-/v1/search";
|
|
21
22
|
const NPM_SEARCH_PAGE_SIZE = 250;
|
|
@@ -69,13 +70,13 @@ export function isCacheValid(query: string): boolean {
|
|
|
69
70
|
|
|
70
71
|
// Import persistent cache
|
|
71
72
|
import {
|
|
72
|
-
getCachedSearch,
|
|
73
|
-
setCachedSearch,
|
|
74
73
|
getCachedPackage,
|
|
75
|
-
setCachedPackage,
|
|
76
|
-
getPackageDescriptions,
|
|
77
74
|
getCachedPackageSize,
|
|
75
|
+
getCachedSearch,
|
|
76
|
+
getPackageDescriptions,
|
|
77
|
+
setCachedPackage,
|
|
78
78
|
setCachedPackageSize,
|
|
79
|
+
setCachedSearch,
|
|
79
80
|
} from "../utils/cache.js";
|
|
80
81
|
|
|
81
82
|
function toNpmPackage(entry: NpmSearchResultObject): NpmPackage | undefined {
|
|
@@ -201,11 +202,13 @@ export async function getInstalledPackages(
|
|
|
201
202
|
return packages;
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
function getInstalledPackageIdentity(pkg: InstalledPackage): string {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
function getInstalledPackageIdentity(pkg: InstalledPackage, options?: { cwd?: string }): string {
|
|
206
|
+
const baseCwd = pkg.scope === "project" ? options?.cwd : getAgentDir();
|
|
207
|
+
|
|
208
|
+
return normalizePackageIdentity(pkg.source, {
|
|
209
|
+
...(pkg.resolvedPath ? { resolvedPath: pkg.resolvedPath } : {}),
|
|
210
|
+
...(baseCwd ? { cwd: baseCwd } : {}),
|
|
211
|
+
});
|
|
209
212
|
}
|
|
210
213
|
|
|
211
214
|
export async function isSourceInstalled(
|
|
@@ -214,10 +217,10 @@ export async function isSourceInstalled(
|
|
|
214
217
|
options?: { scope?: "global" | "project" }
|
|
215
218
|
): Promise<boolean> {
|
|
216
219
|
const installed = await getPackageCatalog(ctx.cwd).listInstalledPackages({ dedupe: false });
|
|
217
|
-
const expected = normalizePackageIdentity(source);
|
|
220
|
+
const expected = normalizePackageIdentity(source, { cwd: ctx.cwd });
|
|
218
221
|
|
|
219
222
|
return installed.some((pkg) => {
|
|
220
|
-
if (getInstalledPackageIdentity(pkg) !== expected) {
|
|
223
|
+
if (getInstalledPackageIdentity(pkg, { cwd: ctx.cwd }) !== expected) {
|
|
221
224
|
return false;
|
|
222
225
|
}
|
|
223
226
|
return options?.scope ? pkg.scope === options.scope : true;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { type Dirent } from "node:fs";
|
|
3
|
+
import { mkdir, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { homedir } from "node:os";
|
|
3
5
|
import { dirname, join, matchesGlob, relative, resolve } from "node:path";
|
|
4
6
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { homedir } from "node:os";
|
|
6
|
-
import { execFile } from "node:child_process";
|
|
7
7
|
import { promisify } from "node:util";
|
|
8
8
|
import { getAgentDir } from "@mariozechner/pi-coding-agent";
|
|
9
|
-
import
|
|
9
|
+
import {
|
|
10
|
+
type InstalledPackage,
|
|
11
|
+
type PackageExtensionEntry,
|
|
12
|
+
type Scope,
|
|
13
|
+
type State,
|
|
14
|
+
} from "../types/index.js";
|
|
10
15
|
import { parseNpmSource } from "../utils/format.js";
|
|
11
16
|
import { fileExists, readSummary } from "../utils/fs.js";
|
|
12
17
|
import { resolveNpmCommand } from "../utils/npm-exec.js";
|
package/src/packages/install.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Package installation logic
|
|
3
3
|
*/
|
|
4
|
-
import { mkdir, rm, writeFile
|
|
5
|
-
import { join } from "node:path";
|
|
4
|
+
import { cp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
6
5
|
import { homedir } from "node:os";
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import {
|
|
8
|
+
type ExtensionAPI,
|
|
9
|
+
type ExtensionCommandContext,
|
|
10
|
+
type ProgressEvent,
|
|
11
11
|
} from "@mariozechner/pi-coding-agent";
|
|
12
|
+
import { TIMEOUTS } from "../constants.js";
|
|
13
|
+
import { runTaskWithLoader } from "../ui/async-task.js";
|
|
12
14
|
import { normalizePackageSource } from "../utils/format.js";
|
|
13
15
|
import { fileExists } from "../utils/fs.js";
|
|
14
|
-
import { clearSearchCache } from "./discovery.js";
|
|
15
|
-
import { getPackageCatalog } from "./catalog.js";
|
|
16
|
-
import { discoverPackageExtensionEntrypoints, readPackageManifest } from "./extensions.js";
|
|
17
16
|
import { logPackageInstall } from "../utils/history.js";
|
|
18
|
-
import { clearUpdatesAvailable } from "../utils/settings.js";
|
|
19
|
-
import { notify, error as notifyError, success } from "../utils/notify.js";
|
|
20
|
-
import { confirmAction, confirmReload, showProgress } from "../utils/ui-helpers.js";
|
|
21
17
|
import { tryOperation } from "../utils/mode.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
18
|
+
import { fetchWithTimeout } from "../utils/network.js";
|
|
19
|
+
import { notify, error as notifyError, success } from "../utils/notify.js";
|
|
24
20
|
import { execNpm } from "../utils/npm-exec.js";
|
|
25
21
|
import { normalizePackageIdentity } from "../utils/package-source.js";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
22
|
+
import { clearUpdatesAvailable } from "../utils/settings.js";
|
|
23
|
+
import { updateExtmgrStatus } from "../utils/status.js";
|
|
24
|
+
import { confirmAction, confirmReload, showProgress } from "../utils/ui-helpers.js";
|
|
25
|
+
import { getPackageCatalog } from "./catalog.js";
|
|
26
|
+
import { clearSearchCache } from "./discovery.js";
|
|
27
|
+
import { discoverPackageExtensionEntrypoints, readPackageManifest } from "./extensions.js";
|
|
28
28
|
|
|
29
29
|
export type InstallScope = "global" | "project";
|
|
30
30
|
|
|
@@ -171,7 +171,7 @@ export async function installPackage(
|
|
|
171
171
|
|
|
172
172
|
// Check if it's a GitHub URL to a .ts file - handle as direct download
|
|
173
173
|
const githubTsMatch = source.match(
|
|
174
|
-
/^https:\/\/github\.com\/([
|
|
174
|
+
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+\.ts)$/
|
|
175
175
|
);
|
|
176
176
|
const githubInfo = safeExtractGithubMatch(githubTsMatch);
|
|
177
177
|
if (githubInfo) {
|
|
@@ -211,6 +211,7 @@ export async function installPackage(
|
|
|
211
211
|
title: "Install Package",
|
|
212
212
|
message: `Installing ${normalized}...`,
|
|
213
213
|
cancellable: false,
|
|
214
|
+
fallbackWithoutLoader: true,
|
|
214
215
|
},
|
|
215
216
|
async ({ setMessage }) => {
|
|
216
217
|
await getPackageCatalog(ctx.cwd).install(normalized, scope, (event) => {
|
|
@@ -231,7 +232,7 @@ export async function installPackage(
|
|
|
231
232
|
clearSearchCache();
|
|
232
233
|
logPackageInstall(pi, normalized, normalized, undefined, scope, true);
|
|
233
234
|
success(ctx, `Installed ${normalized} (${scope})`);
|
|
234
|
-
clearUpdatesAvailable(pi, ctx, [normalizePackageIdentity(normalized)]);
|
|
235
|
+
clearUpdatesAvailable(pi, ctx, [normalizePackageIdentity(normalized, { cwd: ctx.cwd })]);
|
|
235
236
|
|
|
236
237
|
const reloaded = await confirmReload(ctx, "Package installed.");
|
|
237
238
|
if (!reloaded) {
|
|
@@ -1,33 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Package management (update, remove)
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
5
|
-
ExtensionAPI,
|
|
6
|
-
ExtensionCommandContext,
|
|
7
|
-
ProgressEvent,
|
|
8
|
-
} from "@mariozechner/pi-coding-agent";
|
|
9
|
-
import type { InstalledPackage } from "../types/index.js";
|
|
10
4
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
type ExtensionAPI,
|
|
6
|
+
type ExtensionCommandContext,
|
|
7
|
+
getAgentDir,
|
|
8
|
+
type ProgressEvent,
|
|
9
|
+
} from "@mariozechner/pi-coding-agent";
|
|
10
|
+
import { UI } from "../constants.js";
|
|
11
|
+
import { type InstalledPackage } from "../types/index.js";
|
|
12
|
+
import { runTaskWithLoader } from "../ui/async-task.js";
|
|
16
13
|
import { formatInstalledPackageLabel } from "../utils/format.js";
|
|
14
|
+
import { logPackageRemove, logPackageUpdate } from "../utils/history.js";
|
|
15
|
+
import { requireUI } from "../utils/mode.js";
|
|
16
|
+
import { notify, error as notifyError, success } from "../utils/notify.js";
|
|
17
17
|
import { normalizePackageIdentity } from "../utils/package-source.js";
|
|
18
|
-
import { logPackageUpdate, logPackageRemove } from "../utils/history.js";
|
|
19
18
|
import { clearUpdatesAvailable } from "../utils/settings.js";
|
|
20
|
-
import {
|
|
19
|
+
import { updateExtmgrStatus } from "../utils/status.js";
|
|
21
20
|
import {
|
|
22
21
|
confirmAction,
|
|
23
22
|
confirmReload,
|
|
24
|
-
showProgress,
|
|
25
23
|
formatListOutput,
|
|
24
|
+
showProgress,
|
|
26
25
|
} from "../utils/ui-helpers.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
import { getPackageCatalog } from "./catalog.js";
|
|
27
|
+
import {
|
|
28
|
+
clearSearchCache,
|
|
29
|
+
getInstalledPackages,
|
|
30
|
+
getInstalledPackagesAllScopes,
|
|
31
|
+
} from "./discovery.js";
|
|
31
32
|
|
|
32
33
|
export interface PackageMutationOutcome {
|
|
33
34
|
reloaded: boolean;
|
|
@@ -56,7 +57,7 @@ async function updatePackageInternal(
|
|
|
56
57
|
): Promise<PackageMutationOutcome> {
|
|
57
58
|
showProgress(ctx, "Updating", source);
|
|
58
59
|
|
|
59
|
-
const updateIdentity = normalizePackageIdentity(source);
|
|
60
|
+
const updateIdentity = normalizePackageIdentity(source, { cwd: ctx.cwd });
|
|
60
61
|
|
|
61
62
|
try {
|
|
62
63
|
const updates = await getPackageCatalog(ctx.cwd).checkForAvailableUpdates();
|
|
@@ -78,6 +79,7 @@ async function updatePackageInternal(
|
|
|
78
79
|
title: "Update Package",
|
|
79
80
|
message: `Updating ${source}...`,
|
|
80
81
|
cancellable: false,
|
|
82
|
+
fallbackWithoutLoader: true,
|
|
81
83
|
},
|
|
82
84
|
async ({ setMessage }) => {
|
|
83
85
|
await getPackageCatalog(ctx.cwd).update(source, (event) => {
|
|
@@ -128,6 +130,7 @@ async function updatePackagesInternal(
|
|
|
128
130
|
title: "Update Packages",
|
|
129
131
|
message: "Updating all packages...",
|
|
130
132
|
cancellable: false,
|
|
133
|
+
fallbackWithoutLoader: true,
|
|
131
134
|
},
|
|
132
135
|
async ({ setMessage }) => {
|
|
133
136
|
await getPackageCatalog(ctx.cwd).update(undefined, (event) => {
|
|
@@ -186,8 +189,31 @@ export async function updatePackagesWithOutcome(
|
|
|
186
189
|
return updatePackagesInternal(ctx, pi);
|
|
187
190
|
}
|
|
188
191
|
|
|
189
|
-
function packageIdentity(
|
|
190
|
-
|
|
192
|
+
function packageIdentity(
|
|
193
|
+
source: string,
|
|
194
|
+
options?: { resolvedPath?: string; cwd?: string }
|
|
195
|
+
): string {
|
|
196
|
+
return normalizePackageIdentity(source, options);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function packageSourceIdentities(source: string, ctx: ExtensionCommandContext): Set<string> {
|
|
200
|
+
return new Set([
|
|
201
|
+
packageIdentity(source, { cwd: ctx.cwd }),
|
|
202
|
+
packageIdentity(source, { cwd: getAgentDir() }),
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function installedPackageMatchesSource(
|
|
207
|
+
pkg: InstalledPackage,
|
|
208
|
+
identities: Set<string>,
|
|
209
|
+
ctx: ExtensionCommandContext
|
|
210
|
+
): boolean {
|
|
211
|
+
return identities.has(
|
|
212
|
+
packageIdentity(pkg.source, {
|
|
213
|
+
...(pkg.resolvedPath ? { resolvedPath: pkg.resolvedPath } : {}),
|
|
214
|
+
cwd: pkg.scope === "project" ? ctx.cwd : getAgentDir(),
|
|
215
|
+
})
|
|
216
|
+
);
|
|
191
217
|
}
|
|
192
218
|
|
|
193
219
|
async function getInstalledPackagesAllScopesForRemoval(
|
|
@@ -244,7 +270,6 @@ function buildRemovalTargets(
|
|
|
244
270
|
return addTarget("global");
|
|
245
271
|
case "project":
|
|
246
272
|
return addTarget("project");
|
|
247
|
-
case "cancel":
|
|
248
273
|
default:
|
|
249
274
|
return [];
|
|
250
275
|
}
|
|
@@ -285,6 +310,7 @@ async function executeRemovalTargets(
|
|
|
285
310
|
title: "Remove Package",
|
|
286
311
|
message: `Removing ${target.source}...`,
|
|
287
312
|
cancellable: false,
|
|
313
|
+
fallbackWithoutLoader: true,
|
|
288
314
|
},
|
|
289
315
|
async ({ setMessage }) => {
|
|
290
316
|
await getPackageCatalog(ctx.cwd).remove(target.source, target.scope, (event) => {
|
|
@@ -338,8 +364,8 @@ async function removePackageInternal(
|
|
|
338
364
|
pi: ExtensionAPI
|
|
339
365
|
): Promise<PackageMutationOutcome> {
|
|
340
366
|
const installed = await getInstalledPackagesAllScopesForRemoval(ctx);
|
|
341
|
-
const
|
|
342
|
-
const matching = installed.filter((
|
|
367
|
+
const identities = packageSourceIdentities(source, ctx);
|
|
368
|
+
const matching = installed.filter((pkg) => installedPackageMatchesSource(pkg, identities, ctx));
|
|
343
369
|
|
|
344
370
|
const hasBothScopes =
|
|
345
371
|
matching.some((pkg) => pkg.scope === "global") &&
|
|
@@ -385,13 +411,13 @@ async function removePackageInternal(
|
|
|
385
411
|
.filter((result) => result.success)
|
|
386
412
|
.map((result) => result.target);
|
|
387
413
|
|
|
388
|
-
const remaining = (await getInstalledPackagesAllScopesForRemoval(ctx)).filter(
|
|
389
|
-
(
|
|
414
|
+
const remaining = (await getInstalledPackagesAllScopesForRemoval(ctx)).filter((pkg) =>
|
|
415
|
+
installedPackageMatchesSource(pkg, identities, ctx)
|
|
390
416
|
);
|
|
391
417
|
notifyRemovalSummary(source, remaining, failures, ctx);
|
|
392
418
|
|
|
393
419
|
if (failures.length === 0 && remaining.length === 0) {
|
|
394
|
-
clearUpdatesAvailable(pi, ctx,
|
|
420
|
+
clearUpdatesAvailable(pi, ctx, identities);
|
|
395
421
|
}
|
|
396
422
|
|
|
397
423
|
const successfulRemovalCount = successfulTargets.length;
|
package/src/types/index.ts
CHANGED
|
@@ -46,25 +46,32 @@ export interface PackageExtensionEntry {
|
|
|
46
46
|
state: State;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export interface
|
|
50
|
-
type: "local"
|
|
49
|
+
export interface LocalUnifiedItem {
|
|
50
|
+
type: "local";
|
|
51
51
|
id: string;
|
|
52
52
|
displayName: string;
|
|
53
53
|
summary: string;
|
|
54
54
|
scope: Scope;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
state: State;
|
|
56
|
+
activePath: string;
|
|
57
|
+
disabledPath: string;
|
|
58
|
+
originalState: State;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PackageUnifiedItem {
|
|
62
|
+
type: "package";
|
|
63
|
+
id: string;
|
|
64
|
+
displayName: string;
|
|
65
|
+
scope: Scope;
|
|
66
|
+
source: string;
|
|
62
67
|
version?: string | undefined;
|
|
63
68
|
description?: string | undefined;
|
|
64
69
|
size?: number | undefined; // Package size in bytes
|
|
65
70
|
updateAvailable?: boolean | undefined;
|
|
66
71
|
}
|
|
67
72
|
|
|
73
|
+
export type UnifiedItem = LocalUnifiedItem | PackageUnifiedItem;
|
|
74
|
+
|
|
68
75
|
export interface SearchCache {
|
|
69
76
|
query: string;
|
|
70
77
|
results: NpmPackage[];
|