@lebronj/pi-suite 0.1.13 → 0.1.14

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
@@ -7,12 +7,15 @@ JHP's Pi extension suite for team coding workflows.
7
7
  ```bash
8
8
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent
9
9
  pi install npm:@lebronj/pi-suite
10
+ pi install npm:pi-mcp-adapter
11
+ pi install npm:pi-subagents
12
+ pi install npm:pi-web-access
10
13
  ```
11
14
 
12
15
  Or use the bootstrap script to install Pi, configure the team OpenAI-compatible endpoint, install this suite, and set up Bun + qmd for memory search:
13
16
 
14
17
  ```bash
15
- curl -fsSL https://registry.npmjs.org/@lebronj/pi-suite/-/pi-suite-0.1.13.tgz | tar -xzO package/scripts/bootstrap.sh | bash
18
+ curl -fsSL https://registry.npmjs.org/@lebronj/pi-suite/-/pi-suite-0.1.14.tgz | tar -xzO package/scripts/bootstrap.sh | bash
16
19
  ```
17
20
 
18
21
  ## What Is Included
@@ -22,7 +25,11 @@ curl -fsSL https://registry.npmjs.org/@lebronj/pi-suite/-/pi-suite-0.1.13.tgz |
22
25
  - Skills: provider checklist, Pi capability reference, image-to-editable-PPT workflow.
23
26
  - Vendored package: `@jhp/pi-memory`, including qmd search, external curator service, and memory/skill-draft versioning.
24
27
 
25
- `pi-mcp-adapter`, `pi-subagents`, and `pi-web-access` are loaded by this suite. Do not install them separately unless you filter suite resources, because duplicate extension tools/flags can conflict.
28
+ Install the companion packages above with the suite so MCP, subagent, and web tools register from their own package manifests. The bootstrap script installs the same companion packages automatically.
29
+
30
+ Do not add those companion packages inside the `@lebronj/pi-suite` manifest at the same time; loading them both from the suite manifest and as standalone Pi packages creates duplicate tool/flag registration conflicts.
31
+
32
+ Existing users can run `pi update --extensions`; if Pi reports missing suite companion packages on startup, run `/pi-suite-repair` and it will install or refresh the currently required companion package set, then reload resources.
26
33
 
27
34
  Figma is not installed or loaded by default. Enable it only when needed:
28
35
 
@@ -0,0 +1,143 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getAgentDir, type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
4
+
5
+ interface PackageEntryObject {
6
+ source?: unknown;
7
+ }
8
+
9
+ interface SettingsFile {
10
+ packages?: unknown;
11
+ }
12
+
13
+ interface RepairRequirement {
14
+ source: string;
15
+ description: string;
16
+ }
17
+
18
+ const REQUIRED_PACKAGES: RepairRequirement[] = [
19
+ { source: "npm:pi-mcp-adapter", description: "MCP tools" },
20
+ { source: "npm:pi-subagents", description: "subagent delegation" },
21
+ { source: "npm:pi-web-access", description: "web search/content tools" },
22
+ ];
23
+
24
+ function readSettings(path: string): SettingsFile | undefined {
25
+ if (!existsSync(path)) return undefined;
26
+ try {
27
+ const parsed = JSON.parse(readFileSync(path, "utf8")) as unknown;
28
+ return parsed && typeof parsed === "object" ? (parsed as SettingsFile) : undefined;
29
+ } catch {
30
+ return undefined;
31
+ }
32
+ }
33
+
34
+ function packageSource(entry: unknown): string | undefined {
35
+ if (typeof entry === "string") return entry;
36
+ if (!entry || typeof entry !== "object") return undefined;
37
+ const source = (entry as PackageEntryObject).source;
38
+ return typeof source === "string" ? source : undefined;
39
+ }
40
+
41
+ function packageSourcesFromSettings(settings: SettingsFile | undefined): string[] {
42
+ if (!settings || !Array.isArray(settings.packages)) return [];
43
+ return settings.packages.flatMap((entry) => {
44
+ const source = packageSource(entry);
45
+ return source ? [source] : [];
46
+ });
47
+ }
48
+
49
+ function npmPackageName(source: string): string | undefined {
50
+ if (!source.startsWith("npm:")) return undefined;
51
+ const spec = source.slice("npm:".length);
52
+ if (spec.startsWith("@")) {
53
+ const slash = spec.indexOf("/");
54
+ if (slash === -1) return undefined;
55
+ const versionStart = spec.indexOf("@", slash + 1);
56
+ return versionStart === -1 ? spec : spec.slice(0, versionStart);
57
+ }
58
+ const versionStart = spec.indexOf("@");
59
+ return versionStart === -1 ? spec : spec.slice(0, versionStart);
60
+ }
61
+
62
+ function sourceIdentity(source: string): string {
63
+ return npmPackageName(source) ?? source;
64
+ }
65
+
66
+ function isVersionPinnedNpmSource(source: string): boolean {
67
+ if (!source.startsWith("npm:")) return false;
68
+ const name = npmPackageName(source);
69
+ return Boolean(name && source !== `npm:${name}`);
70
+ }
71
+
72
+ function requirementSatisfied(requirement: RepairRequirement, installedSources: string[]): boolean {
73
+ if (isVersionPinnedNpmSource(requirement.source)) {
74
+ return installedSources.includes(requirement.source);
75
+ }
76
+ const requiredIdentity = sourceIdentity(requirement.source);
77
+ return installedSources.some((source) => sourceIdentity(source) === requiredIdentity);
78
+ }
79
+
80
+ function readInstalledPackageSources(ctx: ExtensionContext): string[] {
81
+ const globalSettings = readSettings(join(getAgentDir(), "settings.json"));
82
+ const projectSettings = readSettings(join(ctx.cwd, ".pi", "settings.json"));
83
+ return [...packageSourcesFromSettings(globalSettings), ...packageSourcesFromSettings(projectSettings)];
84
+ }
85
+
86
+ function pendingRequirements(ctx: ExtensionContext): RepairRequirement[] {
87
+ const installedSources = readInstalledPackageSources(ctx);
88
+ return REQUIRED_PACKAGES.filter((requirement) => !requirementSatisfied(requirement, installedSources));
89
+ }
90
+
91
+ function formatRequirement(requirement: RepairRequirement): string {
92
+ return `${requirement.source} (${requirement.description})`;
93
+ }
94
+
95
+ export default function piSuiteRepairExtension(pi: ExtensionAPI): void {
96
+ let reminderShown = false;
97
+
98
+ pi.on("session_start", (_event, ctx) => {
99
+ if (!ctx.hasUI || reminderShown) return;
100
+ const pending = pendingRequirements(ctx);
101
+ if (pending.length === 0) return;
102
+ reminderShown = true;
103
+ ctx.ui.notify(
104
+ `pi-suite needs companion package repair: ${pending.map((item) => item.source).join(", ")}. Run /pi-suite-repair, then reload if prompted.`,
105
+ "warning",
106
+ );
107
+ });
108
+
109
+ pi.registerCommand("pi-suite-repair", {
110
+ description: "Install missing required companion Pi packages, then reload resources.",
111
+ handler: async (_args, ctx) => {
112
+ if (!ctx.hasUI) return;
113
+
114
+ const pending = pendingRequirements(ctx);
115
+ if (pending.length === 0) {
116
+ ctx.ui.notify("pi-suite companion packages are already registered. No repair needed.", "info");
117
+ return;
118
+ }
119
+
120
+ ctx.ui.notify(
121
+ `Repairing missing pi-suite companion packages: ${pending.map((item) => item.source).join(", ")}`,
122
+ "info",
123
+ );
124
+
125
+ const failures: string[] = [];
126
+ for (const requirement of pending) {
127
+ const result = await pi.exec("pi", ["install", requirement.source], { signal: ctx.signal, timeout: 120_000 });
128
+ if (result.code !== 0) {
129
+ const details = (result.stderr || result.stdout || "unknown error").trim();
130
+ failures.push(`${formatRequirement(requirement)}: ${details}`);
131
+ }
132
+ }
133
+
134
+ if (failures.length > 0) {
135
+ ctx.ui.notify(`pi-suite repair failed: ${failures.join("; ")}`, "error");
136
+ return;
137
+ }
138
+
139
+ ctx.ui.notify("pi-suite companion packages are installed. Reloading Pi resources...", "info");
140
+ await ctx.reload();
141
+ },
142
+ });
143
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lebronj/pi-suite",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "JHP's Pi extension suite for team coding workflows",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -22,11 +22,6 @@
22
22
  "README.md",
23
23
  "LICENSE"
24
24
  ],
25
- "dependencies": {
26
- "pi-mcp-adapter": "2.9.0",
27
- "pi-subagents": "0.28.0",
28
- "pi-web-access": "0.10.7"
29
- },
30
25
  "peerDependencies": {
31
26
  "@earendil-works/pi-agent-core": "*",
32
27
  "@earendil-works/pi-ai": "*",
@@ -54,19 +49,13 @@
54
49
  "pi": {
55
50
  "extensions": [
56
51
  "./extensions",
57
- "./vendor/pi-memory/index.ts",
58
- "node_modules/pi-mcp-adapter/index.ts",
59
- "node_modules/pi-subagents/src/extension/index.ts",
60
- "node_modules/pi-web-access/index.ts"
52
+ "./vendor/pi-memory/index.ts"
61
53
  ],
62
54
  "prompts": [
63
- "./prompts",
64
- "node_modules/pi-subagents/prompts"
55
+ "./prompts"
65
56
  ],
66
57
  "skills": [
67
- "./skills",
68
- "node_modules/pi-subagents/skills",
69
- "node_modules/pi-web-access/skills"
58
+ "./skills"
70
59
  ]
71
60
  },
72
61
  "publishConfig": {
@@ -83,6 +83,17 @@ NODE
83
83
  echo "Installing Pi extension suite: $PI_SUITE"
84
84
  pi install "$PI_SUITE"
85
85
 
86
+ COMPANION_PACKAGES=(
87
+ "npm:pi-mcp-adapter"
88
+ "npm:pi-subagents"
89
+ "npm:pi-web-access"
90
+ )
91
+
92
+ echo "Installing Pi companion packages..."
93
+ for companion_package in "${COMPANION_PACKAGES[@]}"; do
94
+ pi install "$companion_package"
95
+ done
96
+
86
97
  link_if_safe() {
87
98
  local source_path="$1"
88
99
  local link_path="$2"
@@ -209,6 +209,7 @@ The pet extension provides a small terminal companion and durable profile.
209
209
  - `prompt-url-widget.ts`: detects PR/issue prompt templates, fetches GitHub metadata with `gh`, shows a widget, and names the session when possible.
210
210
  - `snake.ts`: `/snake` opens a TUI snake game; `Esc` pauses/saves, `q` quits, arrows/WASD move.
211
211
  - `tps.ts`: after each assistant run, shows tokens-per-second and token usage details.
212
+ - `pi-suite-repair.ts`: registers `/pi-suite-repair` and startup reminders for missing companion Pi packages declared by the suite.
212
213
  - `memory-curator.ts`: deprecated compatibility notice only; external curation is managed by pi-memory service tools.
213
214
 
214
215
  ## Skills
@@ -244,7 +245,7 @@ Global user package configuration is in `~/.pi/agent/settings.json`; project pac
244
245
 
245
246
  Current suite package:
246
247
 
247
- - `@lebronj/pi-suite`: bundles local extensions, prompts, suite skills, vendored `@jhp/pi-memory`, and optional package hooks for `pi-mcp-adapter`, `pi-subagents`, and `pi-web-access`. It does not install or load `pi-mono-figma` by default.
248
+ - `@lebronj/pi-suite`: bundles local extensions, prompts, suite skills, and vendored `@jhp/pi-memory`. The bootstrap script installs `pi-mcp-adapter`, `pi-subagents`, and `pi-web-access` as standalone companion Pi packages. It does not install or load `pi-mono-figma` by default.
248
249
 
249
250
  Common project packages:
250
251
 
@@ -260,7 +261,7 @@ Bootstrap behavior:
260
261
  - Installs global `@earendil-works/pi-coding-agent`.
261
262
  - Writes the team OpenAI-compatible provider to `~/.pi/agent/models.json`.
262
263
  - Sets default provider/model in `~/.pi/agent/settings.json`.
263
- - Runs `pi install npm:@lebronj/pi-suite` by default; this does not install or load `pi-mono-figma`.
264
+ - Runs `pi install npm:@lebronj/pi-suite` by default, then installs companion packages with `pi install npm:pi-mcp-adapter`, `pi install npm:pi-subagents`, and `pi install npm:pi-web-access`; this does not install or load `pi-mono-figma`.
264
265
  - Prints follow-up instructions for enabling Figma later with `pi install npm:pi-mono-figma` and disabling it with `pi remove npm:pi-mono-figma`.
265
266
  - Creates `~/.pi/agent/memory` and links it into the workspace `.pi/memory` when safe.
266
267
  - Optionally initializes the local `~/.pi/agent/evolution` repo for memory/skill-draft snapshots; it never writes tokens or enables auto-push.