icoa-cli 2.19.30 → 2.19.32

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) {
@@ -31,24 +32,33 @@ function drawTokenBar() {
31
32
  console.log(chalk.gray(' Tokens: ') + color('█'.repeat(filled)) + chalk.gray('░'.repeat(empty)) + chalk.gray(` ${used}/${cap} (${pct}%)`));
32
33
  }
33
34
  const DEMO_FLAG = 'icoa{w3lc0me_2_ai4ctf}';
34
- // Scripted hints for the built-in Base64 demo challenge. These mirror the
35
- // three real-competition hint tiers (nudge technique near-answer) so
36
- // the user can feel what `hint a/b/c` will be like in the actual event.
35
+ // Scripted hints for the built-in Base64 demo challenge. The hint philosophy:
36
+ // - a: nudge you toward the fingerprint (padding, charset).
37
+ // - b: tell you the encoding name, nothing more. No shell command.
38
+ // - c: for simple challenges, c deliberately adds no new info — hint b was
39
+ // already enough. Instead c explains the hint principle and reminds the
40
+ // user how to run a shell command inside ai4ctf (the `!` prefix).
41
+ // This mirrors real competition behavior where trivial challenges cap at hint b.
37
42
  const DEMO_HINTS = {
38
43
  a: [
39
- 'The string ends with `==` and contains only letters, digits, `+`, `/`, and `=`.',
40
- 'That pattern is a fingerprint — you have seen it before. Think about where `=` is used as *padding*.',
44
+ 'The string ends with "==" and uses only letters, digits, "+", "/", and "=".',
45
+ 'That pattern is a fingerprint — you have seen it before.',
46
+ 'Where is "=" typically used as padding?',
41
47
  ],
42
48
  b: [
43
- 'That is **Base64**. The `==` is padding; the character set (A–Z, a–z, 0–9, +, /) confirms it.',
44
- 'You can decode it right in this shell — try:',
45
- ' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d',
46
- 'Or just ask the AI: "decode this for me".',
49
+ 'This is Base64 encoded. Decode the string to find the flag.',
47
50
  ],
48
51
  c: [
49
- 'The decoded value is `icoa{w3lc0me_2_ai4ctf}`.',
50
- 'Submit it with:',
51
- ' submit icoa{w3lc0me_2_ai4ctf}',
52
+ 'Hints never give you the answer directly — they only point you in the right direction.',
53
+ 'For simple challenges like this one, hint c adds nothing extra:',
54
+ 'hint b already tells you everything you need.',
55
+ '',
56
+ 'If you do not remember how to decode Base64, ask your AI teammate —',
57
+ 'just type a question like: how do I decode Base64 on the command line?',
58
+ '',
59
+ 'To run a shell command inside ai4ctf, prefix it with "!". For example:',
60
+ '',
61
+ ' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d',
52
62
  ],
53
63
  };
54
64
  function showDemoHint(tier) {
@@ -59,17 +69,21 @@ function showDemoHint(tier) {
59
69
  console.log(color.bold(` ▸ ${tierLabel} `) + chalk.gray(title));
60
70
  console.log();
61
71
  for (const line of DEMO_HINTS[tier]) {
62
- console.log(chalk.white(' ' + line));
72
+ if (line === '')
73
+ console.log();
74
+ else
75
+ console.log(chalk.white(' ' + line));
63
76
  }
64
77
  console.log();
65
- const nextTier = tier === 'a' ? 'b' : tier === 'b' ? 'c' : null;
66
- if (nextTier) {
67
- console.log(chalk.gray(` Need more? Type: `) + chalk.cyan(`hint ${nextTier}`));
78
+ if (tier === 'a') {
79
+ console.log(chalk.gray(' Stuck? Try: ') + chalk.cyan('hint b'));
80
+ console.log();
68
81
  }
69
- else {
70
- console.log(chalk.gray(' That is the deepest hint. Try: ') + chalk.cyan('submit icoa{w3lc0me_2_ai4ctf}'));
82
+ else if (tier === 'b') {
83
+ console.log(chalk.gray(' Really stuck? Try: ') + chalk.cyan('hint c'));
84
+ console.log();
71
85
  }
72
- console.log();
86
+ // No trailing CTA after hint c — the content itself explains everything.
73
87
  }
74
88
  export async function handleChatMessage(input) {
75
89
  if (!chatSession)
@@ -104,7 +118,45 @@ export async function handleChatMessage(input) {
104
118
  body: JSON.stringify({ type: 'ai4ctf', solved: true, tokensUsed: chatTokensUsed, timestamp: new Date().toISOString() }),
105
119
  signal: AbortSignal.timeout(5000),
106
120
  }).catch(() => { });
107
- 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'));
108
160
  console.log();
109
161
  return 'exit';
110
162
  }
@@ -248,7 +300,8 @@ export function registerAi4ctfCommand(program) {
248
300
  console.log(chalk.bold.white(' 👉 New here? Start with the hints in order:'));
249
301
  console.log(' ' + chalk.cyan('hint a') + chalk.gray(' → nudge'));
250
302
  console.log(' ' + chalk.cyan('hint b') + chalk.gray(' → technique'));
251
- console.log(' ' + chalk.cyan('hint c') + chalk.gray(' → near-answer'));
303
+ console.log(' ' + chalk.cyan('hint c') + chalk.gray(' → principle + shell reminder'));
304
+ console.log(chalk.gray(' (hints guide you — they never give the answer directly)'));
252
305
  console.log();
253
306
  console.log(chalk.white(' Or chat freely with your AI teammate — ask anything'));
254
307
  console.log(chalk.gray(' about the challenge. Example: ') + chalk.white('"what encoding is this?"'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "icoa-cli",
3
- "version": "2.19.30",
3
+ "version": "2.19.32",
4
4
  "description": "ICOA CLI — The world's first CLI-native CTF competition terminal",
5
5
  "type": "module",
6
6
  "bin": {