@trim21/personal-pi-extensions 0.0.346 → 0.0.348
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/package.json +1 -1
- package/src/talk/core.ts +37 -3
- package/src/talk/index.ts +60 -21
package/package.json
CHANGED
package/src/talk/core.ts
CHANGED
|
@@ -267,6 +267,21 @@ export class TalkCore {
|
|
|
267
267
|
// both timing out.
|
|
268
268
|
await this.resolveInterlock(letter);
|
|
269
269
|
await trackIncomingAsk(this.storage, self.addr, letter);
|
|
270
|
+
} else if (letter.kind === "message") {
|
|
271
|
+
// A plain message from a peer we are blocked asking breaks the wait: the
|
|
272
|
+
// peer is engaging, so do not keep the caller stuck waiting for a reply.
|
|
273
|
+
const myAsk = await this.findOutAskTo(letter.from.addr);
|
|
274
|
+
if (myAsk) {
|
|
275
|
+
const waiter = this.askWaiters.get(myAsk.askId);
|
|
276
|
+
if (waiter) {
|
|
277
|
+
this.askWaiters.delete(myAsk.askId);
|
|
278
|
+
waiter({
|
|
279
|
+
replied: false,
|
|
280
|
+
reason: "peer sent a message instead of replying to your ask",
|
|
281
|
+
});
|
|
282
|
+
await clearAsk(this.storage, self.addr, myAsk.askId);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
270
285
|
}
|
|
271
286
|
return true;
|
|
272
287
|
}
|
|
@@ -535,7 +550,7 @@ export class TalkCore {
|
|
|
535
550
|
const nameNote = agentName === undefined ? "" : ` You are visible as "${agentName}".`;
|
|
536
551
|
const existing = await readGroup(this.storage, name);
|
|
537
552
|
if (existing?.members.includes(self.agentId)) {
|
|
538
|
-
return `Already in group ${name} (${existing.members.length} member(s)).${nameNote}`;
|
|
553
|
+
return `Already in group ${name} (${existing.members.length} member(s)). Members: ${await this.groupMemberNames(existing.members)}.${nameNote}`;
|
|
539
554
|
}
|
|
540
555
|
await this.leaveCurrentGroup();
|
|
541
556
|
if (existing) {
|
|
@@ -544,7 +559,12 @@ export class TalkCore {
|
|
|
544
559
|
members: [...existing.members, self.agentId],
|
|
545
560
|
updatedAt: this.now(),
|
|
546
561
|
});
|
|
547
|
-
return `Joined group ${name} (${
|
|
562
|
+
return `Joined group ${name} (${
|
|
563
|
+
existing.members.length + 1
|
|
564
|
+
} member(s)). Members: ${await this.groupMemberNames([
|
|
565
|
+
...existing.members,
|
|
566
|
+
self.agentId,
|
|
567
|
+
])}. You now see only co-members.${nameNote}`;
|
|
548
568
|
}
|
|
549
569
|
const now = this.now();
|
|
550
570
|
await writeGroup(this.storage, {
|
|
@@ -553,7 +573,7 @@ export class TalkCore {
|
|
|
553
573
|
createdAt: now,
|
|
554
574
|
updatedAt: now,
|
|
555
575
|
});
|
|
556
|
-
return `Created group ${name}.${nameNote} Other agents join it with /talk-group-join ${name}.`;
|
|
576
|
+
return `Created group ${name}. Members: ${await this.groupMemberNames([self.agentId])}.${nameNote} Other agents join it with /talk-group-join ${name}.`;
|
|
557
577
|
}
|
|
558
578
|
|
|
559
579
|
/**
|
|
@@ -621,6 +641,20 @@ export class TalkCore {
|
|
|
621
641
|
return `Groups (${groups.length}):\n${lines.join("\n")}`;
|
|
622
642
|
}
|
|
623
643
|
|
|
644
|
+
/** Human-readable member list: `name (shortId)`, self marked `← you`. */
|
|
645
|
+
private async groupMemberNames(memberIds: string[]): Promise<string> {
|
|
646
|
+
const self = this.requireSelf();
|
|
647
|
+
const records = await listRecords(this.storage);
|
|
648
|
+
const label = (agentId: string): string => {
|
|
649
|
+
const rec = records.find((r) => r.agentId === agentId);
|
|
650
|
+
const id = agentId.length > 8 ? `${agentId.slice(0, 8)}…` : agentId;
|
|
651
|
+
return rec ? `${rec.name} (${id})` : `unknown agent (${id})`;
|
|
652
|
+
};
|
|
653
|
+
return memberIds
|
|
654
|
+
.map((agentId) => (agentId === self.agentId ? `${label(agentId)} ← you` : label(agentId)))
|
|
655
|
+
.join(", ");
|
|
656
|
+
}
|
|
657
|
+
|
|
624
658
|
/**
|
|
625
659
|
* Status-bar text for the caller: "alias@group" when an explicit alias was
|
|
626
660
|
* set via `talk-group-join --name`, "@group" otherwise; undefined when the
|
package/src/talk/index.ts
CHANGED
|
@@ -148,12 +148,9 @@ export default function talk(pi: ExtensionAPI) {
|
|
|
148
148
|
events: {
|
|
149
149
|
deliver: deliverToAgent,
|
|
150
150
|
notify(content) {
|
|
151
|
-
// Presence transitions are informational —
|
|
152
|
-
//
|
|
153
|
-
pi.
|
|
154
|
-
{ customType: NOTIFY_TYPE, content, display: true },
|
|
155
|
-
{ deliverAs: "nextTurn" },
|
|
156
|
-
);
|
|
151
|
+
// Presence transitions are informational — show in the TUI only, never
|
|
152
|
+
// in LLM context.
|
|
153
|
+
pi.appendEntry(NOTIFY_TYPE, content);
|
|
157
154
|
},
|
|
158
155
|
},
|
|
159
156
|
});
|
|
@@ -289,22 +286,34 @@ export default function talk(pi: ExtensionAPI) {
|
|
|
289
286
|
|
|
290
287
|
type OkResult<TFlags extends TObject> = Extract<CommandResult<TFlags>, { kind: "ok" }>;
|
|
291
288
|
|
|
292
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Parse a /talk command; on help/error or init failure the text is sent,
|
|
291
|
+
* otherwise run() produces the listing text. With `sendToContext` the result
|
|
292
|
+
* is injected into the LLM context (sendMessage); otherwise it is appended
|
|
293
|
+
* as a display-only session entry (appendEntry, never sent to the LLM).
|
|
294
|
+
*/
|
|
293
295
|
function handleCommand<TFlags extends TObject>(
|
|
294
296
|
spec: CommandSpec<TFlags>,
|
|
295
297
|
args: string,
|
|
296
298
|
ctx: ExtensionCommandContext,
|
|
297
299
|
run: (parsed: OkResult<TFlags>) => Promise<string> | string,
|
|
300
|
+
options?: { sendToContext?: boolean },
|
|
298
301
|
): Promise<void> {
|
|
302
|
+
const emit = (text: string): void => {
|
|
303
|
+
if (options?.sendToContext) {
|
|
304
|
+
pi.sendMessage({ customType: LIST_TYPE, content: text, display: true });
|
|
305
|
+
} else {
|
|
306
|
+
pi.appendEntry(LIST_TYPE, text);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
299
309
|
const parsed = parseCommand(spec, args);
|
|
300
310
|
if (parsed.kind !== "ok") {
|
|
301
|
-
|
|
311
|
+
emit(parsed.text);
|
|
302
312
|
return Promise.resolve();
|
|
303
313
|
}
|
|
304
314
|
return (async () => {
|
|
305
315
|
const initError = requireInit();
|
|
306
|
-
|
|
307
|
-
pi.sendMessage({ customType: LIST_TYPE, content: text, display: true });
|
|
316
|
+
emit(initError ?? (await run(parsed)));
|
|
308
317
|
// Group membership can change under any of these commands; keep the
|
|
309
318
|
// footer/status-bar text in sync.
|
|
310
319
|
refreshGroupStatus(ctx.ui);
|
|
@@ -412,27 +421,41 @@ export default function talk(pi: ExtensionAPI) {
|
|
|
412
421
|
pi.registerCommand("talk-group-join", {
|
|
413
422
|
description: TALK_GROUP_JOIN_SPEC.description,
|
|
414
423
|
handler: (args, ctx) =>
|
|
415
|
-
handleCommand(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
424
|
+
handleCommand(
|
|
425
|
+
TALK_GROUP_JOIN_SPEC,
|
|
426
|
+
args,
|
|
427
|
+
ctx,
|
|
428
|
+
async (parsed) => {
|
|
429
|
+
const agentName = parsed.flags.name?.trim() || undefined;
|
|
430
|
+
if (agentName !== undefined) explicitName = agentName;
|
|
431
|
+
return core.groupJoin(parsed.args[0], agentName);
|
|
432
|
+
},
|
|
433
|
+
{ sendToContext: true },
|
|
434
|
+
),
|
|
420
435
|
});
|
|
421
436
|
|
|
422
437
|
pi.registerCommand("talk-group-join-last", {
|
|
423
438
|
description: TALK_GROUP_JOIN_LAST_SPEC.description,
|
|
424
439
|
handler: (args, ctx) =>
|
|
425
|
-
handleCommand(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
440
|
+
handleCommand(
|
|
441
|
+
TALK_GROUP_JOIN_LAST_SPEC,
|
|
442
|
+
args,
|
|
443
|
+
ctx,
|
|
444
|
+
async (parsed) => {
|
|
445
|
+
const agentName = parsed.flags.name?.trim() || undefined;
|
|
446
|
+
if (agentName !== undefined) explicitName = agentName;
|
|
447
|
+
return core.groupJoinLast(agentName);
|
|
448
|
+
},
|
|
449
|
+
{ sendToContext: true },
|
|
450
|
+
),
|
|
430
451
|
});
|
|
431
452
|
|
|
432
453
|
pi.registerCommand("talk-group-leave", {
|
|
433
454
|
description: TALK_GROUP_LEAVE_SPEC.description,
|
|
434
455
|
handler: (args, ctx) =>
|
|
435
|
-
handleCommand(TALK_GROUP_LEAVE_SPEC, args, ctx, async () => core.groupLeave()
|
|
456
|
+
handleCommand(TALK_GROUP_LEAVE_SPEC, args, ctx, async () => core.groupLeave(), {
|
|
457
|
+
sendToContext: true,
|
|
458
|
+
}),
|
|
436
459
|
});
|
|
437
460
|
|
|
438
461
|
pi.registerCommand("talk-group-list", {
|
|
@@ -486,4 +509,20 @@ export default function talk(pi: ExtensionAPI) {
|
|
|
486
509
|
invalidate: (): void => undefined,
|
|
487
510
|
};
|
|
488
511
|
});
|
|
512
|
+
|
|
513
|
+
// ── Display-only entries (appendEntry): shown in chat, persisted, never in LLM context ──
|
|
514
|
+
|
|
515
|
+
for (const type of [LIST_TYPE, NOTIFY_TYPE]) {
|
|
516
|
+
pi.registerEntryRenderer<string>(type, (entry, _options, theme) => {
|
|
517
|
+
const text = typeof entry.data === "string" ? entry.data : "";
|
|
518
|
+
if (!text) return;
|
|
519
|
+
return {
|
|
520
|
+
render: (width: number) =>
|
|
521
|
+
truncateToVisualLines(text, Infinity, width, 1).visualLines.map((line) =>
|
|
522
|
+
theme.bg("customMessageBg", line),
|
|
523
|
+
),
|
|
524
|
+
invalidate: (): void => undefined,
|
|
525
|
+
};
|
|
526
|
+
});
|
|
527
|
+
}
|
|
489
528
|
}
|