@pencil-agent/nano-pencil 1.3.0 → 1.3.2

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.
@@ -0,0 +1,193 @@
1
+ /**
2
+ * [INPUT]: Soul profile and memory manager
3
+ * [OUTPUT]: Formatted display of Soul stats and personality
4
+ * [POS]: Interactive mode component for /soul command
5
+ */
6
+
7
+ import type { SoulManager } from "nanosoul";
8
+
9
+ interface DisplayOptions {
10
+ compact?: boolean;
11
+ }
12
+
13
+ /**
14
+ * Format Soul stats for display
15
+ */
16
+ export function formatSoulStats(
17
+ soul: SoulManager,
18
+ options: DisplayOptions = {},
19
+ ): string {
20
+ const profile = soul.getProfile();
21
+ const stats = soul.getStats();
22
+
23
+ if (options.compact) {
24
+ return formatCompactSoul(profile, stats);
25
+ }
26
+
27
+ return formatFullSoul(profile, stats);
28
+ }
29
+
30
+ /**
31
+ * Format compact Soul stats (single line)
32
+ */
33
+ function formatCompactSoul(profile: any, stats: any): string {
34
+ const personality = profile.personality;
35
+ const expertise = stats.expertise.slice(0, 3);
36
+
37
+ const topTraits = Object.entries(personality)
38
+ .filter(
39
+ ([_, value]) => typeof value === "number" && (value > 0.6 || value < 0.4),
40
+ )
41
+ .map(([key, value]) => {
42
+ const label = getTraitLabel(key);
43
+ const numValue = typeof value === "number" ? value : 0.5;
44
+ const status = numValue > 0.6 ? "↑" : numValue < 0.4 ? "↓" : "→";
45
+ return `${label}${status} ${(numValue * 100).toFixed(0)}%`;
46
+ })
47
+ .slice(0, 3)
48
+ .join(", ");
49
+
50
+ const topExpertise = expertise
51
+ .map((e: any) => `${e.domain}(${(e.confidence * 100).toFixed(0)}%)`)
52
+ .join(", ");
53
+
54
+ return `🧠 Soul: ${topTraits} | Expertise: ${topExpertise} | Interactions: ${stats.stats.totalInteractions}`;
55
+ }
56
+
57
+ /**
58
+ * Format full Soul stats (detailed view)
59
+ */
60
+ function formatFullSoul(profile: any, stats: any): string {
61
+ const lines: string[] = [];
62
+
63
+ lines.push("╔═════════════════════════════════════════════════╗");
64
+ lines.push("║ 🧠 AI Soul - Personality & Stats ║");
65
+ lines.push("╠═════════════════════════════════════════════════╣");
66
+ lines.push("║");
67
+
68
+ // Personality Section
69
+ lines.push("║ 📊 Personality Traits");
70
+ lines.push("║ ────────────────────────────────────────────────");
71
+
72
+ const personality = profile.personality;
73
+ const traits = [
74
+ { key: "openness", label: "开放性", emoji: "🎨" },
75
+ { key: "conscientiousness", label: "尽责性", emoji: "📋" },
76
+ { key: "codeVerbosity", label: "代码冗长", emoji: "📝" },
77
+ { key: "abstractionLevel", label: "抽象层级", emoji: "🏗️" },
78
+ { key: "safetyMargin", label: "安全边际", emoji: "🛡️" },
79
+ { key: "explorationDrive", label: "探索欲望", emoji: "🔍" },
80
+ ];
81
+
82
+ for (const trait of traits) {
83
+ const value = personality[trait.key];
84
+ const bar = createBar(value, 10);
85
+ const percent = (value * 100).toFixed(0).padStart(3);
86
+ lines.push(`║ ${trait.emoji} ${trait.label.padEnd(12)} ${bar} ${percent}%`);
87
+ }
88
+
89
+ lines.push("║");
90
+ lines.push("║ 🎯 Top Expertise Areas");
91
+
92
+ const expertise = stats.expertise.slice(0, 5);
93
+ if (expertise.length === 0) {
94
+ lines.push("║ (暂无专长数据,继续使用以积累)");
95
+ } else {
96
+ for (const exp of expertise) {
97
+ const confidence = (exp.confidence * 100).toFixed(0).padStart(3);
98
+ const examples = exp.examples.toString().padStart(3);
99
+ lines.push(
100
+ `║ • ${exp.domain.padEnd(20)} 信心: ${confidence}% 成功: ${examples} 次`,
101
+ );
102
+ }
103
+ }
104
+
105
+ lines.push("║");
106
+ lines.push("║ 💭 Current Mood");
107
+
108
+ const emotional = profile.emotionalState;
109
+ const mood = [
110
+ { label: "信心", value: emotional.confidence, emoji: "😊" },
111
+ { label: "好奇心", value: emotional.curiosity, emoji: "🤔" },
112
+ { label: "挫败感", value: emotional.frustration, emoji: "😤" },
113
+ { label: "心流", value: emotional.flow, emoji: "✨" },
114
+ ];
115
+
116
+ for (const m of mood) {
117
+ const bar = createBar(m.value, 8);
118
+ const percent = (m.value * 100).toFixed(0).padStart(3);
119
+ lines.push(`║ ${m.emoji} ${m.label.padEnd(8)} ${bar} ${percent}%`);
120
+ }
121
+
122
+ lines.push("║");
123
+ lines.push("║ 📈 Development Stats");
124
+ lines.push("║ ────────────────────────────────────────────────");
125
+ lines.push(`║ 总交互次数: ${stats.stats.totalInteractions}`);
126
+ lines.push(`║ 成功率: ${(stats.stats.successRate * 100).toFixed(1)}%`);
127
+ lines.push(`║ Soul 版本: ${profile.version}`);
128
+ lines.push(
129
+ `║ Soul 年龄: ${Math.floor((Date.now() - profile.createdAt.getTime()) / (1000 * 60 * 60 * 24))} 天`,
130
+ );
131
+ lines.push(`║ 最后进化: ${formatTimeAgo(profile.lastEvolved)}`);
132
+
133
+ lines.push("║");
134
+ lines.push("║ 🧘 User Relationship");
135
+ lines.push("║ ────────────────────────────────────────────────");
136
+ const rel = profile.userRelationship;
137
+ lines.push(`║ 交互次数: ${rel.interactionCount}`);
138
+ lines.push(`║ 满意度: ${(rel.satisfactionScore * 100).toFixed(0)}%`);
139
+ lines.push(` 沟通风格: ${rel.communicationStyle}`);
140
+
141
+ if (rel.knownPreferences.length > 0) {
142
+ lines.push(`║ 已知偏好: ${rel.knownPreferences.slice(0, 3).join(", ")}`);
143
+ }
144
+
145
+ lines.push("║");
146
+ lines.push("╚═════════════════════════════════════════════════╝");
147
+
148
+ return lines.join("\n");
149
+ }
150
+
151
+ /**
152
+ * Create a visual bar for values
153
+ */
154
+ function createBar(value: number, width: number): string {
155
+ const filled = Math.round(value * width);
156
+ const empty = width - filled;
157
+ return "█".repeat(filled) + "░".repeat(empty);
158
+ }
159
+
160
+ /**
161
+ * Get trait label in Chinese
162
+ */
163
+ function getTraitLabel(key: string): string {
164
+ const labels: Record<string, string> = {
165
+ openness: "开放性",
166
+ conscientiousness: "尽责性",
167
+ extraversion: "外向性",
168
+ agreeableness: "宜人性",
169
+ neuroticism: "神经质",
170
+ codeVerbosity: "代码冗长",
171
+ abstractionLevel: "抽象层级",
172
+ safetyMargin: "安全边际",
173
+ explorationDrive: "探索",
174
+ };
175
+ return labels[key] || key;
176
+ }
177
+
178
+ /**
179
+ * Format time ago in Chinese
180
+ */
181
+ function formatTimeAgo(date: Date): string {
182
+ const now = Date.now();
183
+ const diff = now - date.getTime();
184
+
185
+ const minutes = Math.floor(diff / (1000 * 60));
186
+ const hours = Math.floor(diff / (1000 * 60 * 60));
187
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
188
+
189
+ if (minutes < 1) return "刚刚";
190
+ if (minutes < 60) return `${minutes} 分钟前`;
191
+ if (hours < 24) return `${hours} 小时前`;
192
+ return `${days} 天前`;
193
+ }
@@ -95,6 +95,7 @@ import { promptForApiKey } from "./components/apikey-input.js";
95
95
  import { BashExecutionComponent } from "./components/bash-execution.js";
96
96
  import { BorderedLoader } from "./components/bordered-loader.js";
97
97
  import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
98
+ import { PencilLoader } from "./components/pencil-loader.js";
98
99
  import { CompactionSummaryMessageComponent } from "./components/compaction-summary-message.js";
99
100
  import { CustomEditor } from "./components/custom-editor.js";
100
101
  import { CustomMessageComponent } from "./components/custom-message.js";
@@ -193,7 +194,7 @@ export class InteractiveMode {
193
194
  private version: string;
194
195
  private isInitialized = false;
195
196
  private onInputCallback?: (text: string) => void;
196
- private loadingAnimation: Loader | undefined = undefined;
197
+ private loadingAnimation: Component | undefined = undefined;
197
198
  private pendingWorkingMessage: string | undefined = undefined;
198
199
  private readonly defaultWorkingMessage = "Working...";
199
200
 
@@ -233,11 +234,11 @@ export class InteractiveMode {
233
234
  private pendingBashComponents: BashExecutionComponent[] = [];
234
235
 
235
236
  // Auto-compaction state
236
- private autoCompactionLoader: Loader | undefined = undefined;
237
+ private autoCompactionLoader: Component | undefined = undefined;
237
238
  private autoCompactionEscapeHandler?: () => void;
238
239
 
239
240
  // Auto-retry state
240
- private retryLoader: Loader | undefined = undefined;
241
+ private retryLoader: Component | undefined = undefined;
241
242
  private retryEscapeHandler?: () => void;
242
243
 
243
244
  // Messages queued while compaction is running
@@ -1153,7 +1154,7 @@ export class InteractiveMode {
1153
1154
  waitForIdle: () => this.session.agent.waitForIdle(),
1154
1155
  newSession: async (options) => {
1155
1156
  if (this.loadingAnimation) {
1156
- this.loadingAnimation.stop();
1157
+ (this.loadingAnimation as PencilLoader).stop();
1157
1158
  this.loadingAnimation = undefined;
1158
1159
  }
1159
1160
  this.statusContainer.clear();
@@ -1439,7 +1440,7 @@ export class InteractiveMode {
1439
1440
  this.defaultEditor.onExtensionShortcut = undefined;
1440
1441
  this.updateTerminalTitle();
1441
1442
  if (this.loadingAnimation) {
1442
- this.loadingAnimation.setMessage(
1443
+ (this.loadingAnimation as PencilLoader).setMessage(
1443
1444
  `${this.defaultWorkingMessage} (${appKey(this.keybindings, "interrupt")} to interrupt)`,
1444
1445
  );
1445
1446
  }
@@ -1606,9 +1607,9 @@ export class InteractiveMode {
1606
1607
  setWorkingMessage: (message) => {
1607
1608
  if (this.loadingAnimation) {
1608
1609
  if (message) {
1609
- this.loadingAnimation.setMessage(message);
1610
+ (this.loadingAnimation as PencilLoader).setMessage(message);
1610
1611
  } else {
1611
- this.loadingAnimation.setMessage(
1612
+ (this.loadingAnimation as PencilLoader).setMessage(
1612
1613
  `${this.defaultWorkingMessage} (${appKey(this.keybindings, "interrupt")} to interrupt)`,
1613
1614
  );
1614
1615
  }
@@ -2237,6 +2238,16 @@ export class InteractiveMode {
2237
2238
  await this.handleReloadCommand();
2238
2239
  return;
2239
2240
  }
2241
+ if (text === "/soul") {
2242
+ this.handleSoulCommand();
2243
+ this.editor.setText("");
2244
+ return;
2245
+ }
2246
+ if (text === "/memory") {
2247
+ this.handleMemoryCommand();
2248
+ this.editor.setText("");
2249
+ return;
2250
+ }
2240
2251
  if (text === "/debug") {
2241
2252
  this.handleDebugCommand();
2242
2253
  this.editor.setText("");
@@ -2349,24 +2360,25 @@ export class InteractiveMode {
2349
2360
  this.retryEscapeHandler = undefined;
2350
2361
  }
2351
2362
  if (this.retryLoader) {
2352
- this.retryLoader.stop();
2363
+ (this.retryLoader as PencilLoader).stop();
2353
2364
  this.retryLoader = undefined;
2354
2365
  }
2355
2366
  if (this.loadingAnimation) {
2356
- this.loadingAnimation.stop();
2367
+ (this.loadingAnimation as PencilLoader).stop();
2357
2368
  }
2358
2369
  this.statusContainer.clear();
2359
- this.loadingAnimation = new Loader(
2370
+ this.loadingAnimation = new PencilLoader(
2360
2371
  this.ui,
2361
- (spinner) => theme.fg("accent", spinner),
2362
- (text) => theme.fg("muted", text),
2372
+ theme,
2363
2373
  this.defaultWorkingMessage,
2364
2374
  );
2365
2375
  this.statusContainer.addChild(this.loadingAnimation);
2366
2376
  // Apply any pending working message queued before loader existed
2367
2377
  if (this.pendingWorkingMessage !== undefined) {
2368
2378
  if (this.pendingWorkingMessage) {
2369
- this.loadingAnimation.setMessage(this.pendingWorkingMessage);
2379
+ (this.loadingAnimation as PencilLoader).setMessage(
2380
+ this.pendingWorkingMessage,
2381
+ );
2370
2382
  }
2371
2383
  this.pendingWorkingMessage = undefined;
2372
2384
  }
@@ -2512,7 +2524,7 @@ export class InteractiveMode {
2512
2524
 
2513
2525
  case "agent_end":
2514
2526
  if (this.loadingAnimation) {
2515
- this.loadingAnimation.stop();
2527
+ (this.loadingAnimation as PencilLoader).stop();
2516
2528
  this.loadingAnimation = undefined;
2517
2529
  this.statusContainer.clear();
2518
2530
  }
@@ -2539,10 +2551,9 @@ export class InteractiveMode {
2539
2551
  this.statusContainer.clear();
2540
2552
  const reasonText =
2541
2553
  event.reason === "overflow" ? "Context overflow detected, " : "";
2542
- this.autoCompactionLoader = new Loader(
2554
+ this.autoCompactionLoader = new PencilLoader(
2543
2555
  this.ui,
2544
- (spinner) => theme.fg("accent", spinner),
2545
- (text) => theme.fg("muted", text),
2556
+ theme,
2546
2557
  `${reasonText}Auto-compacting... (${appKey(this.keybindings, "interrupt")} to cancel)`,
2547
2558
  );
2548
2559
  this.statusContainer.addChild(this.autoCompactionLoader);
@@ -2558,7 +2569,7 @@ export class InteractiveMode {
2558
2569
  }
2559
2570
  // Stop loader
2560
2571
  if (this.autoCompactionLoader) {
2561
- this.autoCompactionLoader.stop();
2572
+ (this.autoCompactionLoader as PencilLoader).stop();
2562
2573
  this.autoCompactionLoader = undefined;
2563
2574
  this.statusContainer.clear();
2564
2575
  }
@@ -2598,10 +2609,9 @@ export class InteractiveMode {
2598
2609
  // Show retry indicator
2599
2610
  this.statusContainer.clear();
2600
2611
  const delaySeconds = Math.round(event.delayMs / 1000);
2601
- this.retryLoader = new Loader(
2612
+ this.retryLoader = new PencilLoader(
2602
2613
  this.ui,
2603
- (spinner) => theme.fg("warning", spinner),
2604
- (text) => theme.fg("muted", text),
2614
+ theme,
2605
2615
  `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s... (${appKey(this.keybindings, "interrupt")} to cancel)`,
2606
2616
  );
2607
2617
  this.statusContainer.addChild(this.retryLoader);
@@ -2617,7 +2627,7 @@ export class InteractiveMode {
2617
2627
  }
2618
2628
  // Stop loader
2619
2629
  if (this.retryLoader) {
2620
- this.retryLoader.stop();
2630
+ (this.retryLoader as PencilLoader).stop();
2621
2631
  this.retryLoader = undefined;
2622
2632
  this.statusContainer.clear();
2623
2633
  }
@@ -4033,7 +4043,7 @@ export class InteractiveMode {
4033
4043
  }
4034
4044
 
4035
4045
  // Set up escape handler and loader if summarizing
4036
- let summaryLoader: Loader | undefined;
4046
+ let summaryLoader: Component | undefined;
4037
4047
  const originalOnEscape = this.defaultEditor.onEscape;
4038
4048
 
4039
4049
  if (wantsSummary) {
@@ -4041,10 +4051,9 @@ export class InteractiveMode {
4041
4051
  this.session.abortBranchSummary();
4042
4052
  };
4043
4053
  this.chatContainer.addChild(new Spacer(1));
4044
- summaryLoader = new Loader(
4054
+ summaryLoader = new PencilLoader(
4045
4055
  this.ui,
4046
- (spinner) => theme.fg("accent", spinner),
4047
- (text) => theme.fg("muted", text),
4056
+ theme,
4048
4057
  `Summarizing branch... (${appKey(this.keybindings, "interrupt")} to cancel)`,
4049
4058
  );
4050
4059
  this.statusContainer.addChild(summaryLoader);
@@ -4081,7 +4090,7 @@ export class InteractiveMode {
4081
4090
  );
4082
4091
  } finally {
4083
4092
  if (summaryLoader) {
4084
- summaryLoader.stop();
4093
+ (summaryLoader as PencilLoader).stop();
4085
4094
  this.statusContainer.clear();
4086
4095
  }
4087
4096
  this.defaultEditor.onEscape = originalOnEscape;
@@ -4146,7 +4155,7 @@ export class InteractiveMode {
4146
4155
  private async handleResumeSession(sessionPath: string): Promise<void> {
4147
4156
  // Stop loading animation
4148
4157
  if (this.loadingAnimation) {
4149
- this.loadingAnimation.stop();
4158
+ (this.loadingAnimation as PencilLoader).stop();
4150
4159
  this.loadingAnimation = undefined;
4151
4160
  }
4152
4161
  this.statusContainer.clear();
@@ -4794,7 +4803,7 @@ export class InteractiveMode {
4794
4803
  private async handleClearCommand(): Promise<void> {
4795
4804
  // Stop loading animation
4796
4805
  if (this.loadingAnimation) {
4797
- this.loadingAnimation.stop();
4806
+ (this.loadingAnimation as PencilLoader).stop();
4798
4807
  this.loadingAnimation = undefined;
4799
4808
  }
4800
4809
  this.statusContainer.clear();
@@ -5011,7 +5020,7 @@ export class InteractiveMode {
5011
5020
  ): Promise<CompactionResult | undefined> {
5012
5021
  // Stop loading animation
5013
5022
  if (this.loadingAnimation) {
5014
- this.loadingAnimation.stop();
5023
+ (this.loadingAnimation as PencilLoader).stop();
5015
5024
  this.loadingAnimation = undefined;
5016
5025
  }
5017
5026
  this.statusContainer.clear();
@@ -5028,12 +5037,7 @@ export class InteractiveMode {
5028
5037
  const label = isAuto
5029
5038
  ? `Auto-compacting context... ${cancelHint}`
5030
5039
  : `Compacting context... ${cancelHint}`;
5031
- const compactingLoader = new Loader(
5032
- this.ui,
5033
- (spinner) => theme.fg("accent", spinner),
5034
- (text) => theme.fg("muted", text),
5035
- label,
5036
- );
5040
+ const compactingLoader = new PencilLoader(this.ui, theme, label);
5037
5041
  this.statusContainer.addChild(compactingLoader);
5038
5042
  this.ui.requestRender();
5039
5043
 
@@ -5065,7 +5069,7 @@ export class InteractiveMode {
5065
5069
  this.showError(`Compaction failed: ${message}`);
5066
5070
  }
5067
5071
  } finally {
5068
- compactingLoader.stop();
5072
+ (compactingLoader as PencilLoader).stop();
5069
5073
  this.statusContainer.clear();
5070
5074
  this.defaultEditor.onEscape = originalOnEscape;
5071
5075
  }
@@ -5075,7 +5079,7 @@ export class InteractiveMode {
5075
5079
 
5076
5080
  stop(): void {
5077
5081
  if (this.loadingAnimation) {
5078
- this.loadingAnimation.stop();
5082
+ (this.loadingAnimation as PencilLoader).stop();
5079
5083
  this.loadingAnimation = undefined;
5080
5084
  }
5081
5085
  this.clearExtensionTerminalInputListeners();
@@ -5089,4 +5093,56 @@ export class InteractiveMode {
5089
5093
  this.isInitialized = false;
5090
5094
  }
5091
5095
  }
5096
+
5097
+ private handleSoulCommand(): void {
5098
+ const soulManager = (this.session as any)._soulManager;
5099
+ if (!soulManager) {
5100
+ this.chatContainer.addChild(new Spacer(1));
5101
+ this.chatContainer.addChild(
5102
+ new Text(theme.fg("warning", "⚠️ Soul 未启用"), 1, 0),
5103
+ );
5104
+ this.chatContainer.addChild(
5105
+ new Text(
5106
+ theme.fg(
5107
+ "dim",
5108
+ "Soul (AI 性格系统) 未启用。请确保使用 NanoPencil 1.3.0 或更高版本。",
5109
+ ),
5110
+ 1,
5111
+ 0,
5112
+ ),
5113
+ );
5114
+ this.ui.requestRender();
5115
+ return;
5116
+ }
5117
+
5118
+ const { formatSoulStats } = require("./components/soul-stats.js");
5119
+ const stats = formatSoulStats(soulManager, { compact: false });
5120
+
5121
+ this.chatContainer.addChild(new Spacer(1));
5122
+ this.chatContainer.addChild(new Text(stats, 1, 0));
5123
+ this.ui.requestRender();
5124
+ }
5125
+
5126
+ private handleMemoryCommand(): void {
5127
+ const lines: string[] = [];
5128
+ lines.push(theme.fg("accent", "📚 Project Memory - NanoMem"));
5129
+ lines.push("");
5130
+ lines.push(theme.fg("dim", "存储位置: ~/.nanopencil/agent/memory/"));
5131
+ lines.push(theme.fg("dim", " - knowledge.json (项目知识)"));
5132
+ lines.push(theme.fg("dim", " - lessons.json (经验教训)"));
5133
+ lines.push(theme.fg("dim", " - preferences.json (用户偏好)"));
5134
+ lines.push(theme.fg("dim", " - patterns.json (行为模式)"));
5135
+ lines.push(theme.fg("dim", " - facets.json (模式/困境)"));
5136
+ lines.push("");
5137
+ lines.push(
5138
+ theme.fg("dim", "💡 提示: NanoMem 自动从对话中提取和记忆项目知识"),
5139
+ );
5140
+ lines.push(theme.fg("dim", " - 记住 API 端点、配置选项"));
5141
+ lines.push(theme.fg("dim", " - 学习错误模式和解决方案"));
5142
+ lines.push(theme.fg("dim", " - 识别用户偏好和编码风格"));
5143
+
5144
+ this.chatContainer.addChild(new Spacer(1));
5145
+ this.chatContainer.addChild(new Text(lines.join("\n"), 1, 0));
5146
+ this.ui.requestRender();
5147
+ }
5092
5148
  }
@@ -1,81 +1,81 @@
1
- {
2
- "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
- "name": "warm",
4
- "vars": {
5
- "warmBrown": "#c4a574",
6
- "warmLight": "#d4a574",
7
- "warmBorder": "#a08060",
8
- "blue": "#5f87ff",
9
- "green": "#b5bd68",
10
- "red": "#cc6666",
11
- "yellow": "#d4a84b",
12
- "gray": "#808080",
13
- "dimGray": "#666666",
14
- "darkGray": "#505050",
15
- "accent": "warmBrown",
16
- "selectedBg": "#3d362a",
17
- "userMsgBg": "#2e2a24",
18
- "toolPendingBg": "#2a2820",
19
- "toolSuccessBg": "#2a3024",
20
- "toolErrorBg": "#3c2828",
21
- "customMsgBg": "#2d2838"
22
- },
23
- "colors": {
24
- "accent": "accent",
25
- "border": "warmBorder",
26
- "borderAccent": "warmLight",
27
- "borderMuted": "darkGray",
28
- "success": "green",
29
- "error": "red",
30
- "warning": "yellow",
31
- "muted": "gray",
32
- "dim": "dimGray",
33
- "text": "",
34
- "thinkingText": "gray",
35
- "selectedBg": "selectedBg",
36
- "userMessageBg": "userMsgBg",
37
- "userMessageText": "",
38
- "customMessageBg": "customMsgBg",
39
- "customMessageText": "",
40
- "customMessageLabel": "#b8956b",
41
- "toolPendingBg": "toolPendingBg",
42
- "toolSuccessBg": "toolSuccessBg",
43
- "toolErrorBg": "toolErrorBg",
44
- "toolTitle": "",
45
- "toolOutput": "gray",
46
- "mdHeading": "warmLight",
47
- "mdLink": "#81a2be",
48
- "mdLinkUrl": "dimGray",
49
- "mdCode": "accent",
50
- "mdCodeBlock": "green",
51
- "mdCodeBlockBorder": "gray",
52
- "mdQuote": "gray",
53
- "mdQuoteBorder": "gray",
54
- "mdHr": "gray",
55
- "mdListBullet": "accent",
56
- "toolDiffAdded": "green",
57
- "toolDiffRemoved": "red",
58
- "toolDiffContext": "gray",
59
- "syntaxComment": "#6A9955",
60
- "syntaxKeyword": "#569CD6",
61
- "syntaxFunction": "#DCDCAA",
62
- "syntaxVariable": "#9CDCFE",
63
- "syntaxString": "#CE9178",
64
- "syntaxNumber": "#B5CEA8",
65
- "syntaxType": "#4EC9B0",
66
- "syntaxOperator": "#D4D4D4",
67
- "syntaxPunctuation": "#D4D4D4",
68
- "thinkingOff": "darkGray",
69
- "thinkingMinimal": "#6e6e6e",
70
- "thinkingLow": "#5f87af",
71
- "thinkingMedium": "warmBrown",
72
- "thinkingHigh": "#b294bb",
73
- "thinkingXhigh": "#d183e8",
74
- "bashMode": "green"
75
- },
76
- "export": {
77
- "pageBg": "#1a1814",
78
- "cardBg": "#242018",
79
- "infoBg": "#3c3728"
80
- }
81
- }
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
+ "name": "warm",
4
+ "vars": {
5
+ "warmBrown": "#c4a574",
6
+ "warmLight": "#d4a574",
7
+ "warmBorder": "#a08060",
8
+ "blue": "#5f87ff",
9
+ "green": "#b5bd68",
10
+ "red": "#cc6666",
11
+ "yellow": "#d4a84b",
12
+ "gray": "#808080",
13
+ "dimGray": "#666666",
14
+ "darkGray": "#505050",
15
+ "accent": "warmBrown",
16
+ "selectedBg": "#3d362a",
17
+ "userMsgBg": "#2e2a24",
18
+ "toolPendingBg": "#2a2820",
19
+ "toolSuccessBg": "#2a3024",
20
+ "toolErrorBg": "#3c2828",
21
+ "customMsgBg": "#2d2838"
22
+ },
23
+ "colors": {
24
+ "accent": "accent",
25
+ "border": "warmBorder",
26
+ "borderAccent": "warmLight",
27
+ "borderMuted": "darkGray",
28
+ "success": "green",
29
+ "error": "red",
30
+ "warning": "yellow",
31
+ "muted": "gray",
32
+ "dim": "dimGray",
33
+ "text": "",
34
+ "thinkingText": "gray",
35
+ "selectedBg": "selectedBg",
36
+ "userMessageBg": "userMsgBg",
37
+ "userMessageText": "warmLight",
38
+ "customMessageBg": "customMsgBg",
39
+ "customMessageText": "",
40
+ "customMessageLabel": "#b8956b",
41
+ "toolPendingBg": "toolPendingBg",
42
+ "toolSuccessBg": "toolSuccessBg",
43
+ "toolErrorBg": "toolErrorBg",
44
+ "toolTitle": "",
45
+ "toolOutput": "gray",
46
+ "mdHeading": "warmLight",
47
+ "mdLink": "#81a2be",
48
+ "mdLinkUrl": "dimGray",
49
+ "mdCode": "accent",
50
+ "mdCodeBlock": "green",
51
+ "mdCodeBlockBorder": "gray",
52
+ "mdQuote": "gray",
53
+ "mdQuoteBorder": "gray",
54
+ "mdHr": "gray",
55
+ "mdListBullet": "accent",
56
+ "toolDiffAdded": "green",
57
+ "toolDiffRemoved": "red",
58
+ "toolDiffContext": "gray",
59
+ "syntaxComment": "#6A9955",
60
+ "syntaxKeyword": "#569CD6",
61
+ "syntaxFunction": "#DCDCAA",
62
+ "syntaxVariable": "#9CDCFE",
63
+ "syntaxString": "#CE9178",
64
+ "syntaxNumber": "#B5CEA8",
65
+ "syntaxType": "#4EC9B0",
66
+ "syntaxOperator": "#D4D4D4",
67
+ "syntaxPunctuation": "#D4D4D4",
68
+ "thinkingOff": "darkGray",
69
+ "thinkingMinimal": "#6e6e6e",
70
+ "thinkingLow": "#5f87af",
71
+ "thinkingMedium": "warmBrown",
72
+ "thinkingHigh": "#b294bb",
73
+ "thinkingXhigh": "#d183e8",
74
+ "bashMode": "green"
75
+ },
76
+ "export": {
77
+ "pageBg": "#1a1814",
78
+ "cardBg": "#242018",
79
+ "infoBg": "#3c3728"
80
+ }
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pencil-agent/nano-pencil",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
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": {