@rohirik/pi-ltm 2.15.1 → 2.16.0
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/dist/index.js +7 -7
- package/package.json +2 -2
- package/src/find-core.ts +26 -0
- package/src/index.ts +3 -11
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import{spawn as
|
|
2
|
-
`);this.buffer=
|
|
3
|
-
`;this.child?.stdin?.write(
|
|
4
|
-
`);if(
|
|
1
|
+
import{spawn as k,execSync as E}from"node:child_process";import{join as d}from"node:path";import{homedir as x}from"node:os";import{existsSync as g,readdirSync as M}from"node:fs";import{existsSync as T}from"node:fs";import{createRequire as P}from"node:module";import{dirname as h,resolve as S}from"node:path";function y(o){let n;try{n=P(o).resolve("@rohirik/openltm-core")}catch{return null}for(let t=h(n);t!==h(t);t=h(t)){let r=S(t,"src","cli","bin.ts");if(T(r))return{script:r,args:["mcp-serve"]}}return null}var v="LTM_BRIDGE_DEPTH";function C(){let o=[process.env.BUN_INSTALL?d(process.env.BUN_INSTALL,"bin","bun"):null,d(x(),".bun","bin","bun"),"/opt/homebrew/bin/bun","/usr/local/bin/bun","/usr/bin/bun"].filter(n=>n!==null&&g(n));if(o.length>0)return o[0];for(let n of["which bun","command -v bun"])try{let t=E(n,{encoding:"utf-8",stdio:"pipe"}).trim();if(t&&g(t)&&!/\bpi\b/.test(t))return t}catch{}return null}function _(){let o=d(x(),".claude","plugins","cache","ltm","ltm");if(g(o))try{let n=M(o).filter(t=>/^\d/.test(t)).sort().reverse();for(let t of n){let r=d(o,t,"src","mcp-server.ts");if(g(r))return{script:r,args:[]}}}catch{}return y(import.meta.url)}var w=class{constructor(n,t,r=[]){this.runtime=n;this.script=t;this.args=r}child=null;pending=new Map;buffer="";nextId=1;exited=!1;start(){if(this.child)return;let n=parseInt(process.env[v]??"0",10),t={...process.env,[v]:String(n+1)};this.child=k(this.runtime,[this.script,...this.args],{stdio:["pipe","pipe","pipe"],env:t}),this.child.stdout?.on("data",r=>{this.buffer+=r.toString("utf-8");let e=this.buffer.split(`
|
|
2
|
+
`);this.buffer=e.pop()??"";for(let i of e){let c=i.trim();if(c)try{let l=JSON.parse(c);if(l.id!==void 0){let s=this.pending.get(l.id);s&&(this.pending.delete(l.id),l.error?s.reject(new Error(l.error.message)):s.resolve(l.result))}}catch{}}}),this.child.on("exit",()=>{this.exited=!0;for(let r of this.pending.values())r.reject(new Error("LTM MCP server exited"));this.pending.clear()}),this.child.on("error",()=>{this.exited=!0;for(let r of this.pending.values())r.reject(new Error("LTM MCP server error"));this.pending.clear()})}send(n,t,r){let e=JSON.stringify({jsonrpc:"2.0",id:r,method:n,params:t})+`
|
|
3
|
+
`;this.child?.stdin?.write(e)}request(n,t,r=3e4){let e=this.nextId++;return new Promise((i,c)=>{let l=setTimeout(()=>{this.pending.delete(e),c(new Error(`LTM MCP timeout: ${n}`))},r);this.pending.set(e,{resolve:s=>{clearTimeout(l),i(s)},reject:s=>{clearTimeout(l),c(s)}}),this.send(n,t,e)})}async initialize(){await this.request("initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"pi-ltm-bridge",version:"1.0.0"}}),this.send("notifications/initialized")}async listTools(){return(await this.request("tools/list"))?.tools??[]}async callTool(n,t){let r=await this.request("tools/call",{name:n,arguments:t},6e4),e=(r?.content??[]).filter(i=>i?.type==="text"&&i.text).map(i=>i.text).join(`
|
|
4
|
+
`);if(r?.isError)throw new Error(e||`${n} returned an error`);return e}};function j(o,n){try{let t=JSON.parse(n),r=Array.isArray(t.globals)?t.globals:[],e=Array.isArray(t.scoped)?t.scoped:[];if(r.length===0&&e.length===0)return"";let i=["## Prior Knowledge (LTM)",""];if(r.length>0){i.push("Global:");for(let c of r.slice(0,3))i.push(`- [${c.id}] ${String(c.content).replace(/\s+/g," ").trim()}`);i.push("")}if(e.length>0){i.push(`Project (${o}):`);for(let c of e.slice(0,7))i.push(`- [${c.id}] ${String(c.content).replace(/\s+/g," ").trim()}`);i.push("")}return i.join(`
|
|
5
5
|
`).trimEnd()+`
|
|
6
|
-
`}catch{return""}}function
|
|
6
|
+
`}catch{return""}}function I(o){let n=o;if(parseInt(process.env[v]??"0",10)>0)return;let t=C(),r=_();if(!t||!r)return;let e=new w(t,r.script,r.args);e.start();let i=new Set,c=(async()=>{await e.initialize();let l=await e.listTools();for(let s of l){let a=s.name;i.add(a),n.registerTool({name:a,label:a,description:s.description??"",parameters:s.inputSchema??{type:"object",properties:{}},async execute(p,u){return{content:[{type:"text",text:await e.callTool(a,u??{})}],details:{}}}})}})().catch(()=>{});n.on("before_agent_start",async l=>{await c;let s=l;try{let p=String(s?.cwd??process.cwd()).replace(/\/$/,"").split("/").pop()??"",u=i.has("context")?"context":i.has("recall")?"recall":"";if(!u)return;let m=u==="context"?await e.callTool("context",{project:p}):await e.callTool("recall",{project:p,limit:8,sort_by:"relevance"}),f=u==="context"?j(p,m):`## Prior Knowledge (LTM)
|
|
7
7
|
|
|
8
8
|
${m}
|
|
9
|
-
`;if(!f.trim())return;let
|
|
9
|
+
`;if(!f.trim())return;let b=String(s?.systemPrompt??"");return{systemPrompt:b?`${b}
|
|
10
10
|
|
|
11
|
-
${f}`:f}}catch{}})}export{
|
|
11
|
+
${f}`:f}}catch{}})}export{I as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rohirik/pi-ltm",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.16.0",
|
|
4
4
|
"description": "LTM (Long-Term Memory) native extension for Pi \u2014 share memories with Claude Code and OpenCode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@rohirik/openltm-core": "^2.
|
|
43
|
+
"@rohirik/openltm-core": "^2.16.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"bun-types": ">=1.0.0"
|
package/src/find-core.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* find-core.ts — locate the `@rohirik/openltm-core` CLI entry that runs `mcp-serve`.
|
|
3
|
+
*
|
|
4
|
+
* Kept dependency-free so a test can run it under Node: the host runs on Node,
|
|
5
|
+
* which enforces core's `exports` map and refuses unlisted subpaths such as
|
|
6
|
+
* `@rohirik/openltm-core/package.json` (ERR_PACKAGE_PATH_NOT_EXPORTED). Bun,
|
|
7
|
+
* which runs the rest of the tests, does not — that gap shipped a plugin whose
|
|
8
|
+
* every tool failed. So resolve core's main entry and walk up to its root.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { createRequire } from "node:module";
|
|
12
|
+
import { dirname, resolve } from "node:path";
|
|
13
|
+
|
|
14
|
+
export function findCoreCli(fromUrl: string): { script: string; args: string[] } | null {
|
|
15
|
+
let entry: string;
|
|
16
|
+
try {
|
|
17
|
+
entry = createRequire(fromUrl).resolve("@rohirik/openltm-core");
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
for (let dir = dirname(entry); dir !== dirname(dir); dir = dirname(dir)) {
|
|
22
|
+
const script = resolve(dir, "src", "cli", "bin.ts");
|
|
23
|
+
if (existsSync(script)) return { script, args: ["mcp-serve"] };
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
* Pattern adapted from context-mode's Pi adapter (MIT).
|
|
9
9
|
*/
|
|
10
10
|
import { spawn, execSync } from "node:child_process";
|
|
11
|
-
import {
|
|
12
|
-
import { resolve, dirname, join } from "node:path";
|
|
11
|
+
import { join } from "node:path";
|
|
13
12
|
import { homedir } from "node:os";
|
|
14
13
|
import { existsSync, readdirSync } from "node:fs";
|
|
14
|
+
import { findCoreCli } from "./find-core.js";
|
|
15
15
|
|
|
16
16
|
// ── Fork-bomb prevention ──────────────────────────────────────────────────────
|
|
17
17
|
|
|
@@ -60,15 +60,7 @@ function findMcpServer(): { script: string; args: string[] } | null {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
// 2. openltm-core package — run the packaged CLI entrypoint with mcp-serve
|
|
63
|
-
|
|
64
|
-
const req = createRequire(import.meta.url);
|
|
65
|
-
const pkgJson = req.resolve("@rohirik/openltm-core/package.json");
|
|
66
|
-
const script = resolve(dirname(pkgJson), "src", "cli", "bin.ts");
|
|
67
|
-
if (existsSync(script)) return { script, args: ["mcp-serve"] };
|
|
68
|
-
} catch {
|
|
69
|
-
// not available
|
|
70
|
-
}
|
|
71
|
-
return null;
|
|
63
|
+
return findCoreCli(import.meta.url);
|
|
72
64
|
}
|
|
73
65
|
|
|
74
66
|
// ── Minimal MCP stdio client ──────────────────────────────────────────────────
|