@pi-harness/pi-harness 0.1.29 → 0.1.31

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.
Files changed (53) hide show
  1. package/README.md +1 -1
  2. package/apps/web/dist/assets/index-D9ZcvGXi.js +25 -0
  3. package/apps/web/dist/assets/{index-xF647pQJ.css → index-DJsNIiIo.css} +1 -1
  4. package/apps/web/dist/index.html +2 -2
  5. package/apps/web/package.json +1 -15
  6. package/apps/web/profile/cordis.yml +0 -221
  7. package/apps/web/server-dist/bin.js +4 -2
  8. package/apps/web/server-dist/bin.js.map +1 -1
  9. package/apps/web/src/server/bin.ts +4 -2
  10. package/apps/web/src/style.css +3 -0
  11. package/apps/web/test/bin.test.ts +6 -0
  12. package/node_modules/@pi-harness/api-gateway/dist/index.d.ts.map +1 -1
  13. package/node_modules/@pi-harness/api-gateway/dist/index.js +43 -12
  14. package/node_modules/@pi-harness/api-gateway/dist/index.js.map +1 -1
  15. package/node_modules/@pi-harness/api-gateway/package.json +1 -27
  16. package/node_modules/@pi-harness/cli/dist/bin.js +2 -1
  17. package/node_modules/@pi-harness/cli/dist/bin.js.map +1 -1
  18. package/node_modules/@pi-harness/cli/dist/main.d.ts +2 -0
  19. package/node_modules/@pi-harness/cli/dist/main.d.ts.map +1 -1
  20. package/node_modules/@pi-harness/cli/dist/main.js +8 -1
  21. package/node_modules/@pi-harness/cli/dist/main.js.map +1 -1
  22. package/node_modules/@pi-harness/cli/package.json +1 -1
  23. package/node_modules/@pi-harness/cli/profiles/default/cordis.yml +0 -87
  24. package/node_modules/@pi-harness/host-webserver/package.json +1 -1
  25. package/node_modules/@pi-harness/web-app/package.json +1 -1
  26. package/package.json +8 -35
  27. package/packages/api-gateway/dist/index.d.ts.map +1 -1
  28. package/packages/api-gateway/dist/index.js +43 -12
  29. package/packages/api-gateway/dist/index.js.map +1 -1
  30. package/packages/api-gateway/package.json +1 -27
  31. package/packages/api-gateway/src/index.ts +55 -17
  32. package/packages/api-gateway/test/index.test.ts +157 -2
  33. package/packages/api-gateway/test/packed-package.test.ts +106 -10
  34. package/packages/api-gateway/test/release-contract.test.ts +10 -5
  35. package/packages/bundle-web-app/package.json +1 -1
  36. package/packages/cli/dist/bin.js +2 -1
  37. package/packages/cli/dist/bin.js.map +1 -1
  38. package/packages/cli/dist/main.d.ts +2 -0
  39. package/packages/cli/dist/main.d.ts.map +1 -1
  40. package/packages/cli/dist/main.js +8 -1
  41. package/packages/cli/dist/main.js.map +1 -1
  42. package/packages/cli/package.json +1 -1
  43. package/packages/cli/profiles/default/cordis.yml +0 -87
  44. package/packages/cli/src/bin.ts +2 -1
  45. package/packages/cli/src/main.ts +10 -1
  46. package/packages/cli/test/binary.test.ts +5 -1
  47. package/packages/cli/test/broken-pipe.test.ts +1 -1
  48. package/packages/cli/test/cli.test.ts +1 -0
  49. package/packages/cli/test/main.test.ts +1 -0
  50. package/packages/cli/test/profiles/plugins/cordis.yml +122 -0
  51. package/packages/cli/test/profiles.integration.test.ts +40 -23
  52. package/packages/host-webserver/package.json +1 -1
  53. package/apps/web/dist/assets/index-DCkzrlCA.js +0 -25
@@ -10,7 +10,7 @@ import timerPlugin from "@deepseek-ai/cordis-plugin-timer";
10
10
  import { SessionManager } from "@earendil-works/pi-coding-agent";
11
11
  import { afterEach, describe, expect, test, vi } from "vitest";
12
12
  import webServerPlugin from "@pi-harness/host-webserver";
13
- import { PiPluginUiRegistry, PiToolRegistry } from "@pi-harness/core";
13
+ import { PiPluginUiRegistry, PiToolRegistry, PiToolRegistryLeasedError } from "@pi-harness/core";
14
14
  import type { MarketplacePlugin } from "../src/marketplace.js";
15
15
  import apiPlugin from "../src/index.js";
16
16
  import type * as FsPromises from "node:fs/promises";
@@ -2190,12 +2190,167 @@ describe("API gateway plugin", () => {
2190
2190
  }
2191
2191
 
2192
2192
  expect(response.status).toBe(200);
2193
- await expect(response.json()).resolves.toMatchObject({ installed: true, plugin: { id: "skill-guard" } });
2193
+ await expect(response.json()).resolves.toMatchObject({ installed: true, restartRequired: false, plugin: { id: "skill-guard" } });
2194
2194
  expect((await readFile(npmLog, "utf8")).trim()).toMatch(/^install --save-exact --package-lock=false @pi-harness\/plugin-skill-guard@\d/u);
2195
2195
  expect(created).toEqual([expect.objectContaining({ name: "@pi-harness/plugin-skill-guard" })]);
2196
2196
  await expect(readFile(configPath, "utf8")).resolves.toContain('name: "@pi-harness/plugin-skill-guard"');
2197
2197
  });
2198
2198
 
2199
+ // A plugin registers its tools while it activates, and pi-runtime takes the tool registry when it activates, so an installed entry only works if it sits ahead of the runtime inside the runtime's own group.
2200
+ test("installs a marketplace plugin into the runtime's group ahead of the runtime", async () => {
2201
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-api-plugin-placement-"));
2202
+ temporaryDirectories.push(directory);
2203
+ const shimDirectory = join(directory, "bin");
2204
+ await mkdir(shimDirectory);
2205
+ await writeFile(join(directory, "package.json"), '{ "name": "harness" }\n', "utf8");
2206
+ const configPath = join(directory, "profile.yml");
2207
+ await writeFile(
2208
+ configPath,
2209
+ '- id: agent\n name: cordis:group\n group: true\n config:\n - id: tools\n name: "@pi-harness/core/plugins/tools"\n config: {}\n - id: runtime\n name: "@pi-harness/core/plugins/runtime"\n config: {}\n',
2210
+ "utf8",
2211
+ );
2212
+ await writeFile(join(shimDirectory, "npm"), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
2213
+ const context = new Context();
2214
+ contexts.push(context);
2215
+ await context.plugin(webServerPlugin, { host: "127.0.0.1", port: 0 });
2216
+ const session = { sessionId: "marketplace-placement-session", sessionFile: undefined, messages: [], isStreaming: false, subscribe: () => () => {} };
2217
+ context.provide("piRuntime", { session, prompt: () => Promise.resolve(), abort: () => Promise.resolve(), dispose: () => Promise.resolve() } as never);
2218
+ context.provide("piModels", { model: { provider: "test", id: "model" } } as never);
2219
+ context.provide("piHarnessLaunch", { cwd: directory, agentDir: directory, configPath, args: [], requestExit() {} });
2220
+ const runtimeOptions = { id: "runtime", name: "@pi-harness/core/plugins/runtime", config: {} };
2221
+ const runtimeGroup = { data: [{ id: "tools", name: "@pi-harness/core/plugins/tools", config: {} }, runtimeOptions] };
2222
+ const loaderEntries = [
2223
+ // The loader addresses a nested group by its qualified id, while the profile file names the same entry by its own id.
2224
+ { id: "profile:agent", options: { id: "agent", name: "cordis:group" }, subgroup: runtimeGroup },
2225
+ { id: "profile:runtime", options: runtimeOptions, parent: runtimeGroup },
2226
+ ];
2227
+ const created: Array<[unknown, unknown, unknown]> = [];
2228
+ context.reflect.provide("loader", {
2229
+ entries: () => loaderEntries,
2230
+ create: (options: unknown, parent: unknown, position: unknown) => {
2231
+ created.push([options, parent, position]);
2232
+ return Promise.resolve("marketplace-entry");
2233
+ },
2234
+ resolve: () => ({ fiber: { await: () => Promise.resolve() } }),
2235
+ remove: () => Promise.resolve(),
2236
+ });
2237
+ await context.plugin(apiPlugin);
2238
+
2239
+ const originalPath = process.env.PATH ?? "";
2240
+ process.env.PATH = `${shimDirectory}:${originalPath}`;
2241
+ let response: Response;
2242
+ try {
2243
+ response = await fetch(context.webServer.url + "/api/marketplace/install", {
2244
+ method: "POST",
2245
+ headers: { "content-type": "application/json" },
2246
+ body: JSON.stringify({ id: "skill-guard" }),
2247
+ });
2248
+ } finally {
2249
+ process.env.PATH = originalPath;
2250
+ }
2251
+
2252
+ expect(response.status).toBe(200);
2253
+ await expect(response.json()).resolves.toMatchObject({ installed: true, restartRequired: false });
2254
+ expect(created).toEqual([[expect.objectContaining({ id: "marketplace-skill-guard", name: "@pi-harness/plugin-skill-guard" }), "profile:agent", 1]]);
2255
+ await expect(readFile(configPath, "utf8")).resolves.toBe(
2256
+ '- id: agent\n name: cordis:group\n group: true\n config:\n - id: tools\n name: "@pi-harness/core/plugins/tools"\n config: {}\n - id: marketplace-skill-guard\n name: "@pi-harness/plugin-skill-guard"\n config: {}\n - id: runtime\n name: "@pi-harness/core/plugins/runtime"\n config: {}\n',
2257
+ );
2258
+ });
2259
+
2260
+ // The runtime snapshots the tool set when it takes the registry, so a plugin that contributes tools cannot join a harness that is already running. Rolling the install back would leave the user unable to install it at all, so the package and the profile row stay and the console asks for a restart.
2261
+ test("keeps an installed plugin in place when the runtime already leased the tool registry", async () => {
2262
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-api-plugin-leased-"));
2263
+ temporaryDirectories.push(directory);
2264
+ const shimDirectory = join(directory, "bin");
2265
+ await mkdir(shimDirectory);
2266
+ await writeFile(join(directory, "package.json"), '{ "name": "harness", "dependencies": {} }\n', "utf8");
2267
+ const configPath = join(directory, "profile.yml");
2268
+ await writeFile(configPath, '- id: runtime\n name: "@pi-harness/core/plugins/runtime"\n config: {}\n', "utf8");
2269
+ await writeFile(join(shimDirectory, "npm"), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
2270
+ const context = new Context();
2271
+ contexts.push(context);
2272
+ await context.plugin(webServerPlugin, { host: "127.0.0.1", port: 0 });
2273
+ const session = { sessionId: "marketplace-leased-session", sessionFile: undefined, messages: [], isStreaming: false, subscribe: () => () => {} };
2274
+ context.provide("piRuntime", { session, prompt: () => Promise.resolve(), abort: () => Promise.resolve(), dispose: () => Promise.resolve() } as never);
2275
+ context.provide("piModels", { model: { provider: "test", id: "model" } } as never);
2276
+ context.provide("piHarnessLaunch", { cwd: directory, agentDir: directory, configPath, args: [], requestExit() {} });
2277
+ const removed: string[] = [];
2278
+ context.reflect.provide("loader", {
2279
+ entries: () => [],
2280
+ create: () => Promise.resolve("marketplace-entry"),
2281
+ // The loader wraps an activation failure in its own error chain, which is what the gateway has to see through.
2282
+ resolve: () => ({
2283
+ fiber: {
2284
+ await: () => Promise.reject(new Error("failed to apply loader entry", { cause: new PiToolRegistryLeasedError("skill_scan") })),
2285
+ },
2286
+ }),
2287
+ remove: (id: string) => {
2288
+ removed.push(id);
2289
+ return Promise.resolve();
2290
+ },
2291
+ });
2292
+ await context.plugin(apiPlugin);
2293
+
2294
+ const originalPath = process.env.PATH ?? "";
2295
+ process.env.PATH = `${shimDirectory}:${originalPath}`;
2296
+ let response: Response;
2297
+ try {
2298
+ response = await fetch(context.webServer.url + "/api/marketplace/install", {
2299
+ method: "POST",
2300
+ headers: { "content-type": "application/json" },
2301
+ body: JSON.stringify({ id: "skill-guard" }),
2302
+ });
2303
+ } finally {
2304
+ process.env.PATH = originalPath;
2305
+ }
2306
+
2307
+ expect(response.status).toBe(200);
2308
+ await expect(response.json()).resolves.toMatchObject({ installed: true, restartRequired: true, plugin: { id: "skill-guard" } });
2309
+ expect(removed).toEqual(["marketplace-entry"]);
2310
+ await expect(readFile(configPath, "utf8")).resolves.toContain('name: "@pi-harness/plugin-skill-guard"');
2311
+ await expect(readFile(join(directory, "package.json"), "utf8")).resolves.toBe('{ "name": "harness", "dependencies": {} }\n');
2312
+ });
2313
+
2314
+ // Reverting the profile here would leave a plugin that can be switched off but never on again, so the change stays and the plugin comes back on the next start.
2315
+ test("keeps a re-enabled plugin enabled in the profile when the runtime already leased the tool registry", async () => {
2316
+ const context = new Context();
2317
+ contexts.push(context);
2318
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-api-plugin-toggle-leased-"));
2319
+ temporaryDirectories.push(directory);
2320
+ const configPath = join(directory, "profile.yml");
2321
+ const loaderEntry = {
2322
+ id: "profile:marketplace-skill-guard",
2323
+ options: { id: "marketplace-skill-guard", name: "@pi-harness/plugin-skill-guard", config: {} },
2324
+ update: () => Promise.reject(new Error("failed to apply loader entry", { cause: new PiToolRegistryLeasedError("skill_scan") })),
2325
+ };
2326
+ await writeFile(
2327
+ configPath,
2328
+ '- id: marketplace-skill-guard\n name: "@pi-harness/plugin-skill-guard"\n disabled: true\n config: {}\n- id: runtime\n name: "@pi-harness/core/plugins/runtime"\n config: {}\n',
2329
+ "utf8",
2330
+ );
2331
+ await context.plugin(webServerPlugin, { host: "127.0.0.1", port: 0 });
2332
+ const session = { sessionId: "plugin-toggle-leased-session", sessionFile: undefined, messages: [], isStreaming: false, subscribe: () => () => {} };
2333
+ context.provide("piRuntime", { session, prompt: () => Promise.resolve(), abort: () => Promise.resolve(), dispose: () => Promise.resolve() } as never);
2334
+ context.provide("piModels", { model: { provider: "test", id: "model" }, runtime: { getModels: () => [], getModel: () => undefined } } as never);
2335
+ context.provide("piHarnessLaunch", { cwd: directory, agentDir: directory, configPath, args: [], requestExit() {} });
2336
+ context.reflect.provide("loader", {
2337
+ *entries() {
2338
+ yield loaderEntry;
2339
+ },
2340
+ });
2341
+ await context.plugin(apiPlugin);
2342
+
2343
+ const response = await fetch(context.webServer.url + "/api/plugins/toggle", {
2344
+ method: "POST",
2345
+ headers: { "content-type": "application/json" },
2346
+ body: JSON.stringify({ id: "marketplace-skill-guard", enabled: true }),
2347
+ });
2348
+
2349
+ expect(response.status).toBe(200);
2350
+ await expect(response.json()).resolves.toMatchObject({ restartRequired: true, plugin: { id: "marketplace-skill-guard" } });
2351
+ await expect(readFile(configPath, "utf8")).resolves.not.toContain("disabled: true");
2352
+ });
2353
+
2199
2354
  test("locks marketplace installation before reading a request body", async () => {
2200
2355
  const cwd = await mkdtemp(join(tmpdir(), "pi-harness-api-plugin-install-lock-"));
2201
2356
  temporaryDirectories.push(cwd);
@@ -9,29 +9,79 @@ const execFileAsync = promisify(execFile);
9
9
  const fixtures: string[] = [];
10
10
  const repositoryRoot = resolve(import.meta.dirname, "../../..");
11
11
 
12
- // Stands in for npm so the smoke test can be exercised without packing and globally installing the real workspace: `pack` reports one tarball name per requested workspace and `install` lays out the tree the script inspects, optionally without the files the root bin map points at.
13
- const fakeNpmSource = `import { mkdirSync, writeFileSync } from "node:fs";
12
+ // Stands in for the launcher's own @pi-harness/core inside the installed tree, so the smoke test can drive the marketplace stage without a real global install. Both modules are reduced to the behaviour that stage depends on.
13
+ const fakeCoreSource = `import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { join } from "node:path";
15
+
16
+ export const prepareHarnessProfile = ({ builtinProfilePath, profileName, directory }) => {
17
+ const profileDirectory = join(directory, "profiles", profileName);
18
+ mkdirSync(profileDirectory, { recursive: true });
19
+ writeFileSync(join(directory, "package.json"), JSON.stringify({ name: "pi-harness-home", private: true }));
20
+ const profilePath = join(profileDirectory, "cordis.yml");
21
+ writeFileSync(profilePath, readFileSync(builtinProfilePath, "utf8"));
22
+ return Promise.resolve(profilePath);
23
+ };
24
+ `;
25
+
26
+ const fakeResolveSource = `import { existsSync } from "node:fs";
14
27
  import { dirname, join } from "node:path";
28
+
29
+ export const resolvePluginEntry = (fromFile, name) => {
30
+ let directory = dirname(fromFile);
31
+ for (;;) {
32
+ const candidate = join(directory, "node_modules", ...name.split("/"), "dist", "index.js");
33
+ if (existsSync(candidate)) return candidate;
34
+ const parent = dirname(directory);
35
+ if (parent === directory) return undefined;
36
+ directory = parent;
37
+ }
38
+ };
39
+ `;
40
+
41
+ // Stands in for npm so the smoke test can be exercised without packing and globally installing the real workspace: `pack` reports one tarball name per requested workspace, a `--prefix` install lays out the tree the script inspects, optionally without the files the root bin map points at, and a plain install lays out the marketplace package in the directory it was run from.
42
+ const fakeNpmSource = `import { mkdirSync, writeFileSync } from "node:fs";
43
+ import { basename, dirname, join } from "node:path";
15
44
  import process from "node:process";
16
45
 
17
46
  const args = process.argv.slice(2);
18
47
  if (args[0] === "pack") {
19
48
  const workspaces = args.filter((argument, index) => args[index - 1] === "--workspace");
20
- process.stdout.write((workspaces.length === 0 ? ["harness.tgz"] : workspaces.map((name) => name.slice(name.indexOf("/") + 1) + ".tgz")).join("\\n") + "\\n");
49
+ // The root is packed with its scripts, so prepack's own build output shares this stdout with the tarball name.
50
+ const lines = workspaces.length === 0 ? ["> pi-harness build:web", "built 75 plugin packages in 3 waves", "harness.tgz"] : workspaces.map((name) => name.slice(name.indexOf("/") + 1) + ".tgz");
51
+ process.stdout.write(lines.join("\\n") + "\\n");
21
52
  process.exit(0);
22
53
  }
23
54
  if (args[0] !== "install") process.exit(1);
24
- const prefix = args[args.indexOf("--prefix") + 1];
25
- const harnessRoot = join(prefix, "lib", "node_modules", "@pi-harness", "pi-harness");
26
- const agentRoot = join(harnessRoot, "node_modules", "@earendil-works", "pi-coding-agent");
27
55
  const write = (path, content) => {
28
56
  mkdirSync(dirname(path), { recursive: true });
29
57
  writeFileSync(path, content);
30
58
  };
59
+ const prefixIndex = args.indexOf("--prefix");
60
+ if (prefixIndex < 0) {
61
+ if (process.env.PACKED_PACKAGE_FIXTURE_MARKETPLACE !== "0") {
62
+ const name = "@pi-harness/" + basename(args[args.length - 1]).replace(/\\.tgz$/u, "");
63
+ const root = join(process.cwd(), "node_modules", ...name.split("/"));
64
+ write(join(root, "package.json"), JSON.stringify({ name, version: "9.9.9", type: "module", exports: { ".": { import: "./dist/index.js" } } }));
65
+ write(join(root, "dist", "index.js"), "export default {};\\n");
66
+ }
67
+ process.exit(0);
68
+ }
69
+ const prefix = args[prefixIndex + 1];
70
+ const harnessRoot = join(prefix, "lib", "node_modules", "@pi-harness", "pi-harness");
71
+ const agentRoot = join(harnessRoot, "node_modules", "@earendil-works", "pi-coding-agent");
31
72
  const bin = { "pi-harness": "./apps/web/server-dist/bin.js", pih: "./packages/cli/dist/bin.js" };
32
73
  write(join(harnessRoot, "package.json"), JSON.stringify({ name: "@pi-harness/pi-harness", version: "9.9.9", bin, dependencies: { "@earendil-works/pi-coding-agent": "0.84.4" } }));
33
74
  write(join(agentRoot, "package.json"), JSON.stringify({ name: "@earendil-works/pi-coding-agent", version: "0.84.4", dependencies: {} }));
34
75
  write(join(agentRoot, "dist", "cli", "args.js"), "");
76
+ const profileEntries = ["- id: webserver\\n name: \\"@pi-harness/host-webserver\\"\\n"];
77
+ if (process.env.PACKED_PACKAGE_FIXTURE_BUNDLED_PLUGIN === "1") profileEntries.push("- id: modlens\\n name: \\"@pi-harness/plugin-modlens\\"\\n");
78
+ write(join(harnessRoot, "apps", "web", "profile", "cordis.yml"), profileEntries.join(""));
79
+ const shippedDependencies = process.env.PACKED_PACKAGE_FIXTURE_SHIPPED_DEP === "1" ? { "@pi-harness/client-web": "9.9.9" } : undefined;
80
+ write(join(harnessRoot, "apps", "web", "package.json"), JSON.stringify({ name: "@pi-harness/web", private: true, dependencies: shippedDependencies }));
81
+ if (process.env.PACKED_PACKAGE_FIXTURE_PROFILE_ENTRY !== "0") write(join(harnessRoot, "node_modules", "@pi-harness", "host-webserver", "dist", "index.js"), "export default {};\\n");
82
+ if (process.env.PACKED_PACKAGE_FIXTURE_BUNDLED_PLUGIN === "1") write(join(harnessRoot, "node_modules", "@pi-harness", "plugin-modlens", "dist", "index.js"), "export default {};\\n");
83
+ write(join(harnessRoot, "node_modules", "@pi-harness", "core", "dist", "index.js"), process.env.PACKED_PACKAGE_FIXTURE_CORE);
84
+ write(join(harnessRoot, "node_modules", "@pi-harness", "core", "dist", "plugin-resolve.js"), process.env.PACKED_PACKAGE_FIXTURE_RESOLVE);
35
85
  if (process.env.PACKED_PACKAGE_FIXTURE_BINS === "1") for (const target of Object.values(bin)) write(join(harnessRoot, target), "");
36
86
  `;
37
87
 
@@ -43,9 +93,26 @@ const createFakeNpm = async (): Promise<string> => {
43
93
  return fakeNpm;
44
94
  };
45
95
 
46
- const runSmokeTest = async (fakeNpm: string, bins: boolean): ReturnType<typeof execFileAsync> =>
96
+ const runSmokeTest = async (
97
+ fakeNpm: string,
98
+ bins: boolean,
99
+ marketplace = true,
100
+ profileEntry = true,
101
+ shippedDependency = false,
102
+ bundledPlugin = false,
103
+ ): ReturnType<typeof execFileAsync> =>
47
104
  execFileAsync(process.execPath, [resolve(repositoryRoot, "scripts/test-packed-package.mjs")], {
48
- env: { ...process.env, npm_execpath: fakeNpm, PACKED_PACKAGE_FIXTURE_BINS: bins ? "1" : "0" },
105
+ env: {
106
+ ...process.env,
107
+ npm_execpath: fakeNpm,
108
+ PACKED_PACKAGE_FIXTURE_BINS: bins ? "1" : "0",
109
+ PACKED_PACKAGE_FIXTURE_CORE: fakeCoreSource,
110
+ PACKED_PACKAGE_FIXTURE_RESOLVE: fakeResolveSource,
111
+ PACKED_PACKAGE_FIXTURE_MARKETPLACE: marketplace ? "1" : "0",
112
+ PACKED_PACKAGE_FIXTURE_PROFILE_ENTRY: profileEntry ? "1" : "0",
113
+ PACKED_PACKAGE_FIXTURE_SHIPPED_DEP: shippedDependency ? "1" : "0",
114
+ PACKED_PACKAGE_FIXTURE_BUNDLED_PLUGIN: bundledPlugin ? "1" : "0",
115
+ },
49
116
  });
50
117
 
51
118
  afterEach(async () => {
@@ -53,7 +120,7 @@ afterEach(async () => {
53
120
  });
54
121
 
55
122
  describe("packed package smoke test", () => {
56
- it("accepts a tarball whose bin entrypoints are present", async () => {
123
+ it("accepts a tarball whose bin entrypoints are present and whose marketplace install is loadable", async () => {
57
124
  const fakeNpm = await createFakeNpm();
58
125
 
59
126
  const { stdout } = await runSmokeTest(fakeNpm, true);
@@ -62,9 +129,38 @@ describe("packed package smoke test", () => {
62
129
  });
63
130
 
64
131
  it("rejects a tarball that ships no runnable bin entrypoint", async () => {
65
- // `npm pack --ignore-scripts` never runs prepack, so an unbuilt workspace produces a tarball with a bin map pointing at files the tarball does not contain.
132
+ // A `files` allowlist that omits build output, or a prepack that failed to produce it, ships a bin map pointing at files the tarball does not contain.
66
133
  const fakeNpm = await createFakeNpm();
67
134
 
68
135
  await expect(runSmokeTest(fakeNpm, false)).rejects.toThrow(/missing the pi-harness entrypoint \.\/apps\/web\/server-dist\/bin\.js/u);
69
136
  });
137
+
138
+ it("rejects an install whose shipped profile enables an entry the tarball never brings in", async () => {
139
+ // The 0.1.29 launcher shipped a profile naming 45 packages it did not depend on, so a clean install failed to boot on the first entry the loader could not import.
140
+ const fakeNpm = await createFakeNpm();
141
+
142
+ await expect(runSmokeTest(fakeNpm, true, true, false)).rejects.toThrow(/enables 1 entr\(ies\) the install does not contain: @pi-harness\/host-webserver/u);
143
+ });
144
+
145
+ it("rejects an install whose shipped profile bundles a pluggable plugin", async () => {
146
+ // Official plugins are installed from the plugin center like community ones, so a profile entry for one would hand every fresh install a plugin the user never asked for.
147
+ const fakeNpm = await createFakeNpm();
148
+
149
+ await expect(runSmokeTest(fakeNpm, true, true, true, false, true)).rejects.toThrow(/enables 1 pluggable plugin\(s\): @pi-harness\/plugin-modlens/u);
150
+ });
151
+
152
+ it("rejects an install whose shipped workspace depends on a package npm can never fetch", async () => {
153
+ // apps/web is built out of two private workspaces, so the dependency list 0.1.29 shipped made every npm command run inside the installation fail with E404 on @pi-harness/client-web.
154
+ const fakeNpm = await createFakeNpm();
155
+
156
+ await expect(runSmokeTest(fakeNpm, true, true, true, true)).rejects.toThrow(
157
+ /apps\/web\/package\.json depends on @pi-harness\/client-web, which the install neither contains nor can fetch/u,
158
+ );
159
+ });
160
+
161
+ it("rejects a launcher whose marketplace install lands somewhere the loader cannot resolve", async () => {
162
+ const fakeNpm = await createFakeNpm();
163
+
164
+ await expect(runSmokeTest(fakeNpm, true, false)).rejects.toThrow(/installed into the harness home but the loader cannot resolve it/u);
165
+ });
70
166
  });
@@ -70,7 +70,8 @@ describe("release contract", () => {
70
70
 
71
71
  test("prepack builds every workspace that a root bin points at", () => {
72
72
  const root = readJson("package.json") as { bin: Record<string, string>; scripts: Record<string, string> };
73
- expect(root.scripts.prepack).toBe("npm run build:web");
73
+ // The rest of prepack prepares the manifests the tarball ships, which package-install.test.ts owns; this test only cares that the build still runs before anything is packed.
74
+ expect(root.scripts.prepack).toContain("npm run build:web");
74
75
  const built = [...root.scripts["build:web"]!.matchAll(/npm run build -w (\S+)/gu)].map((match) => match[1]);
75
76
  for (const target of Object.values(root.bin)) expect(built, `${target} is not built by build:web`).toContain(workspaceNameFor(target));
76
77
  expect(built.indexOf("@pi-harness/core")).toBeLessThan(built.indexOf("@pi-harness/cli"));
@@ -97,8 +98,8 @@ describe("release contract", () => {
97
98
  expect(core.files).not.toContain("profiles");
98
99
  });
99
100
 
100
- test("the published launcher declares every plugin package its shipped profiles load", () => {
101
- // Every plugin in a shipped profile is now an ordinary npm package, so the package a user installs has to pull each one like any other dependency.
101
+ test("the published launcher declares every package its shipped profiles load, and no plugin", () => {
102
+ // A profile entry is imported by its bare specifier, so the package a user installs has to pull the infrastructure each entry names. Pluggable plugins are the exception by design: they are ordinary npm packages installed from the plugin center, so bundling one would put it in every install whether the user wanted it or not.
102
103
  const root = readJson("package.json") as { name: string; dependencies: Record<string, string> };
103
104
  const required = new Map<string, string>();
104
105
  for (const file of sourceFiles(resolve(repositoryRoot, "packages/cli/profiles"), ".yml")) {
@@ -106,8 +107,12 @@ describe("release contract", () => {
106
107
  required.set(packageNameOf(match[1] ?? ""), relative(repositoryRoot, file));
107
108
  }
108
109
  const external = [...required].filter(([name]) => !name.includes(":"));
109
- expect(external.filter(([name]) => name.startsWith("@pi-harness/plugin-")).length).toBeGreaterThan(0);
110
- for (const [name, file] of external) expect(root.dependencies[name], `${name} (loaded by ${file}) is not declared by ${root.name}`).toBeDefined();
110
+ expect(external.length).toBeGreaterThan(0);
111
+ for (const [name, file] of external) {
112
+ expect(name.startsWith("@pi-harness/plugin-"), `${name} (loaded by ${file}) is a pluggable plugin, which a shipped profile must not enable`).toBe(false);
113
+ expect(root.dependencies[name], `${name} (loaded by ${file}) is not declared by ${root.name}`).toBeDefined();
114
+ }
115
+ expect(Object.keys(root.dependencies).filter((name) => name.startsWith("@pi-harness/plugin-"))).toEqual([]);
111
116
  });
112
117
 
113
118
  test("the plugin API declares every package its sources import as a peer", () => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/web-app",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "private": true,
5
5
  "description": "Patchable Web application bundle for Pi Harness",
6
6
  "homepage": "https://github.com/pi-harness/pi-harness#readme",
@@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { coreUpdateNotice } from "@pi-harness/core";
6
+ import { coreUpdateNotice, harnessHomeDirectory } from "@pi-harness/core";
7
7
  import { runCli } from "./main.js";
8
8
  import { shouldRelaunchForDevelopmentProfile, superviseDevelopmentProcess } from "./relaunch.js";
9
9
  const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
@@ -12,6 +12,7 @@ const agentDir = configuredAgentDir === undefined || configuredAgentDir.length =
12
12
  const environment = {
13
13
  cwd: process.cwd(),
14
14
  agentDir,
15
+ harnessHome: harnessHomeDirectory(),
15
16
  version: packageJson.version,
16
17
  supervised: process.env.PI_HARNESS_SUPERVISED === "1",
17
18
  stdin: process.stdin,
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ import type { Readable, Writable } from "node:stream";
2
2
  export interface CliEnvironment {
3
3
  readonly cwd: string;
4
4
  readonly agentDir: string;
5
+ /** Directory that owns the booted copy of a built-in profile and the node_modules the marketplace installs into. */
6
+ readonly harnessHome: string;
5
7
  readonly version: string;
6
8
  readonly stdin: Readable;
7
9
  readonly stdout: Writable;
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAOtD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAClE;AAgCD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAM7C,wBAAsB,MAAM,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAqLpG"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAOtD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oHAAoH;IACpH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAClE;AAgCD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAM7C,wBAAsB,MAAM,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA4LpG"}
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
- import { bootHarness, provideLaunchContext, provideStdioContext, resolveProfileConfig } from "@pi-harness/core";
2
+ import { bootHarness, prepareHarnessProfile, provideLaunchContext, provideStdioContext, resolveProfileConfig } from "@pi-harness/core";
3
3
  import { CliUsageError, parseLauncherArgs } from "./args.js";
4
4
  import { NodeStdio } from "./node-stdio.js";
5
5
  import { BUILTIN_PROFILES, BUILTIN_PROFILES_DIR } from "./profiles.js";
@@ -61,6 +61,13 @@ export async function runCli(_args, _environment) {
61
61
  : { configPath: invocation.configPath }),
62
62
  cwd: environment.cwd,
63
63
  });
64
+ // A built-in profile is a template: the copy under the harness home is what boots, because that is the file the web console appends marketplace entries to and the directory those packages are installed beside. An explicit --config already names a file the user owns, so it is booted as given.
65
+ if (invocation.configPath === undefined)
66
+ configPath = await prepareHarnessProfile({
67
+ builtinProfilePath: configPath,
68
+ profileName: invocation.profile ?? "default",
69
+ directory: environment.harnessHome,
70
+ });
64
71
  if (invocation.dumpConfig) {
65
72
  environment.stdout.write(await readFile(configPath, "utf8"));
66
73
  return 0;
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cli",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "private": true,
5
5
  "description": "Plugin-first Pi Harness CLI",
6
6
  "homepage": "https://github.com/pi-harness/pi-harness#readme",
@@ -26,97 +26,10 @@
26
26
  - bash
27
27
  - edit
28
28
  - write
29
- - id: agent-teams
30
- name: "@pi-harness/plugin-agent-teams"
31
- config: {}
32
- - id: modlens
33
- name: "@pi-harness/plugin-modlens"
34
- config: {}
35
- - id: vision-toolkit
36
- name: "@pi-harness/plugin-vision-toolkit"
37
- config: {}
38
- - id: git-time-capsule
39
- name: "@pi-harness/plugin-git-time-capsule"
40
- config: {}
41
- - id: dependency-checker
42
- name: "@pi-harness/plugin-dependency-checker"
43
- config: {}
44
- - id: at-file
45
- name: "@pi-harness/plugin-at-file"
46
- config: {}
47
- - id: test-harness
48
- name: "@pi-harness/plugin-test-harness"
49
- config:
50
- timeoutMs: 120000
51
- - id: session-insights
52
- name: "@pi-harness/plugin-session-insights"
53
- config: {}
54
- - id: readme-gen
55
- name: "@pi-harness/plugin-readme-gen"
56
- config: {}
57
- - id: i18n-pair
58
- name: "@pi-harness/plugin-i18n-pair"
59
- config: {}
60
- - id: cleaner
61
- name: "@pi-harness/plugin-cleaner"
62
- config: {}
63
- - id: sql-lens
64
- name: "@pi-harness/plugin-sql-lens"
65
- config:
66
- timeoutMs: 5000
67
- - id: docker-sandbox
68
- name: "@pi-harness/plugin-docker-sandbox"
69
- config: {}
70
- - id: mcp-client
71
- name: "@pi-harness/plugin-mcp-client"
72
- config: {}
73
- - id: browser-fetch
74
- name: "@pi-harness/plugin-browser-fetch"
75
- config: {}
76
- - id: browser-session
77
- name: "@pi-harness/plugin-browser-session"
78
- config: {}
79
- - id: plugin-stars
80
- name: "@pi-harness/plugin-plugin-stars"
81
- config: {}
82
- - id: yaml-validator
83
- name: "@pi-harness/plugin-yaml-validator"
84
- config: {}
85
- - id: plugin-dev
86
- name: "@pi-harness/plugin-plugin-dev"
87
- config: {}
88
- - id: openpets
89
- name: "@pi-harness/plugin-openpets"
90
- config: {}
91
- - id: session-bridge
92
- name: "@pi-harness/plugin-session-bridge"
93
- config: {}
94
- - id: skill-guard
95
- name: "@pi-harness/plugin-skill-guard"
96
- config: {}
97
- - id: recall-unread
98
- name: "@pi-harness/plugin-recall-unread"
99
- config: {}
100
- - id: turn-rewind
101
- name: "@pi-harness/plugin-turn-rewind"
102
- config: {}
103
- - id: context-doctor
104
- name: "@pi-harness/plugin-context-doctor"
105
- config: {}
106
29
  - id: runtime
107
30
  name: "@pi-harness/core/plugins/runtime"
108
31
  config:
109
32
  thinkingLevel: medium
110
- - id: context
111
- name: "@pi-harness/plugin-context"
112
- config: {}
113
- - id: token-guard
114
- name: "@pi-harness/plugin-token-guard"
115
- config:
116
- maxPercent: 90
117
- - id: fail-logger
118
- name: "@pi-harness/plugin-fail-logger"
119
- config: {}
120
33
  - id: stdio
121
34
  name: "@pi-harness/core/plugins/stdio"
122
35
  config: {}
@@ -4,7 +4,7 @@ import { readFileSync } from "node:fs";
4
4
  import { homedir } from "node:os";
5
5
  import { join, resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
- import { coreUpdateNotice } from "@pi-harness/core";
7
+ import { coreUpdateNotice, harnessHomeDirectory } from "@pi-harness/core";
8
8
  import { runCli, type CliEnvironment } from "./main.js";
9
9
  import { shouldRelaunchForDevelopmentProfile, superviseDevelopmentProcess } from "./relaunch.js";
10
10
 
@@ -16,6 +16,7 @@ const agentDir = configuredAgentDir === undefined || configuredAgentDir.length =
16
16
  const environment: CliEnvironment = {
17
17
  cwd: process.cwd(),
18
18
  agentDir,
19
+ harnessHome: harnessHomeDirectory(),
19
20
  version: packageJson.version,
20
21
  supervised: process.env.PI_HARNESS_SUPERVISED === "1",
21
22
  stdin: process.stdin,