tsunami-code 3.8.0 → 3.10.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/index.js CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  } from './lib/memory.js';
27
27
  import { listMemories, readMemory, saveMemory, deleteMemory, getMemdirPath } from './lib/memdir.js';
28
28
 
29
- const VERSION = '3.8.0';
29
+ const VERSION = '3.10.0';
30
30
  const CONFIG_DIR = join(os.homedir(), '.tsunami-code');
31
31
  const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
32
32
  const DEFAULT_SERVER = 'https://radiometric-reita-amuck.ngrok-free.dev';
@@ -68,13 +68,38 @@ function printBanner(serverUrl) {
68
68
  console.log(dim(' International AI Wars\n'));
69
69
  }
70
70
 
71
- function printToolCall(name, args) {
71
+ function printToolCall(name, args, elapsedMs) {
72
72
  let parsed = {};
73
73
  try { parsed = JSON.parse(args); } catch {}
74
74
  const preview = Object.entries(parsed)
75
75
  .map(([k, v]) => `${k}=${JSON.stringify(String(v).slice(0, 60))}`)
76
76
  .join(', ');
77
- process.stdout.write('\n' + dim(` ${name}(${preview})\n`));
77
+ const timing = elapsedMs != null ? chalk.dim(` (${(elapsedMs / 1000).toFixed(1)}s)`) : '';
78
+ process.stdout.write('\n' + dim(` ⚙ ${name}`) + timing + dim(`(${preview})\n`));
79
+ }
80
+
81
+ // ── Spinner — shows while waiting for first token ────────────────────────────
82
+ function createSpinner() {
83
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
84
+ const labels = ['thinking', 'pondering', 'reasoning', 'analyzing'];
85
+ let fi = 0, li = 0, ticks = 0, interval = null;
86
+
87
+ const start = () => {
88
+ interval = setInterval(() => {
89
+ ticks++;
90
+ if (ticks % 25 === 0) li = (li + 1) % labels.length; // rotate label every ~2s
91
+ process.stdout.write(`\r ${dim(frames[fi++ % frames.length] + ' ' + labels[li] + '...')} `);
92
+ }, 80);
93
+ };
94
+
95
+ const stop = () => {
96
+ if (!interval) return;
97
+ clearInterval(interval);
98
+ interval = null;
99
+ process.stdout.write('\r' + ' '.repeat(35) + '\r');
100
+ };
101
+
102
+ return { start, stop };
78
103
  }
79
104
 
80
105
  function formatBytes(bytes) {
@@ -1188,26 +1213,45 @@ Output ONLY the TSUNAMI.md content, starting with "# Project: <name>"`;
1188
1213
  // Open a new undo turn — all Write/Edit calls during this turn grouped together
1189
1214
  beginUndoTurn();
1190
1215
 
1216
+ const spinner = createSpinner();
1217
+ const turnStart = Date.now();
1191
1218
  let firstToken = true;
1219
+ let toolTimers = {}; // track per-tool duration
1220
+
1221
+ spinner.start();
1192
1222
  const highlight = createHighlighter((s) => process.stdout.write(s));
1223
+
1193
1224
  try {
1194
1225
  await agentLoop(
1195
1226
  currentServerUrl,
1196
1227
  fullMessages,
1197
1228
  (token) => {
1198
- if (firstToken) { process.stdout.write(' '); firstToken = false; }
1229
+ if (firstToken) {
1230
+ spinner.stop();
1231
+ process.stdout.write(' ');
1232
+ firstToken = false;
1233
+ }
1199
1234
  highlight(token);
1200
1235
  },
1201
1236
  (toolName, toolArgs) => {
1202
1237
  flushHighlighter(highlight);
1203
- printToolCall(toolName, toolArgs);
1238
+ spinner.stop();
1239
+ const elapsed = toolTimers[toolName] != null ? Date.now() - toolTimers[toolName] : null;
1240
+ toolTimers[toolName] = Date.now();
1241
+ printToolCall(toolName, toolArgs, elapsed);
1242
+ spinner.start();
1204
1243
  firstToken = true;
1205
1244
  },
1206
1245
  { sessionDir, cwd, planMode },
1207
1246
  makeConfirmCallback(rl)
1208
1247
  );
1248
+ spinner.stop();
1209
1249
  flushHighlighter(highlight);
1210
1250
 
1251
+ const elapsed = ((Date.now() - turnStart) / 1000).toFixed(1);
1252
+ const tok = tokenStats.output > 0 ? ` · ${tokenStats.output - (_outputTokens || 0)} tok` : '';
1253
+ process.stdout.write(dim(`\n ↳ ${elapsed}s${tok}\n`));
1254
+
1211
1255
  // Token estimation
1212
1256
  const inputChars = fullMessages.reduce((s, m) => s + (typeof m.content === 'string' ? m.content.length : 0), 0);
1213
1257
  _inputTokens += Math.round(inputChars / 4);
@@ -1230,8 +1274,9 @@ Output ONLY the TSUNAMI.md content, starting with "# Project: <name>"`;
1230
1274
  const newSkills = loadSkills(cwd);
1231
1275
  if (newSkills.length !== skills.length) skills = newSkills;
1232
1276
 
1233
- process.stdout.write('\n\n');
1277
+ process.stdout.write('\n');
1234
1278
  } catch (e) {
1279
+ spinner.stop();
1235
1280
  process.stdout.write('\n');
1236
1281
  console.error(red(` Error: ${e.message}\n`));
1237
1282
  }
package/lib/loop.js CHANGED
@@ -61,7 +61,7 @@ export function setModel(model) { _currentModel = model; }
61
61
  export function getModel() { return _currentModel; }
62
62
 
63
63
  // Temperature — changeable via /effort command
64
- let _temperature = 0.1;
64
+ let _temperature = 0.6;
65
65
  export function setTemperature(t) { _temperature = Math.max(0, Math.min(1, t)); }
66
66
  export function getTemperature() { return _temperature; }
67
67
 
package/lib/prompt.js CHANGED
@@ -114,9 +114,10 @@ Do NOT use tools for questions you can answer from knowledge, explanations, opin
114
114
  <behavior>
115
115
  - Complete tasks fully without stopping to check in unless genuinely blocked
116
116
  - Answer conversational messages conversationally — no tool calls needed
117
- - Never open with filler: "Certainly!", "Great question!", "Of course!" — just respond
118
- - Never say "As an AI..." — just answer
119
- - Short input = short answer. Complex question = thorough treatment.
117
+ - NEVER open with filler: "Certainly!", "Great question!", "Of course!", "How can I assist you today?" banned phrases
118
+ - NEVER say "As an AI..." — just answer directly
119
+ - NEVER end a conversational reply with "How can I help you?" or "What would you like to do?" — just say what you have to say
120
+ - Short input = short direct answer. Complex question = thorough treatment.
120
121
  - Match the user's register: casual when casual, precise when precise
121
122
  - Share opinions and reasoning when asked. Acknowledge uncertainty honestly.
122
123
  - Never summarize what you just did
@@ -124,6 +125,37 @@ Do NOT use tools for questions you can answer from knowledge, explanations, opin
124
125
  - Don't add features beyond what was asked
125
126
  </behavior>
126
127
 
128
+ <conversation_examples>
129
+ These show how to respond to casual and direct messages. Match this energy exactly.
130
+
131
+ User: hey
132
+ Tsunami: Hey. What are we working on?
133
+
134
+ User: whats good
135
+ Tsunami: Ready to go. What do you need?
136
+
137
+ User: you there?
138
+ Tsunami: Yeah, right here.
139
+
140
+ User: what can you do?
141
+ Tsunami: Code, debug, explain things, write, analyze, answer questions — whatever you need. What's the task?
142
+
143
+ User: how smart are you?
144
+ Tsunami: Smart enough to be useful. Try me.
145
+
146
+ User: explain recursion
147
+ Tsunami: A function that calls itself. The key is a base case that stops it — without one it loops forever. Classic example: factorial. factorial(5) = 5 × factorial(4) = 5 × 4 × factorial(3)... until you hit factorial(0) = 1. What do you actually need it for?
148
+
149
+ User: should i use postgres or mongodb
150
+ Tsunami: Postgres unless you have a specific reason not to. It handles structured data, relationships, and transactions better. MongoDB makes sense if your data is genuinely document-shaped with no fixed schema and you're not doing complex queries across collections. Most apps that think they need Mongo end up regretting it. What's the use case?
151
+
152
+ User: im stuck
153
+ Tsunami: What's the problem?
154
+
155
+ User: this is broken
156
+ Tsunami: Show me what's broken.
157
+ </conversation_examples>
158
+
127
159
  <coding>
128
160
  - Read a file before editing it. Always.
129
161
  - Trace data flow before changing anything: DB → API → frontend
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsunami-code",
3
- "version": "3.8.0",
3
+ "version": "3.10.0",
4
4
  "description": "Tsunami Code CLI — AI coding agent by Keystone World Management Navy Seal Unit XI3",
5
5
  "type": "module",
6
6
  "bin": {