@pencil-agent/nano-pencil 1.6.2 → 1.6.3
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/core/mcp-manager.js +2 -2
- package/dist/core/sdk.js +5 -5
- package/dist/main.js +99 -56
- package/package.json +1 -1
package/dist/core/mcp-manager.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Manages MCP client lifecycle and tool integration.
|
|
5
5
|
*/
|
|
6
6
|
import { MCPClient } from "./mcp/mcp-client.js";
|
|
7
|
+
import { loadMCPTools } from "./mcp/mcp-adapter.js";
|
|
7
8
|
import { listEnabledMCPServers } from "./mcp/mcp-config.js";
|
|
8
9
|
export class MCPManager {
|
|
9
10
|
client;
|
|
@@ -25,8 +26,7 @@ export class MCPManager {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
// Load tools from all servers
|
|
28
|
-
|
|
29
|
-
// this.tools = await loadMCPTools(this.client);
|
|
29
|
+
this.tools = await loadMCPTools(this.client);
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Get all MCP tools as NanoPencil ToolDefinitions
|
package/dist/core/sdk.js
CHANGED
|
@@ -234,20 +234,20 @@ export async function createAgentSession(options = {}) {
|
|
|
234
234
|
}
|
|
235
235
|
// Initialize MCP if enabled (before creating AgentSession)
|
|
236
236
|
let mcpManager;
|
|
237
|
-
|
|
238
|
-
// Will be re-enabled after refactoring tool adapter
|
|
239
|
-
// const mcpTools: ToolDefinition[] = [];
|
|
237
|
+
const mcpTools = [];
|
|
240
238
|
if (options.enableMCP) {
|
|
241
239
|
try {
|
|
242
240
|
mcpManager = new MCPManager();
|
|
243
241
|
await mcpManager.initialize();
|
|
244
|
-
|
|
242
|
+
mcpTools.push(...mcpManager.getTools());
|
|
245
243
|
time("mcp.initialize");
|
|
246
244
|
}
|
|
247
245
|
catch (error) {
|
|
248
246
|
console.warn(`Failed to initialize MCP: ${error}`);
|
|
249
247
|
}
|
|
250
248
|
}
|
|
249
|
+
// Merge MCP tools with custom tools
|
|
250
|
+
const allCustomTools = [...(options.customTools || []), ...mcpTools];
|
|
251
251
|
// Initialize Soul if enabled (before creating AgentSession)
|
|
252
252
|
let soulManager;
|
|
253
253
|
if (isSoulEnabled(options)) {
|
|
@@ -273,7 +273,7 @@ export async function createAgentSession(options = {}) {
|
|
|
273
273
|
cwd,
|
|
274
274
|
scopedModels: options.scopedModels,
|
|
275
275
|
resourceLoader,
|
|
276
|
-
customTools:
|
|
276
|
+
customTools: allCustomTools,
|
|
277
277
|
modelRegistry,
|
|
278
278
|
initialActiveToolNames,
|
|
279
279
|
extensionRunnerRef,
|
package/dist/main.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This file handles CLI argument parsing and translates them into
|
|
5
5
|
* createAgentSession() options. The SDK does the heavy lifting.
|
|
6
6
|
*/
|
|
7
|
-
import { modelsAreEqual, supportsXhigh } from "@mariozechner/pi-ai";
|
|
7
|
+
import { modelsAreEqual, supportsXhigh, } from "@mariozechner/pi-ai";
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import { join } from "path";
|
|
10
10
|
import { createInterface } from "readline";
|
|
@@ -19,17 +19,17 @@ import { DEFAULT_THINKING_LEVEL } from "./core/defaults.js";
|
|
|
19
19
|
import { exportFromFile } from "./core/export-html/index.js";
|
|
20
20
|
import { KeybindingsManager } from "./core/keybindings.js";
|
|
21
21
|
import { ModelRegistry } from "./core/model-registry.js";
|
|
22
|
-
import { resolveCliModel, resolveModelScope } from "./core/model-resolver.js";
|
|
22
|
+
import { resolveCliModel, resolveModelScope, } from "./core/model-resolver.js";
|
|
23
23
|
import { DefaultPackageManager } from "./core/package-manager.js";
|
|
24
24
|
import { DefaultResourceLoader } from "./core/resource-loader.js";
|
|
25
|
-
import { createAgentSession } from "./core/sdk.js";
|
|
25
|
+
import { createAgentSession, } from "./core/sdk.js";
|
|
26
26
|
import { SessionManager } from "./core/session-manager.js";
|
|
27
27
|
import { SettingsManager } from "./core/settings-manager.js";
|
|
28
28
|
import { printTimings, time } from "./core/timings.js";
|
|
29
29
|
import { allTools } from "./core/tools/index.js";
|
|
30
30
|
import { runMigrations, showDeprecationWarnings } from "./migrations.js";
|
|
31
31
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
|
|
32
|
-
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
|
|
32
|
+
import { initTheme, stopThemeWatcher, } from "./modes/interactive/theme/theme.js";
|
|
33
33
|
import { ensureNanopencilCodingPlanAuth, ensureNanopencilDefaultConfig, NANOPENCIL_DEFAULT_PROVIDER, } from "./nanopencil-defaults.js";
|
|
34
34
|
import { getNanopencilDefaultExtensionPaths } from "./pencil-mem-integration.js";
|
|
35
35
|
/**
|
|
@@ -65,7 +65,9 @@ function reportSettingsErrors(settingsManager, context) {
|
|
|
65
65
|
function isTruthyEnvFlag(value) {
|
|
66
66
|
if (!value)
|
|
67
67
|
return false;
|
|
68
|
-
return value === "1" ||
|
|
68
|
+
return (value === "1" ||
|
|
69
|
+
value.toLowerCase() === "true" ||
|
|
70
|
+
value.toLowerCase() === "yes");
|
|
69
71
|
}
|
|
70
72
|
function getPackageCommandUsage(command) {
|
|
71
73
|
switch (command) {
|
|
@@ -82,56 +84,59 @@ function getPackageCommandUsage(command) {
|
|
|
82
84
|
function printPackageCommandHelp(command) {
|
|
83
85
|
switch (command) {
|
|
84
86
|
case "install":
|
|
85
|
-
console.log(`${chalk.bold("Usage:")}
|
|
86
|
-
${getPackageCommandUsage("install")}
|
|
87
|
-
|
|
88
|
-
Install a package and add it to settings.
|
|
89
|
-
|
|
90
|
-
Options:
|
|
91
|
-
-l, --local Install project-locally (.pi/settings.json)
|
|
92
|
-
|
|
93
|
-
Examples:
|
|
94
|
-
${APP_NAME} install npm:@foo/bar
|
|
95
|
-
${APP_NAME} install git:github.com/user/repo
|
|
96
|
-
${APP_NAME} install git:git@github.com:user/repo
|
|
97
|
-
${APP_NAME} install https://github.com/user/repo
|
|
98
|
-
${APP_NAME} install ssh://git@github.com/user/repo
|
|
99
|
-
${APP_NAME} install ./local/path
|
|
87
|
+
console.log(`${chalk.bold("Usage:")}
|
|
88
|
+
${getPackageCommandUsage("install")}
|
|
89
|
+
|
|
90
|
+
Install a package and add it to settings.
|
|
91
|
+
|
|
92
|
+
Options:
|
|
93
|
+
-l, --local Install project-locally (.pi/settings.json)
|
|
94
|
+
|
|
95
|
+
Examples:
|
|
96
|
+
${APP_NAME} install npm:@foo/bar
|
|
97
|
+
${APP_NAME} install git:github.com/user/repo
|
|
98
|
+
${APP_NAME} install git:git@github.com:user/repo
|
|
99
|
+
${APP_NAME} install https://github.com/user/repo
|
|
100
|
+
${APP_NAME} install ssh://git@github.com/user/repo
|
|
101
|
+
${APP_NAME} install ./local/path
|
|
100
102
|
`);
|
|
101
103
|
return;
|
|
102
104
|
case "remove":
|
|
103
|
-
console.log(`${chalk.bold("Usage:")}
|
|
104
|
-
${getPackageCommandUsage("remove")}
|
|
105
|
-
|
|
106
|
-
Remove a package and its source from settings.
|
|
107
|
-
|
|
108
|
-
Options:
|
|
109
|
-
-l, --local Remove from project settings (.pi/settings.json)
|
|
110
|
-
|
|
111
|
-
Example:
|
|
112
|
-
${APP_NAME} remove npm:@foo/bar
|
|
105
|
+
console.log(`${chalk.bold("Usage:")}
|
|
106
|
+
${getPackageCommandUsage("remove")}
|
|
107
|
+
|
|
108
|
+
Remove a package and its source from settings.
|
|
109
|
+
|
|
110
|
+
Options:
|
|
111
|
+
-l, --local Remove from project settings (.pi/settings.json)
|
|
112
|
+
|
|
113
|
+
Example:
|
|
114
|
+
${APP_NAME} remove npm:@foo/bar
|
|
113
115
|
`);
|
|
114
116
|
return;
|
|
115
117
|
case "update":
|
|
116
|
-
console.log(`${chalk.bold("Usage:")}
|
|
117
|
-
${getPackageCommandUsage("update")}
|
|
118
|
-
|
|
119
|
-
Update installed packages.
|
|
120
|
-
If <source> is provided, only that package is updated.
|
|
118
|
+
console.log(`${chalk.bold("Usage:")}
|
|
119
|
+
${getPackageCommandUsage("update")}
|
|
120
|
+
|
|
121
|
+
Update installed packages.
|
|
122
|
+
If <source> is provided, only that package is updated.
|
|
121
123
|
`);
|
|
122
124
|
return;
|
|
123
125
|
case "list":
|
|
124
|
-
console.log(`${chalk.bold("Usage:")}
|
|
125
|
-
${getPackageCommandUsage("list")}
|
|
126
|
-
|
|
127
|
-
List installed packages from user and project settings.
|
|
126
|
+
console.log(`${chalk.bold("Usage:")}
|
|
127
|
+
${getPackageCommandUsage("list")}
|
|
128
|
+
|
|
129
|
+
List installed packages from user and project settings.
|
|
128
130
|
`);
|
|
129
131
|
return;
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
134
|
function parsePackageCommand(args) {
|
|
133
135
|
const [command, ...rest] = args;
|
|
134
|
-
if (command !== "install" &&
|
|
136
|
+
if (command !== "install" &&
|
|
137
|
+
command !== "remove" &&
|
|
138
|
+
command !== "update" &&
|
|
139
|
+
command !== "list") {
|
|
135
140
|
return undefined;
|
|
136
141
|
}
|
|
137
142
|
let local = false;
|
|
@@ -178,7 +183,8 @@ async function handlePackageCommand(args) {
|
|
|
178
183
|
return true;
|
|
179
184
|
}
|
|
180
185
|
const source = options.source;
|
|
181
|
-
if ((options.command === "install" || options.command === "remove") &&
|
|
186
|
+
if ((options.command === "install" || options.command === "remove") &&
|
|
187
|
+
!source) {
|
|
182
188
|
console.error(chalk.red(`Missing ${options.command} source.`));
|
|
183
189
|
console.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));
|
|
184
190
|
process.exitCode = 1;
|
|
@@ -188,7 +194,11 @@ async function handlePackageCommand(args) {
|
|
|
188
194
|
const agentDir = getAgentDir();
|
|
189
195
|
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
190
196
|
reportSettingsErrors(settingsManager, "package command");
|
|
191
|
-
const packageManager = new DefaultPackageManager({
|
|
197
|
+
const packageManager = new DefaultPackageManager({
|
|
198
|
+
cwd,
|
|
199
|
+
agentDir,
|
|
200
|
+
settingsManager,
|
|
201
|
+
});
|
|
192
202
|
packageManager.setProgressCallback((event) => {
|
|
193
203
|
if (event.type === "start") {
|
|
194
204
|
process.stdout.write(chalk.dim(`${event.message}\n`));
|
|
@@ -203,7 +213,9 @@ async function handlePackageCommand(args) {
|
|
|
203
213
|
return true;
|
|
204
214
|
case "remove": {
|
|
205
215
|
await packageManager.remove(source, { local: options.local });
|
|
206
|
-
const removed = packageManager.removeSourceFromSettings(source, {
|
|
216
|
+
const removed = packageManager.removeSourceFromSettings(source, {
|
|
217
|
+
local: options.local,
|
|
218
|
+
});
|
|
207
219
|
if (!removed) {
|
|
208
220
|
console.error(chalk.red(`No matching package found for ${source}`));
|
|
209
221
|
process.exitCode = 1;
|
|
@@ -269,7 +281,9 @@ async function prepareInitialMessage(parsed, autoResizeImages) {
|
|
|
269
281
|
if (parsed.fileArgs.length === 0) {
|
|
270
282
|
return {};
|
|
271
283
|
}
|
|
272
|
-
const { text, images } = await processFileArguments(parsed.fileArgs, {
|
|
284
|
+
const { text, images } = await processFileArguments(parsed.fileArgs, {
|
|
285
|
+
autoResizeImages,
|
|
286
|
+
});
|
|
273
287
|
let initialMessage;
|
|
274
288
|
if (parsed.messages.length > 0) {
|
|
275
289
|
initialMessage = text + parsed.messages[0];
|
|
@@ -289,7 +303,9 @@ async function prepareInitialMessage(parsed, autoResizeImages) {
|
|
|
289
303
|
*/
|
|
290
304
|
async function resolveSessionPath(sessionArg, cwd, sessionDir) {
|
|
291
305
|
// If it looks like a file path, use as-is
|
|
292
|
-
if (sessionArg.includes("/") ||
|
|
306
|
+
if (sessionArg.includes("/") ||
|
|
307
|
+
sessionArg.includes("\\") ||
|
|
308
|
+
sessionArg.endsWith(".jsonl")) {
|
|
293
309
|
return { type: "path", path: sessionArg };
|
|
294
310
|
}
|
|
295
311
|
// Try to match as session ID in current project first
|
|
@@ -357,7 +373,7 @@ async function createSessionManager(parsed, cwd) {
|
|
|
357
373
|
// Default case (new session) returns undefined, SDK will create one
|
|
358
374
|
return undefined;
|
|
359
375
|
}
|
|
360
|
-
function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager) {
|
|
376
|
+
async function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager) {
|
|
361
377
|
const options = {};
|
|
362
378
|
let cliThinkingFromModel = false;
|
|
363
379
|
if (sessionManager) {
|
|
@@ -389,12 +405,19 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
389
405
|
}
|
|
390
406
|
}
|
|
391
407
|
}
|
|
392
|
-
if (!options.model &&
|
|
408
|
+
if (!options.model &&
|
|
409
|
+
scopedModels.length > 0 &&
|
|
410
|
+
!parsed.continue &&
|
|
411
|
+
!parsed.resume) {
|
|
393
412
|
// Check if saved default is in scoped models - use it if so, otherwise first scoped model
|
|
394
413
|
const savedProvider = settingsManager.getDefaultProvider();
|
|
395
414
|
const savedModelId = settingsManager.getDefaultModel();
|
|
396
|
-
const savedModel = savedProvider && savedModelId
|
|
397
|
-
|
|
415
|
+
const savedModel = savedProvider && savedModelId
|
|
416
|
+
? modelRegistry.find(savedProvider, savedModelId)
|
|
417
|
+
: undefined;
|
|
418
|
+
const savedInScope = savedModel
|
|
419
|
+
? scopedModels.find((sm) => modelsAreEqual(sm.model, savedModel))
|
|
420
|
+
: undefined;
|
|
398
421
|
if (savedInScope) {
|
|
399
422
|
options.model = savedInScope.model;
|
|
400
423
|
// Use thinking level from scoped model config if explicitly set
|
|
@@ -438,6 +461,13 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
438
461
|
else if (parsed.tools) {
|
|
439
462
|
options.tools = parsed.tools.map((name) => allTools[name]);
|
|
440
463
|
}
|
|
464
|
+
// Enable MCP by default if there are enabled MCP servers
|
|
465
|
+
// Users can disable with --no-mcp flag if needed
|
|
466
|
+
const { listEnabledMCPServers } = await import("./core/mcp/mcp-config.js");
|
|
467
|
+
const enabledMcpServers = listEnabledMCPServers();
|
|
468
|
+
if (enabledMcpServers.length > 0) {
|
|
469
|
+
options.enableMCP = true;
|
|
470
|
+
}
|
|
441
471
|
return { options, cliThinkingFromModel };
|
|
442
472
|
}
|
|
443
473
|
async function handleConfigCommand(args) {
|
|
@@ -448,7 +478,11 @@ async function handleConfigCommand(args) {
|
|
|
448
478
|
const agentDir = getAgentDir();
|
|
449
479
|
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
450
480
|
reportSettingsErrors(settingsManager, "config command");
|
|
451
|
-
const packageManager = new DefaultPackageManager({
|
|
481
|
+
const packageManager = new DefaultPackageManager({
|
|
482
|
+
cwd,
|
|
483
|
+
agentDir,
|
|
484
|
+
settingsManager,
|
|
485
|
+
});
|
|
452
486
|
const resolvedPaths = await packageManager.resolve();
|
|
453
487
|
await selectConfig({
|
|
454
488
|
resolvedPaths,
|
|
@@ -488,14 +522,20 @@ export async function main(args) {
|
|
|
488
522
|
}
|
|
489
523
|
}
|
|
490
524
|
const modelRegistry = new ModelRegistry(authStorage, getModelsPath(), APP_NAME === "nanopencil"
|
|
491
|
-
? {
|
|
525
|
+
? {
|
|
526
|
+
useOnlyCustomModels: true,
|
|
527
|
+
allowOptionalApiKeyForProvider: NANOPENCIL_DEFAULT_PROVIDER,
|
|
528
|
+
}
|
|
492
529
|
: {});
|
|
493
530
|
const defaultExtPaths = APP_NAME === "nanopencil" ? getNanopencilDefaultExtensionPaths() : [];
|
|
494
531
|
const resourceLoader = new DefaultResourceLoader({
|
|
495
532
|
cwd,
|
|
496
533
|
agentDir,
|
|
497
534
|
settingsManager,
|
|
498
|
-
additionalExtensionPaths: [
|
|
535
|
+
additionalExtensionPaths: [
|
|
536
|
+
...defaultExtPaths,
|
|
537
|
+
...(firstPass.extensions ?? []),
|
|
538
|
+
],
|
|
499
539
|
additionalSkillPaths: firstPass.skills,
|
|
500
540
|
additionalPromptTemplatePaths: firstPass.promptTemplates,
|
|
501
541
|
additionalThemePaths: firstPass.themes,
|
|
@@ -525,7 +565,8 @@ export async function main(args) {
|
|
|
525
565
|
}
|
|
526
566
|
// Apply pending provider registrations from extensions immediately
|
|
527
567
|
// so they're available for model resolution before AgentSession is created
|
|
528
|
-
for (const { name, config } of extensionsResult.runtime
|
|
568
|
+
for (const { name, config } of extensionsResult.runtime
|
|
569
|
+
.pendingProviderRegistrations) {
|
|
529
570
|
modelRegistry.registerProvider(name, config);
|
|
530
571
|
}
|
|
531
572
|
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
@@ -592,7 +633,8 @@ export async function main(args) {
|
|
|
592
633
|
if (APP_NAME === "nanopencil" && settingsManager.getTheme() === undefined) {
|
|
593
634
|
settingsManager.setTheme("warm");
|
|
594
635
|
}
|
|
595
|
-
initTheme(settingsManager.getTheme() ??
|
|
636
|
+
initTheme(settingsManager.getTheme() ??
|
|
637
|
+
(APP_NAME === "nanopencil" ? "warm" : undefined), isInteractive);
|
|
596
638
|
// Show deprecation warnings in interactive mode
|
|
597
639
|
if (isInteractive && deprecationWarnings.length > 0) {
|
|
598
640
|
await showDeprecationWarnings(deprecationWarnings);
|
|
@@ -616,7 +658,7 @@ export async function main(args) {
|
|
|
616
658
|
}
|
|
617
659
|
sessionManager = SessionManager.open(selectedPath);
|
|
618
660
|
}
|
|
619
|
-
const { options: sessionOptions, cliThinkingFromModel } = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager);
|
|
661
|
+
const { options: sessionOptions, cliThinkingFromModel } = await buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager);
|
|
620
662
|
sessionOptions.authStorage = authStorage;
|
|
621
663
|
sessionOptions.modelRegistry = modelRegistry;
|
|
622
664
|
sessionOptions.resourceLoader = resourceLoader;
|
|
@@ -655,7 +697,8 @@ export async function main(args) {
|
|
|
655
697
|
await runRpcMode(session);
|
|
656
698
|
}
|
|
657
699
|
else if (isInteractive) {
|
|
658
|
-
if (scopedModels.length > 0 &&
|
|
700
|
+
if (scopedModels.length > 0 &&
|
|
701
|
+
(parsed.verbose || !settingsManager.getQuietStartup())) {
|
|
659
702
|
const modelList = scopedModels
|
|
660
703
|
.map((sm) => {
|
|
661
704
|
const thinkingStr = sm.thinkingLevel ? `:${sm.thinkingLevel}` : "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pencil-agent/nano-pencil",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "CLI writing agent with read, bash, edit, write tools and session management. Based on pi; supports DashScope Coding Plan. Soul enabled by default for AI personality evolution.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|