@aexol/spectral 0.6.4 → 0.6.9
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/cli.js +8 -1
- package/dist/commands/serve.js +1 -0
- package/dist/extensions/aexol-mcp.js +16 -1
- package/dist/mcp/tool-registrar.js +18 -2
- package/dist/relay/auto-research.js +631 -445
- package/dist/relay/dispatcher.js +5 -7
- package/dist/relay/models-fetch.js +5 -1
- package/dist/server/pi-bridge.js +35 -11
- package/dist/server/session-stream.js +10 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -138,7 +138,14 @@ function delegateToPi(args) {
|
|
|
138
138
|
const piBin = resolvePiBin();
|
|
139
139
|
const child = spawn(process.execPath, [piBin, ...args], {
|
|
140
140
|
stdio: "inherit",
|
|
141
|
-
env:
|
|
141
|
+
env: {
|
|
142
|
+
...process.env,
|
|
143
|
+
// Prevent git from opening an interactive editor when the agent
|
|
144
|
+
// runs commands like `git rebase --continue`, `git commit` (without -m),
|
|
145
|
+
// or `git merge`. Without this, the editor hangs forever waiting for
|
|
146
|
+
// TTY input that doesn't exist in the agent's non-interactive shell.
|
|
147
|
+
GIT_EDITOR: "true",
|
|
148
|
+
},
|
|
142
149
|
});
|
|
143
150
|
// Forward common termination signals to pi so its TUI can clean up.
|
|
144
151
|
const signals = ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"];
|
package/dist/commands/serve.js
CHANGED
|
@@ -45,8 +45,23 @@ function renderContentToString(content) {
|
|
|
45
45
|
}
|
|
46
46
|
if (typeof first.text === "string")
|
|
47
47
|
return first.text;
|
|
48
|
+
// For image/audio/binary content types, return a metadata placeholder
|
|
49
|
+
// instead of serializing the raw base64 data into the model context.
|
|
50
|
+
if (first.type === "image" || first.type === "audio") {
|
|
51
|
+
const mimeType = typeof first.mimeType === "string" ? first.mimeType : first.type;
|
|
52
|
+
const dataLen = typeof first.data === "string" ? first.data.length : 0;
|
|
53
|
+
return `[${first.type}: ${mimeType}${dataLen ? `, ${dataLen.toLocaleString()} bytes base64` : ""}]`;
|
|
54
|
+
}
|
|
48
55
|
try {
|
|
49
|
-
|
|
56
|
+
// Strip large binary fields from serialization to prevent context overflow.
|
|
57
|
+
const safe = content.map((c) => {
|
|
58
|
+
const copy = { ...c };
|
|
59
|
+
if ("data" in copy && typeof copy.data === "string" && copy.data.length > 200) {
|
|
60
|
+
copy.data = `[${copy.data.length.toLocaleString()} bytes base64 omitted]`;
|
|
61
|
+
}
|
|
62
|
+
return copy;
|
|
63
|
+
});
|
|
64
|
+
return JSON.stringify(safe, null, 2);
|
|
50
65
|
}
|
|
51
66
|
catch {
|
|
52
67
|
return String(content);
|
|
@@ -57,7 +57,14 @@ export function transformMcpContent(content) {
|
|
|
57
57
|
}
|
|
58
58
|
if (c.type === "resource") {
|
|
59
59
|
const resourceUri = c.resource?.uri ?? "(no URI)";
|
|
60
|
-
|
|
60
|
+
// Blob resources contain base64 binary data — never serialize the raw
|
|
61
|
+
// blob into the model context (causes context overflow and dead sessions).
|
|
62
|
+
const resourceContent = c.resource?.text ??
|
|
63
|
+
("blob" in (c.resource ?? {}) && c.resource.blob
|
|
64
|
+
? `[Binary blob: ${c.resource.mimeType ?? "application/octet-stream"}]`
|
|
65
|
+
: c.resource
|
|
66
|
+
? JSON.stringify(c.resource)
|
|
67
|
+
: "(no content)");
|
|
61
68
|
return truncateTextBlock({
|
|
62
69
|
type: "text",
|
|
63
70
|
text: `[Resource: ${resourceUri}]\n${resourceContent}`,
|
|
@@ -77,6 +84,15 @@ export function transformMcpContent(content) {
|
|
|
77
84
|
text: `[Audio content: ${c.mimeType ?? "audio/*"}]`,
|
|
78
85
|
};
|
|
79
86
|
}
|
|
80
|
-
|
|
87
|
+
// Unknown content type — serialize as text but strip any potentially
|
|
88
|
+
// large binary fields (data, blob) to avoid context overflow.
|
|
89
|
+
const safe = { ...c };
|
|
90
|
+
if ("data" in safe && typeof safe.data === "string" && safe.data.length > 200) {
|
|
91
|
+
safe.data = `[${safe.data.length.toLocaleString()} bytes base64 omitted]`;
|
|
92
|
+
}
|
|
93
|
+
if ("blob" in safe && typeof safe.blob === "string" && safe.blob.length > 200) {
|
|
94
|
+
safe.blob = `[${safe.blob.length.toLocaleString()} bytes base64 omitted]`;
|
|
95
|
+
}
|
|
96
|
+
return truncateTextBlock({ type: "text", text: JSON.stringify(safe) });
|
|
81
97
|
});
|
|
82
98
|
}
|