fix: reduce workspace dependency tree

This commit is contained in:
Armin Ronacher 2026-08-23 09:28:19 +02:00
parent a1f955e9f4
commit f8f03460a0
12 changed files with 90 additions and 234 deletions

138
package-lock.json generated
View file

@ -3180,23 +3180,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@ -3968,15 +3951,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
"integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
@ -4228,22 +4202,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
@ -5382,7 +5340,7 @@
"yaml": "2.9.0"
},
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"@vitest/coverage-v8": "4.1.9",
"typescript": "5.9.3",
"vitest": "4.1.9"
@ -5398,23 +5356,6 @@
"extraneous": true,
"license": "MIT"
},
"packages/agent/node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"packages/agent/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"packages/ai": {
"name": "@earendil-works/pi-ai",
"version": "0.84.2",
@ -5435,7 +5376,7 @@
"pi-ai": "dist/cli.js"
},
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"canvas": "3.2.3",
"vitest": "4.1.9"
},
@ -5443,23 +5384,6 @@
"node": ">=22.19.0"
}
},
"packages/ai/node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"packages/ai/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"packages/client": {
"name": "@earendil-works/pi-client",
"version": "0.84.2",
@ -5489,7 +5413,6 @@
"chalk": "5.6.2",
"cross-spawn": "7.0.6",
"diff": "8.0.4",
"glob": "13.0.6",
"grok-mermaid": "0.2.2",
"highlight.js": "10.7.3",
"hosted-git-info": "9.0.3",
@ -5508,7 +5431,7 @@
"devDependencies": {
"@types/cross-spawn": "6.0.6",
"@types/hosted-git-info": "3.0.5",
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"@types/proper-lockfile": "4.1.4",
"@types/semver": "7.7.1",
"shx": "0.4.0",
@ -5601,53 +5524,19 @@
"extraneous": true,
"license": "MIT"
},
"packages/coding-agent/node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"packages/coding-agent/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"packages/evals": {
"name": "@earendil-works/pi-evals",
"version": "0.84.2",
"devDependencies": {
"@earendil-works/pi-ai": "^0.84.2",
"@earendil-works/pi-coding-agent": "^0.84.2",
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"shx": "0.4.0",
"typescript": "5.9.3",
"vitest": "4.1.9",
"vitest-evals": "0.15.0"
}
},
"packages/evals/node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"packages/evals/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"packages/protocol": {
"name": "@earendil-works/pi-protocol",
"version": "0.84.2",
@ -5700,30 +5589,13 @@
"version": "0.84.2",
"license": "MIT",
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"vitest": "4.1.9"
},
"engines": {
"node": ">=22.19.0"
}
},
"packages/telemetry/node_modules/@types/node": {
"version": "24.12.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"packages/telemetry/node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"packages/tui": {
"name": "@earendil-works/pi-tui",
"version": "0.84.2",

View file

@ -60,7 +60,7 @@
"node": ">=22.19.0"
},
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"@vitest/coverage-v8": "4.1.9",
"typescript": "5.9.3",
"vitest": "4.1.9"

View file

@ -92,7 +92,7 @@
"node": ">=22.19.0"
},
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"canvas": "3.2.3",
"vitest": "4.1.9"
}

View file

@ -8,6 +8,7 @@
### Changed
- Changed package resource glob expansion to use Node.js's built-in implementation with deterministic visible-path matching, reducing the installed runtime dependency tree.
- Changed the bundled Node.js runtime to load jiti's Babel transform only when an extension needs it, reducing CLI startup time and bundle size.
- Changed syntax highlighting to initialize only twenty common languages eagerly and defer the remaining grammars until after the initial TUI render, reducing CLI startup time.
- Changed the Node.js CLI and RPC entrypoints to load a bundled runtime, reducing startup filesystem reads while keeping the public library and legacy module paths on the modular runtime for normal dependency identity.

View file

@ -130,7 +130,7 @@ Add a `pi` manifest to `package.json` or use conventional directories. Include t
}
```
Paths are relative to the package root. Arrays support glob patterns and `!exclusions`.
Paths are relative to the package root. Arrays support glob patterns and `!exclusions`. Positive manifest globs discover visible paths in lexical order. List dot-prefixed paths directly. If a glob would need to continue through a symlink, list the symlinked resource root directly.
### Gallery Metadata

View file

@ -513,7 +513,6 @@
"chalk": "5.6.2",
"cross-spawn": "7.0.6",
"diff": "8.0.4",
"glob": "13.0.6",
"grok-mermaid": "0.2.2",
"highlight.js": "10.7.3",
"hosted-git-info": "9.0.3",
@ -1233,23 +1232,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/google-auth-library": {
"version": "10.6.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz",
@ -1447,15 +1429,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
"integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -1567,22 +1540,6 @@
"node": ">=8"
}
},
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/proper-lockfile": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",

View file

@ -18,7 +18,6 @@
"chalk": "5.6.2",
"cross-spawn": "7.0.6",
"diff": "8.0.4",
"glob": "13.0.6",
"grok-mermaid": "0.2.2",
"highlight.js": "10.7.3",
"hosted-git-info": "9.0.3",
@ -1223,23 +1222,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
"integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
"license": "BlueOak-1.0.0",
"dependencies": {
"minimatch": "^10.2.2",
"minipass": "^7.1.3",
"path-scurry": "^2.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/google-auth-library": {
"version": "10.6.2",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz",
@ -1437,15 +1419,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
"integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
"license": "BlueOak-1.0.0",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -1557,22 +1530,6 @@
"node": ">=8"
}
},
"node_modules/path-scurry": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
"integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
"license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^11.0.0",
"minipass": "^7.1.2"
},
"engines": {
"node": "18 || 20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/proper-lockfile": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",

View file

@ -53,7 +53,6 @@
"chalk": "5.6.2",
"cross-spawn": "7.0.6",
"diff": "8.0.4",
"glob": "13.0.6",
"grok-mermaid": "0.2.2",
"highlight.js": "10.7.3",
"hosted-git-info": "9.0.3",
@ -79,7 +78,7 @@
"devDependencies": {
"@types/cross-spawn": "6.0.6",
"@types/hosted-git-info": "3.0.5",
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"@types/proper-lockfile": "4.1.4",
"@types/semver": "7.7.1",
"shx": "0.4.0",

View file

@ -1,6 +1,16 @@
import type { ChildProcess, ChildProcessByStdio } from "node:child_process";
import { createHash } from "node:crypto";
import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
import {
chmodSync,
existsSync,
globSync,
mkdirSync,
readdirSync,
readFileSync,
rmSync,
statSync,
writeFileSync,
} from "node:fs";
import { homedir } from "node:os";
function getEnv(): NodeJS.ProcessEnv {
@ -24,7 +34,6 @@ function getEnv(): NodeJS.ProcessEnv {
import { basename, dirname, join, relative, resolve, sep } from "node:path";
import type { Readable } from "node:stream";
import { globSync } from "glob";
import ignore from "ignore";
import { minimatch } from "minimatch";
import { gt, maxSatisfying, rcompare, satisfies, valid, validRange } from "semver";
@ -275,6 +284,18 @@ function hasGlobPattern(s: string): boolean {
return s.includes("*") || s.includes("?");
}
/** Glob entries discover visible paths; exact entries can target dot paths or symlinked trees. */
function expandPackageGlob(pattern: string, root: string): string[] {
return globSync(pattern, { cwd: root })
.map((match) => resolve(root, match))
.filter((path) =>
relative(root, path)
.split(sep)
.every((segment) => segment === ".." || !segment.startsWith(".")),
)
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
}
function splitPatterns(entries: string[]): { plain: string[]; patterns: string[] } {
const plain: string[] = [];
const patterns: string[] = [];
@ -2300,12 +2321,7 @@ export class DefaultPackageManager implements PackageManager {
return [resolve(root, entry)];
}
return globSync(entry, {
cwd: root,
absolute: true,
dot: false,
nodir: false,
}).map((match) => resolve(match));
return expandPackageGlob(entry, root);
});
return this.collectFilesFromPaths(resolved, resourceType);
}

View file

@ -1647,6 +1647,60 @@ Content`,
expect(result.skills.some((r) => isEnabled(r, "pdf-to-markdown", "includes"))).toBe(true);
expect(result.skills.some((r) => isEnabled(r, "document-processor-api", "includes"))).toBe(true);
});
it("should sort manifest glob matches and use exact entries for dot paths and symlink traversal", async () => {
const pkgDir = join(tempDir, "manifest-glob-semantics-pkg");
const extensionFilesDir = join(pkgDir, "extension-files");
const extensionGroupDir = join(pkgDir, "extension-groups", "group");
const linkedPluginSource = join(pkgDir, "linked-plugin-source");
mkdirSync(join(extensionFilesDir, "nested"), { recursive: true });
mkdirSync(extensionGroupDir, { recursive: true });
mkdirSync(join(pkgDir, "plugins", "local", "skills", "local-skill"), { recursive: true });
mkdirSync(join(linkedPluginSource, "skills", "linked-skill"), { recursive: true });
writeFileSync(join(extensionFilesDir, "z.ts"), "export default function() {}");
writeFileSync(join(extensionFilesDir, "a.ts"), "export default function() {}");
writeFileSync(join(extensionFilesDir, ".ignored.ts"), "export default function() {}");
writeFileSync(join(extensionFilesDir, "nested", ".hidden.ts"), "export default function() {}");
writeFileSync(join(extensionGroupDir, "index.ts"), "export default function() {}");
writeFileSync(
join(pkgDir, "plugins", "local", "skills", "local-skill", "SKILL.md"),
"---\nname: local-skill\ndescription: Local\n---\n",
);
writeFileSync(
join(linkedPluginSource, "skills", "linked-skill", "SKILL.md"),
"---\nname: linked-skill\ndescription: Linked\n---\n",
);
symlinkSync(
linkedPluginSource,
join(pkgDir, "plugins", "linked"),
process.platform === "win32" ? "junction" : "dir",
);
writeFileSync(
join(pkgDir, "package.json"),
JSON.stringify({
name: "manifest-glob-semantics-pkg",
pi: {
extensions: [
"./extension-files/*.ts",
"./extension-files/**/.ignored.ts",
"./extension-files/nested/.hidden.ts",
"./extension-groups/*/",
],
skills: ["./plugins/*/skills", "./plugins/linked/skills"],
},
}),
);
const result = await packageManager.resolveExtensionSources([pkgDir]);
expect(result.extensions.map((resource) => relative(pkgDir, resource.path))).toEqual([
join("extension-files", "a.ts"),
join("extension-files", "z.ts"),
join("extension-files", "nested", ".hidden.ts"),
join("extension-groups", "group", "index.ts"),
]);
expect(result.skills.some((resource) => pathEndsWith(resource.path, "local-skill/SKILL.md"))).toBe(true);
expect(result.skills.some((resource) => pathEndsWith(resource.path, "linked-skill/SKILL.md"))).toBe(true);
});
});
describe("pattern filtering in package filters", () => {

View file

@ -11,7 +11,7 @@
"devDependencies": {
"@earendil-works/pi-ai": "^0.84.2",
"@earendil-works/pi-coding-agent": "^0.84.2",
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"shx": "0.4.0",
"typescript": "5.9.3",
"vitest-evals": "0.15.0",

View file

@ -41,7 +41,7 @@
"node": ">=22.19.0"
},
"devDependencies": {
"@types/node": "24.12.4",
"@types/node": "22.19.19",
"vitest": "4.1.9"
}
}