@pasko70/pibo 1.4.4 → 1.4.6
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/apps/chat/agent-profiles.js +4 -1
- package/dist/apps/chat/agent-store.js +196 -3
- package/dist/apps/chat/web-app.js +5 -4
- package/dist/apps/chat-ui/assets/{dist-ZB1-ui2y.js → dist-B6kzRv2_.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C3PnEkhb.js → dist-Bns-O5iY.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BAXNalar.js → dist-CVcI9eYD.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-vKlxFkTa.js → dist-CqkKCn6l.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DnACFKyO.js → dist-D4CEl91a.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CYPL-B2Z.js → dist-D9K0kHT0.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-B2BEpL7n.js → dist-DWA7BIr3.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BwUvs6Ph.js → dist-Dj3uUYqF.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C0zsJ8II.js → dist-DqaKPP5Y.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CiDSXgtg.js → dist-DuM9PL5k.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BAGS_xkV.js → dist-DvPgMX-r.js} +1 -1
- package/dist/apps/chat-ui/assets/{index-0x7tuTNX.js → index-Baxj7Erc.js} +18 -17
- package/dist/apps/chat-ui/index.html +1 -1
- package/dist/apps/chat-vscode-web/assets/{index-C3GTPyDo.js → index-CjOC7zYy.js} +4 -4
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/cli-ui/inkMarkdown.js +8 -3
- package/dist/apps/cli-ui/inkSyntaxHighlighter.js +166 -0
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/{pibo-vscode-ext-1.4.4.vsix → pibo-vscode-ext-1.4.6.vsix} +0 -0
- package/dist/cli.js +20 -0
- package/dist/mcp/agent-context.js +10 -6
- package/dist/mcp/commands/info.js +19 -7
- package/dist/mcp/config.js +98 -65
- package/dist/plugins/builtin.js +15 -1
- package/dist/plugins/codex-compat.js +2 -0
- package/dist/session-ui/terminalRows.js +111 -10
- package/dist/shared/trace-nodes.js +12 -0
- package/dist/skills/cli.js +25 -1
- package/dist/tools/codex-image-generation.js +272 -0
- package/dist/tools/guides.js +71 -0
- package/dist/tools/index.js +7 -3
- package/dist/tools/python-runtime.js +2 -2
- package/dist/tools/registry.js +25 -1
- package/package.json +1 -1
- package/skills/builtin/graphify/SKILL.md +52 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#101d22" />
|
|
7
7
|
<title>Pibo</title>
|
|
8
|
-
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-CjOC7zYy.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/apps/chat-vscode/assets/index-B5QK07zO.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sanitizeTerminalText, tokenizeJsonTextLine } from "./inkJson.js";
|
|
2
|
+
import { highlightInkCodeLine, normalizeInkCodeLanguage } from "./inkSyntaxHighlighter.js";
|
|
2
3
|
export function renderInkMarkdownLines(markdown, options = {}) {
|
|
3
4
|
return renderInkMarkdownTerminalLines(markdown, options).map((line) => line.tokens.map((token) => token.text).join(""));
|
|
4
5
|
}
|
|
@@ -105,14 +106,18 @@ function inlineMarkdownTokens(text, defaults = {}) {
|
|
|
105
106
|
return tokens.filter((token) => token.text.length > 0);
|
|
106
107
|
}
|
|
107
108
|
function codeFenceTokens(sourceLine, language) {
|
|
108
|
-
|
|
109
|
+
const normalizedLanguage = normalizeInkCodeLanguage(language);
|
|
110
|
+
if (isBashLanguage(normalizedLanguage))
|
|
109
111
|
return [{ text: " " }, ...tokenizeInkBashCommand(sourceLine)];
|
|
110
|
-
if (
|
|
112
|
+
if (normalizedLanguage === "json")
|
|
111
113
|
return [{ text: " " }, ...tokenizeJsonTextLine(sourceLine)];
|
|
114
|
+
const highlighted = highlightInkCodeLine(sourceLine, normalizedLanguage);
|
|
115
|
+
if (highlighted)
|
|
116
|
+
return [{ text: " " }, ...highlighted];
|
|
112
117
|
return [{ text: ` ${sourceLine}`, tone: "default" }];
|
|
113
118
|
}
|
|
114
119
|
function isBashLanguage(language) {
|
|
115
|
-
return
|
|
120
|
+
return language === "bash";
|
|
116
121
|
}
|
|
117
122
|
function line(tokens) {
|
|
118
123
|
return { prefix: "none", tokens };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
const languageAliases = new Map([
|
|
4
|
+
["sh", "bash"],
|
|
5
|
+
["shell", "bash"],
|
|
6
|
+
["shellscript", "bash"],
|
|
7
|
+
["zsh", "bash"],
|
|
8
|
+
["js", "javascript"],
|
|
9
|
+
["mjs", "javascript"],
|
|
10
|
+
["cjs", "javascript"],
|
|
11
|
+
["ts", "typescript"],
|
|
12
|
+
["mts", "typescript"],
|
|
13
|
+
["cts", "typescript"],
|
|
14
|
+
["md", "markdown"],
|
|
15
|
+
["yml", "yaml"],
|
|
16
|
+
["jsonc", "json"],
|
|
17
|
+
["py", "python"],
|
|
18
|
+
["rs", "rust"],
|
|
19
|
+
]);
|
|
20
|
+
const grammarComponents = {
|
|
21
|
+
bash: ["bash"],
|
|
22
|
+
css: ["css"],
|
|
23
|
+
go: ["go"],
|
|
24
|
+
html: ["markup"],
|
|
25
|
+
javascript: ["javascript"],
|
|
26
|
+
json: ["json"],
|
|
27
|
+
jsx: ["markup", "javascript", "jsx"],
|
|
28
|
+
markdown: ["markup", "markdown"],
|
|
29
|
+
python: ["python"],
|
|
30
|
+
rust: ["rust"],
|
|
31
|
+
sql: ["sql"],
|
|
32
|
+
tsx: ["markup", "javascript", "jsx", "typescript", "tsx"],
|
|
33
|
+
typescript: ["javascript", "typescript"],
|
|
34
|
+
yaml: ["yaml"],
|
|
35
|
+
};
|
|
36
|
+
const loadedComponents = new Set();
|
|
37
|
+
let prismInstance;
|
|
38
|
+
export function highlightInkCodeLine(sourceLine, language) {
|
|
39
|
+
if (shouldUsePlainCodeTokens())
|
|
40
|
+
return [{ text: sourceLine, tone: "default" }];
|
|
41
|
+
const normalizedLanguage = normalizeInkCodeLanguage(language);
|
|
42
|
+
const prism = loadPrism();
|
|
43
|
+
if (!loadGrammar(prism, normalizedLanguage))
|
|
44
|
+
return undefined;
|
|
45
|
+
const grammar = prism.languages[normalizedLanguage];
|
|
46
|
+
if (!grammar)
|
|
47
|
+
return undefined;
|
|
48
|
+
try {
|
|
49
|
+
return flattenPrismTokens(prism.tokenize(sourceLine, grammar));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function normalizeInkCodeLanguage(language) {
|
|
56
|
+
const normalized = language.trim().toLowerCase();
|
|
57
|
+
return languageAliases.get(normalized) ?? normalized;
|
|
58
|
+
}
|
|
59
|
+
function loadPrism() {
|
|
60
|
+
prismInstance ??= require("prismjs");
|
|
61
|
+
return prismInstance;
|
|
62
|
+
}
|
|
63
|
+
function loadGrammar(prism, language) {
|
|
64
|
+
const components = grammarComponents[language];
|
|
65
|
+
if (!components)
|
|
66
|
+
return false;
|
|
67
|
+
for (const component of components) {
|
|
68
|
+
if (loadedComponents.has(component))
|
|
69
|
+
continue;
|
|
70
|
+
require(`prismjs/components/prism-${component}.js`);
|
|
71
|
+
loadedComponents.add(component);
|
|
72
|
+
}
|
|
73
|
+
return Boolean(prism.languages[language]);
|
|
74
|
+
}
|
|
75
|
+
function flattenPrismTokens(tokens, inheritedTone = "default") {
|
|
76
|
+
const result = [];
|
|
77
|
+
for (const token of tokens) {
|
|
78
|
+
if (typeof token === "string") {
|
|
79
|
+
if (token.length > 0)
|
|
80
|
+
result.push({ text: token, tone: inheritedTone });
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const tone = toneForPrismToken(token) ?? inheritedTone;
|
|
84
|
+
appendPrismContent(result, token.content, tone);
|
|
85
|
+
}
|
|
86
|
+
return mergeAdjacentTokens(result);
|
|
87
|
+
}
|
|
88
|
+
function appendPrismContent(result, content, tone) {
|
|
89
|
+
if (typeof content === "string") {
|
|
90
|
+
if (content.length > 0)
|
|
91
|
+
result.push({ text: content, tone });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(content)) {
|
|
95
|
+
result.push(...flattenPrismTokens(content, tone));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const nestedTone = toneForPrismToken(content) ?? tone;
|
|
99
|
+
appendPrismContent(result, content.content, nestedTone);
|
|
100
|
+
}
|
|
101
|
+
function toneForPrismToken(token) {
|
|
102
|
+
const classes = [token.type, ...aliasesForToken(token)];
|
|
103
|
+
for (const className of classes) {
|
|
104
|
+
switch (className) {
|
|
105
|
+
case "comment":
|
|
106
|
+
case "prolog":
|
|
107
|
+
case "doctype":
|
|
108
|
+
case "cdata":
|
|
109
|
+
return "dim";
|
|
110
|
+
case "string":
|
|
111
|
+
case "char":
|
|
112
|
+
case "attr-value":
|
|
113
|
+
case "url":
|
|
114
|
+
return "green";
|
|
115
|
+
case "number":
|
|
116
|
+
case "boolean":
|
|
117
|
+
case "constant":
|
|
118
|
+
return "blue";
|
|
119
|
+
case "keyword":
|
|
120
|
+
case "operator":
|
|
121
|
+
case "punctuation":
|
|
122
|
+
case "important":
|
|
123
|
+
case "atrule":
|
|
124
|
+
return "magenta";
|
|
125
|
+
case "function":
|
|
126
|
+
case "method":
|
|
127
|
+
case "selector":
|
|
128
|
+
case "class-name":
|
|
129
|
+
return "yellow";
|
|
130
|
+
case "tag":
|
|
131
|
+
case "property":
|
|
132
|
+
case "attr-name":
|
|
133
|
+
case "variable":
|
|
134
|
+
case "regex":
|
|
135
|
+
return "cyan";
|
|
136
|
+
case "builtin":
|
|
137
|
+
case "symbol":
|
|
138
|
+
case "deleted":
|
|
139
|
+
return "red";
|
|
140
|
+
default:
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
function aliasesForToken(token) {
|
|
147
|
+
if (!token.alias)
|
|
148
|
+
return [];
|
|
149
|
+
return Array.isArray(token.alias) ? token.alias : [token.alias];
|
|
150
|
+
}
|
|
151
|
+
function mergeAdjacentTokens(tokens) {
|
|
152
|
+
const merged = [];
|
|
153
|
+
for (const token of tokens) {
|
|
154
|
+
const previous = merged[merged.length - 1];
|
|
155
|
+
if (previous && previous.tone === token.tone && previous.weight === token.weight && previous.italic === token.italic) {
|
|
156
|
+
previous.text += token.text;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
merged.push({ ...token });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return merged;
|
|
163
|
+
}
|
|
164
|
+
function shouldUsePlainCodeTokens() {
|
|
165
|
+
return Boolean(process.env.NO_COLOR) || process.env.TERM === "dumb" || process.env.PIBO_ASCII_PROGRESS === "1";
|
|
166
|
+
}
|
|
Binary file
|
package/dist/apps/vscode-artifacts/{pibo-vscode-ext-1.4.4.vsix → pibo-vscode-ext-1.4.6.vsix}
RENAMED
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { Command } from "commander";
|
|
2
3
|
import { PIBO_CONFIG_KEYS, getDefaultPiboConfigPath, deletePiboConfigValue, getDisplayPiboConfigValue, loadPiboConfig, redactPiboConfig, savePiboConfig, setPiboConfigValue, } from "./config/config.js";
|
|
3
4
|
import { parsePiboThinkingLevel } from "./core/thinking.js";
|
|
@@ -20,6 +21,16 @@ function printConfigKeys() {
|
|
|
20
21
|
function printRootDiscovery() {
|
|
21
22
|
console.log(printRootDiscoveryText());
|
|
22
23
|
}
|
|
24
|
+
function getPiboVersion() {
|
|
25
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
26
|
+
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
|
|
27
|
+
throw new Error("Unable to read Pibo package version");
|
|
28
|
+
}
|
|
29
|
+
return packageJson.version;
|
|
30
|
+
}
|
|
31
|
+
function printPiboVersion() {
|
|
32
|
+
console.log(getPiboVersion());
|
|
33
|
+
}
|
|
23
34
|
function printConfigDiscovery() {
|
|
24
35
|
console.log(printConfigDiscoveryText());
|
|
25
36
|
}
|
|
@@ -46,6 +57,10 @@ export async function runPiboCli(argv = process.argv) {
|
|
|
46
57
|
printRootDiscovery();
|
|
47
58
|
return;
|
|
48
59
|
}
|
|
60
|
+
if (argv[2] === "--version" || argv[2] === "-V") {
|
|
61
|
+
printPiboVersion();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
49
64
|
if (argv[2] === "mcp") {
|
|
50
65
|
const { runMcpCli } = await import("./mcp/index.js");
|
|
51
66
|
await runMcpCli([argv[0] ?? "node", "pibo mcp", ...argv.slice(3)]);
|
|
@@ -348,6 +363,7 @@ export async function runPiboCli(argv = process.argv) {
|
|
|
348
363
|
.option("--auth <mode>", "Auth service mode: 'better-auth' (default) or 'local' (loopback-only, no Google OAuth)")
|
|
349
364
|
.option("--web-host <host>", "Bind the HTTP web host, for example 0.0.0.0 for LAN access")
|
|
350
365
|
.option("--web-port <port>", "Bind the HTTP web host port", parsePort)
|
|
366
|
+
.option("--gateway-port <port>", "Bind the agent-runtime gateway port", parsePort)
|
|
351
367
|
.action(async (options) => {
|
|
352
368
|
const { runWebGatewayServer } = await import("./gateway/web.js");
|
|
353
369
|
const authMode = options.auth;
|
|
@@ -360,6 +376,7 @@ export async function runPiboCli(argv = process.argv) {
|
|
|
360
376
|
}
|
|
361
377
|
await runWebGatewayServer({
|
|
362
378
|
authMode: authMode,
|
|
379
|
+
port: options.gatewayPort,
|
|
363
380
|
web: {
|
|
364
381
|
host: options.webHost,
|
|
365
382
|
port: options.webPort,
|
|
@@ -403,6 +420,9 @@ Commands:
|
|
|
403
420
|
gateway Inspect and restart host gateways through safe CLI commands
|
|
404
421
|
gateway:web Start a web gateway runtime (use --auth=local for loopback-only local auth)
|
|
405
422
|
|
|
423
|
+
Options:
|
|
424
|
+
--version Print the Pibo CLI version
|
|
425
|
+
|
|
406
426
|
Next:
|
|
407
427
|
pibo <command> --help
|
|
408
428
|
`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { ensureConfigExists,
|
|
2
|
+
import { ensureConfigExists, isHttpServer, loadConfig, } from './config.js';
|
|
3
3
|
import { ErrorCode, formatCliError } from './errors.js';
|
|
4
4
|
export const MCP_SERVER_DESCRIPTION_MAX_LENGTH = 480;
|
|
5
5
|
export const ENABLED_MCP_SERVERS_CONTEXT_PATH = '.pibo/context/enabled-mcp-servers.md';
|
|
@@ -22,11 +22,15 @@ export function normalizeMcpServerDescription(value) {
|
|
|
22
22
|
return description;
|
|
23
23
|
}
|
|
24
24
|
export async function listMcpServerInfos(configPath) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return [];
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
try {
|
|
26
|
+
const config = await loadConfig(configPath);
|
|
27
|
+
return Object.entries(config.mcpServers).map(([name, server]) => mcpServerInfoFromConfig(name, server));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (error.message.includes('CONFIG_NOT_FOUND'))
|
|
31
|
+
return [];
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
30
34
|
}
|
|
31
35
|
export async function setMcpServerDescription(serverName, descriptionInput, configPath) {
|
|
32
36
|
const description = normalizeMcpServerDescription(descriptionInput);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Info command - Show server or tool details
|
|
3
3
|
*/
|
|
4
4
|
import { getConnection, safeClose } from '../client.js';
|
|
5
|
-
import {
|
|
5
|
+
import { formatConfigSourceSummaries, getConfigSourceSummaries, loadConfig, } from '../config.js';
|
|
6
6
|
import { ErrorCode, formatCliError, serverConnectionError, toolNotFoundError, } from '../errors.js';
|
|
7
7
|
import { formatServerDetails, formatToolSchema } from '../output.js';
|
|
8
8
|
/**
|
|
@@ -28,12 +28,24 @@ export async function infoCommand(options) {
|
|
|
28
28
|
process.exit(ErrorCode.CLIENT_ERROR);
|
|
29
29
|
}
|
|
30
30
|
const { server: serverName, tool: toolName } = parseTarget(options.target);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
console.error(
|
|
31
|
+
const serverConfig = config.mcpServers[serverName];
|
|
32
|
+
if (!serverConfig) {
|
|
33
|
+
const available = Object.keys(config.mcpServers);
|
|
34
|
+
const serverList = available.length > 0 ? available.join(', ') : '(none)';
|
|
35
|
+
const summaries = await getConfigSourceSummaries(options.configPath);
|
|
36
|
+
console.error(formatCliError({
|
|
37
|
+
code: ErrorCode.CLIENT_ERROR,
|
|
38
|
+
type: 'SERVER_NOT_FOUND',
|
|
39
|
+
message: `Server "${serverName}" not found in config`,
|
|
40
|
+
details: [
|
|
41
|
+
`Merged available servers: ${serverList}`,
|
|
42
|
+
'Config search paths:',
|
|
43
|
+
formatConfigSourceSummaries(summaries),
|
|
44
|
+
].join('\n'),
|
|
45
|
+
suggestion: available.length > 0
|
|
46
|
+
? `Use one of: ${available.map((s) => `pibo mcp info ${s}`).join(', ')}`
|
|
47
|
+
: `Add server to mcp_servers.json: { "mcpServers": { "${serverName}": { ... } } }`,
|
|
48
|
+
}));
|
|
37
49
|
process.exit(ErrorCode.CLIENT_ERROR);
|
|
38
50
|
}
|
|
39
51
|
let connection;
|
package/dist/mcp/config.js
CHANGED
|
@@ -311,6 +311,17 @@ export function getDefaultConfigPaths() {
|
|
|
311
311
|
paths.push(join(home, '.config', 'mcp', 'mcp_servers.json'));
|
|
312
312
|
return paths;
|
|
313
313
|
}
|
|
314
|
+
export function getConfigSearchPaths(explicitPath) {
|
|
315
|
+
const paths = [];
|
|
316
|
+
if (explicitPath) {
|
|
317
|
+
paths.push(resolve(explicitPath));
|
|
318
|
+
}
|
|
319
|
+
if (process.env.MCP_CONFIG_PATH) {
|
|
320
|
+
paths.push(resolve(process.env.MCP_CONFIG_PATH));
|
|
321
|
+
}
|
|
322
|
+
paths.push(...getDefaultConfigPaths());
|
|
323
|
+
return [...new Set(paths)];
|
|
324
|
+
}
|
|
314
325
|
export function getPreferredConfigPath(explicitPath) {
|
|
315
326
|
if (explicitPath) {
|
|
316
327
|
return resolve(explicitPath);
|
|
@@ -341,38 +352,7 @@ export async function ensureConfigExists(explicitPath) {
|
|
|
341
352
|
await writeFile(configPath, `${JSON.stringify({ mcpServers: {} }, null, 2)}\n`);
|
|
342
353
|
return configPath;
|
|
343
354
|
}
|
|
344
|
-
|
|
345
|
-
* Load and parse MCP servers configuration
|
|
346
|
-
*/
|
|
347
|
-
export async function loadConfig(explicitPath) {
|
|
348
|
-
let configPath;
|
|
349
|
-
// Check explicit path from argument or environment
|
|
350
|
-
if (explicitPath) {
|
|
351
|
-
configPath = resolve(explicitPath);
|
|
352
|
-
}
|
|
353
|
-
else if (process.env.MCP_CONFIG_PATH) {
|
|
354
|
-
configPath = resolve(process.env.MCP_CONFIG_PATH);
|
|
355
|
-
}
|
|
356
|
-
// If explicit path provided, it must exist
|
|
357
|
-
if (configPath) {
|
|
358
|
-
if (!existsSync(configPath)) {
|
|
359
|
-
throw new Error(formatCliError(configNotFoundError(configPath)));
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
// Search default paths
|
|
364
|
-
const searchPaths = getDefaultConfigPaths();
|
|
365
|
-
for (const path of searchPaths) {
|
|
366
|
-
if (existsSync(path)) {
|
|
367
|
-
configPath = path;
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
if (!configPath) {
|
|
372
|
-
throw new Error(formatCliError(configSearchError()));
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
// Read and parse config
|
|
355
|
+
async function readRawConfig(configPath) {
|
|
376
356
|
const content = await readFile(configPath, 'utf-8');
|
|
377
357
|
let config;
|
|
378
358
|
try {
|
|
@@ -381,45 +361,98 @@ export async function loadConfig(explicitPath) {
|
|
|
381
361
|
catch (e) {
|
|
382
362
|
throw new Error(formatCliError(configInvalidJsonError(configPath, e.message)));
|
|
383
363
|
}
|
|
384
|
-
// Validate structure
|
|
385
364
|
if (!config.mcpServers || typeof config.mcpServers !== 'object') {
|
|
386
365
|
throw new Error(formatCliError(configMissingFieldError(configPath)));
|
|
387
366
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
367
|
+
return config;
|
|
368
|
+
}
|
|
369
|
+
function validateServerConfig(serverName, serverConfig) {
|
|
370
|
+
if (!serverConfig || typeof serverConfig !== 'object') {
|
|
371
|
+
throw new Error(formatCliError({
|
|
372
|
+
code: ErrorCode.CLIENT_ERROR,
|
|
373
|
+
type: 'CONFIG_INVALID_SERVER',
|
|
374
|
+
message: `Invalid server configuration for "${serverName}"`,
|
|
375
|
+
details: 'Server config must be an object',
|
|
376
|
+
suggestion: `Use { "command": "..." } for stdio or { "url": "..." } for HTTP`,
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
379
|
+
const hasCommand = 'command' in serverConfig;
|
|
380
|
+
const hasUrl = 'url' in serverConfig;
|
|
381
|
+
if (!hasCommand && !hasUrl) {
|
|
382
|
+
throw new Error(formatCliError({
|
|
383
|
+
code: ErrorCode.CLIENT_ERROR,
|
|
384
|
+
type: 'CONFIG_INVALID_SERVER',
|
|
385
|
+
message: `Server "${serverName}" missing required field`,
|
|
386
|
+
details: `Must have either "command" (for stdio) or "url" (for HTTP)`,
|
|
387
|
+
suggestion: `Add "command": "npx ..." for local servers or "url": "https://..." for remote servers`,
|
|
388
|
+
}));
|
|
389
|
+
}
|
|
390
|
+
if (hasCommand && hasUrl) {
|
|
391
|
+
throw new Error(formatCliError({
|
|
392
|
+
code: ErrorCode.CLIENT_ERROR,
|
|
393
|
+
type: 'CONFIG_INVALID_SERVER',
|
|
394
|
+
message: `Server "${serverName}" has both "command" and "url"`,
|
|
395
|
+
details: 'A server must be either stdio (command) or HTTP (url), not both',
|
|
396
|
+
suggestion: `Remove one of "command" or "url"`,
|
|
397
|
+
}));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Load and merge MCP servers configuration.
|
|
402
|
+
* More specific paths appear first and win server-name conflicts.
|
|
403
|
+
*/
|
|
404
|
+
export async function loadConfig(explicitPath) {
|
|
405
|
+
const explicitOrEnvPath = explicitPath
|
|
406
|
+
? resolve(explicitPath)
|
|
407
|
+
: process.env.MCP_CONFIG_PATH
|
|
408
|
+
? resolve(process.env.MCP_CONFIG_PATH)
|
|
409
|
+
: undefined;
|
|
410
|
+
if (explicitOrEnvPath && !existsSync(explicitOrEnvPath)) {
|
|
411
|
+
throw new Error(formatCliError(configNotFoundError(explicitOrEnvPath)));
|
|
412
|
+
}
|
|
413
|
+
const existingPaths = getConfigSearchPaths(explicitPath).filter((path) => existsSync(path));
|
|
414
|
+
if (existingPaths.length === 0) {
|
|
415
|
+
throw new Error(formatCliError(configSearchError()));
|
|
416
|
+
}
|
|
417
|
+
const merged = { mcpServers: {} };
|
|
418
|
+
for (const configPath of existingPaths) {
|
|
419
|
+
const config = await readRawConfig(configPath);
|
|
420
|
+
for (const [serverName, serverConfig] of Object.entries(config.mcpServers)) {
|
|
421
|
+
if (!(serverName in merged.mcpServers)) {
|
|
422
|
+
merged.mcpServers[serverName] = serverConfig;
|
|
423
|
+
}
|
|
409
424
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
425
|
+
}
|
|
426
|
+
for (const [serverName, serverConfig] of Object.entries(merged.mcpServers)) {
|
|
427
|
+
validateServerConfig(serverName, serverConfig);
|
|
428
|
+
}
|
|
429
|
+
return substituteEnvVarsInObject(merged);
|
|
430
|
+
}
|
|
431
|
+
export async function getConfigSourceSummaries(explicitPath) {
|
|
432
|
+
const summaries = [];
|
|
433
|
+
for (const configPath of getConfigSearchPaths(explicitPath)) {
|
|
434
|
+
if (!existsSync(configPath)) {
|
|
435
|
+
summaries.push({ path: configPath, exists: false, servers: [] });
|
|
436
|
+
continue;
|
|
418
437
|
}
|
|
438
|
+
const config = await readRawConfig(configPath);
|
|
439
|
+
summaries.push({
|
|
440
|
+
path: configPath,
|
|
441
|
+
exists: true,
|
|
442
|
+
servers: Object.keys(config.mcpServers),
|
|
443
|
+
});
|
|
419
444
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
445
|
+
return summaries;
|
|
446
|
+
}
|
|
447
|
+
export function formatConfigSourceSummaries(summaries) {
|
|
448
|
+
return summaries
|
|
449
|
+
.map((summary) => {
|
|
450
|
+
const serverList = summary.exists
|
|
451
|
+
? summary.servers.join(', ') || '(none)'
|
|
452
|
+
: '(not found)';
|
|
453
|
+
return ` - ${summary.path}: ${serverList}`;
|
|
454
|
+
})
|
|
455
|
+
.join('\n');
|
|
423
456
|
}
|
|
424
457
|
/**
|
|
425
458
|
* Get a specific server config by name
|
package/dist/plugins/builtin.js
CHANGED
|
@@ -133,6 +133,11 @@ export const piboCorePlugin = definePiboPlugin({
|
|
|
133
133
|
path: builtinSkillPath("pibo-docker-system"),
|
|
134
134
|
kind: "builtin",
|
|
135
135
|
});
|
|
136
|
+
api.registerSkill({
|
|
137
|
+
name: "graphify",
|
|
138
|
+
path: builtinSkillPath("graphify"),
|
|
139
|
+
kind: "builtin",
|
|
140
|
+
});
|
|
136
141
|
api.registerSkill({
|
|
137
142
|
name: "prd",
|
|
138
143
|
path: builtinSkillPath("prd"),
|
|
@@ -245,7 +250,16 @@ export const piboCorePlugin = definePiboPlugin({
|
|
|
245
250
|
slashCommands: ["thinking"],
|
|
246
251
|
execute(context, event) {
|
|
247
252
|
const params = getThinkingParams(event);
|
|
248
|
-
|
|
253
|
+
if (!params.level)
|
|
254
|
+
return { ...context.getThinkingLevel(), action: "show_thinking_menu" };
|
|
255
|
+
const previousLevel = context.getThinkingLevel().level;
|
|
256
|
+
const result = context.setThinkingLevel(params.level);
|
|
257
|
+
return {
|
|
258
|
+
...result,
|
|
259
|
+
action: "set_thinking_level",
|
|
260
|
+
previousLevel,
|
|
261
|
+
changed: previousLevel !== result.level,
|
|
262
|
+
};
|
|
249
263
|
},
|
|
250
264
|
});
|
|
251
265
|
api.registerGatewayAction({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { dirname, resolve } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { createCodexImageGenerationToolProfile } from "../tools/codex-image-generation.js";
|
|
3
4
|
import { definePiboPlugin } from "./registry.js";
|
|
4
5
|
const CODEX_COMPAT_REGISTERED_TOOL_NAMES = [
|
|
5
6
|
"apply_patch",
|
|
@@ -22,6 +23,7 @@ export const piboCodexCompatPlugin = definePiboPlugin({
|
|
|
22
23
|
description: toolDescriptions[name],
|
|
23
24
|
});
|
|
24
25
|
}
|
|
26
|
+
api.registerTool(createCodexImageGenerationToolProfile());
|
|
25
27
|
api.registerContextFile({
|
|
26
28
|
key: CODEX_BASE_PROMPT_CONTEXT_FILE_KEY,
|
|
27
29
|
label: "Codex Base Prompt",
|