icoa-cli 2.19.31 → 2.19.33

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.
@@ -5,6 +5,7 @@ import { getConfig } from '../lib/config.js';
5
5
  import { logCommand } from '../lib/logger.js';
6
6
  import { printMarkdown, printError } from '../lib/ui.js';
7
7
  import { t } from '../lib/i18n.js';
8
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
8
9
  function getChallengeContext() {
9
10
  const config = getConfig();
10
11
  if (config.currentChallengeName && config.currentChallengeCategory) {
@@ -117,7 +118,45 @@ export async function handleChatMessage(input) {
117
118
  body: JSON.stringify({ type: 'ai4ctf', solved: true, tokensUsed: chatTokensUsed, timestamp: new Date().toISOString() }),
118
119
  signal: AbortSignal.timeout(5000),
119
120
  }).catch(() => { });
120
- console.log(chalk.white(` ${t('ai4ctfNext')}`));
121
+ // Wrap-up summary — only shown after a successful solve.
122
+ await sleep(1500);
123
+ console.log();
124
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
125
+ console.log(chalk.bold.white(' ✨ What you just learned'));
126
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
127
+ console.log();
128
+ console.log(chalk.white(' 1. Need a command? ') + chalk.gray('Just ask your AI teammate in natural'));
129
+ console.log(chalk.gray(' language — "how do I decode Base64 on the command line?"'));
130
+ console.log(chalk.gray(' You do not need to memorize every tool. The AI era is'));
131
+ console.log(chalk.gray(' about ') + chalk.white('thinking') + chalk.gray(', not mechanical memorization.'));
132
+ console.log();
133
+ console.log(chalk.white(' 2. Need to run something? ') + chalk.gray('Prefix shell commands with "!":'));
134
+ console.log();
135
+ console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
136
+ console.log();
137
+ await sleep(2000);
138
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
139
+ console.log(chalk.bold.white(' 🎯 Real competition hint quotas'));
140
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
141
+ console.log();
142
+ console.log(chalk.yellow(' hint a ') + chalk.white('50 uses per competition ') + chalk.gray('(use freely)'));
143
+ console.log(chalk.yellow(' hint b ') + chalk.white('10 uses ') + chalk.gray('(when stuck)'));
144
+ console.log(chalk.yellow(' hint c ') + chalk.white(' 2 uses ') + chalk.gray('(last resort)'));
145
+ console.log();
146
+ console.log(chalk.gray(' Prefer hint a → b → c. And when you just need to look'));
147
+ console.log(chalk.gray(' something up, chat with the AI first — it costs nothing'));
148
+ console.log(chalk.gray(' against your hint quota.'));
149
+ console.log();
150
+ await sleep(2000);
151
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
152
+ console.log(chalk.bold.white(' 🔜 Next up: ') + chalk.red.bold('ctf4ai') + chalk.white(' — trick the AI into saying "koala"'));
153
+ console.log(chalk.cyan(' ─────────────────────────────────────────────'));
154
+ console.log();
155
+ console.log(chalk.white(' This next demo ') + chalk.bold.white('does not need programming') + chalk.white(' — just your'));
156
+ console.log(chalk.white(' wit and creativity. Can you make a "safe" AI break its'));
157
+ console.log(chalk.white(' own rules?'));
158
+ console.log();
159
+ console.log(chalk.gray(' Type: ') + chalk.bold.red('ctf4ai'));
121
160
  console.log();
122
161
  return 'exit';
123
162
  }
@@ -175,6 +214,15 @@ export async function handleChatMessage(input) {
175
214
  if (chatTokensUsed >= DEMO_TOKEN_CAP) {
176
215
  chatActive = false;
177
216
  chatSession = null;
217
+ // Report the token-cap session so the server can count "hit the wall"
218
+ // outcomes. Without this, a user who burned 5000 tokens without solving
219
+ // was invisible to the admin dashboard.
220
+ fetch('https://practice.icoa2026.au/api/icoa/demo-stats', {
221
+ method: 'POST',
222
+ headers: { 'Content-Type': 'application/json' },
223
+ body: JSON.stringify({ type: 'ai4ctf', solved: false, tokensUsed: chatTokensUsed, timestamp: new Date().toISOString() }),
224
+ signal: AbortSignal.timeout(5000),
225
+ }).catch(() => { });
178
226
  console.log();
179
227
  console.log(chalk.yellow(` ${t('tokenLimit')}`));
180
228
  drawTokenBar();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.31",
3
+ "version": "2.19.33",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {