natureco-cli 5.64.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 CHANGED
@@ -2,6 +2,22 @@
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
+
5
21
  ## [5.64.0] - 2026-07-13 — Secure unified agent and operations foundation
6
22
 
7
23
  ### Added
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 · 57+ tools · 10 messaging channels.
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
- - **57+ tools** — file ops, web search, image generation, code execution, memory, and more
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 (57+ tools active) |
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.64.0",
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"
@@ -27,6 +27,7 @@
27
27
  "lint:fix": "eslint src/ bin/ test/ --fix",
28
28
  "lint:errors-only": "eslint src/ bin/ test/ --quiet",
29
29
  "smoke": "node --check bin/natureco.js && node bin/natureco.js help",
30
+ "smoke:context": "node scripts/e2e-context-smoke.js",
30
31
  "postinstall": "node scripts/postinstall.js",
31
32
  "prepublishOnly": "node --check bin/natureco.js && eslint src/ bin/ test/ --quiet && vitest run"
32
33
  },
@@ -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
+ });
@@ -34,6 +34,8 @@ const { getTaskManager } = require("../utils/tasks");
34
34
  const { buildTiers, assemble, discoverProjectRules } = require("../utils/system-prompt");
35
35
  const { buildSkillIndex } = require("../utils/skill-index");
36
36
  const { AgentCore } = require("../utils/agent-core");
37
+ const { prepareConversationHistory } = require("../utils/conversation-context");
38
+ const tokenBudget = require("../utils/token-budget");
37
39
 
38
40
  const agentCore = new AgentCore({ maxIterations: 10 });
39
41
 
@@ -522,7 +524,14 @@ async function codeV5(targetPath) {
522
524
 
523
525
  // Workflow step — run before every request
524
526
  process.stdout.write(tui.styled('\r 🔧 workflow... ', { color: tui.PALETTE.muted }));
525
- const wfResult = await executeTool('workflow', { action: 'run', task: input }, toolDefs);
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);
526
535
  const wf = wfResult?.result || {};
527
536
  if (wf.success !== false) {
528
537
  const loaded = wf.skillsLoaded && wf.skillsLoaded.length > 0 ? ` [skill: ${wf.skillsLoaded.join(', ')}]` : '';
@@ -12,6 +12,15 @@ const { getLang } = require('../utils/i18n');
12
12
 
13
13
  const L = (tr, en) => (getLang() === 'en' ? en : tr);
14
14
 
15
+ function providerHostname(providerUrl) {
16
+ if (!providerUrl) return '';
17
+ try {
18
+ return new URL(providerUrl).hostname;
19
+ } catch {
20
+ return String(providerUrl).replace(/^https?:\/\//i, '').split('/')[0];
21
+ }
22
+ }
23
+
15
24
  function help() {
16
25
  const config = getConfig() || {};
17
26
  const version = require('../../package.json').version;
@@ -203,7 +212,7 @@ function help() {
203
212
  tui.styled(' ╭' + '─'.repeat(cardW) + '╮', { color: tui.PALETTE.border }),
204
213
  ];
205
214
  if (config.providerUrl) {
206
- const provider = config.providerUrl.replace('https?:\/\/', '').split('/')[0];
215
+ const provider = providerHostname(config.providerUrl);
207
216
  cardLines.push(tui.styled(' │ ', { color: tui.PALETTE.border }) + tui.C.muted('Provider ') + tui.styled(provider.padEnd(38), { color: tui.PALETTE.text, bold: true }) + tui.styled(' │', { color: tui.PALETTE.border }));
208
217
  }
209
218
  if (config.providerModel) {
@@ -228,3 +237,4 @@ function help() {
228
237
  }
229
238
 
230
239
  module.exports = help;
240
+ module.exports.providerHostname = providerHostname;
@@ -0,0 +1,52 @@
1
+ 'use strict';
2
+
3
+ function estimateTokens(content) {
4
+ if (!content) return 0;
5
+ return Math.ceil(String(content).length / 4);
6
+ }
7
+
8
+ function prepareConversationHistory(messages, options = {}) {
9
+ if (!Array.isArray(messages)) return [];
10
+
11
+ if (typeof options === 'number') options = { maxMessages: options };
12
+ const maxMessages = Math.max(1, options.maxMessages || 20);
13
+ const maxTokens = Math.max(1, options.maxTokens || 2048);
14
+
15
+ const candidates = messages
16
+ .filter(message =>
17
+ message &&
18
+ (message.role === 'user' || message.role === 'assistant') &&
19
+ typeof message.content === 'string' &&
20
+ message.content.trim()
21
+ )
22
+ .slice(-maxMessages);
23
+
24
+ const selected = [];
25
+ let remainingTokens = maxTokens;
26
+
27
+ for (let i = candidates.length - 1; i >= 0 && remainingTokens > 0; i--) {
28
+ const message = candidates[i];
29
+ const content = message.content.trim();
30
+ const contentTokens = estimateTokens(content);
31
+ if (contentTokens <= remainingTokens) {
32
+ selected.unshift({ role: message.role, content });
33
+ remainingTokens -= contentTokens;
34
+ continue;
35
+ }
36
+
37
+ // Preserve the newest oversized turn, but never let a generated file or
38
+ // verbose tool summary consume the entire next request's context budget.
39
+ if (selected.length === 0) {
40
+ const maxChars = Math.max(4, remainingTokens * 4);
41
+ selected.unshift({
42
+ role: message.role,
43
+ content: content.slice(0, Math.max(0, maxChars - 36)) + '\n[... context truncated ...]',
44
+ });
45
+ }
46
+ break;
47
+ }
48
+
49
+ return selected;
50
+ }
51
+
52
+ module.exports = { estimateTokens, prepareConversationHistory };
@@ -22,6 +22,7 @@ const PRESETS = {
22
22
  fileContentMaxChars: 1000,
23
23
  conversationOnDisk: 6,
24
24
  conversationInContext: 8,
25
+ workflowHistoryMaxTokens: 1024,
25
26
  autoCompact: true,
26
27
  compactModel: null,
27
28
  reservedTokens: 1024
@@ -42,6 +43,7 @@ const PRESETS = {
42
43
  fileContentMaxChars: 2000,
43
44
  conversationOnDisk: 10,
44
45
  conversationInContext: 12,
46
+ workflowHistoryMaxTokens: 2048,
45
47
  autoCompact: true,
46
48
  compactModel: null,
47
49
  reservedTokens: 2048
@@ -62,6 +64,7 @@ const PRESETS = {
62
64
  fileContentMaxChars: 5000,
63
65
  conversationOnDisk: 20,
64
66
  conversationInContext: 25,
67
+ workflowHistoryMaxTokens: 8192,
65
68
  autoCompact: false,
66
69
  compactModel: null,
67
70
  reservedTokens: 4096