@llblab/pi-kit 0.36.1 → 0.36.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.
- package/CHANGELOG.md +10 -0
- package/README.md +3 -3
- package/node_modules/@llblab/pi-claude-usage/CHANGELOG.md +4 -0
- package/node_modules/@llblab/pi-claude-usage/README.md +2 -2
- package/node_modules/@llblab/pi-claude-usage/lib/status-format.ts +2 -3
- package/node_modules/@llblab/pi-claude-usage/package.json +1 -1
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +1 -1
- package/node_modules/@llblab/pi-codex-usage/lib/status-format.ts +2 -3
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +2 -2
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +43 -5
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +45 -0
- package/node_modules/@llblab/pi-telegram/README.md +4 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +17 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +23 -11
- package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +24 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +7 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +7 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +22 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +52 -10
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +9 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +4 -4
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/prompts.d.ts +6 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +50 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +120 -14
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +13 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +39 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +144 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +15 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +14 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +122 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +9 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +3 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +52 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.d.ts +17 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +25 -0
- package/node_modules/@llblab/pi-telegram/dist/package.json +2 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +10 -10
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +23 -3
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +2 -0
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +24 -1
- package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +30 -13
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +25 -8
- package/node_modules/@llblab/pi-telegram/lib/bus.ts +11 -0
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +34 -8
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +54 -11
- package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +12 -0
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +4 -3
- package/node_modules/@llblab/pi-telegram/lib/menu.ts +4 -4
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +79 -16
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +142 -26
- package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +18 -0
- package/node_modules/@llblab/pi-telegram/lib/thread-cleanup-manager.ts +173 -17
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +14 -8
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +166 -10
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +9 -6
- package/node_modules/@llblab/pi-telegram/lib/workspace-admission.ts +8 -7
- package/node_modules/@llblab/pi-telegram/lib/workspace-retirement.ts +56 -2
- package/node_modules/@llblab/pi-telegram/lib/workspace-slots.ts +44 -0
- package/node_modules/@llblab/pi-telegram/package.json +2 -1
- package/node_modules/@llblab/pi-telegram/scripts/run-macos-tests.mjs +43 -0
- package/package.json +4 -4
|
@@ -187,7 +187,8 @@ interface TelegramWorkspaceRetirementFenceBase {
|
|
|
187
187
|
retirementIntentId: string;
|
|
188
188
|
profileKey: string;
|
|
189
189
|
bindingKey: string;
|
|
190
|
-
|
|
190
|
+
/** Null is admitted only for explicit manual cleanup of a slotless binding. */
|
|
191
|
+
slot: string | null;
|
|
191
192
|
target: TelegramTarget & { threadId: number };
|
|
192
193
|
leaderEpoch: number | string;
|
|
193
194
|
retirementRequestedAtMs: number;
|
|
@@ -228,7 +229,7 @@ export interface TelegramWorkspaceDeletionPermit {
|
|
|
228
229
|
readonly retirementIntentId: string;
|
|
229
230
|
readonly profileKey: string;
|
|
230
231
|
readonly bindingKey: string;
|
|
231
|
-
readonly slot: string;
|
|
232
|
+
readonly slot: string | null;
|
|
232
233
|
readonly target: TelegramTarget & { threadId: number };
|
|
233
234
|
readonly leaderEpoch: number | string;
|
|
234
235
|
readonly issuedAtMs: number;
|
|
@@ -376,7 +377,7 @@ export interface TelegramWorkspaceAdmissionLedger {
|
|
|
376
377
|
operationId: string;
|
|
377
378
|
cleanupWorkSetId: string;
|
|
378
379
|
bindingKey: string;
|
|
379
|
-
slot: string;
|
|
380
|
+
slot: string | null;
|
|
380
381
|
target: TelegramTarget & { threadId: number };
|
|
381
382
|
leaderEpoch: number | string;
|
|
382
383
|
cleanupRequestedAtMs: number;
|
|
@@ -538,8 +539,8 @@ function normalizeFence(
|
|
|
538
539
|
!isBoundedText(value.retirementIntentId) ||
|
|
539
540
|
value.profileKey !== profileKey ||
|
|
540
541
|
!isBoundedText(value.bindingKey) ||
|
|
541
|
-
typeof value.slot
|
|
542
|
-
|
|
542
|
+
!((typeof value.slot === "string" && /^[A-Z]$/u.test(value.slot)) ||
|
|
543
|
+
(value.destructiveKind === "manual-thread-cleanup" && value.slot === null)) ||
|
|
543
544
|
!target ||
|
|
544
545
|
!isLeaderEpoch(value.leaderEpoch) ||
|
|
545
546
|
!isSafeTimestamp(value.retirementRequestedAtMs) ||
|
|
@@ -1869,7 +1870,7 @@ export function createTelegramWorkspaceAdmissionLedger(
|
|
|
1869
1870
|
operationId: string;
|
|
1870
1871
|
retirementIntentId: string;
|
|
1871
1872
|
bindingKey: string;
|
|
1872
|
-
slot: string;
|
|
1873
|
+
slot: string | null;
|
|
1873
1874
|
target: TelegramTarget & { threadId: number };
|
|
1874
1875
|
leaderEpoch: number | string;
|
|
1875
1876
|
retirementRequestedAtMs: number;
|
|
@@ -2307,7 +2308,7 @@ export function createTelegramWorkspaceAdmissionLedger(
|
|
|
2307
2308
|
}),
|
|
2308
2309
|
listReservedSlots: () => {
|
|
2309
2310
|
const fence = read().fence;
|
|
2310
|
-
return fence && isTelegramWorkspaceRetirementFence(fence)
|
|
2311
|
+
return fence && isTelegramWorkspaceRetirementFence(fence) && fence.slot !== null
|
|
2311
2312
|
? [fence.slot]
|
|
2312
2313
|
: [];
|
|
2313
2314
|
},
|
|
@@ -1764,6 +1764,8 @@ export async function runTelegramWorkspaceRetirementLifecycle(input: {
|
|
|
1764
1764
|
owner,
|
|
1765
1765
|
leaderEpoch: epoch,
|
|
1766
1766
|
});
|
|
1767
|
+
if (fence.slot === null)
|
|
1768
|
+
return { kind: "retained", reason: "stale-intent" };
|
|
1767
1769
|
input.admission.completeRetirementFence(fence);
|
|
1768
1770
|
return {
|
|
1769
1771
|
kind: "retired",
|
|
@@ -1892,6 +1894,7 @@ export function createTelegramWorkspaceSlotRotation(
|
|
|
1892
1894
|
binding: TelegramWorkspaceThreadBinding,
|
|
1893
1895
|
) => TelegramWorkspaceExternalProtectionEvidence;
|
|
1894
1896
|
recordEvent: (message: string, details: Record<string, unknown>) => void;
|
|
1897
|
+
onSlotReused?: (bindingKey: string, isCurrent: () => boolean) => Promise<void>;
|
|
1895
1898
|
},
|
|
1896
1899
|
): TelegramWorkspaceCapacityRunner {
|
|
1897
1900
|
const requests = createTelegramWorkspaceOperationGate();
|
|
@@ -1906,7 +1909,7 @@ export function createTelegramWorkspaceSlotRotation(
|
|
|
1906
1909
|
return requests.runExclusive(async () => {
|
|
1907
1910
|
if (!isCurrent())
|
|
1908
1911
|
throw new Error("Telegram Workspace allocation lost leader authority.");
|
|
1909
|
-
const rotate = async () => {
|
|
1912
|
+
const rotate = async (options?: { reuseWhenProtected?: boolean }) => {
|
|
1910
1913
|
const result = await input.runExclusive(async () => {
|
|
1911
1914
|
if (!isCurrent())
|
|
1912
1915
|
throw new Error(
|
|
@@ -1959,6 +1962,57 @@ export function createTelegramWorkspaceSlotRotation(
|
|
|
1959
1962
|
},
|
|
1960
1963
|
});
|
|
1961
1964
|
});
|
|
1965
|
+
if (
|
|
1966
|
+
options?.reuseWhenProtected &&
|
|
1967
|
+
result.kind === "blocked" &&
|
|
1968
|
+
result.stage === "preparation" &&
|
|
1969
|
+
result.reason === "protected-capacity"
|
|
1970
|
+
) {
|
|
1971
|
+
// Every letter is protected, so deleting a Thread is off the table: reassign the
|
|
1972
|
+
// least recently used letter as metadata and keep its Thread, journals and work.
|
|
1973
|
+
const reused = await input.runExclusive(async () => {
|
|
1974
|
+
if (!isCurrent())
|
|
1975
|
+
throw new Error(
|
|
1976
|
+
"Telegram Workspace slot reuse lost leader authority.",
|
|
1977
|
+
);
|
|
1978
|
+
await input.store.load();
|
|
1979
|
+
if (!isCurrent())
|
|
1980
|
+
throw new Error(
|
|
1981
|
+
"Telegram Workspace slot reuse lost leader authority.",
|
|
1982
|
+
);
|
|
1983
|
+
return input.store.reuseLeastRecentlyUsedWorkspaceSlot(isCurrent);
|
|
1984
|
+
});
|
|
1985
|
+
if (!isCurrent())
|
|
1986
|
+
throw new Error("Telegram Workspace rotation lost leader authority.");
|
|
1987
|
+
if (reused) {
|
|
1988
|
+
if (reused.kind === "reused") {
|
|
1989
|
+
// The store commit is final. Await display repair before the next allocation,
|
|
1990
|
+
// but never roll back or repeat a published reuse after a transport failure.
|
|
1991
|
+
try {
|
|
1992
|
+
await input.onSlotReused?.(reused.bindingKey, isCurrent);
|
|
1993
|
+
} catch (error) {
|
|
1994
|
+
try {
|
|
1995
|
+
input.recordEvent("Telegram Workspace slot display update failed.", {
|
|
1996
|
+
slot: reused.slot,
|
|
1997
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1998
|
+
});
|
|
1999
|
+
} catch {
|
|
2000
|
+
/* A diagnostic failure grants no rollback or another display attempt. */
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
if (!isCurrent())
|
|
2004
|
+
throw new Error("Telegram Workspace rotation lost leader authority.");
|
|
2005
|
+
try {
|
|
2006
|
+
input.recordEvent("Telegram Workspace slot reused.", {
|
|
2007
|
+
slot: reused.slot,
|
|
2008
|
+
});
|
|
2009
|
+
} catch {
|
|
2010
|
+
/* Diagnostics cannot turn a published reassignment into another attempt. */
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return { kind: "reused" as const };
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
1962
2016
|
if (
|
|
1963
2017
|
result.kind !== "retired" &&
|
|
1964
2018
|
result.kind !== "not-needed" &&
|
|
@@ -2104,7 +2158,7 @@ export function createTelegramWorkspaceSlotRotation(
|
|
|
2104
2158
|
}
|
|
2105
2159
|
}
|
|
2106
2160
|
}
|
|
2107
|
-
await rotate();
|
|
2161
|
+
await rotate({ reuseWhenProtected: true });
|
|
2108
2162
|
return operation();
|
|
2109
2163
|
}
|
|
2110
2164
|
});
|
|
@@ -27,6 +27,50 @@ export type TelegramWorkspaceSlotAllocation =
|
|
|
27
27
|
| { kind: "reclaim"; candidate: TelegramWorkspaceSlotOccupancy }
|
|
28
28
|
| { kind: "blocked"; reason: "invalid-state" | "protected-capacity" };
|
|
29
29
|
|
|
30
|
+
/** A binding whose letter may be reassigned without touching its Thread, journals or accepted work. */
|
|
31
|
+
export interface TelegramWorkspaceReusableSlot {
|
|
32
|
+
bindingKey: string;
|
|
33
|
+
/** Uppercase display letter currently held by the binding. */
|
|
34
|
+
slot: string;
|
|
35
|
+
/** A live owner counts as most recently used, whatever its stored clocks say. */
|
|
36
|
+
live: boolean;
|
|
37
|
+
/** Last known use: inactivity start for detached bindings, otherwise the last binding update. */
|
|
38
|
+
lastUsedMs: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Metadata-only fallback for a full A-Z pool: pick the least recently used letter,
|
|
43
|
+
* preferring detached bindings over live ones. Unlike pressure retirement this
|
|
44
|
+
* ignores accepted-work protection because reuse deletes nothing.
|
|
45
|
+
* Returns undefined for an empty or malformed candidate set.
|
|
46
|
+
*/
|
|
47
|
+
export function selectTelegramWorkspaceReusableSlot(
|
|
48
|
+
candidates: readonly TelegramWorkspaceReusableSlot[],
|
|
49
|
+
): TelegramWorkspaceReusableSlot | undefined {
|
|
50
|
+
const slots = new Set<string>();
|
|
51
|
+
const keys = new Set<string>();
|
|
52
|
+
for (const candidate of candidates) {
|
|
53
|
+
if (
|
|
54
|
+
!/^[A-Z]$/u.test(candidate.slot) ||
|
|
55
|
+
!candidate.bindingKey ||
|
|
56
|
+
!Number.isSafeInteger(candidate.lastUsedMs) ||
|
|
57
|
+
candidate.lastUsedMs < 0 ||
|
|
58
|
+
slots.has(candidate.slot) ||
|
|
59
|
+
keys.has(candidate.bindingKey)
|
|
60
|
+
)
|
|
61
|
+
return undefined;
|
|
62
|
+
slots.add(candidate.slot);
|
|
63
|
+
keys.add(candidate.bindingKey);
|
|
64
|
+
}
|
|
65
|
+
const [selected] = [...candidates].sort(
|
|
66
|
+
(left, right) =>
|
|
67
|
+
Number(left.live) - Number(right.live) ||
|
|
68
|
+
left.lastUsedMs - right.lastUsedMs ||
|
|
69
|
+
left.slot.localeCompare(right.slot),
|
|
70
|
+
);
|
|
71
|
+
return selected ? { ...selected } : undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
30
74
|
function isSlot(slot: string): boolean {
|
|
31
75
|
return /^[a-z]$/u.test(slot);
|
|
32
76
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-telegram",
|
|
3
|
-
"version": "0.57.
|
|
3
|
+
"version": "0.57.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
30
|
"test": "node --experimental-strip-types --import ./tests/fixtures/canonical-tmpdir.ts --test --test-concurrency=4 --test-reporter=dot tests/*.test.ts",
|
|
31
|
+
"test:low-concurrency": "node --experimental-strip-types --import ./tests/fixtures/canonical-tmpdir.ts --test --test-concurrency=2 --test-reporter=dot tests/*.test.ts",
|
|
31
32
|
"test:verbose": "node --experimental-strip-types --import ./tests/fixtures/canonical-tmpdir.ts --test --test-reporter=spec tests/*.test.ts",
|
|
32
33
|
"typecheck": "tsc --noEmit",
|
|
33
34
|
"build": "node scripts/build-dist.mjs",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic macOS CI test shards
|
|
3
|
+
* Zones: CI, test execution
|
|
4
|
+
* Keeps real-process tests isolated and partitions the remaining files without changing test deadlines.
|
|
5
|
+
*/
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
import { readdirSync } from "node:fs";
|
|
8
|
+
import { delimiter, join } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
|
|
11
|
+
const [shard, phase, mode, ...extra] = process.argv.slice(2);
|
|
12
|
+
if (!["0", "1"].includes(shard) || !["process", "remaining"].includes(phase) ||
|
|
13
|
+
(mode !== undefined && mode !== "--list") || extra.length) {
|
|
14
|
+
throw new Error("Usage: run-macos-tests.mjs <0|1> <process|remaining> [--list]");
|
|
15
|
+
}
|
|
16
|
+
const root = fileURLToPath(new URL("..", import.meta.url));
|
|
17
|
+
const entries = readdirSync(join(root, "tests"), { withFileTypes: true })
|
|
18
|
+
.filter((entry) => entry.name.endsWith(".test.ts"));
|
|
19
|
+
if (entries.some((entry) => !entry.isFile()))
|
|
20
|
+
throw new Error("The CI test inventory must contain only regular test files.");
|
|
21
|
+
const names = entries.map((entry) => entry.name).sort();
|
|
22
|
+
const processTest = "process-shutdown.test.ts";
|
|
23
|
+
if (!names.includes(processTest)) throw new Error("The real-process test suite is missing.");
|
|
24
|
+
const files = (phase === "process"
|
|
25
|
+
? (shard === "0" ? [processTest] : [])
|
|
26
|
+
: names.filter((name) => name !== processTest).filter((_, index) => index % 2 === Number(shard)))
|
|
27
|
+
.map((name) => `tests/${name}`);
|
|
28
|
+
if (mode === "--list") {
|
|
29
|
+
console.log(JSON.stringify(files));
|
|
30
|
+
} else if (files.length) {
|
|
31
|
+
console.log(`macOS shard ${Number(shard) + 1}/2 ${phase}: ${files.length} test file(s)`);
|
|
32
|
+
const result = spawnSync(process.execPath, [
|
|
33
|
+
"--experimental-strip-types", "--import", "./tests/fixtures/canonical-tmpdir.ts",
|
|
34
|
+
"--test", "--test-concurrency=1", `--test-reporter=${phase === "process" ? "spec" : "dot"}`,
|
|
35
|
+
...files,
|
|
36
|
+
], {
|
|
37
|
+
cwd: root,
|
|
38
|
+
stdio: "inherit",
|
|
39
|
+
env: { ...process.env, PATH: [join(root, "node_modules", ".bin"), process.env.PATH].filter(Boolean).join(delimiter) },
|
|
40
|
+
});
|
|
41
|
+
if (result.error) throw result.error;
|
|
42
|
+
process.exitCode = result.status ?? 1;
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@llblab/pi-actors": "0.55.0",
|
|
48
|
-
"@llblab/pi-claude-usage": "0.2.
|
|
48
|
+
"@llblab/pi-claude-usage": "0.2.3",
|
|
49
49
|
"@llblab/pi-clean-room": "0.3.0",
|
|
50
|
-
"@llblab/pi-codex-usage": "0.13.
|
|
50
|
+
"@llblab/pi-codex-usage": "0.13.2",
|
|
51
51
|
"@llblab/pi-grow-loop": "0.9.0",
|
|
52
52
|
"@llblab/pi-state-flow": "0.26.5",
|
|
53
|
-
"@llblab/pi-telegram": "0.57.
|
|
53
|
+
"@llblab/pi-telegram": "0.57.11",
|
|
54
54
|
"@llblab/skills": "1.15.0"
|
|
55
55
|
},
|
|
56
56
|
"bundledDependencies": [
|