@evandu/super-pi 0.1.138 → 0.1.140

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 (72) hide show
  1. package/agents/super-pi-knowledge/index.ts +11 -13
  2. package/agents/super-pi-memory/index.ts +11 -5
  3. package/agents/super-pi-task/core.ts +418 -1
  4. package/agents/super-pi-task/index.ts +115 -0
  5. package/bin/super-pi.js +7 -11
  6. package/dist/.super-pi-check-inputs.json +2 -2
  7. package/dist/client/.super-pi-client-sources.json +7 -6
  8. package/dist/client/assets/{CodeMirrorEditor-CVImD0nh.js → CodeMirrorEditor-DvZeOLny.js} +2 -2
  9. package/dist/client/assets/{dist-CiEW7LQW.js → dist-3BuyVG3H.js} +1 -1
  10. package/dist/client/assets/{dist-faxwvvOU.js → dist-BCUfH4nP.js} +1 -1
  11. package/dist/client/assets/{dist-yONALz0V.js → dist-BIIMtU9W.js} +1 -1
  12. package/dist/client/assets/{dist-CKI1xVeE.js → dist-C-QmRwbd.js} +1 -1
  13. package/dist/client/assets/{dist-4uPxkRdw.js → dist-CTkzLBdb.js} +1 -1
  14. package/dist/client/assets/{dist-CUACXe1Y.js → dist-C_VuSpx8.js} +1 -1
  15. package/dist/client/assets/{dist-BwQM8_Mk.js → dist-CaUsvSz1.js} +1 -1
  16. package/dist/client/assets/{dist-Clf26yld.js → dist-Cb1gxS57.js} +1 -1
  17. package/dist/client/assets/{dist-YB4GJD3u.js → dist-CqDSeoUk.js} +1 -1
  18. package/dist/client/assets/{dist-DozjvPAZ.js → dist-D7yfnKNC.js} +1 -1
  19. package/dist/client/assets/{dist-Cocw5XJ_.js → dist-DA8yW4lK.js} +1 -1
  20. package/dist/client/assets/{dist-amySbADh.js → dist-DAcS4Kj8.js} +1 -1
  21. package/dist/client/assets/{dist-B75OT6A9.js → dist-DN0M4DAX.js} +1 -1
  22. package/dist/client/assets/{dist-At94VK1P.js → dist-DRgWZqFH.js} +1 -1
  23. package/dist/client/assets/{dist-BIgRwYsI.js → dist-DdfW8Gjv.js} +1 -1
  24. package/dist/client/assets/{dist-DhEa5hHR.js → dist-DlQ8PMvv.js} +1 -1
  25. package/dist/client/assets/{dist-quQ6u6Rw.js → dist-Dvca0LeR.js} +1 -1
  26. package/dist/client/assets/{dist-BqblSnWL.js → dist-HJdP1yxN.js} +1 -1
  27. package/dist/client/assets/{dist-pnGHl3nq.js → dist-gBAr9yXF.js} +1 -1
  28. package/dist/client/assets/{dist-1H_gIENV.js → dist-gyzurUDR.js} +1 -1
  29. package/dist/client/assets/{dist-DSCjkO-y.js → dist-qG53hT1b.js} +1 -1
  30. package/dist/client/assets/{dist-CNP-Q5Gs.js → dist-r4Kq1ABA.js} +1 -1
  31. package/dist/client/assets/{index-CNoiRdJC.js → index-CNbh1fL2.js} +14 -14
  32. package/dist/client/assets/index-DCSFD4VV.css +1 -0
  33. package/dist/client/index.html +2 -2
  34. package/dist/server/application/conversation-service.d.ts +13 -4
  35. package/dist/server/application/conversation-service.js +112 -61
  36. package/dist/server/application/run-service.d.ts +13 -0
  37. package/dist/server/application/run-service.js +255 -69
  38. package/dist/server/application/scheduled-task-service.js +8 -1
  39. package/dist/server/application/session-orchestrator-service.d.ts +113 -0
  40. package/dist/server/application/session-orchestrator-service.js +234 -0
  41. package/dist/server/application/workspace-service.js +16 -1
  42. package/dist/server/feishu-cli.js +15 -4
  43. package/dist/server/file-index.d.ts +30 -0
  44. package/dist/server/file-index.js +49 -4
  45. package/dist/server/files.d.ts +21 -0
  46. package/dist/server/files.js +38 -0
  47. package/dist/server/http-server.js +1580 -1402
  48. package/dist/server/index.js +23 -6
  49. package/dist/server/logging.js +56 -3
  50. package/dist/server/pi-session-pool.d.ts +2 -0
  51. package/dist/server/pi-session-pool.js +1 -0
  52. package/dist/server/pi-session.d.ts +118 -0
  53. package/dist/server/pi-session.js +132 -10
  54. package/dist/server/runtime.d.ts +48 -0
  55. package/dist/server/runtime.js +189 -86
  56. package/dist/server/server-context.d.ts +2 -0
  57. package/dist/server/session-ledger.d.ts +60 -0
  58. package/dist/server/session-ledger.js +76 -0
  59. package/dist/server/store.d.ts +44 -1
  60. package/dist/server/store.js +114 -12
  61. package/dist/server/subagent-runs.d.ts +31 -1
  62. package/dist/server/subagent-runs.js +48 -20
  63. package/dist/server/subagents.js +7 -0
  64. package/dist/server/task-tool.d.ts +18 -0
  65. package/dist/server/task-tool.js +85 -0
  66. package/dist/server/tool-runner.js +13 -4
  67. package/dist/server/types.d.ts +50 -0
  68. package/dist/server/ws-server.d.ts +86 -6
  69. package/dist/server/ws-server.js +291 -51
  70. package/package.json +16 -2
  71. package/scripts/diagnose.mjs +161 -58
  72. package/dist/client/assets/index-FxTrUapG.css +0 -1
@@ -464,6 +464,10 @@ export type Conversation = {
464
464
  status: RunStatus;
465
465
  messages: Message[];
466
466
  archivedAt?: string;
467
+ /** Transport projection only: false means messages were omitted, rather than an empty transcript. */
468
+ messagesLoaded?: boolean;
469
+ /** Pending question summary, retained when a focused snapshot omits this conversation's messages. */
470
+ hasPendingQuestion?: boolean;
467
471
  /** Pi's own resolved transcript path, observed from this conversation's live worker. It is only a
468
472
  * locator: revert still verifies the file header and every retained boundary before writing. */
469
473
  piSessionFile?: string;
@@ -484,6 +488,21 @@ export type Conversation = {
484
488
  * would answer "what happened" with something the reader has to go and decode.
485
489
  */
486
490
  error?: string;
491
+ /**
492
+ * WHY THIS CONVERSATION IS NOT ON THE MODEL THE USER SET FOR IT - in words a person reads.
493
+ *
494
+ * A default model can stop being usable between one session and the next: Pi may drop the model
495
+ * from its list, or the workspace's own model rules may forbid it. The conversation then starts on
496
+ * Pi's own default, which is the right behaviour - but doing it SILENTLY is not: the user set a
497
+ * default, they set a rule, and nobody told them the two contradicted each other (TEST-062).
498
+ *
499
+ * It lives on the conversation rather than on the workspace because that is where the decision
500
+ * was made: a default can be usable for one workspace and unusable for another, and two
501
+ * conversations of the same workspace can disagree if the rules changed in between. It is set
502
+ * ONCE, at birth, and never rewritten afterwards - it describes how this conversation came to be,
503
+ * not what is true right now.
504
+ */
505
+ modelNotice?: string;
487
506
  /** Absent means "Pi's own default", which is why a conversation created before the picker existed still works. */
488
507
  model?: ModelSelection;
489
508
  thinkingLevel?: string;
@@ -852,6 +871,29 @@ export type TodoItem = {
852
871
  status: "pending" | "in_progress" | "completed";
853
872
  priority?: "high" | "medium" | "low";
854
873
  };
874
+ /** Summary of an orchestrated sibling session, returned by orchestrator queries. */
875
+ export type OrchestratorSessionSummary = {
876
+ conversationId: string;
877
+ workspaceId: string;
878
+ title: string;
879
+ status: RunStatus;
880
+ origin: "user" | "orchestrator";
881
+ parentConversationId?: string;
882
+ task?: string;
883
+ messageCount: number;
884
+ turnCount: number;
885
+ lastAssistantSnippet?: string;
886
+ lastUserSnippet?: string;
887
+ hasPendingQuestion: boolean;
888
+ activeTool?: {
889
+ label: string;
890
+ detail?: string;
891
+ };
892
+ error?: string;
893
+ updatedAt: string;
894
+ createdAt?: number;
895
+ lastProgress?: string;
896
+ };
855
897
  /**
856
898
  * What Pi reports about ITS OWN queue, forwarded to the browser as it arrives.
857
899
  *
@@ -1194,6 +1236,14 @@ export type ClientCommandBody =
1194
1236
  type: "stream.configure";
1195
1237
  coalesce: boolean;
1196
1238
  }
1239
+ /** Selects this socket's transcript; omitted conversationId requests sidebar summaries only. */
1240
+ | {
1241
+ type: "files.index.subscribe";
1242
+ workspaceId?: string;
1243
+ } | {
1244
+ type: "state.subscribe";
1245
+ conversationId?: string;
1246
+ }
1197
1247
  /** Asks for the agent catalog read from disk. Answered by `agent.catalog`. */
1198
1248
  | {
1199
1249
  type: "agent.catalog.fetch";
@@ -4,6 +4,40 @@ import type { AppState, ServerEvent } from "./types.js";
4
4
  import type { EventBroadcaster } from "./server-context.js";
5
5
  import type { CommandHandler } from "./command-handler.js";
6
6
  import type { CatalogService } from "./application/catalog-service.js";
7
+ /**
8
+ * A WebSocket is a live transport, not an unbounded queue. `ws.send()` only
9
+ * copies bytes into the socket's userland buffer; a browser that is frozen or
10
+ * a network peer that has disappeared can therefore make the buffer grow
11
+ * without throwing. Once this threshold is crossed we drop that connection
12
+ * and let the normal close path clean up its resources.
13
+ *
14
+ * AND YET DROPPING IT IS THE WRONG ANSWER FOR A BUSY SERVER. The threshold was
15
+ * written for a peer that has gone away - a frozen tab, a pulled cable. A server
16
+ * that is merely DELIVERING TOO MUCH hits the same number: a sub-agent that
17
+ * streams text emits one `subagent.event` per delta, each of which asks for a
18
+ * full state broadcast, and a browser that cannot parse frames as fast as they
19
+ * arrive lets the buffer grow past the threshold while it is perfectly alive.
20
+ * The browser then reports code 1006 and reconnects, only to be dropped again -
21
+ * "连接中 / 断连 / 连接中" forever - and the user's work is interrupted rather
22
+ * than slowed.
23
+ *
24
+ * So a frame that does not fit is DROPPED, not the connection: the next frame
25
+ * carries the same state, and a browser that is behind will catch up on the next
26
+ * one instead of being disconnected and losing its place. The connection is
27
+ * only terminated when the socket itself is gone (readyState is not OPEN).
28
+ */
29
+ export declare const MAX_WS_BUFFERED_BYTES: number;
30
+ /** Maximum size of one inbound WebSocket message. Attachments are uploaded
31
+ * over HTTP and commands contain references, so multi-megabyte WS frames are
32
+ * almost certainly malformed or abusive. */
33
+ export declare const MAX_WS_PAYLOAD_BYTES: number;
34
+ /**
35
+ * Send one frame without allowing a race with close/error to escape as an
36
+ * uncaught exception. The `ws` package can throw synchronously after the
37
+ * readyState check (for example when a close happens between the two calls),
38
+ * and an unhandled `error` event can otherwise terminate the Node process.
39
+ */
40
+ export declare function safeSend(socket: WebSocket, payload: string): boolean;
7
41
  /**
8
42
  * Concrete implementation of EventBroadcaster delivering server events
9
43
  * across active WebSocket connections.
@@ -11,21 +45,67 @@ import type { CatalogService } from "./application/catalog-service.js";
11
45
  export declare class WsBroadcaster implements EventBroadcaster {
12
46
  private readonly getState;
13
47
  private readonly sockets;
48
+ private readonly scopes;
49
+ private readonly fileIndexScopes;
14
50
  private readonly coalescedSockets;
15
51
  private readonly pendingStreams;
16
- private cachedState?;
17
- private cachedStatePayload?;
18
- private stateFlushScheduled;
19
- constructor(getState: () => AppState);
20
- register(socket: WebSocket): void;
52
+ /**
53
+ * DIAGNOSTIC ONLY - sends every requested state frame immediately instead of merging them.
54
+ *
55
+ * The legacy flood switch (`SUPER_PI_LEGACY_SUBAGENT_FLOOD=1`) restores the pre-fix WIRING: one
56
+ * full state broadcast per sub-agent event. But the 150ms merge window would still fold those
57
+ * broadcasts into one frame, so the "before" measurement would not actually be "before" - it
58
+ * would show a flood that the fixed server also survives, and the A/B comparison would prove
59
+ * nothing. This flag removes the window as well, so the probe can reproduce the real pre-fix
60
+ * wire shape: one frame per request, sent at once.
61
+ *
62
+ * Never set outside a probe or a regression test that is asserting the old behaviour.
63
+ */
64
+ private readonly sendStateImmediately;
65
+ constructor(getState: (scope?: {
66
+ conversationId?: string;
67
+ }) => AppState);
68
+ register(socket: WebSocket, scope?: {
69
+ conversationId?: string;
70
+ }): void;
21
71
  unregister(socket: WebSocket): void;
72
+ subscribe(socket: WebSocket, conversationId?: string): void;
73
+ sendState(socket: WebSocket): void;
74
+ subscribeFileIndex(socket: WebSocket, workspaceId?: string): void;
75
+ private receives;
22
76
  configureStreaming(socket: WebSocket, coalesce: boolean): void;
23
77
  private flushStreaming;
24
78
  private enqueueStreaming;
25
79
  getSockets(): Set<WebSocket>;
26
80
  broadcast(event: ServerEvent): void;
81
+ /**
82
+ * BROADCAST STATES IN A TIME WINDOW, NOT IN A MICROTASK.
83
+ *
84
+ * The microtask flag this replaces merged only the calls that arrived within the
85
+ * SAME tick. A sub-agent that streams text emits one `subagent.event` per delta,
86
+ * each asking for a full state broadcast, and those deltas arrive across many
87
+ * ticks - so a single sub-agent run could ask for HUNDREDS of full state
88
+ * broadcasts. On a machine whose state is large, that is a flood the browser
89
+ * cannot drain: its parse queue falls behind, the socket buffer grows, and the
90
+ * connection is dropped (the browser reports 1006).
91
+ *
92
+ * A window turns a burst into a handful of frames. The state a browser receives
93
+ * is the LATEST state - the intermediate ones carried nothing the last one did
94
+ * not - so nothing is lost by sending fewer of them. The only thing that
95
+ * changes is how promptly the browser sees a change, and 150ms is below the
96
+ * threshold at which a person notices.
97
+ */
98
+ private stateFlushScheduled;
27
99
  broadcastState(): void;
28
- getStateSnapshot(): AppState;
100
+ private flushState;
101
+ /**
102
+ * Releases the pending state window, so a shutting-down server does not hold the event loop
103
+ * open on a timer whose flush would send to sockets that are already closed.
104
+ */
105
+ dispose(): void;
106
+ getStateSnapshot(scope?: {
107
+ conversationId?: string;
108
+ }): AppState;
29
109
  }
30
110
  export interface WsServerOptions {
31
111
  httpServer: NodeHttpServer;