paseo-smart-session 1.2.4 → 1.2.5
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 +2 -2
- package/client/pill.tsx +112 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,13 +37,13 @@ That history remains useful after an individual session ends or a provider cache
|
|
|
37
37
|
Install from npm on Paseo 0.9.0 or newer:
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
|
-
paseo plugin install npm:paseo-smart-session
|
|
40
|
+
paseo plugin install npm:paseo-smart-session@1.2.5
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
Paseo 0.8 can install the same plugin from Git:
|
|
44
44
|
|
|
45
45
|
```sh
|
|
46
|
-
paseo plugin add tomgrin10/paseo-smart-session
|
|
46
|
+
paseo plugin add tomgrin10/paseo-smart-session --ref v1.2.5
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
```sh
|
package/client/pill.tsx
CHANGED
|
@@ -197,9 +197,27 @@ function AutoCompactIcon({
|
|
|
197
197
|
return <Icon name="FoldVertical" size={size} color={color} />;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
/** The lean
|
|
200
|
+
/** The lean shapes this needs from the agent directory, which carries far more. */
|
|
201
|
+
interface ListedAgent {
|
|
202
|
+
readonly id?: string;
|
|
203
|
+
readonly workspaceId?: string | null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface AgentUpdate {
|
|
207
|
+
readonly kind: "remove" | "upsert";
|
|
208
|
+
readonly agentId?: string;
|
|
209
|
+
readonly agent?: ListedAgent;
|
|
210
|
+
}
|
|
211
|
+
|
|
201
212
|
interface AgentListing {
|
|
202
|
-
readonly entries?: readonly { readonly agent?:
|
|
213
|
+
readonly entries?: readonly { readonly agent?: ListedAgent }[];
|
|
214
|
+
readonly subscription?: {
|
|
215
|
+
subscribe(observer: {
|
|
216
|
+
snapshot(listing: AgentListing): void;
|
|
217
|
+
update(message: { readonly type?: string; readonly payload?: AgentUpdate }): void;
|
|
218
|
+
}): () => void;
|
|
219
|
+
release(): Promise<void>;
|
|
220
|
+
};
|
|
203
221
|
}
|
|
204
222
|
|
|
205
223
|
/**
|
|
@@ -227,6 +245,10 @@ function updatePill(handle: PillHandle, title: string): void {
|
|
|
227
245
|
export function contributeClient(client: PluginClientContext) {
|
|
228
246
|
/** Every agent this app knows of, and its pill registration while one is up. */
|
|
229
247
|
const tracked = new Map<string, { workspaceId: string; handle: PillHandle | null }>();
|
|
248
|
+
const lifetime = new AbortController();
|
|
249
|
+
let stopped = false;
|
|
250
|
+
let unsubscribeOwnedObservation: (() => void) | null = null;
|
|
251
|
+
let releaseAgentObservation: (() => Promise<void>) | null = null;
|
|
230
252
|
|
|
231
253
|
function register(agentId: string, entry: { workspaceId: string; handle: PillHandle | null }): void {
|
|
232
254
|
const toggle = async () => {
|
|
@@ -299,42 +321,114 @@ export function contributeClient(client: PluginClientContext) {
|
|
|
299
321
|
tracked.delete(agentId);
|
|
300
322
|
}
|
|
301
323
|
|
|
324
|
+
function applyAgentUpdate(update: AgentUpdate): void {
|
|
325
|
+
if (update.kind === "remove") {
|
|
326
|
+
if (typeof update.agentId === "string") forget(update.agentId);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const agent = update.agent;
|
|
330
|
+
if (
|
|
331
|
+
typeof agent?.id !== "string" ||
|
|
332
|
+
typeof agent.workspaceId !== "string" ||
|
|
333
|
+
agent.workspaceId === ""
|
|
334
|
+
) return;
|
|
335
|
+
track(agent.id, agent.workspaceId);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function trackAgents(entries: AgentListing["entries"]): Set<string> {
|
|
339
|
+
const present = new Set<string>();
|
|
340
|
+
for (const entry of entries ?? []) {
|
|
341
|
+
const agent = entry.agent;
|
|
342
|
+
if (
|
|
343
|
+
typeof agent?.id !== "string" ||
|
|
344
|
+
typeof agent.workspaceId !== "string" ||
|
|
345
|
+
agent.workspaceId === ""
|
|
346
|
+
) continue;
|
|
347
|
+
present.add(agent.id);
|
|
348
|
+
track(agent.id, agent.workspaceId);
|
|
349
|
+
}
|
|
350
|
+
return present;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** A restored observation replaces its directory snapshot, including removals. */
|
|
354
|
+
function replaceAgents(entries: AgentListing["entries"]): void {
|
|
355
|
+
const present = trackAgents(entries);
|
|
356
|
+
for (const agentId of [...tracked.keys()]) {
|
|
357
|
+
if (!present.has(agentId)) forget(agentId);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
302
361
|
const refresh = () => refreshPills(() => client.rpc(enrolmentState, {}));
|
|
303
362
|
|
|
304
363
|
const unsubscribeStore = subscribe(sync);
|
|
305
364
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const { id, workspaceId } = update.agent;
|
|
312
|
-
if (typeof workspaceId !== "string" || workspaceId === "") return;
|
|
313
|
-
track(id, workspaceId);
|
|
365
|
+
// v0.8 returns only the listing and emits its subscribed updates through this
|
|
366
|
+
// local listener. Keep it attached until a newer runtime gives us the owned
|
|
367
|
+
// observation whose snapshots can reconcile the whole directory on reconnect.
|
|
368
|
+
let unsubscribeLegacyAgents: (() => void) | null = client.paseo.agents.subscribe((update) => {
|
|
369
|
+
applyAgentUpdate(update as AgentUpdate);
|
|
314
370
|
});
|
|
315
371
|
|
|
316
372
|
// The subscription only carries agents that report in from now on, and an idle
|
|
317
373
|
// one may not do that for hours.
|
|
318
374
|
void (async () => {
|
|
319
375
|
try {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
376
|
+
// `agents.subscribe()` listens only to observations already owned by
|
|
377
|
+
// this API instance. A plain list stopped receiving newly created agents
|
|
378
|
+
// in Paseo 0.9, which made both plugin pills disappear on new sessions.
|
|
379
|
+
const listAgents = client.paseo.agents.list as unknown as (options: {
|
|
380
|
+
subscribe: Record<string, never>;
|
|
381
|
+
signal: AbortSignal;
|
|
382
|
+
}) => Promise<AgentListing>;
|
|
383
|
+
const listing = await listAgents({ subscribe: {}, signal: lifetime.signal });
|
|
384
|
+
const release = listing.subscription
|
|
385
|
+
? () => listing.subscription!.release()
|
|
386
|
+
: null;
|
|
387
|
+
if (stopped) {
|
|
388
|
+
await release?.();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
releaseAgentObservation = release;
|
|
392
|
+
// The legacy listener was already live while this snapshot was in flight,
|
|
393
|
+
// so bootstrap must be additive or it can erase a just-created agent.
|
|
394
|
+
trackAgents(listing.entries);
|
|
395
|
+
if (listing.subscription) {
|
|
396
|
+
unsubscribeOwnedObservation = listing.subscription.subscribe({
|
|
397
|
+
snapshot(snapshot) {
|
|
398
|
+
if (!stopped) replaceAgents(snapshot.entries);
|
|
399
|
+
},
|
|
400
|
+
update(message) {
|
|
401
|
+
if (!stopped && message.type === "agent_update" && message.payload) {
|
|
402
|
+
applyAgentUpdate(message.payload);
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
unsubscribeLegacyAgents?.();
|
|
407
|
+
unsubscribeLegacyAgents = null;
|
|
325
408
|
}
|
|
326
409
|
} catch {
|
|
327
|
-
|
|
410
|
+
const release = releaseAgentObservation;
|
|
411
|
+
releaseAgentObservation = null;
|
|
412
|
+
await release?.().catch(() => undefined);
|
|
413
|
+
// Not fatal to the rest of the client contribution; a reload can retry.
|
|
328
414
|
}
|
|
329
415
|
})();
|
|
330
416
|
|
|
331
417
|
void refresh().catch(() => undefined);
|
|
332
418
|
const timer = setInterval(() => void refresh().catch(() => undefined), REFRESH_MS);
|
|
333
419
|
|
|
334
|
-
return () => {
|
|
420
|
+
return async () => {
|
|
421
|
+
stopped = true;
|
|
422
|
+
lifetime.abort();
|
|
335
423
|
clearInterval(timer);
|
|
336
|
-
|
|
424
|
+
unsubscribeLegacyAgents?.();
|
|
425
|
+
unsubscribeLegacyAgents = null;
|
|
426
|
+
unsubscribeOwnedObservation?.();
|
|
427
|
+
unsubscribeOwnedObservation = null;
|
|
337
428
|
unsubscribeStore();
|
|
338
429
|
for (const agentId of [...tracked.keys()]) forget(agentId);
|
|
430
|
+
const release = releaseAgentObservation;
|
|
431
|
+
releaseAgentObservation = null;
|
|
432
|
+
await release?.().catch(() => undefined);
|
|
339
433
|
};
|
|
340
434
|
}
|
package/package.json
CHANGED