codehere 0.2.1 → 0.3.0-rc.1
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/README.md +88 -68
- package/dist/domain/entities/task.js +4 -4
- package/dist/error-handler.js +4 -9
- package/dist/index.js +253 -1219
- package/dist/infrastructure/config/product-context.js +7 -6
- package/dist/infrastructure/hooks/claude-sdk-hook.js +335 -63
- package/dist/infrastructure/observability/execution-tracer.js +11 -6
- package/dist/infrastructure/orchestration/agent-adapter.js +13 -0
- package/dist/infrastructure/orchestration/agent-installer.js +101 -0
- package/dist/infrastructure/orchestration/agents-config-seed.js +56 -0
- package/dist/infrastructure/orchestration/aider-adapter.js +319 -0
- package/dist/infrastructure/orchestration/artifacts-extractor.js +175 -0
- package/dist/infrastructure/orchestration/claude-code-adapter.js +352 -0
- package/dist/infrastructure/orchestration/codex-adapter.js +310 -0
- package/dist/infrastructure/orchestration/generic-cli-adapter.js +553 -0
- package/dist/infrastructure/orchestration/opencode-adapter.js +275 -0
- package/dist/infrastructure/orchestration/progress-aggregator.js +189 -0
- package/dist/infrastructure/orchestration/readiness.js +106 -0
- package/dist/infrastructure/orchestration/session-manager.js +272 -0
- package/dist/infrastructure/orchestration/session-persistence.js +109 -0
- package/dist/infrastructure/protocols/mcp-helpers.js +10 -30
- package/dist/infrastructure/protocols/mcp-server-impl.js +359 -21
- package/dist/infrastructure/protocols/ui-page.js +1827 -0
- package/dist/infrastructure/security/file-collection.js +115 -0
- package/dist/infrastructure/security/trust-scorer.js +301 -56
- package/dist/infrastructure/storage/task-repository.js +8 -7
- package/dist/monitoring.js +10 -49
- package/dist/presentation/cli/commands/help-command.js +96 -139
- package/dist/presentation/cli/commands/hook-command.js +17 -24
- package/dist/presentation/cli/commands/report-command.js +59 -72
- package/dist/presentation/cli/commands/setup-command.js +4 -4
- package/dist/presentation/cli/commands/status-command.js +334 -43
- package/dist/presentation/cli/commands/trust-command.js +115 -99
- package/dist/presentation/cli/error-display.js +17 -21
- package/dist/ui.js +17 -12
- package/package.json +35 -67
- package/dist/agents/base.js +0 -101
- package/dist/agents/orchestrator-model-driven.js +0 -141
- package/dist/agents/react-orchestrator-agent.js +0 -54
- package/dist/application/agents/execution-agent.js +0 -508
- package/dist/application/agents/multi-agent-orchestrator.js +0 -295
- package/dist/application/agents/planning-agent.js +0 -433
- package/dist/application/agents/validation-agent.js +0 -317
- package/dist/application/architectures/plan-and-act.js +0 -242
- package/dist/application/index.js +0 -12
- package/dist/application/services/agent-factory.js +0 -28
- package/dist/application/services/dependency-container.js +0 -596
- package/dist/application/services/git-context-service.js +0 -83
- package/dist/application/services/intelligent-router.js +0 -934
- package/dist/application/services/tool-executor-service.js +0 -94
- package/dist/application/use-cases/ask-question-use-case.js +0 -338
- package/dist/application/use-cases/edit-file-use-case.js +0 -830
- package/dist/application/use-cases/explain-file-use-case.js +0 -50
- package/dist/application/use-cases/index-codebase-use-case.js +0 -113
- package/dist/application/use-cases/planning-use-case.js +0 -276
- package/dist/application/use-cases/react-orchestration-use-case.js +0 -329
- package/dist/application/use-cases/reflexion-use-case.js +0 -30
- package/dist/application/workflows/deterministic-workflows.js +0 -189
- package/dist/ast-parser.js +0 -331
- package/dist/cache.js +0 -180
- package/dist/chat.js +0 -251
- package/dist/code-analysis.js +0 -327
- package/dist/context.js +0 -187
- package/dist/docs.js +0 -146
- package/dist/domain/entities/code-chunk.js +0 -6
- package/dist/domain/entities/decision.js +0 -9
- package/dist/domain/entities/edit.js +0 -6
- package/dist/domain/entities/knowledge-node.js +0 -9
- package/dist/domain/entities/knowledge-preservation.js +0 -10
- package/dist/domain/entities/memory.js +0 -6
- package/dist/domain/entities/pattern.js +0 -7
- package/dist/domain/entities/plan.js +0 -6
- package/dist/domain/entities/query.js +0 -6
- package/dist/domain/errors/embeddings-not-found-error.js +0 -13
- package/dist/domain/index.js +0 -19
- package/dist/domain/interfaces/ai-service.interface.js +0 -6
- package/dist/domain/interfaces/code-analyzer.interface.js +0 -6
- package/dist/domain/interfaces/decision-repository.interface.js +0 -9
- package/dist/domain/interfaces/embedding-repository.interface.js +0 -6
- package/dist/domain/interfaces/knowledge-graph-repository.interface.js +0 -9
- package/dist/domain/interfaces/knowledge-preservation-repository.interface.js +0 -8
- package/dist/domain/interfaces/memory-repository.interface.js +0 -6
- package/dist/domain/interfaces/pattern-repository.interface.js +0 -6
- package/dist/domain/interfaces/verification-service.interface.js +0 -6
- package/dist/domain/services/cross-team-pattern-sharing.js +0 -125
- package/dist/domain/services/decision-recorder.js +0 -223
- package/dist/domain/services/decision-retriever.js +0 -133
- package/dist/domain/services/environment-mode-manager.js +0 -22
- package/dist/domain/services/graded-memory-activation.js +0 -69
- package/dist/domain/services/knowledge-access.js +0 -132
- package/dist/domain/services/knowledge-extractor.js +0 -247
- package/dist/domain/services/knowledge-graph-builder.js +0 -268
- package/dist/domain/services/knowledge-graph-query.js +0 -187
- package/dist/domain/services/memory-retriever.js +0 -82
- package/dist/domain/services/memory-synthesizer.js +0 -91
- package/dist/domain/services/pattern-extractor.js +0 -442
- package/dist/domain/services/query-intent-classifier.js +0 -140
- package/dist/domain/services/react-loop.js +0 -186
- package/dist/domain/services/risk-tier-detector.js +0 -78
- package/dist/edit.js +0 -319
- package/dist/embed.js +0 -459
- package/dist/formatter.js +0 -168
- package/dist/git.js +0 -198
- package/dist/infrastructure/ai/cohere-ai-service.js +0 -607
- package/dist/infrastructure/ai/command-r-evaluation.js +0 -206
- package/dist/infrastructure/ai/model-config.js +0 -84
- package/dist/infrastructure/ai/provider-ai-service.js +0 -477
- package/dist/infrastructure/cache/embedding-cache.js +0 -175
- package/dist/infrastructure/cache/query-result-cache.js +0 -66
- package/dist/infrastructure/cache/response-cache.js +0 -48
- package/dist/infrastructure/cache/security-scan-cache.js +0 -47
- package/dist/infrastructure/chunking/ast-code-chunker.js +0 -19
- package/dist/infrastructure/chunking/code-aware-chunker.js +0 -397
- package/dist/infrastructure/context/context-compressor.js +0 -329
- package/dist/infrastructure/context/conversation-context.js +0 -128
- package/dist/infrastructure/context/session-manager.js +0 -94
- package/dist/infrastructure/cost/cost-tracker.js +0 -360
- package/dist/infrastructure/file-scanner/file-scanner.js +0 -106
- package/dist/infrastructure/governance/nist-ai-rmf.js +0 -292
- package/dist/infrastructure/governance/policy-as-code.js +0 -258
- package/dist/infrastructure/governance/prompt-to-code-lineage.js +0 -239
- package/dist/infrastructure/index.js +0 -7
- package/dist/infrastructure/observability/prompt-versioner.js +0 -145
- package/dist/infrastructure/protocols/a2a-metadata.js +0 -137
- package/dist/infrastructure/protocols/a2a-protocol.js +0 -314
- package/dist/infrastructure/protocols/mcp-oauth.js +0 -184
- package/dist/infrastructure/protocols/mcp-server.js +0 -333
- package/dist/infrastructure/protocols/streaming-handler.js +0 -103
- package/dist/infrastructure/providers/cohere-provider.js +0 -444
- package/dist/infrastructure/providers/fake-provider.js +0 -130
- package/dist/infrastructure/providers/local-llm-provider.js +0 -330
- package/dist/infrastructure/providers/model-config.types.js +0 -9
- package/dist/infrastructure/providers/model-provider.interface.js +0 -8
- package/dist/infrastructure/providers/openai-provider.js +0 -413
- package/dist/infrastructure/providers/openrouter-provider.js +0 -399
- package/dist/infrastructure/providers/operation-provider-resolver.js +0 -105
- package/dist/infrastructure/providers/provider-config-loader.js +0 -120
- package/dist/infrastructure/providers/provider-registry.js +0 -88
- package/dist/infrastructure/safety/pattern-detector.js +0 -133
- package/dist/infrastructure/security/ai-sast-scanner.js +0 -290
- package/dist/infrastructure/security/docker-sandbox.js +0 -178
- package/dist/infrastructure/security/enhanced-security-gate.js +0 -151
- package/dist/infrastructure/security/license-scanner.js +0 -167
- package/dist/infrastructure/security/provider-bias-detector.js +0 -164
- package/dist/infrastructure/security/sandbox-executor.js +0 -64
- package/dist/infrastructure/serialization/toon-serializer.js +0 -119
- package/dist/infrastructure/storage/memory-stream-service.js +0 -204
- package/dist/infrastructure/storage/plan-repository.js +0 -96
- package/dist/infrastructure/storage/sqlite-decision-repository.js +0 -232
- package/dist/infrastructure/storage/sqlite-embedding-repository.js +0 -311
- package/dist/infrastructure/storage/sqlite-knowledge-graph-repository.js +0 -417
- package/dist/infrastructure/storage/sqlite-knowledge-preservation-repository.js +0 -230
- package/dist/infrastructure/storage/sqlite-memory-repository.js +0 -229
- package/dist/infrastructure/storage/sqlite-pattern-repository.js +0 -249
- package/dist/infrastructure/storage/task-helpers.js +0 -197
- package/dist/infrastructure/telemetry/telemetry-service.js +0 -167
- package/dist/infrastructure/ux/appropriate-friction.js +0 -213
- package/dist/infrastructure/ux/bi-directional-learning.js +0 -337
- package/dist/infrastructure/ux/capability-boundaries.js +0 -42
- package/dist/infrastructure/ux/comprehensive-formatter.js +0 -117
- package/dist/infrastructure/ux/contextual-feature-discovery.js +0 -10
- package/dist/infrastructure/ux/expectation-management.js +0 -327
- package/dist/infrastructure/ux/feature-discovery.js +0 -14
- package/dist/infrastructure/ux/feedback-prompt.js +0 -45
- package/dist/infrastructure/ux/hitl-validation.js +0 -297
- package/dist/infrastructure/ux/progress-indicator.js +0 -116
- package/dist/infrastructure/ux/progressive-disclosure.js +0 -236
- package/dist/infrastructure/ux/review-checkpoint.js +0 -72
- package/dist/infrastructure/ux/staged-feature-intro.js +0 -24
- package/dist/infrastructure/ux/stream-markdown.js +0 -151
- package/dist/infrastructure/ux/syntax-highlighter.js +0 -91
- package/dist/infrastructure/ux/team-standards.js +0 -196
- package/dist/infrastructure/ux/transparency.js +0 -71
- package/dist/infrastructure/validation/agent-feedback.js +0 -55
- package/dist/infrastructure/validation/agent-validation-helper.js +0 -137
- package/dist/infrastructure/validation/review-handler.js +0 -40
- package/dist/infrastructure/validation/summary-aggregator.js +0 -70
- package/dist/infrastructure/validation/summary-extractor.js +0 -45
- package/dist/infrastructure/validation/trace-summary.js +0 -52
- package/dist/infrastructure/verification/verification-service.js +0 -47
- package/dist/infrastructure/xai/attention-visualizer.js +0 -172
- package/dist/infrastructure/xai/cot-visualizer.js +0 -283
- package/dist/infrastructure/xai/decision-tree-log.js +0 -212
- package/dist/infrastructure/xai/interactive-xai.js +0 -260
- package/dist/infrastructure/xai/uncertainty-quantifier.js +0 -198
- package/dist/intelligent-retrieval.js +0 -272
- package/dist/intent/classifier.js +0 -2
- package/dist/intent/context.js +0 -2
- package/dist/iterative-refinement.js +0 -189
- package/dist/learning.js +0 -232
- package/dist/log.js +0 -31
- package/dist/migrate.js +0 -133
- package/dist/parallel-processor.js +0 -530
- package/dist/planner.js +0 -198
- package/dist/policy.js +0 -26
- package/dist/presentation/cli/commands/ask-command.js +0 -314
- package/dist/presentation/cli/commands/cost-command.js +0 -191
- package/dist/presentation/cli/commands/decision-command.js +0 -207
- package/dist/presentation/cli/commands/docs-command.js +0 -25
- package/dist/presentation/cli/commands/fix-command.js +0 -53
- package/dist/presentation/cli/commands/knowledge-command.js +0 -129
- package/dist/presentation/cli/commands/learning-dashboard-command.js +0 -183
- package/dist/presentation/cli/commands/models-command.js +0 -194
- package/dist/presentation/cli/commands/orchestrate-command.js +0 -207
- package/dist/presentation/cli/commands/plan-command.js +0 -246
- package/dist/presentation/cli/commands/product-command.js +0 -199
- package/dist/presentation/cli/commands/react-command.js +0 -181
- package/dist/presentation/cli/commands/review-command.js +0 -154
- package/dist/presentation/cli/commands/run-command.js +0 -188
- package/dist/presentation/cli/commands/smart-command.js +0 -395
- package/dist/presentation/cli/commands/suggest-command.js +0 -138
- package/dist/presentation/cli/commands/trace-command.js +0 -129
- package/dist/presentation/cli/commands/undo-command.js +0 -150
- package/dist/query-optimizer.js +0 -205
- package/dist/refactor.js +0 -116
- package/dist/review.js +0 -206
- package/dist/search.js +0 -163
- package/dist/session.js +0 -652
- package/dist/task-verification.js +0 -336
- package/dist/testgen.js +0 -166
- package/dist/token-optimizer.js +0 -277
- package/dist/tools/bash.js +0 -213
- package/dist/tools/edit.js +0 -235
- package/dist/tools/executor.js +0 -153
- package/dist/tools/git-tool.js +0 -292
- package/dist/tools/parser.js +0 -158
- package/dist/tools/registry.js +0 -302
- package/dist/tools/search.js +0 -100
- package/dist/types.js +0 -2
- package/dist/utils/check-api-status.js +0 -100
- package/dist/utils/diff-parser.js +0 -162
- package/dist/verification/backup.js +0 -259
- package/dist/verification/compiler.js +0 -264
- package/dist/verification/index.js +0 -273
- package/dist/verification/test-runner.js +0 -379
package/dist/embed.js
DELETED
|
@@ -1,459 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, statSync, existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
-
import { join, relative, dirname } from 'path';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
import { config } from 'dotenv';
|
|
5
|
-
// CohereClient is lazy-loaded in getCohereClient() to avoid hard dependency
|
|
6
|
-
import initSqlJs from 'sql.js';
|
|
7
|
-
import { encoding_for_model } from 'tiktoken';
|
|
8
|
-
import { indexParallel } from './parallel-processor.js';
|
|
9
|
-
import { colors, createProgressBar, createTable, success, warning, info, formatPath, formatNumber, sectionHeader, newline, statusIndicator, } from './ui.js';
|
|
10
|
-
// Load .env from agent directory
|
|
11
|
-
try {
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
14
|
-
const agentDir = join(__dirname, '..');
|
|
15
|
-
config({ path: join(agentDir, '.env') });
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
// Fallback
|
|
19
|
-
}
|
|
20
|
-
config(); // Also try current directory
|
|
21
|
-
function detectEmbeddingProvider() {
|
|
22
|
-
if (process.env.OPENAI_API_KEY)
|
|
23
|
-
return 'openai';
|
|
24
|
-
if (process.env.COHERE_API_KEY)
|
|
25
|
-
return 'cohere';
|
|
26
|
-
return 'none';
|
|
27
|
-
}
|
|
28
|
-
// Lazy-init Cohere client only when needed
|
|
29
|
-
let _cohereClient = null;
|
|
30
|
-
function getCohereClient() {
|
|
31
|
-
if (!_cohereClient) {
|
|
32
|
-
const { CohereClient } = require('cohere-ai');
|
|
33
|
-
_cohereClient = new CohereClient({ token: process.env.COHERE_API_KEY || '' });
|
|
34
|
-
}
|
|
35
|
-
return _cohereClient;
|
|
36
|
-
}
|
|
37
|
-
import { getEmbeddingsDbPath } from './infrastructure/storage/embeddings-path.js';
|
|
38
|
-
/**
|
|
39
|
-
* @deprecated Legacy global DB path - use getEmbeddingsDbPath() instead
|
|
40
|
-
* This function and DB_PATH are only used by the legacy indexRepository() function.
|
|
41
|
-
* The active index command uses indexRepositoryParallel() which uses per-repo paths.
|
|
42
|
-
*/
|
|
43
|
-
function getLegacyDbPath() {
|
|
44
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
45
|
-
const __dirname = dirname(__filename);
|
|
46
|
-
const agentDir = join(__dirname, '..');
|
|
47
|
-
// Check if we're in the agent directory structure
|
|
48
|
-
if (existsSync(join(agentDir, 'package.json'))) {
|
|
49
|
-
return join(agentDir, 'data', 'embeddings.sqlite');
|
|
50
|
-
}
|
|
51
|
-
// Otherwise use current directory
|
|
52
|
-
return join(process.cwd(), 'agent', 'data', 'embeddings.sqlite');
|
|
53
|
-
}
|
|
54
|
-
// Legacy DB_PATH - only used by deprecated indexRepository() function
|
|
55
|
-
// Active CLI uses indexRepositoryParallel() with per-repo paths
|
|
56
|
-
const DB_PATH = getLegacyDbPath();
|
|
57
|
-
const CHUNK_SIZE = 300; // target tokens per chunk
|
|
58
|
-
const OVERLAP = 50; // overlap tokens between chunks
|
|
59
|
-
const enc = encoding_for_model('gpt-3.5-turbo');
|
|
60
|
-
function shouldIgnorePath(filepath) {
|
|
61
|
-
const ignorePatterns = [
|
|
62
|
-
'node_modules',
|
|
63
|
-
'.git',
|
|
64
|
-
'dist',
|
|
65
|
-
'build',
|
|
66
|
-
'.next',
|
|
67
|
-
'coverage',
|
|
68
|
-
'.env',
|
|
69
|
-
'embeddings.sqlite',
|
|
70
|
-
'logs.jsonl',
|
|
71
|
-
'agent/data',
|
|
72
|
-
'agent/dist',
|
|
73
|
-
'agent/node_modules',
|
|
74
|
-
];
|
|
75
|
-
return ignorePatterns.some(pattern => filepath.includes(pattern));
|
|
76
|
-
}
|
|
77
|
-
function getAllFiles(dir, baseDir = dir) {
|
|
78
|
-
const files = [];
|
|
79
|
-
try {
|
|
80
|
-
const entries = readdirSync(dir);
|
|
81
|
-
for (const entry of entries) {
|
|
82
|
-
const fullPath = join(dir, entry);
|
|
83
|
-
const relPath = relative(baseDir, fullPath);
|
|
84
|
-
if (shouldIgnorePath(relPath)) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
const stat = statSync(fullPath);
|
|
88
|
-
if (stat.isDirectory()) {
|
|
89
|
-
files.push(...getAllFiles(fullPath, baseDir));
|
|
90
|
-
}
|
|
91
|
-
else if (stat.isFile()) {
|
|
92
|
-
// Only process text files
|
|
93
|
-
const ext = entry.split('.').pop()?.toLowerCase();
|
|
94
|
-
const textExtensions = [
|
|
95
|
-
'ts', 'tsx', 'js', 'jsx', 'json', 'md', 'txt', 'py', 'java', 'cpp', 'c', 'h',
|
|
96
|
-
'go', 'rs', 'rb', 'php', 'html', 'css', 'scss', 'sql', 'sh', 'yaml', 'yml',
|
|
97
|
-
'xml', 'toml', 'ini', 'conf', 'config'
|
|
98
|
-
];
|
|
99
|
-
if (ext && textExtensions.includes(ext)) {
|
|
100
|
-
files.push(fullPath);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
// Skip directories we can't read
|
|
107
|
-
}
|
|
108
|
-
return files;
|
|
109
|
-
}
|
|
110
|
-
function chunkText(text, targetTokens, overlap) {
|
|
111
|
-
const tokens = enc.encode(text);
|
|
112
|
-
const chunks = [];
|
|
113
|
-
if (tokens.length <= targetTokens) {
|
|
114
|
-
return [text];
|
|
115
|
-
}
|
|
116
|
-
let start = 0;
|
|
117
|
-
while (start < tokens.length) {
|
|
118
|
-
const end = Math.min(start + targetTokens, tokens.length);
|
|
119
|
-
const chunkTokens = tokens.slice(start, end);
|
|
120
|
-
const decoded = enc.decode(chunkTokens);
|
|
121
|
-
// Handle both string and Uint8Array return types
|
|
122
|
-
const chunkText = typeof decoded === 'string' ? decoded : new TextDecoder().decode(decoded);
|
|
123
|
-
chunks.push(chunkText);
|
|
124
|
-
if (end >= tokens.length)
|
|
125
|
-
break;
|
|
126
|
-
start = end - overlap;
|
|
127
|
-
}
|
|
128
|
-
return chunks;
|
|
129
|
-
}
|
|
130
|
-
async function embedTextOpenAI(text) {
|
|
131
|
-
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
132
|
-
method: 'POST',
|
|
133
|
-
headers: {
|
|
134
|
-
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
|
|
135
|
-
'Content-Type': 'application/json',
|
|
136
|
-
},
|
|
137
|
-
body: JSON.stringify({
|
|
138
|
-
input: text,
|
|
139
|
-
model: 'text-embedding-3-small',
|
|
140
|
-
}),
|
|
141
|
-
});
|
|
142
|
-
if (!response.ok) {
|
|
143
|
-
const errText = await response.text();
|
|
144
|
-
throw new Error(`OpenAI embedding error: ${response.status} ${errText}`);
|
|
145
|
-
}
|
|
146
|
-
const data = await response.json();
|
|
147
|
-
return data.data?.[0]?.embedding || [];
|
|
148
|
-
}
|
|
149
|
-
async function embedTextCohere(text) {
|
|
150
|
-
const cohere = getCohereClient();
|
|
151
|
-
const response = await cohere.embed({
|
|
152
|
-
texts: [text],
|
|
153
|
-
model: 'embed-english-v3.0',
|
|
154
|
-
inputType: 'search_document',
|
|
155
|
-
});
|
|
156
|
-
const embeddings = Array.isArray(response.embeddings)
|
|
157
|
-
? response.embeddings
|
|
158
|
-
: response.embeddings.embeddings || [];
|
|
159
|
-
return embeddings[0] || [];
|
|
160
|
-
}
|
|
161
|
-
async function embedText(text, retries = 3) {
|
|
162
|
-
const provider = detectEmbeddingProvider();
|
|
163
|
-
if (provider === 'none') {
|
|
164
|
-
throw new Error('No embedding API key found. Set OPENAI_API_KEY or COHERE_API_KEY to use index/ask/fix commands.');
|
|
165
|
-
}
|
|
166
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
167
|
-
try {
|
|
168
|
-
if (provider === 'openai') {
|
|
169
|
-
return await embedTextOpenAI(text);
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
return await embedTextCohere(text);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
const isRateLimit = error?.status === 429 || error?.message?.includes('429') || error?.message?.includes('rate limit');
|
|
177
|
-
if (isRateLimit && attempt < retries - 1) {
|
|
178
|
-
const waitTime = Math.min(Math.pow(2, attempt) * 1000, 60000);
|
|
179
|
-
console.log(warning(`Rate limited, waiting ${waitTime / 1000}s before retry...`));
|
|
180
|
-
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
throw new Error(`Embedding error (${provider}): ${error instanceof Error ? error.message : String(error)}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
throw new Error('Embedding failed after retries');
|
|
187
|
-
}
|
|
188
|
-
function cosineSimilarity(a, b) {
|
|
189
|
-
if (a.length !== b.length)
|
|
190
|
-
return 0;
|
|
191
|
-
let dotProduct = 0;
|
|
192
|
-
let normA = 0;
|
|
193
|
-
let normB = 0;
|
|
194
|
-
for (let i = 0; i < a.length; i++) {
|
|
195
|
-
dotProduct += a[i] * b[i];
|
|
196
|
-
normA += a[i] * a[i];
|
|
197
|
-
normB += b[i] * b[i];
|
|
198
|
-
}
|
|
199
|
-
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
200
|
-
}
|
|
201
|
-
export async function indexRepository(repoPath = process.cwd()) {
|
|
202
|
-
sectionHeader('Scanning Repository');
|
|
203
|
-
const files = getAllFiles(repoPath, repoPath);
|
|
204
|
-
console.log(info(`Found ${formatNumber(files.length)} files to index`));
|
|
205
|
-
newline();
|
|
206
|
-
// Initialize SQL.js
|
|
207
|
-
const SQL = await initSqlJs();
|
|
208
|
-
let db;
|
|
209
|
-
// Load existing database or create new one
|
|
210
|
-
if (existsSync(DB_PATH)) {
|
|
211
|
-
const buffer = readFileSync(DB_PATH);
|
|
212
|
-
db = new SQL.Database(buffer);
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
db = new SQL.Database();
|
|
216
|
-
}
|
|
217
|
-
// Create table
|
|
218
|
-
db.run(`
|
|
219
|
-
CREATE TABLE IF NOT EXISTS embeddings (
|
|
220
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
221
|
-
filepath TEXT NOT NULL,
|
|
222
|
-
chunkIndex INTEGER NOT NULL,
|
|
223
|
-
content TEXT NOT NULL,
|
|
224
|
-
embedding TEXT NOT NULL
|
|
225
|
-
)
|
|
226
|
-
`);
|
|
227
|
-
db.run(`
|
|
228
|
-
CREATE INDEX IF NOT EXISTS idx_filepath ON embeddings(filepath)
|
|
229
|
-
`);
|
|
230
|
-
// Clear existing data
|
|
231
|
-
db.run('DELETE FROM embeddings');
|
|
232
|
-
const insertStmt = db.prepare(`
|
|
233
|
-
INSERT INTO embeddings (filepath, chunkIndex, content, embedding)
|
|
234
|
-
VALUES (?, ?, ?, ?)
|
|
235
|
-
`);
|
|
236
|
-
let totalChunks = 0;
|
|
237
|
-
const fileResults = [];
|
|
238
|
-
// Create progress bar
|
|
239
|
-
const progressBar = createProgressBar(files.length, colors.dim('Processing') + ' |{bar}| ' + colors.cyan('{percentage}%') + ' | {value}/{total}');
|
|
240
|
-
sectionHeader('Processing Files');
|
|
241
|
-
for (let i = 0; i < files.length; i++) {
|
|
242
|
-
const filepath = files[i];
|
|
243
|
-
const relPath = relative(repoPath, filepath);
|
|
244
|
-
try {
|
|
245
|
-
const content = readFileSync(filepath, 'utf-8');
|
|
246
|
-
const chunks = chunkText(content, CHUNK_SIZE, OVERLAP);
|
|
247
|
-
let fileChunks = 0;
|
|
248
|
-
let fileErrors = 0;
|
|
249
|
-
for (let chunkIdx = 0; chunkIdx < chunks.length; chunkIdx++) {
|
|
250
|
-
const chunk = chunks[chunkIdx];
|
|
251
|
-
try {
|
|
252
|
-
const embedding = await embedText(chunk);
|
|
253
|
-
insertStmt.run([
|
|
254
|
-
relPath,
|
|
255
|
-
chunkIdx,
|
|
256
|
-
chunk,
|
|
257
|
-
JSON.stringify(embedding),
|
|
258
|
-
]);
|
|
259
|
-
fileChunks++;
|
|
260
|
-
// Rate limiting: delay between chunks to stay under 40/min limit
|
|
261
|
-
// 40 calls/min = 1.5s per call, use 2s to be safe
|
|
262
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
263
|
-
}
|
|
264
|
-
catch (err) {
|
|
265
|
-
fileErrors++;
|
|
266
|
-
// Continue with next chunk instead of failing entire file
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
totalChunks += fileChunks;
|
|
270
|
-
if (fileErrors === 0) {
|
|
271
|
-
fileResults.push({
|
|
272
|
-
file: relPath,
|
|
273
|
-
chunks: fileChunks,
|
|
274
|
-
status: statusIndicator('success') + ' Done',
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
fileResults.push({
|
|
279
|
-
file: relPath,
|
|
280
|
-
chunks: fileChunks,
|
|
281
|
-
status: statusIndicator('warning') + ` Done (${fileErrors} errors)`,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
progressBar.update(i + 1);
|
|
285
|
-
}
|
|
286
|
-
catch (err) {
|
|
287
|
-
fileResults.push({
|
|
288
|
-
file: relPath,
|
|
289
|
-
chunks: 0,
|
|
290
|
-
status: statusIndicator('error') + ' Failed',
|
|
291
|
-
});
|
|
292
|
-
progressBar.update(i + 1);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
progressBar.stop();
|
|
296
|
-
insertStmt.free();
|
|
297
|
-
// Save database to file
|
|
298
|
-
const data = db.export();
|
|
299
|
-
const buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
300
|
-
writeFileSync(DB_PATH, buffer);
|
|
301
|
-
db.close();
|
|
302
|
-
newline();
|
|
303
|
-
sectionHeader('Indexing Results');
|
|
304
|
-
// Display file results table
|
|
305
|
-
const fileTable = createTable(['File', 'Chunks', 'Status'], fileResults.map(r => [
|
|
306
|
-
formatPath(r.file),
|
|
307
|
-
formatNumber(r.chunks),
|
|
308
|
-
r.status,
|
|
309
|
-
]));
|
|
310
|
-
console.log(fileTable.toString());
|
|
311
|
-
newline();
|
|
312
|
-
// Summary
|
|
313
|
-
const successful = fileResults.filter(r => r.status.includes('Done')).length;
|
|
314
|
-
const failed = fileResults.filter(r => r.status.includes('Failed')).length;
|
|
315
|
-
sectionHeader('Summary');
|
|
316
|
-
console.log(createTable(['Metric', 'Value'], [
|
|
317
|
-
['Total Files', formatNumber(files.length)],
|
|
318
|
-
['Successful', statusIndicator('success') + ' ' + formatNumber(successful)],
|
|
319
|
-
['Failed', failed > 0 ? statusIndicator('error') + ' ' + formatNumber(failed) : statusIndicator('success') + ' 0'],
|
|
320
|
-
['Total Chunks', formatNumber(totalChunks)],
|
|
321
|
-
['Database Size', colors.cyan(`${(buffer.length / 1024 / 1024).toFixed(2)} MB`)],
|
|
322
|
-
]).toString());
|
|
323
|
-
newline();
|
|
324
|
-
console.log(success(`Indexing complete: ${formatNumber(totalChunks)} chunks indexed`));
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* NEW: Parallel indexing with caching
|
|
328
|
-
*/
|
|
329
|
-
export async function indexRepositoryParallel(repoPath, options = {}) {
|
|
330
|
-
const targetDir = repoPath || process.cwd();
|
|
331
|
-
// Find all code files
|
|
332
|
-
const files = getAllFiles(targetDir, targetDir);
|
|
333
|
-
if (files.length === 0) {
|
|
334
|
-
console.log(warning('No code files found to index.'));
|
|
335
|
-
return {
|
|
336
|
-
indexed: 0,
|
|
337
|
-
cached: 0,
|
|
338
|
-
totalChunks: 0,
|
|
339
|
-
timeMs: 0,
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
console.log(info(`Found ${formatNumber(files.length)} files to index`));
|
|
343
|
-
console.log(info('Using parallel processing with caching...'));
|
|
344
|
-
newline();
|
|
345
|
-
// Use parallel processor to get embeddings
|
|
346
|
-
// Auto-use parallel for repos with >100 files
|
|
347
|
-
const result = await indexParallel(files, {
|
|
348
|
-
maxConcurrency: options.maxConcurrency || (files.length > 100 ? 10 : 5),
|
|
349
|
-
useCache: options.useCache !== false,
|
|
350
|
-
cacheDir: join(targetDir, '.codehere-cache'),
|
|
351
|
-
sequential: files.length <= 100, // Only sequential for very small repos
|
|
352
|
-
});
|
|
353
|
-
// Now save to SQLite database
|
|
354
|
-
// Use per-repo database path for codebase isolation
|
|
355
|
-
const pathInfo = getEmbeddingsDbPath(targetDir);
|
|
356
|
-
const dbPath = pathInfo.dbPath;
|
|
357
|
-
console.log(info(`Database path: ${dbPath}`));
|
|
358
|
-
// Ensure cache directory exists (already created by getEmbeddingsDbPath, but double-check)
|
|
359
|
-
const dbDir = dirname(dbPath);
|
|
360
|
-
if (!existsSync(dbDir)) {
|
|
361
|
-
console.log(info(`Creating cache directory: ${dbDir}`));
|
|
362
|
-
mkdirSync(dbDir, { recursive: true });
|
|
363
|
-
}
|
|
364
|
-
console.log(info('Initializing SQLite database...'));
|
|
365
|
-
const SQL = await initSqlJs();
|
|
366
|
-
let db;
|
|
367
|
-
// Load existing database or create new one
|
|
368
|
-
if (existsSync(dbPath)) {
|
|
369
|
-
const buffer = readFileSync(dbPath);
|
|
370
|
-
db = new SQL.Database(buffer);
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
db = new SQL.Database();
|
|
374
|
-
}
|
|
375
|
-
// Create table
|
|
376
|
-
db.run(`
|
|
377
|
-
CREATE TABLE IF NOT EXISTS embeddings (
|
|
378
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
379
|
-
filepath TEXT NOT NULL,
|
|
380
|
-
chunkIndex INTEGER NOT NULL,
|
|
381
|
-
content TEXT NOT NULL,
|
|
382
|
-
embedding TEXT NOT NULL
|
|
383
|
-
)
|
|
384
|
-
`);
|
|
385
|
-
db.run(`
|
|
386
|
-
CREATE INDEX IF NOT EXISTS idx_filepath ON embeddings(filepath)
|
|
387
|
-
`);
|
|
388
|
-
// Clear existing data
|
|
389
|
-
db.run('DELETE FROM embeddings');
|
|
390
|
-
const insertStmt = db.prepare(`
|
|
391
|
-
INSERT INTO embeddings (filepath, chunkIndex, content, embedding)
|
|
392
|
-
VALUES (?, ?, ?, ?)
|
|
393
|
-
`);
|
|
394
|
-
// Load cached embeddings and write to database
|
|
395
|
-
const cacheDir = join(targetDir, '.codehere-cache');
|
|
396
|
-
let dbChunks = 0;
|
|
397
|
-
if (existsSync(cacheDir)) {
|
|
398
|
-
const cacheFiles = readdirSync(cacheDir).filter(f => f.endsWith('.json'));
|
|
399
|
-
console.log(info(`Loading ${cacheFiles.length} cache files into database...`));
|
|
400
|
-
for (const cacheFile of cacheFiles) {
|
|
401
|
-
try {
|
|
402
|
-
const cachePath = join(cacheDir, cacheFile);
|
|
403
|
-
const cacheEntry = JSON.parse(readFileSync(cachePath, 'utf-8'));
|
|
404
|
-
if (cacheEntry.chunks && Array.isArray(cacheEntry.chunks)) {
|
|
405
|
-
// Handle both absolute and relative paths
|
|
406
|
-
let relPath = cacheEntry.filepath || cacheFile.replace('.json', '').replace(/_/g, '/');
|
|
407
|
-
if (relPath.startsWith('/') || relPath.startsWith(targetDir)) {
|
|
408
|
-
// Absolute path - make it relative
|
|
409
|
-
relPath = relative(targetDir, relPath);
|
|
410
|
-
}
|
|
411
|
-
// If still absolute or empty, use filename
|
|
412
|
-
if (!relPath || relPath.startsWith('/')) {
|
|
413
|
-
relPath = cacheFile.replace('.json', '').replace(/_/g, '/');
|
|
414
|
-
}
|
|
415
|
-
for (let i = 0; i < cacheEntry.chunks.length; i++) {
|
|
416
|
-
const chunk = cacheEntry.chunks[i];
|
|
417
|
-
if (chunk.content && chunk.embedding) {
|
|
418
|
-
insertStmt.run([
|
|
419
|
-
relPath,
|
|
420
|
-
i,
|
|
421
|
-
chunk.content,
|
|
422
|
-
JSON.stringify(chunk.embedding),
|
|
423
|
-
]);
|
|
424
|
-
dbChunks++;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
catch (err) {
|
|
430
|
-
console.log(warning(`Error processing cache file ${cacheFile}: ${err instanceof Error ? err.message : String(err)}`));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
console.log(warning(`Cache directory not found: ${cacheDir}`));
|
|
436
|
-
}
|
|
437
|
-
insertStmt.free();
|
|
438
|
-
// Save database to file
|
|
439
|
-
try {
|
|
440
|
-
const data = db.export();
|
|
441
|
-
const buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
442
|
-
writeFileSync(dbPath, buffer);
|
|
443
|
-
db.close();
|
|
444
|
-
console.log(success(`Database saved to: ${dbPath}`));
|
|
445
|
-
}
|
|
446
|
-
catch (err) {
|
|
447
|
-
db.close();
|
|
448
|
-
throw new Error(`Failed to save database to ${dbPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
449
|
-
}
|
|
450
|
-
console.log(success(`Parallel indexing complete:`));
|
|
451
|
-
console.log(` • Indexed: ${formatNumber(result.indexed)} files`);
|
|
452
|
-
console.log(` • Cached: ${formatNumber(result.cached)} files`);
|
|
453
|
-
console.log(` • Total chunks: ${formatNumber(result.totalChunks)}`);
|
|
454
|
-
console.log(` • Saved to database: ${formatNumber(dbChunks)} chunks`);
|
|
455
|
-
console.log(` • Database: ${dbPath}`);
|
|
456
|
-
console.log(` • Time: ${formatNumber(result.timeMs / 1000)}s`);
|
|
457
|
-
return result;
|
|
458
|
-
}
|
|
459
|
-
//# sourceMappingURL=embed.js.map
|
package/dist/formatter.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terminal Markdown Formatter
|
|
3
|
-
* Converts markdown to beautifully formatted terminal output
|
|
4
|
-
*/
|
|
5
|
-
import { colors } from './ui.js';
|
|
6
|
-
import { formatCodeBlockWithHighlight } from './infrastructure/ux/syntax-highlighter.js';
|
|
7
|
-
/**
|
|
8
|
-
* Format markdown text for terminal display
|
|
9
|
-
*/
|
|
10
|
-
export function formatMarkdown(text) {
|
|
11
|
-
if (!text)
|
|
12
|
-
return '';
|
|
13
|
-
let formatted = text;
|
|
14
|
-
// Remove markdown code blocks but preserve content with syntax highlighting
|
|
15
|
-
formatted = formatted.replace(/```(\w*)\n?([\s\S]*?)```/g, (match, lang, code) => {
|
|
16
|
-
try {
|
|
17
|
-
// Use formatCodeBlock for better formatting with borders
|
|
18
|
-
return '\n' + formatCodeBlock(code.trim(), lang || 'text') + '\n';
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return '\n' + colors.cyan(code.trim()) + '\n';
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
// Remove inline code but style it
|
|
25
|
-
formatted = formatted.replace(/`([^`]+)`/g, (match, code) => {
|
|
26
|
-
return colors.cyan(code);
|
|
27
|
-
});
|
|
28
|
-
// Convert headers to bold
|
|
29
|
-
formatted = formatted.replace(/^### (.*$)/gim, (match, text) => {
|
|
30
|
-
return '\n' + colors.bold(text) + '\n';
|
|
31
|
-
});
|
|
32
|
-
formatted = formatted.replace(/^## (.*$)/gim, (match, text) => {
|
|
33
|
-
return '\n' + colors.bold(text) + '\n';
|
|
34
|
-
});
|
|
35
|
-
formatted = formatted.replace(/^# (.*$)/gim, (match, text) => {
|
|
36
|
-
return '\n' + colors.bold(text) + '\n';
|
|
37
|
-
});
|
|
38
|
-
// Convert bold (**text** or __text__) to colored bold
|
|
39
|
-
// But preserve numbered lists in bold (e.g., **1. Title** -> 1. Title in bold)
|
|
40
|
-
formatted = formatted.replace(/\*\*(\d+)\. (.+?)\*\*/g, (match, num, text) => {
|
|
41
|
-
return colors.bold(`${num}. ${text}`);
|
|
42
|
-
});
|
|
43
|
-
formatted = formatted.replace(/\*\*(.+?)\*\*/g, (match, text) => {
|
|
44
|
-
return colors.bold(text);
|
|
45
|
-
});
|
|
46
|
-
formatted = formatted.replace(/__(.+?)__/g, (match, text) => {
|
|
47
|
-
return colors.bold(text);
|
|
48
|
-
});
|
|
49
|
-
// Convert italic (*text* or _text_) to dim
|
|
50
|
-
formatted = formatted.replace(/\*(.+?)\*/g, (match, text) => {
|
|
51
|
-
// Don't convert if it's part of **bold**
|
|
52
|
-
if (text.includes('*'))
|
|
53
|
-
return match;
|
|
54
|
-
return colors.dim(text);
|
|
55
|
-
});
|
|
56
|
-
formatted = formatted.replace(/_(.+?)_/g, (match, text) => {
|
|
57
|
-
// Don't convert if it's part of __bold__
|
|
58
|
-
if (text.includes('_'))
|
|
59
|
-
return match;
|
|
60
|
-
return colors.dim(text);
|
|
61
|
-
});
|
|
62
|
-
// Convert bullet points to clean bullets
|
|
63
|
-
formatted = formatted.replace(/^[\*\-\+] (.+)$/gim, (match, text) => {
|
|
64
|
-
return ' • ' + text.trim();
|
|
65
|
-
});
|
|
66
|
-
// Convert numbered lists - preserve numbering with proper indentation
|
|
67
|
-
// Handle both plain numbered lists and those that might have been bold
|
|
68
|
-
formatted = formatted.replace(/^(\d+)\. (.+)$/gim, (match, num, text) => {
|
|
69
|
-
// If text is already bold (from previous processing), keep it bold
|
|
70
|
-
const trimmed = text.trim();
|
|
71
|
-
return ` ${num}. ${trimmed}`;
|
|
72
|
-
});
|
|
73
|
-
// Clean up multiple newlines (max 2)
|
|
74
|
-
formatted = formatted.replace(/\n{3,}/g, '\n\n');
|
|
75
|
-
// Remove markdown links but keep text
|
|
76
|
-
formatted = formatted.replace(/\[([^\]]+)\]\([^\)]+\)/g, (match, text) => {
|
|
77
|
-
return text;
|
|
78
|
-
});
|
|
79
|
-
// Remove horizontal rules
|
|
80
|
-
formatted = formatted.replace(/^---+\s*$/gim, '');
|
|
81
|
-
// Clean up any remaining markdown artifacts
|
|
82
|
-
formatted = formatted.replace(/\[([^\]]+)\]\[[^\]]+\]/g, '$1'); // Reference links
|
|
83
|
-
formatted = formatted.replace(/!\[([^\]]*)\]\([^\)]+\)/g, '$1'); // Images
|
|
84
|
-
return formatted.trim();
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Format code block for terminal with syntax highlighting
|
|
88
|
-
*/
|
|
89
|
-
export function formatCodeBlock(code, language, filepath) {
|
|
90
|
-
try {
|
|
91
|
-
return formatCodeBlockWithHighlight(code, language, filepath);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
// Fallback to basic formatting if highlighter not available
|
|
95
|
-
const lines = code.split('\n');
|
|
96
|
-
const maxWidth = process.stdout.columns || 80;
|
|
97
|
-
const indent = ' ';
|
|
98
|
-
let output = colors.dim('┌─ Code ──────────────────────────────────────┐\n');
|
|
99
|
-
for (const line of lines) {
|
|
100
|
-
// Truncate very long lines
|
|
101
|
-
const displayLine = line.length > maxWidth - 10
|
|
102
|
-
? line.substring(0, maxWidth - 13) + '...'
|
|
103
|
-
: line;
|
|
104
|
-
output += indent + colors.cyan(displayLine) + '\n';
|
|
105
|
-
}
|
|
106
|
-
output += colors.dim('└──────────────────────────────────────────────┘');
|
|
107
|
-
return output;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Format list items nicely
|
|
112
|
-
*/
|
|
113
|
-
export function formatList(items) {
|
|
114
|
-
return items.map(item => ' • ' + item.trim()).join('\n');
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Format response text with proper wrapping and formatting
|
|
118
|
-
*/
|
|
119
|
-
export function formatResponse(text, maxWidth = 80) {
|
|
120
|
-
if (!text)
|
|
121
|
-
return '';
|
|
122
|
-
// First format markdown
|
|
123
|
-
let formatted = formatMarkdown(text);
|
|
124
|
-
// Word wrap to terminal width
|
|
125
|
-
const lines = formatted.split('\n');
|
|
126
|
-
const wrapped = [];
|
|
127
|
-
for (const line of lines) {
|
|
128
|
-
if (line.length <= maxWidth) {
|
|
129
|
-
wrapped.push(line);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
// Wrap long lines
|
|
133
|
-
const words = line.split(' ');
|
|
134
|
-
let currentLine = '';
|
|
135
|
-
for (const word of words) {
|
|
136
|
-
if ((currentLine + word).length <= maxWidth) {
|
|
137
|
-
currentLine += (currentLine ? ' ' : '') + word;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
if (currentLine) {
|
|
141
|
-
wrapped.push(currentLine);
|
|
142
|
-
}
|
|
143
|
-
currentLine = word;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (currentLine) {
|
|
147
|
-
wrapped.push(currentLine);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return wrapped.join('\n');
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Clean and format AI response for display
|
|
155
|
-
*/
|
|
156
|
-
export function cleanResponse(response) {
|
|
157
|
-
if (!response)
|
|
158
|
-
return '';
|
|
159
|
-
let cleaned = response;
|
|
160
|
-
// Remove any leading/trailing markdown artifacts
|
|
161
|
-
cleaned = cleaned.trim();
|
|
162
|
-
// Remove markdown frontmatter if present
|
|
163
|
-
cleaned = cleaned.replace(/^---[\s\S]*?---\n/, '');
|
|
164
|
-
// Format the response
|
|
165
|
-
cleaned = formatResponse(cleaned);
|
|
166
|
-
return cleaned;
|
|
167
|
-
}
|
|
168
|
-
//# sourceMappingURL=formatter.js.map
|