@pencil-agent/nano-pencil 1.10.3 → 1.10.4

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.
Files changed (197) hide show
  1. package/dist/cli/args.d.ts +2 -0
  2. package/dist/cli/args.js +4 -0
  3. package/dist/core/mcp/mcp-client.js +25 -4
  4. package/dist/core/mcp/mcp-config.js +4 -3
  5. package/dist/core/sdk.js +21 -6
  6. package/dist/core/settings-manager.d.ts +3 -0
  7. package/dist/core/settings-manager.js +11 -0
  8. package/dist/core/slash-commands.js +1 -0
  9. package/dist/main.js +2 -2
  10. package/dist/modes/interactive/components/footer.d.ts +3 -1
  11. package/dist/modes/interactive/components/footer.js +26 -16
  12. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  13. package/dist/modes/interactive/components/settings-selector.js +10 -0
  14. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  15. package/dist/modes/interactive/interactive-mode.js +107 -1
  16. package/node_modules/@types/node/README.md +3 -3
  17. package/node_modules/@types/node/assert/strict.d.ts +101 -4
  18. package/node_modules/@types/node/assert.d.ts +141 -248
  19. package/node_modules/@types/node/async_hooks.d.ts +30 -12
  20. package/node_modules/@types/node/buffer.buffer.d.ts +3 -8
  21. package/node_modules/@types/node/buffer.d.ts +44 -170
  22. package/node_modules/@types/node/child_process.d.ts +31 -78
  23. package/node_modules/@types/node/cluster.d.ts +241 -332
  24. package/node_modules/@types/node/console.d.ts +49 -350
  25. package/node_modules/@types/node/constants.d.ts +3 -4
  26. package/node_modules/@types/node/crypto.d.ts +683 -1208
  27. package/node_modules/@types/node/dgram.d.ts +18 -51
  28. package/node_modules/@types/node/diagnostics_channel.d.ts +4 -6
  29. package/node_modules/@types/node/dns/promises.d.ts +33 -9
  30. package/node_modules/@types/node/dns.d.ts +179 -128
  31. package/node_modules/@types/node/domain.d.ts +13 -17
  32. package/node_modules/@types/node/events.d.ts +869 -792
  33. package/node_modules/@types/node/fs/promises.d.ts +105 -46
  34. package/node_modules/@types/node/fs.d.ts +734 -433
  35. package/node_modules/@types/node/globals.d.ts +8 -30
  36. package/node_modules/@types/node/globals.typedarray.d.ts +63 -0
  37. package/node_modules/@types/node/http.d.ts +385 -267
  38. package/node_modules/@types/node/http2.d.ts +565 -716
  39. package/node_modules/@types/node/https.d.ts +68 -241
  40. package/node_modules/@types/node/index.d.ts +28 -6
  41. package/node_modules/@types/node/inspector/promises.d.ts +41 -0
  42. package/node_modules/@types/node/inspector.d.ts +224 -0
  43. package/node_modules/@types/node/inspector.generated.d.ts +1096 -836
  44. package/node_modules/@types/node/module.d.ts +349 -69
  45. package/node_modules/@types/node/net.d.ts +124 -203
  46. package/node_modules/@types/node/os.d.ts +11 -10
  47. package/node_modules/@types/node/package.json +18 -3
  48. package/node_modules/@types/node/path/posix.d.ts +8 -0
  49. package/node_modules/@types/node/path/win32.d.ts +8 -0
  50. package/node_modules/@types/node/path.d.ts +120 -133
  51. package/node_modules/@types/node/perf_hooks.d.ts +319 -637
  52. package/node_modules/@types/node/process.d.ts +331 -136
  53. package/node_modules/@types/node/punycode.d.ts +5 -5
  54. package/node_modules/@types/node/querystring.d.ts +4 -4
  55. package/node_modules/@types/node/quic.d.ts +910 -0
  56. package/node_modules/@types/node/readline/promises.d.ts +3 -4
  57. package/node_modules/@types/node/readline.d.ts +72 -120
  58. package/node_modules/@types/node/repl.d.ts +89 -104
  59. package/node_modules/@types/node/sea.d.ts +11 -2
  60. package/node_modules/@types/node/sqlite.d.ts +955 -0
  61. package/node_modules/@types/node/stream/consumers.d.ts +10 -10
  62. package/node_modules/@types/node/stream/promises.d.ts +136 -15
  63. package/node_modules/@types/node/stream/web.d.ts +176 -413
  64. package/node_modules/@types/node/stream.d.ts +573 -488
  65. package/node_modules/@types/node/string_decoder.d.ts +4 -4
  66. package/node_modules/@types/node/test/reporters.d.ts +96 -0
  67. package/node_modules/@types/node/test.d.ts +632 -179
  68. package/node_modules/@types/node/timers/promises.d.ts +4 -4
  69. package/node_modules/@types/node/timers.d.ts +5 -132
  70. package/node_modules/@types/node/tls.d.ts +162 -223
  71. package/node_modules/@types/node/trace_events.d.ts +9 -9
  72. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +1 -7
  73. package/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
  74. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +2 -0
  75. package/node_modules/@types/node/ts5.6/index.d.ts +30 -6
  76. package/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
  77. package/node_modules/@types/node/ts5.7/index.d.ts +117 -0
  78. package/node_modules/@types/node/tty.d.ts +58 -16
  79. package/node_modules/@types/node/url.d.ts +127 -572
  80. package/node_modules/@types/node/util/types.d.ts +558 -0
  81. package/node_modules/@types/node/util.d.ts +507 -1176
  82. package/node_modules/@types/node/v8.d.ts +209 -35
  83. package/node_modules/@types/node/vm.d.ts +287 -80
  84. package/node_modules/@types/node/wasi.d.ts +26 -5
  85. package/node_modules/@types/node/web-globals/abortcontroller.d.ts +27 -2
  86. package/node_modules/@types/node/web-globals/blob.d.ts +23 -0
  87. package/node_modules/@types/node/web-globals/console.d.ts +9 -0
  88. package/node_modules/@types/node/web-globals/crypto.d.ts +39 -0
  89. package/node_modules/@types/node/web-globals/encoding.d.ts +11 -0
  90. package/node_modules/@types/node/web-globals/events.d.ts +9 -0
  91. package/node_modules/@types/node/web-globals/fetch.d.ts +14 -0
  92. package/node_modules/@types/node/web-globals/importmeta.d.ts +13 -0
  93. package/node_modules/@types/node/web-globals/messaging.d.ts +23 -0
  94. package/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
  95. package/node_modules/@types/node/web-globals/performance.d.ts +45 -0
  96. package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  97. package/node_modules/@types/node/web-globals/streams.d.ts +115 -0
  98. package/node_modules/@types/node/web-globals/timers.d.ts +44 -0
  99. package/node_modules/@types/node/web-globals/url.d.ts +24 -0
  100. package/node_modules/@types/node/worker_threads.d.ts +338 -336
  101. package/node_modules/@types/node/zlib.d.ts +256 -114
  102. package/node_modules/color-convert/CHANGELOG.md +54 -0
  103. package/node_modules/esprima/ChangeLog +235 -0
  104. package/node_modules/rimraf/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -1
  105. package/node_modules/rimraf/node_modules/glob/dist/commonjs/index.d.ts +2 -2
  106. package/node_modules/rimraf/node_modules/glob/dist/esm/bin.mjs +111 -35
  107. package/node_modules/rimraf/node_modules/glob/dist/esm/bin.mjs.map +1 -1
  108. package/node_modules/rimraf/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -1
  109. package/node_modules/rimraf/node_modules/glob/dist/esm/index.d.ts +2 -2
  110. package/node_modules/rimraf/node_modules/glob/package.json +1 -1
  111. package/node_modules/source-map/CHANGELOG.md +301 -0
  112. package/node_modules/undici-types/agent.d.ts +13 -12
  113. package/node_modules/undici-types/api.d.ts +26 -26
  114. package/node_modules/undici-types/balanced-pool.d.ts +13 -12
  115. package/node_modules/undici-types/cache-interceptor.d.ts +173 -0
  116. package/node_modules/undici-types/client-stats.d.ts +15 -0
  117. package/node_modules/undici-types/client.d.ts +19 -19
  118. package/node_modules/undici-types/connector.d.ts +2 -2
  119. package/node_modules/undici-types/cookies.d.ts +2 -0
  120. package/node_modules/undici-types/diagnostics-channel.d.ts +18 -10
  121. package/node_modules/undici-types/dispatcher.d.ts +123 -103
  122. package/node_modules/undici-types/env-http-proxy-agent.d.ts +4 -3
  123. package/node_modules/undici-types/errors.d.ts +66 -54
  124. package/node_modules/undici-types/eventsource.d.ts +9 -4
  125. package/node_modules/undici-types/fetch.d.ts +22 -20
  126. package/node_modules/undici-types/formdata.d.ts +7 -7
  127. package/node_modules/undici-types/global-dispatcher.d.ts +4 -4
  128. package/node_modules/undici-types/global-origin.d.ts +5 -5
  129. package/node_modules/undici-types/h2c-client.d.ts +73 -0
  130. package/node_modules/undici-types/handlers.d.ts +8 -8
  131. package/node_modules/undici-types/header.d.ts +157 -1
  132. package/node_modules/undici-types/index.d.ts +64 -47
  133. package/node_modules/undici-types/interceptors.d.ts +64 -8
  134. package/node_modules/undici-types/mock-agent.d.ts +36 -18
  135. package/node_modules/undici-types/mock-call-history.d.ts +111 -0
  136. package/node_modules/undici-types/mock-client.d.ts +6 -4
  137. package/node_modules/undici-types/mock-errors.d.ts +3 -3
  138. package/node_modules/undici-types/mock-interceptor.d.ts +21 -20
  139. package/node_modules/undici-types/mock-pool.d.ts +6 -4
  140. package/node_modules/undici-types/package.json +1 -1
  141. package/node_modules/undici-types/patch.d.ts +0 -4
  142. package/node_modules/undici-types/pool-stats.d.ts +8 -8
  143. package/node_modules/undici-types/pool.d.ts +15 -13
  144. package/node_modules/undici-types/proxy-agent.d.ts +5 -4
  145. package/node_modules/undici-types/readable.d.ts +19 -16
  146. package/node_modules/undici-types/retry-agent.d.ts +1 -1
  147. package/node_modules/undici-types/retry-handler.d.ts +19 -10
  148. package/node_modules/undici-types/round-robin-pool.d.ts +41 -0
  149. package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  150. package/node_modules/undici-types/util.d.ts +3 -3
  151. package/node_modules/undici-types/utility.d.ts +7 -0
  152. package/node_modules/undici-types/webidl.d.ts +142 -29
  153. package/node_modules/undici-types/websocket.d.ts +46 -10
  154. package/node_modules/which/CHANGELOG.md +166 -0
  155. package/package.json +10 -5
  156. package/dist/packages/nanomem/cli.d.ts +0 -8
  157. package/dist/packages/nanomem/cli.js +0 -90
  158. package/dist/packages/nanomem/config.d.ts +0 -46
  159. package/dist/packages/nanomem/config.js +0 -48
  160. package/dist/packages/nanomem/consolidation.d.ts +0 -13
  161. package/dist/packages/nanomem/consolidation.js +0 -111
  162. package/dist/packages/nanomem/engine.d.ts +0 -67
  163. package/dist/packages/nanomem/engine.js +0 -492
  164. package/dist/packages/nanomem/eviction.d.ts +0 -16
  165. package/dist/packages/nanomem/eviction.js +0 -22
  166. package/dist/packages/nanomem/extension.d.ts +0 -11
  167. package/dist/packages/nanomem/extension.js +0 -264
  168. package/dist/packages/nanomem/extraction.d.ts +0 -10
  169. package/dist/packages/nanomem/extraction.js +0 -136
  170. package/dist/packages/nanomem/full-insights-html.d.ts +0 -8
  171. package/dist/packages/nanomem/full-insights-html.js +0 -311
  172. package/dist/packages/nanomem/full-insights.d.ts +0 -21
  173. package/dist/packages/nanomem/full-insights.js +0 -327
  174. package/dist/packages/nanomem/i18n.d.ts +0 -50
  175. package/dist/packages/nanomem/i18n.js +0 -169
  176. package/dist/packages/nanomem/index.d.ts +0 -18
  177. package/dist/packages/nanomem/index.js +0 -14
  178. package/dist/packages/nanomem/insights-html.d.ts +0 -8
  179. package/dist/packages/nanomem/insights-html.js +0 -431
  180. package/dist/packages/nanomem/linking.d.ts +0 -11
  181. package/dist/packages/nanomem/linking.js +0 -40
  182. package/dist/packages/nanomem/package.json +0 -10
  183. package/dist/packages/nanomem/privacy.d.ts +0 -16
  184. package/dist/packages/nanomem/privacy.js +0 -52
  185. package/dist/packages/nanomem/scoring.d.ts +0 -25
  186. package/dist/packages/nanomem/scoring.js +0 -63
  187. package/dist/packages/nanomem/store.d.ts +0 -16
  188. package/dist/packages/nanomem/store.js +0 -68
  189. package/dist/packages/nanomem/types.d.ts +0 -191
  190. package/dist/packages/nanomem/types.js +0 -7
  191. package/dist/packages/nanomem/update.d.ts +0 -14
  192. package/dist/packages/nanomem/update.js +0 -126
  193. package/node_modules/@types/node/compatibility/disposable.d.ts +0 -16
  194. package/node_modules/@types/node/compatibility/index.d.ts +0 -9
  195. package/node_modules/@types/node/compatibility/indexable.d.ts +0 -20
  196. package/node_modules/undici-types/file.d.ts +0 -39
  197. package/node_modules/undici-types/filereader.d.ts +0 -54
@@ -34,6 +34,8 @@ export interface Args {
34
34
  noThemes?: boolean;
35
35
  listModels?: string | true;
36
36
  offline?: boolean;
37
+ /** Disable MCP (Model Context Protocol). Default: false (MCP enabled) */
38
+ noMcp?: boolean;
37
39
  verbose?: boolean;
38
40
  /** Disable Soul (AI personality evolution). Default: false (Soul enabled) */
39
41
  disableSoul?: boolean;
package/dist/cli/args.js CHANGED
@@ -138,6 +138,9 @@ export function parseArgs(args, extensionFlags) {
138
138
  else if (arg === "--disable-soul") {
139
139
  result.disableSoul = true;
140
140
  }
141
+ else if (arg === "--no-mcp") {
142
+ result.noMcp = true;
143
+ }
141
144
  else if (arg.startsWith("@")) {
142
145
  result.fileArgs.push(arg.slice(1)); // Remove @ prefix
143
146
  }
@@ -207,6 +210,7 @@ ${chalk.bold("Options:")}
207
210
  --verbose Force verbose startup (overrides quietStartup setting)
208
211
  --offline Disable startup network operations (same as PI_OFFLINE=1)
209
212
  --disable-soul Disable Soul (AI personality evolution)
213
+ --no-mcp Disable MCP (Model Context Protocol) tools
210
214
  --help, -h Show this help
211
215
  --version, -v Show version number
212
216
 
@@ -8,6 +8,24 @@ import { spawn } from "child_process";
8
8
  import { existsSync, readFileSync } from "fs";
9
9
  import { join } from "path";
10
10
  import { getAgentDir } from "../../config.js";
11
+ // Log level control: DEBUG shows all MCP messages, RELEASE only shows summary
12
+ // Check if running from installed location (production) vs development
13
+ const isProductionBuild = typeof import.meta.url === "string" && import.meta.url.includes("node_modules");
14
+ const isDebugMode = process.env.NODE_ENV === "development" || (process.env.NODE_ENV !== "production" && !isProductionBuild);
15
+ function mcpLog(...args) {
16
+ if (isDebugMode) {
17
+ console.log(...args);
18
+ }
19
+ }
20
+ function mcpWarn(...args) {
21
+ if (isDebugMode) {
22
+ console.warn(...args);
23
+ }
24
+ }
25
+ function mcpError(...args) {
26
+ // Errors are always shown
27
+ console.error(...args);
28
+ }
11
29
  /**
12
30
  * MCP Client class
13
31
  * Manages connections to MCP servers and tool calls
@@ -38,7 +56,7 @@ export class MCPClient {
38
56
  }
39
57
  }
40
58
  catch (error) {
41
- console.error(`Failed to load MCP config: ${error}`);
59
+ mcpError(`Failed to load MCP config: ${error}`);
42
60
  }
43
61
  }
44
62
  /**
@@ -138,12 +156,15 @@ export class MCPClient {
138
156
  runtime.process.stderr.on("data", (chunk) => {
139
157
  const text = chunk.toString("utf8").trim();
140
158
  if (text.length > 0) {
141
- console.error(`[MCP:${serverId}] ${text}`);
159
+ // Only show stderr errors in debug mode
160
+ if (isDebugMode) {
161
+ mcpError(`[MCP:${serverId}] ${text}`);
162
+ }
142
163
  }
143
164
  });
144
165
  runtime.process.on("exit", (code, signal) => {
145
166
  const message = `[MCP:debug] Server exited: code=${code ?? "null"}, signal=${signal ?? "null"}`;
146
- console.log(message);
167
+ mcpLog(message);
147
168
  for (const pending of runtime.pendingRequests.values()) {
148
169
  clearTimeout(pending.timer);
149
170
  pending.reject(new Error(message));
@@ -173,7 +194,7 @@ export class MCPClient {
173
194
  const line = runtime.buffer.slice(0, lineEnd).toString("utf8").replace(/\r$/, "");
174
195
  runtime.buffer = runtime.buffer.slice(lineEnd + 1);
175
196
  if (line.length > 0) {
176
- console.log(`[MCP:${serverId}] Received: ${line.slice(0, 200)}`);
197
+ mcpLog(`[MCP:${serverId}] Received: ${line.slice(0, 200)}`);
177
198
  this.handleJsonRpcMessage(serverId, line);
178
199
  }
179
200
  }
@@ -24,13 +24,14 @@ const DEFAULT_MCP_CONFIG = {
24
24
  name: "Fetch (Web Scraper)",
25
25
  command: "npx",
26
26
  args: ["-y", "@kazuph/mcp-fetch"],
27
- enabled: true,
27
+ enabled: false,
28
28
  transport: "stdio",
29
29
  toolTimeout: 30000,
30
30
  },
31
31
  {
32
32
  id: "puppeteer",
33
33
  name: "Puppeteer (Browser Automation)",
34
+ // 注意:此包已废弃 (DEPRECATED),但仍可正常工作
34
35
  command: "npx",
35
36
  args: ["-y", "@modelcontextprotocol/server-puppeteer"],
36
37
  enabled: true,
@@ -60,7 +61,7 @@ const DEFAULT_MCP_CONFIG = {
60
61
  id: "sqlite",
61
62
  name: "SQLite (Database)",
62
63
  command: "npx",
63
- args: ["-y", "@modelcontextprotocol/server-sqlite"],
64
+ args: ["-y", "mcp-server-sqlite"],
64
65
  enabled: false,
65
66
  transport: "stdio",
66
67
  toolTimeout: 30000,
@@ -95,7 +96,7 @@ const DEFAULT_MCP_CONFIG = {
95
96
  id: "git",
96
97
  name: "Git",
97
98
  command: "npx",
98
- args: ["-y", "@executeautomation/server-git"],
99
+ args: ["-y", "@liangshanli/mcp-server-git"],
99
100
  enabled: false,
100
101
  transport: "stdio",
101
102
  toolTimeout: 30000,
package/dist/core/sdk.js CHANGED
@@ -242,14 +242,29 @@ export async function createAgentSession(options = {}) {
242
242
  mcpTools.push(...mcpManager.getTools());
243
243
  time("mcp.initialize");
244
244
  const mcpStatus = mcpManager.getStatus();
245
- if (mcpStatus.toolCount === 0) {
246
- const failed = mcpStatus.failedServers.length > 0
247
- ? ` failed=${mcpStatus.failedServers.join(",")}`
248
- : "";
249
- console.warn(`MCP enabled but no tools loaded (enabled=${mcpStatus.enabledServers.length}, started=${mcpStatus.startedServers.length}, tools=0).${failed}`);
245
+ const isProduction = process.env.NODE_ENV === "production";
246
+ if (isProduction) {
247
+ // Production mode: concise summary
248
+ const started = mcpStatus.startedServers;
249
+ const failed = mcpStatus.failedServers;
250
+ if (started.length > 0) {
251
+ console.error(`MCP: ${started.length} server(s) ready (${started.join(", ")})`);
252
+ }
253
+ if (failed.length > 0) {
254
+ console.error(`MCP: ${failed.length} failed (${failed.join(", ")})`);
255
+ }
250
256
  }
251
257
  else {
252
- console.error(`MCP tools loaded: ${mcpStatus.toolCount}`);
258
+ // Dev mode: detailed info
259
+ if (mcpStatus.toolCount === 0) {
260
+ const failed = mcpStatus.failedServers.length > 0
261
+ ? ` failed=${mcpStatus.failedServers.join(",")}`
262
+ : "";
263
+ console.warn(`MCP enabled but no tools loaded (enabled=${mcpStatus.enabledServers.length}, started=${mcpStatus.startedServers.length}, tools=0).${failed}`);
264
+ }
265
+ else {
266
+ console.error(`MCP tools loaded: ${mcpStatus.toolCount}`);
267
+ }
253
268
  }
254
269
  process.once("exit", () => mcpManager?.dispose());
255
270
  }
@@ -16,6 +16,7 @@ export interface RetrySettings {
16
16
  export interface TerminalSettings {
17
17
  showImages?: boolean;
18
18
  clearOnShrink?: boolean;
19
+ showTokenStats?: boolean;
19
20
  }
20
21
  export interface ImageSettings {
21
22
  autoResize?: boolean;
@@ -206,6 +207,8 @@ export declare class SettingsManager {
206
207
  setShowImages(show: boolean): void;
207
208
  getClearOnShrink(): boolean;
208
209
  setClearOnShrink(enabled: boolean): void;
210
+ getShowTokenStats(): boolean;
211
+ setShowTokenStats(enabled: boolean): void;
209
212
  getImageAutoResize(): boolean;
210
213
  setImageAutoResize(enabled: boolean): void;
211
214
  getBlockImages(): boolean;
@@ -587,6 +587,17 @@ export class SettingsManager {
587
587
  this.markModified("terminal", "clearOnShrink");
588
588
  this.save();
589
589
  }
590
+ getShowTokenStats() {
591
+ return this.settings.terminal?.showTokenStats ?? true;
592
+ }
593
+ setShowTokenStats(enabled) {
594
+ if (!this.globalSettings.terminal) {
595
+ this.globalSettings.terminal = {};
596
+ }
597
+ this.globalSettings.terminal.showTokenStats = enabled;
598
+ this.markModified("terminal", "showTokenStats");
599
+ this.save();
600
+ }
590
601
  getImageAutoResize() {
591
602
  return this.settings.images?.autoResize ?? true;
592
603
  }
@@ -17,6 +17,7 @@ export const BUILTIN_SLASH_COMMANDS = [
17
17
  { name: "copy", description: "Copy last agent message to clipboard" },
18
18
  { name: "name", description: "Set session display name" },
19
19
  { name: "session", description: "Show session info and stats" },
20
+ { name: "usage", description: "Show token usage and cost stats" },
20
21
  { name: "changelog", description: "Show changelog entries" },
21
22
  { name: "hotkeys", description: "Show all keyboard shortcuts" },
22
23
  { name: "fork", description: "Create a new fork from a previous message" },
package/dist/main.js CHANGED
@@ -617,8 +617,8 @@ export async function main(args) {
617
617
  sessionManager = SessionManager.open(selectedPath);
618
618
  }
619
619
  const { options: sessionOptions, cliThinkingFromModel } = buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry, settingsManager);
620
- // NanoPencil 默认启用 MCP;离线模式下关闭以避免启动阻塞。
621
- sessionOptions.enableMCP = APP_NAME === "nanopencil" && !offlineMode;
620
+ // NanoPencil 默认启用 MCP;离线模式或 --no-mcp 参数下关闭
621
+ sessionOptions.enableMCP = APP_NAME === "nanopencil" && !offlineMode && !parsed.noMcp;
622
622
  sessionOptions.authStorage = authStorage;
623
623
  sessionOptions.modelRegistry = modelRegistry;
624
624
  sessionOptions.resourceLoader = resourceLoader;
@@ -9,8 +9,10 @@ export declare class FooterComponent implements Component {
9
9
  private session;
10
10
  private footerData;
11
11
  private autoCompactEnabled;
12
- constructor(session: AgentSession, footerData: ReadonlyFooterDataProvider);
12
+ private showTokenStats;
13
+ constructor(session: AgentSession, footerData: ReadonlyFooterDataProvider, showTokenStats?: boolean);
13
14
  setAutoCompactEnabled(enabled: boolean): void;
15
+ setShowTokenStats(enabled: boolean): void;
14
16
  /**
15
17
  * No-op: git branch caching now handled by provider.
16
18
  * Kept for compatibility with existing call sites in interactive-mode.
@@ -33,13 +33,18 @@ export class FooterComponent {
33
33
  session;
34
34
  footerData;
35
35
  autoCompactEnabled = true;
36
- constructor(session, footerData) {
36
+ showTokenStats = true;
37
+ constructor(session, footerData, showTokenStats = true) {
37
38
  this.session = session;
38
39
  this.footerData = footerData;
40
+ this.showTokenStats = showTokenStats;
39
41
  }
40
42
  setAutoCompactEnabled(enabled) {
41
43
  this.autoCompactEnabled = enabled;
42
44
  }
45
+ setShowTokenStats(enabled) {
46
+ this.showTokenStats = enabled;
47
+ }
43
48
  /**
44
49
  * No-op: git branch caching now handled by provider.
45
50
  * Kept for compatibility with existing call sites in interactive-mode.
@@ -107,26 +112,31 @@ export class FooterComponent {
107
112
  }
108
113
  // Build stats line
109
114
  const statsParts = [];
110
- if (totalInput)
111
- statsParts.push(`↑${formatTokens(totalInput)}`);
112
- if (totalOutput)
113
- statsParts.push(`↓${formatTokens(totalOutput)}`);
114
- if (totalCacheRead)
115
- statsParts.push(`R${formatTokens(totalCacheRead)}`);
116
- if (totalCacheWrite)
117
- statsParts.push(`W${formatTokens(totalCacheWrite)}`);
118
- // Show cost with "(sub)" indicator if using OAuth subscription
119
- const usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;
120
- if (totalCost || usingSubscription) {
121
- const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
122
- statsParts.push(costStr);
115
+ // Token stats (can be hidden via showTokenStats setting)
116
+ if (this.showTokenStats) {
117
+ if (totalInput)
118
+ statsParts.push(`↑${formatTokens(totalInput)}`);
119
+ if (totalOutput)
120
+ statsParts.push(`↓${formatTokens(totalOutput)}`);
121
+ if (totalCacheRead)
122
+ statsParts.push(`R${formatTokens(totalCacheRead)}`);
123
+ if (totalCacheWrite)
124
+ statsParts.push(`W${formatTokens(totalCacheWrite)}`);
125
+ // Show cost with "(sub)" indicator if using OAuth subscription
126
+ const usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;
127
+ if (totalCost || usingSubscription) {
128
+ const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
129
+ statsParts.push(costStr);
130
+ }
123
131
  }
124
- // Colorize context percentage based on usage
132
+ // Context percentage (always shown - it's useful)
125
133
  let contextPercentStr;
126
134
  const autoIndicator = this.autoCompactEnabled ? " (auto)" : "";
135
+ // Show both percentage and absolute tokens used
136
+ const totalUsed = totalInput + totalOutput + totalCacheRead + totalCacheWrite;
127
137
  const contextPercentDisplay = contextPercent === "?"
128
138
  ? `?/${formatTokens(contextWindow)}${autoIndicator}`
129
- : `${contextPercent}%/${formatTokens(contextWindow)}${autoIndicator}`;
139
+ : `${contextPercent}% ${formatTokens(totalUsed)}/${formatTokens(contextWindow)}${autoIndicator}`;
130
140
  if (contextPercentValue > 90) {
131
141
  contextPercentStr = theme.fg("error", contextPercentDisplay);
132
142
  }
@@ -22,6 +22,7 @@ export interface SettingsConfig {
22
22
  autocompleteMaxVisible: number;
23
23
  quietStartup: boolean;
24
24
  clearOnShrink: boolean;
25
+ showTokenStats: boolean;
25
26
  }
26
27
  export interface SettingsCallbacks {
27
28
  onAutoCompactChange: (enabled: boolean) => void;
@@ -43,6 +44,7 @@ export interface SettingsCallbacks {
43
44
  onAutocompleteMaxVisibleChange: (maxVisible: number) => void;
44
45
  onQuietStartupChange: (enabled: boolean) => void;
45
46
  onClearOnShrinkChange: (enabled: boolean) => void;
47
+ onShowTokenStatsChange: (enabled: boolean) => void;
46
48
  onCancel: () => void;
47
49
  }
48
50
  /**
@@ -223,6 +223,13 @@ export class SettingsSelectorComponent extends Container {
223
223
  currentValue: config.clearOnShrink ? "true" : "false",
224
224
  values: ["true", "false"],
225
225
  });
226
+ items.splice(autocompleteIndex + 2, 0, {
227
+ id: "show-token-stats",
228
+ label: "Show token stats",
229
+ description: "Show token usage in footer (input, output, cost)",
230
+ currentValue: config.showTokenStats ? "true" : "false",
231
+ values: ["true", "false"],
232
+ });
226
233
  // Add borders
227
234
  this.addChild(new DynamicBorder());
228
235
  this.settingsList = new SettingsList(items, 10, getSettingsListTheme(), (id, newValue) => {
@@ -275,6 +282,9 @@ export class SettingsSelectorComponent extends Container {
275
282
  case "clear-on-shrink":
276
283
  callbacks.onClearOnShrinkChange(newValue === "true");
277
284
  break;
285
+ case "show-token-stats":
286
+ callbacks.onShowTokenStatsChange(newValue === "true");
287
+ break;
278
288
  }
279
289
  }, callbacks.onCancel, { enableSearch: true });
280
290
  this.addChild(this.settingsList);
@@ -300,6 +300,10 @@ export declare class InteractiveMode {
300
300
  private handleExportCommand;
301
301
  private handleShareCommand;
302
302
  private handleCopyCommand;
303
+ /**
304
+ * Handle /usage command - show token usage statistics
305
+ */
306
+ private handleUsageCommand;
303
307
  private handleNameCommand;
304
308
  private handleSessionCommand;
305
309
  private handleChangelogCommand;
@@ -168,7 +168,7 @@ export class InteractiveMode {
168
168
  this.editorContainer = new Container();
169
169
  this.editorContainer.addChild(this.editor);
170
170
  this.footerDataProvider = new FooterDataProvider();
171
- this.footer = new FooterComponent(session, this.footerDataProvider);
171
+ this.footer = new FooterComponent(session, this.footerDataProvider, this.settingsManager.getShowTokenStats());
172
172
  this.footer.setAutoCompactEnabled(session.autoCompactionEnabled);
173
173
  // Load hide thinking block setting
174
174
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
@@ -1569,6 +1569,11 @@ export class InteractiveMode {
1569
1569
  this.editor.setText("");
1570
1570
  return;
1571
1571
  }
1572
+ if (text === "/usage") {
1573
+ await this.handleUsageCommand();
1574
+ this.editor.setText("");
1575
+ return;
1576
+ }
1572
1577
  if (text === "/name" || text.startsWith("/name ")) {
1573
1578
  this.handleNameCommand(text);
1574
1579
  this.editor.setText("");
@@ -2714,6 +2719,7 @@ export class InteractiveMode {
2714
2719
  autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
2715
2720
  quietStartup: this.settingsManager.getQuietStartup(),
2716
2721
  clearOnShrink: this.settingsManager.getClearOnShrink(),
2722
+ showTokenStats: this.settingsManager.getShowTokenStats(),
2717
2723
  }, {
2718
2724
  onAutoCompactChange: (enabled) => {
2719
2725
  this.session.setAutoCompactionEnabled(enabled);
@@ -2811,6 +2817,11 @@ export class InteractiveMode {
2811
2817
  this.settingsManager.setClearOnShrink(enabled);
2812
2818
  this.ui.setClearOnShrink(enabled);
2813
2819
  },
2820
+ onShowTokenStatsChange: (enabled) => {
2821
+ this.settingsManager.setShowTokenStats(enabled);
2822
+ this.footer.setShowTokenStats(enabled);
2823
+ this.ui.requestRender();
2824
+ },
2814
2825
  onCancel: () => {
2815
2826
  done();
2816
2827
  this.ui.requestRender();
@@ -3541,6 +3552,101 @@ export class InteractiveMode {
3541
3552
  this.showError(error instanceof Error ? error.message : String(error));
3542
3553
  }
3543
3554
  }
3555
+ /**
3556
+ * Handle /usage command - show token usage statistics
3557
+ */
3558
+ async handleUsageCommand() {
3559
+ // Group usage by model
3560
+ const modelUsage = new Map();
3561
+ let totalInput = 0;
3562
+ let totalOutput = 0;
3563
+ let totalCacheRead = 0;
3564
+ let totalCacheWrite = 0;
3565
+ let totalCost = 0;
3566
+ let totalTokens = 0;
3567
+ let requestCount = 0;
3568
+ // Aggregate usage by model
3569
+ for (const entry of this.sessionManager.getEntries()) {
3570
+ if (entry.type === "message" && entry.message.role === "assistant") {
3571
+ const msg = entry.message;
3572
+ const modelId = msg.model || "unknown";
3573
+ if (!modelUsage.has(modelId)) {
3574
+ modelUsage.set(modelId, {
3575
+ input: 0,
3576
+ output: 0,
3577
+ cacheRead: 0,
3578
+ cacheWrite: 0,
3579
+ totalTokens: 0,
3580
+ cost: 0,
3581
+ requestCount: 0,
3582
+ });
3583
+ }
3584
+ const stats = modelUsage.get(modelId);
3585
+ stats.input += msg.usage.input;
3586
+ stats.output += msg.usage.output;
3587
+ stats.cacheRead += msg.usage.cacheRead;
3588
+ stats.cacheWrite += msg.usage.cacheWrite;
3589
+ stats.totalTokens += msg.usage.totalTokens;
3590
+ stats.cost += msg.usage.cost.total;
3591
+ stats.requestCount++;
3592
+ totalInput += msg.usage.input;
3593
+ totalOutput += msg.usage.output;
3594
+ totalCacheRead += msg.usage.cacheRead;
3595
+ totalCacheWrite += msg.usage.cacheWrite;
3596
+ totalTokens += msg.usage.totalTokens;
3597
+ totalCost += msg.usage.cost.total;
3598
+ requestCount++;
3599
+ }
3600
+ }
3601
+ // Get context usage
3602
+ const contextUsage = this.session.getContextUsage();
3603
+ const contextWindow = contextUsage?.contextWindow ?? 0;
3604
+ const contextPercent = contextUsage?.percent ?? 0;
3605
+ // Format numbers
3606
+ const fmt = (n) => n.toLocaleString();
3607
+ const fmtCost = (n) => `$${n.toFixed(4)}`;
3608
+ // Build output
3609
+ const lines = [];
3610
+ lines.push(theme.bold(theme.fg("accent", "═══ Token Usage ═══")));
3611
+ lines.push("");
3612
+ // Show usage by model
3613
+ if (modelUsage.size > 0) {
3614
+ for (const [modelId, stats] of modelUsage) {
3615
+ lines.push(theme.fg("accent", `┌─ ${modelId} ─`));
3616
+ lines.push("");
3617
+ lines.push(`│ Requests: ${stats.requestCount}`);
3618
+ lines.push(`│ Input: ${fmt(stats.input)} tokens`);
3619
+ lines.push(`│ Output: ${fmt(stats.output)} tokens`);
3620
+ lines.push(`│ Cache: ${fmt(stats.cacheRead + stats.cacheWrite)} tokens`);
3621
+ lines.push(`│ Total: ${fmt(stats.totalTokens)} tokens`);
3622
+ lines.push(`│ Cost: ${fmtCost(stats.cost)}`);
3623
+ lines.push(theme.fg("accent", `└${"─".repeat(Math.min(50, modelId.length + 4))}`));
3624
+ lines.push("");
3625
+ }
3626
+ }
3627
+ // Total
3628
+ lines.push(theme.bold(" ─────────── Total ───────────"));
3629
+ lines.push(` Requests: ${requestCount}`);
3630
+ lines.push(` Input: ${fmt(totalInput)} tokens`);
3631
+ lines.push(` Output: ${fmt(totalOutput)} tokens`);
3632
+ lines.push(` Cache: ${fmt(totalCacheRead + totalCacheWrite)} tokens`);
3633
+ lines.push(` Total: ${fmt(totalTokens)} tokens`);
3634
+ lines.push(` Cost: ${fmtCost(totalCost)}`);
3635
+ lines.push("");
3636
+ lines.push(` Context: ${contextPercent.toFixed(1)}% / ${fmt(contextWindow)} tokens`);
3637
+ // Show current model info
3638
+ const state = this.session.state;
3639
+ if (state.model) {
3640
+ lines.push(` Current: ${state.model.id}`);
3641
+ }
3642
+ lines.push("");
3643
+ lines.push(theme.fg("dim", " Tip: Use /settings → Terminal → Show token stats to toggle footer display"));
3644
+ // Display in chat
3645
+ for (const line of lines) {
3646
+ this.chatContainer.addChild(new Spacer(1));
3647
+ this.chatContainer.addChild(new Text(line, 1, 0));
3648
+ }
3649
+ }
3544
3650
  handleNameCommand(text) {
3545
3651
  const name = text.replace(/^\/name\s*/, "").trim();
3546
3652
  if (!name) {
@@ -5,11 +5,11 @@
5
5
  This package contains type definitions for node (https://nodejs.org/).
6
6
 
7
7
  # Details
8
- Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node/v20.
8
+ Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
9
9
 
10
10
  ### Additional Details
11
- * Last updated: Thu, 26 Feb 2026 18:47:04 GMT
11
+ * Last updated: Fri, 06 Mar 2026 00:57:44 GMT
12
12
  * Dependencies: [undici-types](https://npmjs.com/package/undici-types)
13
13
 
14
14
  # Credits
15
- These definitions were written by [Microsoft TypeScript](https://github.com/Microsoft), [Alberto Schiabel](https://github.com/jkomyno), [Andrew Makarov](https://github.com/r3nya), [Benjamin Toueg](https://github.com/btoueg), [David Junger](https://github.com/touffy), [Mohsen Azimi](https://github.com/mohsen1), [Nikita Galkin](https://github.com/galkin), [Sebastian Silbermann](https://github.com/eps1lon), [Wilco Bakker](https://github.com/WilcoBakker), [Marcin Kopacz](https://github.com/chyzwar), [Trivikram Kamat](https://github.com/trivikr), [Junxiao Shi](https://github.com/yoursunny), [Ilia Baryshnikov](https://github.com/qwelias), [ExE Boss](https://github.com/ExE-Boss), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Anna Henningsen](https://github.com/addaleax), [Victor Perin](https://github.com/victorperin), [NodeJS Contributors](https://github.com/NodeJS), [Linus Unnebäck](https://github.com/LinusU), [wafuwafu13](https://github.com/wafuwafu13), [Matteo Collina](https://github.com/mcollina), and [Dmitry Semigradsky](https://github.com/Semigradsky).
15
+ These definitions were written by [Microsoft TypeScript](https://github.com/Microsoft), [Alberto Schiabel](https://github.com/jkomyno), [Andrew Makarov](https://github.com/r3nya), [Benjamin Toueg](https://github.com/btoueg), [David Junger](https://github.com/touffy), [Mohsen Azimi](https://github.com/mohsen1), [Nikita Galkin](https://github.com/galkin), [Sebastian Silbermann](https://github.com/eps1lon), [Wilco Bakker](https://github.com/WilcoBakker), [Marcin Kopacz](https://github.com/chyzwar), [Trivikram Kamat](https://github.com/trivikr), [Junxiao Shi](https://github.com/yoursunny), [Ilia Baryshnikov](https://github.com/qwelias), [ExE Boss](https://github.com/ExE-Boss), [Piotr Błażejewicz](https://github.com/peterblazejewicz), [Anna Henningsen](https://github.com/addaleax), [Victor Perin](https://github.com/victorperin), [NodeJS Contributors](https://github.com/NodeJS), [Linus Unnebäck](https://github.com/LinusU), [wafuwafu13](https://github.com/wafuwafu13), [Matteo Collina](https://github.com/mcollina), [Dmitry Semigradsky](https://github.com/Semigradsky), [René](https://github.com/Renegade334), and [Yagiz Nizipli](https://github.com/anonrig).
@@ -1,8 +1,105 @@
1
- declare module "assert/strict" {
2
- import { strict } from "node:assert";
1
+ /**
2
+ * In strict assertion mode, non-strict methods behave like their corresponding
3
+ * strict methods. For example, `assert.deepEqual()` will behave like
4
+ * `assert.deepStrictEqual()`.
5
+ *
6
+ * In strict assertion mode, error messages for objects display a diff. In legacy
7
+ * assertion mode, error messages for objects display the objects, often truncated.
8
+ *
9
+ * To use strict assertion mode:
10
+ *
11
+ * ```js
12
+ * import { strict as assert } from 'node:assert';
13
+ * ```
14
+ *
15
+ * ```js
16
+ * import assert from 'node:assert/strict';
17
+ * ```
18
+ *
19
+ * Example error diff:
20
+ *
21
+ * ```js
22
+ * import { strict as assert } from 'node:assert';
23
+ *
24
+ * assert.deepEqual([[[1, 2, 3]], 4, 5], [[[1, 2, '3']], 4, 5]);
25
+ * // AssertionError: Expected inputs to be strictly deep-equal:
26
+ * // + actual - expected ... Lines skipped
27
+ * //
28
+ * // [
29
+ * // [
30
+ * // ...
31
+ * // 2,
32
+ * // + 3
33
+ * // - '3'
34
+ * // ],
35
+ * // ...
36
+ * // 5
37
+ * // ]
38
+ * ```
39
+ *
40
+ * To deactivate the colors, use the `NO_COLOR` or `NODE_DISABLE_COLORS`
41
+ * environment variables. This will also deactivate the colors in the REPL. For
42
+ * more on color support in terminal environments, read the tty
43
+ * [`getColorDepth()`](https://nodejs.org/docs/latest-v25.x/api/tty.html#writestreamgetcolordepthenv) documentation.
44
+ * @since v15.0.0
45
+ * @see [source](https://github.com/nodejs/node/blob/v25.x/lib/assert/strict.js)
46
+ */
47
+ declare module "node:assert/strict" {
48
+ import {
49
+ Assert,
50
+ AssertionError,
51
+ AssertionErrorOptions,
52
+ AssertOptions,
53
+ AssertPredicate,
54
+ AssertStrict,
55
+ deepStrictEqual,
56
+ doesNotMatch,
57
+ doesNotReject,
58
+ doesNotThrow,
59
+ fail,
60
+ ifError,
61
+ match,
62
+ notDeepStrictEqual,
63
+ notStrictEqual,
64
+ ok,
65
+ partialDeepStrictEqual,
66
+ rejects,
67
+ strictEqual,
68
+ throws,
69
+ } from "node:assert";
70
+ function strict(value: unknown, message?: string | Error): asserts value;
71
+ namespace strict {
72
+ export {
73
+ Assert,
74
+ AssertionError,
75
+ AssertionErrorOptions,
76
+ AssertOptions,
77
+ AssertPredicate,
78
+ AssertStrict,
79
+ deepStrictEqual,
80
+ deepStrictEqual as deepEqual,
81
+ doesNotMatch,
82
+ doesNotReject,
83
+ doesNotThrow,
84
+ fail,
85
+ ifError,
86
+ match,
87
+ notDeepStrictEqual,
88
+ notDeepStrictEqual as notDeepEqual,
89
+ notStrictEqual,
90
+ notStrictEqual as notEqual,
91
+ ok,
92
+ partialDeepStrictEqual,
93
+ rejects,
94
+ strict,
95
+ strictEqual,
96
+ strictEqual as equal,
97
+ throws,
98
+ };
99
+ }
3
100
  export = strict;
4
101
  }
5
- declare module "node:assert/strict" {
6
- import { strict } from "node:assert";
102
+ declare module "assert/strict" {
103
+ import strict = require("node:assert/strict");
7
104
  export = strict;
8
105
  }