pipane 0.1.5 → 0.1.7

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 (138) hide show
  1. package/README.md +45 -1
  2. package/THIRD_PARTY_NOTICES.md +29 -0
  3. package/bin/pipane-rendezvous.js +21 -0
  4. package/bin/pipane.js +21 -1
  5. package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  6. package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  7. package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  8. package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  9. package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  10. package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  11. package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  12. package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  13. package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  14. package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  15. package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  16. package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  17. package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  18. package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  19. package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  20. package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  21. package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  22. package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  23. package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  24. package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  25. package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  26. package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  27. package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  28. package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  29. package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  30. package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  31. package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  32. package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  33. package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  34. package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  35. package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  36. package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  37. package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  38. package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  39. package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  40. package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  41. package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  42. package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  43. package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  44. package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  45. package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  46. package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  47. package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  48. package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  49. package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  50. package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  51. package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  52. package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  53. package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  54. package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  55. package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  56. package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  57. package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  58. package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  59. package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  60. package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  61. package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  62. package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  63. package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  64. package/dist/client/assets/__vite-browser-external-DtLbhLGx.js +1 -0
  65. package/dist/client/assets/app-runtime-Rw-O-AwW.js +1 -0
  66. package/dist/client/assets/backend-landing-page-B7SbyIXQ.js +1 -0
  67. package/dist/client/assets/index-DwbBcYUf.js +2 -0
  68. package/dist/client/assets/index-iblQYBAl.css +1 -0
  69. package/dist/client/assets/main-LGItV9Aj.js +2807 -0
  70. package/dist/client/assets/pairing-page-D-WxlWZR.js +1 -0
  71. package/dist/client/assets/remote-backend-manager-BWuGh30I.js +1 -0
  72. package/dist/client/assets/rendezvous-trust-api-C2Zob5i4.js +4 -0
  73. package/dist/client/assets/webrtc-frame-transport-BijNnA7N.js +1 -0
  74. package/dist/client/assets/ws-agent-adapter-BRysf-Y7.js +6 -0
  75. package/dist/client/index.html +2 -2
  76. package/dist/server/rendezvous/rendezvous-hub.js +426 -0
  77. package/dist/server/rendezvous/server.js +247 -0
  78. package/dist/server/rendezvous/trust-store.js +432 -0
  79. package/dist/server/server/auth-guard.js +61 -0
  80. package/dist/server/server/backend-connection-authorizer.js +29 -0
  81. package/dist/server/server/backend-identity.js +167 -0
  82. package/dist/server/server/backend-protocol-handler.js +132 -0
  83. package/dist/server/server/backend-trust-store.js +157 -0
  84. package/dist/server/server/backend-webrtc.js +239 -0
  85. package/dist/server/server/bundled-extensions.js +6 -0
  86. package/dist/server/server/conversation-file-access.js +97 -0
  87. package/dist/server/server/extension-status.js +31 -0
  88. package/dist/server/server/frame-connection.js +48 -0
  89. package/dist/server/server/frame-router.js +45 -0
  90. package/dist/server/server/ice-servers.js +24 -0
  91. package/dist/server/server/local-backend-api.js +389 -0
  92. package/dist/server/server/local-settings.js +28 -0
  93. package/dist/server/server/pi-rpc-protocol.js +407 -0
  94. package/dist/server/server/pi-runtime.js +1 -1
  95. package/dist/server/server/process-pool.js +179 -136
  96. package/dist/server/server/rendezvous-client.js +282 -0
  97. package/dist/server/server/rest-api.js +121 -231
  98. package/dist/server/server/server.js +188 -134
  99. package/dist/server/server/session-actor.js +202 -0
  100. package/dist/server/server/session-index.js +111 -18
  101. package/dist/server/server/session-jsonl.js +128 -8
  102. package/dist/server/server/session-path.js +145 -0
  103. package/dist/server/server/session-registry.js +67 -0
  104. package/dist/server/server/update-api.js +28 -0
  105. package/dist/server/server/update-check.js +33 -13
  106. package/dist/server/server/update-manager.js +231 -0
  107. package/dist/server/server/worktree-name.js +124 -0
  108. package/dist/server/server/ws-handler.js +784 -478
  109. package/dist/server/shared/backend-api.js +1 -0
  110. package/dist/server/shared/backend-protocol.js +164 -0
  111. package/dist/server/shared/jsonl-sync.js +41 -0
  112. package/dist/server/shared/node-trust-crypto.js +61 -0
  113. package/dist/server/shared/rendezvous-protocol.js +243 -0
  114. package/dist/server/shared/rpc-timeouts.js +4 -0
  115. package/dist/server/shared/thinking-levels.js +94 -0
  116. package/dist/server/shared/tool-runtime.js +1 -0
  117. package/dist/server/shared/trust-protocol.js +97 -0
  118. package/dist/server/shared/updates.js +4 -0
  119. package/dist/server/shared/ws-protocol.js +473 -0
  120. package/docs/protocol.md +127 -0
  121. package/extensions/canvas.ts +1 -1
  122. package/package.json +42 -17
  123. package/dist/client/assets/_node-stub_node_crypto-C_7epg3G.js +0 -1
  124. package/dist/client/assets/_node-stub_node_fs-B-VOzeXW.js +0 -1
  125. package/dist/client/assets/_node-stub_node_http-CROXaVGJ.js +0 -1
  126. package/dist/client/assets/_node-stub_node_os-TTKJha15.js +0 -1
  127. package/dist/client/assets/_node-stub_node_path-DJCJiKv7.js +0 -1
  128. package/dist/client/assets/_node-stub_stream-DDexIdn_.js +0 -1
  129. package/dist/client/assets/index-BtDAXAo1.css +0 -1
  130. package/dist/client/assets/index-CAQqlK61.js +0 -131
  131. package/dist/client/assets/index-CJEeBmBj.js +0 -3
  132. package/dist/client/assets/index-DUEhKmPQ.js +0 -1
  133. package/dist/client/assets/index-XEVKscP-.js +0 -4443
  134. package/dist/client/assets/index-woI4agCy.js +0 -45
  135. package/dist/server/server/attached-session.js +0 -209
  136. package/dist/server/server/load-trace-store.js +0 -48
  137. package/dist/server/server/session-lifecycle.js +0 -155
  138. package/patches/@mariozechner+pi-web-ui+0.55.3.patch +0 -3437
@@ -0,0 +1,407 @@
1
+ import { StringDecoder } from "node:string_decoder";
2
+ const SUPPORTED_COMMAND_TYPES = [
3
+ "prompt",
4
+ "steer",
5
+ "abort",
6
+ "new_session",
7
+ "get_state",
8
+ "set_model",
9
+ "get_available_models",
10
+ "set_thinking_level",
11
+ "compact",
12
+ "get_session_stats",
13
+ "switch_session",
14
+ "fork",
15
+ "set_session_name",
16
+ "get_commands",
17
+ ];
18
+ class ValidationFailure extends Error {
19
+ constructor(path, message) {
20
+ super(`${path}: ${message}`);
21
+ }
22
+ }
23
+ function fail(path, message) {
24
+ throw new ValidationFailure(path, message);
25
+ }
26
+ function isRecord(value) {
27
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28
+ }
29
+ function record(value, path) {
30
+ if (!isRecord(value))
31
+ fail(path, "expected an object");
32
+ return value;
33
+ }
34
+ function string(value, path, allowEmpty = true) {
35
+ if (typeof value !== "string" || (!allowEmpty && value.length === 0)) {
36
+ fail(path, allowEmpty ? "expected a string" : "expected a non-empty string");
37
+ }
38
+ return value;
39
+ }
40
+ function optionalString(value, path) {
41
+ if (value !== undefined)
42
+ string(value, path);
43
+ }
44
+ function boolean(value, path) {
45
+ if (typeof value !== "boolean")
46
+ fail(path, "expected a boolean");
47
+ return value;
48
+ }
49
+ function integer(value, path) {
50
+ if (!Number.isSafeInteger(value) || value < 0)
51
+ fail(path, "expected a non-negative safe integer");
52
+ return value;
53
+ }
54
+ function finiteNumber(value, path) {
55
+ if (typeof value !== "number" || !Number.isFinite(value))
56
+ fail(path, "expected a finite number");
57
+ return value;
58
+ }
59
+ function array(value, path) {
60
+ if (!Array.isArray(value))
61
+ fail(path, "expected an array");
62
+ return value;
63
+ }
64
+ function stringArray(value, path) {
65
+ array(value, path).forEach((item, index) => string(item, `${path}[${index}]`));
66
+ }
67
+ function thinkingLevel(value, path) {
68
+ if (!["off", "minimal", "low", "medium", "high", "xhigh", "max"].includes(String(value))) {
69
+ fail(path, "expected a supported thinking level");
70
+ }
71
+ }
72
+ function model(value, path) {
73
+ const source = record(value, path);
74
+ string(source.provider, `${path}.provider`, false);
75
+ string(source.id, `${path}.id`, false);
76
+ }
77
+ function agentMessage(value, path) {
78
+ const message = record(value, path);
79
+ string(message.role, `${path}.role`, false);
80
+ }
81
+ function validateState(value, path) {
82
+ const state = record(value, path);
83
+ if (state.model !== undefined && state.model !== null)
84
+ model(state.model, `${path}.model`);
85
+ thinkingLevel(state.thinkingLevel, `${path}.thinkingLevel`);
86
+ boolean(state.isStreaming, `${path}.isStreaming`);
87
+ boolean(state.isCompacting, `${path}.isCompacting`);
88
+ if (state.steeringMode !== "all" && state.steeringMode !== "one-at-a-time") {
89
+ fail(`${path}.steeringMode`, "expected all or one-at-a-time");
90
+ }
91
+ if (state.followUpMode !== "all" && state.followUpMode !== "one-at-a-time") {
92
+ fail(`${path}.followUpMode`, "expected all or one-at-a-time");
93
+ }
94
+ optionalString(state.sessionFile, `${path}.sessionFile`);
95
+ string(state.sessionId, `${path}.sessionId`);
96
+ optionalString(state.sessionName, `${path}.sessionName`);
97
+ boolean(state.autoCompactionEnabled, `${path}.autoCompactionEnabled`);
98
+ integer(state.messageCount, `${path}.messageCount`);
99
+ integer(state.pendingMessageCount, `${path}.pendingMessageCount`);
100
+ }
101
+ function validateSlashCommands(value, path) {
102
+ array(value, path).forEach((item, index) => {
103
+ const command = record(item, `${path}[${index}]`);
104
+ string(command.name, `${path}[${index}].name`, false);
105
+ optionalString(command.description, `${path}[${index}].description`);
106
+ if (!["extension", "prompt", "skill"].includes(String(command.source))) {
107
+ fail(`${path}[${index}].source`, "expected extension, prompt, or skill");
108
+ }
109
+ if (command.sourceInfo !== undefined)
110
+ record(command.sourceInfo, `${path}[${index}].sourceInfo`);
111
+ });
112
+ }
113
+ function validateSessionStats(value, path) {
114
+ const stats = record(value, path);
115
+ optionalString(stats.sessionFile, `${path}.sessionFile`);
116
+ string(stats.sessionId, `${path}.sessionId`, false);
117
+ for (const field of ["userMessages", "assistantMessages", "toolCalls", "toolResults", "totalMessages"]) {
118
+ integer(stats[field], `${path}.${field}`);
119
+ }
120
+ const tokens = record(stats.tokens, `${path}.tokens`);
121
+ for (const field of ["input", "output", "cacheRead", "cacheWrite", "total"]) {
122
+ integer(tokens[field], `${path}.tokens.${field}`);
123
+ }
124
+ if (finiteNumber(stats.cost, `${path}.cost`) < 0)
125
+ fail(`${path}.cost`, "expected a non-negative number");
126
+ if (stats.contextUsage !== undefined) {
127
+ const context = record(stats.contextUsage, `${path}.contextUsage`);
128
+ if (context.tokens !== null)
129
+ integer(context.tokens, `${path}.contextUsage.tokens`);
130
+ integer(context.contextWindow, `${path}.contextUsage.contextWindow`);
131
+ if (context.percent !== null && finiteNumber(context.percent, `${path}.contextUsage.percent`) < 0) {
132
+ fail(`${path}.contextUsage.percent`, "expected a non-negative number or null");
133
+ }
134
+ }
135
+ }
136
+ const SUPPORTED_COMMAND_SET = new Set(SUPPORTED_COMMAND_TYPES);
137
+ function commandType(value, path) {
138
+ const type = string(value, path, false);
139
+ if (!SUPPORTED_COMMAND_SET.has(type))
140
+ fail(path, `unexpected command '${type}'`);
141
+ return type;
142
+ }
143
+ function validateResponse(value) {
144
+ string(value.id, "$rpc.id", false);
145
+ const command = commandType(value.command, "$rpc.command");
146
+ const success = boolean(value.success, "$rpc.success");
147
+ if (!success) {
148
+ string(value.error, "$rpc.error", false);
149
+ return value;
150
+ }
151
+ switch (command) {
152
+ case "prompt":
153
+ case "steer":
154
+ case "abort":
155
+ case "set_thinking_level":
156
+ case "set_session_name":
157
+ break;
158
+ case "new_session":
159
+ case "switch_session": {
160
+ const data = record(value.data, "$rpc.data");
161
+ boolean(data.cancelled, "$rpc.data.cancelled");
162
+ break;
163
+ }
164
+ case "get_state":
165
+ validateState(value.data, "$rpc.data");
166
+ break;
167
+ case "set_model":
168
+ model(value.data, "$rpc.data");
169
+ break;
170
+ case "get_available_models": {
171
+ const data = record(value.data, "$rpc.data");
172
+ array(data.models, "$rpc.data.models").forEach((item, index) => model(item, `$rpc.data.models[${index}]`));
173
+ break;
174
+ }
175
+ case "compact":
176
+ record(value.data, "$rpc.data");
177
+ break;
178
+ case "get_session_stats":
179
+ validateSessionStats(value.data, "$rpc.data");
180
+ break;
181
+ case "fork": {
182
+ const data = record(value.data, "$rpc.data");
183
+ string(data.text, "$rpc.data.text");
184
+ boolean(data.cancelled, "$rpc.data.cancelled");
185
+ break;
186
+ }
187
+ case "get_commands": {
188
+ const data = record(value.data, "$rpc.data");
189
+ validateSlashCommands(data.commands, "$rpc.data.commands");
190
+ break;
191
+ }
192
+ }
193
+ return value;
194
+ }
195
+ function validateExtensionUiRequest(value) {
196
+ string(value.id, "$rpc.id", false);
197
+ const method = string(value.method, "$rpc.method", false);
198
+ switch (method) {
199
+ case "select":
200
+ string(value.title, "$rpc.title");
201
+ stringArray(value.options, "$rpc.options");
202
+ if (value.timeout !== undefined)
203
+ integer(value.timeout, "$rpc.timeout");
204
+ break;
205
+ case "confirm":
206
+ string(value.title, "$rpc.title");
207
+ string(value.message, "$rpc.message");
208
+ if (value.timeout !== undefined)
209
+ integer(value.timeout, "$rpc.timeout");
210
+ break;
211
+ case "input":
212
+ string(value.title, "$rpc.title");
213
+ optionalString(value.placeholder, "$rpc.placeholder");
214
+ if (value.timeout !== undefined)
215
+ integer(value.timeout, "$rpc.timeout");
216
+ break;
217
+ case "editor":
218
+ string(value.title, "$rpc.title");
219
+ optionalString(value.prefill, "$rpc.prefill");
220
+ break;
221
+ case "notify":
222
+ string(value.message, "$rpc.message");
223
+ if (value.notifyType !== undefined && !["info", "warning", "error"].includes(String(value.notifyType))) {
224
+ fail("$rpc.notifyType", "expected info, warning, or error");
225
+ }
226
+ break;
227
+ case "setStatus":
228
+ string(value.statusKey, "$rpc.statusKey", false);
229
+ optionalString(value.statusText, "$rpc.statusText");
230
+ break;
231
+ case "setWidget":
232
+ string(value.widgetKey, "$rpc.widgetKey", false);
233
+ if (value.widgetLines !== undefined)
234
+ stringArray(value.widgetLines, "$rpc.widgetLines");
235
+ if (value.widgetPlacement !== undefined && value.widgetPlacement !== "aboveEditor" && value.widgetPlacement !== "belowEditor") {
236
+ fail("$rpc.widgetPlacement", "expected aboveEditor or belowEditor");
237
+ }
238
+ break;
239
+ case "setTitle":
240
+ string(value.title, "$rpc.title");
241
+ break;
242
+ case "set_editor_text":
243
+ string(value.text, "$rpc.text");
244
+ break;
245
+ default:
246
+ fail("$rpc.method", `unknown extension UI method '${method}'`);
247
+ }
248
+ return value;
249
+ }
250
+ function validateEvent(value, type) {
251
+ switch (type) {
252
+ case "agent_start":
253
+ case "agent_settled":
254
+ case "turn_start":
255
+ break;
256
+ case "agent_end":
257
+ array(value.messages, "$rpc.messages").forEach((item, index) => agentMessage(item, `$rpc.messages[${index}]`));
258
+ boolean(value.willRetry, "$rpc.willRetry");
259
+ break;
260
+ case "turn_end":
261
+ agentMessage(value.message, "$rpc.message");
262
+ array(value.toolResults, "$rpc.toolResults").forEach((item, index) => agentMessage(item, `$rpc.toolResults[${index}]`));
263
+ break;
264
+ case "message_start":
265
+ case "message_end":
266
+ agentMessage(value.message, "$rpc.message");
267
+ break;
268
+ case "message_update":
269
+ agentMessage(value.message, "$rpc.message");
270
+ record(value.assistantMessageEvent, "$rpc.assistantMessageEvent");
271
+ break;
272
+ case "tool_execution_start":
273
+ string(value.toolCallId, "$rpc.toolCallId", false);
274
+ string(value.toolName, "$rpc.toolName", false);
275
+ record(value.args, "$rpc.args");
276
+ break;
277
+ case "tool_execution_update":
278
+ string(value.toolCallId, "$rpc.toolCallId", false);
279
+ string(value.toolName, "$rpc.toolName", false);
280
+ record(value.args, "$rpc.args");
281
+ record(value.partialResult, "$rpc.partialResult");
282
+ break;
283
+ case "tool_execution_end":
284
+ string(value.toolCallId, "$rpc.toolCallId", false);
285
+ string(value.toolName, "$rpc.toolName", false);
286
+ record(value.result, "$rpc.result");
287
+ boolean(value.isError, "$rpc.isError");
288
+ break;
289
+ case "queue_update":
290
+ stringArray(value.steering, "$rpc.steering");
291
+ stringArray(value.followUp, "$rpc.followUp");
292
+ break;
293
+ case "compaction_start":
294
+ if (!["manual", "threshold", "overflow"].includes(String(value.reason)))
295
+ fail("$rpc.reason", "expected a compaction reason");
296
+ break;
297
+ case "compaction_end":
298
+ if (!["manual", "threshold", "overflow"].includes(String(value.reason)))
299
+ fail("$rpc.reason", "expected a compaction reason");
300
+ if (value.result !== undefined && value.result !== null)
301
+ record(value.result, "$rpc.result");
302
+ boolean(value.aborted, "$rpc.aborted");
303
+ boolean(value.willRetry, "$rpc.willRetry");
304
+ optionalString(value.errorMessage, "$rpc.errorMessage");
305
+ break;
306
+ case "auto_retry_start":
307
+ integer(value.attempt, "$rpc.attempt");
308
+ integer(value.maxAttempts, "$rpc.maxAttempts");
309
+ integer(value.delayMs, "$rpc.delayMs");
310
+ string(value.errorMessage, "$rpc.errorMessage");
311
+ break;
312
+ case "auto_retry_end":
313
+ boolean(value.success, "$rpc.success");
314
+ integer(value.attempt, "$rpc.attempt");
315
+ optionalString(value.finalError, "$rpc.finalError");
316
+ break;
317
+ case "entry_appended":
318
+ record(value.entry, "$rpc.entry");
319
+ break;
320
+ case "session_info_changed":
321
+ optionalString(value.name, "$rpc.name");
322
+ break;
323
+ case "thinking_level_changed":
324
+ thinkingLevel(value.level, "$rpc.level");
325
+ break;
326
+ case "extension_error":
327
+ string(value.extensionPath, "$rpc.extensionPath");
328
+ string(value.event, "$rpc.event");
329
+ string(value.error, "$rpc.error");
330
+ break;
331
+ default:
332
+ fail("$rpc.type", `unknown event '${type}'`);
333
+ }
334
+ return value;
335
+ }
336
+ /** Validate one complete line emitted by Pi RPC before it reaches state mutation. */
337
+ export function decodePiRpcLine(line) {
338
+ let parsed;
339
+ try {
340
+ parsed = JSON.parse(line);
341
+ }
342
+ catch (error) {
343
+ return {
344
+ ok: false,
345
+ error: {
346
+ message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
347
+ line,
348
+ },
349
+ };
350
+ }
351
+ try {
352
+ const value = record(parsed, "$rpc");
353
+ const type = string(value.type, "$rpc.type", false);
354
+ if (type === "response")
355
+ return { ok: true, value: validateResponse(value) };
356
+ if (type === "extension_ui_request")
357
+ return { ok: true, value: validateExtensionUiRequest(value) };
358
+ return { ok: true, value: validateEvent(value, type) };
359
+ }
360
+ catch (error) {
361
+ return {
362
+ ok: false,
363
+ error: {
364
+ message: error instanceof Error ? error.message : String(error),
365
+ line,
366
+ },
367
+ };
368
+ }
369
+ }
370
+ /**
371
+ * Pi RPC is strict JSONL: only LF delimits records. Node readline also splits on
372
+ * U+2028/U+2029, so use this decoder for protocol-compliant framing.
373
+ */
374
+ export function attachStrictJsonlReader(stream, onLine) {
375
+ const decoder = new StringDecoder("utf8");
376
+ let buffer = "";
377
+ const consume = (chunk) => {
378
+ buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
379
+ while (true) {
380
+ const newline = buffer.indexOf("\n");
381
+ if (newline === -1)
382
+ break;
383
+ let line = buffer.slice(0, newline);
384
+ buffer = buffer.slice(newline + 1);
385
+ if (line.endsWith("\r"))
386
+ line = line.slice(0, -1);
387
+ if (line.length > 0)
388
+ onLine(line);
389
+ }
390
+ };
391
+ const end = () => {
392
+ buffer += decoder.end();
393
+ if (buffer.length > 0)
394
+ onLine(buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer);
395
+ buffer = "";
396
+ };
397
+ stream.on("data", consume);
398
+ stream.on("end", end);
399
+ return () => {
400
+ stream.removeListener("data", consume);
401
+ stream.removeListener("end", end);
402
+ };
403
+ }
404
+ /** Build a correlated command line after static command typing has succeeded. */
405
+ export function encodePiRpcCommand(command, id) {
406
+ return `${JSON.stringify({ ...command, id })}\n`;
407
+ }
@@ -24,7 +24,7 @@ export function makePiNotFoundMessage(command) {
24
24
  }
25
25
  export async function installPiGlobal(deps = {}) {
26
26
  const spawnSync = deps.spawnSync ?? childSpawnSync;
27
- const result = spawnSync("npm", ["install", "-g", "@mariozechner/pi-coding-agent"], {
27
+ const result = spawnSync("npm", ["install", "-g", "@earendil-works/pi-coding-agent"], {
28
28
  stdio: "inherit",
29
29
  env: process.env,
30
30
  });