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
package/src/commands/code_v5.js
CHANGED
|
@@ -20,7 +20,17 @@ const readline = require("readline");
|
|
|
20
20
|
const chalk = require("chalk");
|
|
21
21
|
const tui = require("../utils/tui");
|
|
22
22
|
const { getConfig } = require("../utils/config");
|
|
23
|
-
const { loadToolDefinitions, executeTool } = require("../utils/tools");
|
|
23
|
+
const { loadToolDefinitions, executeTool, toOpenAIFormat } = require("../utils/tools");
|
|
24
|
+
const { checkPreHooks, runPostHooks, permissionSummary } = require("../utils/tool-hooks");
|
|
25
|
+
const { checkPermission, isApproved, markApproved, formatPermissionPrompt } = require("../utils/permissions");
|
|
26
|
+
const { getPlanMode } = require("../utils/plan-mode");
|
|
27
|
+
const { getWorktree } = require("../utils/worktree");
|
|
28
|
+
const { getLevel: getEffortLevel, getConfig: getEffortConfig } = require("../utils/effort-levels");
|
|
29
|
+
const { getResponseFormat } = require("../utils/structured-output");
|
|
30
|
+
const { getFallbackChain } = require("../utils/fallback-chain");
|
|
31
|
+
const { getTaskManager } = require("../utils/tasks");
|
|
32
|
+
const { buildTiers, assemble, discoverProjectRules } = require("../utils/system-prompt");
|
|
33
|
+
const { buildSkillIndex } = require("../utils/skill-index");
|
|
24
34
|
|
|
25
35
|
const IS_MAC = os.platform() === "darwin";
|
|
26
36
|
const MAX_ITERATIONS = 10;
|
|
@@ -59,23 +69,34 @@ async function apiRequest(url, key, body) {
|
|
|
59
69
|
|
|
60
70
|
async function sendMessageWithTools(providerUrl, providerKey, model, messages, toolDefs) {
|
|
61
71
|
const isMM = isMiniMax(providerUrl);
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
const effortLevel = getEffortLevel();
|
|
73
|
+
const effortCfg = getEffortConfig(effortLevel);
|
|
74
|
+
const fallbackChain = getFallbackChain();
|
|
75
|
+
const openaiTools = toOpenAIFormat(toolDefs);
|
|
66
76
|
const body = {
|
|
67
|
-
model,
|
|
77
|
+
model: fallbackChain.current || model,
|
|
68
78
|
messages,
|
|
69
|
-
temperature:
|
|
70
|
-
max_tokens:
|
|
79
|
+
temperature: effortCfg.temperature,
|
|
80
|
+
max_tokens: effortCfg.maxTokens,
|
|
71
81
|
stream: false,
|
|
72
82
|
};
|
|
73
|
-
if (
|
|
74
|
-
body.tools =
|
|
83
|
+
if (openaiTools.length > 0) {
|
|
84
|
+
body.tools = openaiTools;
|
|
75
85
|
body.tool_choice = "auto";
|
|
76
86
|
}
|
|
77
|
-
const
|
|
78
|
-
|
|
87
|
+
const respFmt = getResponseFormat({});
|
|
88
|
+
if (respFmt) body.response_format = respFmt;
|
|
89
|
+
try {
|
|
90
|
+
const res = await apiRequest(providerUrl, providerKey, body);
|
|
91
|
+
return res.choices?.[0]?.message || {};
|
|
92
|
+
} catch (err) {
|
|
93
|
+
const fb = fallbackChain.recordError(body.model, err);
|
|
94
|
+
if (fb.fallback) {
|
|
95
|
+
console.log(tui.C.yellow(`\n ⚠ ${body.model} başarısız → ${fb.nextModel} deneniyor...\n`));
|
|
96
|
+
return sendMessageWithTools(providerUrl, providerKey, fb.nextModel, messages, toolDefs);
|
|
97
|
+
}
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
79
100
|
}
|
|
80
101
|
|
|
81
102
|
function confirm(prompt) {
|
|
@@ -285,6 +306,126 @@ async function codeV5(targetPath) {
|
|
|
285
306
|
const projectCtx = scanProject(cwd);
|
|
286
307
|
const toolDefs = loadToolDefinitions();
|
|
287
308
|
|
|
309
|
+
// Inject virtual tools
|
|
310
|
+
const planMode = getPlanMode();
|
|
311
|
+
const wt = getWorktree();
|
|
312
|
+
const taskMgr = getTaskManager();
|
|
313
|
+
|
|
314
|
+
// File tracking for summary + snapshots
|
|
315
|
+
function trackFileChanges(toolName, args, result) {
|
|
316
|
+
if (toolName === 'write_file' || toolName === 'edit_file') {
|
|
317
|
+
const fp = args.filePath || args.path;
|
|
318
|
+
if (fp && result && result.success !== false) {
|
|
319
|
+
filesChanged++;
|
|
320
|
+
try {
|
|
321
|
+
const fh = require('../utils/file-history');
|
|
322
|
+
const content = fs.readFileSync(fp, 'utf8');
|
|
323
|
+
fh.snapshot(fp, content);
|
|
324
|
+
} catch {}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (toolName === 'bash' || toolName === 'shell_command') commandsRun++;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function processToolCallsWithTracking(reply, config, toolDefs, messages) {
|
|
331
|
+
return processToolCalls(reply, config, toolDefs, messages, trackFileChanges);
|
|
332
|
+
}
|
|
333
|
+
const virtualTools = [
|
|
334
|
+
{
|
|
335
|
+
name: 'EnterPlanMode',
|
|
336
|
+
description: 'Switch to plan-only mode. Research and plan without making changes. Use ExitPlanMode when ready.',
|
|
337
|
+
parameters: { type: 'object', properties: {}, required: [] },
|
|
338
|
+
execute: async () => {
|
|
339
|
+
if (planMode.enter()) return { result: 'Plan mode activated. Use ExitPlanMode when your plan is ready.' };
|
|
340
|
+
return { result: 'Already in plan mode.' };
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: 'ExitPlanMode',
|
|
345
|
+
description: 'Exit plan mode and present your plan for review.',
|
|
346
|
+
parameters: { type: 'object', properties: { plan: { type: 'string' }, summary: { type: 'string' } }, required: ['plan'] },
|
|
347
|
+
execute: async (args) => {
|
|
348
|
+
const ok = planMode.exit(args.plan);
|
|
349
|
+
if (!ok) return { error: 'Not in plan mode.' };
|
|
350
|
+
console.log(tui.C.cyan('\n 📋 Plan sunuldu. Onay için /plan approve yazın, red için /plan reject.\n'));
|
|
351
|
+
return { result: `Plan submitted.\n\n${args.plan}` };
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
name: 'EnterWorktree',
|
|
356
|
+
description: 'Create an isolated worktree for experimental changes.',
|
|
357
|
+
parameters: { type: 'object', properties: { branch: { type: 'string' } } },
|
|
358
|
+
execute: async (args) => wt.enter(args),
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: 'ExitWorktree',
|
|
362
|
+
description: 'Exit the current worktree and merge changes back.',
|
|
363
|
+
parameters: { type: 'object', properties: { merge: { type: 'boolean' } } },
|
|
364
|
+
execute: async (args) => wt.exit(args),
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
name: 'CreateTask', description: 'Run a command in the background.',
|
|
368
|
+
parameters: { type: 'object', properties: { command: { type: 'string' }, timeout: { type: 'number' } }, required: ['command'] },
|
|
369
|
+
execute: async (args) => taskMgr.create(args.command, args),
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
name: 'ListTasks', description: 'List all background tasks.',
|
|
373
|
+
parameters: { type: 'object', properties: {} },
|
|
374
|
+
execute: async () => ({ tasks: taskMgr.list() }),
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
name: 'GetTaskResult', description: 'Get the full result of a task.',
|
|
378
|
+
parameters: { type: 'object', properties: { taskId: { type: 'string' } }, required: ['taskId'] },
|
|
379
|
+
execute: async (args) => { const t = taskMgr.get(args.taskId); return t || { error: 'Task not found' }; },
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
name: 'StopTask', description: 'Stop a running task.',
|
|
383
|
+
parameters: { type: 'object', properties: { taskId: { type: 'string' } }, required: ['taskId'] },
|
|
384
|
+
execute: async (args) => taskMgr.stop(args.taskId),
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
name: 'SearchSessions', description: 'Search past sessions.',
|
|
388
|
+
parameters: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] },
|
|
389
|
+
execute: async (args) => { const { search } = require('../utils/session-search'); return { results: search(args.query, 5) }; },
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: 'RestoreFile', description: 'Restore a file from snapshot history.',
|
|
393
|
+
parameters: { type: 'object', properties: { filePath: { type: 'string' }, timestamp: { type: 'number' } }, required: ['filePath'] },
|
|
394
|
+
execute: async (args) => { const fh = require('../utils/file-history'); const snaps = fh.getHistory(args.filePath); if (!snaps.length) return { error: 'No history' }; return fh.restore(args.filePath, args.timestamp || snaps[0].timestamp); },
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
name: 'FileHistory', description: 'List snapshot history for a file.',
|
|
398
|
+
parameters: { type: 'object', properties: { filePath: { type: 'string' } }, required: ['filePath'] },
|
|
399
|
+
execute: async (args) => { const fh = require('../utils/file-history'); return { snapshots: fh.getHistory(args.filePath) }; },
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: 'UltraReview', description: 'Multi-focus code review (security, style, logic, performance).',
|
|
403
|
+
parameters: { type: 'object', properties: { files: { type: 'array', items: { type: 'string' } }, diff: { type: 'string' } } },
|
|
404
|
+
execute: async (args) => {
|
|
405
|
+
const ur = require('../utils/ultra-review');
|
|
406
|
+
if (args.diff) return ur.reviewDiff(args.diff);
|
|
407
|
+
if (args.files) return { reviews: args.files.map(f => { try { return ur.reviewFile(f, fs.readFileSync(f, 'utf8')); } catch { return { file: f, error: 'Not found' }; } }) };
|
|
408
|
+
return { error: 'Specify files or diff' };
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
name: 'ScheduleTask', description: 'Schedule a recurring cron task.',
|
|
413
|
+
parameters: { type: 'object', properties: { schedule: { type: 'string' }, command: { type: 'string' }, description: { type: 'string' } }, required: ['schedule', 'command'] },
|
|
414
|
+
execute: async (args) => require('../utils/cron').addJob(args),
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
name: 'ListScheduledTasks', description: 'List cron tasks.',
|
|
418
|
+
parameters: { type: 'object', properties: {} },
|
|
419
|
+
execute: async () => ({ jobs: require('../utils/cron').loadJobs() }),
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: 'RemoveScheduledTask', description: 'Remove a cron task.',
|
|
423
|
+
parameters: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },
|
|
424
|
+
execute: async (args) => { require('../utils/cron').removeJob(args.id); return { removed: true }; },
|
|
425
|
+
},
|
|
426
|
+
];
|
|
427
|
+
toolDefs.push(...virtualTools);
|
|
428
|
+
|
|
288
429
|
// Header / Welcome
|
|
289
430
|
console.log("");
|
|
290
431
|
console.log(tui.styled(" ╭" + "─".repeat(58) + "╮", { color: tui.PALETTE.primary }));
|
|
@@ -308,19 +449,26 @@ async function codeV5(targetPath) {
|
|
|
308
449
|
}
|
|
309
450
|
|
|
310
451
|
console.log("\n " + tui.C.muted("Komutlar:"));
|
|
452
|
+
console.log(" " + tui.C.amber("/plan on|approve|reject|show") + tui.C.muted(" — Plan modu"));
|
|
311
453
|
console.log(" " + tui.C.amber("/summary") + tui.C.muted(" — Oturum özeti"));
|
|
312
454
|
console.log(" " + tui.C.amber("/done") + tui.C.muted(" — Özet + çıkış"));
|
|
313
455
|
console.log(" " + tui.C.amber("Ctrl+C") + tui.C.muted(" — Çıkış"));
|
|
314
456
|
console.log("");
|
|
315
457
|
|
|
316
|
-
//
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
458
|
+
// Three-tier system prompt (Hermes-style)
|
|
459
|
+
const skillsIndexBlock = buildSkillIndex();
|
|
460
|
+
const cfg = getConfig();
|
|
461
|
+
const projectRules = discoverProjectRules(cwd);
|
|
462
|
+
const promptOpts = {
|
|
463
|
+
botName: 'Code Agent',
|
|
464
|
+
userName: cfg.userName || 'kullanıcı',
|
|
465
|
+
skillsIndexBlock,
|
|
466
|
+
projectRules,
|
|
467
|
+
hasHistory: false,
|
|
468
|
+
userHome: os.homedir(),
|
|
469
|
+
};
|
|
470
|
+
const { stable, context, volatile } = buildTiers(promptOpts);
|
|
471
|
+
const systemPrompt = assemble(stable, context, volatile);
|
|
324
472
|
|
|
325
473
|
let messages = [{ role: "system", content: systemPrompt }];
|
|
326
474
|
let totalIn = 0, totalOut = 0;
|
|
@@ -337,83 +485,133 @@ async function codeV5(targetPath) {
|
|
|
337
485
|
if (!input) { process.stdout.write(" " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true })); return ask(); }
|
|
338
486
|
if (input === "/summary") {
|
|
339
487
|
printSummary(filesChanged, commandsRun, messages.length - 1, startTime);
|
|
340
|
-
// v5.6.22: /summary sadece gosterir, cikmaz
|
|
341
488
|
process.stdout.write("\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
|
|
342
489
|
return ask();
|
|
343
490
|
}
|
|
344
491
|
if (input === "/done" || input === "exit" || input === "quit") {
|
|
345
|
-
// v5.6.22: /done cikinca summary goster
|
|
346
492
|
printSummary(filesChanged, commandsRun, messages.length - 1, startTime);
|
|
347
493
|
rl.close();
|
|
348
494
|
return;
|
|
349
495
|
}
|
|
496
|
+
if (input.startsWith("/plan ")) {
|
|
497
|
+
const arg = input.slice(6).trim();
|
|
498
|
+
const pm = getPlanMode();
|
|
499
|
+
if (arg === "on" || arg === "enter") {
|
|
500
|
+
if (pm.enter()) console.log(tui.C.cyan('\n 📋 Plan modu aktif.\n'));
|
|
501
|
+
else console.log(tui.C.yellow(' Zaten plan modunda.'));
|
|
502
|
+
} else if (arg === "approve") {
|
|
503
|
+
if (pm.inReview()) { pm.approve(); console.log(tui.C.green(' ✓ Plan onaylandı.\n')); }
|
|
504
|
+
else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
|
|
505
|
+
} else if (arg === "reject") {
|
|
506
|
+
if (pm.inReview()) { pm.reject(); console.log(tui.C.amber(' ⨯ Plan reddedildi.\n')); }
|
|
507
|
+
else console.log(tui.C.yellow(' Onay bekleyen plan yok.'));
|
|
508
|
+
} else if (arg === "show") {
|
|
509
|
+
if (pm.planHistory.length > 0) console.log(tui.C.cyan('\n 📋 Son Plan:\n ' + pm.planHistory[pm.planHistory.length - 1].plan.replace(/\n/g, '\n ') + '\n'));
|
|
510
|
+
else console.log(tui.C.yellow(' Henüz plan yok.'));
|
|
511
|
+
} else {
|
|
512
|
+
console.log(tui.C.yellow(' Kullanım: /plan on|approve|reject|show'));
|
|
513
|
+
}
|
|
514
|
+
process.stdout.write("\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
|
|
515
|
+
return ask();
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Workflow step — run before every request
|
|
519
|
+
process.stdout.write(tui.styled('\r 🔧 workflow... ', { color: tui.PALETTE.muted }));
|
|
520
|
+
const wfResult = await executeTool('workflow', { action: 'run', task: input }, toolDefs);
|
|
521
|
+
const wf = wfResult?.result || {};
|
|
522
|
+
if (wf.success !== false) {
|
|
523
|
+
const loaded = wf.skillsLoaded && wf.skillsLoaded.length > 0 ? ` [skill: ${wf.skillsLoaded.join(', ')}]` : '';
|
|
524
|
+
process.stdout.write(tui.styled(` ✓ workflow${loaded}\n`, { color: tui.PALETTE.success }));
|
|
525
|
+
} else {
|
|
526
|
+
process.stdout.write(tui.styled(' ✗ workflow\n', { color: tui.PALETTE.danger }));
|
|
527
|
+
}
|
|
350
528
|
|
|
351
529
|
messages.push({ role: "user", content: input });
|
|
352
|
-
process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
|
|
353
530
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
531
|
+
if (wf.passthrough && wf.reply !== undefined && wf.reply !== null) {
|
|
532
|
+
// Simple chat — workflow handled it directly
|
|
533
|
+
const fullReply = String(wf.reply);
|
|
534
|
+
process.stdout.write('\n' + fullReply + '\n');
|
|
535
|
+
messages.push({ role: 'assistant', content: fullReply });
|
|
536
|
+
totalIn += Math.ceil(input.length / 4);
|
|
537
|
+
totalOut += Math.ceil(fullReply.length / 4);
|
|
538
|
+
} else if (wf.status === 'completed' || (wf.results && wf.results.length > 0)) {
|
|
539
|
+
// Complex task — inject workflow report as context, then LLM crafts final reply
|
|
540
|
+
const workflowSteps = wf.results || [];
|
|
541
|
+
const report = workflowSteps.map(r => {
|
|
542
|
+
const t = r.tool || r.name || '?';
|
|
543
|
+
const s = r.status === 'done' ? '✓' : '✗';
|
|
544
|
+
let summary = '';
|
|
545
|
+
if (r.result) {
|
|
546
|
+
try { summary = typeof r.result === 'string' ? r.result.slice(0, 400) : JSON.stringify(r.result).slice(0, 400); } catch {}
|
|
547
|
+
}
|
|
548
|
+
return ` ${s} ${t}: ${summary}`;
|
|
549
|
+
}).join('\n');
|
|
550
|
+
const skillInfo = wf.skillsLoaded && wf.skillsLoaded.length > 0
|
|
551
|
+
? `\n\nKullanilan skill'ler: ${wf.skillsLoaded.join(', ')}`
|
|
552
|
+
: '';
|
|
553
|
+
const preWfLen = messages.length;
|
|
554
|
+
messages.push({
|
|
555
|
+
role: 'system',
|
|
556
|
+
content: `=== WORKFLOW SONUCLARI ===\nSu araclar calisti:\n${report}${skillInfo}\n\nKullaniciya bu sonuclari anlamli bir sekilde ozetle.\n=== SONUC BITTI ===`,
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
|
|
560
|
+
|
|
561
|
+
// Single LLM call to summarize workflow results
|
|
562
|
+
let wfReply = null;
|
|
358
563
|
try {
|
|
359
|
-
|
|
564
|
+
wfReply = await sendMessageWithTools(
|
|
360
565
|
config.providerUrl, config.providerApiKey, config.providerModel,
|
|
361
566
|
messages, toolDefs
|
|
362
567
|
);
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
568
|
+
// Remove workflow results after call
|
|
569
|
+
messages.splice(preWfLen, 1);
|
|
570
|
+
if (wfReply.content) {
|
|
571
|
+
process.stdout.write(wfReply.content);
|
|
572
|
+
messages.push({ role: "assistant", content: wfReply.content });
|
|
573
|
+
totalOut += Math.ceil(wfReply.content.length / 4);
|
|
574
|
+
}
|
|
575
|
+
// Handle any tool calls from the summary (rare but possible)
|
|
576
|
+
if (wfReply.tool_calls && wfReply.tool_calls.length > 0) {
|
|
577
|
+
await processToolCallsWithTracking(wfReply, config, toolDefs, messages);
|
|
367
578
|
}
|
|
579
|
+
} catch (e) {
|
|
580
|
+
console.log("\n " + tui.C.red("❌ " + e.message));
|
|
581
|
+
}
|
|
368
582
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
console.log("\n " + tui.C.yellow("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı."));
|
|
386
|
-
break;
|
|
583
|
+
totalIn += Math.ceil(((wfReply?.content || '') + report + skillInfo).length / 4) + Math.ceil(input.length / 4);
|
|
584
|
+
} else {
|
|
585
|
+
// Workflow failed or returned unexpected format — fallback to multi-turn LLM
|
|
586
|
+
process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
|
|
587
|
+
let iter = 0;
|
|
588
|
+
while (iter < MAX_ITERATIONS) {
|
|
589
|
+
iter++;
|
|
590
|
+
try {
|
|
591
|
+
const reply = await sendMessageWithTools(
|
|
592
|
+
config.providerUrl, config.providerApiKey, config.providerModel,
|
|
593
|
+
messages, toolDefs
|
|
594
|
+
);
|
|
595
|
+
if (reply.content) {
|
|
596
|
+
process.stdout.write(reply.content);
|
|
597
|
+
messages.push({ role: "assistant", content: reply.content });
|
|
598
|
+
totalOut += Math.ceil(reply.content.length / 4);
|
|
387
599
|
}
|
|
388
600
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
394
|
-
printToolCall(name, args);
|
|
395
|
-
if (name === "bash" || name === "shell_command") commandsRun++;
|
|
396
|
-
if (name === "write_file" || name === "edit_file") filesChanged++;
|
|
397
|
-
const result = await executeTool(name, args, toolDefs);
|
|
398
|
-
// v5.6.21: Sonuç gizleme - sadece status goster, yol/size gizle
|
|
399
|
-
printToolCallSafe(name, args, result);
|
|
400
|
-
const out = result.error
|
|
401
|
-
? "ERROR: " + result.error
|
|
402
|
-
: (typeof result.result === "string" ? result.result : JSON.stringify(result.result));
|
|
403
|
-
messages.push({ role: "tool", tool_call_id: tc.id, content: (out || "(empty)").slice(0, 8000) });
|
|
404
|
-
totalIn += Math.ceil(out.length / 4);
|
|
601
|
+
if (reply.tool_calls && reply.tool_calls.length > 0) {
|
|
602
|
+
await processToolCallsWithTracking(reply, config, toolDefs, messages);
|
|
603
|
+
process.stdout.write("\n " + tui.styled("AI ", { color: tui.PALETTE.secondary, bold: true }));
|
|
604
|
+
continue;
|
|
405
605
|
}
|
|
406
|
-
|
|
407
|
-
|
|
606
|
+
break;
|
|
607
|
+
} catch (e) {
|
|
608
|
+
console.log("\n " + tui.C.red("❌ " + e.message));
|
|
609
|
+
break;
|
|
408
610
|
}
|
|
409
|
-
break;
|
|
410
|
-
} catch (e) {
|
|
411
|
-
console.log("\n " + tui.C.red("❌ " + e.message));
|
|
412
|
-
break;
|
|
413
611
|
}
|
|
612
|
+
totalIn += Math.ceil(input.length / 4);
|
|
414
613
|
}
|
|
415
614
|
|
|
416
|
-
totalIn += Math.ceil(input.length / 4);
|
|
417
615
|
process.stdout.write("\n\n " + tui.styled("You ", { color: tui.PALETTE.primary, bold: true }));
|
|
418
616
|
ask();
|
|
419
617
|
});
|
|
@@ -421,6 +619,112 @@ async function codeV5(targetPath) {
|
|
|
421
619
|
ask();
|
|
422
620
|
}
|
|
423
621
|
|
|
622
|
+
const PARALLEL_SAFE_TOOLS = new Set(['read_file', 'file_search', 'grep_search', 'web_search', 'web_readability', 'duckduckgo_search', 'exa_search', 'searxng_search', 'firecrawl', 'memory_search', 'memory']);
|
|
623
|
+
|
|
624
|
+
async function processToolCalls(reply, config, toolDefs, messages, onToolResult) {
|
|
625
|
+
for (const tc of reply.tool_calls) {
|
|
626
|
+
let args = {};
|
|
627
|
+
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
628
|
+
const risk = assessRisk(tc.function.name, args);
|
|
629
|
+
|
|
630
|
+
// Built-in risk assessment
|
|
631
|
+
if (risk.requiresApproval) {
|
|
632
|
+
process.stdout.write("\n");
|
|
633
|
+
const approved = await confirm(
|
|
634
|
+
`⚠ ${tc.function.name}: ${risk.reason}\n Devam edilsin mi? (Y/n) `
|
|
635
|
+
);
|
|
636
|
+
if (!approved) {
|
|
637
|
+
console.log("\n " + tui.C.yellow("⚠ Kullanıcı onayı iptal etti, tool çalıştırılmadı."));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Plan mode check
|
|
643
|
+
const pm = getPlanMode();
|
|
644
|
+
const planCheck = pm.checkTool(tc.function.name, args);
|
|
645
|
+
if (!planCheck.allowed) {
|
|
646
|
+
console.log("\n " + tui.C.red("⛔ Plan modunda engellendi: " + planCheck.reason));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
pm.recordTool(tc.function.name, args);
|
|
650
|
+
|
|
651
|
+
// Permission check
|
|
652
|
+
const perm = checkPermission(tc.function.name, args);
|
|
653
|
+
if (perm.action === 'deny') {
|
|
654
|
+
console.log("\n " + tui.C.red("⛔ İzin engelledi: " + perm.reason));
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
if (perm.action === 'ask') {
|
|
658
|
+
const permKey = `${perm.rule.raw}:${JSON.stringify(args)}`;
|
|
659
|
+
if (!isApproved(permKey)) {
|
|
660
|
+
process.stdout.write("\n");
|
|
661
|
+
const ok = await confirm(`İzin gerekli: ${formatPermissionPrompt(tc.function.name, args, perm.reason)}\n İzin ver? [y=once, Y=session, p=persistent, n=no] `);
|
|
662
|
+
if (ok === 'persistent') markApproved(permKey, true);
|
|
663
|
+
else if (ok === 'session' || ok === true) markApproved(permKey, false);
|
|
664
|
+
else {
|
|
665
|
+
console.log("\n " + tui.C.yellow("⛔ İzin reddedildi"));
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Pre-hook check
|
|
672
|
+
const hook = checkPreHooks(tc.function.name, args);
|
|
673
|
+
if (hook.action === 'deny') {
|
|
674
|
+
console.log("\n " + tui.C.red("⛔ Hook engelledi: " + hook.rule.raw));
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (hook.action === 'ask') {
|
|
678
|
+
const ok = await confirm(`Hook onayı: ${permissionSummary(hook.rule, tc.function.name, args)}\n İzin verilsin mi? (y/N) `);
|
|
679
|
+
if (!ok) {
|
|
680
|
+
console.log("\n " + tui.C.yellow("⛔ Hook reddetti: " + hook.rule.raw));
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
messages.push({ role: "assistant", content: reply.content || null, tool_calls: reply.tool_calls });
|
|
687
|
+
|
|
688
|
+
const parsed = reply.tool_calls.map(tc => {
|
|
689
|
+
let args = {};
|
|
690
|
+
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
691
|
+
return { name: tc.function.name, args, id: tc.id };
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
const parallelSafe = parsed.filter(p => PARALLEL_SAFE_TOOLS.has(p.name));
|
|
695
|
+
const sequential = parsed.filter(p => !PARALLEL_SAFE_TOOLS.has(p.name));
|
|
696
|
+
|
|
697
|
+
// Print all tool calls
|
|
698
|
+
for (const p of parsed) printToolCall(p.name, p.args);
|
|
699
|
+
|
|
700
|
+
// Run parallel-safe tools concurrently
|
|
701
|
+
if (parallelSafe.length > 0) {
|
|
702
|
+
const results = await Promise.all(parallelSafe.map(async (p) => {
|
|
703
|
+
const result = runPostHooks(p.name, p.args, await executeTool(p.name, p.args, toolDefs));
|
|
704
|
+
printToolCallSafe(p.name, p.args, result);
|
|
705
|
+
if (onToolResult) onToolResult(p.name, p.args, result);
|
|
706
|
+
const out = result.error
|
|
707
|
+
? "ERROR: " + result.error
|
|
708
|
+
: (typeof result.result === "string" ? result.result : JSON.stringify(result.result));
|
|
709
|
+
return { id: p.id, content: (out || "(empty)").slice(0, 8000) };
|
|
710
|
+
}));
|
|
711
|
+
for (const r of results) {
|
|
712
|
+
messages.push({ role: "tool", tool_call_id: r.id, content: r.content });
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Run sequential tools one at a time
|
|
717
|
+
for (const p of sequential) {
|
|
718
|
+
const result = runPostHooks(p.name, p.args, await executeTool(p.name, p.args, toolDefs));
|
|
719
|
+
printToolCallSafe(p.name, p.args, result);
|
|
720
|
+
if (onToolResult) onToolResult(p.name, p.args, result);
|
|
721
|
+
const out = result.error
|
|
722
|
+
? "ERROR: " + result.error
|
|
723
|
+
: (typeof result.result === "string" ? result.result : JSON.stringify(result.result));
|
|
724
|
+
messages.push({ role: "tool", tool_call_id: p.id, content: (out || "(empty)").slice(0, 8000) });
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
424
728
|
function printSummary(files, cmds, msgs, startTime) {
|
|
425
729
|
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
426
730
|
const min = Math.floor(elapsed / 60);
|