@evandu/super-pi 0.1.82 → 0.1.84
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/README.md +174 -164
- package/bin/super-pi.js +59 -122
- package/dist/client/.super-pi-client-sources.json +5 -5
- package/dist/client/assets/index-8Pf3MG2d.js +72 -0
- package/dist/client/assets/index-Jnj15dhT.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/application/run-service.js +49 -7
- package/dist/server/command-handler.d.ts +2 -4
- package/dist/server/command-handler.js +3 -7
- package/dist/server/http-server.js +19 -2
- package/dist/server/index.js +3 -7
- package/dist/server/runtime.js +49 -5
- package/dist/server/store.d.ts +24 -0
- package/dist/server/store.js +46 -0
- package/dist/server/terminal.d.ts +4 -6
- package/dist/server/terminal.js +9 -13
- package/dist/server/types.d.ts +15 -0
- package/package.json +155 -151
- package/dist/client/assets/index-BXkoUfEn.js +0 -58
- package/dist/client/assets/index-BaL1YDWD.css +0 -1
package/dist/server/runtime.js
CHANGED
|
@@ -232,9 +232,22 @@ export function taskExtensionPath(from = import.meta.dirname) {
|
|
|
232
232
|
* The tool's name as far as the stream has revealed it so far, or an empty string while the model is
|
|
233
233
|
* still on the first token. Deliberately NOT a placeholder: a block labelled 「工具」 tells the reader
|
|
234
234
|
* nothing they cannot already see, whereas one labelled 'edit' one second early is the whole point.
|
|
235
|
+
*
|
|
236
|
+
* THE EVENT IS READ BEFORE `partial`, and that order is the whole fix. This used to look only at
|
|
237
|
+
* `partial` - the half-built assistant message - which is where the Anthropic and pi-messages converters
|
|
238
|
+
* put the toolCall block. Real Pi does NOT send it: a live RPC probe against Pi itself returns
|
|
239
|
+
* `toolcall_start {"contentIndex":1,"id":"call_…","toolName":"read","hasPartial":false}`, the name on the
|
|
240
|
+
* event and no `partial` at all. So this returned "" for every call the user ever made, every placeholder
|
|
241
|
+
* row was filed under an empty name, and the name-based lookup that pairs a call with the row the reader
|
|
242
|
+
* is already looking at could never match - see `onToolCall` in application/run-service.ts, which then
|
|
243
|
+
* fell back to recency and put the calls on each other's rows. Reading `toolName` first is what makes the
|
|
244
|
+
* pairing work at all; `partial` stays as the fallback for a Pi that only fills the message.
|
|
235
245
|
*/
|
|
236
|
-
function toolNameOf(
|
|
237
|
-
const
|
|
246
|
+
function toolNameOf(event) {
|
|
247
|
+
const direct = event?.toolName;
|
|
248
|
+
if (typeof direct === "string" && direct)
|
|
249
|
+
return direct;
|
|
250
|
+
const content = event?.partial?.content;
|
|
238
251
|
const block = Array.isArray(content) ? content.find((item) => item?.type === "toolCall") : undefined;
|
|
239
252
|
return typeof block?.name === "string" ? block.name : "";
|
|
240
253
|
}
|
|
@@ -705,12 +718,13 @@ export class PiRpcRuntime {
|
|
|
705
718
|
// A fresh index means a fresh call, so anything the PREVIOUS call at this index wrote is
|
|
706
719
|
// dropped here rather than carried into this one's first fragment.
|
|
707
720
|
argumentText.delete(event.contentIndex);
|
|
708
|
-
|
|
709
|
-
|
|
721
|
+
const name = toolNameOf(event);
|
|
722
|
+
toolNames.set(event.contentIndex, name);
|
|
723
|
+
onToolPreparing?.({ contentIndex: event.contentIndex, name });
|
|
710
724
|
}
|
|
711
725
|
else if (event?.type === "toolcall_delta" && typeof event.contentIndex === "number") {
|
|
712
726
|
const delta = typeof event.delta === "string" ? event.delta : "";
|
|
713
|
-
//
|
|
727
|
+
// THE NAME IS CARRIED FORWARD because the line naming the call needs it: `toolcall_start`
|
|
714
728
|
// is the only event that carries one, and by the second fragment the mapping has to choose
|
|
715
729
|
// between a `read`'s path and a `bash`'s command.
|
|
716
730
|
const name = toolNames.get(event.contentIndex) ?? "";
|
|
@@ -723,6 +737,36 @@ export class PiRpcRuntime {
|
|
|
723
737
|
const detail = describeToolCallInProgress(name, text);
|
|
724
738
|
onToolPreparing?.({ contentIndex: event.contentIndex, name, ...(text ? { live: text } : {}), ...(detail ? { detail } : {}) });
|
|
725
739
|
}
|
|
740
|
+
// `toolcall_end` IS THE ARGUMENTS, FINISHED - and this branch is what stops a call that Pi
|
|
741
|
+
// announced but never ran from rendering as a call with no parameters at all.
|
|
742
|
+
//
|
|
743
|
+
// Until `tool_execution_start`, a row's parameters exist only as the JSON text streaming past
|
|
744
|
+
// in `live`, which the transcript deliberately does not show as parameters. So a call the turn
|
|
745
|
+
// cut off mid-flight - an abort, a cancelled turn, an upstream error - reached the reader as
|
|
746
|
+
// 「正在生成参数…」 above 「(这次调用没有可显示的参数)」, the two halves of which are the same fact: the
|
|
747
|
+
// parameters were known and were not shown. Pi puts the completed object on this event, so the
|
|
748
|
+
// row gets its real parameters from here instead.
|
|
749
|
+
//
|
|
750
|
+
// Reduced exactly as everywhere else (`describeToolCallArgs`), so this is the same bounded
|
|
751
|
+
// derivation and not the arguments themselves, and the raw object stops at this line.
|
|
752
|
+
else if (event?.type === "toolcall_end" && typeof event.contentIndex === "number") {
|
|
753
|
+
const toolCall = event.toolCall;
|
|
754
|
+
const name = typeof toolCall?.name === "string" && toolCall.name ? toolCall.name : (toolNames.get(event.contentIndex) ?? "");
|
|
755
|
+
// The name this event carries is the authoritative one, so a row filed under an empty name
|
|
756
|
+
// by a start that carried none can still be paired with its execution.
|
|
757
|
+
if (name)
|
|
758
|
+
toolNames.set(event.contentIndex, name);
|
|
759
|
+
const args = describeToolCallArgs(toolCall?.arguments);
|
|
760
|
+
const text = argumentText.get(event.contentIndex) ?? "";
|
|
761
|
+
// `detail` GOES OUT ONLY WHEN NOTHING HAS DERIVED ONE. The delta path reads the same target
|
|
762
|
+
// out of the same text a fragment earlier, so re-sending it would be a patch that changes
|
|
763
|
+
// nothing - and a patch that changes nothing still publishes a frame, which is one more
|
|
764
|
+
// `message.tools` broadcast per call for no reader-visible change. The one case it earns its
|
|
765
|
+
// place in is a call whose fragments never became readable, where this is the last moment
|
|
766
|
+
// the parameters are available to name the target from.
|
|
767
|
+
const detail = describeToolCall(name, toolCall?.arguments);
|
|
768
|
+
onToolPreparing?.({ contentIndex: event.contentIndex, name, final: true, ...(args ? { args } : {}), ...(!describeToolCallInProgress(name, text) && detail ? { detail } : {}) });
|
|
769
|
+
}
|
|
726
770
|
// Pi's reasoning lifecycle is three events, not one flag: `thinking_delta` means the model is
|
|
727
771
|
// STILL THINKING RIGHT NOW, and `thinking_end` is the only thing that says it stopped. There is
|
|
728
772
|
// deliberately no `active` field read here - every `thinking_delta` in Pi's wire shape carries
|
package/dist/server/store.d.ts
CHANGED
|
@@ -307,6 +307,30 @@ export declare class Store {
|
|
|
307
307
|
question?: ToolCallQuestion;
|
|
308
308
|
backgroundTask?: ToolCallBlock["backgroundTask"];
|
|
309
309
|
}): Promise<ToolCallBlock[]>;
|
|
310
|
+
/**
|
|
311
|
+
* STOPS SEVERAL ROWS FROM CLAIMING THE MODEL IS STILL WRITING THEM, in one write.
|
|
312
|
+
*
|
|
313
|
+
* A row is created by `toolcall_start` and filled in by `tool_execution_start`, so a call the turn cut
|
|
314
|
+
* off between the two - an abort, a cancelled turn, an upstream error - kept `preparing` for the rest of
|
|
315
|
+
* time. A finished turn showing 「生成参数中…」 is the same expensive lie as a settled tool still saying
|
|
316
|
+
* 「正在生成参数…」: it says the agent is working on something it has already stopped doing, and it is
|
|
317
|
+
* what a reader sees on every such row for the rest of the conversation.
|
|
318
|
+
*
|
|
319
|
+
* WHAT IS *NOT* WRITTEN HERE, and the omissions are the point. No `status`: Pi reported no outcome for
|
|
320
|
+
* these calls, and `status` is the field that says an outcome was observed - writing `"error"` would
|
|
321
|
+
* claim the tool failed, which is a different fact from "it never ran". No `result`, for the same
|
|
322
|
+
* reason. `preparing: false` alone says exactly what is true, which is that the arguments stopped
|
|
323
|
+
* arriving.
|
|
324
|
+
*
|
|
325
|
+
* `live` IS CLEARED, because during preparation that field holds the ARGUMENT TEXT and the transcript
|
|
326
|
+
* would otherwise print a raw JSON fragment under a call that never ran. The parameters themselves are
|
|
327
|
+
* not lost: `args` carries them from `toolcall_end`, and `detail` has named the target since the first
|
|
328
|
+
* readable fragment.
|
|
329
|
+
*
|
|
330
|
+
* Addressed by position like every other row write, and one that is not there is skipped rather than
|
|
331
|
+
* failing the turn - the same tolerance `settleToolCall` has for an id it cannot resolve.
|
|
332
|
+
*/
|
|
333
|
+
clearPreparingToolCalls(conversationId: string, messageId: string, rows: readonly number[]): Promise<ToolCallBlock[]>;
|
|
310
334
|
setStatus(conversationId: string, status: Conversation["status"]): Promise<void>;
|
|
311
335
|
/** The plan a revert would carry out, without carrying it out. The server reads this to stop children first. */
|
|
312
336
|
planRevert(conversationId: string, messageId: string, withdraw?: boolean): RevertPlan;
|
package/dist/server/store.js
CHANGED
|
@@ -1084,6 +1084,52 @@ export class Store {
|
|
|
1084
1084
|
await this.persist();
|
|
1085
1085
|
return structuredClone(calls);
|
|
1086
1086
|
}
|
|
1087
|
+
/**
|
|
1088
|
+
* STOPS SEVERAL ROWS FROM CLAIMING THE MODEL IS STILL WRITING THEM, in one write.
|
|
1089
|
+
*
|
|
1090
|
+
* A row is created by `toolcall_start` and filled in by `tool_execution_start`, so a call the turn cut
|
|
1091
|
+
* off between the two - an abort, a cancelled turn, an upstream error - kept `preparing` for the rest of
|
|
1092
|
+
* time. A finished turn showing 「生成参数中…」 is the same expensive lie as a settled tool still saying
|
|
1093
|
+
* 「正在生成参数…」: it says the agent is working on something it has already stopped doing, and it is
|
|
1094
|
+
* what a reader sees on every such row for the rest of the conversation.
|
|
1095
|
+
*
|
|
1096
|
+
* WHAT IS *NOT* WRITTEN HERE, and the omissions are the point. No `status`: Pi reported no outcome for
|
|
1097
|
+
* these calls, and `status` is the field that says an outcome was observed - writing `"error"` would
|
|
1098
|
+
* claim the tool failed, which is a different fact from "it never ran". No `result`, for the same
|
|
1099
|
+
* reason. `preparing: false` alone says exactly what is true, which is that the arguments stopped
|
|
1100
|
+
* arriving.
|
|
1101
|
+
*
|
|
1102
|
+
* `live` IS CLEARED, because during preparation that field holds the ARGUMENT TEXT and the transcript
|
|
1103
|
+
* would otherwise print a raw JSON fragment under a call that never ran. The parameters themselves are
|
|
1104
|
+
* not lost: `args` carries them from `toolcall_end`, and `detail` has named the target since the first
|
|
1105
|
+
* readable fragment.
|
|
1106
|
+
*
|
|
1107
|
+
* Addressed by position like every other row write, and one that is not there is skipped rather than
|
|
1108
|
+
* failing the turn - the same tolerance `settleToolCall` has for an id it cannot resolve.
|
|
1109
|
+
*/
|
|
1110
|
+
async clearPreparingToolCalls(conversationId, messageId, rows) {
|
|
1111
|
+
const conversation = this.requireConversation(conversationId);
|
|
1112
|
+
const message = conversation.messages.find((item) => item.id === messageId);
|
|
1113
|
+
if (!message)
|
|
1114
|
+
throw new Error("Assistant message not found");
|
|
1115
|
+
const calls = message.toolCalls;
|
|
1116
|
+
if (!calls)
|
|
1117
|
+
return [];
|
|
1118
|
+
let touched = false;
|
|
1119
|
+
for (const index of rows) {
|
|
1120
|
+
const call = calls[index];
|
|
1121
|
+
if (!call || call.preparing !== true)
|
|
1122
|
+
continue;
|
|
1123
|
+
call.preparing = false;
|
|
1124
|
+
call.live = "";
|
|
1125
|
+
touched = true;
|
|
1126
|
+
}
|
|
1127
|
+
if (touched) {
|
|
1128
|
+
conversation.updatedAt = now();
|
|
1129
|
+
await this.persist();
|
|
1130
|
+
}
|
|
1131
|
+
return structuredClone(calls);
|
|
1132
|
+
}
|
|
1087
1133
|
async setStatus(conversationId, status) { const conversation = this.requireConversation(conversationId); conversation.status = status; conversation.updatedAt = now(); await this.persistMetadata(conversationId); }
|
|
1088
1134
|
/** The plan a revert would carry out, without carrying it out. The server reads this to stop children first. */
|
|
1089
1135
|
planRevert(conversationId, messageId, withdraw = false) { return planRevert(this.state, conversationId, messageId, withdraw); }
|
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* So the guards here are deliberately redundant, and each one closes a hole the others do not:
|
|
22
22
|
*
|
|
23
|
-
* 1.
|
|
24
|
-
*
|
|
25
|
-
* it is a deliberate act by someone who knows what it does.
|
|
23
|
+
* 1. AVAILABLE BY DEFAULT. The terminal is a built-in local capability. Network scope, workspace
|
|
24
|
+
* resolution, and bounded sessions still protect every command.
|
|
26
25
|
* 2. NETWORK SCOPE. Even enabled, a command is refused unless the WebSocket arrived from loopback or
|
|
27
26
|
* an RFC 1918 / link-local / ULA address (`isLocalOrPrivateAddress`, the same predicate the file
|
|
28
27
|
* endpoints use). A request that arrives from a routed or proxied address is refused by name.
|
|
@@ -48,7 +47,6 @@
|
|
|
48
47
|
*
|
|
49
48
|
* `node-pty` allocates a real pseudo-terminal (ConPTY on Windows, `forkpty` elsewhere), which is the
|
|
50
49
|
* only way to get them. The cost is a native module, and it is paid only by operators who set
|
|
51
|
-
* `SUPER_PI_TERMINAL=1` - see `loadPty` below, which is reached lazily and never at import time.
|
|
52
50
|
*/
|
|
53
51
|
import type { ServerEvent, Workspace } from "./types.js";
|
|
54
52
|
/** One shell per browser tab, and a hard ceiling so reconnects cannot accumulate processes. */
|
|
@@ -99,11 +97,11 @@ export type TerminalEvent = {
|
|
|
99
97
|
reason?: string;
|
|
100
98
|
};
|
|
101
99
|
/**
|
|
102
|
-
*
|
|
100
|
+
* The terminal is built in; node-pty availability is checked when a session opens.
|
|
103
101
|
*/
|
|
104
102
|
export declare function isTerminalEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
105
103
|
/** The sentence a browser shows when the terminal is missing. Says WHICH of the three gates closed. */
|
|
106
|
-
export declare function terminalDisabledReason(
|
|
104
|
+
export declare function terminalDisabledReason(_env?: NodeJS.ProcessEnv): string;
|
|
107
105
|
export declare class TerminalService {
|
|
108
106
|
private readonly sessions;
|
|
109
107
|
private readonly workspaceFor;
|
package/dist/server/terminal.js
CHANGED
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* So the guards here are deliberately redundant, and each one closes a hole the others do not:
|
|
22
22
|
*
|
|
23
|
-
* 1.
|
|
24
|
-
*
|
|
25
|
-
* it is a deliberate act by someone who knows what it does.
|
|
23
|
+
* 1. AVAILABLE BY DEFAULT. The terminal is a built-in local capability. Network scope, workspace
|
|
24
|
+
* resolution, and bounded sessions still protect every command.
|
|
26
25
|
* 2. NETWORK SCOPE. Even enabled, a command is refused unless the WebSocket arrived from loopback or
|
|
27
26
|
* an RFC 1918 / link-local / ULA address (`isLocalOrPrivateAddress`, the same predicate the file
|
|
28
27
|
* endpoints use). A request that arrives from a routed or proxied address is refused by name.
|
|
@@ -48,7 +47,6 @@
|
|
|
48
47
|
*
|
|
49
48
|
* `node-pty` allocates a real pseudo-terminal (ConPTY on Windows, `forkpty` elsewhere), which is the
|
|
50
49
|
* only way to get them. The cost is a native module, and it is paid only by operators who set
|
|
51
|
-
* `SUPER_PI_TERMINAL=1` - see `loadPty` below, which is reached lazily and never at import time.
|
|
52
50
|
*/
|
|
53
51
|
import { createRequire } from "node:module";
|
|
54
52
|
import { existsSync } from "node:fs";
|
|
@@ -60,8 +58,8 @@ let ptyLoadFailure;
|
|
|
60
58
|
*
|
|
61
59
|
* `import("node-pty")` would be evaluated by the bundler/compiler as a real dynamic import of a package
|
|
62
60
|
* the project does not depend on by default, and its rejection is a load-time failure of the WHOLE
|
|
63
|
-
* server rather than of the terminal.
|
|
64
|
-
*
|
|
61
|
+
* server rather than of the terminal. A server can start without node-pty and report a useful error only
|
|
62
|
+
* when the terminal is used.
|
|
65
63
|
*
|
|
66
64
|
* `createRequire` sidesteps the module-resolution question entirely: this file is compiled to ESM by
|
|
67
65
|
* `tsconfig.server.json`, `node-pty` is CommonJS, and `require` is the one call that loads CJS from ESM
|
|
@@ -166,18 +164,16 @@ const MAX_CHUNK_BYTES = 64 * 1024;
|
|
|
166
164
|
/** Hard per-session backlog. Beyond this the session is considered runaway and is killed. */
|
|
167
165
|
const MAX_BACKLOG_BYTES = 4 * 1024 * 1024;
|
|
168
166
|
/**
|
|
169
|
-
*
|
|
167
|
+
* The terminal is built in; node-pty availability is checked when a session opens.
|
|
170
168
|
*/
|
|
171
169
|
export function isTerminalEnabled(env = process.env) {
|
|
172
|
-
|
|
173
|
-
return
|
|
170
|
+
void env;
|
|
171
|
+
return true;
|
|
174
172
|
}
|
|
175
173
|
/** The sentence a browser shows when the terminal is missing. Says WHICH of the three gates closed. */
|
|
176
|
-
export function terminalDisabledReason(
|
|
177
|
-
if (!isTerminalEnabled(env))
|
|
178
|
-
return "终端未启用。设置 SUPER_PI_TERMINAL=1 后重启即可使用。";
|
|
174
|
+
export function terminalDisabledReason(_env = process.env) {
|
|
179
175
|
if (ptyLoadFailure)
|
|
180
|
-
return
|
|
176
|
+
return "node-pty unavailable: " + ptyLoadFailure;
|
|
181
177
|
return "";
|
|
182
178
|
}
|
|
183
179
|
export class TerminalService {
|
package/dist/server/types.d.ts
CHANGED
|
@@ -262,12 +262,27 @@ export type ToolCallNotice = {
|
|
|
262
262
|
* field with two meanings would make the caller store one kind of text by appending and the other by
|
|
263
263
|
* replacing - which is a flicker and a duplication at once. Pi sends argument fragments raw; accumulating
|
|
264
264
|
* them is the runtime's job, where the fragments already are.
|
|
265
|
+
*
|
|
266
|
+
* `args` arrives ONLY at `toolcall_end`, where Pi hands over the finished argument object. Nothing before
|
|
267
|
+
* that point can produce it: `live` is raw JSON text, and a half-written document is not one. It is what
|
|
268
|
+
* gives a row its parameters before `tool_execution_start` announces the call, so a call the turn cut off
|
|
269
|
+
* mid-flight shows what it was going to do instead of 「(这次调用没有可显示的参数)」. Bounded by the same
|
|
270
|
+
* `describeToolCallArgs` derivation as every other arguments field, so it adds no new way for raw arguments
|
|
271
|
+
* to reach `state.json`.
|
|
272
|
+
*
|
|
273
|
+
* `final` says these are the FINISHED arguments, and it exists so that one cannot create a row. Pi emits
|
|
274
|
+
* `toolcall_end` whenever the argument document closes, which on a live probe is before the call runs -
|
|
275
|
+
* but a turn can also close a document after the call has already been announced and settled, and a
|
|
276
|
+
* notice that arrives then describes a row that is already on screen. A caller that treated it as an
|
|
277
|
+
* announcement would append a second, empty block for a call the reader is already looking at.
|
|
265
278
|
*/
|
|
266
279
|
export interface ToolCallPreparing {
|
|
267
280
|
contentIndex: number;
|
|
268
281
|
name: string;
|
|
269
282
|
live?: string;
|
|
270
283
|
detail?: string;
|
|
284
|
+
args?: ToolCallArg[];
|
|
285
|
+
final?: boolean;
|
|
271
286
|
}
|
|
272
287
|
/**
|
|
273
288
|
* `archivedAt` is the whole archive mechanism: a state MARKER, not a move. The conversation object never
|
package/package.json
CHANGED
|
@@ -1,151 +1,155 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@evandu/super-pi",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Web control plane and companion for Pi",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"super-pi": "bin/super-pi.js"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"dev
|
|
30
|
-
"dev:
|
|
31
|
-
"dev:
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"scripts/stream-
|
|
41
|
-
"scripts/
|
|
42
|
-
"scripts/
|
|
43
|
-
"scripts/
|
|
44
|
-
"scripts/
|
|
45
|
-
"scripts/
|
|
46
|
-
"scripts/dispatch-
|
|
47
|
-
"scripts/
|
|
48
|
-
"scripts/
|
|
49
|
-
"scripts/
|
|
50
|
-
"scripts/
|
|
51
|
-
"scripts/agent-
|
|
52
|
-
"scripts/
|
|
53
|
-
"scripts/
|
|
54
|
-
"scripts/
|
|
55
|
-
"scripts/
|
|
56
|
-
"scripts/image-
|
|
57
|
-
"scripts/
|
|
58
|
-
"scripts/
|
|
59
|
-
"scripts/
|
|
60
|
-
"scripts/
|
|
61
|
-
"scripts/
|
|
62
|
-
"scripts/subagent-
|
|
63
|
-
"scripts/
|
|
64
|
-
"scripts/
|
|
65
|
-
"scripts/
|
|
66
|
-
"scripts/workflow-
|
|
67
|
-
"scripts/workflow-
|
|
68
|
-
"scripts/workflow-
|
|
69
|
-
"scripts/
|
|
70
|
-
"scripts/
|
|
71
|
-
"scripts/
|
|
72
|
-
"scripts/
|
|
73
|
-
"scripts/
|
|
74
|
-
"scripts/revert-session-
|
|
75
|
-
"scripts/revert-
|
|
76
|
-
"scripts/
|
|
77
|
-
"scripts/
|
|
78
|
-
"scripts/tool
|
|
79
|
-
"scripts/
|
|
80
|
-
"scripts/files-
|
|
81
|
-
"scripts/
|
|
82
|
-
"scripts/
|
|
83
|
-
"scripts/
|
|
84
|
-
"scripts/
|
|
85
|
-
"scripts/
|
|
86
|
-
"scripts/
|
|
87
|
-
"scripts/
|
|
88
|
-
"scripts/
|
|
89
|
-
"scripts/tool-
|
|
90
|
-
"scripts/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"scripts/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"scripts/
|
|
97
|
-
"scripts/
|
|
98
|
-
"scripts/
|
|
99
|
-
"scripts/
|
|
100
|
-
"scripts/
|
|
101
|
-
"scripts/
|
|
102
|
-
"scripts/
|
|
103
|
-
"scripts/
|
|
104
|
-
"scripts/
|
|
105
|
-
"scripts/
|
|
106
|
-
"scripts/
|
|
107
|
-
"scripts/
|
|
108
|
-
"scripts/
|
|
109
|
-
"scripts/
|
|
110
|
-
"scripts/
|
|
111
|
-
"scripts/
|
|
112
|
-
"scripts/
|
|
113
|
-
"scripts/
|
|
114
|
-
"scripts/
|
|
115
|
-
"scripts/
|
|
116
|
-
"scripts/
|
|
117
|
-
"scripts/
|
|
118
|
-
"scripts/
|
|
119
|
-
"scripts/
|
|
120
|
-
"scripts/
|
|
121
|
-
"scripts/
|
|
122
|
-
"scripts/
|
|
123
|
-
"scripts/
|
|
124
|
-
"scripts/
|
|
125
|
-
"scripts/
|
|
126
|
-
"scripts/
|
|
127
|
-
"scripts/
|
|
128
|
-
"scripts/
|
|
129
|
-
"scripts/
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
"@
|
|
143
|
-
"
|
|
144
|
-
"react": "latest",
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@evandu/super-pi",
|
|
3
|
+
"version": "0.1.84",
|
|
4
|
+
"description": "Web control plane and companion for Pi",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"super-pi": "bin/super-pi.js",
|
|
9
|
+
"super_pi": "bin/super-pi.js"
|
|
10
|
+
},
|
|
11
|
+
"pi": {
|
|
12
|
+
"extensions": [
|
|
13
|
+
"./dist/extension.js"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"agents",
|
|
19
|
+
"bin",
|
|
20
|
+
"scripts/restart-server.mjs",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22.19.0"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"prepack": "npm run build",
|
|
28
|
+
"prepublishOnly": "npm run build && cross-env SUPER_PI_REQUIRE_REAL_PI=1 node scripts/extension-load.test.mjs",
|
|
29
|
+
"dev": "concurrently --kill-others-on-fail \"npm:dev:server\" \"npm:dev:client\"",
|
|
30
|
+
"dev:client": "vite --host 0.0.0.0",
|
|
31
|
+
"dev:server": "cross-env SUPER_PI_PORT=3081 tsx watch src/server/index.ts",
|
|
32
|
+
"dev:installed": "npm run build && cross-env SUPER_PI_PORT=3080 node bin/super-pi.js",
|
|
33
|
+
"build": "tsc -b && vite build && node scripts/fresh-build.mjs",
|
|
34
|
+
"start": "node dist/server/index.js",
|
|
35
|
+
"restart:server": "node scripts/restart-server.mjs",
|
|
36
|
+
"smoke": "npm run build && node scripts/smoke.mjs",
|
|
37
|
+
"check": "node scripts/run-check.mjs"
|
|
38
|
+
},
|
|
39
|
+
"check:logic": [
|
|
40
|
+
"scripts/stream-checkpoint.test.mjs",
|
|
41
|
+
"scripts/stream-transport.test.mjs",
|
|
42
|
+
"scripts/lan-access.test.mjs",
|
|
43
|
+
"scripts/terminal-pty.test.mjs",
|
|
44
|
+
"scripts/persistence-repository.test.mjs",
|
|
45
|
+
"scripts/sqlite-repository.test.mjs",
|
|
46
|
+
"scripts/dispatch-ancestry.test.mjs",
|
|
47
|
+
"scripts/dispatch-endpoint.test.mjs",
|
|
48
|
+
"scripts/dispatched-by.test.mjs",
|
|
49
|
+
"scripts/verify-source-text.test.mjs",
|
|
50
|
+
"scripts/runtime-extension-ui.test.mjs",
|
|
51
|
+
"scripts/agent-mechanism.test.mjs",
|
|
52
|
+
"scripts/agent-wiring.test.mjs",
|
|
53
|
+
"scripts/message-timestamps.test.mjs",
|
|
54
|
+
"scripts/pi-resolution.test.mjs",
|
|
55
|
+
"scripts/agent-real-pi.test.mjs",
|
|
56
|
+
"scripts/image-input-real-pi.test.mjs",
|
|
57
|
+
"scripts/image-upload.test.mjs",
|
|
58
|
+
"scripts/extension-ui-e2e.test.mjs",
|
|
59
|
+
"scripts/session-picker.test.mjs",
|
|
60
|
+
"scripts/workspace-cwd.test.mjs",
|
|
61
|
+
"scripts/subagents.test.mjs",
|
|
62
|
+
"scripts/subagent-noise.test.mjs",
|
|
63
|
+
"scripts/subagent-runs.test.mjs",
|
|
64
|
+
"scripts/conversation-reconcile.test.mjs",
|
|
65
|
+
"scripts/subagent-dispatch.test.mjs",
|
|
66
|
+
"scripts/workflow-plan.test.mjs",
|
|
67
|
+
"scripts/workflow-engine.test.mjs",
|
|
68
|
+
"scripts/workflow-endpoint.test.mjs",
|
|
69
|
+
"scripts/workflow-ui.test.mjs",
|
|
70
|
+
"scripts/agent-vis-records.test.mjs",
|
|
71
|
+
"scripts/queue-store.test.mjs",
|
|
72
|
+
"scripts/followup.test.mjs",
|
|
73
|
+
"scripts/md-render.test.mjs",
|
|
74
|
+
"scripts/revert-session-format.test.mjs",
|
|
75
|
+
"scripts/revert-session-file.test.mjs",
|
|
76
|
+
"scripts/revert-real-pi.test.mjs",
|
|
77
|
+
"scripts/bg-task.test.mjs",
|
|
78
|
+
"scripts/todo-tool.test.mjs",
|
|
79
|
+
"scripts/tool-calls.test.mjs",
|
|
80
|
+
"scripts/files-api.test.mjs",
|
|
81
|
+
"scripts/files-missing-path.test.mjs",
|
|
82
|
+
"scripts/task-tool.test.mjs",
|
|
83
|
+
"scripts/fork-server.test.mjs",
|
|
84
|
+
"scripts/styles-no-dangling.test.mjs",
|
|
85
|
+
"scripts/theme-no-hardcoded-colours.test.mjs",
|
|
86
|
+
"scripts/agent-config-regression.test.mjs",
|
|
87
|
+
"scripts/model-filter.test.mjs",
|
|
88
|
+
"scripts/active-memory.test.mjs",
|
|
89
|
+
"scripts/tool-runner.test.mjs",
|
|
90
|
+
"scripts/tool-runtime-api.test.mjs",
|
|
91
|
+
"scripts/extension-load.test.mjs",
|
|
92
|
+
"scripts/static-client-assets.test.mjs",
|
|
93
|
+
"scripts/cli.test.mjs"
|
|
94
|
+
],
|
|
95
|
+
"check:browser": [
|
|
96
|
+
"scripts/revert-browser.test.mjs",
|
|
97
|
+
"scripts/extension-ui-browser.test.mjs",
|
|
98
|
+
"scripts/inline-rename-blur.test.mjs",
|
|
99
|
+
"scripts/message-timestamps-browser.test.mjs",
|
|
100
|
+
"scripts/session-picker-browser.test.mjs",
|
|
101
|
+
"scripts/workspace-settings-browser.test.mjs",
|
|
102
|
+
"scripts/subagent-card-browser.test.mjs",
|
|
103
|
+
"scripts/workflow-browser.test.mjs",
|
|
104
|
+
"scripts/conversation-reconcile-browser.test.mjs",
|
|
105
|
+
"scripts/visual-defects-browser.test.mjs",
|
|
106
|
+
"scripts/session-state-animation-browser.test.mjs",
|
|
107
|
+
"scripts/agent-vis-card-browser.test.mjs",
|
|
108
|
+
"scripts/queue-dock.test.mjs",
|
|
109
|
+
"scripts/md-render-browser.test.mjs",
|
|
110
|
+
"scripts/right-sidebar-browser.test.mjs",
|
|
111
|
+
"scripts/sidebar-tools-browser.test.mjs",
|
|
112
|
+
"scripts/tool-runtime-browser.test.mjs",
|
|
113
|
+
"scripts/session-context-menu-browser.test.mjs",
|
|
114
|
+
"scripts/tool-call-blocks-browser.test.mjs",
|
|
115
|
+
"scripts/files-tab-browser.test.mjs",
|
|
116
|
+
"scripts/msg-tabs-browser.test.mjs",
|
|
117
|
+
"scripts/tabs-on-top-browser.test.mjs",
|
|
118
|
+
"scripts/subagent-source.test.mjs",
|
|
119
|
+
"scripts/fork-resize-browser.test.mjs",
|
|
120
|
+
"scripts/msg-bubbles.test.mjs",
|
|
121
|
+
"scripts/narrow-layout.test.mjs",
|
|
122
|
+
"scripts/scrollbar-style.test.mjs",
|
|
123
|
+
"scripts/stream-tail-browser.test.mjs",
|
|
124
|
+
"scripts/theme-contrast.test.mjs",
|
|
125
|
+
"scripts/theme-switch-state.test.mjs",
|
|
126
|
+
"scripts/settings-window-structure.test.mjs",
|
|
127
|
+
"scripts/file-tab-selected-contrast.test.mjs",
|
|
128
|
+
"scripts/help-window.test.mjs",
|
|
129
|
+
"scripts/composer-regression-browser.test.mjs",
|
|
130
|
+
"scripts/composer-resize-browser.test.mjs",
|
|
131
|
+
"scripts/workspace-picker-browser.test.mjs",
|
|
132
|
+
"scripts/optimistic-browser.test.mjs",
|
|
133
|
+
"scripts/active-memory-browser.test.mjs"
|
|
134
|
+
],
|
|
135
|
+
"dependencies": {
|
|
136
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
137
|
+
"@xterm/xterm": "^6.0.0",
|
|
138
|
+
"node-pty": "^1.2.0-beta.15",
|
|
139
|
+
"ws": "latest"
|
|
140
|
+
},
|
|
141
|
+
"devDependencies": {
|
|
142
|
+
"@types/node": "latest",
|
|
143
|
+
"@types/react": "latest",
|
|
144
|
+
"@types/react-dom": "latest",
|
|
145
|
+
"@types/ws": "latest",
|
|
146
|
+
"@vitejs/plugin-react": "latest",
|
|
147
|
+
"concurrently": "latest",
|
|
148
|
+
"cross-env": "latest",
|
|
149
|
+
"react": "latest",
|
|
150
|
+
"react-dom": "latest",
|
|
151
|
+
"tsx": "latest",
|
|
152
|
+
"typescript": "latest",
|
|
153
|
+
"vite": "latest"
|
|
154
|
+
}
|
|
155
|
+
}
|