@aexol/spectral 0.1.1 → 0.1.2
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/server/pi-bridge.js +55 -15
- package/package.json +2 -1
package/dist/server/pi-bridge.js
CHANGED
|
@@ -48,8 +48,11 @@
|
|
|
48
48
|
* conversations within a single WS connection work normally.
|
|
49
49
|
*/
|
|
50
50
|
import { AuthStorage, createAgentSession, DefaultResourceLoader, ModelRegistry, SessionManager, } from "@mariozechner/pi-coding-agent";
|
|
51
|
-
import {
|
|
51
|
+
import { createJiti } from "@mariozechner/jiti";
|
|
52
52
|
import { randomUUID } from "node:crypto";
|
|
53
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
54
|
+
import { dirname, resolve } from "node:path";
|
|
55
|
+
import { fileURLToPath } from "node:url";
|
|
53
56
|
import aexolMcpExtension from "../extensions/aexol-mcp.js";
|
|
54
57
|
import { fetchAllowedModels as defaultFetchAllowedModels, } from "../relay/models-fetch.js";
|
|
55
58
|
/**
|
|
@@ -87,6 +90,41 @@ function extractTextFromContent(content) {
|
|
|
87
90
|
}
|
|
88
91
|
return out;
|
|
89
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Resolve the entry point of the pi-mcp-adapter extension (index.ts)
|
|
95
|
+
* by walking up from this file's location through node_modules.
|
|
96
|
+
* Returns the absolute path, or null if the package is not installed.
|
|
97
|
+
*/
|
|
98
|
+
function resolveMcpAdapterEntry() {
|
|
99
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
100
|
+
const rel = "node_modules/pi-mcp-adapter/package.json";
|
|
101
|
+
const root = "/";
|
|
102
|
+
let dir = __dirname;
|
|
103
|
+
for (let i = 0; i < 20; i++) {
|
|
104
|
+
const pkgPath = resolve(dir, rel);
|
|
105
|
+
try {
|
|
106
|
+
const raw = readFileSync(pkgPath, "utf8");
|
|
107
|
+
const pkg = JSON.parse(raw);
|
|
108
|
+
const extRel = pkg.pi?.extensions?.[0];
|
|
109
|
+
if (extRel) {
|
|
110
|
+
return resolve(dirname(pkgPath), extRel);
|
|
111
|
+
}
|
|
112
|
+
// Package found but no pi.extensions — try index.ts as fallback
|
|
113
|
+
const indexTs = resolve(dirname(pkgPath), "index.ts");
|
|
114
|
+
if (existsSync(indexTs))
|
|
115
|
+
return indexTs;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// package.json not readable at this level, keep walking up
|
|
120
|
+
}
|
|
121
|
+
const parent = dirname(dir);
|
|
122
|
+
if (parent === dir || parent === root)
|
|
123
|
+
break;
|
|
124
|
+
dir = parent;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
90
128
|
export class PiBridge {
|
|
91
129
|
session;
|
|
92
130
|
unsubscribe;
|
|
@@ -117,23 +155,25 @@ export class PiBridge {
|
|
|
117
155
|
async start() {
|
|
118
156
|
if (this.disposed)
|
|
119
157
|
throw new Error("PiBridge already disposed");
|
|
120
|
-
// Build extension factories. Always include the Aexol MCP extension;
|
|
121
|
-
// dynamically load the pi-mcp-adapter (standard MCP servers) with
|
|
122
|
-
// graceful degradation when the package is not installed.
|
|
123
158
|
const extensionFactories = [aexolMcpExtension];
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
// Load pi-mcp-adapter via jiti so tsc never crawls its .ts files in
|
|
160
|
+
// node_modules. The static `import` was causing tsc to type-check
|
|
161
|
+
// pi-mcp-adapter's source and fail the build on its type errors.
|
|
162
|
+
// jiti is the same loader pi uses internally for all extensions.
|
|
163
|
+
const mcpAdapterPath = resolveMcpAdapterEntry();
|
|
164
|
+
if (mcpAdapterPath) {
|
|
165
|
+
try {
|
|
166
|
+
const jiti = createJiti(import.meta.url, { moduleCache: false });
|
|
167
|
+
const mcpAdapterFactory = await jiti.import(mcpAdapterPath, { default: true });
|
|
168
|
+
if (typeof mcpAdapterFactory === "function") {
|
|
169
|
+
extensionFactories.push(async (pi) => mcpAdapterFactory(pi));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
console.info("[PiBridge] pi-mcp-adapter not found; standard MCP servers disabled.");
|
|
134
174
|
}
|
|
135
175
|
}
|
|
136
|
-
|
|
176
|
+
else {
|
|
137
177
|
console.info("[PiBridge] pi-mcp-adapter not found; standard MCP servers disabled.");
|
|
138
178
|
}
|
|
139
179
|
// ResourceLoader with extensions wired in via factories.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aexol/spectral",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Always-on coding agent for Aexol — branded pi wrapper with relay-based browser access.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@inquirer/prompts": "^7.2.0",
|
|
54
|
+
"@mariozechner/jiti": "^2.6.5",
|
|
54
55
|
"@mariozechner/pi-coding-agent": "^0.70.2",
|
|
55
56
|
"better-sqlite3": "^12.9.0",
|
|
56
57
|
"pi-mcp-adapter": "^2.5.4",
|