ei-tui 1.6.7 → 1.6.8
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/cli/install.ts +147 -40
package/package.json
CHANGED
package/src/cli/install.ts
CHANGED
|
@@ -34,15 +34,26 @@ export async function installMcpClients(): Promise<void> {
|
|
|
34
34
|
console.log(`ℹ️ OpenCode not detected — skipping OpenCode plugin install.`);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const hasPi =
|
|
37
|
+
const hasPi =
|
|
38
|
+
await Bun.file(join(home, ".pi", "agent", "settings.json")).exists() ||
|
|
38
39
|
await Bun.file(join(home, ".pi", "agent", "auth.json")).exists();
|
|
39
|
-
const hasOmp = await Bun.file(join(home, ".omp", "agent", "settings.json")).exists() ||
|
|
40
|
-
await Bun.file(join(home, ".omp", "agent", "auth.json")).exists();
|
|
41
40
|
|
|
42
|
-
if (hasPi
|
|
41
|
+
if (hasPi) {
|
|
43
42
|
await installPi();
|
|
44
43
|
} else {
|
|
45
|
-
console.log(`ℹ️ Pi
|
|
44
|
+
console.log(`ℹ️ Pi not detected — skipping Pi extension install.`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const hasOmp =
|
|
48
|
+
await Bun.file(join(home, ".omp", "agent", "settings.json")).exists() ||
|
|
49
|
+
await Bun.file(join(home, ".omp", "agent", "auth.json")).exists() ||
|
|
50
|
+
await Bun.file(join(home, ".omp", "agent", "config.yml")).exists() ||
|
|
51
|
+
await Bun.file(join(home, ".omp", "agent", "agent.db")).exists();
|
|
52
|
+
|
|
53
|
+
if (hasOmp) {
|
|
54
|
+
await installOmp();
|
|
55
|
+
} else {
|
|
56
|
+
console.log(`ℹ️ OMP not detected — skipping OMP extension install.`);
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
@@ -289,7 +300,12 @@ if (input.session_id && input.hook_source) {
|
|
|
289
300
|
|
|
290
301
|
const args = raw ? ["-n", "5", ...sessionArgs, raw] : ["--recent", "-n", "5"];
|
|
291
302
|
|
|
292
|
-
|
|
303
|
+
async function runEi(commandArgs) {
|
|
304
|
+
const direct = await $\`ei \${commandArgs}\`.quiet().text().catch(() => "");
|
|
305
|
+
if (direct.trim()) return direct;
|
|
306
|
+
return await $\`bunx ei-tui@latest \${commandArgs}\`.quiet().text().catch(() => "");
|
|
307
|
+
}
|
|
308
|
+
const output = await runEi(args);
|
|
293
309
|
if (output.trim()) process.stdout.write(\`\\n\${heading}\\n\${output.trim()}\\n\`);
|
|
294
310
|
`;
|
|
295
311
|
|
|
@@ -431,12 +447,18 @@ exit 0
|
|
|
431
447
|
|
|
432
448
|
async function installPi(): Promise<void> {
|
|
433
449
|
const home = process.env.HOME || "~";
|
|
434
|
-
const dataPath = process.env.EI_DATA_PATH ?? join(home, ".local", "share", "ei");
|
|
435
450
|
|
|
436
451
|
const extensionContent = `import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
437
452
|
import { Type } from "typebox";
|
|
438
453
|
import { $ } from "bun";
|
|
439
454
|
|
|
455
|
+
const runEi = async (cmdArgs: string[]): Promise<string> => {
|
|
456
|
+
const direct = await $\`ei \${cmdArgs}\`.quiet().text().catch(() => "");
|
|
457
|
+
if (direct.trim()) return direct;
|
|
458
|
+
return $\`bunx ei-tui@latest \${cmdArgs}\`.quiet().text().catch(() => "");
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
|
|
440
462
|
export default function eiIntegration(pi: ExtensionAPI) {
|
|
441
463
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
442
464
|
const entries = ctx.sessionManager.getEntries();
|
|
@@ -457,11 +479,7 @@ export default function eiIntegration(pi: ExtensionAPI) {
|
|
|
457
479
|
? ["-n", "5", "--", prompt]
|
|
458
480
|
: ["--recent", "-n", "5"];
|
|
459
481
|
|
|
460
|
-
const output = await
|
|
461
|
-
.env({ ...process.env, EI_DATA_PATH: "${dataPath}" })
|
|
462
|
-
.quiet()
|
|
463
|
-
.text()
|
|
464
|
-
.catch(() => "");
|
|
482
|
+
const output = await runEi(args).catch(() => "");
|
|
465
483
|
|
|
466
484
|
if (!output.trim()) return undefined;
|
|
467
485
|
|
|
@@ -502,11 +520,7 @@ export default function eiIntegration(pi: ExtensionAPI) {
|
|
|
502
520
|
const args = params.type
|
|
503
521
|
? [params.type, "-n", "5", "--", params.query]
|
|
504
522
|
: ["-n", "5", "--", params.query];
|
|
505
|
-
const output = await
|
|
506
|
-
.env({ ...process.env, EI_DATA_PATH: "${dataPath}" })
|
|
507
|
-
.quiet()
|
|
508
|
-
.text()
|
|
509
|
-
.catch(() => "No results found");
|
|
523
|
+
const output = await runEi(args).catch(() => "");
|
|
510
524
|
return {
|
|
511
525
|
content: [{ type: "text" as const, text: output.trim() || "No results found" }],
|
|
512
526
|
details: {},
|
|
@@ -522,11 +536,7 @@ export default function eiIntegration(pi: ExtensionAPI) {
|
|
|
522
536
|
id: Type.String({ description: "Entity ID from ei_search results" }),
|
|
523
537
|
}),
|
|
524
538
|
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
525
|
-
const output = await
|
|
526
|
-
.env({ ...process.env, EI_DATA_PATH: "${dataPath}" })
|
|
527
|
-
.quiet()
|
|
528
|
-
.text()
|
|
529
|
-
.catch(() => "Not found");
|
|
539
|
+
const output = await runEi(["--id", params.id]).catch(() => "");
|
|
530
540
|
return {
|
|
531
541
|
content: [{ type: "text" as const, text: output.trim() || "Not found" }],
|
|
532
542
|
details: {},
|
|
@@ -536,26 +546,121 @@ export default function eiIntegration(pi: ExtensionAPI) {
|
|
|
536
546
|
}
|
|
537
547
|
`;
|
|
538
548
|
|
|
539
|
-
const
|
|
540
|
-
const ompExtDir = join(home, ".omp", "agent", "extensions");
|
|
549
|
+
const extDir = join(home, ".pi", "agent", "extensions");
|
|
541
550
|
const extFilename = "ei-integration.ts";
|
|
542
551
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
552
|
+
await Bun.$`mkdir -p ${extDir}`;
|
|
553
|
+
await Bun.write(join(extDir, extFilename), extensionContent);
|
|
554
|
+
console.log(`✓ Installed Ei extension to ~/.pi/agent/extensions/${extFilename}`);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function installOmp(): Promise<void> {
|
|
558
|
+
const home = process.env.HOME || "~";
|
|
547
559
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
console.log(`✓ Installed Ei extension to ~/.pi/agent/extensions/${extFilename}`);
|
|
552
|
-
}
|
|
560
|
+
const extensionContent = `import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
561
|
+
import { Type } from "typebox";
|
|
562
|
+
import { $ } from "bun";
|
|
553
563
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
564
|
+
const runEi = async (cmdArgs: string[]): Promise<string> => {
|
|
565
|
+
const direct = await $\`ei \${cmdArgs}\`.quiet().text().catch(() => "");
|
|
566
|
+
if (direct.trim()) return direct;
|
|
567
|
+
return $\`bunx ei-tui@latest \${cmdArgs}\`.quiet().text().catch(() => "");
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
export default function eiIntegration(pi: ExtensionAPI) {
|
|
572
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
573
|
+
const entries = ctx.sessionManager.getEntries();
|
|
574
|
+
const recentMsgs = entries
|
|
575
|
+
.filter((e: any) => e.type === "message" && (e.message?.role === "user" || e.message?.role === "assistant"))
|
|
576
|
+
.slice(-5)
|
|
577
|
+
.map((e: any) => {
|
|
578
|
+
const role = e.message?.role ?? "unknown";
|
|
579
|
+
const text = Array.isArray(e.message?.content)
|
|
580
|
+
? e.message.content.filter((b: any) => b.type === "text").map((b: any) => b.text).join(" ")
|
|
581
|
+
: (e.message?.content ?? "");
|
|
582
|
+
return \`\${role}: \${text.slice(0, 200)}\`;
|
|
583
|
+
})
|
|
584
|
+
.join("\\n");
|
|
585
|
+
|
|
586
|
+
const prompt = event.prompt ?? "";
|
|
587
|
+
const args = prompt
|
|
588
|
+
? ["-n", "5", "--", prompt]
|
|
589
|
+
: ["--recent", "-n", "5"];
|
|
590
|
+
|
|
591
|
+
const output = await runEi(args).catch(() => "");
|
|
592
|
+
|
|
593
|
+
if (!output.trim()) return undefined;
|
|
594
|
+
|
|
595
|
+
const heading = [
|
|
596
|
+
"## Ei Memory Context",
|
|
597
|
+
"*(The user cannot see this block. It is injected automatically before their message.)*",
|
|
598
|
+
"*(If you reference anything from it, briefly explain where it came from.)*",
|
|
599
|
+
"",
|
|
600
|
+
"Ei is a personal knowledge base built from your coding sessions, Slack, documents, and conversations.",
|
|
601
|
+
"The following items MAY be relevant to your current task — use ei_search or ei_lookup for targeted queries.",
|
|
602
|
+
].join("\\n");
|
|
603
|
+
|
|
604
|
+
return {
|
|
605
|
+
message: {
|
|
606
|
+
customType: "ei-context",
|
|
607
|
+
content: \`\${heading}\\n\\n\${output.trim()}\`,
|
|
608
|
+
display: false,
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
pi.registerTool({
|
|
614
|
+
name: "ei_search",
|
|
615
|
+
label: "Search Ei Memory",
|
|
616
|
+
description: "Semantic search of Ei's personal knowledge base — facts, topics, people, quotes across all sources. Use when you need context about the user, their work, or anything Ei has learned.",
|
|
617
|
+
promptSnippet: "Search Ei's personal memory for relevant facts, topics, people, or quotes.",
|
|
618
|
+
parameters: Type.Object({
|
|
619
|
+
query: Type.String({ description: "Natural language search query" }),
|
|
620
|
+
type: Type.Optional(Type.Union([
|
|
621
|
+
Type.Literal("facts"),
|
|
622
|
+
Type.Literal("topics"),
|
|
623
|
+
Type.Literal("people"),
|
|
624
|
+
Type.Literal("quotes"),
|
|
625
|
+
Type.Literal("personas"),
|
|
626
|
+
], { description: "Filter to a specific data type. Omit for balanced results across all types." })),
|
|
627
|
+
}),
|
|
628
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
629
|
+
const args = params.type
|
|
630
|
+
? [params.type, "-n", "5", "--", params.query]
|
|
631
|
+
: ["-n", "5", "--", params.query];
|
|
632
|
+
const output = await runEi(args).catch(() => "");
|
|
633
|
+
return {
|
|
634
|
+
content: [{ type: "text" as const, text: output.trim() || "No results found" }],
|
|
635
|
+
details: {},
|
|
636
|
+
};
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
pi.registerTool({
|
|
641
|
+
name: "ei_lookup",
|
|
642
|
+
label: "Lookup Ei Entity",
|
|
643
|
+
description: "Full-record lookup for a specific Ei entity (Fact, Topic, Person, Quote, or Persona) by ID. Use after ei_search to retrieve complete details for an item.",
|
|
644
|
+
parameters: Type.Object({
|
|
645
|
+
id: Type.String({ description: "Entity ID from ei_search results" }),
|
|
646
|
+
}),
|
|
647
|
+
async execute(_id, params, _signal, _onUpdate, _ctx) {
|
|
648
|
+
const output = await runEi(["--id", params.id]).catch(() => "");
|
|
649
|
+
return {
|
|
650
|
+
content: [{ type: "text" as const, text: output.trim() || "Not found" }],
|
|
651
|
+
details: {},
|
|
652
|
+
};
|
|
653
|
+
},
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
`;
|
|
657
|
+
|
|
658
|
+
const extDir = join(home, ".omp", "agent", "extensions");
|
|
659
|
+
const extFilename = "ei-integration.ts";
|
|
660
|
+
|
|
661
|
+
await Bun.$`mkdir -p ${extDir}`;
|
|
662
|
+
await Bun.write(join(extDir, extFilename), extensionContent);
|
|
663
|
+
console.log(`✓ Installed Ei extension to ~/.omp/agent/extensions/${extFilename}`);
|
|
559
664
|
}
|
|
560
665
|
|
|
561
666
|
async function installOpenCodePlugin(): Promise<void> {
|
|
@@ -603,7 +708,8 @@ export function extractAgentName(systemPrompt: string): string | null {
|
|
|
603
708
|
// tolerates OMO renaming agents without requiring a hardcoded alias map.
|
|
604
709
|
export async function resolveEiPersona(rawName: string): Promise<PersonaResult | null> {
|
|
605
710
|
try {
|
|
606
|
-
const
|
|
711
|
+
const direct = await $\`ei personas -n 5 \${rawName}\`.quiet().text().catch(() => "")
|
|
712
|
+
const out = direct.trim() ? direct : await $\`bunx ei-tui@latest personas -n 5 \${rawName}\`.text()
|
|
607
713
|
const candidates = JSON.parse(out.trim()) as PersonaResult[]
|
|
608
714
|
if (!Array.isArray(candidates) || candidates.length === 0) return null
|
|
609
715
|
const rawLower = rawName.toLowerCase()
|
|
@@ -650,7 +756,8 @@ export default async function EiPersonaPlugin() {
|
|
|
650
756
|
input: { sessionID?: string; model: { id: string; providerID: string; [key: string]: unknown } },
|
|
651
757
|
output: { system: string[] },
|
|
652
758
|
): Promise<void> => {
|
|
653
|
-
|
|
759
|
+
if (!Array.isArray(output.system) || typeof output.system[0] !== "string") return
|
|
760
|
+
const rawName = extractAgentName(output.system[0])
|
|
654
761
|
if (!rawName) return
|
|
655
762
|
|
|
656
763
|
const cacheKey = \`\${input.sessionID ?? "unknown"}:\${rawName}\`
|