tachibot-mcp 2.7.4 โ 2.7.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.
- package/dist/src/modes/shared/helpers/challenger-helpers.js +11 -10
- package/dist/src/modes/shared/helpers/verifier-helpers.js +12 -11
- package/dist/src/sequential-thinking.js +7 -6
- package/dist/src/tools/tachi-tool.js +21 -20
- package/dist/src/utils/ink-renderer.js +59 -3
- package/dist/src/utils/input-validator.js +2 -1
- package/package.json +1 -1
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* - Interface Segregation: Small, focused function signatures
|
|
18
18
|
* - Dependency Inversion: Functions depend on types, not concrete implementations
|
|
19
19
|
*/
|
|
20
|
+
import { icon } from '../../../utils/ink-renderer.js';
|
|
20
21
|
// ============================================================================
|
|
21
22
|
// Tone Detection
|
|
22
23
|
// ============================================================================
|
|
@@ -153,10 +154,10 @@ export const findThirdWay = (config) => {
|
|
|
153
154
|
* Synthesize all challenges into coherent report
|
|
154
155
|
*/
|
|
155
156
|
export const synthesizeChallengerReport = (config) => {
|
|
156
|
-
let synthesis = `##
|
|
157
|
+
let synthesis = `## ${icon('target')} Devil's Advocate Analysis\n\n`;
|
|
157
158
|
// Tone Analysis Section
|
|
158
|
-
synthesis += `###
|
|
159
|
-
synthesis += `**Status:** ${config.tone_analysis.detected ? '
|
|
159
|
+
synthesis += `### ${icon('comment')} Tone Analysis\n\n`;
|
|
160
|
+
synthesis += `**Status:** ${config.tone_analysis.detected ? `${icon('warning')} Uncontested Tone Detected` : `${icon('check')} Healthy Debate Room`}\n`;
|
|
160
161
|
synthesis += `**Severity:** ${config.tone_analysis.severity.toUpperCase()}\n`;
|
|
161
162
|
synthesis += `**Message:** ${config.tone_analysis.message}\n\n`;
|
|
162
163
|
if (config.tone_analysis.phrases.length > 0) {
|
|
@@ -167,14 +168,14 @@ export const synthesizeChallengerReport = (config) => {
|
|
|
167
168
|
synthesis += `\n`;
|
|
168
169
|
}
|
|
169
170
|
// Claims Analysis
|
|
170
|
-
synthesis += `###
|
|
171
|
+
synthesis += `### ${icon('search')} Claims Analyzed: ${config.claims.length}\n\n`;
|
|
171
172
|
if (config.claims.length > 0) {
|
|
172
173
|
synthesis += buildClaimsTable(config.claims.slice(0, 5));
|
|
173
174
|
synthesis += `\n`;
|
|
174
175
|
}
|
|
175
176
|
// Fact-Check Results
|
|
176
177
|
if (config.fact_check) {
|
|
177
|
-
synthesis += `###
|
|
178
|
+
synthesis += `### ${icon('check')} Fact-Check Results\n\n`;
|
|
178
179
|
synthesis += formatFactCheckResults(config.fact_check);
|
|
179
180
|
synthesis += `\n`;
|
|
180
181
|
}
|
|
@@ -204,13 +205,13 @@ export const synthesizeChallengerReport = (config) => {
|
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
207
|
// Summary
|
|
207
|
-
synthesis += `###
|
|
208
|
+
synthesis += `### ${icon('list')} Summary\n\n`;
|
|
208
209
|
synthesis += `\`\`\`\n`;
|
|
209
210
|
synthesis += `Thoroughness: ${config.thoroughness}\n`;
|
|
210
211
|
synthesis += `Claims Analyzed: ${config.claims.length}\n`;
|
|
211
|
-
synthesis += `Tone Detected: ${config.tone_analysis.detected ?
|
|
212
|
-
synthesis += `Fact-Checked: ${config.fact_check ?
|
|
213
|
-
synthesis += `Counter-Evidence: ${config.counter_evidence ?
|
|
212
|
+
synthesis += `Tone Detected: ${config.tone_analysis.detected ? `YES ${icon('warning')}` : `NO ${icon('check')}`}\n`;
|
|
213
|
+
synthesis += `Fact-Checked: ${config.fact_check ? `YES ${icon('check')}` : 'NO'}\n`;
|
|
214
|
+
synthesis += `Counter-Evidence: ${config.counter_evidence ? `YES ${icon('check')}` : 'NO'}\n`;
|
|
214
215
|
synthesis += `Opposite Views: ${config.opposite_views?.length || 0}\n`;
|
|
215
216
|
synthesis += `Third-Way Options: ${config.third_way?.length || 0}\n`;
|
|
216
217
|
synthesis += `\`\`\`\n`;
|
|
@@ -408,7 +409,7 @@ const buildClaimsTable = (claims) => {
|
|
|
408
409
|
claims.forEach(claim => {
|
|
409
410
|
const priority = (claim.priority * 100).toFixed(0) + '%';
|
|
410
411
|
const claimText = claim.claim.length > 80 ? claim.claim.substring(0, 77) + '...' : claim.claim;
|
|
411
|
-
const testable = claim.testable ? '
|
|
412
|
+
const testable = claim.testable ? icon('check') : icon('error');
|
|
412
413
|
table += `| ${priority} | ${claimText} | ${testable} |\n`;
|
|
413
414
|
});
|
|
414
415
|
return table;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - Interface Segregation: Small, focused function signatures
|
|
12
12
|
* - Dependency Inversion: Functions depend on types, not concrete implementations
|
|
13
13
|
*/
|
|
14
|
+
import { icon } from '../../../utils/ink-renderer.js';
|
|
14
15
|
// ============================================================================
|
|
15
16
|
// Prompt Building
|
|
16
17
|
// ============================================================================
|
|
@@ -193,18 +194,18 @@ export const synthesizeVerifierReport = (config) => {
|
|
|
193
194
|
const majorityResponses = config.consensus.clusters.get(config.consensus.majorityCluster) || [];
|
|
194
195
|
const outlierCount = config.responses.length - majorityResponses.length;
|
|
195
196
|
const consensusPercent = (config.consensus.agreement * 100).toFixed(1);
|
|
196
|
-
let synthesis = `##
|
|
197
|
+
let synthesis = `## ${icon('search')} Multi-Model Verification Report\n\n`;
|
|
197
198
|
// Consensus indicator
|
|
198
|
-
synthesis += `###
|
|
199
|
+
synthesis += `### ${icon('chart')} Consensus: ${consensusPercent}%\n\n`;
|
|
199
200
|
const consensusBar = Math.round(config.consensus.agreement * 10);
|
|
200
201
|
synthesis += `\`\`\`\n`;
|
|
201
202
|
synthesis += `[${'โฃฟ'.repeat(consensusBar)}${'โฃฟ'.repeat(10 - consensusBar)}] ${consensusPercent}% agreement\n`;
|
|
202
203
|
synthesis += `\`\`\`\n\n`;
|
|
203
204
|
// Model responses table
|
|
204
|
-
synthesis += `###
|
|
205
|
+
synthesis += `### ${icon('cpu')} Model Responses\n\n`;
|
|
205
206
|
synthesis += buildResponseTable(config.responses, majorityResponses);
|
|
206
207
|
// Majority analysis
|
|
207
|
-
synthesis += `###
|
|
208
|
+
synthesis += `### ${icon('target')} Majority View\n\n`;
|
|
208
209
|
synthesis += `**Conclusion:** ${config.consensus.majorityCluster}\n`;
|
|
209
210
|
synthesis += `**Models in agreement:** ${majorityResponses.length}/${config.responses.length}\n\n`;
|
|
210
211
|
if (majorityResponses.length > 0) {
|
|
@@ -226,7 +227,7 @@ export const synthesizeVerifierReport = (config) => {
|
|
|
226
227
|
}
|
|
227
228
|
// Dissenting views
|
|
228
229
|
if (outlierCount > 0) {
|
|
229
|
-
synthesis += `###
|
|
230
|
+
synthesis += `### ${icon('warning')} Dissenting Views (${outlierCount})\n\n`;
|
|
230
231
|
config.outliers.forEach(outlier => {
|
|
231
232
|
synthesis += `**${outlier.model}:** "${outlier.conclusion || 'unknown'}"\n`;
|
|
232
233
|
const preview = (outlier.response || '').substring(0, 150).replace(/\n/g, ' ');
|
|
@@ -236,14 +237,14 @@ export const synthesizeVerifierReport = (config) => {
|
|
|
236
237
|
});
|
|
237
238
|
}
|
|
238
239
|
// Summary
|
|
239
|
-
synthesis += `###
|
|
240
|
+
synthesis += `### ${icon('list')} Summary\n\n`;
|
|
240
241
|
synthesis += `\`\`\`\n`;
|
|
241
242
|
synthesis += `Total Models: ${config.responses.length}\n`;
|
|
242
243
|
synthesis += `Consensus: ${consensusPercent}%\n`;
|
|
243
244
|
synthesis += `Majority View: ${config.consensus.majorityCluster}\n`;
|
|
244
245
|
synthesis += `Agreeing Models: ${majorityResponses.length}\n`;
|
|
245
246
|
synthesis += `Dissenting: ${outlierCount}\n`;
|
|
246
|
-
synthesis += `High Confidence: ${config.consensus.agreement >= 0.8 ?
|
|
247
|
+
synthesis += `High Confidence: ${config.consensus.agreement >= 0.8 ? `YES ${icon('check')}` : 'NO'}\n`;
|
|
247
248
|
synthesis += `\`\`\`\n`;
|
|
248
249
|
return synthesis;
|
|
249
250
|
};
|
|
@@ -273,10 +274,10 @@ const buildResponseTable = (responses, majorityResponses) => {
|
|
|
273
274
|
table += '|:------:|:------|:----------:|-----------:|:--------|\n';
|
|
274
275
|
responses.forEach((resp) => {
|
|
275
276
|
const isMajority = majorityResponses.includes(resp);
|
|
276
|
-
const statusIcon = isMajority ? '
|
|
277
|
-
const conclusionIcon = resp.conclusion === 'true' ? '
|
|
278
|
-
resp.conclusion === 'false' ? '
|
|
279
|
-
resp.conclusion === 'uncertain' ? '
|
|
277
|
+
const statusIcon = isMajority ? icon('check') : icon('warning');
|
|
278
|
+
const conclusionIcon = resp.conclusion === 'true' ? icon('check') :
|
|
279
|
+
resp.conclusion === 'false' ? icon('error') :
|
|
280
|
+
resp.conclusion === 'uncertain' ? icon('question') : '?';
|
|
280
281
|
const confidence = resp.confidence ? `${Math.round(resp.confidence * 100)}%` : 'N/A';
|
|
281
282
|
const preview = (resp.response || '').substring(0, 60).replace(/\n/g, ' ').trim();
|
|
282
283
|
const previewText = preview ? `${preview}...` : 'No response';
|
|
@@ -9,6 +9,7 @@ import { ToolExecutionService } from "./orchestrators/collaborative/services/too
|
|
|
9
9
|
import { ReasoningMode } from "./reasoning-chain.js";
|
|
10
10
|
import { isModelAvailable, getAvailableModelNames } from "./utils/model-availability.js";
|
|
11
11
|
import { formatMemorySaveHint } from "./utils/memory-provider.js";
|
|
12
|
+
import { icon } from "./utils/ink-renderer.js";
|
|
12
13
|
/** Map string aliases to numeric values */
|
|
13
14
|
const CONTEXT_WINDOW_MAP = {
|
|
14
15
|
none: 0,
|
|
@@ -162,26 +163,26 @@ export class SequentialThinking {
|
|
|
162
163
|
guidance += `Thoughts completed: ${thoughtsSoFar}/${session.totalThoughts}\n\n`;
|
|
163
164
|
// Suggest next steps based on progress
|
|
164
165
|
if (progress < 30) {
|
|
165
|
-
guidance +=
|
|
166
|
+
guidance += `${icon('search')} **Early Stage**: Focus on understanding and decomposing the problem.\n`;
|
|
166
167
|
guidance += "Consider: What are the key components? What constraints exist?\n";
|
|
167
168
|
}
|
|
168
169
|
else if (progress < 60) {
|
|
169
|
-
guidance +=
|
|
170
|
+
guidance += `${icon('wrench')} **Middle Stage**: Explore solutions and alternatives.\n`;
|
|
170
171
|
guidance += "Consider: What approaches could work? What are the trade-offs?\n";
|
|
171
172
|
guidance += "You may want to branch to explore alternatives.\n";
|
|
172
173
|
}
|
|
173
174
|
else if (progress < 90) {
|
|
174
|
-
guidance +=
|
|
175
|
+
guidance += `${icon('target')} **Late Stage**: Refine and validate your approach.\n`;
|
|
175
176
|
guidance += "Consider: Are there edge cases? Can we optimize further?\n";
|
|
176
177
|
guidance += "You may want to revise earlier thoughts with new insights.\n";
|
|
177
178
|
}
|
|
178
179
|
else {
|
|
179
|
-
guidance +=
|
|
180
|
+
guidance += `${icon('sparkle')} **Final Stage**: Synthesize and conclude.\n`;
|
|
180
181
|
guidance += "Consider: What's the final solution? What are the next steps?\n";
|
|
181
182
|
}
|
|
182
183
|
// Check if revision might be helpful
|
|
183
184
|
if (thoughtsSoFar > 3 && !session.thoughts.some(t => t.isRevision)) {
|
|
184
|
-
guidance +=
|
|
185
|
+
guidance += `\n${icon('lightbulb')} **Tip**: Consider revising earlier thoughts if new insights emerged.\n`;
|
|
185
186
|
}
|
|
186
187
|
return guidance;
|
|
187
188
|
}
|
|
@@ -189,7 +190,7 @@ export class SequentialThinking {
|
|
|
189
190
|
* Generate a summary of the thinking session
|
|
190
191
|
*/
|
|
191
192
|
generateSummary(session) {
|
|
192
|
-
let summary = `##
|
|
193
|
+
let summary = `## ${icon('target')} Thinking Session Complete\n\n`;
|
|
193
194
|
summary += `**Objective**: ${session.objective || "Not specified"}\n`;
|
|
194
195
|
summary += `**Total Thoughts**: ${session.thoughts.length}\n`;
|
|
195
196
|
// Count revisions and branches
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* tachi "anything" --mode=solve โ force specific mode
|
|
12
12
|
*/
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
import { renderBigText } from "../utils/ink-renderer.js";
|
|
14
|
+
import { renderBigText, icon } from "../utils/ink-renderer.js";
|
|
15
15
|
// Import tool executors
|
|
16
16
|
import { callGemini, isGeminiAvailable } from "./gemini-tools.js";
|
|
17
17
|
import { callGrok } from "./grok-tools.js";
|
|
@@ -104,14 +104,15 @@ function routeIntent(query) {
|
|
|
104
104
|
// ============================================================================
|
|
105
105
|
// MODE HANDLERS
|
|
106
106
|
// ============================================================================
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
// Use icon() for Nerd Font support with Unicode fallback
|
|
108
|
+
const getModeIcon = (mode) => ({
|
|
109
|
+
research: icon('search'),
|
|
110
|
+
solve: icon('wrench'),
|
|
111
|
+
verify: icon('check'),
|
|
112
|
+
creative: icon('lightbulb'),
|
|
113
|
+
architect: icon('building'),
|
|
114
|
+
judge: icon('scales'),
|
|
115
|
+
}[mode]);
|
|
115
116
|
const MODE_HEADERS = {
|
|
116
117
|
research: "RESEARCH",
|
|
117
118
|
solve: "SOLVE",
|
|
@@ -168,7 +169,7 @@ async function solveHandler(query) {
|
|
|
168
169
|
{ role: "system", content: "You are Qwen3-Coder. Debug and solve the code problem. Provide working code." },
|
|
169
170
|
{ role: "user", content: query }
|
|
170
171
|
], OpenRouterModel.QWEN3_CODER_PLUS, 0.2, 6000);
|
|
171
|
-
results.push(
|
|
172
|
+
results.push(`**${icon('wrench')} Qwen Analysis:**\n${qwenResult}`);
|
|
172
173
|
}
|
|
173
174
|
catch {
|
|
174
175
|
// Qwen failed, continue with Grok
|
|
@@ -187,7 +188,7 @@ async function solveHandler(query) {
|
|
|
187
188
|
temperature: 0.3,
|
|
188
189
|
maxTokens: 2000
|
|
189
190
|
});
|
|
190
|
-
results.push(`\n
|
|
191
|
+
results.push(`\n**${icon('search')} Related Solutions:**\n${searchResult.content}`);
|
|
191
192
|
}
|
|
192
193
|
catch {
|
|
193
194
|
// Search failed, continue
|
|
@@ -206,7 +207,7 @@ async function solveHandler(query) {
|
|
|
206
207
|
async function verifyHandler(query) {
|
|
207
208
|
const judgePrompt = `You are a critical analyst and judge. For the given question or statement:
|
|
208
209
|
1. Analyze for correctness, accuracy, and potential issues
|
|
209
|
-
2. Provide a clear verdict:
|
|
210
|
+
2. Provide a clear verdict: VALID, INVALID, or NEEDS MORE CONTEXT
|
|
210
211
|
3. Support your verdict with evidence and reasoning
|
|
211
212
|
4. List any caveats or edge cases
|
|
212
213
|
5. Confidence score (0-100%)`;
|
|
@@ -214,7 +215,7 @@ async function verifyHandler(query) {
|
|
|
214
215
|
if (isGeminiAvailable()) {
|
|
215
216
|
try {
|
|
216
217
|
const result = await callGemini(query, undefined, judgePrompt);
|
|
217
|
-
return
|
|
218
|
+
return `**${icon('scales')} Gemini Judge:**\n${result}`;
|
|
218
219
|
}
|
|
219
220
|
catch {
|
|
220
221
|
// Fall through to GPT
|
|
@@ -227,7 +228,7 @@ async function verifyHandler(query) {
|
|
|
227
228
|
{ role: "system", content: judgePrompt },
|
|
228
229
|
{ role: "user", content: query }
|
|
229
230
|
], OPENAI_MODELS.DEFAULT, 0.3, 4000);
|
|
230
|
-
return
|
|
231
|
+
return `**${icon('scales')} GPT Judge:**\n${result}`;
|
|
231
232
|
}
|
|
232
233
|
catch {
|
|
233
234
|
// Fall through to Grok
|
|
@@ -239,7 +240,7 @@ async function verifyHandler(query) {
|
|
|
239
240
|
{ role: "system", content: judgePrompt },
|
|
240
241
|
{ role: "user", content: query }
|
|
241
242
|
]);
|
|
242
|
-
return
|
|
243
|
+
return `**${icon('scales')} Grok Judge:**\n${result}`;
|
|
243
244
|
}
|
|
244
245
|
catch (error) {
|
|
245
246
|
return `[Verification failed: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
@@ -280,7 +281,7 @@ async function architectHandler(query) {
|
|
|
280
281
|
temperature: 0.3,
|
|
281
282
|
maxTokens: 2500
|
|
282
283
|
});
|
|
283
|
-
results.push(
|
|
284
|
+
results.push(`**${icon('search')} Context & Patterns:**\n${searchResult.content}`);
|
|
284
285
|
}
|
|
285
286
|
catch {
|
|
286
287
|
// Search failed, continue
|
|
@@ -325,7 +326,7 @@ Provide:
|
|
|
325
326
|
2. KEY REASONS: Top 3 reasons for this choice
|
|
326
327
|
3. RISKS: Main risks to watch for
|
|
327
328
|
4. NEXT STEPS: Concrete action items`);
|
|
328
|
-
results.push(`\n
|
|
329
|
+
results.push(`\n**${icon('scales')} Final Verdict (Gemini):**\n${judgeResult}`);
|
|
329
330
|
}
|
|
330
331
|
catch {
|
|
331
332
|
// Judge failed
|
|
@@ -371,7 +372,7 @@ Provide:
|
|
|
371
372
|
2. CONSENSUS: Where models agreed
|
|
372
373
|
3. DISAGREEMENTS: Where they differed and why
|
|
373
374
|
4. CONFIDENCE: Your confidence level (0-100%)`);
|
|
374
|
-
results.push(`\n
|
|
375
|
+
results.push(`\n**${icon('scales')} FINAL VERDICT (Gemini Judge):**\n${finalVerdict}`);
|
|
375
376
|
}
|
|
376
377
|
catch {
|
|
377
378
|
// Judge failed
|
|
@@ -446,11 +447,11 @@ Examples:
|
|
|
446
447
|
}
|
|
447
448
|
log.info(`Tachi routing to ${resolvedMode}${routeInfo}`);
|
|
448
449
|
// Build response with header
|
|
449
|
-
const
|
|
450
|
+
const modeIcon = getModeIcon(resolvedMode);
|
|
450
451
|
const headerText = MODE_HEADERS[resolvedMode];
|
|
451
452
|
// BigText header (disabled via TACHIBOT_BIG_HEADERS=false)
|
|
452
453
|
let response = renderBigText(headerText, { font: "block", gradient: "cristal" });
|
|
453
|
-
response += `\n${
|
|
454
|
+
response += `\n${modeIcon} **${resolvedMode.toUpperCase()} MODE**${routeInfo}\n\n`;
|
|
454
455
|
response += `---\n\n`;
|
|
455
456
|
// Execute mode handler
|
|
456
457
|
try {
|
|
@@ -316,6 +316,28 @@ export const nerdIcons = {
|
|
|
316
316
|
tag: '', // nf-fa-tag
|
|
317
317
|
bookmark: '', // nf-fa-bookmark
|
|
318
318
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
319
|
+
// REASONING / ANALYSIS (replaces emojis)
|
|
320
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
321
|
+
target: '๓ฐ', // nf-md-bullseye (replaces ๐ฏ)
|
|
322
|
+
scales: '๓ฐท', // nf-md-scale_balance (replaces โ๏ธ)
|
|
323
|
+
eye: '', // nf-fa-eye (replaces ๐)
|
|
324
|
+
eyeSlash: '', // nf-fa-eye_slash
|
|
325
|
+
building: '', // nf-fa-building (replaces ๐๏ธ)
|
|
326
|
+
handshake: '๓ฑข', // nf-md-handshake (replaces ๐ค)
|
|
327
|
+
flask: '', // nf-fa-flask (replaces ๐งช)
|
|
328
|
+
sword: '๓ฐฅ', // nf-md-sword (replaces โ๏ธ)
|
|
329
|
+
swords: '๓ฐ', // nf-md-sword_cross
|
|
330
|
+
money: '', // nf-fa-dollar (replaces ๐ฐ)
|
|
331
|
+
branch: '', // nf-oct-git_branch (replaces ๐ฟ)
|
|
332
|
+
lightbulb: '', // nf-fa-lightbulb_o (replaces ๐ก)
|
|
333
|
+
compass: '', // nf-fa-compass
|
|
334
|
+
flag: '', // nf-fa-flag
|
|
335
|
+
trophy: '', // nf-fa-trophy
|
|
336
|
+
shield: '', // nf-fa-shield
|
|
337
|
+
puzzle: '๓ฐ', // nf-md-puzzle (replaces ๐งฉ)
|
|
338
|
+
thumbUp: '', // nf-fa-thumbs_up
|
|
339
|
+
thumbDown: '', // nf-fa-thumbs_down
|
|
340
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
319
341
|
// POWERLINE
|
|
320
342
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
321
343
|
plRight: '', // Powerline right arrow
|
|
@@ -499,6 +521,26 @@ export function icon(name) {
|
|
|
499
521
|
bookmark: 'โถ',
|
|
500
522
|
clock: 'โท',
|
|
501
523
|
calendar: 'โฆ',
|
|
524
|
+
// Reasoning/Analysis
|
|
525
|
+
target: 'โ',
|
|
526
|
+
scales: 'โ',
|
|
527
|
+
eye: 'โ',
|
|
528
|
+
eyeSlash: 'โ',
|
|
529
|
+
building: 'โฃ',
|
|
530
|
+
handshake: 'โก',
|
|
531
|
+
flask: 'โ',
|
|
532
|
+
sword: 'โ ',
|
|
533
|
+
swords: 'โ',
|
|
534
|
+
money: '$',
|
|
535
|
+
branch: 'โ',
|
|
536
|
+
lightbulb: 'โฆ',
|
|
537
|
+
compass: 'โ',
|
|
538
|
+
flag: 'โ',
|
|
539
|
+
trophy: 'โ',
|
|
540
|
+
shield: 'โ',
|
|
541
|
+
puzzle: 'โฆ',
|
|
542
|
+
thumbUp: '+',
|
|
543
|
+
thumbDown: '-',
|
|
502
544
|
// Powerline (no fallback - just empty)
|
|
503
545
|
plRight: '',
|
|
504
546
|
plLeft: '',
|
|
@@ -634,6 +676,15 @@ export function renderGradientModelName(model) {
|
|
|
634
676
|
export const showBigHeaders = () => {
|
|
635
677
|
return process.env.TACHIBOT_BIG_HEADERS !== 'false';
|
|
636
678
|
};
|
|
679
|
+
/**
|
|
680
|
+
* Strip ANSI escape codes from text
|
|
681
|
+
*/
|
|
682
|
+
function stripAnsiCodes(text) {
|
|
683
|
+
// Comprehensive ANSI regex - covers SGR, cursor, and other sequences
|
|
684
|
+
// eslint-disable-next-line no-control-regex
|
|
685
|
+
const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
|
|
686
|
+
return text.replace(ansiRegex, '');
|
|
687
|
+
}
|
|
637
688
|
/**
|
|
638
689
|
* Render large ASCII art text with optional gradient
|
|
639
690
|
* Uses ink-big-text for rendering, then applies gradient-string for colors
|
|
@@ -645,13 +696,18 @@ export function renderBigText(text, options) {
|
|
|
645
696
|
return '';
|
|
646
697
|
const font = options?.font || 'block';
|
|
647
698
|
const gradient = options?.gradient;
|
|
648
|
-
// Render BigText to string
|
|
649
|
-
|
|
699
|
+
// Render BigText to string and strip any ANSI codes from Ink
|
|
700
|
+
let ascii = stripAnsiCodes(renderInkToString(_jsx(BigText, { text: text, font: font })));
|
|
650
701
|
// Apply gradient if specified
|
|
651
702
|
if (gradient) {
|
|
652
703
|
const gradFn = gradientString[gradient];
|
|
653
704
|
if (gradFn && typeof gradFn.multiline === 'function') {
|
|
654
|
-
|
|
705
|
+
// Normalize line widths for proper gradient alignment
|
|
706
|
+
// gradient-string.multiline() applies colors per-line, so lines must be equal width
|
|
707
|
+
const lines = ascii.split('\n');
|
|
708
|
+
const maxWidth = Math.max(...lines.map(l => l.length));
|
|
709
|
+
const normalized = lines.map(l => l.padEnd(maxWidth)).join('\n');
|
|
710
|
+
return gradFn.multiline(normalized);
|
|
655
711
|
}
|
|
656
712
|
}
|
|
657
713
|
return ascii;
|
|
@@ -9,11 +9,12 @@ export const MAX_SYSTEM_PROMPT_LENGTH = 5000;
|
|
|
9
9
|
// Patterns to detect potential injection attempts
|
|
10
10
|
// NOTE: Role injection (user:/assistant:/system:) pattern removed due to false positives
|
|
11
11
|
// with legitimate LLM-generated content. For LLM-to-LLM calls, use skipValidation flag.
|
|
12
|
+
// NOTE: Path traversal (../) pattern removed - too many false positives in architecture
|
|
13
|
+
// discussions and code examples mentioning relative paths.
|
|
12
14
|
const SUSPICIOUS_PATTERNS = [
|
|
13
15
|
/<\s*script/gi, // XSS attempts
|
|
14
16
|
/\b(exec|eval)\s*\(/gi, // Code execution attempts (require() removed - false positives in code examples)
|
|
15
17
|
/;\s*(rm|del|format|drop\s+table)/gi, // Command/SQL injection
|
|
16
|
-
/\.\.\//g, // Path traversal
|
|
17
18
|
/\x00/g, // Null byte injection
|
|
18
19
|
];
|
|
19
20
|
/**
|
package/package.json
CHANGED