@pencil-agent/nano-pencil 0.0.4 → 0.0.5

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.

Potentially problematic release.


This version of @pencil-agent/nano-pencil might be problematic. Click here for more details.

@@ -2,11 +2,12 @@
2
2
  * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。
3
3
  * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),
4
4
  * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。
5
+ * 若 models.json 已存在,会合并默认模型(补充缺失模型并更新 contextWindow/maxTokens 与官方一致)。
5
6
  */
6
7
  import type { AuthStorage } from "./core/auth-storage.js";
7
8
  import type { ModelRegistry } from "./core/model-registry.js";
8
9
  export declare const NANOPENCIL_DEFAULT_PROVIDER = "dashscope-coding";
9
- /** 默认 models.json 内容:仅百炼 Coding Plan,不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */
10
+ /** 默认 models.json 内容:dashscope-coding 支持的模型(百炼 Coding Plan),不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */
10
11
  export declare const NANOPENCIL_DEFAULT_MODELS_JSON: {
11
12
  readonly providers: {
12
13
  readonly "dashscope-coding": {
@@ -36,12 +37,37 @@ export declare const NANOPENCIL_DEFAULT_MODELS_JSON: {
36
37
  readonly input: readonly ["text"];
37
38
  readonly contextWindow: 1000000;
38
39
  readonly maxTokens: 65536;
40
+ }, {
41
+ readonly id: "MiniMax-M2.5";
42
+ readonly name: "MiniMax-M2.5";
43
+ readonly input: readonly ["text"];
44
+ readonly contextWindow: 1000000;
45
+ readonly maxTokens: 65536;
46
+ }, {
47
+ readonly id: "glm-5";
48
+ readonly name: "GLM-5";
49
+ readonly input: readonly ["text"];
50
+ readonly contextWindow: 202752;
51
+ readonly maxTokens: 16384;
52
+ }, {
53
+ readonly id: "glm-4.7";
54
+ readonly name: "GLM-4.7";
55
+ readonly input: readonly ["text"];
56
+ readonly contextWindow: 202752;
57
+ readonly maxTokens: 16384;
58
+ }, {
59
+ readonly id: "kimi-k2.5";
60
+ readonly name: "Kimi K2.5";
61
+ readonly input: readonly ["text", "image"];
62
+ readonly contextWindow: 262144;
63
+ readonly maxTokens: 32768;
39
64
  }];
40
65
  };
41
66
  };
42
67
  };
43
68
  /**
44
- * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan)。
69
+ * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan);
70
+ * 若已存在则合并默认模型(补充 qwen3.5-plus 等并更新 contextWindow/maxTokens)。
45
71
  * 仅在以 nanopencil 运行时调用。
46
72
  */
47
73
  export declare function ensureNanopencilDefaultConfig(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"nanopencil-defaults.d.ts","sourceRoot":"","sources":["../src/nanopencil-defaults.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,eAAO,MAAM,2BAA2B,qBAAqB,CAAC;AAG9D,6JAAqG;AACrG,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCjC,CAAC;AAEX;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CASpD;AAED;;;GAGG;AACH,wBAAsB,8BAA8B,CACnD,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,GAC1B,OAAO,CAAC,IAAI,CAAC,CAsBf","sourcesContent":["/**\n * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。\n * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),\n * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { getAgentDir, getModelsPath } from \"./config.js\";\nimport type { AuthStorage } from \"./core/auth-storage.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\n\nexport const NANOPENCIL_DEFAULT_PROVIDER = \"dashscope-coding\";\nconst CODING_PLAN_BASE_URL = \"https://coding.dashscope.aliyuncs.com/v1\";\n\n/** 默认 models.json 内容:仅百炼 Coding Plan,不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */\nexport const NANOPENCIL_DEFAULT_MODELS_JSON = {\n\tproviders: {\n\t\t[NANOPENCIL_DEFAULT_PROVIDER]: {\n\t\t\tbaseUrl: CODING_PLAN_BASE_URL,\n\t\t\tapi: \"openai-completions\",\n\t\t\tmodels: [\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3.5-plus\",\n\t\t\t\t\tname: \"Qwen3.5 Plus\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-max-2026-01-23\",\n\t\t\t\t\tname: \"Qwen3 Max\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-next\",\n\t\t\t\t\tname: \"Qwen3 Coder Next\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-plus\",\n\t\t\t\t\tname: \"Qwen3 Coder Plus\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n} as const;\n\n/**\n * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan)。\n * 仅在以 nanopencil 运行时调用。\n */\nexport function ensureNanopencilDefaultConfig(): void {\n\tconst agentDir = getAgentDir();\n\tif (!existsSync(agentDir)) {\n\t\tmkdirSync(agentDir, { recursive: true, mode: 0o700 });\n\t}\n\tconst modelsPath = getModelsPath();\n\tif (!existsSync(modelsPath)) {\n\t\twriteFileSync(modelsPath, JSON.stringify(NANOPENCIL_DEFAULT_MODELS_JSON, null, 2), \"utf-8\");\n\t}\n}\n\n/**\n * 若未配置百炼 Coding Plan API Key:在 TTY 下提示输入并写入 auth.json 后刷新 registry;非 TTY 下报错退出。\n * 仅在以 nanopencil 运行时、在创建 ModelRegistry 之后调用。\n */\nexport async function ensureNanopencilCodingPlanAuth(\n\tauthStorage: AuthStorage,\n\tmodelRegistry: ModelRegistry,\n): Promise<void> {\n\tconst key = await modelRegistry.getApiKeyForProvider(NANOPENCIL_DEFAULT_PROVIDER);\n\tif (key) return;\n\n\tif (process.stdin.isTTY) {\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\tconst answer = await new Promise<string>((resolve) => {\n\t\t\trl.question(\"请输入百炼 Coding Plan API Key (sk-sp-...): \", (line) => {\n\t\t\t\trl.close();\n\t\t\t\tresolve((line ?? \"\").trim());\n\t\t\t});\n\t\t});\n\t\tif (!answer) {\n\t\t\tconsole.error(\"未输入 API Key,已退出。\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.set(NANOPENCIL_DEFAULT_PROVIDER, { type: \"api_key\", key: answer });\n\t\tmodelRegistry.refresh();\n\t} else {\n\t\tconsole.error(\"未配置百炼 Coding Plan API Key。请先交互运行 nanopencil 并按要求输入 API Key。\");\n\t\tprocess.exit(1);\n\t}\n}\n"]}
1
+ {"version":3,"file":"nanopencil-defaults.d.ts","sourceRoot":"","sources":["../src/nanopencil-defaults.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,eAAO,MAAM,2BAA2B,qBAAqB,CAAC;AAM9D,gMAA4H;AAC5H,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiEjC,CAAC;AA6EX;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CAWpD;AAED;;;GAGG;AACH,wBAAsB,8BAA8B,CACnD,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,GAC1B,OAAO,CAAC,IAAI,CAAC,CAsBf","sourcesContent":["/**\n * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。\n * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),\n * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。\n * 若 models.json 已存在,会合并默认模型(补充缺失模型并更新 contextWindow/maxTokens 与官方一致)。\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { getAgentDir, getModelsPath } from \"./config.js\";\nimport type { AuthStorage } from \"./core/auth-storage.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\n\nexport const NANOPENCIL_DEFAULT_PROVIDER = \"dashscope-coding\";\nconst CODING_PLAN_BASE_URL = \"https://coding.dashscope.aliyuncs.com/v1\";\n\ntype DefaultModelDef =\n\t(typeof NANOPENCIL_DEFAULT_MODELS_JSON.providers)[typeof NANOPENCIL_DEFAULT_PROVIDER][\"models\"][number];\n\n/** 默认 models.json 内容:dashscope-coding 支持的模型(百炼 Coding Plan),不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */\nexport const NANOPENCIL_DEFAULT_MODELS_JSON = {\n\tproviders: {\n\t\t[NANOPENCIL_DEFAULT_PROVIDER]: {\n\t\t\tbaseUrl: CODING_PLAN_BASE_URL,\n\t\t\tapi: \"openai-completions\",\n\t\t\tmodels: [\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3.5-plus\",\n\t\t\t\t\tname: \"Qwen3.5 Plus\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-max-2026-01-23\",\n\t\t\t\t\tname: \"Qwen3 Max\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-next\",\n\t\t\t\t\tname: \"Qwen3 Coder Next\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-plus\",\n\t\t\t\t\tname: \"Qwen3 Coder Plus\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"MiniMax-M2.5\",\n\t\t\t\t\tname: \"MiniMax-M2.5\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"glm-5\",\n\t\t\t\t\tname: \"GLM-5\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 202752,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"glm-4.7\",\n\t\t\t\t\tname: \"GLM-4.7\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 202752,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"kimi-k2.5\",\n\t\t\t\t\tname: \"Kimi K2.5\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 32768,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n} as const;\n\nconst DEFAULT_MODELS: DefaultModelDef[] = [\n\t...NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER].models,\n];\n\n/**\n * 若 models.json 已存在,合并默认模型:补充缺失模型,并将已知模型的 contextWindow/maxTokens/input 更新为官方值。\n */\nfunction mergeNanopencilModelsIfNeeded(modelsPath: string): void {\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(modelsPath, \"utf-8\");\n\t} catch {\n\t\treturn;\n\t}\n\tlet data: { providers?: Record<string, { baseUrl?: string; api?: string; models?: unknown[] }> };\n\ttry {\n\t\tdata = JSON.parse(raw);\n\t} catch {\n\t\treturn;\n\t}\n\tif (!data.providers) data.providers = {};\n\tconst provider = data.providers[NANOPENCIL_DEFAULT_PROVIDER];\n\tconst providerConfig = NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER];\n\n\tif (!provider) {\n\t\tdata.providers[NANOPENCIL_DEFAULT_PROVIDER] = {\n\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\tapi: providerConfig.api,\n\t\t\tmodels: DEFAULT_MODELS.map((m) => ({ ...m })),\n\t\t};\n\t\twriteFileSync(modelsPath, JSON.stringify(data, null, 2), \"utf-8\");\n\t\treturn;\n\t}\n\n\tconst models = (Array.isArray(provider.models) ? [...provider.models] : []) as Record<string, unknown>[];\n\tconst byId = new Map<string, Record<string, unknown>>();\n\tfor (const m of models) {\n\t\tconst id = m?.id;\n\t\tif (typeof id === \"string\") byId.set(id, m);\n\t}\n\n\tlet changed = false;\n\tfor (const def of DEFAULT_MODELS) {\n\t\tconst id = def.id;\n\t\tconst existing = byId.get(id);\n\t\tif (!existing) {\n\t\t\tmodels.push({ ...def });\n\t\t\tbyId.set(id, models[models.length - 1]);\n\t\t\tchanged = true;\n\t\t} else {\n\t\t\tif (existing.contextWindow !== def.contextWindow) {\n\t\t\t\texisting.contextWindow = def.contextWindow;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (existing.maxTokens !== def.maxTokens) {\n\t\t\t\texisting.maxTokens = def.maxTokens;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (JSON.stringify(existing.input) !== JSON.stringify(def.input)) {\n\t\t\t\texisting.input = def.input;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (existing.name !== def.name) {\n\t\t\t\texisting.name = def.name;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (changed) {\n\t\t(data.providers[NANOPENCIL_DEFAULT_PROVIDER] as { models: unknown[] }).models = models;\n\t\twriteFileSync(modelsPath, JSON.stringify(data, null, 2), \"utf-8\");\n\t}\n}\n\n/**\n * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan);\n * 若已存在则合并默认模型(补充 qwen3.5-plus 等并更新 contextWindow/maxTokens)。\n * 仅在以 nanopencil 运行时调用。\n */\nexport function ensureNanopencilDefaultConfig(): void {\n\tconst agentDir = getAgentDir();\n\tif (!existsSync(agentDir)) {\n\t\tmkdirSync(agentDir, { recursive: true, mode: 0o700 });\n\t}\n\tconst modelsPath = getModelsPath();\n\tif (!existsSync(modelsPath)) {\n\t\twriteFileSync(modelsPath, JSON.stringify(NANOPENCIL_DEFAULT_MODELS_JSON, null, 2), \"utf-8\");\n\t\treturn;\n\t}\n\tmergeNanopencilModelsIfNeeded(modelsPath);\n}\n\n/**\n * 若未配置百炼 Coding Plan API Key:在 TTY 下提示输入并写入 auth.json 后刷新 registry;非 TTY 下报错退出。\n * 仅在以 nanopencil 运行时、在创建 ModelRegistry 之后调用。\n */\nexport async function ensureNanopencilCodingPlanAuth(\n\tauthStorage: AuthStorage,\n\tmodelRegistry: ModelRegistry,\n): Promise<void> {\n\tconst key = await modelRegistry.getApiKeyForProvider(NANOPENCIL_DEFAULT_PROVIDER);\n\tif (key) return;\n\n\tif (process.stdin.isTTY) {\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\tconst answer = await new Promise<string>((resolve) => {\n\t\t\trl.question(\"请输入百炼 Coding Plan API Key (sk-sp-...): \", (line) => {\n\t\t\t\trl.close();\n\t\t\t\tresolve((line ?? \"\").trim());\n\t\t\t});\n\t\t});\n\t\tif (!answer) {\n\t\t\tconsole.error(\"未输入 API Key,已退出。\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.set(NANOPENCIL_DEFAULT_PROVIDER, { type: \"api_key\", key: answer });\n\t\tmodelRegistry.refresh();\n\t} else {\n\t\tconsole.error(\"未配置百炼 Coding Plan API Key。请先交互运行 nanopencil 并按要求输入 API Key。\");\n\t\tprocess.exit(1);\n\t}\n}\n"]}
@@ -2,13 +2,14 @@
2
2
  * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。
3
3
  * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),
4
4
  * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。
5
+ * 若 models.json 已存在,会合并默认模型(补充缺失模型并更新 contextWindow/maxTokens 与官方一致)。
5
6
  */
6
- import { existsSync, mkdirSync, writeFileSync } from "fs";
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
7
8
  import { createInterface } from "readline";
8
9
  import { getAgentDir, getModelsPath } from "./config.js";
9
10
  export const NANOPENCIL_DEFAULT_PROVIDER = "dashscope-coding";
10
11
  const CODING_PLAN_BASE_URL = "https://coding.dashscope.aliyuncs.com/v1";
11
- /** 默认 models.json 内容:仅百炼 Coding Plan,不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */
12
+ /** 默认 models.json 内容:dashscope-coding 支持的模型(百炼 Coding Plan),不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */
12
13
  export const NANOPENCIL_DEFAULT_MODELS_JSON = {
13
14
  providers: {
14
15
  [NANOPENCIL_DEFAULT_PROVIDER]: {
@@ -43,12 +44,115 @@ export const NANOPENCIL_DEFAULT_MODELS_JSON = {
43
44
  contextWindow: 1000000,
44
45
  maxTokens: 65536,
45
46
  },
47
+ {
48
+ id: "MiniMax-M2.5",
49
+ name: "MiniMax-M2.5",
50
+ input: ["text"],
51
+ contextWindow: 1000000,
52
+ maxTokens: 65536,
53
+ },
54
+ {
55
+ id: "glm-5",
56
+ name: "GLM-5",
57
+ input: ["text"],
58
+ contextWindow: 202752,
59
+ maxTokens: 16384,
60
+ },
61
+ {
62
+ id: "glm-4.7",
63
+ name: "GLM-4.7",
64
+ input: ["text"],
65
+ contextWindow: 202752,
66
+ maxTokens: 16384,
67
+ },
68
+ {
69
+ id: "kimi-k2.5",
70
+ name: "Kimi K2.5",
71
+ input: ["text", "image"],
72
+ contextWindow: 262144,
73
+ maxTokens: 32768,
74
+ },
46
75
  ],
47
76
  },
48
77
  },
49
78
  };
79
+ const DEFAULT_MODELS = [
80
+ ...NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER].models,
81
+ ];
82
+ /**
83
+ * 若 models.json 已存在,合并默认模型:补充缺失模型,并将已知模型的 contextWindow/maxTokens/input 更新为官方值。
84
+ */
85
+ function mergeNanopencilModelsIfNeeded(modelsPath) {
86
+ let raw;
87
+ try {
88
+ raw = readFileSync(modelsPath, "utf-8");
89
+ }
90
+ catch {
91
+ return;
92
+ }
93
+ let data;
94
+ try {
95
+ data = JSON.parse(raw);
96
+ }
97
+ catch {
98
+ return;
99
+ }
100
+ if (!data.providers)
101
+ data.providers = {};
102
+ const provider = data.providers[NANOPENCIL_DEFAULT_PROVIDER];
103
+ const providerConfig = NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER];
104
+ if (!provider) {
105
+ data.providers[NANOPENCIL_DEFAULT_PROVIDER] = {
106
+ baseUrl: providerConfig.baseUrl,
107
+ api: providerConfig.api,
108
+ models: DEFAULT_MODELS.map((m) => ({ ...m })),
109
+ };
110
+ writeFileSync(modelsPath, JSON.stringify(data, null, 2), "utf-8");
111
+ return;
112
+ }
113
+ const models = (Array.isArray(provider.models) ? [...provider.models] : []);
114
+ const byId = new Map();
115
+ for (const m of models) {
116
+ const id = m?.id;
117
+ if (typeof id === "string")
118
+ byId.set(id, m);
119
+ }
120
+ let changed = false;
121
+ for (const def of DEFAULT_MODELS) {
122
+ const id = def.id;
123
+ const existing = byId.get(id);
124
+ if (!existing) {
125
+ models.push({ ...def });
126
+ byId.set(id, models[models.length - 1]);
127
+ changed = true;
128
+ }
129
+ else {
130
+ if (existing.contextWindow !== def.contextWindow) {
131
+ existing.contextWindow = def.contextWindow;
132
+ changed = true;
133
+ }
134
+ if (existing.maxTokens !== def.maxTokens) {
135
+ existing.maxTokens = def.maxTokens;
136
+ changed = true;
137
+ }
138
+ if (JSON.stringify(existing.input) !== JSON.stringify(def.input)) {
139
+ existing.input = def.input;
140
+ changed = true;
141
+ }
142
+ if (existing.name !== def.name) {
143
+ existing.name = def.name;
144
+ changed = true;
145
+ }
146
+ }
147
+ }
148
+ if (changed) {
149
+ data.providers[NANOPENCIL_DEFAULT_PROVIDER].models = models;
150
+ writeFileSync(modelsPath, JSON.stringify(data, null, 2), "utf-8");
151
+ }
152
+ }
50
153
  /**
51
- * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan)。
154
+ * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan);
155
+ * 若已存在则合并默认模型(补充 qwen3.5-plus 等并更新 contextWindow/maxTokens)。
52
156
  * 仅在以 nanopencil 运行时调用。
53
157
  */
54
158
  export function ensureNanopencilDefaultConfig() {
@@ -59,7 +163,9 @@ export function ensureNanopencilDefaultConfig() {
59
163
  const modelsPath = getModelsPath();
60
164
  if (!existsSync(modelsPath)) {
61
165
  writeFileSync(modelsPath, JSON.stringify(NANOPENCIL_DEFAULT_MODELS_JSON, null, 2), "utf-8");
166
+ return;
62
167
  }
168
+ mergeNanopencilModelsIfNeeded(modelsPath);
63
169
  }
64
170
  /**
65
171
  * 若未配置百炼 Coding Plan API Key:在 TTY 下提示输入并写入 auth.json 后刷新 registry;非 TTY 下报错退出。
@@ -1 +1 @@
1
- {"version":3,"file":"nanopencil-defaults.js","sourceRoot":"","sources":["../src/nanopencil-defaults.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。\n * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),\n * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { getAgentDir, getModelsPath } from \"./config.js\";\nimport type { AuthStorage } from \"./core/auth-storage.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\n\nexport const NANOPENCIL_DEFAULT_PROVIDER = \"dashscope-coding\";\nconst CODING_PLAN_BASE_URL = \"https://coding.dashscope.aliyuncs.com/v1\";\n\n/** 默认 models.json 内容:仅百炼 Coding Plan,不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */\nexport const NANOPENCIL_DEFAULT_MODELS_JSON = {\n\tproviders: {\n\t\t[NANOPENCIL_DEFAULT_PROVIDER]: {\n\t\t\tbaseUrl: CODING_PLAN_BASE_URL,\n\t\t\tapi: \"openai-completions\",\n\t\t\tmodels: [\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3.5-plus\",\n\t\t\t\t\tname: \"Qwen3.5 Plus\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-max-2026-01-23\",\n\t\t\t\t\tname: \"Qwen3 Max\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-next\",\n\t\t\t\t\tname: \"Qwen3 Coder Next\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-plus\",\n\t\t\t\t\tname: \"Qwen3 Coder Plus\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n} as const;\n\n/**\n * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan)。\n * 仅在以 nanopencil 运行时调用。\n */\nexport function ensureNanopencilDefaultConfig(): void {\n\tconst agentDir = getAgentDir();\n\tif (!existsSync(agentDir)) {\n\t\tmkdirSync(agentDir, { recursive: true, mode: 0o700 });\n\t}\n\tconst modelsPath = getModelsPath();\n\tif (!existsSync(modelsPath)) {\n\t\twriteFileSync(modelsPath, JSON.stringify(NANOPENCIL_DEFAULT_MODELS_JSON, null, 2), \"utf-8\");\n\t}\n}\n\n/**\n * 若未配置百炼 Coding Plan API Key:在 TTY 下提示输入并写入 auth.json 后刷新 registry;非 TTY 下报错退出。\n * 仅在以 nanopencil 运行时、在创建 ModelRegistry 之后调用。\n */\nexport async function ensureNanopencilCodingPlanAuth(\n\tauthStorage: AuthStorage,\n\tmodelRegistry: ModelRegistry,\n): Promise<void> {\n\tconst key = await modelRegistry.getApiKeyForProvider(NANOPENCIL_DEFAULT_PROVIDER);\n\tif (key) return;\n\n\tif (process.stdin.isTTY) {\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\tconst answer = await new Promise<string>((resolve) => {\n\t\t\trl.question(\"请输入百炼 Coding Plan API Key (sk-sp-...): \", (line) => {\n\t\t\t\trl.close();\n\t\t\t\tresolve((line ?? \"\").trim());\n\t\t\t});\n\t\t});\n\t\tif (!answer) {\n\t\t\tconsole.error(\"未输入 API Key,已退出。\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.set(NANOPENCIL_DEFAULT_PROVIDER, { type: \"api_key\", key: answer });\n\t\tmodelRegistry.refresh();\n\t} else {\n\t\tconsole.error(\"未配置百炼 Coding Plan API Key。请先交互运行 nanopencil 并按要求输入 API Key。\");\n\t\tprocess.exit(1);\n\t}\n}\n"]}
1
+ {"version":3,"file":"nanopencil-defaults.js","sourceRoot":"","sources":["../src/nanopencil-defaults.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * NanoPencil 默认配置:仅支持阿里云百炼 Coding Plan。\n * 首次运行会确保 ~/.nanopencil/agent/ 下存在默认 models.json(无 apiKey),\n * 由 main 在交互模式下提示用户输入 API Key 并写入 auth.json。\n * 若 models.json 已存在,会合并默认模型(补充缺失模型并更新 contextWindow/maxTokens 与官方一致)。\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { createInterface } from \"readline\";\nimport { getAgentDir, getModelsPath } from \"./config.js\";\nimport type { AuthStorage } from \"./core/auth-storage.js\";\nimport type { ModelRegistry } from \"./core/model-registry.js\";\n\nexport const NANOPENCIL_DEFAULT_PROVIDER = \"dashscope-coding\";\nconst CODING_PLAN_BASE_URL = \"https://coding.dashscope.aliyuncs.com/v1\";\n\ntype DefaultModelDef =\n\t(typeof NANOPENCIL_DEFAULT_MODELS_JSON.providers)[typeof NANOPENCIL_DEFAULT_PROVIDER][\"models\"][number];\n\n/** 默认 models.json 内容:dashscope-coding 支持的模型(百炼 Coding Plan),不包含 apiKey(由用户输入后存 auth.json)。contextWindow/maxTokens 与官方一致。 */\nexport const NANOPENCIL_DEFAULT_MODELS_JSON = {\n\tproviders: {\n\t\t[NANOPENCIL_DEFAULT_PROVIDER]: {\n\t\t\tbaseUrl: CODING_PLAN_BASE_URL,\n\t\t\tapi: \"openai-completions\",\n\t\t\tmodels: [\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3.5-plus\",\n\t\t\t\t\tname: \"Qwen3.5 Plus\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-max-2026-01-23\",\n\t\t\t\t\tname: \"Qwen3 Max\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-next\",\n\t\t\t\t\tname: \"Qwen3 Coder Next\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"qwen3-coder-plus\",\n\t\t\t\t\tname: \"Qwen3 Coder Plus\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"MiniMax-M2.5\",\n\t\t\t\t\tname: \"MiniMax-M2.5\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 1000000,\n\t\t\t\t\tmaxTokens: 65536,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"glm-5\",\n\t\t\t\t\tname: \"GLM-5\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 202752,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"glm-4.7\",\n\t\t\t\t\tname: \"GLM-4.7\",\n\t\t\t\t\tinput: [\"text\"],\n\t\t\t\t\tcontextWindow: 202752,\n\t\t\t\t\tmaxTokens: 16384,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: \"kimi-k2.5\",\n\t\t\t\t\tname: \"Kimi K2.5\",\n\t\t\t\t\tinput: [\"text\", \"image\"],\n\t\t\t\t\tcontextWindow: 262144,\n\t\t\t\t\tmaxTokens: 32768,\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n} as const;\n\nconst DEFAULT_MODELS: DefaultModelDef[] = [\n\t...NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER].models,\n];\n\n/**\n * 若 models.json 已存在,合并默认模型:补充缺失模型,并将已知模型的 contextWindow/maxTokens/input 更新为官方值。\n */\nfunction mergeNanopencilModelsIfNeeded(modelsPath: string): void {\n\tlet raw: string;\n\ttry {\n\t\traw = readFileSync(modelsPath, \"utf-8\");\n\t} catch {\n\t\treturn;\n\t}\n\tlet data: { providers?: Record<string, { baseUrl?: string; api?: string; models?: unknown[] }> };\n\ttry {\n\t\tdata = JSON.parse(raw);\n\t} catch {\n\t\treturn;\n\t}\n\tif (!data.providers) data.providers = {};\n\tconst provider = data.providers[NANOPENCIL_DEFAULT_PROVIDER];\n\tconst providerConfig = NANOPENCIL_DEFAULT_MODELS_JSON.providers[NANOPENCIL_DEFAULT_PROVIDER];\n\n\tif (!provider) {\n\t\tdata.providers[NANOPENCIL_DEFAULT_PROVIDER] = {\n\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\tapi: providerConfig.api,\n\t\t\tmodels: DEFAULT_MODELS.map((m) => ({ ...m })),\n\t\t};\n\t\twriteFileSync(modelsPath, JSON.stringify(data, null, 2), \"utf-8\");\n\t\treturn;\n\t}\n\n\tconst models = (Array.isArray(provider.models) ? [...provider.models] : []) as Record<string, unknown>[];\n\tconst byId = new Map<string, Record<string, unknown>>();\n\tfor (const m of models) {\n\t\tconst id = m?.id;\n\t\tif (typeof id === \"string\") byId.set(id, m);\n\t}\n\n\tlet changed = false;\n\tfor (const def of DEFAULT_MODELS) {\n\t\tconst id = def.id;\n\t\tconst existing = byId.get(id);\n\t\tif (!existing) {\n\t\t\tmodels.push({ ...def });\n\t\t\tbyId.set(id, models[models.length - 1]);\n\t\t\tchanged = true;\n\t\t} else {\n\t\t\tif (existing.contextWindow !== def.contextWindow) {\n\t\t\t\texisting.contextWindow = def.contextWindow;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (existing.maxTokens !== def.maxTokens) {\n\t\t\t\texisting.maxTokens = def.maxTokens;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (JSON.stringify(existing.input) !== JSON.stringify(def.input)) {\n\t\t\t\texisting.input = def.input;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tif (existing.name !== def.name) {\n\t\t\t\texisting.name = def.name;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (changed) {\n\t\t(data.providers[NANOPENCIL_DEFAULT_PROVIDER] as { models: unknown[] }).models = models;\n\t\twriteFileSync(modelsPath, JSON.stringify(data, null, 2), \"utf-8\");\n\t}\n}\n\n/**\n * 确保 NanoPencil 默认配置存在:创建 agent 目录,若 models.json 不存在则写入默认(仅 Coding Plan);\n * 若已存在则合并默认模型(补充 qwen3.5-plus 等并更新 contextWindow/maxTokens)。\n * 仅在以 nanopencil 运行时调用。\n */\nexport function ensureNanopencilDefaultConfig(): void {\n\tconst agentDir = getAgentDir();\n\tif (!existsSync(agentDir)) {\n\t\tmkdirSync(agentDir, { recursive: true, mode: 0o700 });\n\t}\n\tconst modelsPath = getModelsPath();\n\tif (!existsSync(modelsPath)) {\n\t\twriteFileSync(modelsPath, JSON.stringify(NANOPENCIL_DEFAULT_MODELS_JSON, null, 2), \"utf-8\");\n\t\treturn;\n\t}\n\tmergeNanopencilModelsIfNeeded(modelsPath);\n}\n\n/**\n * 若未配置百炼 Coding Plan API Key:在 TTY 下提示输入并写入 auth.json 后刷新 registry;非 TTY 下报错退出。\n * 仅在以 nanopencil 运行时、在创建 ModelRegistry 之后调用。\n */\nexport async function ensureNanopencilCodingPlanAuth(\n\tauthStorage: AuthStorage,\n\tmodelRegistry: ModelRegistry,\n): Promise<void> {\n\tconst key = await modelRegistry.getApiKeyForProvider(NANOPENCIL_DEFAULT_PROVIDER);\n\tif (key) return;\n\n\tif (process.stdin.isTTY) {\n\t\tconst rl = createInterface({ input: process.stdin, output: process.stdout });\n\t\tconst answer = await new Promise<string>((resolve) => {\n\t\t\trl.question(\"请输入百炼 Coding Plan API Key (sk-sp-...): \", (line) => {\n\t\t\t\trl.close();\n\t\t\t\tresolve((line ?? \"\").trim());\n\t\t\t});\n\t\t});\n\t\tif (!answer) {\n\t\t\tconsole.error(\"未输入 API Key,已退出。\");\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tauthStorage.set(NANOPENCIL_DEFAULT_PROVIDER, { type: \"api_key\", key: answer });\n\t\tmodelRegistry.refresh();\n\t} else {\n\t\tconsole.error(\"未配置百炼 Coding Plan API Key。请先交互运行 nanopencil 并按要求输入 API Key。\");\n\t\tprocess.exit(1);\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pencil-agent/nano-pencil",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "CLI writing agent with read, bash, edit, write tools and session management. Based on pi; supports DashScope Coding Plan.",
5
5
  "type": "module",
6
6
  "piConfig": {