pi-sessions 0.14.2 → 0.14.3
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.
|
@@ -24,7 +24,8 @@ import { installSubagents } from "./subagents/install.ts";
|
|
|
24
24
|
* The single advertised entrypoint. It loads settings once, constructs each feature in
|
|
25
25
|
* dependency order, and wires them by constructor parameters.
|
|
26
26
|
* It also owns the single `session_start`/`session_shutdown` subscription so lifecycle order
|
|
27
|
-
* is deterministic: broker registration (messaging) resolves before any other feature hook
|
|
27
|
+
* is deterministic: broker registration (messaging) resolves before any other feature hook,
|
|
28
|
+
* and incoming messages start turns only once every feature hook has resolved.
|
|
28
29
|
*/
|
|
29
30
|
export default function piSessions(pi: ExtensionAPI): void {
|
|
30
31
|
const settings = loadSettings();
|
|
@@ -141,6 +142,9 @@ export default function piSessions(pi: ExtensionAPI): void {
|
|
|
141
142
|
for (const lifecycle of lifecycles) {
|
|
142
143
|
await lifecycle.onSessionStart?.(event, ctx);
|
|
143
144
|
}
|
|
145
|
+
for (const lifecycle of lifecycles) {
|
|
146
|
+
lifecycle.onSessionReady?.(ctx);
|
|
147
|
+
}
|
|
144
148
|
});
|
|
145
149
|
|
|
146
150
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
@@ -65,11 +65,13 @@ export function installMessaging(
|
|
|
65
65
|
onIncomingSubagentReport: (handler) => service.onIncomingSubagentReport(handler),
|
|
66
66
|
async onSessionStart(_event, ctx) {
|
|
67
67
|
incomingRuntime.bindContext(ctx);
|
|
68
|
-
incomingRuntime.replayPending(ctx);
|
|
69
68
|
try {
|
|
70
69
|
await service.start(ctx);
|
|
71
70
|
} catch {}
|
|
72
71
|
},
|
|
72
|
+
onSessionReady() {
|
|
73
|
+
incomingRuntime.open();
|
|
74
|
+
},
|
|
73
75
|
onSessionShutdown() {
|
|
74
76
|
incomingRuntime.clearContext();
|
|
75
77
|
service.stop();
|
|
@@ -21,6 +21,7 @@ interface IncomingMessageActions {
|
|
|
21
21
|
|
|
22
22
|
export class IncomingSessionMessageRuntime {
|
|
23
23
|
private context: ExtensionContext | undefined;
|
|
24
|
+
private ready = false;
|
|
24
25
|
private readonly actions: IncomingMessageActions;
|
|
25
26
|
|
|
26
27
|
constructor(pi: ExtensionAPI) {
|
|
@@ -32,10 +33,17 @@ export class IncomingSessionMessageRuntime {
|
|
|
32
33
|
|
|
33
34
|
bindContext(ctx: ExtensionContext): void {
|
|
34
35
|
this.context = ctx;
|
|
36
|
+
this.ready = false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
open(): void {
|
|
40
|
+
this.replayPending(this.requireContext());
|
|
41
|
+
this.ready = true;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
clearContext(): void {
|
|
38
45
|
this.context = undefined;
|
|
46
|
+
this.ready = false;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
deliver(received: ReceivedMessageEntry): void {
|
|
@@ -47,14 +55,18 @@ export class IncomingSessionMessageRuntime {
|
|
|
47
55
|
throw new Error(SESSION_STARTING_MESSAGE);
|
|
48
56
|
}
|
|
49
57
|
this.actions.appendEntry(MESSAGE_RECEIVED_CUSTOM_TYPE, received);
|
|
50
|
-
|
|
58
|
+
// The broker connects before other features finish session_start, and a turn started now
|
|
59
|
+
// would run without the tools they activate. The receipt is durable; open() replays it.
|
|
60
|
+
if (this.ready) {
|
|
61
|
+
this.inject(ctx, received);
|
|
62
|
+
}
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
cancel(): void {
|
|
54
66
|
this.requireContext().abort();
|
|
55
67
|
}
|
|
56
68
|
|
|
57
|
-
replayPending(ctx: ExtensionContext): void {
|
|
69
|
+
private replayPending(ctx: ExtensionContext): void {
|
|
58
70
|
const entries = ctx.sessionManager.getEntries();
|
|
59
71
|
const deliveredMessageIds = new Set<string>();
|
|
60
72
|
const pendingReceipts: ReceivedMessageEntry[] = [];
|
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
*/
|
|
12
12
|
export interface SessionLifecycle {
|
|
13
13
|
onSessionStart?(event: SessionStartEvent, ctx: ExtensionContext): Promise<void> | void;
|
|
14
|
+
/** Runs once every feature's onSessionStart has resolved. */
|
|
15
|
+
onSessionReady?(ctx: ExtensionContext): void;
|
|
14
16
|
onSessionShutdown?(event: SessionShutdownEvent, ctx: ExtensionContext): Promise<void> | void;
|
|
15
17
|
}
|
|
16
18
|
|