natureco-cli 5.19.0 → 5.20.0
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/CHANGELOG.md +32 -0
- package/package.json +1 -1
- package/skills/a-b-testing/SKILL.md +34 -0
- package/skills/accessibility-audit/SKILL.md +34 -0
- package/skills/agent-memory/SKILL.md +34 -0
- package/skills/agent-orchestration/SKILL.md +34 -0
- package/skills/analytics-setup/SKILL.md +34 -0
- package/skills/api-design/SKILL.md +34 -0
- package/skills/api-versioning/SKILL.md +34 -0
- package/skills/audio-transcription/SKILL.md +34 -0
- package/skills/authentication-patterns/SKILL.md +34 -0
- package/skills/authorization-rbac/SKILL.md +34 -0
- package/skills/backup-strategy/SKILL.md +34 -0
- package/skills/bash-scripting/SKILL.md +34 -0
- package/skills/batch-api-calls/SKILL.md +34 -0
- package/skills/batch-processing/SKILL.md +34 -0
- package/skills/bulk-file-operations/SKILL.md +34 -0
- package/skills/cache-responses/SKILL.md +34 -0
- package/skills/caching-strategy/SKILL.md +34 -0
- package/skills/calendar-optimization/SKILL.md +34 -0
- package/skills/changelog-generation/SKILL.md +34 -0
- package/skills/chat-bot-design/SKILL.md +34 -0
- package/skills/chunking-strategy/SKILL.md +34 -0
- package/skills/ci-cd-pipeline/SKILL.md +34 -0
- package/skills/classification-pipeline/SKILL.md +34 -0
- package/skills/clipboard-master/SKILL.md +34 -0
- package/skills/code-explanation/SKILL.md +34 -0
- package/skills/code-generation/SKILL.md +34 -0
- package/skills/code-migration/SKILL.md +34 -0
- package/skills/code-review-checklist/SKILL.md +34 -0
- package/skills/contact-management/SKILL.md +34 -0
- package/skills/content-generation/SKILL.md +34 -0
- package/skills/context-pruning/SKILL.md +34 -0
- package/skills/context-window-management/SKILL.md +34 -0
- package/skills/continuous-improvement/SKILL.md +34 -0
- package/skills/cron-scheduling/SKILL.md +34 -0
- package/skills/cross-platform-compat/SKILL.md +34 -0
- package/skills/csv-processing/SKILL.md +34 -0
- package/skills/daily-journal/SKILL.md +34 -0
- package/skills/data-analysis/SKILL.md +34 -0
- package/skills/data-backup/SKILL.md +34 -0
- package/skills/data-cleaning/SKILL.md +34 -0
- package/skills/data-extraction/SKILL.md +34 -0
- package/skills/data-validation/SKILL.md +34 -0
- package/skills/database-migrations/SKILL.md +34 -0
- package/skills/database-schema-design/SKILL.md +34 -0
- package/skills/decision-matrix/SKILL.md +34 -0
- package/skills/dependency-management/SKILL.md +34 -0
- package/skills/dev-environment-setup/SKILL.md +34 -0
- package/skills/distraction-blocker/SKILL.md +34 -0
- package/skills/docker-optimization/SKILL.md +34 -0
- package/skills/document-template/SKILL.md +34 -0
- package/skills/documentation-gen/SKILL.md +34 -0
- package/skills/efficient-formatting/SKILL.md +34 -0
- package/skills/email-management/SKILL.md +34 -0
- package/skills/email-service/SKILL.md +34 -0
- package/skills/embedding-generation/SKILL.md +34 -0
- package/skills/entity-extraction/SKILL.md +34 -0
- package/skills/environment-config/SKILL.md +34 -0
- package/skills/error-handling/SKILL.md +34 -0
- package/skills/estimation-techniques/SKILL.md +34 -0
- package/skills/event-driven-architecture/SKILL.md +34 -0
- package/skills/excel-automation/SKILL.md +34 -0
- package/skills/execution-monitoring/SKILL.md +34 -0
- package/skills/expense-tracking/SKILL.md +34 -0
- package/skills/feature-engineering/SKILL.md +34 -0
- package/skills/feature-flags/SKILL.md +34 -0
- package/skills/file-conversion/SKILL.md +34 -0
- package/skills/file-upload-handling/SKILL.md +34 -0
- package/skills/fine-tuning-prep/SKILL.md +34 -0
- package/skills/focus-mode/SKILL.md +34 -0
- package/skills/form-validation/SKILL.md +34 -0
- package/skills/function-calling/SKILL.md +34 -0
- package/skills/git-workflow/SKILL.md +34 -0
- package/skills/goal-setting/SKILL.md +34 -0
- package/skills/graphql-design/SKILL.md +34 -0
- package/skills/habit-tracker/SKILL.md +34 -0
- package/skills/hallucination-detection/SKILL.md +34 -0
- package/skills/image-processing/SKILL.md +34 -0
- package/skills/json-transformation/SKILL.md +34 -0
- package/skills/keyboard-shortcuts/SKILL.md +34 -0
- package/skills/knowledge-base/SKILL.md +34 -0
- package/skills/knowledge-graph/SKILL.md +34 -0
- package/skills/kubernetes-deployment/SKILL.md +34 -0
- package/skills/language-translation/SKILL.md +34 -0
- package/skills/llm-chaining/SKILL.md +34 -0
- package/skills/localization-i18n/SKILL.md +34 -0
- package/skills/logging-best-practices/SKILL.md +34 -0
- package/skills/machine-learning-pipeline/SKILL.md +34 -0
- package/skills/meeting-notes/SKILL.md +34 -0
- package/skills/meeting-scheduler/SKILL.md +34 -0
- package/skills/message-queues/SKILL.md +34 -0
- package/skills/message-summarization/SKILL.md +34 -0
- package/skills/microservices-architecture/SKILL.md +34 -0
- package/skills/milestone-tracking/SKILL.md +34 -0
- package/skills/model-deployment/SKILL.md +34 -0
- package/skills/model-evaluation/SKILL.md +34 -0
- package/skills/monitoring-setup/SKILL.md +34 -0
- package/skills/monorepo-setup/SKILL.md +34 -0
- package/skills/multi-agent-systems/SKILL.md +34 -0
- package/skills/network-troubleshooting/SKILL.md +34 -0
- package/skills/note-organization/SKILL.md +34 -0
- package/skills/package-publishing/SKILL.md +34 -0
- package/skills/password-generator/SKILL.md +34 -0
- package/skills/pdf-processing/SKILL.md +34 -0
- package/skills/performance-optimization/SKILL.md +34 -0
- package/skills/pomodoro-timer/SKILL.md +34 -0
- package/skills/powershell-automation/SKILL.md +34 -0
- package/skills/priority-filtering/SKILL.md +34 -0
- package/skills/project-tracking/SKILL.md +34 -0
- package/skills/prompt-compression/SKILL.md +34 -0
- package/skills/prompt-engineering/SKILL.md +34 -0
- package/skills/push-notifications/SKILL.md +34 -0
- package/skills/rag-implementation/SKILL.md +34 -0
- package/skills/rate-limiting/SKILL.md +34 -0
- package/skills/real-time-communication/SKILL.md +34 -0
- package/skills/refactoring-strategy/SKILL.md +34 -0
- package/skills/regex-mastery/SKILL.md +34 -0
- package/skills/report-generation/SKILL.md +34 -0
- package/skills/research-compiler/SKILL.md +34 -0
- package/skills/responsive-design/SKILL.md +34 -0
- package/skills/rest-api-patterns/SKILL.md +34 -0
- package/skills/retrospectives/SKILL.md +34 -0
- package/skills/risk-assessment/SKILL.md +34 -0
- package/skills/roadmap-creation/SKILL.md +34 -0
- package/skills/search-implementation/SKILL.md +34 -0
- package/skills/secrets-management/SKILL.md +34 -0
- package/skills/security-audit/SKILL.md +34 -0
- package/skills/selective-memory/SKILL.md +34 -0
- package/skills/semantic-search/SKILL.md +34 -0
- package/skills/semantic-versioning/SKILL.md +34 -0
- package/skills/sentiment-analysis/SKILL.md +34 -0
- package/skills/seo-optimization/SKILL.md +34 -0
- package/skills/snippet-manager/SKILL.md +34 -0
- package/skills/sprint-planning/SKILL.md +34 -0
- package/skills/sql-query-optimization/SKILL.md +34 -0
- package/skills/stakeholder-communication/SKILL.md +34 -0
- package/skills/state-management/SKILL.md +34 -0
- package/skills/statistical-analysis/SKILL.md +34 -0
- package/skills/streaming-responses/SKILL.md +34 -0
- package/skills/structured-output/SKILL.md +34 -0
- package/skills/summarization-techniques/SKILL.md +34 -0
- package/skills/system-diagnostics/SKILL.md +34 -0
- package/skills/task-decomposition/SKILL.md +34 -0
- package/skills/task-prioritization/SKILL.md +34 -0
- package/skills/template-library/SKILL.md +34 -0
- package/skills/test-generation/SKILL.md +34 -0
- package/skills/testing-strategy/SKILL.md +34 -0
- package/skills/text-expansion/SKILL.md +34 -0
- package/skills/time-blocking/SKILL.md +34 -0
- package/skills/token-budgeting/SKILL.md +34 -0
- package/skills/token-optimization/SKILL.md +34 -0
- package/skills/tool-calling-patterns/SKILL.md +34 -0
- package/skills/vector-database-setup/SKILL.md +34 -0
- package/skills/video-editing/SKILL.md +34 -0
- package/skills/visualization-creation/SKILL.md +34 -0
- package/skills/web-scraping/SKILL.md +34 -0
- package/skills/webhook-handling/SKILL.md +34 -0
- package/skills/weekly-review/SKILL.md +34 -0
- package/skills/workflow-automation/SKILL.md +34 -0
- package/src/commands/code_v5.js +377 -73
- package/src/commands/repl.js +505 -86
- package/src/providers/model/anthropic.js +84 -0
- package/src/providers/model/gemini.js +49 -0
- package/src/providers/model/minimax.js +48 -0
- package/src/providers/model/ollama.js +42 -0
- package/src/providers/model/openai.js +49 -0
- package/src/providers/search/duckduckgo.js +45 -0
- package/src/providers/search/exa.js +52 -0
- package/src/providers/search/searxng.js +51 -0
- package/src/providers/search/tavily.js +47 -0
- package/src/tools/model_provider.js +71 -0
- package/src/tools/parallel_search.js +40 -49
- package/src/tools/search_provider.js +79 -0
- package/src/tools/web_search.js +42 -62
- package/src/tools/workflow.js +21 -9
- package/src/utils/cron.js +82 -126
- package/src/utils/effort-levels.js +42 -0
- package/src/utils/fallback-chain.js +72 -0
- package/src/utils/file-history.js +78 -0
- package/src/utils/model-provider.js +113 -0
- package/src/utils/permissions.js +147 -0
- package/src/utils/plan-mode.js +164 -0
- package/src/utils/provider-detect.js +7 -32
- package/src/utils/sandbox.js +60 -0
- package/src/utils/search-provider.js +62 -0
- package/src/utils/session-search.js +66 -0
- package/src/utils/structured-output.js +20 -0
- package/src/utils/system-prompt.js +28 -2
- package/src/utils/tasks.js +132 -0
- package/src/utils/tool-hooks.js +154 -0
- package/src/utils/tools.js +16 -0
- package/src/utils/ultra-review.js +59 -0
- package/src/utils/worktree.js +192 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const loadConfig = () => {
|
|
2
|
+
try { return JSON.parse(require('fs').readFileSync(require('path').join(require('os').homedir(), '.natureco', 'config.json'), 'utf8')); } catch { return {}; }
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
require('../providers/search/tavily');
|
|
6
|
+
require('../providers/search/duckduckgo');
|
|
7
|
+
require('../providers/search/searxng');
|
|
8
|
+
require('../providers/search/exa');
|
|
9
|
+
|
|
10
|
+
const name = 'search_provider';
|
|
11
|
+
const description = 'Unified search backend with pluggable providers. search/status/switch/list. Supports Tavily, DuckDuckGo, SearXNG, Exa. Switch via NATURECO_SEARCH_PROVIDER env or config.searchProvider. Default: tavily (falls back to others if no API key).';
|
|
12
|
+
const parameters = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
action: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['search', 'status', 'list', 'switch'],
|
|
18
|
+
description: 'Operation: search, status, list, or switch',
|
|
19
|
+
},
|
|
20
|
+
query: { type: 'string', description: '(search) Search query' },
|
|
21
|
+
maxResults: { type: 'number', description: '(search) Max results (default: 5)' },
|
|
22
|
+
provider: { type: 'string', description: '(search/switch) Provider name to use or switch to' },
|
|
23
|
+
},
|
|
24
|
+
required: ['action'],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
async function execute(params) {
|
|
28
|
+
const cfg = loadConfig();
|
|
29
|
+
const { getActiveProvider, getProviderNames, resolveProviderConfig, getProvider } = require('../utils/search-provider');
|
|
30
|
+
|
|
31
|
+
switch (params.action) {
|
|
32
|
+
case 'search': {
|
|
33
|
+
if (!params.query) return { success: false, error: 'query gerekli' };
|
|
34
|
+
const providerName = params.provider || process.env.NATURECO_SEARCH_PROVIDER || cfg.searchProvider;
|
|
35
|
+
let Provider;
|
|
36
|
+
if (providerName) Provider = getProvider(providerName);
|
|
37
|
+
if (!Provider) Provider = getActiveProvider(cfg);
|
|
38
|
+
const provider = new Provider(cfg);
|
|
39
|
+
return provider.search(params.query, { maxResults: params.maxResults || 5 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
case 'status': {
|
|
43
|
+
const active = resolveProviderConfig(cfg);
|
|
44
|
+
const avail = getProviderNames().sort();
|
|
45
|
+
return {
|
|
46
|
+
active,
|
|
47
|
+
available: avail,
|
|
48
|
+
config: cfg.searchProvider || '(not set, using default)',
|
|
49
|
+
env: process.env.NATURECO_SEARCH_PROVIDER || '(not set)',
|
|
50
|
+
default: 'tavily',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
case 'list': {
|
|
55
|
+
const avail = getProviderNames().sort();
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
providers: avail.map(name => {
|
|
59
|
+
const Provider = getProvider(name);
|
|
60
|
+
const inst = new Provider(cfg);
|
|
61
|
+
const hasKey = name === 'duckduckgo' || name === 'searxng' || !!(cfg[name + 'ApiKey'] || process.env[name.toUpperCase() + '_API_KEY']);
|
|
62
|
+
return { name, available: hasKey };
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case 'switch': {
|
|
68
|
+
if (!params.provider) return { success: false, error: 'provider (name) gerekli' };
|
|
69
|
+
const { setConfigValue } = require('../utils/config');
|
|
70
|
+
setConfigValue('searchProvider', params.provider);
|
|
71
|
+
return { success: true, message: `Search provider switched to: ${params.provider}` };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
default:
|
|
75
|
+
return { success: false, error: `Unknown action: ${params.action}` };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = { name, description, parameters, execute };
|
package/src/tools/web_search.js
CHANGED
|
@@ -1,82 +1,62 @@
|
|
|
1
1
|
const { getConfig } = require('../utils/config');
|
|
2
|
+
const { getActiveProvider, getProviderNames, DEFAULT_PROVIDER } = require('../utils/search-provider');
|
|
3
|
+
require('../providers/search/tavily');
|
|
4
|
+
require('../providers/search/duckduckgo');
|
|
5
|
+
require('../providers/search/searxng');
|
|
6
|
+
require('../providers/search/exa');
|
|
2
7
|
|
|
3
8
|
module.exports = {
|
|
4
9
|
name: 'web_search',
|
|
5
|
-
description: 'Search the web for current information using Tavily',
|
|
10
|
+
description: 'Search the web for current information using the configured search provider (Tavily, DuckDuckGo, SearXNG, Exa). Switch via NATURECO_SEARCH_PROVIDER env or config.searchProvider.',
|
|
6
11
|
inputSchema: {
|
|
7
12
|
type: 'object',
|
|
8
13
|
properties: {
|
|
9
|
-
query: {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
14
|
+
query: { type: 'string', description: 'Search query' },
|
|
15
|
+
maxResults: { type: 'number', description: 'Maximum results (default: 5)' },
|
|
16
|
+
provider: { type: 'string', description: 'Override provider: tavily, duckduckgo, searxng, exa (default: configured or tavily)' },
|
|
13
17
|
},
|
|
14
18
|
required: ['query']
|
|
15
19
|
},
|
|
16
|
-
|
|
20
|
+
|
|
17
21
|
async execute(params) {
|
|
18
22
|
try {
|
|
19
23
|
const config = getConfig();
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const response = await fetch('https://api.tavily.com/search', {
|
|
30
|
-
method: 'POST',
|
|
31
|
-
headers: { 'Content-Type': 'application/json' },
|
|
32
|
-
body: JSON.stringify({
|
|
33
|
-
api_key: apiKey,
|
|
34
|
-
query: params.query,
|
|
35
|
-
search_depth: 'basic',
|
|
36
|
-
max_results: 5
|
|
37
|
-
})
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
return {
|
|
42
|
-
success: false,
|
|
43
|
-
error: `Tavily API error: ${response.status} ${response.statusText}`
|
|
44
|
-
};
|
|
24
|
+
const providerName = params.provider || process.env.NATURECO_SEARCH_PROVIDER || config.searchProvider;
|
|
25
|
+
let Provider;
|
|
26
|
+
|
|
27
|
+
if (providerName) {
|
|
28
|
+
const { getProvider } = require('../utils/search-provider');
|
|
29
|
+
Provider = getProvider(providerName);
|
|
45
30
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (data.error) {
|
|
50
|
-
return {
|
|
51
|
-
success: false,
|
|
52
|
-
error: data.error
|
|
53
|
-
};
|
|
31
|
+
if (!Provider) {
|
|
32
|
+
Provider = getActiveProvider(config);
|
|
54
33
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
34
|
+
|
|
35
|
+
const provider = new Provider(config);
|
|
36
|
+
const result = await provider.search(params.query, {
|
|
37
|
+
maxResults: params.maxResults || 5,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!result.success && providerName && !params.provider) {
|
|
41
|
+
const allProviders = getProviderNames();
|
|
42
|
+
for (const name of allProviders) {
|
|
43
|
+
if (name === providerName) continue;
|
|
44
|
+
const { getProvider } = require('../utils/search-provider');
|
|
45
|
+
const FallbackProvider = getProvider(name);
|
|
46
|
+
if (!FallbackProvider) continue;
|
|
47
|
+
const fallback = new FallbackProvider(config);
|
|
48
|
+
const fallbackResult = await fallback.search(params.query, { maxResults: params.maxResults || 5 });
|
|
49
|
+
if (fallbackResult.success) {
|
|
50
|
+
fallbackResult.fallback = true;
|
|
51
|
+
fallbackResult.fallbackReason = result.error;
|
|
52
|
+
return fallbackResult;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
63
55
|
}
|
|
64
|
-
|
|
65
|
-
return
|
|
66
|
-
success: true,
|
|
67
|
-
query: params.query,
|
|
68
|
-
results: data.results.map(r => ({
|
|
69
|
-
title: r.title,
|
|
70
|
-
snippet: r.content,
|
|
71
|
-
url: r.url
|
|
72
|
-
})),
|
|
73
|
-
count: data.results.length
|
|
74
|
-
};
|
|
56
|
+
|
|
57
|
+
return result;
|
|
75
58
|
} catch (error) {
|
|
76
|
-
return {
|
|
77
|
-
success: false,
|
|
78
|
-
error: error.message
|
|
79
|
-
};
|
|
59
|
+
return { success: false, error: error.message };
|
|
80
60
|
}
|
|
81
61
|
}
|
|
82
62
|
};
|
package/src/tools/workflow.js
CHANGED
|
@@ -6,6 +6,8 @@ const os = require('os');
|
|
|
6
6
|
const WORKFLOW_DIR = path.join(os.homedir(), '.natureco', 'workflows');
|
|
7
7
|
const WORKFLOW_HISTORY = path.join(os.homedir(), '.natureco', 'workflow-history.json');
|
|
8
8
|
|
|
9
|
+
const { buildSkillIndex } = require('../utils/skill-index');
|
|
10
|
+
|
|
9
11
|
function ensureDir(dir) { try { fs.mkdirSync(dir, { recursive: true }); } catch {} }
|
|
10
12
|
function loadConfig() {
|
|
11
13
|
try { return JSON.parse(fs.readFileSync(path.join(os.homedir(), '.natureco', 'config.json'), 'utf8')); } catch { return {}; }
|
|
@@ -94,6 +96,8 @@ async function workflow(params) {
|
|
|
94
96
|
return { success: false, error: 'Provider ayarli degil. Once: natureco setup' };
|
|
95
97
|
}
|
|
96
98
|
|
|
99
|
+
const skillsIndexBlock = buildSkillIndex();
|
|
100
|
+
|
|
97
101
|
// ── RUN: Execute a complete workflow ──────────────────────────────────
|
|
98
102
|
if (action === 'run') {
|
|
99
103
|
if (!task) return { success: false, error: 'task gerekli' };
|
|
@@ -114,7 +118,7 @@ async function workflow(params) {
|
|
|
114
118
|
if (isSimple) {
|
|
115
119
|
// Passthrough: just chat with LLM, no tools — include user memory
|
|
116
120
|
const memCtx = memoryContext();
|
|
117
|
-
const sysMsg = 'Sen yardimci bir asistansin. Kisa ve oz yanit ver.' + (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '');
|
|
121
|
+
const sysMsg = 'Sen yardimci bir asistansin. Kisa ve oz yanit ver.' + (memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '') + '\n\n' + skillsIndexBlock;
|
|
118
122
|
const chatBody = { model, stream: false, messages: [{ role: 'system', content: sysMsg }, { role: 'user', content: task }], temperature: 0.7, max_tokens: 1000 };
|
|
119
123
|
try {
|
|
120
124
|
const chatResult = await apiCall(providerUrl, providerApiKey, chatBody);
|
|
@@ -127,12 +131,13 @@ async function workflow(params) {
|
|
|
127
131
|
|
|
128
132
|
// Phase 1: LLM plans the workflow
|
|
129
133
|
const memCtx = memoryContext();
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
const planPrompt = {
|
|
135
|
+
role: 'system',
|
|
136
|
+
content: 'Sen bir workflow planlama asistanisin. Verilen gorev icin hangi tool\'larin kullanilacagini ve hangi sirayla calisacagini belirle. SADECE JSON formatinda yanit ver, baska bir sey yazma.\n\nKullanilabilir tool\'lar:\n' +
|
|
137
|
+
tools.map(t => '- ' + t).join('\n') +
|
|
138
|
+
'\n\nKullanilabilir skill\'ler (gorevle ilgili skill varsa plana skill_view adimi olarak ekle):\n' + skillsIndexBlock +
|
|
139
|
+
(memCtx ? '\n\nKullanici bilgisi:\n' + memCtx : '') +
|
|
140
|
+
'\n\nJSON format:\n{\n "workflowName": "...",\n "description": "...",\n "skillsLoaded": ["..."],\n "steps": [\n { "step": 1, "tool": "tool_name", "purpose": "...", "params": { ... } }\n ]\n}\n\nHer adim icin params kismina tool\'un gerektirdigi parametreleri ekle. Adimlar birbirine bagimli olabilir, onceki adimin outputu sonraki adimin inputu olarak kullanilabilir.\n\nGorevle ilgili skill varsa ILK adim olarak skill_view ile yukle, ardindan diger adimlara gec.'
|
|
136
141
|
};
|
|
137
142
|
const planBody = {
|
|
138
143
|
model, stream: false,
|
|
@@ -203,7 +208,8 @@ async function workflow(params) {
|
|
|
203
208
|
role: 'system',
|
|
204
209
|
content: 'Bir sonraki adimi calistiriyorsun. Sana verilen tool\'u ve parametreleri kullanarak islemi gerceklestir. Tool cagrisini dogru formatta yap.\n\nTool: ' + step.tool + '\nAmac: ' + (step.purpose || '') + '\nPlanlanan parametreler: ' + JSON.stringify(step.params || {}) +
|
|
205
210
|
'\n\nOnceki adim sonuclari:\n' + stepResults.map(r => 'Adim ' + r.step + ' (' + r.tool + '): ' + (r.status === 'done' ? JSON.stringify(r.result).slice(0, 300) : r.status)).join('\n') +
|
|
206
|
-
'\n\
|
|
211
|
+
'\n\nKullanilabilir skill\'ler:\n' + skillsIndexBlock +
|
|
212
|
+
'\n\nTek bir tool cagrisi yap ve sonucu bekle. Tool cagrisi yaparken Onceki adim sonuclarindaki gerekli verileri parametre olarak kullan. Ilgili skill varsa once skill_view ile yukle, sonra asil tool\'u cagir.'
|
|
207
213
|
};
|
|
208
214
|
const executeBody = {
|
|
209
215
|
model, stream: false,
|
|
@@ -251,6 +257,10 @@ async function workflow(params) {
|
|
|
251
257
|
history.unshift({ id: wfId, name: plan.workflowName || task.slice(0, 50), task, status: wfEntry.status, steps: plan.steps.length, completedAt: wfEntry.completedAt });
|
|
252
258
|
fs.writeFileSync(WORKFLOW_HISTORY, JSON.stringify(history.slice(0, 50), null, 2));
|
|
253
259
|
|
|
260
|
+
const skillsLoaded = stepResults
|
|
261
|
+
.filter(r => r.tool === 'skill_view' && r.status === 'done')
|
|
262
|
+
.map(r => r.args?.name || 'bilinmeyen-skill');
|
|
263
|
+
|
|
254
264
|
return {
|
|
255
265
|
success: true,
|
|
256
266
|
workflowId: wfId,
|
|
@@ -260,6 +270,7 @@ async function workflow(params) {
|
|
|
260
270
|
completedSteps: stepResults.filter(r => r.status === 'done').length,
|
|
261
271
|
failedSteps: stepResults.filter(r => r.status === 'error' || r.status === 'skipped').length,
|
|
262
272
|
status: wfEntry.status,
|
|
273
|
+
skillsLoaded: skillsLoaded.length > 0 ? skillsLoaded : undefined,
|
|
263
274
|
plan: plan.steps.map(s => ({ step: s.step, tool: s.tool, purpose: s.purpose })),
|
|
264
275
|
results: stepResults.map(r => ({
|
|
265
276
|
step: r.step, tool: r.tool, status: r.status,
|
|
@@ -276,7 +287,8 @@ async function workflow(params) {
|
|
|
276
287
|
const planPrompt = {
|
|
277
288
|
role: 'system',
|
|
278
289
|
content: 'Kullanilabilir tool\'lar:\n' + tools.map(t => '- ' + t).join('\n') +
|
|
279
|
-
'\n\
|
|
290
|
+
'\n\nKullanilabilir skill\'ler:\n' + skillsIndexBlock +
|
|
291
|
+
'\n\nGorev icin bir workflow plani JSON formatinda olustur. JSON disinda hicbir sey yazma.\nFormat: { "workflowName": "...", "description": "...", "estimatedSteps": N, "skillsLoaded": ["..."], "steps": [{ "step": 1, "tool": "...", "purpose": "...", "params": {...}, "expectedOutput": "..." }] }\n\nGorevle ilgili skill varsa plana skill_view adimi olarak ekle.'
|
|
280
292
|
};
|
|
281
293
|
const planBody = {
|
|
282
294
|
model, stream: false,
|
package/src/utils/cron.js
CHANGED
|
@@ -1,126 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (schedule.startsWith('daily at ')) {
|
|
87
|
-
const time = schedule.replace('daily at ', '');
|
|
88
|
-
const [hour, minute = '0'] = time.split(':');
|
|
89
|
-
return `${minute} ${hour} * * *`;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Zaten cron expression ise olduğu gibi döndür
|
|
93
|
-
return schedule;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function validateCronExpression(expression) {
|
|
97
|
-
return cron.validate(expression);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function logCronOutput(jobId, output) {
|
|
101
|
-
const logFile = path.join(CRON_LOGS_DIR, `${jobId}.log`);
|
|
102
|
-
const timestamp = new Date().toISOString();
|
|
103
|
-
const logEntry = `[${timestamp}]\n${output}\n\n`;
|
|
104
|
-
fs.appendFileSync(logFile, logEntry, 'utf-8');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getCronLog(jobId) {
|
|
108
|
-
const logFile = path.join(CRON_LOGS_DIR, `${jobId}.log`);
|
|
109
|
-
if (!fs.existsSync(logFile)) {
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
return fs.readFileSync(logFile, 'utf-8');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
module.exports = {
|
|
116
|
-
loadCronJobs,
|
|
117
|
-
saveCronJobs,
|
|
118
|
-
addCronJob,
|
|
119
|
-
removeCronJob,
|
|
120
|
-
updateCronJob,
|
|
121
|
-
getCronJob,
|
|
122
|
-
parseCronSchedule,
|
|
123
|
-
validateCronExpression,
|
|
124
|
-
logCronOutput,
|
|
125
|
-
getCronLog,
|
|
126
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* cron — Scheduled task monitoring (cron-like expressions)
|
|
3
|
+
*
|
|
4
|
+
* Format (standard cron): min hour dom mon dow
|
|
5
|
+
* e.g., "every 5 min" -> minute field = "star/5"
|
|
6
|
+
* Checks if a task should run based on its schedule.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
|
|
13
|
+
const CRON_FILE = path.join(os.homedir(), '.natureco', 'cron-jobs.json');
|
|
14
|
+
|
|
15
|
+
function parseCron(expr) {
|
|
16
|
+
const parts = expr.trim().split(/\s+/);
|
|
17
|
+
if (parts.length !== 5) return null;
|
|
18
|
+
const [min, hour, dom, mon, dow] = parts;
|
|
19
|
+
return { min, hour, dom, mon, dow };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function matchesField(value, pattern) {
|
|
23
|
+
if (pattern === '*') return true;
|
|
24
|
+
if (pattern.startsWith('*/')) {
|
|
25
|
+
const step = parseInt(pattern.slice(2), 10);
|
|
26
|
+
return value % step === 0;
|
|
27
|
+
}
|
|
28
|
+
if (pattern.includes(',')) return pattern.split(',').some(p => matchesField(value, p));
|
|
29
|
+
if (pattern.includes('-')) {
|
|
30
|
+
const [lo, hi] = pattern.split('-').map(Number);
|
|
31
|
+
return value >= lo && value <= hi;
|
|
32
|
+
}
|
|
33
|
+
return parseInt(pattern, 10) === value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function shouldRun(expr) {
|
|
37
|
+
const parsed = parseCron(expr);
|
|
38
|
+
if (!parsed) return false;
|
|
39
|
+
const now = new Date();
|
|
40
|
+
return (
|
|
41
|
+
matchesField(now.getMinutes(), parsed.min) &&
|
|
42
|
+
matchesField(now.getHours(), parsed.hour) &&
|
|
43
|
+
matchesField(now.getDate(), parsed.dom) &&
|
|
44
|
+
matchesField(now.getMonth() + 1, parsed.mon) &&
|
|
45
|
+
matchesField(now.getDay(), parsed.dow)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function loadJobs() {
|
|
50
|
+
try {
|
|
51
|
+
if (fs.existsSync(CRON_FILE)) return JSON.parse(fs.readFileSync(CRON_FILE, 'utf8'));
|
|
52
|
+
} catch {}
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function addJob(job) {
|
|
57
|
+
const jobs = loadJobs();
|
|
58
|
+
const entry = {
|
|
59
|
+
id: `cron_${Date.now()}`,
|
|
60
|
+
schedule: job.schedule,
|
|
61
|
+
command: job.command,
|
|
62
|
+
description: job.description || '',
|
|
63
|
+
createdAt: Date.now(),
|
|
64
|
+
lastRun: null,
|
|
65
|
+
enabled: true,
|
|
66
|
+
};
|
|
67
|
+
jobs.push(entry);
|
|
68
|
+
const dir = path.dirname(CRON_FILE);
|
|
69
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
70
|
+
fs.writeFileSync(CRON_FILE, JSON.stringify(jobs, null, 2));
|
|
71
|
+
return entry;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function removeJob(id) {
|
|
75
|
+
const jobs = loadJobs().filter(j => j.id !== id);
|
|
76
|
+
const dir = path.dirname(CRON_FILE);
|
|
77
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
78
|
+
fs.writeFileSync(CRON_FILE, JSON.stringify(jobs, null, 2));
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { parseCron, shouldRun, loadJobs, addJob, removeJob };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* effort-levels — Effort level control (Claude Code: low/medium/high)
|
|
3
|
+
*
|
|
4
|
+
* Controls token budget, iteration limits, and tool breadth:
|
|
5
|
+
* low: quick answers, 2 tool iterations, 1024 max_tokens, minimal tools
|
|
6
|
+
* medium: balanced, 5 iterations, 2048 max_tokens, standard tools (default)
|
|
7
|
+
* high: thorough, 12 iterations, 4096 max_tokens, all tools
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const LEVELS = { low: 'low', medium: 'medium', high: 'high' };
|
|
11
|
+
|
|
12
|
+
const CONFIG = {
|
|
13
|
+
low: {
|
|
14
|
+
maxTokens: 1024,
|
|
15
|
+
maxToolIterations: 2,
|
|
16
|
+
temperature: 0.1,
|
|
17
|
+
toolBreadth: 'minimal',
|
|
18
|
+
},
|
|
19
|
+
medium: {
|
|
20
|
+
maxTokens: 2048,
|
|
21
|
+
maxToolIterations: 5,
|
|
22
|
+
temperature: 0.3,
|
|
23
|
+
toolBreadth: 'standard',
|
|
24
|
+
},
|
|
25
|
+
high: {
|
|
26
|
+
maxTokens: 4096,
|
|
27
|
+
maxToolIterations: 12,
|
|
28
|
+
temperature: 0.5,
|
|
29
|
+
toolBreadth: 'all',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function getLevel(cfg = {}) {
|
|
34
|
+
const level = (cfg.effort || cfg.effortLevel || 'medium').toLowerCase();
|
|
35
|
+
return LEVELS[level] || 'medium';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getConfig(level) {
|
|
39
|
+
return CONFIG[level] || CONFIG.medium;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { LEVELS, CONFIG, getLevel, getConfig };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fallback-chain — Multi-model fallback chain (3 models max)
|
|
3
|
+
*
|
|
4
|
+
* Config:
|
|
5
|
+
* "models": ["gpt-4", "claude-3", "gemini-pro"]
|
|
6
|
+
* "fallback": {
|
|
7
|
+
* "enabled": true,
|
|
8
|
+
* "onError": true,
|
|
9
|
+
* "onRateLimit": true,
|
|
10
|
+
* "onTimeout": true
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* Returns which model to use for each turn, rotating through the chain
|
|
14
|
+
* when errors occur.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
class FallbackChain {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.models = [];
|
|
20
|
+
this.currentIndex = 0;
|
|
21
|
+
this.config = { onError: true, onRateLimit: true, onTimeout: true };
|
|
22
|
+
this.fallbacksUsed = 0;
|
|
23
|
+
this.history = [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
configure(models, config = {}) {
|
|
27
|
+
this.models = Array.isArray(models) ? models.filter(Boolean) : [];
|
|
28
|
+
this.currentIndex = 0;
|
|
29
|
+
this.fallbacksUsed = 0;
|
|
30
|
+
this.config = { ...this.config, ...config };
|
|
31
|
+
this.history = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get current() {
|
|
35
|
+
return this.models[this.currentIndex] || null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get hasFallback() {
|
|
39
|
+
return this.currentIndex < this.models.length - 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get remaining() {
|
|
43
|
+
return Math.max(0, this.models.length - this.currentIndex - 1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get list() {
|
|
47
|
+
return [...this.models];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
recordError(model, error) {
|
|
51
|
+
this.history.push({ model, error: error.message || String(error), at: Date.now() });
|
|
52
|
+
if (this.hasFallback) {
|
|
53
|
+
this.currentIndex++;
|
|
54
|
+
this.fallbacksUsed++;
|
|
55
|
+
return { fallback: true, nextModel: this.current, from: model };
|
|
56
|
+
}
|
|
57
|
+
return { fallback: false, nextModel: null, from: model };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
reset() {
|
|
61
|
+
this.currentIndex = 0;
|
|
62
|
+
this.fallbacksUsed = 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let _instance = null;
|
|
67
|
+
function getFallbackChain() {
|
|
68
|
+
if (!_instance) _instance = new FallbackChain();
|
|
69
|
+
return _instance;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { FallbackChain, getFallbackChain };
|