natureco-cli 5.19.0 → 5.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/package.json +1 -1
  3. package/skills/a-b-testing/SKILL.md +34 -0
  4. package/skills/accessibility-audit/SKILL.md +34 -0
  5. package/skills/agent-memory/SKILL.md +34 -0
  6. package/skills/agent-orchestration/SKILL.md +34 -0
  7. package/skills/analytics-setup/SKILL.md +34 -0
  8. package/skills/api-design/SKILL.md +34 -0
  9. package/skills/api-versioning/SKILL.md +34 -0
  10. package/skills/audio-transcription/SKILL.md +34 -0
  11. package/skills/authentication-patterns/SKILL.md +34 -0
  12. package/skills/authorization-rbac/SKILL.md +34 -0
  13. package/skills/backup-strategy/SKILL.md +34 -0
  14. package/skills/bash-scripting/SKILL.md +34 -0
  15. package/skills/batch-api-calls/SKILL.md +34 -0
  16. package/skills/batch-processing/SKILL.md +34 -0
  17. package/skills/bulk-file-operations/SKILL.md +34 -0
  18. package/skills/cache-responses/SKILL.md +34 -0
  19. package/skills/caching-strategy/SKILL.md +34 -0
  20. package/skills/calendar-optimization/SKILL.md +34 -0
  21. package/skills/changelog-generation/SKILL.md +34 -0
  22. package/skills/chat-bot-design/SKILL.md +34 -0
  23. package/skills/chunking-strategy/SKILL.md +34 -0
  24. package/skills/ci-cd-pipeline/SKILL.md +34 -0
  25. package/skills/classification-pipeline/SKILL.md +34 -0
  26. package/skills/clipboard-master/SKILL.md +34 -0
  27. package/skills/code-explanation/SKILL.md +34 -0
  28. package/skills/code-generation/SKILL.md +34 -0
  29. package/skills/code-migration/SKILL.md +34 -0
  30. package/skills/code-review-checklist/SKILL.md +34 -0
  31. package/skills/contact-management/SKILL.md +34 -0
  32. package/skills/content-generation/SKILL.md +34 -0
  33. package/skills/context-pruning/SKILL.md +34 -0
  34. package/skills/context-window-management/SKILL.md +34 -0
  35. package/skills/continuous-improvement/SKILL.md +34 -0
  36. package/skills/cron-scheduling/SKILL.md +34 -0
  37. package/skills/cross-platform-compat/SKILL.md +34 -0
  38. package/skills/csv-processing/SKILL.md +34 -0
  39. package/skills/daily-journal/SKILL.md +34 -0
  40. package/skills/data-analysis/SKILL.md +34 -0
  41. package/skills/data-backup/SKILL.md +34 -0
  42. package/skills/data-cleaning/SKILL.md +34 -0
  43. package/skills/data-extraction/SKILL.md +34 -0
  44. package/skills/data-validation/SKILL.md +34 -0
  45. package/skills/database-migrations/SKILL.md +34 -0
  46. package/skills/database-schema-design/SKILL.md +34 -0
  47. package/skills/decision-matrix/SKILL.md +34 -0
  48. package/skills/dependency-management/SKILL.md +34 -0
  49. package/skills/dev-environment-setup/SKILL.md +34 -0
  50. package/skills/distraction-blocker/SKILL.md +34 -0
  51. package/skills/docker-optimization/SKILL.md +34 -0
  52. package/skills/document-template/SKILL.md +34 -0
  53. package/skills/documentation-gen/SKILL.md +34 -0
  54. package/skills/efficient-formatting/SKILL.md +34 -0
  55. package/skills/email-management/SKILL.md +34 -0
  56. package/skills/email-service/SKILL.md +34 -0
  57. package/skills/embedding-generation/SKILL.md +34 -0
  58. package/skills/entity-extraction/SKILL.md +34 -0
  59. package/skills/environment-config/SKILL.md +34 -0
  60. package/skills/error-handling/SKILL.md +34 -0
  61. package/skills/estimation-techniques/SKILL.md +34 -0
  62. package/skills/event-driven-architecture/SKILL.md +34 -0
  63. package/skills/excel-automation/SKILL.md +34 -0
  64. package/skills/execution-monitoring/SKILL.md +34 -0
  65. package/skills/expense-tracking/SKILL.md +34 -0
  66. package/skills/feature-engineering/SKILL.md +34 -0
  67. package/skills/feature-flags/SKILL.md +34 -0
  68. package/skills/file-conversion/SKILL.md +34 -0
  69. package/skills/file-upload-handling/SKILL.md +34 -0
  70. package/skills/fine-tuning-prep/SKILL.md +34 -0
  71. package/skills/focus-mode/SKILL.md +34 -0
  72. package/skills/form-validation/SKILL.md +34 -0
  73. package/skills/function-calling/SKILL.md +34 -0
  74. package/skills/git-workflow/SKILL.md +34 -0
  75. package/skills/goal-setting/SKILL.md +34 -0
  76. package/skills/graphql-design/SKILL.md +34 -0
  77. package/skills/habit-tracker/SKILL.md +34 -0
  78. package/skills/hallucination-detection/SKILL.md +34 -0
  79. package/skills/image-processing/SKILL.md +34 -0
  80. package/skills/json-transformation/SKILL.md +34 -0
  81. package/skills/keyboard-shortcuts/SKILL.md +34 -0
  82. package/skills/knowledge-base/SKILL.md +34 -0
  83. package/skills/knowledge-graph/SKILL.md +34 -0
  84. package/skills/kubernetes-deployment/SKILL.md +34 -0
  85. package/skills/language-translation/SKILL.md +34 -0
  86. package/skills/llm-chaining/SKILL.md +34 -0
  87. package/skills/localization-i18n/SKILL.md +34 -0
  88. package/skills/logging-best-practices/SKILL.md +34 -0
  89. package/skills/machine-learning-pipeline/SKILL.md +34 -0
  90. package/skills/meeting-notes/SKILL.md +34 -0
  91. package/skills/meeting-scheduler/SKILL.md +34 -0
  92. package/skills/message-queues/SKILL.md +34 -0
  93. package/skills/message-summarization/SKILL.md +34 -0
  94. package/skills/microservices-architecture/SKILL.md +34 -0
  95. package/skills/milestone-tracking/SKILL.md +34 -0
  96. package/skills/model-deployment/SKILL.md +34 -0
  97. package/skills/model-evaluation/SKILL.md +34 -0
  98. package/skills/monitoring-setup/SKILL.md +34 -0
  99. package/skills/monorepo-setup/SKILL.md +34 -0
  100. package/skills/multi-agent-systems/SKILL.md +34 -0
  101. package/skills/network-troubleshooting/SKILL.md +34 -0
  102. package/skills/note-organization/SKILL.md +34 -0
  103. package/skills/package-publishing/SKILL.md +34 -0
  104. package/skills/password-generator/SKILL.md +34 -0
  105. package/skills/pdf-processing/SKILL.md +34 -0
  106. package/skills/performance-optimization/SKILL.md +34 -0
  107. package/skills/pomodoro-timer/SKILL.md +34 -0
  108. package/skills/powershell-automation/SKILL.md +34 -0
  109. package/skills/priority-filtering/SKILL.md +34 -0
  110. package/skills/project-tracking/SKILL.md +34 -0
  111. package/skills/prompt-compression/SKILL.md +34 -0
  112. package/skills/prompt-engineering/SKILL.md +34 -0
  113. package/skills/push-notifications/SKILL.md +34 -0
  114. package/skills/rag-implementation/SKILL.md +34 -0
  115. package/skills/rate-limiting/SKILL.md +34 -0
  116. package/skills/real-time-communication/SKILL.md +34 -0
  117. package/skills/refactoring-strategy/SKILL.md +34 -0
  118. package/skills/regex-mastery/SKILL.md +34 -0
  119. package/skills/report-generation/SKILL.md +34 -0
  120. package/skills/research-compiler/SKILL.md +34 -0
  121. package/skills/responsive-design/SKILL.md +34 -0
  122. package/skills/rest-api-patterns/SKILL.md +34 -0
  123. package/skills/retrospectives/SKILL.md +34 -0
  124. package/skills/risk-assessment/SKILL.md +34 -0
  125. package/skills/roadmap-creation/SKILL.md +34 -0
  126. package/skills/search-implementation/SKILL.md +34 -0
  127. package/skills/secrets-management/SKILL.md +34 -0
  128. package/skills/security-audit/SKILL.md +34 -0
  129. package/skills/selective-memory/SKILL.md +34 -0
  130. package/skills/semantic-search/SKILL.md +34 -0
  131. package/skills/semantic-versioning/SKILL.md +34 -0
  132. package/skills/sentiment-analysis/SKILL.md +34 -0
  133. package/skills/seo-optimization/SKILL.md +34 -0
  134. package/skills/snippet-manager/SKILL.md +34 -0
  135. package/skills/sprint-planning/SKILL.md +34 -0
  136. package/skills/sql-query-optimization/SKILL.md +34 -0
  137. package/skills/stakeholder-communication/SKILL.md +34 -0
  138. package/skills/state-management/SKILL.md +34 -0
  139. package/skills/statistical-analysis/SKILL.md +34 -0
  140. package/skills/streaming-responses/SKILL.md +34 -0
  141. package/skills/structured-output/SKILL.md +34 -0
  142. package/skills/summarization-techniques/SKILL.md +34 -0
  143. package/skills/system-diagnostics/SKILL.md +34 -0
  144. package/skills/task-decomposition/SKILL.md +34 -0
  145. package/skills/task-prioritization/SKILL.md +34 -0
  146. package/skills/template-library/SKILL.md +34 -0
  147. package/skills/test-generation/SKILL.md +34 -0
  148. package/skills/testing-strategy/SKILL.md +34 -0
  149. package/skills/text-expansion/SKILL.md +34 -0
  150. package/skills/time-blocking/SKILL.md +34 -0
  151. package/skills/token-budgeting/SKILL.md +34 -0
  152. package/skills/token-optimization/SKILL.md +34 -0
  153. package/skills/tool-calling-patterns/SKILL.md +34 -0
  154. package/skills/vector-database-setup/SKILL.md +34 -0
  155. package/skills/video-editing/SKILL.md +34 -0
  156. package/skills/visualization-creation/SKILL.md +34 -0
  157. package/skills/web-scraping/SKILL.md +34 -0
  158. package/skills/webhook-handling/SKILL.md +34 -0
  159. package/skills/weekly-review/SKILL.md +34 -0
  160. package/skills/workflow-automation/SKILL.md +34 -0
  161. package/src/commands/code_v5.js +377 -73
  162. package/src/commands/help.js +3 -1
  163. package/src/commands/naturehub.js +105 -55
  164. package/src/commands/repl.js +506 -87
  165. package/src/providers/model/anthropic.js +84 -0
  166. package/src/providers/model/gemini.js +49 -0
  167. package/src/providers/model/minimax.js +48 -0
  168. package/src/providers/model/ollama.js +42 -0
  169. package/src/providers/model/openai.js +49 -0
  170. package/src/providers/search/duckduckgo.js +45 -0
  171. package/src/providers/search/exa.js +52 -0
  172. package/src/providers/search/searxng.js +51 -0
  173. package/src/providers/search/tavily.js +47 -0
  174. package/src/tools/model_provider.js +71 -0
  175. package/src/tools/parallel_search.js +40 -49
  176. package/src/tools/search_provider.js +79 -0
  177. package/src/tools/web_search.js +42 -62
  178. package/src/tools/workflow.js +27 -10
  179. package/src/utils/cron.js +82 -126
  180. package/src/utils/effort-levels.js +42 -0
  181. package/src/utils/fallback-chain.js +72 -0
  182. package/src/utils/file-history.js +78 -0
  183. package/src/utils/model-provider.js +113 -0
  184. package/src/utils/permissions.js +147 -0
  185. package/src/utils/plan-mode.js +164 -0
  186. package/src/utils/provider-detect.js +7 -32
  187. package/src/utils/sandbox.js +60 -0
  188. package/src/utils/search-provider.js +62 -0
  189. package/src/utils/session-search.js +66 -0
  190. package/src/utils/structured-output.js +20 -0
  191. package/src/utils/system-prompt.js +28 -2
  192. package/src/utils/tasks.js +132 -0
  193. package/src/utils/tool-hooks.js +154 -0
  194. package/src/utils/tools.js +16 -0
  195. package/src/utils/ultra-review.js +59 -0
  196. package/src/utils/worktree.js +192 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * session-search — Full-text search across past sessions
3
+ *
4
+ * Sessions are stored in .natureco/sessions/ as JSON files.
5
+ * This utility indexes and searches them by keyword.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const SESSIONS_DIR = path.join(process.cwd(), '.natureco', 'sessions');
12
+
13
+ function getSessions() {
14
+ if (!fs.existsSync(SESSIONS_DIR)) return [];
15
+ return fs.readdirSync(SESSIONS_DIR)
16
+ .filter(f => f.endsWith('.json'))
17
+ .map(f => {
18
+ const p = path.join(SESSIONS_DIR, f);
19
+ try {
20
+ return { id: f.replace('.json', ''), mtime: fs.statSync(p).mtimeMs, path: p };
21
+ } catch { return null; }
22
+ })
23
+ .filter(Boolean)
24
+ .sort((a, b) => b.mtime - a.mtime);
25
+ }
26
+
27
+ function search(query, maxResults = 10) {
28
+ const q = query.toLowerCase();
29
+ const results = [];
30
+ const sessions = getSessions();
31
+
32
+ for (const session of sessions) {
33
+ try {
34
+ const data = JSON.parse(fs.readFileSync(session.path, 'utf8'));
35
+ const messages = data.messages || [];
36
+ let score = 0;
37
+ const matches = [];
38
+
39
+ for (const msg of messages) {
40
+ const content = (msg.content || '').toLowerCase();
41
+ if (content.includes(q)) {
42
+ score++;
43
+ const snippet = content.slice(
44
+ Math.max(0, content.indexOf(q) - 40),
45
+ content.indexOf(q) + q.length + 40
46
+ );
47
+ matches.push({ role: msg.role, snippet });
48
+ }
49
+ }
50
+
51
+ if (score > 0) {
52
+ results.push({
53
+ id: session.id,
54
+ date: new Date(session.mtime).toISOString(),
55
+ score,
56
+ matches: matches.slice(0, 5),
57
+ firstMessage: data.messages?.[1]?.content?.slice(0, 80) || '',
58
+ });
59
+ }
60
+ } catch {}
61
+ }
62
+
63
+ return results.sort((a, b) => b.score - a.score).slice(0, maxResults);
64
+ }
65
+
66
+ module.exports = { search, getSessions };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * structured-output — JSON Schema-based structured output support
3
+ *
4
+ * Adds response_format to API calls when schema is provided.
5
+ * Config: { "response_format": { "type": "json_object", "schema": {...} } }
6
+ * Tool: SetOutputSchema — defines JSON schema for subsequent responses
7
+ */
8
+
9
+ function hasStructuredOutput(cfg) {
10
+ return !!(cfg.response_format || cfg.jsonSchema || cfg.structuredOutput);
11
+ }
12
+
13
+ function getResponseFormat(cfg) {
14
+ if (cfg.response_format) return cfg.response_format;
15
+ if (cfg.jsonSchema) return { type: 'json_object', schema: cfg.jsonSchema };
16
+ if (cfg.structuredOutput) return { type: 'json_object', schema: cfg.structuredOutput };
17
+ return null;
18
+ }
19
+
20
+ module.exports = { hasStructuredOutput, getResponseFormat };
@@ -25,6 +25,7 @@ function buildTiers(opts) {
25
25
  userHome = '',
26
26
  hasHistory = false,
27
27
  memoryFacts = [],
28
+ projectRules = '',
28
29
  } = opts;
29
30
  const displayBot = botName || 'Asistan';
30
31
  const displayBoss = bossName || userName || 'kullanıcı';
@@ -68,9 +69,10 @@ function buildTiers(opts) {
68
69
  skillsIndexBlock,
69
70
  ].filter(Boolean).join('\n');
70
71
 
71
- // ── CONTEXT TIER (soul + cross-session, built once per resume) ──────
72
+ // ── CONTEXT TIER (soul + project rules + cross-session, built once per resume) ──────
72
73
  const context = [
73
74
  !isSmallModel && soulSummary ? `=== KISISELIK DOSYALARI ===\n${soulSummary}` : '',
75
+ projectRules ? `=== PROJE KURALLARI (CLAUDE.md) ===\n${projectRules}\n=== PROJE KURALLARI BITTI ===` : '',
74
76
  crossSessionContext ? `=== GECMIS KONUSMALAR ===\n${crossSessionContext}` : '',
75
77
  ].filter(Boolean).join('\n');
76
78
 
@@ -107,4 +109,28 @@ function stableContextKey(stable, context) {
107
109
  return stable + '|||' + context;
108
110
  }
109
111
 
110
- module.exports = { buildTiers, assemble, stableContextKey };
112
+ /**
113
+ * CLAUDE.md auto-discover — proje kökünden oku.
114
+ * Cwd'den başlayıp parent dizinlere doğru CLAUDE.md arar.
115
+ */
116
+ function discoverProjectRules(cwd) {
117
+ try {
118
+ const fs = require('fs');
119
+ const path = require('path');
120
+ let dir = path.resolve(cwd || process.cwd());
121
+ // En fazla 5 seviye yukarı çık
122
+ for (let i = 0; i < 5; i++) {
123
+ const candidate = path.join(dir, 'CLAUDE.md');
124
+ if (fs.existsSync(candidate)) {
125
+ const content = fs.readFileSync(candidate, 'utf8').trim();
126
+ if (content.length > 0) return content;
127
+ }
128
+ const parent = path.dirname(dir);
129
+ if (parent === dir) break; // kök dizine ulaştık
130
+ dir = parent;
131
+ }
132
+ } catch {}
133
+ return '';
134
+ }
135
+
136
+ module.exports = { buildTiers, assemble, stableContextKey, discoverProjectRules };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * tasks — Background task management (Claude Code: TaskCreate/TaskList/TaskStop)
3
+ *
4
+ * Tasks run as child processes with status tracking.
5
+ * Tools: CreateTask, ListTasks, StopTask, GetTaskResult
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const os = require('os');
11
+ const fs = require('fs');
12
+
13
+ const TASKS_FILE = path.join(os.homedir(), '.natureco', 'tasks.json');
14
+
15
+ class TaskManager {
16
+ constructor() {
17
+ this.tasks = new Map();
18
+ this._load();
19
+ }
20
+
21
+ create(command, opts = {}) {
22
+ const id = `task_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
23
+ const task = {
24
+ id,
25
+ command,
26
+ status: 'running',
27
+ createdAt: Date.now(),
28
+ completedAt: null,
29
+ exitCode: null,
30
+ stdout: '',
31
+ stderr: '',
32
+ cwd: opts.cwd || process.cwd(),
33
+ };
34
+ this.tasks.set(id, task);
35
+ this._save();
36
+
37
+ const proc = spawn(command, [], {
38
+ shell: true,
39
+ cwd: task.cwd,
40
+ timeout: opts.timeout || 300000,
41
+ env: { ...process.env, ...opts.env },
42
+ });
43
+
44
+ proc.stdout.on('data', data => { task.stdout += data.toString(); });
45
+ proc.stderr.on('data', data => { task.stderr += data.toString(); });
46
+ proc.on('close', code => {
47
+ task.status = code === 0 ? 'completed' : 'failed';
48
+ task.exitCode = code;
49
+ task.completedAt = Date.now();
50
+ this._save();
51
+ });
52
+ proc.on('error', err => {
53
+ task.status = 'failed';
54
+ task.stderr += err.message;
55
+ task.completedAt = Date.now();
56
+ this._save();
57
+ });
58
+
59
+ task._process = proc;
60
+ return { id, status: 'running' };
61
+ }
62
+
63
+ list() {
64
+ return Array.from(this.tasks.values()).map(t => ({
65
+ id: t.id,
66
+ status: t.status,
67
+ command: t.command.slice(0, 80),
68
+ createdAt: t.createdAt,
69
+ completedAt: t.completedAt,
70
+ }));
71
+ }
72
+
73
+ get(id) {
74
+ const task = this.tasks.get(id);
75
+ if (!task) return null;
76
+ return {
77
+ id: task.id,
78
+ command: task.command,
79
+ status: task.status,
80
+ stdout: task.stdout,
81
+ stderr: task.stderr,
82
+ exitCode: task.exitCode,
83
+ createdAt: task.createdAt,
84
+ completedAt: task.completedAt,
85
+ };
86
+ }
87
+
88
+ stop(id) {
89
+ const task = this.tasks.get(id);
90
+ if (!task || task.status !== 'running') return { error: 'Task not found or not running' };
91
+ if (task._process) {
92
+ task._process.kill('SIGTERM');
93
+ setTimeout(() => { if (task._process) task._process.kill('SIGKILL'); }, 5000);
94
+ }
95
+ task.status = 'stopped';
96
+ task.completedAt = Date.now();
97
+ this._save();
98
+ return { id, status: 'stopped' };
99
+ }
100
+
101
+ _save() {
102
+ try {
103
+ const data = Array.from(this.tasks.values()).map(t => ({
104
+ id: t.id, command: t.command, status: t.status,
105
+ createdAt: t.createdAt, completedAt: t.completedAt,
106
+ exitCode: t.exitCode, stdout: t.stdout, stderr: t.stderr,
107
+ }));
108
+ const dir = path.dirname(TASKS_FILE);
109
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
110
+ fs.writeFileSync(TASKS_FILE, JSON.stringify(data, null, 2));
111
+ } catch {}
112
+ }
113
+
114
+ _load() {
115
+ try {
116
+ if (fs.existsSync(TASKS_FILE)) {
117
+ const data = JSON.parse(fs.readFileSync(TASKS_FILE, 'utf8'));
118
+ for (const t of data) {
119
+ this.tasks.set(t.id, { ...t, _process: null });
120
+ }
121
+ }
122
+ } catch {}
123
+ }
124
+ }
125
+
126
+ let _instance = null;
127
+ function getTaskManager() {
128
+ if (!_instance) _instance = new TaskManager();
129
+ return _instance;
130
+ }
131
+
132
+ module.exports = { TaskManager, getTaskManager };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * tool-hooks — Pattern-based pre/post tool execution hooks (Claude Code style)
3
+ *
4
+ * Hooks defined in config under `toolHooks` key:
5
+ * pre: { "ToolName(pattern)": "allow" | "deny" | "ask" }
6
+ * post: { "ToolName(pattern)": "notify" | "record" }
7
+ *
8
+ * Pattern syntax:
9
+ * Bash(git *) — Bash tool, args start with "git"
10
+ * Read(src/**) — Read tool, path starts with "src/"
11
+ * Write(.env*) — Write tool, path starts with ".env"
12
+ * Edit(*) — Edit tool, any path
13
+ * * — All tools
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const os = require('os');
19
+
20
+ function loadRules() {
21
+ const rules = { pre: [], post: [] };
22
+ try {
23
+ const cfgPath = path.join(os.homedir(), '.natureco', 'config.json');
24
+ if (fs.existsSync(cfgPath)) {
25
+ const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
26
+ if (cfg.toolHooks) {
27
+ if (cfg.toolHooks.pre) {
28
+ for (const [pattern, action] of Object.entries(cfg.toolHooks.pre)) {
29
+ rules.pre.push(parseRule(pattern, action));
30
+ }
31
+ }
32
+ if (cfg.toolHooks.post) {
33
+ for (const [pattern, action] of Object.entries(cfg.toolHooks.post)) {
34
+ rules.post.push(parseRule(pattern, action));
35
+ }
36
+ }
37
+ }
38
+ }
39
+ } catch {}
40
+ // Check project-level hooks.json
41
+ try {
42
+ const projectCfg = path.join(process.cwd(), '.natureco', 'hooks.json');
43
+ if (fs.existsSync(projectCfg)) {
44
+ const pCfg = JSON.parse(fs.readFileSync(projectCfg, 'utf8'));
45
+ if (pCfg.pre) {
46
+ for (const [pattern, action] of Object.entries(pCfg.pre)) {
47
+ rules.pre.push(parseRule(pattern, action));
48
+ }
49
+ }
50
+ if (pCfg.post) {
51
+ for (const [pattern, action] of Object.entries(pCfg.post)) {
52
+ rules.post.push(parseRule(pattern, action));
53
+ }
54
+ }
55
+ }
56
+ } catch {}
57
+ return rules;
58
+ }
59
+
60
+ function parseRule(pattern, action) {
61
+ // Pattern: ToolName(glob) or * for all
62
+ const match = pattern.match(/^(\*|[a-zA-Z_]+)\((.+)\)$/);
63
+ let toolName = '*';
64
+ let glob = '*';
65
+ if (match) {
66
+ toolName = match[1];
67
+ glob = match[2];
68
+ } else if (pattern !== '*') {
69
+ toolName = pattern;
70
+ }
71
+ return { toolName, glob, action, raw: pattern };
72
+ }
73
+
74
+ function matchGlob(str, glob) {
75
+ if (glob === '*') return true;
76
+ // Both * and ** match .* since we're matching flat arg strings, not file paths
77
+ const escaped = glob
78
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
79
+ .replace(/\*\*/g, '.*')
80
+ .replace(/\*/g, '.*');
81
+ return new RegExp('^' + escaped + '$').test(str);
82
+ }
83
+
84
+ function flattenArgs(args) {
85
+ if (typeof args === 'string') return args;
86
+ if (args === null || args === undefined) return '';
87
+ const parts = [];
88
+ for (const [k, v] of Object.entries(args)) {
89
+ if (typeof v === 'string') parts.push(v);
90
+ else if (Array.isArray(v)) parts.push(...v.filter(x => typeof x === 'string'));
91
+ else if (typeof v === 'object' && v !== null) parts.push(JSON.stringify(v));
92
+ }
93
+ return parts.join(' ');
94
+ }
95
+
96
+ function matchRule(rule, toolName, args) {
97
+ if (rule.toolName !== '*' && rule.toolName !== toolName) return false;
98
+ // Try matching against flattened args first, then tool name
99
+ const flat = flattenArgs(args);
100
+ return matchGlob(flat, rule.glob) || matchGlob(toolName, rule.glob);
101
+ }
102
+
103
+ /**
104
+ * Check pre-hooks before tool execution.
105
+ * Returns { action: 'allow'|'deny'|'ask', rule, reason }
106
+ */
107
+ function checkPreHooks(toolName, args) {
108
+ const rules = loadRules();
109
+ for (const rule of rules.pre) {
110
+ if (matchRule(rule, toolName, args)) {
111
+ if (rule.action === 'deny') {
112
+ return { action: 'deny', rule, reason: `Hook engelledi: ${rule.raw}` };
113
+ }
114
+ if (rule.action === 'ask') {
115
+ return { action: 'ask', rule, reason: `Hook onay gerektiriyor: ${rule.raw}` };
116
+ }
117
+ if (rule.action === 'allow') {
118
+ return { action: 'allow', rule, reason: '' };
119
+ }
120
+ }
121
+ }
122
+ return { action: 'allow', rule: null, reason: '' };
123
+ }
124
+
125
+ /**
126
+ * Run post-hooks after tool execution.
127
+ * Returns enriched result or original.
128
+ */
129
+ function runPostHooks(toolName, args, result) {
130
+ const rules = loadRules();
131
+ for (const rule of rules.post) {
132
+ if (matchRule(rule, toolName, args)) {
133
+ try {
134
+ const hook = require(path.join(os.homedir(), '.natureco', 'hooks', rule.action));
135
+ if (typeof hook === 'function') {
136
+ return hook({ toolName, args, result }) || result;
137
+ }
138
+ } catch {}
139
+ }
140
+ }
141
+ return result;
142
+ }
143
+
144
+ /**
145
+ * Convert args to string for CLI permission display.
146
+ */
147
+ function permissionSummary(rule, toolName, args) {
148
+ const argsStr = Object.entries(args || {})
149
+ .map(([k, v]) => `${k}=${String(v).slice(0, 60)}`)
150
+ .join(', ');
151
+ return `${toolName}(${argsStr}) — ${rule.raw}`;
152
+ }
153
+
154
+ module.exports = { checkPreHooks, runPostHooks, loadRules, matchGlob, matchRule, permissionSummary, flattenArgs };
@@ -8,6 +8,12 @@
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
10
  const { globalRegistry } = require('./registry');
11
+ const sandbox = require('./sandbox');
12
+
13
+ // Lazy config read — avoids circular deps
14
+ function _getSandboxLevel() {
15
+ try { return sandbox.getLevel(require('./config').getConfig()); } catch { return 'none'; }
16
+ }
11
17
 
12
18
  const TOOLS_DIR = path.join(__dirname, '..', 'tools');
13
19
 
@@ -294,6 +300,16 @@ async function executeTool(toolName, args, toolDefs) {
294
300
  return { error: `${toolName} şu anda kullanılamıyor (check_fn engelledi)` };
295
301
  }
296
302
  }
303
+
304
+ // Sandbox restrictions for bash/shell_command
305
+ if (toolName === 'bash' || toolName === 'shell_command') {
306
+ const level = _getSandboxLevel();
307
+ const cmd = (args && args.command) || '';
308
+ if (level === 'strict' && sandbox.isNetworkCommand(cmd)) {
309
+ return { error: 'strict sandbox: network komutları engellendi. Daha düşük sandbox seviyesi kullanın.' };
310
+ }
311
+ }
312
+
297
313
  try {
298
314
  const result = await tool.execute(args || {});
299
315
  return { result };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * ultra-review — Multi-agent code review
3
+ *
4
+ * Spawns parallel review agents focused on different aspects:
5
+ * - Security: secret scanning, injection risks
6
+ * - Style: code conventions, formatting
7
+ * - Logic: correctness, edge cases
8
+ * - Performance: optimization opportunities
9
+ *
10
+ * Uses natureco's existing agent system for reviews.
11
+ */
12
+
13
+ const path = require('path');
14
+
15
+ const REVIEW_FOCUS = {
16
+ security: {
17
+ name: 'Security Review',
18
+ prompt: 'Review the following code for security issues: secret exposure, injection vulnerabilities, unsafe deserialization, path traversal, command injection. Return issues with severity (high/medium/low) and line references.',
19
+ },
20
+ style: {
21
+ name: 'Style Review',
22
+ prompt: 'Review the following code for style issues: naming conventions, formatting consistency, code organization, documentation quality, adherence to project conventions.',
23
+ },
24
+ logic: {
25
+ name: 'Logic Review',
26
+ prompt: 'Review the following code for logic issues: correctness, edge cases, error handling, race conditions, type safety, off-by-one errors, boundary conditions.',
27
+ },
28
+ performance: {
29
+ name: 'Performance Review',
30
+ prompt: 'Review the following code for performance issues: unnecessary allocations, O(n²) algorithms, memory leaks, blocking operations, caching opportunities, bundle size impact.',
31
+ },
32
+ };
33
+
34
+ function reviewFile(filePath, content) {
35
+ const issues = [];
36
+ for (const [focus, info] of Object.entries(REVIEW_FOCUS)) {
37
+ issues.push({
38
+ focus,
39
+ title: info.name,
40
+ prompt: info.prompt,
41
+ file: filePath,
42
+ });
43
+ }
44
+ return { file: filePath, size: content.length, reviews: issues };
45
+ }
46
+
47
+ function reviewDiff(diffContent) {
48
+ const issues = [];
49
+ for (const [focus, info] of Object.entries(REVIEW_FOCUS)) {
50
+ issues.push({
51
+ focus,
52
+ title: info.name,
53
+ prompt: info.prompt + `\n\nDiff:\n${diffContent.slice(0, 8000)}`,
54
+ });
55
+ }
56
+ return { reviews: issues };
57
+ }
58
+
59
+ module.exports = { reviewFile, reviewDiff, REVIEW_FOCUS };