@akanjs/devkit 3.0.0-beta.15 → 3.0.0-beta.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/executors.ts CHANGED
@@ -1832,6 +1832,11 @@ export class PkgExecutor extends Executor {
1832
1832
  };
1833
1833
  const rootVersion = rootDeps[dep];
1834
1834
  if (rootVersion) return rootVersion;
1835
+ // A transitive dependency the workspace pins rather than imports is only ever written as an override, and
1836
+ // that pin has to reach the published package: neither an override nor a dependency's own shrinkwrap is
1837
+ // applied to a consumer's install, so the version has to be a dependency of what we publish.
1838
+ const overrideVersion = rootPackageJson.overrides?.[dep];
1839
+ if (typeof overrideVersion === "string") return overrideVersion;
1835
1840
 
1836
1841
  try {
1837
1842
  const packageJsonPath = `pkgs/${dep}/package.json`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/devkit",
3
- "version": "3.0.0-beta.15",
3
+ "version": "3.0.0-beta.16",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -39,11 +39,14 @@
39
39
  "./*": "./*.ts"
40
40
  },
41
41
  "dependencies": {
42
+ "@earendil-works/pi-agent-core": "0.80.6",
43
+ "@earendil-works/pi-ai": "0.80.6",
42
44
  "@earendil-works/pi-coding-agent": "0.80.6",
45
+ "@earendil-works/pi-tui": "0.80.6",
43
46
  "@inquirer/prompts": "^8.4.3",
44
47
  "@tailwindcss/node": "^4.3.0",
45
48
  "@trapezedev/project": "^7.1.4",
46
- "akanjs": "3.0.0-beta.15",
49
+ "akanjs": "3.0.0-beta.16",
47
50
  "chalk": "^5.6.2",
48
51
  "commander": "^14.0.3",
49
52
  "dayjs": "^1.11.20",
@@ -0,0 +1,55 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import path from "node:path";
3
+ import type { PackageJson } from "@akanjs/devkit/types";
4
+
5
+ // Guards the published dependency closure of the code agent, which the monorepo cannot exercise on its own.
6
+ //
7
+ // `@earendil-works/pi-coding-agent` asks for `^0.80.6` of its three sibling packages and ships an
8
+ // `npm-shrinkwrap.json` pinning them to the exact version it was built against. Bun reads neither that file nor
9
+ // this workspace's `overrides` when somebody installs the published CLI, so `^0.80.6` resolved to the newest
10
+ // 0.80.x — 0.80.10, which dropped `getOAuthApiKey` from `pi-ai/oauth` while the pinned coding agent still
11
+ // imports it. A global install died on its first import:
12
+ //
13
+ // Export named 'getOAuthApiKey' not found in module '.../@earendil-works/pi-ai/dist/oauth.js'.
14
+ //
15
+ // `PackageRunner` therefore re-declares pi's own pins as dependencies of what we publish; this keeps the two
16
+ // equal, so bumping the coding agent without moving the pins fails here rather than at a user's first run.
17
+
18
+ const repoRoot = path.resolve(import.meta.dir, "../../..");
19
+ const piName = "@earendil-works/pi-coding-agent";
20
+ const piDir = `${repoRoot}/node_modules/${piName}`;
21
+ const publishedPackages = ["pkgs/@akanjs/devkit/package.json", "pkgs/@akanjs/cli/package.json"];
22
+
23
+ interface Shrinkwrap {
24
+ packages: Record<string, { version?: string }>;
25
+ }
26
+
27
+ const readJson = async <T>(file: string) => (await Bun.file(file).json()) as T;
28
+
29
+ const shrinkwrappedPins = async () => {
30
+ const { packages } = await readJson<Shrinkwrap>(`${piDir}/npm-shrinkwrap.json`);
31
+ const entries = Object.entries(packages)
32
+ .map(([key, entry]) => [key.replace(/^node_modules\//, ""), entry.version ?? ""] as const)
33
+ .filter(([name]) => name.startsWith("@earendil-works/"));
34
+ return Object.fromEntries(entries);
35
+ };
36
+
37
+ describe("pi dependency pins", () => {
38
+ test("the shrinkwrap read here belongs to the coding agent we publish", async () => {
39
+ const installed = await readJson<PackageJson>(`${piDir}/package.json`);
40
+ for (const file of publishedPackages) {
41
+ const { dependencies = {} } = await readJson<PackageJson>(`${repoRoot}/${file}`);
42
+ expect({ file, [piName]: dependencies[piName] }).toEqual({ file, [piName]: installed.version });
43
+ }
44
+ });
45
+
46
+ test("every sibling pi package is published at the version the coding agent shrinkwrapped", async () => {
47
+ const pins = await shrinkwrappedPins();
48
+ expect(Object.keys(pins).length).toBeGreaterThan(0);
49
+ for (const file of publishedPackages) {
50
+ const { dependencies = {} } = await readJson<PackageJson>(`${repoRoot}/${file}`);
51
+ const declared = Object.fromEntries(Object.keys(pins).map((name) => [name, dependencies[name]]));
52
+ expect({ file, ...declared }).toEqual({ file, ...pins });
53
+ }
54
+ });
55
+ });
package/types.ts CHANGED
@@ -10,6 +10,7 @@ export interface PackageJson {
10
10
  peerDependencies?: Record<string, string>;
11
11
  peerDependenciesMeta?: Record<string, { optional?: boolean }>;
12
12
  optionalDependencies?: Record<string, string>;
13
+ overrides?: Record<string, string>;
13
14
  engines?: Record<string, string>;
14
15
  exports?: Record<string, string | Record<string, string>>;
15
16
  bun?: {