Files
oh-my-pi-telegram/tests/pi.test.ts
T
Evandro Fonseca Junior d1d04001d0
Release / release (push) Failing after 5s
Validate / validate (push) Failing after 5m21s
chore: fork @llblab/[email protected] as @evandrodevbr/oh-my-pi-telegram
Fork of upstream llblab/[email protected].0 (SHA afe09c5) repackaged as a
drop-in extension for can1357/oh-my-pi (omp >= 16.5.2).

Changes vs upstream:
- Rename package: @llblab/pi-telegram -> @evandrodevbr/oh-my-pi-telegram
- Bump version: 0.22.0 -> 0.22.0-evandro.1
- Update repository/homepage/bugs URLs to evandrodevbr
- Add omp field in package.json (displayName + compatibleWith)
- README: prepend 'Oh My Pi (omp) Compatibility' section with install
  commands, verified-components table, upstream lineage, and rationale
- CHANGELOG: add '0.22.0-evandro.1' entry under Unreleased
- docs/: rename @llblab/pi-telegram imports to @evandrodevbr/oh-my-pi-telegram
- tests/public-api.test.ts: rename package import paths

Gates re-run on the fork:
- npm run typecheck  -> tsc --noEmit (success)
- npm test           -> 1229 pass / 0 fail / 1 platform-only skip
- npm run audit      -> found 0 vulnerabilities
- npm run pack:check -> evandrodevbr-oh-my-pi-telegram-0.22.0-evandro.1.tgz

Verified:
- omp install --link ./pi-telegram -> Linked OK
- omp plugin list -> @evandrodevbr/[email protected].0-evandro.1

Upstream lineage: badlogic/pi-telegram -> llblab/pi-telegram (0.22.0) -> evandrodevbr/oh-my-pi-telegram (this fork)
2026-07-15 14:18:16 -03:00

160 lines
5.1 KiB
TypeScript

/**
* Regression tests for the pi SDK adapter boundary
* Covers narrow bridge-facing helpers over concrete pi context contracts
*/
import assert from "node:assert/strict";
import test from "node:test";
import {
canStartPollingInExtensionContext,
compactExtensionContext,
createExtensionApiRuntimePorts,
createScopedModelPatternPersister,
type ExtensionContext,
getExtensionContextCwd,
formatPollingStartBlockedByRunMode,
getExtensionContextMode,
getExtensionContextModel,
hasExtensionContextPendingMessages,
isExtensionContextIdle,
isExtensionContextPassiveRunMode,
} from "../lib/pi.ts";
type PiRuntimeApiHarness = Parameters<
typeof createExtensionApiRuntimePorts
>[0] & {
events: string[];
};
type PiRuntimeModel = Parameters<PiRuntimeApiHarness["setModel"]>[0];
function createHarnessModel(id: string): PiRuntimeModel {
return { id } as PiRuntimeModel;
}
function getHarnessModelId(model: PiRuntimeModel): string {
return String(Reflect.get(Object(model), "id"));
}
test("Pi context mode helpers feature-detect passive run modes", () => {
assert.equal(getExtensionContextMode({ mode: "print" }), "print");
assert.equal(getExtensionContextMode({ mode: "bogus" }), undefined);
assert.equal(isExtensionContextPassiveRunMode({ mode: "print" }), true);
assert.equal(isExtensionContextPassiveRunMode({ mode: "json" }), true);
assert.equal(isExtensionContextPassiveRunMode({ mode: "rpc" }), false);
assert.equal(isExtensionContextPassiveRunMode({}), false);
assert.equal(canStartPollingInExtensionContext({ mode: "tui" }), true);
assert.equal(canStartPollingInExtensionContext({ mode: "rpc" }), true);
assert.equal(canStartPollingInExtensionContext({ mode: "json" }), false);
assert.equal(canStartPollingInExtensionContext({ mode: "print" }), false);
assert.equal(canStartPollingInExtensionContext({}), true);
assert.equal(
formatPollingStartBlockedByRunMode({ mode: "json" }),
"Telegram polling is unavailable in Pi json mode. Use /telegram-connect from a long-lived Pi session.",
);
});
test("Pi API runtime ports bind methods without losing receiver context", async () => {
const api: PiRuntimeApiHarness = {
events: [],
sendUserMessage(content, options) {
this.events.push(
`send:${String(content)}:${options?.deliverAs ?? "default"}`,
);
},
async exec(command, args) {
this.events.push(`exec:${command}:${args.join(",")}`);
return { stdout: "ok", stderr: "", code: 0, killed: false };
},
getCommands() {
this.events.push("commands");
return [];
},
getThinkingLevel() {
this.events.push("get-thinking");
return "high";
},
setThinkingLevel(level) {
this.events.push(`thinking:${String(level)}`);
},
async setModel(model) {
this.events.push(`model:${getHarnessModelId(model)}`);
return true;
},
};
const runtime = createExtensionApiRuntimePorts(api);
runtime.sendUserMessage("hello", { deliverAs: "followUp" });
assert.deepEqual(await runtime.exec("cmd", ["arg"]), {
stdout: "ok",
stderr: "",
code: 0,
killed: false,
});
assert.deepEqual(runtime.getCommands(), []);
assert.equal(runtime.getThinkingLevel(), "high");
runtime.setThinkingLevel("low");
assert.equal(await runtime.setModel(createHarnessModel("gpt-5")), true);
assert.deepEqual(api.events, [
"send:hello:followUp",
"exec:cmd:arg",
"commands",
"get-thinking",
"thinking:low",
"model:gpt-5",
]);
});
test("Pi scoped model persister invalidates cached inputs without clearing live menus", async () => {
const events: string[] = [];
const persist = createScopedModelPatternPersister({
createSettingsManager: (cwd) => ({
reload: async () => {},
flush: async () => {
events.push("flush");
},
getEnabledModels: () => undefined,
setEnabledModels: (patterns) => {
events.push(`set:${cwd}:${patterns?.join(",") ?? "all"}`);
},
}),
clearCachedModelMenuInputs: () => {
events.push("clear-cache");
},
});
await persist(["openai/gpt-5"], { cwd: "/tmp/project" } as ExtensionContext);
assert.deepEqual(events, [
"set:/tmp/project:openai/gpt-5",
"flush",
"clear-cache",
]);
});
test("Pi context helpers expose model, idle, pending-message, and compact adapters", () => {
const model = { provider: "openai", id: "gpt-5", name: "GPT-5" };
const events: string[] = [];
const ctx = {
model,
isIdle: () => true,
hasPendingMessages: () => false,
cwd: "/tmp/project",
compact: (callbacks: { onComplete: () => void }) => {
events.push("compact");
callbacks.onComplete();
},
} as unknown as ExtensionContext;
compactExtensionContext(ctx, {
onComplete: () => {
events.push("complete");
},
onError: () => {
events.push("error");
},
});
assert.equal(getExtensionContextModel(ctx), model);
assert.equal(getExtensionContextCwd(ctx), "/tmp/project");
assert.equal(isExtensionContextIdle(ctx), true);
assert.equal(hasExtensionContextPendingMessages(ctx), false);
assert.deepEqual(events, ["compact", "complete"]);
});