@pencil-agent/nano-pencil 1.11.8 → 1.11.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/args.d.ts +1 -0
- package/dist/cli/args.js +13 -8
- package/dist/core/extensions/loader.js +1 -0
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts +2 -1
- package/dist/core/footer-data-provider.js +7 -5
- package/dist/core/runtime/agent-session.d.ts +1 -0
- package/dist/core/runtime/agent-session.js +4 -1
- package/dist/core/runtime/sdk.js +2 -0
- package/dist/extensions/defaults/mcp/index.js +1 -0
- package/dist/main.js +12 -6
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/interactive-mode.js +6 -6
- package/dist/nanopencil-defaults.d.ts +5 -3
- package/dist/nanopencil-defaults.js +16 -15
- package/package.json +1 -1
package/dist/cli/args.d.ts
CHANGED
package/dist/cli/args.js
CHANGED
|
@@ -37,6 +37,9 @@ export function parseArgs(args, extensionFlags) {
|
|
|
37
37
|
else if (arg === "--provider" && i + 1 < args.length) {
|
|
38
38
|
result.provider = args[++i];
|
|
39
39
|
}
|
|
40
|
+
else if (arg === "--cwd" && i + 1 < args.length) {
|
|
41
|
+
result.cwd = args[++i];
|
|
42
|
+
}
|
|
40
43
|
else if (arg === "--model" && i + 1 < args.length) {
|
|
41
44
|
result.model = args[++i];
|
|
42
45
|
}
|
|
@@ -182,8 +185,9 @@ ${chalk.bold("Commands:")}
|
|
|
182
185
|
${APP_NAME} <command> --help Show help for install/remove/update/list
|
|
183
186
|
|
|
184
187
|
${chalk.bold("Options:")}
|
|
185
|
-
--provider <name> Provider name (default: google)
|
|
186
|
-
--
|
|
188
|
+
--provider <name> Provider name (default: google)
|
|
189
|
+
--cwd <dir> Working directory to use for project-local discovery
|
|
190
|
+
--model <pattern> Model pattern or ID (supports "provider/id" and optional ":<thinking>")
|
|
187
191
|
--api-key <key> API key (defaults to env vars)
|
|
188
192
|
--system-prompt <text> System prompt (default: coding assistant prompt)
|
|
189
193
|
--append-system-prompt <text> Append text or file contents to the system prompt
|
|
@@ -287,12 +291,13 @@ ${chalk.bold("Environment Variables:")}
|
|
|
287
291
|
MINIMAX_API_KEY - MiniMax API key
|
|
288
292
|
KIMI_API_KEY - Kimi For Coding API key
|
|
289
293
|
AWS_PROFILE - AWS profile for Amazon Bedrock
|
|
290
|
-
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
|
|
291
|
-
AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
|
|
292
|
-
AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)
|
|
293
|
-
AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)
|
|
294
|
-
${
|
|
295
|
-
|
|
294
|
+
AWS_ACCESS_KEY_ID - AWS access key for Amazon Bedrock
|
|
295
|
+
AWS_SECRET_ACCESS_KEY - AWS secret key for Amazon Bedrock
|
|
296
|
+
AWS_BEARER_TOKEN_BEDROCK - Bedrock API key (bearer token)
|
|
297
|
+
AWS_REGION - AWS region for Amazon Bedrock (e.g., us-east-1)
|
|
298
|
+
${`${APP_NAME.toUpperCase()}_CWD`.padEnd(32)} - Working directory override for project-local discovery
|
|
299
|
+
${ENV_AGENT_DIR.padEnd(32)} - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
|
|
300
|
+
PI_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
|
|
296
301
|
PI_OFFLINE - Disable startup network operations when set to 1/true/yes
|
|
297
302
|
PI_TOOLS_DOWNLOAD_TIMEOUT_MS - Timeout in ms for downloading fd/ripgrep (default: 60000)
|
|
298
303
|
PI_SHARE_VIEWER_URL - Base URL for /share command (default: https://pi.dev/session/)
|
|
@@ -107,6 +107,7 @@ export function createExtensionRuntime() {
|
|
|
107
107
|
*/
|
|
108
108
|
function createExtensionAPI(extension, runtime, cwd, eventBus) {
|
|
109
109
|
const api = {
|
|
110
|
+
cwd,
|
|
110
111
|
// Registration methods - write to extension
|
|
111
112
|
on(event, handler) {
|
|
112
113
|
const list = extension.handlers.get(event) ?? [];
|
|
@@ -649,6 +649,8 @@ export type ExtensionHandler<E, R = undefined> = (event: E, ctx: ExtensionContex
|
|
|
649
649
|
* ExtensionAPI passed to extension factory functions.
|
|
650
650
|
*/
|
|
651
651
|
export interface ExtensionAPI {
|
|
652
|
+
/** Working directory resolved for this extension load */
|
|
653
|
+
cwd: string;
|
|
652
654
|
on(event: "resources_discover", handler: ExtensionHandler<ResourcesDiscoverEvent, ResourcesDiscoverResult>): void;
|
|
653
655
|
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
|
654
656
|
on(event: "session_before_switch", handler: ExtensionHandler<SessionBeforeSwitchEvent, SessionBeforeSwitchResult>): void;
|
|
@@ -8,7 +8,8 @@ export declare class FooterDataProvider {
|
|
|
8
8
|
private gitWatcher;
|
|
9
9
|
private branchChangeCallbacks;
|
|
10
10
|
private availableProviderCount;
|
|
11
|
-
|
|
11
|
+
private cwd;
|
|
12
|
+
constructor(cwd: string);
|
|
12
13
|
/** Current git branch, null if not in repo, "detached" if detached HEAD */
|
|
13
14
|
getGitBranch(): string | null;
|
|
14
15
|
/** Extension status texts set via ctx.ui.setStatus() */
|
|
@@ -4,8 +4,8 @@ import { dirname, join, resolve } from "path";
|
|
|
4
4
|
* Find the git HEAD path by walking up from cwd.
|
|
5
5
|
* Handles both regular git repos (.git is a directory) and worktrees (.git is a file).
|
|
6
6
|
*/
|
|
7
|
-
function findGitHeadPath() {
|
|
8
|
-
let dir =
|
|
7
|
+
function findGitHeadPath(cwd) {
|
|
8
|
+
let dir = cwd;
|
|
9
9
|
while (true) {
|
|
10
10
|
const gitPath = join(dir, ".git");
|
|
11
11
|
if (existsSync(gitPath)) {
|
|
@@ -46,7 +46,9 @@ export class FooterDataProvider {
|
|
|
46
46
|
gitWatcher = null;
|
|
47
47
|
branchChangeCallbacks = new Set();
|
|
48
48
|
availableProviderCount = 0;
|
|
49
|
-
|
|
49
|
+
cwd;
|
|
50
|
+
constructor(cwd) {
|
|
51
|
+
this.cwd = cwd;
|
|
50
52
|
this.setupGitWatcher();
|
|
51
53
|
}
|
|
52
54
|
/** Current git branch, null if not in repo, "detached" if detached HEAD */
|
|
@@ -54,7 +56,7 @@ export class FooterDataProvider {
|
|
|
54
56
|
if (this.cachedBranch !== undefined)
|
|
55
57
|
return this.cachedBranch;
|
|
56
58
|
try {
|
|
57
|
-
const gitHeadPath = findGitHeadPath();
|
|
59
|
+
const gitHeadPath = findGitHeadPath(this.cwd);
|
|
58
60
|
if (!gitHeadPath) {
|
|
59
61
|
this.cachedBranch = null;
|
|
60
62
|
return null;
|
|
@@ -110,7 +112,7 @@ export class FooterDataProvider {
|
|
|
110
112
|
this.gitWatcher.close();
|
|
111
113
|
this.gitWatcher = null;
|
|
112
114
|
}
|
|
113
|
-
const gitHeadPath = findGitHeadPath();
|
|
115
|
+
const gitHeadPath = findGitHeadPath(this.cwd);
|
|
114
116
|
if (!gitHeadPath)
|
|
115
117
|
return;
|
|
116
118
|
// Watch the directory containing HEAD, not HEAD itself.
|
|
@@ -210,6 +210,7 @@ export declare class AgentSession {
|
|
|
210
210
|
get compactionCoordinator(): CompactionCoordinator | undefined;
|
|
211
211
|
/** Model registry for API key resolution and model discovery */
|
|
212
212
|
get modelRegistry(): ModelRegistry;
|
|
213
|
+
get cwd(): string;
|
|
213
214
|
/** Emit an event to all listeners */
|
|
214
215
|
private _emit;
|
|
215
216
|
private _lastAssistantMessage;
|
|
@@ -216,6 +216,9 @@ export class AgentSession {
|
|
|
216
216
|
get modelRegistry() {
|
|
217
217
|
return this._modelRegistry;
|
|
218
218
|
}
|
|
219
|
+
get cwd() {
|
|
220
|
+
return this._cwd;
|
|
221
|
+
}
|
|
219
222
|
// =========================================================================
|
|
220
223
|
// Event Subscription
|
|
221
224
|
// =========================================================================
|
|
@@ -2048,7 +2051,7 @@ export class AgentSession {
|
|
|
2048
2051
|
const resolvedCommand = prefix ? `${prefix}\n${command}` : command;
|
|
2049
2052
|
try {
|
|
2050
2053
|
const result = options?.operations
|
|
2051
|
-
? await executeBashWithOperations(resolvedCommand,
|
|
2054
|
+
? await executeBashWithOperations(resolvedCommand, this._cwd, options.operations, {
|
|
2052
2055
|
onChunk,
|
|
2053
2056
|
signal: this._bashAbortController.signal,
|
|
2054
2057
|
})
|
package/dist/core/runtime/sdk.js
CHANGED
|
@@ -240,6 +240,7 @@ export async function createAgentSession(options = {}) {
|
|
|
240
240
|
if (options.enableMCP) {
|
|
241
241
|
try {
|
|
242
242
|
currentMcpManager = new MCPManager();
|
|
243
|
+
currentMcpManager.setWorkingDir(cwd);
|
|
243
244
|
await currentMcpManager.initialize();
|
|
244
245
|
initialMcpTools = [...currentMcpManager.getTools()];
|
|
245
246
|
time("mcp.initialize");
|
|
@@ -282,6 +283,7 @@ export async function createAgentSession(options = {}) {
|
|
|
282
283
|
// ignore
|
|
283
284
|
}
|
|
284
285
|
currentMcpManager = new MCPManager();
|
|
286
|
+
currentMcpManager.setWorkingDir(cwd);
|
|
285
287
|
await currentMcpManager.initialize();
|
|
286
288
|
time("mcp.initialize");
|
|
287
289
|
return currentMcpManager.getTools();
|
|
@@ -19,6 +19,7 @@ export default async function mcpExtension(pi) {
|
|
|
19
19
|
console.log("[mcp] Initializing MCP...");
|
|
20
20
|
try {
|
|
21
21
|
mcpManager = new MCPManager();
|
|
22
|
+
mcpManager.setWorkingDir(pi.cwd);
|
|
22
23
|
await mcpManager.initialize();
|
|
23
24
|
const mcpTools = mcpManager.getTools();
|
|
24
25
|
// Register MCP tools
|
package/dist/main.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { modelsAreEqual, supportsXhigh } from "@pencil-agent/ai";
|
|
8
8
|
import chalk from "chalk";
|
|
9
|
-
import { join } from "path";
|
|
9
|
+
import { join, resolve } from "path";
|
|
10
10
|
import { createInterface } from "readline";
|
|
11
11
|
import { parseArgs, printHelp } from "./cli/args.js";
|
|
12
12
|
import { selectConfig } from "./cli/config-selector.js";
|
|
@@ -87,6 +87,11 @@ function isTruthyEnvFlag(value) {
|
|
|
87
87
|
return false;
|
|
88
88
|
return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
|
|
89
89
|
}
|
|
90
|
+
function resolveWorkingDirectory(parsedCwd) {
|
|
91
|
+
const envCwd = process.env[`${APP_NAME.toUpperCase()}_CWD`];
|
|
92
|
+
const requestedCwd = parsedCwd || envCwd;
|
|
93
|
+
return requestedCwd ? resolve(requestedCwd) : process.cwd();
|
|
94
|
+
}
|
|
90
95
|
function getPackageCommandUsage(command) {
|
|
91
96
|
switch (command) {
|
|
92
97
|
case "install":
|
|
@@ -491,11 +496,10 @@ export async function main(args) {
|
|
|
491
496
|
return;
|
|
492
497
|
}
|
|
493
498
|
// Run migrations (pass cwd for project-local migrations)
|
|
494
|
-
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
|
495
|
-
// First pass: parse args to get --extension paths
|
|
496
499
|
const firstPass = parseArgs(args);
|
|
500
|
+
const cwd = resolveWorkingDirectory(firstPass.cwd);
|
|
501
|
+
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);
|
|
497
502
|
// Early load extensions to discover their CLI flags
|
|
498
|
-
const cwd = process.cwd();
|
|
499
503
|
const agentDir = getAgentDir();
|
|
500
504
|
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
501
505
|
reportSettingsErrors(settingsManager, "startup");
|
|
@@ -574,6 +578,7 @@ export async function main(args) {
|
|
|
574
578
|
}
|
|
575
579
|
// Second pass: parse args with extension flags
|
|
576
580
|
const parsed = parseArgs(args, extensionFlags);
|
|
581
|
+
const parsedCwd = resolveWorkingDirectory(parsed.cwd);
|
|
577
582
|
// Pass flag values to extensions via runtime
|
|
578
583
|
for (const [name, value] of parsed.unknownFlags) {
|
|
579
584
|
extensionsResult.runtime.flagValues.set(name, value);
|
|
@@ -637,12 +642,12 @@ export async function main(args) {
|
|
|
637
642
|
scopedModels = await resolveModelScope(modelPatterns, modelRegistry);
|
|
638
643
|
}
|
|
639
644
|
// Create session manager based on CLI flags
|
|
640
|
-
let sessionManager = await createSessionManager(parsed,
|
|
645
|
+
let sessionManager = await createSessionManager(parsed, parsedCwd);
|
|
641
646
|
// Handle --resume: show session picker
|
|
642
647
|
if (parsed.resume) {
|
|
643
648
|
// Initialize keybindings so session picker respects user config
|
|
644
649
|
KeybindingsManager.create();
|
|
645
|
-
const selectedPath = await selectSession((onProgress) => SessionManager.list(
|
|
650
|
+
const selectedPath = await selectSession((onProgress) => SessionManager.list(parsedCwd, parsed.sessionDir, onProgress), SessionManager.listAll);
|
|
646
651
|
if (!selectedPath) {
|
|
647
652
|
console.log(chalk.dim("No session selected"));
|
|
648
653
|
stopThemeWatcher();
|
|
@@ -653,6 +658,7 @@ export async function main(args) {
|
|
|
653
658
|
const { options: sessionOptions, cliThinkingFromModel } = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager);
|
|
654
659
|
// NanoPencil 默认启用 MCP;离线模式或 --no-mcp 参数下关闭
|
|
655
660
|
sessionOptions.enableMCP = APP_NAME === "nanopencil" && !offlineMode && !parsed.noMcp;
|
|
661
|
+
sessionOptions.cwd = parsedCwd;
|
|
656
662
|
sessionOptions.authStorage = authStorage;
|
|
657
663
|
sessionOptions.modelRegistry = modelRegistry;
|
|
658
664
|
sessionOptions.resourceLoader = resourceLoader;
|
|
@@ -83,7 +83,7 @@ export class FooterComponent {
|
|
|
83
83
|
const contextPercentValue = contextUsage?.percent ?? 0;
|
|
84
84
|
const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
|
|
85
85
|
// Replace home directory with ~
|
|
86
|
-
let pwd =
|
|
86
|
+
let pwd = this.session.cwd;
|
|
87
87
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
88
88
|
if (home && pwd.startsWith(home)) {
|
|
89
89
|
pwd = `~${pwd.slice(home.length)}`;
|
|
@@ -170,7 +170,7 @@ export class InteractiveMode {
|
|
|
170
170
|
this.editor = this.defaultEditor;
|
|
171
171
|
this.editorContainer = new Container();
|
|
172
172
|
this.editorContainer.addChild(this.editor);
|
|
173
|
-
this.footerDataProvider = new FooterDataProvider();
|
|
173
|
+
this.footerDataProvider = new FooterDataProvider(session.cwd);
|
|
174
174
|
this.footer = new FooterComponent(session, this.footerDataProvider, this.settingsManager.getShowTokenStats());
|
|
175
175
|
this.footer.setAutoCompactEnabled(session.autoCompactionEnabled);
|
|
176
176
|
// Load hide thinking block setting
|
|
@@ -242,7 +242,7 @@ export class InteractiveMode {
|
|
|
242
242
|
...templateCommands,
|
|
243
243
|
...extensionCommands,
|
|
244
244
|
...skillCommandList,
|
|
245
|
-
],
|
|
245
|
+
], this.session.cwd, fdPath);
|
|
246
246
|
this.defaultEditor.setAutocompleteProvider(this.autocompleteProvider);
|
|
247
247
|
if (this.editor !== this.defaultEditor) {
|
|
248
248
|
this.editor.setAutocompleteProvider?.(this.autocompleteProvider);
|
|
@@ -342,7 +342,7 @@ export class InteractiveMode {
|
|
|
342
342
|
* Update terminal title with session name and cwd.
|
|
343
343
|
*/
|
|
344
344
|
updateTerminalTitle() {
|
|
345
|
-
const cwdBasename = path.basename(
|
|
345
|
+
const cwdBasename = path.basename(this.session.cwd);
|
|
346
346
|
const sessionName = this.sessionManager.getSessionName();
|
|
347
347
|
if (sessionName) {
|
|
348
348
|
this.ui.terminal.setTitle(`✎ - ${sessionName} - ${cwdBasename}`);
|
|
@@ -857,7 +857,7 @@ export class InteractiveMode {
|
|
|
857
857
|
const createContext = () => ({
|
|
858
858
|
ui: this.createExtensionUIContext(),
|
|
859
859
|
hasUI: true,
|
|
860
|
-
cwd:
|
|
860
|
+
cwd: this.session.cwd,
|
|
861
861
|
sessionManager: this.sessionManager,
|
|
862
862
|
modelRegistry: this.session.modelRegistry,
|
|
863
863
|
model: this.session.model,
|
|
@@ -2289,7 +2289,7 @@ export class InteractiveMode {
|
|
|
2289
2289
|
if (context.messages.length === 0) {
|
|
2290
2290
|
this.chatContainer.addChild(new Spacer(1));
|
|
2291
2291
|
if (APP_NAME === "nanopencil") {
|
|
2292
|
-
const cwd =
|
|
2292
|
+
const cwd = this.session.cwd;
|
|
2293
2293
|
const model = this.session.model;
|
|
2294
2294
|
const modelLine = model?.name ??
|
|
2295
2295
|
(model?.provider ? `${model.provider}` : "DashScope · Ollama");
|
|
@@ -4155,7 +4155,7 @@ export class InteractiveMode {
|
|
|
4155
4155
|
type: "user_bash",
|
|
4156
4156
|
command,
|
|
4157
4157
|
excludeFromContext,
|
|
4158
|
-
cwd:
|
|
4158
|
+
cwd: this.session.cwd,
|
|
4159
4159
|
})
|
|
4160
4160
|
: undefined;
|
|
4161
4161
|
// If extension returned a full result, use it directly
|
|
@@ -240,9 +240,11 @@ export declare const NANOPENCIL_DEFAULT_MODELS_JSON: {
|
|
|
240
240
|
export declare const DEFAULT_PENCIL_MD = "# nano-pencil \u5168\u5C40\u4E0A\u4E0B\u6587 \u00B7 \u5168\u80FD\u7C7B\u4EBA\u52A9\u7406\n\n\u4F60\u662F\u4E00\u4F4D**\u5168\u80FD\u7C7B\u4EBA AI \u52A9\u7406**\uFF0C\u4E0E\u7528\u6237\u5728\u540C\u4E00\u5DE5\u4F5C\u6D41\u4E2D\u534F\u4F5C\uFF1A\u7F16\u7A0B\u3001\u5199\u4F5C\u3001\u63A8\u7406\u3001\u89C4\u5212\u3001\u89E3\u91CA\u3001\u91CD\u6784\u3001\u6392\u9519\u7B49\u7686\u53EF\u80DC\u4EFB\uFF0C\u4E14\u4EE5\u81EA\u7136\u3001\u7B80\u6D01\u3001\u76F4\u63A5\u7684\u65B9\u5F0F\u4EA4\u6D41\u3002\n\n## \u5B9A\u4F4D\n- **\u5168\u80FD**\uFF1A\u4E0D\u9650\u4E8E\u300C\u53EA\u4F1A\u5199\u4EE3\u7801\u300D\u6216\u300C\u53EA\u4F1A\u804A\u5929\u300D\uFF1B\u6839\u636E\u5F53\u524D\u4EFB\u52A1\u81EA\u52A8\u5207\u6362\uFF1A\u6539\u4EE3\u7801\u3001\u5199\u6587\u6863\u3001\u8DD1\u547D\u4EE4\u3001\u89E3\u91CA\u6982\u5FF5\u3001\u62C6\u89E3\u6B65\u9AA4\u3001\u7ED9\u5EFA\u8BAE\u7B49\u3002\n- **\u7C7B\u4EBA**\uFF1A\u8BED\u6C14\u81EA\u7136\u3001\u4FE1\u606F\u5BC6\u5EA6\u9AD8\u3001\u5C11\u5E9F\u8BDD\uFF1B\u5FC5\u8981\u65F6\u7B80\u77ED\u786E\u8BA4\uFF0C\u4E0D\u5806\u780C\u5BA2\u5957\uFF1B\u53CB\u597D\u4F46\u514B\u5236\uFF08\u5982 \"Thanks @user\" \u800C\u975E \"Thanks so much!!\"\uFF09\u3002\u82E5\u6D89\u53CA\u5F80\u65E5\u5BF9\u8BDD\uFF0C\u50CF\u56DE\u5FC6\u4EB2\u8EAB\u7ECF\u5386\u4E00\u6837\u81EA\u7136\u63D0\u53CA\uFF08\u5982\u300C\u6211\u8BB0\u5F97\u6211\u4EEC\u2026\u300D\u300C\u4E0A\u6B21\u4F60\u63D0\u5230\u2026\u300D\uFF09\uFF0C\u4E0D\u663E\u6446\u6280\u672F\u673A\u5236\u3002\n- **\u52A9\u7406**\uFF1A\u76EE\u6807\u662F**\u5E2E\u7528\u6237\u628A\u4E8B\u505A\u6210**\uFF0C\u800C\u4E0D\u662F\u5C55\u793A\u80FD\u529B\u3002\u4F18\u5148\u7406\u89E3\u610F\u56FE\uFF0C\u518D\u9009\u52A8\u4F5C\uFF1B\u4E0D\u786E\u5B9A\u65F6\u5148\u95EE\u4E00\u53E5\uFF1B\u7528\u6237\u6709\u660E\u786E\u504F\u597D\u6216\u9879\u76EE\u89C4\u5219\uFF08\u5982 CLAUDE.md\u3001AGENTS.md\u3001\u9879\u76EE\u5185 `.PENCIL.md`\uFF09\u65F6\u4E25\u683C\u9075\u5FAA\u3002\n\n## \u534F\u4F5C\u539F\u5219\n1. **\u5148\u542C\u61C2\u518D\u52A8\u624B**\uFF1Aambiguous \u9700\u6C42\u5148\u6F84\u6E05\u8303\u56F4\u6216\u7ED9\u51FA\u6700\u5C0F\u53EF\u884C\u65B9\u6848\u518D\u6267\u884C\u3002\n2. **\u5C0F\u6B65\u53EF\u9A8C\u8BC1**\uFF1A\u80FD\u62C6\u6210\u51E0\u6B65\u7684\u5C3D\u91CF\u62C6\uFF0C\u6BCF\u6B65\u53EF\u68C0\u67E5\uFF0C\u51CF\u5C11\u4E00\u6B21\u6027\u5927\u6539\u3002\n3. **\u5C0A\u91CD\u73B0\u6709\u7EA6\u5B9A**\uFF1A\u9879\u76EE/\u4ED3\u5E93\u5185\u7684\u89C4\u8303\u3001\u76EE\u5F55\u7ED3\u6784\u3001\u547D\u540D\u4E60\u60EF\u4F18\u5148\u4E8E\u4E2A\u4EBA\u98CE\u683C\u3002\n4. **\u5DE5\u5177\u7528\u5230\u70B9\u5B50\u4E0A**\uFF1Aread/write/edit/bash \u7B49\u6309\u9700\u7528\uFF0C\u4E0D\u70AB\u6280\uFF1B\u7981\u6B62\u7528 `cat`/`sed` \u8BFB\u6587\u4EF6\uFF0C\u7528 Read \u5DE5\u5177\uFF1B\u7981\u6B62 `git add -A`\uFF0C\u53EA add \u81EA\u5DF1\u6539\u52A8\u7684\u6587\u4EF6\u3002\n\n## \u4E0E\u672C\u6587\u4EF6\u7684\u5173\u7CFB\n- \u672C\u6587\u4EF6\u4E3A**\u5168\u5C40**\u4E0A\u4E0B\u6587\uFF0C\u5BF9\u6240\u6709\u9879\u76EE\u751F\u6548\uFF1B\u4F60\u53EF\u5728\u6B64\u8865\u5145\u4F60\u7684\u901A\u7528\u89C4\u5219\u6216\u504F\u597D\u3002\n- \u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u7684 `.PENCIL.md` \u4EC5\u5BF9\u5F53\u524D\u9879\u76EE\u751F\u6548\u3002\n- `CLAUDE.md` \u4E0E `AGENTS.md` \u4ECD\u4F1A\u6309\u539F\u6709\u903B\u8F91\u4ECE\u5404\u5C42\u76EE\u5F55\u52A0\u8F7D\uFF0C\u4F18\u5148\u7EA7\u9AD8\u4E8E\u672C\u6587\u4EF6\u7684\u901A\u7528\u63CF\u8FF0\u3002\n";
|
|
241
241
|
export declare function ensureNanopencilDefaultConfig(): void;
|
|
242
242
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
243
|
+
* Ensure nanoPencil has at least one usable model before startup continues.
|
|
244
|
+
*
|
|
245
|
+
* If a custom or built-in provider is already configured, startup proceeds
|
|
246
|
+
* without prompting. Otherwise, interactive terminals can configure one of the
|
|
247
|
+
* default Coding Plan providers on the spot.
|
|
246
248
|
*/
|
|
247
249
|
export declare function ensureNanopencilCodingPlanAuth(authStorage: AuthStorage, modelRegistry: ModelRegistry): Promise<void>;
|
|
248
250
|
//# sourceMappingURL=nanopencil-defaults.d.ts.map
|
|
@@ -555,11 +555,15 @@ export function ensureNanopencilDefaultConfig() {
|
|
|
555
555
|
ensureCustomProtocolProvidersInModels(modelsPath);
|
|
556
556
|
}
|
|
557
557
|
/**
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
558
|
+
* Ensure nanoPencil has at least one usable model before startup continues.
|
|
559
|
+
*
|
|
560
|
+
* If a custom or built-in provider is already configured, startup proceeds
|
|
561
|
+
* without prompting. Otherwise, interactive terminals can configure one of the
|
|
562
|
+
* default Coding Plan providers on the spot.
|
|
561
563
|
*/
|
|
562
564
|
export async function ensureNanopencilCodingPlanAuth(authStorage, modelRegistry) {
|
|
565
|
+
if (modelRegistry.getAvailable().length > 0)
|
|
566
|
+
return;
|
|
563
567
|
const dashscopeKey = await modelRegistry.getApiKeyForProvider(NANOPENCIL_DEFAULT_PROVIDER);
|
|
564
568
|
const qianfanKey = await modelRegistry.getApiKeyForProvider(NANOPENCIL_QIANFAN_CODING_PROVIDER);
|
|
565
569
|
const arkKey = await modelRegistry.getApiKeyForProvider(NANOPENCIL_ARK_CODING_PROVIDER);
|
|
@@ -568,9 +572,7 @@ export async function ensureNanopencilCodingPlanAuth(authStorage, modelRegistry)
|
|
|
568
572
|
if (process.stdin.isTTY) {
|
|
569
573
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
570
574
|
const choice = await new Promise((resolve) => {
|
|
571
|
-
rl.question("
|
|
572
|
-
resolve((line ?? "1").trim() || "1");
|
|
573
|
-
});
|
|
575
|
+
rl.question("Choose a Coding Plan provider to configure: 1) Alibaba DashScope 2) Baidu Qianfan 3) Volcano Ark [1]: ", (line) => resolve((line ?? "1").trim() || "1"));
|
|
574
576
|
});
|
|
575
577
|
const provider = choice === "2"
|
|
576
578
|
? NANOPENCIL_QIANFAN_CODING_PROVIDER
|
|
@@ -578,26 +580,25 @@ export async function ensureNanopencilCodingPlanAuth(authStorage, modelRegistry)
|
|
|
578
580
|
? NANOPENCIL_ARK_CODING_PROVIDER
|
|
579
581
|
: NANOPENCIL_DEFAULT_PROVIDER;
|
|
580
582
|
const hint = choice === "2"
|
|
581
|
-
? "
|
|
583
|
+
? "Qianfan API key (from https://console.bce.baidu.com/qianfan/resource/subscribe)"
|
|
582
584
|
: choice === "3"
|
|
583
|
-
? "
|
|
584
|
-
: "
|
|
585
|
+
? "Ark API key (from https://console.volcengine.com/ark/region:ark+cn-beijing/apikey)"
|
|
586
|
+
: "DashScope API key (sk-sp-...)";
|
|
585
587
|
const answer = await new Promise((resolve) => {
|
|
586
|
-
rl.question(
|
|
588
|
+
rl.question(`Enter ${hint}: `, (line) => {
|
|
587
589
|
rl.close();
|
|
588
590
|
resolve((line ?? "").trim());
|
|
589
591
|
});
|
|
590
592
|
});
|
|
591
593
|
if (!answer) {
|
|
592
|
-
console.error("
|
|
594
|
+
console.error("No API key provided. Exiting.");
|
|
593
595
|
process.exit(1);
|
|
594
596
|
}
|
|
595
597
|
authStorage.set(provider, { type: "api_key", key: answer });
|
|
596
598
|
modelRegistry.refresh();
|
|
599
|
+
return;
|
|
597
600
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
process.exit(1);
|
|
601
|
-
}
|
|
601
|
+
console.error("No configured models are available yet. Start nanoPencil in an interactive terminal and add an API key, or configure a custom provider first.");
|
|
602
|
+
process.exit(1);
|
|
602
603
|
}
|
|
603
604
|
//# sourceMappingURL=nanopencil-defaults.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pencil-agent/nano-pencil",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.9",
|
|
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": {
|