@liy/mote-pi-runtime 0.3.0

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/dist/pi-rpc.js ADDED
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as ___liy_mote_pi_runtimeCreateRequire } from "node:module";var require = ___liy_mote_pi_runtimeCreateRequire(import.meta.url);
3
+
4
+ // src/pi-rpc-runtime.ts
5
+ import { readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ import { InMemoryCredentialStore } from "@earendil-works/pi-ai";
8
+ import {
9
+ CONFIG_DIR_NAME,
10
+ ModelRuntime,
11
+ SessionManager,
12
+ SettingsManager,
13
+ createAgentSessionFromServices,
14
+ createAgentSessionRuntime,
15
+ createAgentSessionServices,
16
+ initTheme,
17
+ parseArgs,
18
+ resolveCliModel
19
+ } from "@earendil-works/pi-coding-agent";
20
+
21
+ // src/pi-session-transport.ts
22
+ import { VERSION } from "@earendil-works/pi-coding-agent";
23
+ import { createInterface } from "node:readline";
24
+ async function servePiSession(runtime, transport) {
25
+ const session = runtime.session;
26
+ const input = createInterface({ input: transport.input, crlfDelay: Infinity });
27
+ input.pause();
28
+ const unsubscribe = session.subscribe((event) => transport.write(event));
29
+ const unsubscribeBackpressure = session.agent.subscribe(() => transport.drain());
30
+ const tasks = /* @__PURE__ */ new Set();
31
+ let closing = false;
32
+ const closeInput = () => {
33
+ closing = true;
34
+ input.close();
35
+ };
36
+ transport.signal?.addEventListener("abort", closeInput, { once: true });
37
+ const respond = (command, success, data) => {
38
+ transport.write({
39
+ type: "response",
40
+ id: command.id,
41
+ command: command.type,
42
+ success,
43
+ ...success ? data === void 0 ? {} : { data } : { error: String(data) }
44
+ });
45
+ };
46
+ const handle = async (line) => {
47
+ let command;
48
+ try {
49
+ const parsed = JSON.parse(line);
50
+ if (typeof parsed !== "object" || parsed === null || !("type" in parsed) || typeof parsed.type !== "string") {
51
+ throw new Error("Expected a Pi command object with a type");
52
+ }
53
+ command = parsed;
54
+ switch (command.type) {
55
+ case "prompt": {
56
+ if (typeof command.message !== "string") throw new Error("Prompt message must be a string");
57
+ let accepted = false;
58
+ const prompt = command;
59
+ try {
60
+ await session.prompt(prompt.message, {
61
+ ...prompt.images ? { images: prompt.images } : {},
62
+ ...prompt.streamingBehavior ? { streamingBehavior: prompt.streamingBehavior } : {},
63
+ source: "rpc",
64
+ preflightResult(success) {
65
+ if (success) {
66
+ accepted = true;
67
+ respond(prompt, true);
68
+ }
69
+ }
70
+ });
71
+ } catch (error) {
72
+ if (!accepted) throw error;
73
+ transport.write({ type: "runtime.error", error: error instanceof Error ? error.message : String(error) });
74
+ }
75
+ break;
76
+ }
77
+ case "steer":
78
+ if (typeof command.message !== "string") throw new Error("Steer message must be a string");
79
+ await session.steer(command.message, command.images);
80
+ respond(command, true);
81
+ break;
82
+ case "abort":
83
+ await session.abort();
84
+ respond(command, true);
85
+ break;
86
+ case "get_state":
87
+ respond(command, true, {
88
+ model: session.model,
89
+ thinkingLevel: session.thinkingLevel,
90
+ isStreaming: session.isStreaming,
91
+ isCompacting: session.isCompacting,
92
+ sessionFile: session.sessionFile,
93
+ sessionId: session.sessionId,
94
+ piVersion: VERSION,
95
+ messageCount: session.messages.length,
96
+ pendingMessageCount: session.pendingMessageCount
97
+ });
98
+ break;
99
+ default:
100
+ respond(command, false, `Unsupported Mote Pi command: ${command.type}`);
101
+ }
102
+ } catch (error) {
103
+ respond(command ?? { type: "parse" }, false, error instanceof Error ? error.message : String(error));
104
+ }
105
+ await transport.drain();
106
+ };
107
+ try {
108
+ transport.write({
109
+ type: "response",
110
+ command: "get_state",
111
+ success: true,
112
+ data: { sessionId: session.sessionId, piVersion: VERSION }
113
+ });
114
+ await session.bindExtensions({
115
+ mode: "rpc",
116
+ shutdownHandler: closeInput,
117
+ onError(error) {
118
+ transport.write({ type: "extension_error", ...error });
119
+ }
120
+ });
121
+ if (closing || transport.signal?.aborted) return;
122
+ await new Promise((resolve, reject) => {
123
+ input.on("line", (line) => {
124
+ if (closing) return;
125
+ const task = handle(line);
126
+ tasks.add(task);
127
+ void task.then(() => tasks.delete(task), reject);
128
+ });
129
+ input.once("close", resolve);
130
+ input.once("error", reject);
131
+ input.resume();
132
+ });
133
+ } finally {
134
+ closing = true;
135
+ transport.signal?.removeEventListener("abort", closeInput);
136
+ input.close();
137
+ transport.input.pause();
138
+ try {
139
+ await session.abort();
140
+ await Promise.allSettled(tasks);
141
+ } finally {
142
+ unsubscribe();
143
+ unsubscribeBackpressure();
144
+ await runtime.dispose();
145
+ await transport.drain();
146
+ }
147
+ }
148
+ }
149
+
150
+ // src/pi-rpc-runtime.ts
151
+ var VolatileSettingsStorage = class {
152
+ global;
153
+ project;
154
+ /**
155
+ * Create process-local settings state from file contents read by Mote.
156
+ *
157
+ * @param global - Raw agent profile settings, when present.
158
+ * @param project - Raw workspace `.pi/settings.json`, when present.
159
+ */
160
+ constructor(global, project) {
161
+ this.global = global;
162
+ this.project = project;
163
+ }
164
+ /**
165
+ * Apply one Pi settings transaction to memory only.
166
+ *
167
+ * @param scope - Global agent settings or project-local settings.
168
+ * @param update - Pi's serialized read-modify-write callback.
169
+ */
170
+ withLock(scope, update) {
171
+ const next = update(scope === "global" ? this.global : this.project);
172
+ if (next === void 0) return;
173
+ if (scope === "global") {
174
+ this.global = next;
175
+ return;
176
+ }
177
+ this.project = next;
178
+ }
179
+ };
180
+ async function createMotePiRpcRuntime(argv, options) {
181
+ const input = parseMotePiRpcArguments(argv);
182
+ process.env.PI_CODING_AGENT_DIR = options.agentDir;
183
+ const sessionManager = input.sessionFile ? SessionManager.open(input.sessionFile, input.sessionDir, options.cwd) : SessionManager.create(options.cwd, input.sessionDir);
184
+ const createRuntime = async ({
185
+ cwd,
186
+ agentDir: agentDir2,
187
+ sessionManager: activeSessionManager,
188
+ sessionStartEvent
189
+ }) => {
190
+ const settingsManager = await loadVolatileSettings(cwd, agentDir2);
191
+ initTheme(settingsManager.getTheme(), false);
192
+ const modelRuntime = await ModelRuntime.create({
193
+ credentials: new InMemoryCredentialStore(),
194
+ modelsPath: null,
195
+ allowModelNetwork: false,
196
+ refreshOnCreate: false
197
+ });
198
+ const services = await createAgentSessionServices({
199
+ cwd,
200
+ agentDir: agentDir2,
201
+ settingsManager,
202
+ modelRuntime
203
+ });
204
+ const extensionErrors = services.resourceLoader.getExtensions().errors.map(({ path, error }) => `Failed to load extension "${path}": ${error}`);
205
+ const serviceErrors = services.diagnostics.filter((diagnostic) => diagnostic.type === "error").map((diagnostic) => diagnostic.message);
206
+ if (extensionErrors.length > 0 || serviceErrors.length > 0) {
207
+ throw new Error([...serviceErrors, ...extensionErrors].join("\n"));
208
+ }
209
+ const resolvedModel = resolveCliModel({
210
+ cliProvider: input.provider,
211
+ cliModel: input.model,
212
+ cliThinking: input.thinking,
213
+ modelRuntime
214
+ });
215
+ if (resolvedModel.error) {
216
+ throw new Error(resolvedModel.error);
217
+ }
218
+ if (!resolvedModel.model) {
219
+ throw new Error("The agent profile did not resolve a Pi model");
220
+ }
221
+ const created = await createAgentSessionFromServices({
222
+ services,
223
+ sessionManager: activeSessionManager,
224
+ ...sessionStartEvent ? { sessionStartEvent } : {},
225
+ model: resolvedModel.model,
226
+ thinkingLevel: input.thinking
227
+ });
228
+ return {
229
+ ...created,
230
+ services,
231
+ diagnostics: services.diagnostics
232
+ };
233
+ };
234
+ return createAgentSessionRuntime(createRuntime, {
235
+ cwd: options.cwd,
236
+ agentDir: options.agentDir,
237
+ sessionManager
238
+ });
239
+ }
240
+ async function runMotePiRpc(argv, options) {
241
+ const runtime = await createMotePiRpcRuntime(argv, options);
242
+ const packageEntry = import.meta.resolve("@earendil-works/pi-coding-agent");
243
+ const output = await import(new URL("./core/output-guard.js", packageEntry).href);
244
+ const shell = await import(new URL("./utils/shell.js", packageEntry).href);
245
+ output.takeOverStdout();
246
+ const shutdown = new AbortController();
247
+ const stop = () => {
248
+ shell.killTrackedDetachedChildren();
249
+ shutdown.abort();
250
+ };
251
+ process.once("SIGTERM", stop);
252
+ process.once("SIGHUP", stop);
253
+ try {
254
+ await servePiSession(runtime, {
255
+ input: process.stdin,
256
+ signal: shutdown.signal,
257
+ write(value) {
258
+ output.writeRawStdout(`${JSON.stringify(value)}
259
+ `);
260
+ },
261
+ drain: () => output.waitForRawStdoutBackpressure()
262
+ });
263
+ } finally {
264
+ process.off("SIGTERM", stop);
265
+ process.off("SIGHUP", stop);
266
+ await output.flushRawStdout();
267
+ output.restoreStdout();
268
+ }
269
+ }
270
+ function parseMotePiRpcArguments(argv) {
271
+ const parsed = parseArgs(argv);
272
+ const errors = parsed.diagnostics.filter((diagnostic) => diagnostic.type === "error").map((diagnostic) => diagnostic.message);
273
+ if (parsed.unknownFlags.size > 0) {
274
+ errors.push(
275
+ `Unknown options: ${[...parsed.unknownFlags.keys()].map((name) => `--${name}`).join(", ")}`
276
+ );
277
+ }
278
+ if (parsed.mode !== "rpc") errors.push("Mote Pi launches require --mode rpc");
279
+ if (!parsed.sessionDir?.trim()) errors.push("Mote Pi launches require --session-dir");
280
+ if (!parsed.provider?.trim() || !parsed.model?.trim() || !parsed.thinking) {
281
+ errors.push("Mote Pi launches require --provider, --model, and --thinking");
282
+ }
283
+ if (parsed.projectTrustOverride !== true) {
284
+ errors.push("Mote Pi launches require --approve");
285
+ }
286
+ if (parsed.apiKey !== void 0) {
287
+ errors.push("--api-key is not supported; Mote provider authorization is gateway-bound");
288
+ }
289
+ if (parsed.continue || parsed.resume || parsed.fork || parsed.noSession || parsed.sessionId || parsed.print || parsed.help || parsed.version || parsed.listModels !== void 0 || parsed.messages.length > 0 || parsed.fileArgs.length > 0) {
290
+ errors.push("The requested Pi CLI behavior is outside Mote's RPC launch contract");
291
+ }
292
+ if (errors.length > 0) throw new Error(errors.join("\n"));
293
+ return {
294
+ sessionDir: parsed.sessionDir.trim(),
295
+ ...parsed.session ? { sessionFile: parsed.session } : {},
296
+ provider: parsed.provider.trim(),
297
+ model: parsed.model.trim(),
298
+ thinking: parsed.thinking
299
+ };
300
+ }
301
+ async function loadVolatileSettings(cwd, agentDir2) {
302
+ const [global, project] = await Promise.all([
303
+ readOptionalFile(join(agentDir2, "settings.json")),
304
+ readOptionalFile(join(cwd, CONFIG_DIR_NAME, "settings.json"))
305
+ ]);
306
+ const settingsManager = SettingsManager.fromStorage(
307
+ new VolatileSettingsStorage(global, project),
308
+ { projectTrusted: true }
309
+ );
310
+ const errors = settingsManager.drainErrors();
311
+ if (errors.length > 0) {
312
+ throw new Error(errors.map(({ scope, error }) => `${scope} settings: ${error.message}`).join("\n"));
313
+ }
314
+ return settingsManager;
315
+ }
316
+ async function readOptionalFile(path) {
317
+ try {
318
+ return await readFile(path, "utf8");
319
+ } catch (error) {
320
+ if (isNodeError(error) && error.code === "ENOENT") return void 0;
321
+ throw error;
322
+ }
323
+ }
324
+ function isNodeError(error) {
325
+ return error instanceof Error && "code" in error;
326
+ }
327
+
328
+ // src/pi-rpc.ts
329
+ var agentDir = process.env.PI_CODING_AGENT_DIR?.trim();
330
+ if (!agentDir) {
331
+ process.stderr.write("[mote-pi-rpc] PI_CODING_AGENT_DIR is required\n");
332
+ process.exit(1);
333
+ }
334
+ process.title = "mote-pi-rpc";
335
+ process.env.PI_CODING_AGENT = "true";
336
+ process.env.AI_AGENT = "pi";
337
+ try {
338
+ await runMotePiRpc(process.argv.slice(2), {
339
+ cwd: process.cwd(),
340
+ agentDir
341
+ });
342
+ } catch (error) {
343
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
344
+ process.stderr.write(`[mote-pi-rpc] ${message}
345
+ `);
346
+ process.exit(1);
347
+ }
348
+ //# sourceMappingURL=pi-rpc.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/pi-rpc-runtime.ts", "../src/pi-session-transport.ts", "../src/pi-rpc.ts"],
4
+ "sourcesContent": ["import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { InMemoryCredentialStore } from \"@earendil-works/pi-ai\";\nimport {\n CONFIG_DIR_NAME,\n type AgentSessionRuntime,\n type CreateAgentSessionRuntimeFactory,\n ModelRuntime,\n SessionManager,\n SettingsManager,\n createAgentSessionFromServices,\n createAgentSessionRuntime,\n createAgentSessionServices,\n initTheme,\n parseArgs,\n resolveCliModel,\n} from \"@earendil-works/pi-coding-agent\";\n\nimport { servePiSession } from \"./pi-session-transport.js\";\n\n/** Runtime paths supplied by the trusted sandbox Orchestrator. */\nexport interface MotePiRpcRuntimeOptions {\n /** Workspace or worktree in which Pi tools execute. */\n cwd: string;\n /** Stable root-managed, read-only agent profile directory. */\n agentDir: string;\n}\n\n/** Parsed launch choices owned by Mote's narrow Pi RPC integration. */\ninterface MotePiRpcArguments {\n /** Durable directory selected by the purpose-specific agent session mapping. */\n sessionDir: string;\n /** Exact mapped session file to resume, when one exists. */\n sessionFile?: string;\n /** Explicit provider selected by the agent profile. */\n provider: string;\n /** Explicit model selected by the agent profile. */\n model: string;\n /** Explicit Pi thinking level selected by the agent profile. */\n thinking: NonNullable<ReturnType<typeof parseArgs>[\"thinking\"]>;\n}\n\n/**\n * Volatile settings storage initialized from read-only profile and project files.\n *\n * @remarks\n * Pi may update settings while a process is alive, but those updates must never\n * create lock files or mutate Mote's root-managed agent profile. Session state is\n * persisted separately by {@link SessionManager} in the mapped session directory.\n */\nclass VolatileSettingsStorage {\n private global: string | undefined;\n private project: string | undefined;\n\n /**\n * Create process-local settings state from file contents read by Mote.\n *\n * @param global - Raw agent profile settings, when present.\n * @param project - Raw workspace `.pi/settings.json`, when present.\n */\n constructor(global: string | undefined, project: string | undefined) {\n this.global = global;\n this.project = project;\n }\n\n /**\n * Apply one Pi settings transaction to memory only.\n *\n * @param scope - Global agent settings or project-local settings.\n * @param update - Pi's serialized read-modify-write callback.\n */\n withLock(\n scope: \"global\" | \"project\",\n update: (current: string | undefined) => string | undefined,\n ): void {\n const next = update(scope === \"global\" ? this.global : this.project);\n if (next === undefined) return;\n if (scope === \"global\") {\n this.global = next;\n return;\n }\n this.project = next;\n }\n}\n\n/**\n * Create a Pi runtime whose only durable mutable state is its mapped session.\n *\n * @param argv - Narrow Pi-compatible arguments emitted by the Orchestrator.\n * @param options - Trusted working directory and stable agent profile paths.\n * @returns Pi runtime ready for the standard JSONL RPC transport.\n */\nexport async function createMotePiRpcRuntime(\n argv: string[],\n options: MotePiRpcRuntimeOptions,\n): Promise<AgentSessionRuntime> {\n const input = parseMotePiRpcArguments(argv);\n // Extensions use Pi's canonical variable to find profile-owned resources.\n // Session state remains explicit through SessionManager and --session-dir.\n process.env.PI_CODING_AGENT_DIR = options.agentDir;\n const sessionManager = input.sessionFile\n // Session history is durable, but its original execution directory may be\n // a cleaned ticket worktree. Every launch owns its current tool cwd.\n ? SessionManager.open(input.sessionFile, input.sessionDir, options.cwd)\n : SessionManager.create(options.cwd, input.sessionDir);\n const createRuntime: CreateAgentSessionRuntimeFactory = async ({\n cwd,\n agentDir,\n sessionManager: activeSessionManager,\n sessionStartEvent,\n }) => {\n const settingsManager = await loadVolatileSettings(cwd, agentDir);\n // The standalone Pi CLI initializes this process-global before extensions\n // load. The SDK path must do the same even though RPC mode renders no TUI.\n initTheme(settingsManager.getTheme(), false);\n const modelRuntime = await ModelRuntime.create({\n credentials: new InMemoryCredentialStore(),\n modelsPath: null,\n allowModelNetwork: false,\n refreshOnCreate: false,\n });\n const services = await createAgentSessionServices({\n cwd,\n agentDir,\n settingsManager,\n modelRuntime,\n });\n const extensionErrors = services.resourceLoader\n .getExtensions()\n .errors.map(({ path, error }) => `Failed to load extension \"${path}\": ${error}`);\n const serviceErrors = services.diagnostics\n .filter((diagnostic) => diagnostic.type === \"error\")\n .map((diagnostic) => diagnostic.message);\n if (extensionErrors.length > 0 || serviceErrors.length > 0) {\n throw new Error([...serviceErrors, ...extensionErrors].join(\"\\n\"));\n }\n\n const resolvedModel = resolveCliModel({\n cliProvider: input.provider,\n cliModel: input.model,\n cliThinking: input.thinking,\n modelRuntime,\n });\n if (resolvedModel.error) {\n throw new Error(resolvedModel.error);\n }\n if (!resolvedModel.model) {\n throw new Error(\"The agent profile did not resolve a Pi model\");\n }\n const created = await createAgentSessionFromServices({\n services,\n sessionManager: activeSessionManager,\n ...(sessionStartEvent ? { sessionStartEvent } : {}),\n model: resolvedModel.model,\n thinkingLevel: input.thinking,\n });\n return {\n ...created,\n services,\n diagnostics: services.diagnostics,\n };\n };\n\n return createAgentSessionRuntime(createRuntime, {\n cwd: options.cwd,\n agentDir: options.agentDir,\n sessionManager,\n });\n}\n\n/**\n * Run Mote's credential-free integration with lossless Pi SDK session events.\n *\n * @param argv - Narrow Pi-compatible arguments emitted by the Orchestrator.\n * @param options - Trusted working directory and stable agent profile paths.\n * @returns Resolves after the input closes and the Pi runtime is disposed.\n */\nexport async function runMotePiRpc(\n argv: string[],\n options: MotePiRpcRuntimeOptions,\n): Promise<void> {\n const runtime = await createMotePiRpcRuntime(argv, options);\n // Pi's pinned package owns stdout isolation/backpressure and detached tool\n // cleanup, but does not export these helpers through its SDK entrypoint.\n // Resolve relative to that installed package; never rewrite its generated files.\n const packageEntry = import.meta.resolve(\"@earendil-works/pi-coding-agent\");\n const output = await import(new URL(\"./core/output-guard.js\", packageEntry).href);\n const shell = await import(new URL(\"./utils/shell.js\", packageEntry).href);\n output.takeOverStdout();\n const shutdown = new AbortController();\n const stop = (): void => {\n shell.killTrackedDetachedChildren();\n shutdown.abort();\n };\n process.once(\"SIGTERM\", stop);\n process.once(\"SIGHUP\", stop);\n try {\n await servePiSession(runtime, {\n input: process.stdin,\n signal: shutdown.signal,\n write(value) { output.writeRawStdout(`${JSON.stringify(value)}\\n`); },\n drain: () => output.waitForRawStdoutBackpressure(),\n });\n } finally {\n process.off(\"SIGTERM\", stop);\n process.off(\"SIGHUP\", stop);\n await output.flushRawStdout();\n output.restoreStdout();\n }\n}\n\n/**\n * Parse and reject any CLI behavior outside Mote's RPC launch contract.\n *\n * @param argv - Raw child-process arguments.\n * @returns Validated session and model choices.\n */\nfunction parseMotePiRpcArguments(argv: string[]): MotePiRpcArguments {\n const parsed = parseArgs(argv);\n const errors = parsed.diagnostics\n .filter((diagnostic) => diagnostic.type === \"error\")\n .map((diagnostic) => diagnostic.message);\n if (parsed.unknownFlags.size > 0) {\n errors.push(\n `Unknown options: ${[...parsed.unknownFlags.keys()].map((name) => `--${name}`).join(\", \")}`,\n );\n }\n if (parsed.mode !== \"rpc\") errors.push(\"Mote Pi launches require --mode rpc\");\n if (!parsed.sessionDir?.trim()) errors.push(\"Mote Pi launches require --session-dir\");\n if (!parsed.provider?.trim() || !parsed.model?.trim() || !parsed.thinking) {\n errors.push(\"Mote Pi launches require --provider, --model, and --thinking\");\n }\n if (parsed.projectTrustOverride !== true) {\n errors.push(\"Mote Pi launches require --approve\");\n }\n if (parsed.apiKey !== undefined) {\n errors.push(\"--api-key is not supported; Mote provider authorization is gateway-bound\");\n }\n if (\n parsed.continue || parsed.resume || parsed.fork || parsed.noSession ||\n parsed.sessionId || parsed.print || parsed.help || parsed.version ||\n parsed.listModels !== undefined || parsed.messages.length > 0 ||\n parsed.fileArgs.length > 0\n ) {\n errors.push(\"The requested Pi CLI behavior is outside Mote's RPC launch contract\");\n }\n if (errors.length > 0) throw new Error(errors.join(\"\\n\"));\n return {\n sessionDir: parsed.sessionDir!.trim(),\n ...(parsed.session ? { sessionFile: parsed.session } : {}),\n provider: parsed.provider!.trim(),\n model: parsed.model!.trim(),\n thinking: parsed.thinking!,\n };\n}\n\n/**\n * Load profile and project settings without giving Pi a file-backed write path.\n *\n * @param cwd - Effective workspace or worktree for the active session.\n * @param agentDir - Stable root-managed agent profile directory.\n * @returns Settings manager whose later writes remain process-local.\n */\nasync function loadVolatileSettings(\n cwd: string,\n agentDir: string,\n): Promise<SettingsManager> {\n const [global, project] = await Promise.all([\n readOptionalFile(join(agentDir, \"settings.json\")),\n readOptionalFile(join(cwd, CONFIG_DIR_NAME, \"settings.json\")),\n ]);\n const settingsManager = SettingsManager.fromStorage(\n new VolatileSettingsStorage(global, project),\n { projectTrusted: true },\n );\n const errors = settingsManager.drainErrors();\n if (errors.length > 0) {\n throw new Error(errors.map(({ scope, error }) => `${scope} settings: ${error.message}`).join(\"\\n\"));\n }\n return settingsManager;\n}\n\n/**\n * Read an optional UTF-8 file while preserving all non-absence errors.\n *\n * @param path - Exact settings path.\n * @returns File contents or `undefined` when the path does not exist.\n */\nasync function readOptionalFile(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") return undefined;\n throw error;\n }\n}\n\n/**\n * Narrow an unknown exception to a Node error with a filesystem code.\n *\n * @param error - Unknown rejected value.\n * @returns Whether the value exposes a string Node error code.\n */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n", "import { VERSION } from \"@earendil-works/pi-coding-agent\";\nimport { createInterface } from \"node:readline\";\nimport type { Readable } from \"node:stream\";\n\nimport type { AgentSessionRuntime, RpcCommand } from \"@earendil-works/pi-coding-agent\";\n\n/** JSONL transport dependencies; the writer must serialize synchronously before Pi mutates partials. */\nexport interface PiSessionTransport {\n /** Commands from the trusted sandbox orchestrator. */\n input: Readable;\n /** Write a complete event or command response without projecting its properties. */\n write(value: unknown): void;\n /** Wait until all preceding writes have reached the consumer. */\n drain(): Promise<void>;\n /** Host shutdown signal; cancellation of one prompt remains a Pi abort command. */\n signal?: AbortSignal;\n}\n\n/**\n * Serve Mote's small command surface directly from the Pi SDK.\n *\n * @remarks\n * Pi's stock RPC serializer removes accumulated partials. Subscribing here\n * preserves native session events while keeping prompting, tools, compaction,\n * retries, and session persistence inside Pi. Command responses are transport\n * control and never become timeline records. Mote does not expose Pi's terminal\n * UI or arbitrary session-switching commands through this internal connection.\n *\n * @param runtime - Pi runtime owning the mapped agent session.\n * @param transport - JSONL input, lossless output, and backpressure boundary.\n * @returns Resolves when input closes or an extension requests shutdown.\n */\nexport async function servePiSession(\n runtime: AgentSessionRuntime,\n transport: PiSessionTransport,\n): Promise<void> {\n const session = runtime.session;\n const input = createInterface({ input: transport.input, crlfDelay: Infinity });\n // The orchestrator can write its first prompt while extensions are binding.\n // Do not consume it until the command listener is installed.\n input.pause();\n const unsubscribe = session.subscribe((event) => transport.write(event));\n const unsubscribeBackpressure = session.agent.subscribe(() => transport.drain());\n const tasks = new Set<Promise<void>>();\n let closing = false;\n const closeInput = (): void => { closing = true; input.close(); };\n transport.signal?.addEventListener(\"abort\", closeInput, { once: true });\n\n /** Emit a correlated command response; native event payloads do not pass through this function. */\n const respond = (command: { id?: string; type: string }, success: boolean, data?: unknown): void => {\n transport.write({\n type: \"response\", id: command.id, command: command.type, success,\n ...(success ? (data === undefined ? {} : { data }) : { error: String(data) }),\n });\n };\n\n /** Execute one command without blocking abort/state requests behind a running prompt. */\n const handle = async (line: string): Promise<void> => {\n let command: RpcCommand | undefined;\n try {\n const parsed: unknown = JSON.parse(line);\n if (typeof parsed !== \"object\" || parsed === null || !(\"type\" in parsed) || typeof parsed.type !== \"string\") {\n throw new Error(\"Expected a Pi command object with a type\");\n }\n command = parsed as RpcCommand;\n switch (command.type) {\n case \"prompt\": {\n if (typeof command.message !== \"string\") throw new Error(\"Prompt message must be a string\");\n let accepted = false;\n const prompt = command;\n try {\n await session.prompt(prompt.message, {\n ...(prompt.images ? { images: prompt.images } : {}),\n ...(prompt.streamingBehavior ? { streamingBehavior: prompt.streamingBehavior } : {}),\n source: \"rpc\",\n preflightResult(success) {\n if (success) {\n accepted = true;\n respond(prompt, true);\n }\n },\n });\n } catch (error) {\n if (!accepted) throw error;\n // Provider failures normally arrive in message_end. A later host\n // failure must still be visible instead of silently losing the run.\n transport.write({ type: \"runtime.error\", error: error instanceof Error ? error.message : String(error) });\n }\n break;\n }\n case \"steer\":\n if (typeof command.message !== \"string\") throw new Error(\"Steer message must be a string\");\n await session.steer(command.message, command.images);\n respond(command, true);\n break;\n case \"abort\":\n await session.abort();\n respond(command, true);\n break;\n case \"get_state\":\n respond(command, true, {\n model: session.model, thinkingLevel: session.thinkingLevel,\n isStreaming: session.isStreaming, isCompacting: session.isCompacting,\n sessionFile: session.sessionFile, sessionId: session.sessionId, piVersion: VERSION,\n messageCount: session.messages.length, pendingMessageCount: session.pendingMessageCount,\n });\n break;\n default:\n respond(command, false, `Unsupported Mote Pi command: ${command.type}`);\n }\n } catch (error) {\n respond(command ?? { type: \"parse\" }, false, error instanceof Error ? error.message : String(error));\n }\n await transport.drain();\n };\n\n try {\n // Control metadata precedes native output so even the first event can be\n // attributed to the installed Pi version and the resumed session.\n transport.write({ type: \"response\", command: \"get_state\", success: true,\n data: { sessionId: session.sessionId, piVersion: VERSION } });\n await session.bindExtensions({\n mode: \"rpc\",\n shutdownHandler: closeInput,\n onError(error) {\n transport.write({ type: \"extension_error\", ...error });\n },\n });\n if (closing || transport.signal?.aborted) return;\n await new Promise<void>((resolve, reject) => {\n input.on(\"line\", (line) => {\n if (closing) return;\n const task = handle(line);\n tasks.add(task);\n void task.then(() => tasks.delete(task), reject);\n });\n input.once(\"close\", resolve);\n input.once(\"error\", reject);\n input.resume();\n });\n } finally {\n closing = true;\n transport.signal?.removeEventListener(\"abort\", closeInput);\n input.close();\n transport.input.pause();\n try {\n await session.abort();\n await Promise.allSettled(tasks);\n } finally {\n unsubscribe();\n unsubscribeBackpressure();\n await runtime.dispose();\n await transport.drain();\n }\n }\n}\n", "#!/usr/bin/env node\nimport { runMotePiRpc } from \"./pi-rpc-runtime.js\";\n\nconst agentDir = process.env.PI_CODING_AGENT_DIR?.trim();\nif (!agentDir) {\n process.stderr.write(\"[mote-pi-rpc] PI_CODING_AGENT_DIR is required\\n\");\n process.exit(1);\n}\n\nprocess.title = \"mote-pi-rpc\";\nprocess.env.PI_CODING_AGENT = \"true\";\nprocess.env.AI_AGENT = \"pi\";\n\ntry {\n await runMotePiRpc(process.argv.slice(2), {\n cwd: process.cwd(),\n agentDir,\n });\n} catch (error) {\n const message = error instanceof Error ? error.stack ?? error.message : String(error);\n process.stderr.write(`[mote-pi-rpc] ${message}\\n`);\n process.exit(1);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["agentDir"]
7
+ }
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@liy/mote-pi-runtime",
3
+ "version": "0.3.0",
4
+ "private": false,
5
+ "description": "Per-run Mote agent runtime: the Pi RPC bridge, precompiled Pi extensions, and agent skills.",
6
+ "license": "UNLICENSED",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "provenance": false
10
+ },
11
+ "type": "module",
12
+ "bin": {
13
+ "mote-pi-rpc": "./dist/pi-rpc.js",
14
+ "orchestrator": "./dist/cli.js"
15
+ },
16
+ "mote": {
17
+ "contract": 1
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "CHANGELOG.md",
22
+ "README.md"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/liy/mote-app.git",
27
+ "directory": "mote-pi-runtime"
28
+ },
29
+ "engines": {
30
+ "node": ">=24.0.0"
31
+ },
32
+ "dependencies": {
33
+ "@earendil-works/pi-ai": "0.84.4",
34
+ "@earendil-works/pi-coding-agent": "0.84.4",
35
+ "pi-mcp-adapter": "2.32.1",
36
+ "pi-web-access": "0.29.0",
37
+ "@liy/mote-agentic-component-catalog": "0.2.5"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^24.5.2",
41
+ "esbuild": "0.27.7",
42
+ "typescript": "^5.9.3",
43
+ "vitest": "^3.2.4",
44
+ "@liy/sandbox-orchestrator": "0.1.0",
45
+ "@liy/mote-core": "0.1.3"
46
+ },
47
+ "scripts": {
48
+ "build:local": "node ../scripts/build-node-esm.mjs && node scripts/compile-extensions.mjs",
49
+ "build": "pnpm --dir ../mote-core build:local && pnpm --dir ../mote-agentic-component-catalog build:local && pnpm --dir ../sandbox-orchestrator build:local && pnpm build:local",
50
+ "release:check": "pnpm pack --dry-run",
51
+ "test:local": "vitest run --passWithNoTests",
52
+ "test": "pnpm build && pnpm test:local",
53
+ "typecheck:local": "tsc --noEmit -p tsconfig.json",
54
+ "typecheck": "pnpm --dir ../mote-core build && pnpm --dir ../sandbox-orchestrator build:local && pnpm typecheck:local"
55
+ }
56
+ }