natureco-cli 5.63.0 → 5.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +20 -3
- package/bin/natureco.js +10 -3
- package/package.json +3 -1
- package/scripts/benchmark-startup.js +26 -0
- package/scripts/e2e-context-smoke.js +33 -0
- package/src/commands/backup.js +3 -3
- package/src/commands/code.js +49 -14
- package/src/commands/code_v5.js +25 -2
- package/src/commands/gateway-server.js +128 -24
- package/src/commands/git.js +2 -2
- package/src/commands/help.js +11 -1
- package/src/commands/pairing.js +2 -22
- package/src/commands/repl.js +8 -6
- package/src/tools/agentic-runner.js +41 -33
- package/src/tools/memory_write.js +16 -12
- package/src/tools/structural_patch.js +25 -0
- package/src/tools/workflow.js +10 -2
- package/src/utils/agent-core.js +51 -0
- package/src/utils/agent-workspace.js +24 -0
- package/src/utils/api.js +12 -8
- package/src/utils/channel-sdk.js +212 -0
- package/src/utils/code-intelligence.js +69 -0
- package/src/utils/coding-session.js +54 -0
- package/src/utils/conversation-context.js +52 -0
- package/src/utils/delivery-store.js +34 -0
- package/src/utils/i18n.js +7 -1
- package/src/utils/json-schema.js +43 -0
- package/src/utils/lsp-client.js +129 -0
- package/src/utils/memory-record.js +49 -0
- package/src/utils/pairing-store.js +55 -0
- package/src/utils/pattern-detector.js +13 -3
- package/src/utils/plugin-registry.js +3 -3
- package/src/utils/process-errors.js +14 -7
- package/src/utils/runtime-health.js +28 -0
- package/src/utils/secret-store.js +90 -0
- package/src/utils/secure-sync.js +63 -0
- package/src/utils/skill-lifecycle.js +59 -0
- package/src/utils/structural-patch.js +68 -0
- package/src/utils/sub-agent.js +13 -2
- package/src/utils/test-failure-analyzer.js +64 -0
- package/src/utils/token-budget.js +3 -0
- package/src/utils/tool-execution-gateway.js +56 -0
- package/src/utils/tool-manifest.js +31 -0
- package/src/utils/tool-path-policy.js +49 -0
- package/src/utils/tool-result.js +17 -0
- package/src/utils/tool-runner.js +81 -53
- package/src/utils/tools.js +30 -42
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to NatureCo CLI will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [5.64.1] - 2026-07-13 — Reliable coding context and token-budgeted follow-ups
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- `natureco code` now passes prior user/assistant turns into each workflow call, so follow-up requests correctly refer to files and work created earlier in the same session.
|
|
9
|
+
- Workflow history excludes system/tool internals, empty messages and stale turns; oversized recent responses are safely truncated instead of being resent in full.
|
|
10
|
+
- The help screen now parses provider URLs correctly (`api.minimax.io` instead of `https:`).
|
|
11
|
+
|
|
12
|
+
### Token economy
|
|
13
|
+
- Added workflow-history budgets to all profiles: Efficient 1,024 tokens, Balanced 2,048 tokens and Quality 8,192 tokens.
|
|
14
|
+
- Long generated HTML/code no longer dominates every later prompt. A synthetic 32,000-character response is bounded from roughly 8,000 repeated tokens to 2,048 in Balanced mode (approximately 74% less repeated context).
|
|
15
|
+
- Preserved recent-turn continuity while keeping token use bounded by both message count and estimated tokens.
|
|
16
|
+
|
|
17
|
+
### Documentation and tests
|
|
18
|
+
- Updated README release highlights, tool count, coding-session behavior and token-economy documentation.
|
|
19
|
+
- Added regression coverage for same-session workflow context, role filtering, recency, oversized response truncation and provider hostname rendering.
|
|
20
|
+
|
|
21
|
+
## [5.64.0] - 2026-07-13 — Secure unified agent and operations foundation
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- Unified `AgentCore`, `ToolExecutionGateway`, single tool manifest, mandatory JSON Schema validation and standardized tool results.
|
|
25
|
+
- Conflict-safe structural patching, atomic rollback, coding `/undo`, `/retry`, `/compact`, local code intelligence and LSP JSON-RPC client.
|
|
26
|
+
- Provenance/confidence/TTL memory records, conflict resolution, approved skill promotion, versioning and rollback.
|
|
27
|
+
- Shared channel SDK with pairing-by-default, persistent idempotent delivery queue, retries, dead letters, reconnect supervision, health and metrics.
|
|
28
|
+
- macOS Keychain, Windows DPAPI, Linux Secret Service and AES-256-GCM encrypted secret fallback.
|
|
29
|
+
- Encrypted multi-device sync primitives with authenticated envelopes and vector-clock conflict detection.
|
|
30
|
+
- Isolated sub-agent worktrees, test-failure analysis/repair loop, startup benchmark and TR/EN catalog snapshots.
|
|
31
|
+
|
|
32
|
+
### Security
|
|
33
|
+
- Fixed bulk-write guardrail bypasses, protected sensitive paths across execution origins and enabled guardrail hard-stop.
|
|
34
|
+
- Removed high-risk shell string interpolation from iMessage delivery, backups, plugin installation/cloning and AI-generated Git commits.
|
|
35
|
+
- Added channel pairing gates, non-interactive fail-closed permission handling and process-listener cleanup.
|
|
36
|
+
|
|
37
|
+
### Tests
|
|
38
|
+
- 73 test files, 711 passing tests (3 skipped), zero high-severity audit findings, CLI smoke and package checks.
|
|
39
|
+
- Windows `--version` median reduced from ~366 ms to ~75 ms, meeting the <100 ms target.
|
|
40
|
+
- Real Windows/macOS/Linux GitHub Actions matrix with lint, tests, smoke, audit and package verification.
|
|
41
|
+
|
|
5
42
|
## [5.63.0] - 2026-07-12 — Complete English REPL localization
|
|
6
43
|
|
|
7
44
|
### Changed
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
A terminal-native AI agent CLI — chat, write code, automate workflows, and connect **Telegram / Discord / Slack / WhatsApp / iMessage** and more.
|
|
14
14
|
|
|
15
|
-
**A Claude Code & OpenClaw alternative** · Multi-agent orchestration · Cross-session memory · Dangerous-command approval · 12 providers, 200+ models ·
|
|
15
|
+
**A Claude Code & OpenClaw alternative** · Multi-agent orchestration · Cross-session memory · Token-budgeted context · Dangerous-command approval · 12 providers, 200+ models · 106 tools · 10 messaging channels.
|
|
16
16
|
|
|
17
17
|
```
|
|
18
18
|
███╗ ██╗ █████╗ ████████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗
|
|
@@ -51,6 +51,8 @@ natureco code
|
|
|
51
51
|
|
|
52
52
|
| Version | Highlights |
|
|
53
53
|
|---------|-----------|
|
|
54
|
+
| **v5.64.1** | **Reliable follow-ups + lower token cost:** `natureco code` now preserves same-session context across workflow calls and caps repeated history by token budget (1,024 / 2,048 / 8,192). Provider labels are rendered correctly. |
|
|
55
|
+
| **v5.64.0** | **Unified secure agent foundation:** one execution gateway, hard-stop guardrails, schema-validated tools, rollback/checkpoints, sourced memory, resilient channel delivery, OS keychains and encrypted sync. |
|
|
54
56
|
| **v5.43.0** | **Security:** 9 vulnerabilities fixed in a 3-round audit (RCE chain, admin-rpc auth, cron persistence, channel access control). See [`SECURITY_AUDIT_SUMMARY.md`](SECURITY_AUDIT_SUMMARY.md). |
|
|
55
57
|
| **v5.42.0** | **Token optimization** — prompts trimmed by ~76% (skill index made compact; big cost savings on multi-step tasks). |
|
|
56
58
|
| **v5.41.0** | **Multi-agent orchestration** — the agent can spawn focused sub-agents (`sub_agent`) and produce step-by-step plans (`plan`) before acting. |
|
|
@@ -102,11 +104,12 @@ Two-tier policy (`deny` / `allowlist` / `full`) applies to **every** shell path
|
|
|
102
104
|
## ✨ Features
|
|
103
105
|
|
|
104
106
|
### 🤖 AI & Chat
|
|
105
|
-
- **
|
|
107
|
+
- **106 tools** — file ops, web search, image generation, code execution, memory, automation, channels, and more
|
|
106
108
|
- **Interactive REPL** — read_file, edit_file, bash, multi-turn conversation
|
|
107
109
|
- **Slash commands** — `/memory`, `/help`, `/skills`, `/model`, `/clear`
|
|
108
110
|
- **Streaming output** with live tool-call visibility and a thinking indicator
|
|
109
111
|
- **Persistent memory** — fact-based, cross-session
|
|
112
|
+
- **Token-budgeted context** — recent relevant turns are retained without repeatedly sending oversized code and tool output
|
|
110
113
|
|
|
111
114
|
### 💻 Coding Agent (Claude Code alternative)
|
|
112
115
|
- **Read / Write / Edit** multi-file operations
|
|
@@ -114,6 +117,20 @@ Two-tier policy (`deny` / `allowlist` / `full`) applies to **every** shell path
|
|
|
114
117
|
- **Multi-agent orchestration** — spawn focused sub-agents and plan before acting
|
|
115
118
|
- **Skills** — progressive-disclosure expertise loaded on demand via `skill_view`
|
|
116
119
|
- **Verify loop** — the agent runs and tests the code it writes
|
|
120
|
+
- **Reliable follow-ups** — references such as “the game you just created” retain the current coding-session context
|
|
121
|
+
- **Context profiles** — Efficient (1,024), Balanced (2,048), and Quality (8,192) workflow-history token budgets
|
|
122
|
+
|
|
123
|
+
### ⚡ Token Economy
|
|
124
|
+
|
|
125
|
+
NatureCo uses progressive disclosure and bounded context instead of sending every skill, tool result, and old response on every request:
|
|
126
|
+
|
|
127
|
+
- Skills are discovered with `skill_find` and loaded only when needed with `skill_view`.
|
|
128
|
+
- System, internal tool, and empty messages are excluded from workflow history.
|
|
129
|
+
- Recent user/assistant turns are kept within the selected token profile.
|
|
130
|
+
- Oversized generated code is truncated in later prompts while the file path and conversational intent remain available.
|
|
131
|
+
- `natureco ask` stays tool-free by default; use `--tools` only when an action is required.
|
|
132
|
+
|
|
133
|
+
For a 32,000-character previous response, the Balanced profile bounds repeated history to about 2,048 tokens instead of roughly 8,000—a reduction of approximately 74% for that repeated context.
|
|
117
134
|
|
|
118
135
|
### 📡 10 Messaging Channels
|
|
119
136
|
|
|
@@ -161,7 +178,7 @@ Two-tier policy (`deny` / `allowlist` / `full`) applies to **every** shell path
|
|
|
161
178
|
|
|
162
179
|
| Command | Description |
|
|
163
180
|
|---------|-------------|
|
|
164
|
-
| `natureco chat` | Interactive REPL chat (
|
|
181
|
+
| `natureco chat` | Interactive REPL chat (106 tools available) |
|
|
165
182
|
| `natureco chat --resume` | Resume the previous session |
|
|
166
183
|
| `natureco code` | Coding agent (write apps/scripts) |
|
|
167
184
|
| `natureco code <file>` | Coding agent on a specific file |
|
package/bin/natureco.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Fast path: version checks are used by shells, installers and health probes.
|
|
4
|
+
// Avoid loading Commander and ~100 command modules for a constant-time answer.
|
|
5
|
+
if (process.argv.length === 3 && (process.argv[2] === '--version' || process.argv[2] === '-V')) {
|
|
6
|
+
process.stdout.write(require('../package.json').version + '\n');
|
|
7
|
+
process.exit(0);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { Command } = require('commander');
|
|
4
11
|
const chalk = require('chalk');
|
|
5
12
|
const packageJson = require('../package.json');
|
|
6
13
|
// Küresel çökme/EPIPE yakalayıcıları — ham Node stack yerine düzgün mesaj + audit log
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.64.1",
|
|
4
4
|
"description": "Terminal-native AI agent CLI with bilingual TR/EN UI, multi-agent orchestration, persistent memory, secure tools and messaging integrations.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
"test:unit": "vitest run",
|
|
23
23
|
"test:watch": "vitest",
|
|
24
24
|
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"perf:startup": "node scripts/benchmark-startup.js",
|
|
25
26
|
"lint": "eslint src/ bin/ test/",
|
|
26
27
|
"lint:fix": "eslint src/ bin/ test/ --fix",
|
|
27
28
|
"lint:errors-only": "eslint src/ bin/ test/ --quiet",
|
|
28
29
|
"smoke": "node --check bin/natureco.js && node bin/natureco.js help",
|
|
30
|
+
"smoke:context": "node scripts/e2e-context-smoke.js",
|
|
29
31
|
"postinstall": "node scripts/postinstall.js",
|
|
30
32
|
"prepublishOnly": "node --check bin/natureco.js && eslint src/ bin/ test/ --quiet && vitest run"
|
|
31
33
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const bin = path.join(__dirname, '..', 'bin', 'natureco.js');
|
|
7
|
+
function measure(args, runs = 7) {
|
|
8
|
+
const samples = [];
|
|
9
|
+
for (let i = 0; i < runs; i++) {
|
|
10
|
+
const start = process.hrtime.bigint();
|
|
11
|
+
const result = spawnSync(process.execPath, [bin, ...args], { encoding: 'utf8', env: { ...process.env, NATURECO_NO_UPDATE_CHECK: '1', FORCE_COLOR: '0' } });
|
|
12
|
+
const durationMs = Number(process.hrtime.bigint() - start) / 1e6;
|
|
13
|
+
if (result.status !== 0) throw new Error(`${args.join(' ')} failed: ${result.stderr}`);
|
|
14
|
+
samples.push(durationMs);
|
|
15
|
+
}
|
|
16
|
+
samples.sort((a, b) => a - b);
|
|
17
|
+
return { min: samples[0], median: samples[Math.floor(samples.length / 2)], p95: samples[Math.min(samples.length - 1, Math.ceil(samples.length * 0.95) - 1)], samples };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const version = measure(['--version']);
|
|
21
|
+
const report = { timestamp: new Date().toISOString(), node: process.version, platform: process.platform, version };
|
|
22
|
+
console.log(JSON.stringify(report, null, 2));
|
|
23
|
+
if (version.median >= 100) {
|
|
24
|
+
console.error(`--version median ${version.median.toFixed(1)}ms exceeds 100ms target`);
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const workflow = require('../src/tools/workflow');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const marker = `natureco-context-${Date.now()}.html`;
|
|
7
|
+
const firstTask = `Bu test oturumundaki dosya adi ${marker}. Arac calistirma; sadece dosya adini iceren kisa bir onay ver.`;
|
|
8
|
+
const first = await workflow.execute({ action: 'run', task: firstTask });
|
|
9
|
+
if (!first || first.success === false || !first.reply) {
|
|
10
|
+
throw new Error(`First turn failed: ${first?.error || 'empty reply'}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const history = [
|
|
14
|
+
{ role: 'user', content: firstTask },
|
|
15
|
+
{ role: 'assistant', content: String(first.reply) },
|
|
16
|
+
];
|
|
17
|
+
const second = await workflow.execute({
|
|
18
|
+
action: 'run',
|
|
19
|
+
task: 'Az once konustugumuz dosyanin tam adi neydi? Yalnizca dosya adini soyle.',
|
|
20
|
+
conversationHistory: history,
|
|
21
|
+
});
|
|
22
|
+
const reply = String(second?.reply || '');
|
|
23
|
+
if (!second || second.success === false || !reply.includes(marker)) {
|
|
24
|
+
throw new Error(`Context recall failed. Expected ${marker}; received: ${reply.slice(0, 240)}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(JSON.stringify({ ok: true, marker, reply: reply.trim() }));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
main().catch(error => {
|
|
31
|
+
console.error(error.message);
|
|
32
|
+
process.exitCode = 1;
|
|
33
|
+
});
|
package/src/commands/backup.js
CHANGED
|
@@ -4,7 +4,7 @@ const { getLang: _gl } = require('../utils/i18n');
|
|
|
4
4
|
const L = (tr, en) => (_gl() === 'en' ? en : tr);
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
|
-
const {
|
|
7
|
+
const { execFileSync } = require('child_process');
|
|
8
8
|
|
|
9
9
|
const NATURECO_DIR = path.join(os.homedir(), '.natureco');
|
|
10
10
|
|
|
@@ -32,7 +32,7 @@ function createBackup() {
|
|
|
32
32
|
|
|
33
33
|
if (fs.existsSync(NATURECO_DIR)) {
|
|
34
34
|
try {
|
|
35
|
-
|
|
35
|
+
execFileSync('tar', ['-czf', backupFile, '-C', path.dirname(NATURECO_DIR), path.basename(NATURECO_DIR)], {
|
|
36
36
|
stdio: 'pipe',
|
|
37
37
|
encoding: 'utf8',
|
|
38
38
|
timeout: 30000
|
|
@@ -97,7 +97,7 @@ function restoreBackup(file) {
|
|
|
97
97
|
|
|
98
98
|
console.log(chalk.yellow(`\n ⚠️ Restoring ${file}...\n`));
|
|
99
99
|
try {
|
|
100
|
-
|
|
100
|
+
execFileSync('tar', ['-xzf', backupFile, '-C', os.homedir()], { stdio: 'pipe', timeout: 15000 });
|
|
101
101
|
console.log(chalk.green(' ✅ Restore complete\n'));
|
|
102
102
|
} catch {
|
|
103
103
|
console.log(chalk.red(' ❌ Restore failed\n'));
|
package/src/commands/code.js
CHANGED
|
@@ -2,7 +2,7 @@ const path = require('path');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const readline = require('readline');
|
|
5
|
-
const { execSync } = require('child_process');
|
|
5
|
+
const { execSync, execFileSync } = require('child_process');
|
|
6
6
|
const inquirer = require('../utils/inquirer-wrapper');
|
|
7
7
|
const TB = require('../utils/token-budget');
|
|
8
8
|
const chalk = require('chalk');
|
|
@@ -14,7 +14,11 @@ const { getMemoryPrompt, loadMemory } = require('../utils/memory');
|
|
|
14
14
|
const { getAgentsPrompt } = require('../utils/agents');
|
|
15
15
|
const { createSession, addMessageToSession } = require('../utils/sessions');
|
|
16
16
|
const { addToHistory } = require('../utils/history');
|
|
17
|
-
const { getToolDefinitions, executeTool } = require('../utils/tool-runner');
|
|
17
|
+
const { getToolDefinitions, executeTool } = require('../utils/tool-runner');
|
|
18
|
+
const { AgentCore } = require('../utils/agent-core');
|
|
19
|
+
const { CodingSession } = require('../utils/coding-session');
|
|
20
|
+
|
|
21
|
+
const agentCore = new AgentCore({ maxIterations: 10 });
|
|
18
22
|
|
|
19
23
|
let rl = null;
|
|
20
24
|
|
|
@@ -224,12 +228,17 @@ async function streamMessage(providerConfig, messages, tools) {
|
|
|
224
228
|
// ── Tool execution ────────────────────────────────────────────────────────────
|
|
225
229
|
const DANGEROUS = [/\brm\b/, /\brmdir\b/, /\bdelete\b/i, /\bdrop\b/i, /\btruncate\b/i];
|
|
226
230
|
|
|
227
|
-
async function runToolCall(toolCall, stats, dryRun = false) {
|
|
231
|
+
async function runToolCall(toolCall, stats, dryRun = false, codingSession = null) {
|
|
232
|
+
const guard = agentCore.assess({ name: toolCall.name, input: toolCall.input });
|
|
233
|
+
if (guard.blocked) return { success: false, error: guard.reason || `blocked_by_guardrails: ${toolCall.name}` };
|
|
228
234
|
const inputPreview = JSON.stringify(toolCall.input).slice(0, 60);
|
|
229
235
|
|
|
230
|
-
const needsConfirm =
|
|
236
|
+
const needsConfirm =
|
|
231
237
|
toolCall.name === 'write_file' ||
|
|
232
|
-
(toolCall.name === 'bash' && DANGEROUS.some(re => re.test(toolCall.input.command || '')));
|
|
238
|
+
(toolCall.name === 'bash' && DANGEROUS.some(re => re.test(toolCall.input.command || '')));
|
|
239
|
+
|
|
240
|
+
const risk = codingSession?.riskSummary(toolCall);
|
|
241
|
+
if (risk && risk.level !== 'low') console.log(chalk.gray(` Risk: ${risk.level} (${risk.risks.join(', ')})`));
|
|
233
242
|
|
|
234
243
|
// Dry-run: write_file'ı engelle, diff göster
|
|
235
244
|
if (dryRun && toolCall.name === 'write_file') {
|
|
@@ -261,8 +270,12 @@ async function runToolCall(toolCall, stats, dryRun = false) {
|
|
|
261
270
|
}
|
|
262
271
|
}
|
|
263
272
|
|
|
264
|
-
const spinner = startSpinner(`${toolCall.name} ${inputPreview}`);
|
|
265
|
-
|
|
273
|
+
const spinner = startSpinner(`${toolCall.name} ${inputPreview}`);
|
|
274
|
+
if (!dryRun && codingSession && (toolCall.name === 'write_file' || toolCall.name === 'edit_file')) {
|
|
275
|
+
codingSession.capture(toolCall.input.path);
|
|
276
|
+
}
|
|
277
|
+
const result = await executeTool(toolCall.name, toolCall.input);
|
|
278
|
+
agentCore.record({ name: toolCall.name, input: toolCall.input }, result);
|
|
266
279
|
stopSpinner(spinner, toolCall.name, result.success !== false);
|
|
267
280
|
|
|
268
281
|
if (result.success !== false) {
|
|
@@ -310,7 +323,8 @@ async function runTests(projectIndex, conversationMessages, tools, providerConfi
|
|
|
310
323
|
}
|
|
311
324
|
|
|
312
325
|
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
313
|
-
async function code(targetFile, options = {}) {
|
|
326
|
+
async function code(targetFile, options = {}) {
|
|
327
|
+
const codingSession = new CodingSession();
|
|
314
328
|
const workDir = options.dir || process.cwd();
|
|
315
329
|
const apiKey = getApiKey();
|
|
316
330
|
const config = getConfig();
|
|
@@ -507,15 +521,35 @@ ${indexPrompt}`);
|
|
|
507
521
|
['/run <cmd>',L('Komutu çalıştır, hata varsa düzelt', 'Run command, fix errors if any')],
|
|
508
522
|
['/test', L('Testleri çalıştır, hata varsa düzelt', 'Run tests, fix errors if any')],
|
|
509
523
|
['/git', L('Git durumu ve son commitler', 'Git status and recent commits')],
|
|
510
|
-
['/commit', L('Staged değişiklikleri AI ile commit et', 'Commit staged changes with AI')],
|
|
524
|
+
['/commit', L('Staged değişiklikleri AI ile commit et', 'Commit staged changes with AI')],
|
|
525
|
+
['/undo', L('Son dosya değişikliğini geri al', 'Undo the last file change')],
|
|
526
|
+
['/retry', L('Son isteği yeniden çalıştır', 'Retry the last request')],
|
|
527
|
+
['/compact', L('Konuşma bağlamını sıkıştır', 'Compact conversation context')],
|
|
511
528
|
['/help', L('Bu yardım', 'This help')],
|
|
512
529
|
].forEach(([c, d]) => console.log(' ' + chalk.cyan(c.padEnd(12)) + chalk.gray(d)));
|
|
513
530
|
console.log(chalk.gray(' Ctrl+C'.padEnd(14) + L('Çıkış', 'Exit')));
|
|
514
531
|
console.log();
|
|
515
532
|
return;
|
|
516
|
-
case 'clear':
|
|
533
|
+
case 'clear':
|
|
517
534
|
console.clear();
|
|
518
|
-
return;
|
|
535
|
+
return;
|
|
536
|
+
case 'undo': {
|
|
537
|
+
const undone = codingSession.undo();
|
|
538
|
+
console.log(undone.ok ? chalk.green(` ✓ ${undone.path}`) : chalk.yellow(` ${undone.error}`));
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
case 'compact': {
|
|
542
|
+
const compacted = codingSession.compact(conversationMessages);
|
|
543
|
+
conversationMessages.splice(0, conversationMessages.length, ...compacted.messages);
|
|
544
|
+
console.log(chalk.green(` ✓ Context compacted: ${compacted.before} → ${compacted.after}`));
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
case 'retry': {
|
|
548
|
+
const previous = codingSession.retryMessage();
|
|
549
|
+
if (!previous) console.log(chalk.yellow(L(' Tekrarlanacak istek yok.', ' No request to retry.')));
|
|
550
|
+
else await handleMessage(previous);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
519
553
|
case 'summary':
|
|
520
554
|
case 'done': {
|
|
521
555
|
const sum = await generateSummary(conversationMessages, providerConfig);
|
|
@@ -591,7 +625,7 @@ ${indexPrompt}`);
|
|
|
591
625
|
console.log(chalk.cyan(`\n ${L('Önerilen', 'Suggested')}: ${chalk.white(commitMsg)}\n`));
|
|
592
626
|
const ok = await confirmAction(L('Commit edilsin mi?', 'Commit?'));
|
|
593
627
|
if (ok) {
|
|
594
|
-
|
|
628
|
+
execFileSync('git', ['commit', '-m', commitMsg], { cwd: workDir, stdio: 'pipe' });
|
|
595
629
|
console.log(chalk.green(L(' ✓ Commit yapıldı!\n', ' ✓ Committed!\n')));
|
|
596
630
|
} else {
|
|
597
631
|
console.log(chalk.gray(L(' İptal edildi.\n', ' Cancelled.\n')));
|
|
@@ -607,7 +641,8 @@ ${indexPrompt}`);
|
|
|
607
641
|
}
|
|
608
642
|
}
|
|
609
643
|
|
|
610
|
-
stats.messageCount++;
|
|
644
|
+
stats.messageCount++;
|
|
645
|
+
codingSession.rememberUserMessage(userMessage);
|
|
611
646
|
console.log(chalk.white('You ') + userMessage);
|
|
612
647
|
conversationMessages.push({ role: 'user', content: userMessage });
|
|
613
648
|
|
|
@@ -655,7 +690,7 @@ ${indexPrompt}`);
|
|
|
655
690
|
|
|
656
691
|
for (let ti = 0; ti < streamResult.toolCalls.length; ti++) {
|
|
657
692
|
const toolCall = streamResult.toolCalls[ti];
|
|
658
|
-
const result = await runToolCall(toolCall, stats, options.dryRun);
|
|
693
|
+
const result = await runToolCall(toolCall, stats, options.dryRun, codingSession);
|
|
659
694
|
const resultStr = result.success !== false
|
|
660
695
|
? (result.output || JSON.stringify(result))
|
|
661
696
|
: `${L('Hata', 'Error')}: ${result.error}`;
|
package/src/commands/code_v5.js
CHANGED
|
@@ -33,6 +33,11 @@ const { getFallbackChain } = require("../utils/fallback-chain");
|
|
|
33
33
|
const { getTaskManager } = require("../utils/tasks");
|
|
34
34
|
const { buildTiers, assemble, discoverProjectRules } = require("../utils/system-prompt");
|
|
35
35
|
const { buildSkillIndex } = require("../utils/skill-index");
|
|
36
|
+
const { AgentCore } = require("../utils/agent-core");
|
|
37
|
+
const { prepareConversationHistory } = require("../utils/conversation-context");
|
|
38
|
+
const tokenBudget = require("../utils/token-budget");
|
|
39
|
+
|
|
40
|
+
const agentCore = new AgentCore({ maxIterations: 10 });
|
|
36
41
|
|
|
37
42
|
const IS_MAC = os.platform() === "darwin";
|
|
38
43
|
const MAX_ITERATIONS = 10;
|
|
@@ -519,7 +524,14 @@ async function codeV5(targetPath) {
|
|
|
519
524
|
|
|
520
525
|
// Workflow step — run before every request
|
|
521
526
|
process.stdout.write(tui.styled('\r 🔧 workflow... ', { color: tui.PALETTE.muted }));
|
|
522
|
-
const wfResult = await executeTool('workflow', {
|
|
527
|
+
const wfResult = await executeTool('workflow', {
|
|
528
|
+
action: 'run',
|
|
529
|
+
task: input,
|
|
530
|
+
conversationHistory: prepareConversationHistory(messages, {
|
|
531
|
+
maxMessages: tokenBudget.load().conversationInContext,
|
|
532
|
+
maxTokens: tokenBudget.load().workflowHistoryMaxTokens,
|
|
533
|
+
}),
|
|
534
|
+
}, toolDefs);
|
|
523
535
|
const wf = wfResult?.result || {};
|
|
524
536
|
if (wf.success !== false) {
|
|
525
537
|
const loaded = wf.skillsLoaded && wf.skillsLoaded.length > 0 ? ` [skill: ${wf.skillsLoaded.join(', ')}]` : '';
|
|
@@ -624,9 +636,16 @@ async function codeV5(targetPath) {
|
|
|
624
636
|
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']);
|
|
625
637
|
|
|
626
638
|
async function processToolCalls(reply, config, toolDefs, messages, onToolResult) {
|
|
639
|
+
agentCore.startIteration();
|
|
640
|
+
const coreBlocked = new Map();
|
|
627
641
|
for (const tc of reply.tool_calls) {
|
|
628
642
|
let args = {};
|
|
629
643
|
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
644
|
+
const guard = agentCore.assess({ name: tc.function.name, input: args });
|
|
645
|
+
if (guard.blocked) {
|
|
646
|
+
coreBlocked.set(tc.id, guard.reason || "blocked_by_guardrails");
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
630
649
|
const risk = assessRisk(tc.function.name, args);
|
|
631
650
|
|
|
632
651
|
// Built-in risk assessment
|
|
@@ -687,7 +706,11 @@ async function processToolCalls(reply, config, toolDefs, messages, onToolResult)
|
|
|
687
706
|
|
|
688
707
|
messages.push({ role: "assistant", content: reply.content || null, tool_calls: reply.tool_calls });
|
|
689
708
|
|
|
690
|
-
const
|
|
709
|
+
for (const [id, reason] of coreBlocked) {
|
|
710
|
+
messages.push({ role: "tool", tool_call_id: id, content: "ERROR: " + reason });
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const parsed = reply.tool_calls.filter(tc => !coreBlocked.has(tc.id)).map(tc => {
|
|
691
714
|
let args = {};
|
|
692
715
|
try { args = JSON.parse(tc.function.arguments || "{}"); } catch {}
|
|
693
716
|
return { name: tc.function.name, args, id: tc.id };
|