erosolar-cli 1.7.55 → 1.7.57
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/shell/unifiedInputProcessor.d.ts +15 -12
- package/dist/shell/unifiedInputProcessor.d.ts.map +1 -1
- package/dist/shell/unifiedInputProcessor.js +45 -72
- package/dist/shell/unifiedInputProcessor.js.map +1 -1
- package/package.json +4 -4
- package/dist/active-stack-security.d.ts +0 -110
- package/dist/active-stack-security.js +0 -313
- package/dist/active-stack-security.js.map +0 -1
- package/dist/advanced-targeting.d.ts +0 -113
- package/dist/advanced-targeting.js +0 -252
- package/dist/advanced-targeting.js.map +0 -1
- package/dist/bin/adapters/node/index.js +0 -33
- package/dist/bin/adapters/types.js +0 -1
- package/dist/bin/alpha-zero/agentWrapper.js +0 -165
- package/dist/bin/alpha-zero/codeEvaluator.js +0 -272
- package/dist/bin/alpha-zero/competitiveRunner.js +0 -219
- package/dist/bin/alpha-zero/index.js +0 -98
- package/dist/bin/alpha-zero/introspection.js +0 -298
- package/dist/bin/alpha-zero/metricsTracker.js +0 -207
- package/dist/bin/alpha-zero/security/core.js +0 -269
- package/dist/bin/alpha-zero/security/google.js +0 -308
- package/dist/bin/alpha-zero/security/googleLoader.js +0 -40
- package/dist/bin/alpha-zero/security/index.js +0 -31
- package/dist/bin/alpha-zero/security/simulation.js +0 -274
- package/dist/bin/alpha-zero/selfModification.js +0 -231
- package/dist/bin/alpha-zero/types.js +0 -30
- package/dist/bin/bin/erosolar-optimized.js +0 -205
- package/dist/bin/capabilities/agentSpawningCapability.js +0 -116
- package/dist/bin/capabilities/bashCapability.js +0 -22
- package/dist/bin/capabilities/cloudCapability.js +0 -36
- package/dist/bin/capabilities/codeAnalysisCapability.js +0 -22
- package/dist/bin/capabilities/codeQualityCapability.js +0 -23
- package/dist/bin/capabilities/dependencySecurityCapability.js +0 -22
- package/dist/bin/capabilities/devCapability.js +0 -22
- package/dist/bin/capabilities/editCapability.js +0 -28
- package/dist/bin/capabilities/emailCapability.js +0 -20
- package/dist/bin/capabilities/enhancedGitCapability.js +0 -221
- package/dist/bin/capabilities/filesystemCapability.js +0 -22
- package/dist/bin/capabilities/globCapability.js +0 -28
- package/dist/bin/capabilities/interactionCapability.js +0 -20
- package/dist/bin/capabilities/learnCapability.js +0 -22
- package/dist/bin/capabilities/mcpCapability.js +0 -20
- package/dist/bin/capabilities/notebookCapability.js +0 -28
- package/dist/bin/capabilities/planningCapability.js +0 -27
- package/dist/bin/capabilities/refactoringCapability.js +0 -23
- package/dist/bin/capabilities/repoChecksCapability.js +0 -22
- package/dist/bin/capabilities/searchCapability.js +0 -22
- package/dist/bin/capabilities/skillCapability.js +0 -76
- package/dist/bin/capabilities/taskManagementCapability.js +0 -20
- package/dist/bin/capabilities/testingCapability.js +0 -23
- package/dist/bin/capabilities/toolManifest.js +0 -159
- package/dist/bin/capabilities/toolRegistry.js +0 -114
- package/dist/bin/capabilities/webCapability.js +0 -20
- package/dist/bin/config.js +0 -139
- package/dist/bin/contracts/v1/agent.js +0 -7
- package/dist/bin/contracts/v1/agentProfileManifest.js +0 -8
- package/dist/bin/contracts/v1/agentRules.js +0 -9
- package/dist/bin/contracts/v1/toolAccess.js +0 -8
- package/dist/bin/erosolar-optimized.d.ts +0 -12
- package/dist/bin/erosolar-optimized.d.ts.map +0 -1
- package/dist/bin/erosolar-optimized.js +0 -239
- package/dist/bin/erosolar-optimized.js.map +0 -1
- package/dist/bin/headless/headlessApp.js +0 -172
- package/dist/bin/mcp/config.js +0 -202
- package/dist/bin/mcp/stdioClient.js +0 -172
- package/dist/bin/mcp/toolBridge.js +0 -104
- package/dist/bin/mcp/types.js +0 -1
- package/dist/bin/plugins/index.js +0 -113
- package/dist/bin/plugins/providers/anthropic/index.js +0 -25
- package/dist/bin/plugins/providers/deepseek/index.js +0 -24
- package/dist/bin/plugins/providers/google/index.js +0 -26
- package/dist/bin/plugins/providers/index.js +0 -19
- package/dist/bin/plugins/providers/ollama/index.js +0 -59
- package/dist/bin/plugins/providers/openai/index.js +0 -26
- package/dist/bin/plugins/providers/xai/index.js +0 -24
- package/dist/bin/plugins/tools/agentSpawning/agentSpawningPlugin.js +0 -8
- package/dist/bin/plugins/tools/bash/localBashPlugin.js +0 -13
- package/dist/bin/plugins/tools/checks/localRepoChecksPlugin.js +0 -13
- package/dist/bin/plugins/tools/cloud/cloudPlugin.js +0 -13
- package/dist/bin/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +0 -13
- package/dist/bin/plugins/tools/codeQuality/codeQualityPlugin.js +0 -13
- package/dist/bin/plugins/tools/dependency/dependencyPlugin.js +0 -11
- package/dist/bin/plugins/tools/development/devPlugin.js +0 -13
- package/dist/bin/plugins/tools/edit/editPlugin.js +0 -14
- package/dist/bin/plugins/tools/email/emailPlugin.js +0 -11
- package/dist/bin/plugins/tools/enhancedGit/enhancedGitPlugin.js +0 -8
- package/dist/bin/plugins/tools/filesystem/localFilesystemPlugin.js +0 -13
- package/dist/bin/plugins/tools/glob/globPlugin.js +0 -14
- package/dist/bin/plugins/tools/index.js +0 -2
- package/dist/bin/plugins/tools/interaction/interactionPlugin.js +0 -11
- package/dist/bin/plugins/tools/learn/learnPlugin.js +0 -13
- package/dist/bin/plugins/tools/mcp/mcpPlugin.js +0 -8
- package/dist/bin/plugins/tools/nodeDefaults.js +0 -56
- package/dist/bin/plugins/tools/notebook/notebookPlugin.js +0 -14
- package/dist/bin/plugins/tools/planning/planningPlugin.js +0 -14
- package/dist/bin/plugins/tools/refactoring/refactoringPlugin.js +0 -11
- package/dist/bin/plugins/tools/registry.js +0 -57
- package/dist/bin/plugins/tools/search/localSearchPlugin.js +0 -13
- package/dist/bin/plugins/tools/skills/skillPlugin.js +0 -8
- package/dist/bin/plugins/tools/taskManagement/taskManagementPlugin.js +0 -11
- package/dist/bin/plugins/tools/testing/testingPlugin.js +0 -11
- package/dist/bin/plugins/tools/web/webPlugin.js +0 -11
- package/dist/bin/providers/anthropicProvider.js +0 -329
- package/dist/bin/providers/googleProvider.js +0 -203
- package/dist/bin/providers/openaiChatCompletionsProvider.js +0 -208
- package/dist/bin/providers/openaiResponsesProvider.js +0 -249
- package/dist/bin/providers/providerFactory.js +0 -24
- package/dist/bin/runtime/agentController.js +0 -321
- package/dist/bin/runtime/agentHost.js +0 -153
- package/dist/bin/runtime/agentSession.js +0 -195
- package/dist/bin/runtime/node.js +0 -10
- package/dist/bin/runtime/universal.js +0 -28
- package/dist/bin/skills/skillRepository.js +0 -236
- package/dist/bin/skills/types.js +0 -1
- package/dist/bin/subagents/taskRunner.js +0 -269
- package/dist/bin/tools/backgroundBashTools.js +0 -211
- package/dist/bin/tools/bashTools.js +0 -159
- package/dist/bin/tools/cloudTools.js +0 -864
- package/dist/bin/tools/codeAnalysisTools.js +0 -641
- package/dist/bin/tools/codeQualityTools.js +0 -294
- package/dist/bin/tools/dependencyTools.js +0 -282
- package/dist/bin/tools/devTools.js +0 -238
- package/dist/bin/tools/diffUtils.js +0 -137
- package/dist/bin/tools/editTools.js +0 -134
- package/dist/bin/tools/emailTools.js +0 -448
- package/dist/bin/tools/fileTools.js +0 -282
- package/dist/bin/tools/globTools.js +0 -173
- package/dist/bin/tools/grepTools.js +0 -332
- package/dist/bin/tools/interactionTools.js +0 -170
- package/dist/bin/tools/learnTools.js +0 -1818
- package/dist/bin/tools/notebookEditTools.js +0 -196
- package/dist/bin/tools/planningTools.js +0 -46
- package/dist/bin/tools/refactoringTools.js +0 -293
- package/dist/bin/tools/repoChecksTools.js +0 -160
- package/dist/bin/tools/searchTools.js +0 -206
- package/dist/bin/tools/skillTools.js +0 -177
- package/dist/bin/tools/taskManagementTools.js +0 -156
- package/dist/bin/tools/testingTools.js +0 -232
- package/dist/bin/tools/webTools.js +0 -480
- package/dist/bin/workspace.js +0 -106
- package/dist/bin/workspace.validator.js +0 -213
- package/dist/capabilities/offensiveSecurityCapability.d.ts +0 -26
- package/dist/capabilities/offensiveSecurityCapability.d.ts.map +0 -1
- package/dist/capabilities/offensiveSecurityCapability.js +0 -58
- package/dist/capabilities/offensiveSecurityCapability.js.map +0 -1
- package/dist/capabilities/realSecurityCapability.d.ts +0 -26
- package/dist/capabilities/realSecurityCapability.d.ts.map +0 -1
- package/dist/capabilities/realSecurityCapability.js +0 -53
- package/dist/capabilities/realSecurityCapability.js.map +0 -1
- package/dist/capabilities/securityCapability.d.ts +0 -32
- package/dist/capabilities/securityCapability.d.ts.map +0 -1
- package/dist/capabilities/securityCapability.js +0 -57
- package/dist/capabilities/securityCapability.js.map +0 -1
- package/dist/capabilities/ultimateSecurityCapability.d.ts +0 -42
- package/dist/capabilities/ultimateSecurityCapability.d.ts.map +0 -1
- package/dist/capabilities/ultimateSecurityCapability.js +0 -96
- package/dist/capabilities/ultimateSecurityCapability.js.map +0 -1
- package/dist/core/designThoughtCheck.d.ts +0 -196
- package/dist/core/designThoughtCheck.d.ts.map +0 -1
- package/dist/core/designThoughtCheck.js +0 -287
- package/dist/core/designThoughtCheck.js.map +0 -1
- package/dist/core/designThoughtCheckEngine.d.ts +0 -58
- package/dist/core/designThoughtCheckEngine.d.ts.map +0 -1
- package/dist/core/designThoughtCheckEngine.js +0 -358
- package/dist/core/designThoughtCheckEngine.js.map +0 -1
- package/dist/core/designThoughtCheckIntegration.d.ts +0 -103
- package/dist/core/designThoughtCheckIntegration.d.ts.map +0 -1
- package/dist/core/designThoughtCheckIntegration.js +0 -207
- package/dist/core/designThoughtCheckIntegration.js.map +0 -1
- package/dist/core/intelligenceTools.d.ts +0 -19
- package/dist/core/intelligenceTools.d.ts.map +0 -1
- package/dist/core/intelligenceTools.js +0 -453
- package/dist/core/intelligenceTools.js.map +0 -1
- package/dist/core/operationalTools.d.ts +0 -19
- package/dist/core/operationalTools.d.ts.map +0 -1
- package/dist/core/operationalTools.js +0 -467
- package/dist/core/operationalTools.js.map +0 -1
- package/dist/offensive/core/offensive-engine.d.ts +0 -171
- package/dist/offensive/core/offensive-engine.d.ts.map +0 -1
- package/dist/offensive/core/offensive-engine.js +0 -345
- package/dist/offensive/core/offensive-engine.js.map +0 -1
- package/dist/offensive/core/offensive-integration.d.ts +0 -129
- package/dist/offensive/core/offensive-integration.d.ts.map +0 -1
- package/dist/offensive/core/offensive-integration.js +0 -364
- package/dist/offensive/core/offensive-integration.js.map +0 -1
- package/dist/offensive/core/offensive-tools.d.ts +0 -55
- package/dist/offensive/core/offensive-tools.d.ts.map +0 -1
- package/dist/offensive/core/offensive-tools.js +0 -438
- package/dist/offensive/core/offensive-tools.js.map +0 -1
- package/dist/offensive/offensive-cli.d.ts +0 -48
- package/dist/offensive/offensive-cli.d.ts.map +0 -1
- package/dist/offensive/offensive-cli.js +0 -233
- package/dist/offensive/offensive-cli.js.map +0 -1
- package/dist/security/apt-simulation-cli.d.ts +0 -57
- package/dist/security/apt-simulation-cli.d.ts.map +0 -1
- package/dist/security/apt-simulation-cli.js +0 -278
- package/dist/security/apt-simulation-cli.js.map +0 -1
- package/dist/security/apt-simulation-engine-complete.d.ts +0 -97
- package/dist/security/apt-simulation-engine-complete.d.ts.map +0 -1
- package/dist/security/apt-simulation-engine-complete.js +0 -441
- package/dist/security/apt-simulation-engine-complete.js.map +0 -1
- package/dist/security/apt-simulation-engine.d.ts +0 -97
- package/dist/security/apt-simulation-engine.d.ts.map +0 -1
- package/dist/security/apt-simulation-engine.js +0 -441
- package/dist/security/apt-simulation-engine.js.map +0 -1
- package/dist/security/authorization.d.ts +0 -45
- package/dist/security/authorization.d.ts.map +0 -1
- package/dist/security/authorization.js +0 -128
- package/dist/security/authorization.js.map +0 -1
- package/dist/security/comprehensive-security-research.d.ts +0 -84
- package/dist/security/comprehensive-security-research.d.ts.map +0 -1
- package/dist/security/comprehensive-security-research.js +0 -211
- package/dist/security/comprehensive-security-research.js.map +0 -1
- package/dist/security/offensive/exploitationEngine.d.ts +0 -54
- package/dist/security/offensive/exploitationEngine.d.ts.map +0 -1
- package/dist/security/offensive/exploitationEngine.js +0 -263
- package/dist/security/offensive/exploitationEngine.js.map +0 -1
- package/dist/security/real/networkExploitation.d.ts +0 -92
- package/dist/security/real/networkExploitation.d.ts.map +0 -1
- package/dist/security/real/networkExploitation.js +0 -316
- package/dist/security/real/networkExploitation.js.map +0 -1
- package/dist/security/real/persistenceImplementation.d.ts +0 -62
- package/dist/security/real/persistenceImplementation.d.ts.map +0 -1
- package/dist/security/real/persistenceImplementation.js +0 -323
- package/dist/security/real/persistenceImplementation.js.map +0 -1
- package/dist/security/real/vulnerabilityScanner.d.ts +0 -73
- package/dist/security/real/vulnerabilityScanner.d.ts.map +0 -1
- package/dist/security/real/vulnerabilityScanner.js +0 -341
- package/dist/security/real/vulnerabilityScanner.js.map +0 -1
- package/dist/shell/capturePastePatch.d.ts +0 -9
- package/dist/shell/capturePastePatch.d.ts.map +0 -1
- package/dist/shell/capturePastePatch.js +0 -98
- package/dist/shell/capturePastePatch.js.map +0 -1
- package/dist/shell/enhancedInteractiveShell.d.ts +0 -90
- package/dist/shell/enhancedInteractiveShell.d.ts.map +0 -1
- package/dist/shell/enhancedInteractiveShell.js +0 -248
- package/dist/shell/enhancedInteractiveShell.js.map +0 -1
- package/dist/shell/inputProcessor.d.ts +0 -56
- package/dist/shell/inputProcessor.d.ts.map +0 -1
- package/dist/shell/inputProcessor.js +0 -172
- package/dist/shell/inputProcessor.js.map +0 -1
- package/dist/shell/interactiveShell-patch.d.ts +0 -27
- package/dist/shell/interactiveShell-patch.d.ts.map +0 -1
- package/dist/shell/interactiveShell-patch.js +0 -38
- package/dist/shell/interactiveShell-patch.js.map +0 -1
- package/dist/shell/interactiveShell-robust.d.ts +0 -26
- package/dist/shell/interactiveShell-robust.d.ts.map +0 -1
- package/dist/shell/interactiveShell-robust.js +0 -34
- package/dist/shell/interactiveShell-robust.js.map +0 -1
- package/dist/shell/multiLinePasteManager.d.ts +0 -106
- package/dist/shell/multiLinePasteManager.d.ts.map +0 -1
- package/dist/shell/multiLinePasteManager.js +0 -308
- package/dist/shell/multiLinePasteManager.js.map +0 -1
- package/dist/shell/processInputBlockPatch.d.ts +0 -8
- package/dist/shell/processInputBlockPatch.d.ts.map +0 -1
- package/dist/shell/processInputBlockPatch.js +0 -133
- package/dist/shell/processInputBlockPatch.js.map +0 -1
- package/dist/tools/enhancedSecurityTools.d.ts +0 -19
- package/dist/tools/enhancedSecurityTools.d.ts.map +0 -1
- package/dist/tools/enhancedSecurityTools.js +0 -215
- package/dist/tools/enhancedSecurityTools.js.map +0 -1
- package/dist/tools/offensiveSecurityTools.d.ts +0 -16
- package/dist/tools/offensiveSecurityTools.d.ts.map +0 -1
- package/dist/tools/offensiveSecurityTools.js +0 -285
- package/dist/tools/offensiveSecurityTools.js.map +0 -1
- package/dist/tools/realSecurityTools.d.ts +0 -18
- package/dist/tools/realSecurityTools.d.ts.map +0 -1
- package/dist/tools/realSecurityTools.js +0 -468
- package/dist/tools/realSecurityTools.js.map +0 -1
- package/dist/tools/securityTools.d.ts +0 -20
- package/dist/tools/securityTools.d.ts.map +0 -1
- package/dist/tools/securityTools.js +0 -449
- package/dist/tools/securityTools.js.map +0 -1
|
@@ -1,480 +0,0 @@
|
|
|
1
|
-
import * as https from 'node:https';
|
|
2
|
-
import * as http from 'node:http';
|
|
3
|
-
import { getSecretValue } from '../core/secretStore.js';
|
|
4
|
-
export function createWebTools() {
|
|
5
|
-
return [
|
|
6
|
-
{
|
|
7
|
-
name: 'WebFetch',
|
|
8
|
-
description: `- Fetches content from a specified URL and processes it using an AI model
|
|
9
|
-
- Takes a URL and a prompt as input
|
|
10
|
-
- Fetches the URL content, converts HTML to markdown
|
|
11
|
-
- Processes the content with the prompt using a small, fast model
|
|
12
|
-
- Returns the model's response about the content
|
|
13
|
-
- Use this tool when you need to retrieve and analyze web content
|
|
14
|
-
|
|
15
|
-
Usage notes:
|
|
16
|
-
- IMPORTANT: If TAVILY_API_KEY is set, use WebExtract instead for better content extraction
|
|
17
|
-
- The URL must be a fully-formed valid URL
|
|
18
|
-
- HTTP URLs will be automatically upgraded to HTTPS
|
|
19
|
-
- The prompt should describe what information you want to extract from the page
|
|
20
|
-
- This tool is read-only and does not modify any files
|
|
21
|
-
- Results may be summarized if the content is very large
|
|
22
|
-
- Includes a self-cleaning 15-minute cache for faster responses when repeatedly accessing the same URL
|
|
23
|
-
- When a URL redirects to a different host, the tool will inform you and provide the redirect URL in a special format. You should then make a new WebFetch request with the redirect URL to fetch the content.`,
|
|
24
|
-
parameters: {
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
url: {
|
|
28
|
-
type: 'string',
|
|
29
|
-
description: 'The URL to fetch content from',
|
|
30
|
-
},
|
|
31
|
-
prompt: {
|
|
32
|
-
type: 'string',
|
|
33
|
-
description: 'The prompt to run on the fetched content',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
required: ['url', 'prompt'],
|
|
37
|
-
},
|
|
38
|
-
handler: async (args) => {
|
|
39
|
-
const url = args['url'];
|
|
40
|
-
const prompt = args['prompt'];
|
|
41
|
-
if (!url || !prompt) {
|
|
42
|
-
return 'Error: url and prompt parameters are required.';
|
|
43
|
-
}
|
|
44
|
-
try {
|
|
45
|
-
// Upgrade HTTP to HTTPS
|
|
46
|
-
const targetUrl = url.replace(/^http:\/\//, 'https://');
|
|
47
|
-
const content = await fetchUrl(targetUrl);
|
|
48
|
-
// Simple HTML to markdown conversion (basic implementation)
|
|
49
|
-
const markdown = htmlToMarkdown(content);
|
|
50
|
-
// Process with prompt (in a real implementation, this would use a small LLM)
|
|
51
|
-
// For now, we'll return the content with the prompt context
|
|
52
|
-
return `Fetched content from ${targetUrl}
|
|
53
|
-
|
|
54
|
-
Prompt: ${prompt}
|
|
55
|
-
|
|
56
|
-
Content (first 5000 characters):
|
|
57
|
-
${markdown.slice(0, 5000)}${markdown.length > 5000 ? '\n\n... (content truncated)' : ''}
|
|
58
|
-
|
|
59
|
-
Summary: This is the content fetched from the URL. In a full implementation, this would be processed by a small LLM to answer the specific prompt.`;
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
return `Error fetching URL: ${error instanceof Error ? error.message : String(error)}`;
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: 'WebExtract',
|
|
68
|
-
description: `- Extracts clean, structured content from one or more URLs using Tavily Extract API
|
|
69
|
-
- Superior to WebFetch for content extraction when TAVILY_API_KEY is available
|
|
70
|
-
- Returns raw text content optimized for LLM consumption
|
|
71
|
-
- Supports batch extraction of up to 20 URLs in a single call
|
|
72
|
-
|
|
73
|
-
Usage notes:
|
|
74
|
-
- Requires TAVILY_API_KEY environment variable
|
|
75
|
-
- Best for extracting article content, documentation, blog posts
|
|
76
|
-
- Returns clean text without HTML artifacts
|
|
77
|
-
- More reliable than basic HTML parsing for complex pages
|
|
78
|
-
- Use for deep content extraction when you need full page text`,
|
|
79
|
-
parameters: {
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: {
|
|
82
|
-
urls: {
|
|
83
|
-
type: 'array',
|
|
84
|
-
items: { type: 'string' },
|
|
85
|
-
description: 'Array of URLs to extract content from (max 20)',
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
required: ['urls'],
|
|
89
|
-
},
|
|
90
|
-
handler: async (args) => {
|
|
91
|
-
const urls = args['urls'];
|
|
92
|
-
if (!urls || !Array.isArray(urls) || urls.length === 0) {
|
|
93
|
-
return 'Error: urls parameter is required and must be a non-empty array.';
|
|
94
|
-
}
|
|
95
|
-
if (urls.length > 20) {
|
|
96
|
-
return 'Error: Maximum 20 URLs allowed per request.';
|
|
97
|
-
}
|
|
98
|
-
const tavilyKey = getSecretValue('TAVILY_API_KEY') || process.env['TAVILY_API_KEY']?.trim();
|
|
99
|
-
if (!tavilyKey) {
|
|
100
|
-
return [
|
|
101
|
-
'WebExtract requires TAVILY_API_KEY to be set.',
|
|
102
|
-
'Get your API key at: https://tavily.com',
|
|
103
|
-
'Use /secrets to configure this value.',
|
|
104
|
-
'',
|
|
105
|
-
'Falling back to WebFetch for basic extraction is available as an alternative.',
|
|
106
|
-
].join('\n');
|
|
107
|
-
}
|
|
108
|
-
try {
|
|
109
|
-
const response = await fetch('https://api.tavily.com/extract', {
|
|
110
|
-
method: 'POST',
|
|
111
|
-
headers: {
|
|
112
|
-
'Content-Type': 'application/json',
|
|
113
|
-
},
|
|
114
|
-
body: JSON.stringify({
|
|
115
|
-
api_key: tavilyKey,
|
|
116
|
-
urls: urls,
|
|
117
|
-
}),
|
|
118
|
-
});
|
|
119
|
-
if (!response.ok) {
|
|
120
|
-
const errorText = await response.text().catch(() => '');
|
|
121
|
-
throw new Error(`Tavily Extract returned HTTP ${response.status}: ${errorText}`);
|
|
122
|
-
}
|
|
123
|
-
const payload = (await response.json());
|
|
124
|
-
const results = payload.results || [];
|
|
125
|
-
const failedUrls = payload.failed_results || [];
|
|
126
|
-
if (results.length === 0 && failedUrls.length === urls.length) {
|
|
127
|
-
return `Failed to extract content from all ${urls.length} URLs. This may be due to access restrictions or invalid URLs.`;
|
|
128
|
-
}
|
|
129
|
-
let output = `Extracted content from ${results.length}/${urls.length} URLs:\n\n`;
|
|
130
|
-
for (const result of results) {
|
|
131
|
-
output += `--- ${result.url} ---\n`;
|
|
132
|
-
if (result.raw_content) {
|
|
133
|
-
// Truncate very long content
|
|
134
|
-
const content = result.raw_content.length > 10000
|
|
135
|
-
? result.raw_content.slice(0, 10000) + '\n\n... (content truncated)'
|
|
136
|
-
: result.raw_content;
|
|
137
|
-
output += `${content}\n\n`;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
output += '(No content extracted)\n\n';
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (failedUrls.length > 0) {
|
|
144
|
-
output += `\nFailed URLs (${failedUrls.length}):\n`;
|
|
145
|
-
for (const failed of failedUrls) {
|
|
146
|
-
output += `- ${failed.url}: ${failed.error || 'Unknown error'}\n`;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return output.trim();
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
return `Error extracting content: ${error instanceof Error ? error.message : String(error)}`;
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
name: 'WebSearch',
|
|
158
|
-
description: `- Allows Claude to search the web and use the results to inform responses
|
|
159
|
-
- Provides up-to-date information for current events and recent data
|
|
160
|
-
- Returns search result information formatted as search result blocks
|
|
161
|
-
- Use this tool for accessing information beyond Claude's knowledge cutoff
|
|
162
|
-
- Searches are performed automatically within a single API call
|
|
163
|
-
|
|
164
|
-
Usage notes:
|
|
165
|
-
- Domain filtering is supported to include or block specific websites
|
|
166
|
-
- Web search is only available in the US
|
|
167
|
-
- Account for "Today's date" in <env>. For example, if <env> says "Today's date: 2025-07-01", and the user wants the latest docs, do not use 2024 in the search query. Use 2025.`,
|
|
168
|
-
parameters: {
|
|
169
|
-
type: 'object',
|
|
170
|
-
properties: {
|
|
171
|
-
query: {
|
|
172
|
-
type: 'string',
|
|
173
|
-
description: 'The search query to use',
|
|
174
|
-
},
|
|
175
|
-
allowed_domains: {
|
|
176
|
-
type: 'array',
|
|
177
|
-
items: {
|
|
178
|
-
type: 'string',
|
|
179
|
-
},
|
|
180
|
-
description: 'Only include search results from these domains',
|
|
181
|
-
},
|
|
182
|
-
blocked_domains: {
|
|
183
|
-
type: 'array',
|
|
184
|
-
items: {
|
|
185
|
-
type: 'string',
|
|
186
|
-
},
|
|
187
|
-
description: 'Never include search results from these domains',
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
required: ['query'],
|
|
191
|
-
},
|
|
192
|
-
handler: async (args) => {
|
|
193
|
-
const query = typeof args['query'] === 'string' ? args['query'].trim() : '';
|
|
194
|
-
const allowed = parseDomainList(args['allowed_domains']);
|
|
195
|
-
const blocked = parseDomainList(args['blocked_domains']);
|
|
196
|
-
if (!query) {
|
|
197
|
-
return 'Error: query parameter is required.';
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
const provider = resolveSearchProvider();
|
|
201
|
-
if (!provider) {
|
|
202
|
-
return [
|
|
203
|
-
'WebSearch requires TAVILY_API_KEY (recommended), BRAVE_SEARCH_API_KEY, or SERPAPI_API_KEY.',
|
|
204
|
-
'Run /secrets (or set the environment variables directly) to configure an API key.',
|
|
205
|
-
'',
|
|
206
|
-
'Get your Tavily API key at: https://tavily.com (recommended)',
|
|
207
|
-
'Get your Brave Search API key at: https://brave.com/search/api/',
|
|
208
|
-
'Get your SerpAPI key at: https://serpapi.com/',
|
|
209
|
-
].join('\n');
|
|
210
|
-
}
|
|
211
|
-
const results = await provider.search({
|
|
212
|
-
query,
|
|
213
|
-
allowedDomains: allowed,
|
|
214
|
-
blockedDomains: blocked,
|
|
215
|
-
maxResults: 6,
|
|
216
|
-
});
|
|
217
|
-
if (!results.length) {
|
|
218
|
-
return `No web results found for "${query}" ${formatFilterSummary(allowed, blocked)}.`;
|
|
219
|
-
}
|
|
220
|
-
return formatSearchResults(query, results, provider.label, allowed, blocked);
|
|
221
|
-
}
|
|
222
|
-
catch (error) {
|
|
223
|
-
return `Error performing web search: ${error instanceof Error ? error.message : String(error)}`;
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
];
|
|
228
|
-
}
|
|
229
|
-
function resolveSearchProvider() {
|
|
230
|
-
// Tavily is the preferred search provider - check secretStore then env
|
|
231
|
-
const tavilyKey = getSecretValue('TAVILY_API_KEY') || process.env['TAVILY_API_KEY']?.trim();
|
|
232
|
-
if (tavilyKey) {
|
|
233
|
-
return {
|
|
234
|
-
id: 'tavily',
|
|
235
|
-
label: 'Tavily Search',
|
|
236
|
-
search: (params) => performTavilySearch(params, tavilyKey),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
const braveKey = getSecretValue('BRAVE_SEARCH_API_KEY') || process.env['BRAVE_SEARCH_API_KEY']?.trim();
|
|
240
|
-
if (braveKey) {
|
|
241
|
-
return {
|
|
242
|
-
id: 'brave',
|
|
243
|
-
label: 'Brave Search',
|
|
244
|
-
search: (params) => performBraveSearch(params, braveKey),
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
const serpKey = getSecretValue('SERPAPI_API_KEY') || process.env['SERPAPI_API_KEY']?.trim();
|
|
248
|
-
if (serpKey) {
|
|
249
|
-
return {
|
|
250
|
-
id: 'serpapi',
|
|
251
|
-
label: 'SerpAPI (Google)',
|
|
252
|
-
search: (params) => performSerpApiSearch(params, serpKey),
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
async function performBraveSearch(params, apiKey) {
|
|
258
|
-
const url = new URL('https://api.search.brave.com/res/v1/web/search');
|
|
259
|
-
url.searchParams.set('q', params.query);
|
|
260
|
-
url.searchParams.set('count', String(Math.min(params.maxResults * 2, 20)));
|
|
261
|
-
const response = await fetch(url, {
|
|
262
|
-
headers: {
|
|
263
|
-
Accept: 'application/json',
|
|
264
|
-
'X-Subscription-Token': apiKey,
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
if (!response.ok) {
|
|
268
|
-
throw new Error(`Brave Search returned HTTP ${response.status}`);
|
|
269
|
-
}
|
|
270
|
-
const payload = (await response.json());
|
|
271
|
-
const entries = Array.isArray(payload?.web?.results) ? payload.web.results : [];
|
|
272
|
-
const mapped = entries
|
|
273
|
-
.map((entry) => ({
|
|
274
|
-
title: entry.title || entry.url,
|
|
275
|
-
url: entry.url,
|
|
276
|
-
snippet: entry.description || entry.snippet || '',
|
|
277
|
-
source: entry.profile?.name || entry.source || safeHostname(entry.url) || undefined,
|
|
278
|
-
published: entry.publishedDate || entry.subtype,
|
|
279
|
-
}))
|
|
280
|
-
.filter((result) => Boolean(result.url));
|
|
281
|
-
return applyDomainFilters(mapped, params.allowedDomains, params.blockedDomains).slice(0, params.maxResults);
|
|
282
|
-
}
|
|
283
|
-
async function performSerpApiSearch(params, apiKey) {
|
|
284
|
-
const url = new URL('https://serpapi.com/search.json');
|
|
285
|
-
url.searchParams.set('engine', 'google');
|
|
286
|
-
url.searchParams.set('q', params.query);
|
|
287
|
-
url.searchParams.set('num', String(Math.min(params.maxResults * 2, 10)));
|
|
288
|
-
url.searchParams.set('api_key', apiKey);
|
|
289
|
-
const response = await fetch(url);
|
|
290
|
-
if (!response.ok) {
|
|
291
|
-
throw new Error(`SerpAPI returned HTTP ${response.status}`);
|
|
292
|
-
}
|
|
293
|
-
const payload = (await response.json());
|
|
294
|
-
const entries = Array.isArray(payload?.organic_results) ? payload.organic_results : [];
|
|
295
|
-
const mapped = entries
|
|
296
|
-
.map((entry) => ({
|
|
297
|
-
title: entry.title || entry.link,
|
|
298
|
-
url: entry.link,
|
|
299
|
-
snippet: entry.snippet || (Array.isArray(entry.snippet_highlighted_words) ? entry.snippet_highlighted_words.join(' ') : ''),
|
|
300
|
-
source: entry.source || entry.display_link || entry.displayed_link || safeHostname(entry.link) || undefined,
|
|
301
|
-
published: entry.date || entry.snippet_date,
|
|
302
|
-
}))
|
|
303
|
-
.filter((result) => Boolean(result.url));
|
|
304
|
-
return applyDomainFilters(mapped, params.allowedDomains, params.blockedDomains).slice(0, params.maxResults);
|
|
305
|
-
}
|
|
306
|
-
async function performTavilySearch(params, apiKey) {
|
|
307
|
-
const response = await fetch('https://api.tavily.com/search', {
|
|
308
|
-
method: 'POST',
|
|
309
|
-
headers: {
|
|
310
|
-
'Content-Type': 'application/json',
|
|
311
|
-
},
|
|
312
|
-
body: JSON.stringify({
|
|
313
|
-
api_key: apiKey,
|
|
314
|
-
query: params.query,
|
|
315
|
-
search_depth: 'advanced',
|
|
316
|
-
include_answer: true,
|
|
317
|
-
include_raw_content: false,
|
|
318
|
-
max_results: Math.min(params.maxResults * 2, 10),
|
|
319
|
-
include_domains: params.allowedDomains.length ? params.allowedDomains : undefined,
|
|
320
|
-
exclude_domains: params.blockedDomains.length ? params.blockedDomains : undefined,
|
|
321
|
-
}),
|
|
322
|
-
});
|
|
323
|
-
if (!response.ok) {
|
|
324
|
-
const errorText = await response.text().catch(() => '');
|
|
325
|
-
throw new Error(`Tavily Search returned HTTP ${response.status}: ${errorText}`);
|
|
326
|
-
}
|
|
327
|
-
const payload = (await response.json());
|
|
328
|
-
const entries = Array.isArray(payload?.results) ? payload.results : [];
|
|
329
|
-
const mapped = entries
|
|
330
|
-
.map((entry) => ({
|
|
331
|
-
title: entry.title || entry.url,
|
|
332
|
-
url: entry.url,
|
|
333
|
-
snippet: entry.content || '',
|
|
334
|
-
source: safeHostname(entry.url) || undefined,
|
|
335
|
-
published: entry.published_date,
|
|
336
|
-
score: entry.score,
|
|
337
|
-
}))
|
|
338
|
-
.filter((result) => Boolean(result.url));
|
|
339
|
-
// Tavily already handles domain filtering via include_domains/exclude_domains
|
|
340
|
-
return mapped.slice(0, params.maxResults);
|
|
341
|
-
}
|
|
342
|
-
function parseDomainList(value) {
|
|
343
|
-
if (!Array.isArray(value)) {
|
|
344
|
-
return [];
|
|
345
|
-
}
|
|
346
|
-
return value
|
|
347
|
-
.map((entry) => (typeof entry === 'string' ? entry.trim().toLowerCase() : ''))
|
|
348
|
-
.filter(Boolean);
|
|
349
|
-
}
|
|
350
|
-
function applyDomainFilters(results, allowedDomains, blockedDomains) {
|
|
351
|
-
const normalizedAllowed = allowedDomains.map((domain) => domain.startsWith('.') ? domain.slice(1) : domain);
|
|
352
|
-
const normalizedBlocked = blockedDomains.map((domain) => domain.startsWith('.') ? domain.slice(1) : domain);
|
|
353
|
-
return results.filter((result) => {
|
|
354
|
-
const hostname = safeHostname(result.url);
|
|
355
|
-
if (!hostname) {
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
358
|
-
if (normalizedAllowed.length && !normalizedAllowed.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
if (normalizedBlocked.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
|
|
362
|
-
return false;
|
|
363
|
-
}
|
|
364
|
-
return true;
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
function formatSearchResults(query, results, providerLabel, allowed, blocked) {
|
|
368
|
-
const lines = [`Web Search Results for "${query}" (${providerLabel})`, ''];
|
|
369
|
-
results.forEach((result, index) => {
|
|
370
|
-
lines.push(`${index + 1}. ${result.title || result.url}`, result.url);
|
|
371
|
-
if (result.snippet) {
|
|
372
|
-
lines.push(` ${result.snippet}`);
|
|
373
|
-
}
|
|
374
|
-
const meta = [];
|
|
375
|
-
if (result.source) {
|
|
376
|
-
meta.push(`source: ${result.source}`);
|
|
377
|
-
}
|
|
378
|
-
if (result.published) {
|
|
379
|
-
meta.push(`published: ${result.published}`);
|
|
380
|
-
}
|
|
381
|
-
if (meta.length) {
|
|
382
|
-
lines.push(` (${meta.join(' · ')})`);
|
|
383
|
-
}
|
|
384
|
-
lines.push('');
|
|
385
|
-
});
|
|
386
|
-
lines.push(formatFilterSummary(allowed, blocked, providerLabel));
|
|
387
|
-
return lines.join('\n').trim();
|
|
388
|
-
}
|
|
389
|
-
function formatFilterSummary(allowed, blocked, providerLabel) {
|
|
390
|
-
const segments = [];
|
|
391
|
-
if (allowed.length) {
|
|
392
|
-
segments.push(`allowed: ${allowed.join(', ')}`);
|
|
393
|
-
}
|
|
394
|
-
if (blocked.length) {
|
|
395
|
-
segments.push(`blocked: ${blocked.join(', ')}`);
|
|
396
|
-
}
|
|
397
|
-
if (!segments.length) {
|
|
398
|
-
segments.push('none');
|
|
399
|
-
}
|
|
400
|
-
if (providerLabel) {
|
|
401
|
-
segments.push(`provider: ${providerLabel}`);
|
|
402
|
-
}
|
|
403
|
-
return `Filters: ${segments.join(' | ')}`;
|
|
404
|
-
}
|
|
405
|
-
function safeHostname(raw) {
|
|
406
|
-
if (!raw) {
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
try {
|
|
410
|
-
const url = new URL(raw);
|
|
411
|
-
return url.hostname.toLowerCase();
|
|
412
|
-
}
|
|
413
|
-
catch {
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
function fetchUrl(url) {
|
|
418
|
-
return new Promise((resolve, reject) => {
|
|
419
|
-
const client = url.startsWith('https://') ? https : http;
|
|
420
|
-
const request = client
|
|
421
|
-
.get(url, (res) => {
|
|
422
|
-
let data = '';
|
|
423
|
-
// Handle redirects
|
|
424
|
-
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
425
|
-
fetchUrl(res.headers.location)
|
|
426
|
-
.then(resolve)
|
|
427
|
-
.catch(reject);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (res.statusCode !== 200) {
|
|
431
|
-
reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
res.on('data', (chunk) => {
|
|
435
|
-
data += chunk;
|
|
436
|
-
});
|
|
437
|
-
res.on('end', () => {
|
|
438
|
-
resolve(data);
|
|
439
|
-
});
|
|
440
|
-
})
|
|
441
|
-
.on('error', (err) => {
|
|
442
|
-
reject(err);
|
|
443
|
-
});
|
|
444
|
-
request.on('error', (err) => {
|
|
445
|
-
reject(err);
|
|
446
|
-
});
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
function htmlToMarkdown(html) {
|
|
450
|
-
// Very basic HTML to markdown conversion
|
|
451
|
-
let text = html;
|
|
452
|
-
// Remove script and style tags
|
|
453
|
-
text = text.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
|
454
|
-
text = text.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
|
|
455
|
-
// Convert common HTML tags
|
|
456
|
-
text = text.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n\n');
|
|
457
|
-
text = text.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n\n');
|
|
458
|
-
text = text.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n\n');
|
|
459
|
-
text = text.replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n\n');
|
|
460
|
-
text = text.replace(/<br\s*\/?>/gi, '\n');
|
|
461
|
-
text = text.replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**');
|
|
462
|
-
text = text.replace(/<b[^>]*>(.*?)<\/b>/gi, '**$1**');
|
|
463
|
-
text = text.replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*');
|
|
464
|
-
text = text.replace(/<i[^>]*>(.*?)<\/i>/gi, '*$1*');
|
|
465
|
-
text = text.replace(/<code[^>]*>(.*?)<\/code>/gi, '`$1`');
|
|
466
|
-
text = text.replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)');
|
|
467
|
-
// Remove remaining HTML tags
|
|
468
|
-
text = text.replace(/<[^>]+>/g, '');
|
|
469
|
-
// Decode HTML entities
|
|
470
|
-
text = text
|
|
471
|
-
.replace(/ /g, ' ')
|
|
472
|
-
.replace(/&/g, '&')
|
|
473
|
-
.replace(/</g, '<')
|
|
474
|
-
.replace(/>/g, '>')
|
|
475
|
-
.replace(/"/g, '"')
|
|
476
|
-
.replace(/'/g, "'");
|
|
477
|
-
// Clean up excessive newlines
|
|
478
|
-
text = text.replace(/\n{3,}/g, '\n\n');
|
|
479
|
-
return text.trim();
|
|
480
|
-
}
|
package/dist/bin/workspace.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { safeWorkspaceContext, validateWorkspaceOptions } from './workspace.validator.js';
|
|
4
|
-
const PRIORITY_DOCS = ['README.md']; // Removed package.json to save context
|
|
5
|
-
const IGNORED_DIRS = new Set([
|
|
6
|
-
'.git', 'node_modules', 'dist', '.erosolar', 'build', 'coverage', '.next', 'out',
|
|
7
|
-
'__pycache__', '.pytest_cache', '.mypy_cache', 'venv', '.venv', 'env',
|
|
8
|
-
'target', 'bin', 'obj', '.idea', '.vscode', '.DS_Store'
|
|
9
|
-
]);
|
|
10
|
-
const DEFAULT_TREE_DEPTH = 1; // Reduced from 2 to 1 for critical context savings
|
|
11
|
-
const DEFAULT_MAX_ENTRIES = 30; // Further reduced from 50 to 30 - emergency reduction
|
|
12
|
-
const DEFAULT_DOC_LIMIT = 200; // Further reduced from 300 to 200 - emergency reduction
|
|
13
|
-
export function resolveWorkspaceCaptureOptions(env = process.env) {
|
|
14
|
-
return {
|
|
15
|
-
treeDepth: parsePositiveInt(env['EROSOLAR_CONTEXT_TREE_DEPTH']),
|
|
16
|
-
maxEntries: parsePositiveInt(env['EROSOLAR_CONTEXT_MAX_ENTRIES']),
|
|
17
|
-
docExcerptLimit: parsePositiveInt(env['EROSOLAR_CONTEXT_DOC_LIMIT']),
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
export function buildWorkspaceContext(root, options = {}) {
|
|
21
|
-
// CRITICAL: Validate options BEFORE building context
|
|
22
|
-
const optionsValidation = validateWorkspaceOptions(options);
|
|
23
|
-
if (!optionsValidation.valid) {
|
|
24
|
-
console.error('[Workspace Context] Invalid options:', optionsValidation.errors);
|
|
25
|
-
throw new Error(`Invalid workspace options: ${optionsValidation.errors.join(', ')}`);
|
|
26
|
-
}
|
|
27
|
-
// Log warnings if any
|
|
28
|
-
if (optionsValidation.warnings.length > 0) {
|
|
29
|
-
console.warn('[Workspace Context] Warnings:', optionsValidation.warnings);
|
|
30
|
-
}
|
|
31
|
-
const treeDepth = options.treeDepth ?? DEFAULT_TREE_DEPTH;
|
|
32
|
-
const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
33
|
-
const docLimit = options.docExcerptLimit ?? DEFAULT_DOC_LIMIT;
|
|
34
|
-
try {
|
|
35
|
-
const treeLines = formatFileTree(root, treeDepth, maxEntries);
|
|
36
|
-
const docSnippets = capturePriorityDocs(root, docLimit);
|
|
37
|
-
// REMOVED: Rulebook duplication - rulebooks are already in system prompt
|
|
38
|
-
const sections = [`cwd: ${root}`, 'files:', ...treeLines];
|
|
39
|
-
if (docSnippets.length) {
|
|
40
|
-
sections.push(docSnippets.join('\n\n'));
|
|
41
|
-
}
|
|
42
|
-
// REMOVED: Rulebook duplication
|
|
43
|
-
// if (rulebooks.length) {
|
|
44
|
-
// sections.push(rulebooks.join('\n\n'));
|
|
45
|
-
// }
|
|
46
|
-
const rawContent = sections.filter((section) => section.trim().length > 0).join('\n');
|
|
47
|
-
// CRITICAL: Validate and enforce limits on final output
|
|
48
|
-
const safe = safeWorkspaceContext(rawContent, {
|
|
49
|
-
truncate: true, // Auto-truncate if too large
|
|
50
|
-
throwOnError: false // Don't throw, just truncate
|
|
51
|
-
});
|
|
52
|
-
// Log stats for monitoring
|
|
53
|
-
if (process.env['DEBUG_CONTEXT']) {
|
|
54
|
-
console.log('[Workspace Context] Stats:', safe.stats);
|
|
55
|
-
}
|
|
56
|
-
return safe.content;
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
60
|
-
return `Workspace context unavailable (${message}).`;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function capturePriorityDocs(root, docLimit) {
|
|
64
|
-
return PRIORITY_DOCS.filter((name) => existsSync(join(root, name))).map((name) => {
|
|
65
|
-
try {
|
|
66
|
-
const content = readFileSync(join(root, name), 'utf8');
|
|
67
|
-
// Safety: Hard limit to prevent context explosion
|
|
68
|
-
const safeLimit = Math.min(docLimit, 300);
|
|
69
|
-
const snippet = content.length > safeLimit ? `${content.slice(0, safeLimit)}\n...` : content;
|
|
70
|
-
return `--- ${name} ---\n${snippet.trim()}`;
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return `--- ${name} ---\n[Could not read file]`;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function formatFileTree(root, maxDepth, maxEntries) {
|
|
78
|
-
const lines = [];
|
|
79
|
-
const walk = (dir, depth, prefix) => {
|
|
80
|
-
if (depth > maxDepth || lines.length >= maxEntries) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const entries = readdirSync(dir, { withFileTypes: true })
|
|
84
|
-
.filter((entry) => !IGNORED_DIRS.has(entry.name))
|
|
85
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
86
|
-
for (const entry of entries) {
|
|
87
|
-
if (lines.length >= maxEntries) {
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
const isDir = entry.isDirectory();
|
|
91
|
-
lines.push(`${prefix}${entry.name}${isDir ? '/' : ''}`);
|
|
92
|
-
if (isDir && depth < maxDepth) {
|
|
93
|
-
walk(join(dir, entry.name), depth + 1, `${prefix} `);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
walk(root, 0, '');
|
|
98
|
-
return lines;
|
|
99
|
-
}
|
|
100
|
-
function parsePositiveInt(raw) {
|
|
101
|
-
if (!raw) {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
const value = Number.parseInt(raw, 10);
|
|
105
|
-
return Number.isFinite(value) && value > 0 ? value : undefined;
|
|
106
|
-
}
|