@pi-harness/pi-harness 0.1.1

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 (185) hide show
  1. package/README.md +161 -0
  2. package/apps/web/dist/assets/index-C4tLweAB.js +20 -0
  3. package/apps/web/dist/assets/index-DPgRbQ4_.css +1 -0
  4. package/apps/web/dist/index.html +14 -0
  5. package/apps/web/index.html +13 -0
  6. package/apps/web/package.json +24 -0
  7. package/apps/web/profile/cordis.yml +44 -0
  8. package/apps/web/server-dist/bin.d.ts +3 -0
  9. package/apps/web/server-dist/bin.d.ts.map +1 -0
  10. package/apps/web/server-dist/bin.js +67 -0
  11. package/apps/web/server-dist/bin.js.map +1 -0
  12. package/apps/web/src/command-palette.ts +84 -0
  13. package/apps/web/src/file-diff.ts +42 -0
  14. package/apps/web/src/main.ts +12 -0
  15. package/apps/web/src/runtime.css +4 -0
  16. package/apps/web/src/server/bin.ts +64 -0
  17. package/apps/web/src/style.css +7 -0
  18. package/apps/web/tsconfig.build.json +1 -0
  19. package/apps/web/tsconfig.json +1 -0
  20. package/package.json +48 -0
  21. package/packages/api-gateway/dist/index.d.ts +8 -0
  22. package/packages/api-gateway/dist/index.d.ts.map +1 -0
  23. package/packages/api-gateway/dist/index.js +582 -0
  24. package/packages/api-gateway/dist/index.js.map +1 -0
  25. package/packages/api-gateway/package.json +29 -0
  26. package/packages/api-gateway/src/index.ts +577 -0
  27. package/packages/api-gateway/test/index.test.ts +327 -0
  28. package/packages/api-gateway/tsconfig.build.json +1 -0
  29. package/packages/api-gateway/tsconfig.json +1 -0
  30. package/packages/bundle-web-app/cordis.patch.yml +12 -0
  31. package/packages/bundle-web-app/dist/index.d.ts +12 -0
  32. package/packages/bundle-web-app/dist/index.d.ts.map +1 -0
  33. package/packages/bundle-web-app/dist/index.js +63 -0
  34. package/packages/bundle-web-app/dist/index.js.map +1 -0
  35. package/packages/bundle-web-app/package.json +30 -0
  36. package/packages/bundle-web-app/src/index.ts +69 -0
  37. package/packages/bundle-web-app/test/index.test.ts +29 -0
  38. package/packages/bundle-web-app/tsconfig.build.json +1 -0
  39. package/packages/bundle-web-app/tsconfig.json +1 -0
  40. package/packages/cli/dist/args.d.ts +16 -0
  41. package/packages/cli/dist/args.d.ts.map +1 -0
  42. package/packages/cli/dist/args.js +53 -0
  43. package/packages/cli/dist/args.js.map +1 -0
  44. package/packages/cli/dist/bin.d.ts +3 -0
  45. package/packages/cli/dist/bin.d.ts.map +1 -0
  46. package/packages/cli/dist/bin.js +40 -0
  47. package/packages/cli/dist/bin.js.map +1 -0
  48. package/packages/cli/dist/main.d.ts +14 -0
  49. package/packages/cli/dist/main.d.ts.map +1 -0
  50. package/packages/cli/dist/main.js +148 -0
  51. package/packages/cli/dist/main.js.map +1 -0
  52. package/packages/cli/dist/node-stdio.d.ts +10 -0
  53. package/packages/cli/dist/node-stdio.d.ts.map +1 -0
  54. package/packages/cli/dist/node-stdio.js +34 -0
  55. package/packages/cli/dist/node-stdio.js.map +1 -0
  56. package/packages/cli/dist/relaunch.d.ts +5 -0
  57. package/packages/cli/dist/relaunch.d.ts.map +1 -0
  58. package/packages/cli/dist/relaunch.js +52 -0
  59. package/packages/cli/dist/relaunch.js.map +1 -0
  60. package/packages/cli/package.json +25 -0
  61. package/packages/cli/src/args.ts +50 -0
  62. package/packages/cli/src/bin.ts +41 -0
  63. package/packages/cli/src/main.ts +155 -0
  64. package/packages/cli/src/node-stdio.ts +40 -0
  65. package/packages/cli/src/relaunch.ts +48 -0
  66. package/packages/cli/test/args.test.ts +28 -0
  67. package/packages/cli/test/cli.test.ts +153 -0
  68. package/packages/cli/test/relaunch.test.ts +29 -0
  69. package/packages/cli/tsconfig.build.json +11 -0
  70. package/packages/cli/tsconfig.json +10 -0
  71. package/packages/client-web/dist/control-room.d.ts +102 -0
  72. package/packages/client-web/dist/control-room.d.ts.map +1 -0
  73. package/packages/client-web/dist/control-room.js +12 -0
  74. package/packages/client-web/dist/control-room.js.map +1 -0
  75. package/packages/client-web/dist/design-contract.d.ts +85 -0
  76. package/packages/client-web/dist/design-contract.d.ts.map +1 -0
  77. package/packages/client-web/dist/design-contract.js +99 -0
  78. package/packages/client-web/dist/design-contract.js.map +1 -0
  79. package/packages/client-web/dist/index.d.ts +17 -0
  80. package/packages/client-web/dist/index.d.ts.map +1 -0
  81. package/packages/client-web/dist/index.js +19 -0
  82. package/packages/client-web/dist/index.js.map +1 -0
  83. package/packages/client-web/dist/react-room.d.ts +6 -0
  84. package/packages/client-web/dist/react-room.d.ts.map +1 -0
  85. package/packages/client-web/dist/react-room.js +103 -0
  86. package/packages/client-web/dist/react-room.js.map +1 -0
  87. package/packages/client-web/package.json +29 -0
  88. package/packages/client-web/src/control-room.ts +10 -0
  89. package/packages/client-web/src/design-contract.ts +112 -0
  90. package/packages/client-web/src/index.ts +21 -0
  91. package/packages/client-web/src/react-room.tsx +78 -0
  92. package/packages/client-web/test/design-contract.test.ts +24 -0
  93. package/packages/client-web/tsconfig.build.json +1 -0
  94. package/packages/client-web/tsconfig.json +1 -0
  95. package/packages/core/dist/boot.d.ts +13 -0
  96. package/packages/core/dist/boot.d.ts.map +1 -0
  97. package/packages/core/dist/boot.js +96 -0
  98. package/packages/core/dist/boot.js.map +1 -0
  99. package/packages/core/dist/context.d.ts +3 -0
  100. package/packages/core/dist/context.d.ts.map +1 -0
  101. package/packages/core/dist/context.js +2 -0
  102. package/packages/core/dist/context.js.map +1 -0
  103. package/packages/core/dist/index.d.ts +7 -0
  104. package/packages/core/dist/index.d.ts.map +1 -0
  105. package/packages/core/dist/index.js +6 -0
  106. package/packages/core/dist/index.js.map +1 -0
  107. package/packages/core/dist/plugins/model.d.ts +8 -0
  108. package/packages/core/dist/plugins/model.d.ts.map +1 -0
  109. package/packages/core/dist/plugins/model.js +12 -0
  110. package/packages/core/dist/plugins/model.js.map +1 -0
  111. package/packages/core/dist/plugins/models.d.ts +16 -0
  112. package/packages/core/dist/plugins/models.d.ts.map +1 -0
  113. package/packages/core/dist/plugins/models.js +24 -0
  114. package/packages/core/dist/plugins/models.js.map +1 -0
  115. package/packages/core/dist/plugins/resources.d.ts +18 -0
  116. package/packages/core/dist/plugins/resources.d.ts.map +1 -0
  117. package/packages/core/dist/plugins/resources.js +48 -0
  118. package/packages/core/dist/plugins/resources.js.map +1 -0
  119. package/packages/core/dist/plugins/runtime.d.ts +14 -0
  120. package/packages/core/dist/plugins/runtime.d.ts.map +1 -0
  121. package/packages/core/dist/plugins/runtime.js +68 -0
  122. package/packages/core/dist/plugins/runtime.js.map +1 -0
  123. package/packages/core/dist/plugins/session.d.ts +15 -0
  124. package/packages/core/dist/plugins/session.d.ts.map +1 -0
  125. package/packages/core/dist/plugins/session.js +20 -0
  126. package/packages/core/dist/plugins/session.js.map +1 -0
  127. package/packages/core/dist/plugins/stdio.d.ts +8 -0
  128. package/packages/core/dist/plugins/stdio.d.ts.map +1 -0
  129. package/packages/core/dist/plugins/stdio.js +20 -0
  130. package/packages/core/dist/plugins/stdio.js.map +1 -0
  131. package/packages/core/dist/plugins/tools.d.ts +13 -0
  132. package/packages/core/dist/plugins/tools.d.ts.map +1 -0
  133. package/packages/core/dist/plugins/tools.js +17 -0
  134. package/packages/core/dist/plugins/tools.js.map +1 -0
  135. package/packages/core/dist/profile.d.ts +8 -0
  136. package/packages/core/dist/profile.d.ts.map +1 -0
  137. package/packages/core/dist/profile.js +28 -0
  138. package/packages/core/dist/profile.js.map +1 -0
  139. package/packages/core/dist/runtime.d.ts +16 -0
  140. package/packages/core/dist/runtime.d.ts.map +1 -0
  141. package/packages/core/dist/runtime.js +33 -0
  142. package/packages/core/dist/runtime.js.map +1 -0
  143. package/packages/core/dist/services.d.ts +63 -0
  144. package/packages/core/dist/services.d.ts.map +1 -0
  145. package/packages/core/dist/services.js +39 -0
  146. package/packages/core/dist/services.js.map +1 -0
  147. package/packages/core/dist/stdio.d.ts +25 -0
  148. package/packages/core/dist/stdio.d.ts.map +1 -0
  149. package/packages/core/dist/stdio.js +74 -0
  150. package/packages/core/dist/stdio.js.map +1 -0
  151. package/packages/core/package.json +44 -0
  152. package/packages/core/profiles/default/cordis.yml +35 -0
  153. package/packages/core/profiles/development/cordis.yml +47 -0
  154. package/packages/core/src/boot.ts +103 -0
  155. package/packages/core/src/context.ts +3 -0
  156. package/packages/core/src/index.ts +6 -0
  157. package/packages/core/src/plugins/model.ts +12 -0
  158. package/packages/core/src/plugins/models.ts +32 -0
  159. package/packages/core/src/plugins/resources.ts +57 -0
  160. package/packages/core/src/plugins/runtime.ts +73 -0
  161. package/packages/core/src/plugins/session.ts +27 -0
  162. package/packages/core/src/plugins/stdio.ts +20 -0
  163. package/packages/core/src/plugins/tools.ts +23 -0
  164. package/packages/core/src/profile.ts +31 -0
  165. package/packages/core/src/runtime.ts +39 -0
  166. package/packages/core/src/services.ts +105 -0
  167. package/packages/core/src/stdio.ts +88 -0
  168. package/packages/core/test/boot.test.ts +86 -0
  169. package/packages/core/test/profile.test.ts +39 -0
  170. package/packages/core/test/profiles.integration.test.ts +93 -0
  171. package/packages/core/test/runtime-fixture.ts +31 -0
  172. package/packages/core/test/runtime.test.ts +54 -0
  173. package/packages/core/test/services.test.ts +131 -0
  174. package/packages/core/test/stdio.test.ts +87 -0
  175. package/packages/core/tsconfig.build.json +10 -0
  176. package/packages/core/tsconfig.json +10 -0
  177. package/packages/host-webserver/dist/index.d.ts +29 -0
  178. package/packages/host-webserver/dist/index.d.ts.map +1 -0
  179. package/packages/host-webserver/dist/index.js +73 -0
  180. package/packages/host-webserver/dist/index.js.map +1 -0
  181. package/packages/host-webserver/package.json +27 -0
  182. package/packages/host-webserver/src/index.ts +97 -0
  183. package/packages/host-webserver/test/index.test.ts +43 -0
  184. package/packages/host-webserver/tsconfig.build.json +1 -0
  185. package/packages/host-webserver/tsconfig.json +1 -0
@@ -0,0 +1,40 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import type { Readable, Writable } from "node:stream";
3
+ import type { PiHarnessStdio } from "@pi-harness/core";
4
+
5
+ type TerminalReadable = Readable & { isTTY?: boolean };
6
+
7
+ export class NodeStdio implements PiHarnessStdio {
8
+ readonly #input: TerminalReadable;
9
+ readonly #output: Writable;
10
+ readonly #error: Writable;
11
+
12
+ constructor(input: Readable, output: Writable, error: Writable) {
13
+ this.#input = input;
14
+ this.#output = output;
15
+ this.#error = error;
16
+ }
17
+
18
+ async readPrompt(): Promise<string> {
19
+ if (this.#input.isTTY === true) {
20
+ const readline = createInterface({ input: this.#input, output: this.#output });
21
+ try {
22
+ return await readline.question("> ");
23
+ } finally {
24
+ readline.close();
25
+ }
26
+ }
27
+ this.#input.setEncoding("utf8");
28
+ let content = "";
29
+ for await (const chunk of this.#input) content += String(chunk);
30
+ return content.trimEnd();
31
+ }
32
+
33
+ writeOutput(text: string): void {
34
+ this.#output.write(text);
35
+ }
36
+
37
+ writeError(text: string): void {
38
+ this.#error.write(text);
39
+ }
40
+ }
@@ -0,0 +1,48 @@
1
+ import { spawn, type SpawnOptions } from "node:child_process";
2
+ import { parseLauncherArgs } from "./args.js";
3
+
4
+ export const PI_HARNESS_RESTART_EXIT_CODE = 75;
5
+
6
+ function signalExitCode(signal: NodeJS.Signals | null): number {
7
+ if (signal === "SIGINT") return 130;
8
+ if (signal === "SIGHUP") return 129;
9
+ if (signal === "SIGTERM") return 143;
10
+ return 1;
11
+ }
12
+
13
+ export async function superviseDevelopmentProcess(command: string, args: readonly string[], options: SpawnOptions = {}): Promise<number> {
14
+ while (true) {
15
+ const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {
16
+ const child = spawn(command, [...args], options);
17
+ const signals: NodeJS.Signals[] = process.platform === "win32" ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
18
+ const handlers = signals.map((signal) => {
19
+ const handler = () => child.kill(signal);
20
+ process.on(signal, handler);
21
+ return { signal, handler };
22
+ });
23
+ const cleanup = () => {
24
+ for (const { signal, handler } of handlers) process.off(signal, handler);
25
+ };
26
+ child.once("error", (error) => {
27
+ cleanup();
28
+ reject(error);
29
+ });
30
+ child.once("exit", (code, signal) => {
31
+ cleanup();
32
+ resolve({ code, signal });
33
+ });
34
+ });
35
+ if (result.code === PI_HARNESS_RESTART_EXIT_CODE) continue;
36
+ return result.code ?? signalExitCode(result.signal);
37
+ }
38
+ }
39
+
40
+ export function shouldRelaunchForDevelopmentProfile(args: readonly string[], execArgv: readonly string[]): boolean {
41
+ if (execArgv.includes("--expose-internals")) return false;
42
+ try {
43
+ const invocation = parseLauncherArgs(args);
44
+ return invocation.mode === "run" && invocation.configPath === undefined && invocation.profile === "development" && !invocation.dumpConfig;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
@@ -0,0 +1,28 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { parseLauncherArgs } from "../src/args.js";
3
+
4
+ describe("parseLauncherArgs", () => {
5
+ test("uses the default profile and forwards application arguments", () => {
6
+ expect(parseLauncherArgs(["--prompt", "hello"])).toEqual({ mode: "run", profile: "default", dumpConfig: false, args: ["--prompt", "hello"] });
7
+ });
8
+
9
+ test("parses launcher options without consuming escaped application options", () => {
10
+ expect(parseLauncherArgs(["--profile", "development", "--", "--profile", "inside", "hello"])).toEqual({ mode: "run", profile: "development", dumpConfig: false, args: ["--profile", "inside", "hello"] });
11
+ });
12
+
13
+ test("accepts an explicit config instead of a profile", () => {
14
+ expect(parseLauncherArgs(["--config", "./custom.yml", "--dump-config"])).toEqual({ mode: "run", configPath: "./custom.yml", dumpConfig: true, args: [] });
15
+ });
16
+
17
+ test.each([["--help", "help"], ["-h", "help"], ["--version", "version"], ["-v", "version"]] as const)("maps %s to %s mode", (flag, mode) => {
18
+ expect(parseLauncherArgs([flag])).toEqual({ mode });
19
+ });
20
+
21
+ test("rejects mutually exclusive profile and config options", () => {
22
+ expect(() => parseLauncherArgs(["--profile", "default", "--config", "custom.yml"])).toThrow(/cannot be used together/);
23
+ });
24
+
25
+ test("rejects a launcher option with no value", () => {
26
+ expect(() => parseLauncherArgs(["--profile"])).toThrow(/--profile requires a value/);
27
+ });
28
+ });
@@ -0,0 +1,153 @@
1
+ import { mkdtemp, readFile, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { Readable, Writable } from "node:stream";
6
+ import { describe, expect, test } from "vitest";
7
+ import { runCli, type CliEnvironment } from "../src/main.js";
8
+
9
+ interface TestEnvironment extends CliEnvironment {
10
+ readonly output: string[];
11
+ readonly errors: string[];
12
+ readonly forcedExitCodes: number[];
13
+ emitSignal(signal: NodeJS.Signals): void;
14
+ }
15
+
16
+ function createEnvironment(cwd = process.cwd(), input = "", shutdownTimeoutMs = 5_000): TestEnvironment {
17
+ const output: string[] = [];
18
+ const errors: string[] = [];
19
+ const forcedExitCodes: number[] = [];
20
+ const signals = new Set<(signal: NodeJS.Signals) => void>();
21
+ return {
22
+ cwd,
23
+ agentDir: join(cwd, ".pi-agent-test"),
24
+ version: "0.1.0-test",
25
+ stdin: Readable.from([input]),
26
+ stdout: new Writable({ write(chunk, _encoding, callback) { output.push(String(chunk)); callback(); } }),
27
+ stderr: new Writable({ write(chunk, _encoding, callback) { errors.push(String(chunk)); callback(); } }),
28
+ output,
29
+ errors,
30
+ forcedExitCodes,
31
+ shutdownTimeoutMs,
32
+ forceExit(code) {
33
+ forcedExitCodes.push(code);
34
+ },
35
+ onSignal(listener) {
36
+ signals.add(listener);
37
+ return () => signals.delete(listener);
38
+ },
39
+ emitSignal(signal) {
40
+ for (const listener of signals) listener(signal);
41
+ },
42
+ };
43
+ }
44
+
45
+ async function createApplicationProfile(source: string): Promise<{ configPath: string; directory: string }> {
46
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-cli-"));
47
+ const pluginPath = join(directory, "application.mjs");
48
+ const configPath = join(directory, "cordis.yml");
49
+ await writeFile(pluginPath, source, "utf8");
50
+ await writeFile(configPath, JSON.stringify([{ name: pathToFileURL(pluginPath).href, config: { markerPath: join(directory, "marker.txt") } }]), "utf8");
51
+ return { configPath, directory };
52
+ }
53
+
54
+ async function waitForFileContent(path: string, expected: string, timeoutMs = 5_000): Promise<void> {
55
+ const startedAt = Date.now();
56
+ while (true) {
57
+ try {
58
+ if (await readFile(path, "utf8") === expected) return;
59
+ } catch {
60
+ // The producer has not created the marker yet.
61
+ }
62
+ if (Date.now() - startedAt > timeoutMs) throw new Error(`Timed out waiting for ${path} to contain ${expected}`);
63
+ await new Promise((resolve) => setTimeout(resolve, 10));
64
+ }
65
+ }
66
+
67
+ describe("runCli", () => {
68
+ test("prints help without booting a profile", async () => {
69
+ const environment = createEnvironment();
70
+
71
+ const exitCode = await runCli(["--help"], environment);
72
+
73
+ expect(exitCode).toBe(0);
74
+ expect(environment.output.join("")).toContain("Usage: pih");
75
+ expect(environment.errors).toEqual([]);
76
+ });
77
+
78
+ test("prints the package version", async () => {
79
+ const environment = createEnvironment();
80
+
81
+ const exitCode = await runCli(["--version"], environment);
82
+
83
+ expect(exitCode).toBe(0);
84
+ expect(environment.output.join("")).toBe("0.1.0-test\n");
85
+ });
86
+
87
+ test("dumps an explicit profile without importing its plugins", async () => {
88
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-dump-"));
89
+ const configPath = join(directory, "cordis.yml");
90
+ await writeFile(configPath, "- name: ./not-imported.mjs\n", "utf8");
91
+ const environment = createEnvironment(directory);
92
+
93
+ const exitCode = await runCli(["--config", configPath, "--dump-config"], environment);
94
+
95
+ expect(exitCode).toBe(0);
96
+ expect(environment.output.join("")).toBe("- name: ./not-imported.mjs\n");
97
+ });
98
+
99
+ test("runs the application plugin and disposes the Cordis tree", async () => {
100
+ const profile = await createApplicationProfile(`import { appendFileSync, writeFileSync } from "node:fs"; export default { apply(ctx, config) { writeFileSync(config.markerPath, "started"); ctx.effect(() => () => appendFileSync(config.markerPath, ":disposed")); ctx.provide("piApplication", { async run() { appendFileSync(config.markerPath, ":run"); return 7; } }); } };`);
101
+ const environment = createEnvironment(profile.directory);
102
+
103
+ const exitCode = await runCli(["--config", profile.configPath], environment);
104
+
105
+ expect(exitCode).toBe(7);
106
+ await expect(readFile(join(profile.directory, "marker.txt"), "utf8")).resolves.toBe("started:run:disposed");
107
+ });
108
+
109
+ test("aborts and disposes a running application on SIGINT", async () => {
110
+ const profile = await createApplicationProfile(`import { appendFileSync, writeFileSync } from "node:fs"; export default { apply(ctx, config) { writeFileSync(config.markerPath, "started"); ctx.effect(() => () => appendFileSync(config.markerPath, ":disposed")); ctx.provide("piApplication", { async run() { appendFileSync(config.markerPath, ":run"); return new Promise(() => {}); } }); } };`);
111
+ const environment = createEnvironment(profile.directory);
112
+ const result = runCli(["--config", profile.configPath], environment);
113
+ const markerPath = join(profile.directory, "marker.txt");
114
+ await waitForFileContent(markerPath, "started:run");
115
+
116
+ environment.emitSignal("SIGINT");
117
+
118
+ await expect(result).resolves.toBe(130);
119
+ await expect(readFile(markerPath, "utf8")).resolves.toBe("started:run:disposed");
120
+ });
121
+
122
+ test("handles SIGTERM while the Cordis plugin tree is still starting", async () => {
123
+ const profile = await createApplicationProfile(`import { writeFileSync } from "node:fs"; export default { async apply(_ctx, config) { writeFileSync(config.markerPath, "starting"); await new Promise(() => {}); } };`);
124
+ const environment = createEnvironment(profile.directory, "", 50);
125
+ const result = runCli(["--config", profile.configPath], environment);
126
+ await waitForFileContent(join(profile.directory, "marker.txt"), "starting");
127
+
128
+ environment.emitSignal("SIGTERM");
129
+
130
+ await expect(result).resolves.toBe(143);
131
+ });
132
+
133
+ test("forces the bin exit when a Cordis disposer exceeds the shutdown deadline", async () => {
134
+ const profile = await createApplicationProfile(`import { writeFileSync } from "node:fs"; export default { apply(ctx, config) { writeFileSync(config.markerPath, "started"); ctx.effect(() => async () => new Promise(() => {})); ctx.provide("piApplication", { async run() { return new Promise(() => {}); } }); } };`);
135
+ const environment = createEnvironment(profile.directory, "", 25);
136
+ const result = runCli(["--config", profile.configPath], environment);
137
+ await waitForFileContent(join(profile.directory, "marker.txt"), "started");
138
+
139
+ environment.emitSignal("SIGTERM");
140
+
141
+ await expect(result).resolves.toBe(143);
142
+ expect(environment.forcedExitCodes).toEqual([143]);
143
+ });
144
+
145
+ test("returns a usage error for a missing config", async () => {
146
+ const environment = createEnvironment();
147
+
148
+ const exitCode = await runCli(["--config", "missing.yml", "--dump-config"], environment);
149
+
150
+ expect(exitCode).toBe(2);
151
+ expect(environment.errors.join("")).toContain("missing.yml");
152
+ });
153
+ });
@@ -0,0 +1,29 @@
1
+ import { mkdtemp, readFile, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { describe, expect, test } from "vitest";
5
+ import { PI_HARNESS_RESTART_EXIT_CODE, shouldRelaunchForDevelopmentProfile, superviseDevelopmentProcess } from "../src/relaunch.js";
6
+
7
+ describe("development profile relaunch", () => {
8
+ test("requests Node internals only for an executable built-in development profile", () => {
9
+ expect(shouldRelaunchForDevelopmentProfile(["--profile", "development"], [])).toBe(true);
10
+ expect(shouldRelaunchForDevelopmentProfile(["--profile=development", "hello"], [])).toBe(false);
11
+ expect(shouldRelaunchForDevelopmentProfile(["--profile", "default"], [])).toBe(false);
12
+ expect(shouldRelaunchForDevelopmentProfile(["--config", "cordis.yml"], [])).toBe(false);
13
+ expect(shouldRelaunchForDevelopmentProfile(["--profile", "development", "--dump-config"], [])).toBe(false);
14
+ expect(shouldRelaunchForDevelopmentProfile(["--profile", "development"], ["--expose-internals"])).toBe(false);
15
+ expect(shouldRelaunchForDevelopmentProfile(["--profile"], [])).toBe(false);
16
+ });
17
+
18
+ test("restarts a development child after Cordis requests a full reload", async () => {
19
+ const directory = await mkdtemp(join(tmpdir(), "pi-harness-supervisor-"));
20
+ const markerPath = join(directory, "runs.txt");
21
+ const childPath = join(directory, "child.mjs");
22
+ await writeFile(childPath, `import { appendFileSync, existsSync } from "node:fs"; const marker = process.argv[2]; const first = !existsSync(marker); appendFileSync(marker, "run\\n"); process.exit(first ? ${PI_HARNESS_RESTART_EXIT_CODE} : 7);`, "utf8");
23
+
24
+ const exitCode = await superviseDevelopmentProcess(process.execPath, [childPath, markerPath], { stdio: "ignore" });
25
+
26
+ expect(exitCode).toBe(7);
27
+ expect((await readFile(markerPath, "utf8")).split("\n").filter(Boolean)).toEqual(["run", "run"]);
28
+ });
29
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "paths": {},
6
+ "rootDir": "src"
7
+ },
8
+ "include": [
9
+ "src/**/*.ts"
10
+ ]
11
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "../.."
5
+ },
6
+ "include": [
7
+ "src/**/*.ts",
8
+ "test/**/*.ts"
9
+ ]
10
+ }
@@ -0,0 +1,102 @@
1
+ export interface ClientStatus {
2
+ readonly status: string;
3
+ readonly model: string;
4
+ readonly messages: number;
5
+ readonly events: number;
6
+ readonly sessionId: string;
7
+ readonly sessionFile?: string;
8
+ readonly cwd: string;
9
+ readonly agentDir: string;
10
+ readonly plugins: readonly string[];
11
+ }
12
+ export interface ClientSession {
13
+ readonly sessionId: string;
14
+ readonly sessionFile?: string;
15
+ readonly messages: readonly Record<string, unknown>[];
16
+ readonly entries: readonly unknown[];
17
+ readonly events: readonly Record<string, unknown>[];
18
+ }
19
+ export interface ClientModel {
20
+ readonly provider: string;
21
+ readonly id: string;
22
+ readonly name: string;
23
+ readonly reasoning: boolean;
24
+ readonly contextWindow: number | null;
25
+ readonly active: boolean;
26
+ }
27
+ export interface ClientPlugin {
28
+ readonly id: string;
29
+ readonly name: string;
30
+ readonly enabled: boolean;
31
+ readonly state: string;
32
+ }
33
+ export interface ClientProvider {
34
+ readonly provider: string;
35
+ readonly name: string;
36
+ readonly active: boolean;
37
+ readonly auth?: {
38
+ readonly configured?: boolean;
39
+ readonly source?: string;
40
+ readonly label?: string;
41
+ };
42
+ readonly activeModel?: ClientModel;
43
+ readonly models: readonly ClientModel[];
44
+ }
45
+ export interface ClientCommand {
46
+ readonly name: string;
47
+ readonly invocationName: string;
48
+ readonly description?: string;
49
+ readonly source?: string;
50
+ }
51
+ export interface ClientFile {
52
+ readonly path: string;
53
+ readonly status: string;
54
+ readonly label: string;
55
+ }
56
+ export interface ClientApi {
57
+ getStatus(): Promise<ClientStatus>;
58
+ getSession(): Promise<ClientSession>;
59
+ getFiles(): Promise<readonly ClientFile[]>;
60
+ getFileDiff(path: string): Promise<{
61
+ path: string;
62
+ diff: string;
63
+ }>;
64
+ commitFiles(paths: readonly string[], message: string): Promise<{
65
+ committed: boolean;
66
+ commit?: string;
67
+ message: string;
68
+ }>;
69
+ revertFiles(paths: readonly string[]): Promise<{
70
+ reverted: boolean;
71
+ paths: readonly string[];
72
+ }>;
73
+ prompt(value: string): Promise<{
74
+ reply: string;
75
+ messages: number;
76
+ }>;
77
+ abort(): Promise<{
78
+ aborted: boolean;
79
+ }>;
80
+ createSession(): Promise<ClientSession>;
81
+ openSession(path: string): Promise<ClientSession>;
82
+ listSessions(): Promise<readonly Record<string, unknown>[]>;
83
+ listModels(): Promise<readonly ClientModel[]>;
84
+ listProviders(): Promise<readonly ClientProvider[]>;
85
+ testProvider(provider: string): Promise<{
86
+ provider: string;
87
+ reachable: boolean;
88
+ auth?: unknown;
89
+ }>;
90
+ refreshProvider(provider: string): Promise<{
91
+ provider: string;
92
+ models: readonly ClientModel[];
93
+ }>;
94
+ listPlugins(): Promise<readonly ClientPlugin[]>;
95
+ listCommands(): Promise<readonly ClientCommand[]>;
96
+ selectModel(provider: string, model: string): Promise<{
97
+ model: ClientModel;
98
+ }>;
99
+ subscribeEvents(onEvent: (payload: Record<string, unknown>) => void): () => void;
100
+ }
101
+ export declare function createClientApi(): ClientApi;
102
+ //# sourceMappingURL=control-room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-room.d.ts","sourceRoot":"","sources":["../src/control-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ function requestJson(path, init) { return fetch(path, init).then(async (response) => { const payload = await response.json(); if (!response.ok) {
2
+ const error = payload !== null && typeof payload === "object" && "error" in payload && typeof payload.error === "string" ? payload.error : `Request failed with status ${response.status}`;
3
+ throw new Error(error);
4
+ } return payload; }); }
5
+ export function createClientApi() { return { getStatus: () => requestJson("/api/status"), getSession: () => requestJson("/api/session"), getFiles: async () => (await requestJson("/api/files")).items, getFileDiff: (path) => requestJson(`/api/files/diff?path=${encodeURIComponent(path)}`), commitFiles: (paths, message) => requestJson("/api/files/commit", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ paths, message }) }), revertFiles: (paths) => requestJson("/api/files/revert", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ paths, confirm: true }) }), prompt: (value) => requestJson("/api/prompt", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ prompt: value }) }), abort: () => requestJson("/api/abort", { method: "POST" }), createSession: () => requestJson("/api/session/new", { method: "POST" }), openSession: (path) => requestJson("/api/session/open", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ path }) }), listSessions: async () => (await requestJson("/api/sessions")).items, listModels: async () => (await requestJson("/api/models")).items, listProviders: async () => (await requestJson("/api/providers")).items, testProvider: (provider) => requestJson("/api/providers/test", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ provider }) }), refreshProvider: (provider) => requestJson("/api/providers/refresh", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ provider }) }), listPlugins: async () => (await requestJson("/api/plugins")).items, listCommands: async () => (await requestJson("/api/commands")).items, selectModel: (provider, model) => requestJson("/api/model", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ provider, model }) }), subscribeEvents: (onEvent) => { if (typeof EventSource === "undefined")
6
+ return () => { }; const source = new EventSource("/api/events"); source.onmessage = (event) => { try {
7
+ const raw = event.data;
8
+ if (typeof raw === "string")
9
+ onEvent(JSON.parse(raw));
10
+ }
11
+ catch { /* Ignore malformed frames at the network boundary. */ } }; return () => source.close(); } }; }
12
+ //# sourceMappingURL=control-room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-room.js","sourceRoot":"","sources":["../src/control-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ export interface DesignWorkspace {
2
+ readonly path: string;
3
+ readonly sessions: string;
4
+ readonly live: boolean;
5
+ readonly branch: string;
6
+ readonly dirty: string;
7
+ }
8
+ export interface DesignSession {
9
+ readonly id: string;
10
+ readonly title: string;
11
+ readonly meta: string;
12
+ readonly state: "running" | "ok" | "warn" | "error";
13
+ readonly group: "今天" | "昨天" | "更早";
14
+ readonly ws: string;
15
+ }
16
+ export interface DesignTurn {
17
+ readonly kind: "user" | "reasoning" | "plugin" | "tool" | "text" | "approval" | "subagent" | "todo" | "stats";
18
+ readonly text?: string;
19
+ readonly name?: string;
20
+ readonly hook?: string;
21
+ readonly target?: string;
22
+ readonly output?: string;
23
+ readonly dur?: string;
24
+ readonly stat?: string;
25
+ readonly statFg?: string;
26
+ readonly glyph?: string;
27
+ readonly isDiff?: boolean;
28
+ readonly diff?: readonly {
29
+ no: string;
30
+ sign: string;
31
+ text: string;
32
+ }[];
33
+ readonly preset?: string;
34
+ readonly goal?: string;
35
+ readonly lineage?: string;
36
+ readonly steps?: readonly {
37
+ tool: string;
38
+ target: string;
39
+ dur: string;
40
+ }[];
41
+ readonly verdict?: string;
42
+ readonly progress?: string;
43
+ readonly todos?: readonly {
44
+ text: string;
45
+ done: boolean;
46
+ }[];
47
+ readonly stats?: readonly string[];
48
+ }
49
+ export interface DesignEvent {
50
+ readonly ts: string;
51
+ readonly source: string;
52
+ readonly summary: string;
53
+ readonly by: string;
54
+ readonly dur: string;
55
+ }
56
+ export interface DesignPlugin {
57
+ readonly name: string;
58
+ readonly ver: string;
59
+ readonly capability: string;
60
+ readonly on: boolean;
61
+ readonly update: boolean;
62
+ readonly local?: boolean;
63
+ readonly desc: string;
64
+ readonly hooks: readonly string[];
65
+ }
66
+ export interface DesignProvider {
67
+ readonly id: string;
68
+ readonly name: string;
69
+ readonly state: string;
70
+ readonly ok: boolean;
71
+ readonly protocol: "openai" | "anthropic";
72
+ readonly baseUrl: string;
73
+ readonly key: string;
74
+ readonly models: readonly string[];
75
+ readonly latency: string;
76
+ readonly by: string;
77
+ }
78
+ export declare const DESIGN_WORKSPACES: readonly DesignWorkspace[];
79
+ export declare const DESIGN_SESSIONS: readonly DesignSession[];
80
+ export declare const DESIGN_TURNS: readonly DesignTurn[];
81
+ export declare const DESIGN_EVENTS: readonly DesignEvent[];
82
+ export declare const DESIGN_PLUGINS: readonly DesignPlugin[];
83
+ export declare const DESIGN_PROVIDERS: readonly DesignProvider[];
84
+ export declare const DESIGN_TOML = "# ~/.config/pi/pi.toml\n# \u4E00\u5207\u90FD\u662F\u5305\uFF1A\u6A21\u578B\u3001\u5DE5\u5177\u3001\u6C99\u7BB1\u3001\u5B58\u50A8\u3001\u754C\u9762\u90FD\u5728\u8FD9\u91CC\u88C5\u5378\u3002\n\n[agent]\npreset = \"coder\"\nmodel = \"ds-coder-v3\"\nmax_steps = 40\nbudget_usd = 1.50\nask_before = [\"write\", \"shell\", \"network\"]\n\n[sandbox]\nbackend = \"landlock\"\nwritable = [\".\"]\nnetwork = false\n\n[context]\nwindow = 64000\ncompact_at = 0.82\n\n[[packages]]\nname = \"context-repo-map\"\nversion = \"1.4.2\"\n\n[[packages]]\nname = \"guard-secret-scan\"\nversion = \"2.0.1\"\n\n[[packages]]\nname = \"subagent-review\"\nversion = \"0.8.5\"\n\n[[packages]]\npath = \"../pi-pkg-vision-handoff\" # \u672C\u5730\u5F00\u53D1\u4E2D\n\n[keys]\npalette = \"cmd+k\"\nsettings = \"cmd+,\"\ninterrupt = \"ctrl+c\"\n";
85
+ //# sourceMappingURL=design-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-contract.d.ts","sourceRoot":"","sources":["../src/design-contract.ts"],"names":[],"mappings":"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"}