icoa-cli 2.19.35 → 2.19.36
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/dist/commands/ai4ctf.js +57 -68
- package/dist/commands/ctf4ai-demo.js +6 -4
- package/dist/commands/exam.js +3 -3
- package/dist/lib/i18n.d.ts +50 -2
- package/dist/lib/i18n.js +99 -156
- package/package.json +1 -1
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -43,68 +43,45 @@ const DEMO_FLAG = 'icoa{w3lc0me_2_ai4ctf}';
|
|
|
43
43
|
// already enough. Instead c explains the hint principle and reminds the
|
|
44
44
|
// user how to run a shell command inside ai4ctf (the `!` prefix).
|
|
45
45
|
// This mirrors real competition behavior where trivial challenges cap at hint b.
|
|
46
|
-
|
|
47
|
-
a: [
|
|
48
|
-
'The string ends with "==" and uses only letters, digits, "+", "/", and "=".',
|
|
49
|
-
'That pattern is a fingerprint — you have seen it before.',
|
|
50
|
-
'Where is "=" typically used as padding?',
|
|
51
|
-
],
|
|
52
|
-
b: [
|
|
53
|
-
'This is Base64 encoded. Decode the string to find the flag.',
|
|
54
|
-
],
|
|
55
|
-
c: [
|
|
56
|
-
'Hints never give you the answer directly — they only point you in the right direction.',
|
|
57
|
-
'For simple challenges like this one, hint c adds nothing extra:',
|
|
58
|
-
'hint b already tells you everything you need.',
|
|
59
|
-
'',
|
|
60
|
-
'Two ways forward from here:',
|
|
61
|
-
'',
|
|
62
|
-
' 1. Chat with your AI teammate in natural language. Examples:',
|
|
63
|
-
' what is the base64 command?',
|
|
64
|
-
' how do I decode Base64 on macOS?',
|
|
65
|
-
' Just type the question — anything without "!" goes to the AI.',
|
|
66
|
-
'',
|
|
67
|
-
' 2. Run a shell command directly. Shell commands inside ai4ctf',
|
|
68
|
-
' must start with "!", otherwise your text goes to the AI. Example:',
|
|
69
|
-
'',
|
|
70
|
-
' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d',
|
|
71
|
-
],
|
|
72
|
-
};
|
|
46
|
+
// Multi-line hint bodies live in i18n.ts (ai4ctfHintABody/BBody/CBody).
|
|
73
47
|
// Shown when the user hits the 5000-token demo cap without solving. Keeps
|
|
74
48
|
// the session alive (no chatActive=false) so they can still paste the shell
|
|
75
49
|
// command below and then `submit <flag>`.
|
|
76
50
|
function showTokenCapReveal() {
|
|
77
51
|
console.log();
|
|
78
52
|
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
79
|
-
console.log(chalk.bold.yellow(
|
|
53
|
+
console.log(chalk.bold.yellow(` ${t('ai4ctfRevealTitle')}`));
|
|
80
54
|
console.log(chalk.yellow(' ─────────────────────────────────────────────'));
|
|
81
55
|
console.log();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
56
|
+
for (const line of t('ai4ctfRevealBody').split('\n')) {
|
|
57
|
+
if (line === '')
|
|
58
|
+
console.log();
|
|
59
|
+
else
|
|
60
|
+
console.log(chalk.white(' ' + line));
|
|
61
|
+
}
|
|
86
62
|
console.log();
|
|
87
63
|
console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
88
64
|
console.log();
|
|
89
|
-
console.log(chalk.white(
|
|
65
|
+
console.log(chalk.white(` ${t('ai4ctfRevealSeeFlag')}`));
|
|
90
66
|
console.log();
|
|
91
67
|
console.log(chalk.green(' icoa{w3lc0me_2_ai4ctf}'));
|
|
92
68
|
console.log();
|
|
93
|
-
console.log(chalk.white(
|
|
69
|
+
console.log(chalk.white(` ${t('ai4ctfRevealThenSubmit')}`));
|
|
94
70
|
console.log();
|
|
95
71
|
console.log(chalk.cyan(' submit icoa{w3lc0me_2_ai4ctf}'));
|
|
96
72
|
console.log();
|
|
97
|
-
console.log(chalk.gray(
|
|
73
|
+
console.log(chalk.gray(` ${t('ai4ctfRevealLockNote')}`));
|
|
98
74
|
console.log();
|
|
99
75
|
}
|
|
100
76
|
function showDemoHint(tier) {
|
|
101
77
|
const title = tier === 'a' ? t('ai4ctfHintA') : tier === 'b' ? t('ai4ctfHintB') : t('ai4ctfHintC');
|
|
78
|
+
const body = tier === 'a' ? t('ai4ctfHintABody') : tier === 'b' ? t('ai4ctfHintBBody') : t('ai4ctfHintCBody');
|
|
102
79
|
const tierLabel = `Hint ${tier.toUpperCase()}`;
|
|
103
80
|
const color = tier === 'a' ? chalk.green : tier === 'b' ? chalk.yellow : chalk.red;
|
|
104
81
|
console.log();
|
|
105
82
|
console.log(color.bold(` ▸ ${tierLabel} `) + chalk.gray(title));
|
|
106
83
|
console.log();
|
|
107
|
-
for (const line of
|
|
84
|
+
for (const line of body.split('\n')) {
|
|
108
85
|
if (line === '')
|
|
109
86
|
console.log();
|
|
110
87
|
else
|
|
@@ -112,11 +89,11 @@ function showDemoHint(tier) {
|
|
|
112
89
|
}
|
|
113
90
|
console.log();
|
|
114
91
|
if (tier === 'a') {
|
|
115
|
-
console.log(chalk.gray(
|
|
92
|
+
console.log(chalk.gray(` ${t('ai4ctfHintNextA')} `) + chalk.cyan('hint b'));
|
|
116
93
|
console.log();
|
|
117
94
|
}
|
|
118
95
|
else if (tier === 'b') {
|
|
119
|
-
console.log(chalk.gray(
|
|
96
|
+
console.log(chalk.gray(` ${t('ai4ctfHintNextB')} `) + chalk.cyan('hint c'));
|
|
120
97
|
console.log();
|
|
121
98
|
}
|
|
122
99
|
// No trailing CTA after hint c — the content itself explains everything.
|
|
@@ -161,41 +138,53 @@ export async function handleChatMessage(input) {
|
|
|
161
138
|
await sleep(1500);
|
|
162
139
|
console.log();
|
|
163
140
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
164
|
-
console.log(chalk.bold.white(
|
|
141
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapTitle')}`));
|
|
165
142
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
166
143
|
console.log();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
console.log(chalk.
|
|
170
|
-
|
|
144
|
+
const wrap1Head = t('ai4ctfWrapLine1Head');
|
|
145
|
+
const wrap1Body = t('ai4ctfWrapLine1Body');
|
|
146
|
+
console.log(chalk.white(` 1. ${wrap1Head} `) + chalk.gray(wrap1Body.split('\n')[0] || ''));
|
|
147
|
+
for (const line of wrap1Body.split('\n').slice(1)) {
|
|
148
|
+
if (line.trim())
|
|
149
|
+
console.log(chalk.gray(' ' + line.replace(/\{thinking\}/g, 'thinking')));
|
|
150
|
+
}
|
|
171
151
|
console.log();
|
|
172
|
-
console.log(chalk.white(
|
|
152
|
+
console.log(chalk.white(` 2. ${t('ai4ctfWrapLine2Head')} `) + chalk.gray(t('ai4ctfWrapLine2Body')));
|
|
173
153
|
console.log();
|
|
174
154
|
console.log(chalk.cyan(' !echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
175
155
|
console.log();
|
|
176
156
|
await sleep(2000);
|
|
177
157
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
178
|
-
console.log(chalk.bold.white(
|
|
158
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapQuotasTitle')}`));
|
|
179
159
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
180
160
|
console.log();
|
|
181
|
-
console.log(chalk.yellow(' hint a ') + chalk.white('
|
|
182
|
-
console.log(chalk.yellow(' hint b ') + chalk.white('
|
|
183
|
-
console.log(chalk.yellow(' hint c ') + chalk.white('
|
|
161
|
+
console.log(chalk.yellow(' hint a ') + chalk.white(t('ai4ctfWrapQuotaA').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaAHint')));
|
|
162
|
+
console.log(chalk.yellow(' hint b ') + chalk.white(t('ai4ctfWrapQuotaB').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaBHint')));
|
|
163
|
+
console.log(chalk.yellow(' hint c ') + chalk.white(t('ai4ctfWrapQuotaC').padEnd(26)) + chalk.gray(t('ai4ctfWrapQuotaCHint')));
|
|
184
164
|
console.log();
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
165
|
+
for (const line of t('ai4ctfWrapQuotaFooter').split('\n')) {
|
|
166
|
+
console.log(chalk.gray(' ' + line));
|
|
167
|
+
}
|
|
188
168
|
console.log();
|
|
189
169
|
await sleep(2000);
|
|
190
170
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
191
|
-
console.log(chalk.bold.white(
|
|
171
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWrapNextTitle')} `) + chalk.red.bold('ctf4ai') + chalk.white(` — ${t('ai4ctfWrapNextSub')}`));
|
|
192
172
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
193
173
|
console.log();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
174
|
+
const nextBody = t('ai4ctfWrapNextBody');
|
|
175
|
+
const noProg = t('ai4ctfWrapNoProg');
|
|
176
|
+
const lines = nextBody.split('\n');
|
|
177
|
+
// First line contains the {noProg} placeholder to bold-emphasize.
|
|
178
|
+
if (lines[0]) {
|
|
179
|
+
const [before, after] = lines[0].split('{noProg}');
|
|
180
|
+
console.log(chalk.white(' ' + (before || '')) + chalk.bold.white(noProg) + chalk.white(after || ''));
|
|
181
|
+
}
|
|
182
|
+
for (const line of lines.slice(1)) {
|
|
183
|
+
if (line.trim())
|
|
184
|
+
console.log(chalk.white(' ' + line));
|
|
185
|
+
}
|
|
197
186
|
console.log();
|
|
198
|
-
console.log(chalk.gray(
|
|
187
|
+
console.log(chalk.gray(` ${t('ai4ctfWrapTypeCtf4ai')} `) + chalk.bold.red('ctf4ai'));
|
|
199
188
|
console.log();
|
|
200
189
|
return 'exit';
|
|
201
190
|
}
|
|
@@ -274,9 +263,9 @@ export async function handleChatMessage(input) {
|
|
|
274
263
|
// back to the user with a reminder of what actually works now.
|
|
275
264
|
if (tokensLocked) {
|
|
276
265
|
console.log();
|
|
277
|
-
console.log(chalk.yellow(
|
|
278
|
-
console.log(chalk.gray(
|
|
279
|
-
console.log(chalk.gray(
|
|
266
|
+
console.log(chalk.yellow(` ${t('ai4ctfLockedTitle')}`));
|
|
267
|
+
console.log(chalk.gray(` ${t('ai4ctfLockedUse')} `) + chalk.cyan('!echo aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== | base64 -d'));
|
|
268
|
+
console.log(chalk.gray(` ${t('ai4ctfLockedThen')} `) + chalk.cyan('submit icoa{w3lc0me_2_ai4ctf}'));
|
|
280
269
|
console.log();
|
|
281
270
|
return 'continue';
|
|
282
271
|
}
|
|
@@ -349,19 +338,19 @@ export function registerAi4ctfCommand(program) {
|
|
|
349
338
|
console.log(chalk.gray(` ${t('ai4ctfHintCUses')}`));
|
|
350
339
|
console.log();
|
|
351
340
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
352
|
-
console.log(chalk.bold.white(
|
|
353
|
-
console.log(' ' + chalk.cyan('hint a') + chalk.gray(
|
|
354
|
-
console.log(' ' + chalk.cyan('hint b') + chalk.gray(
|
|
355
|
-
console.log(' ' + chalk.cyan('hint c') + chalk.gray(
|
|
356
|
-
console.log(chalk.gray(
|
|
341
|
+
console.log(chalk.bold.white(` ${t('ai4ctfWelcomeCta')}`));
|
|
342
|
+
console.log(' ' + chalk.cyan('hint a') + chalk.gray(` → ${t('ai4ctfHintNudge')}`));
|
|
343
|
+
console.log(' ' + chalk.cyan('hint b') + chalk.gray(` → ${t('ai4ctfHintTechnique')}`));
|
|
344
|
+
console.log(' ' + chalk.cyan('hint c') + chalk.gray(` → ${t('ai4ctfHintPrinciple')}`));
|
|
345
|
+
console.log(chalk.gray(` ${t('ai4ctfWelcomeNoReveal')}`));
|
|
357
346
|
console.log();
|
|
358
|
-
console.log(chalk.white(
|
|
359
|
-
console.log(chalk.gray(
|
|
347
|
+
console.log(chalk.white(` ${t('ai4ctfOrChat')}`));
|
|
348
|
+
console.log(chalk.gray(` ${t('ai4ctfOrChatExample')} `) + chalk.white('"what encoding is this?"'));
|
|
360
349
|
console.log();
|
|
361
350
|
console.log(chalk.yellow(` ${t('ai4ctfCommands')}`));
|
|
362
|
-
console.log(chalk.white(' hint a / b / c ') + chalk.gray(
|
|
351
|
+
console.log(chalk.white(' hint a / b / c ') + chalk.gray(t('ai4ctfCmdHintLine')));
|
|
363
352
|
console.log(chalk.white(' submit <flag> ') + chalk.gray(t('ai4ctfSubmitCmd')));
|
|
364
|
-
console.log(chalk.white(' !<shell cmd> ') + chalk.gray('
|
|
353
|
+
console.log(chalk.white(' !<shell cmd> ') + chalk.gray(t('ai4ctfCmdShellLine')));
|
|
365
354
|
console.log(chalk.gray(' e.g. ') + chalk.white('!echo aWNv... | base64 -d'));
|
|
366
355
|
console.log(chalk.gray(` exit ${t('ai4ctfEndSession')}`));
|
|
367
356
|
console.log();
|
|
@@ -50,18 +50,20 @@ function printDemoReport(ctf4aiSolved, ctf4aiTokens) {
|
|
|
50
50
|
console.log(chalk.white(` ${t('theoryDone2')}`));
|
|
51
51
|
console.log();
|
|
52
52
|
if (hasWrongAnswers) {
|
|
53
|
-
console.log(chalk.white(
|
|
53
|
+
console.log(chalk.white(` 💪 ${t('reportRetryCta')} `) + chalk.bold.cyan('retry'));
|
|
54
54
|
console.log();
|
|
55
55
|
}
|
|
56
56
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
57
57
|
console.log(chalk.white(` ${t('reportReady')}`));
|
|
58
58
|
if (hasWrongAnswers) {
|
|
59
|
-
|
|
59
|
+
const n = retryQueue.length;
|
|
60
|
+
const tmpl = n === 1 ? t('reportRetryWrongN') : t('reportRetryWrongNPlural');
|
|
61
|
+
console.log(chalk.cyan(' retry') + chalk.gray(` ${tmpl.replace('{n}', String(n))}`));
|
|
60
62
|
}
|
|
61
|
-
console.log(chalk.white(' back') + chalk.gray(`
|
|
63
|
+
console.log(chalk.white(' back') + chalk.gray(` ${t('reportBackHint')}`));
|
|
62
64
|
console.log(chalk.white(' demo') + chalk.gray(` ${t('reportDemo')}`));
|
|
63
65
|
console.log(chalk.white(' nations') + chalk.gray(` ${t('reportNations')}`));
|
|
64
|
-
console.log(chalk.white(' about') + chalk.gray(` ${t('
|
|
66
|
+
console.log(chalk.white(' about') + chalk.gray(` ${t('reportAboutHint')}`));
|
|
65
67
|
console.log();
|
|
66
68
|
console.log(chalk.yellow(' ICOA 2026 · Sydney, Australia · Jun 27 - Jul 2'));
|
|
67
69
|
console.log(chalk.cyan.underline(' https://icoa2026.au'));
|
package/dist/commands/exam.js
CHANGED
|
@@ -260,8 +260,8 @@ function printQuestion(q, answer) {
|
|
|
260
260
|
console.log(chalk.yellow(' A/B/C/D') + chalk.gray(` ${t('answerThis')}`));
|
|
261
261
|
console.log(chalk.yellow(' help') + ' ' + helpLabel);
|
|
262
262
|
console.log(chalk.yellow(' next') + chalk.gray(' / ') + chalk.yellow('prev') + chalk.gray(` ${t('htpNav')}`));
|
|
263
|
-
console.log(chalk.yellow(` exam q 1..${total}`) + chalk.gray(
|
|
264
|
-
console.log(chalk.yellow(' exam review') + chalk.gray(
|
|
263
|
+
console.log(chalk.yellow(` exam q 1..${total}`) + chalk.gray(` ${t('htpJump')}`));
|
|
264
|
+
console.log(chalk.yellow(' exam review') + chalk.gray(` ${t('htpReview')}`));
|
|
265
265
|
console.log(chalk.yellow(' back') + chalk.gray(` ${t('htpBack')}`));
|
|
266
266
|
console.log(chalk.yellow(' lang') + chalk.gray(` ${t('htpLang')}`));
|
|
267
267
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
@@ -929,7 +929,7 @@ export function registerExamCommand(program) {
|
|
|
929
929
|
await sleep(2000);
|
|
930
930
|
console.log();
|
|
931
931
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
932
|
-
console.log(chalk.white(
|
|
932
|
+
console.log(chalk.white(` ${t('nextLabel')} `) + chalk.bold.green('ai4ctf') + chalk.gray(` — ${t('ai4ctfDesc')}`));
|
|
933
933
|
console.log(chalk.gray(` ${t('ai4ctfSub')}`));
|
|
934
934
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
935
935
|
console.log();
|
package/dist/lib/i18n.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
type Strings = typeof EN
|
|
2
|
-
declare const EN: {
|
|
1
|
+
type Strings = Partial<typeof EN>;
|
|
2
|
+
export declare const EN: {
|
|
3
3
|
howToPlay: string;
|
|
4
4
|
htpAnswer: string;
|
|
5
5
|
htpHelp: string;
|
|
@@ -139,6 +139,54 @@ declare const EN: {
|
|
|
139
139
|
forNational: string;
|
|
140
140
|
viewRegions: string;
|
|
141
141
|
enterExam: string;
|
|
142
|
+
htpJump: string;
|
|
143
|
+
htpReview: string;
|
|
144
|
+
nextLabel: string;
|
|
145
|
+
reportRetryCta: string;
|
|
146
|
+
reportRetryWrongN: string;
|
|
147
|
+
reportRetryWrongNPlural: string;
|
|
148
|
+
reportBackHint: string;
|
|
149
|
+
reportAboutHint: string;
|
|
150
|
+
ai4ctfWelcomeCta: string;
|
|
151
|
+
ai4ctfHintNudge: string;
|
|
152
|
+
ai4ctfHintTechnique: string;
|
|
153
|
+
ai4ctfHintPrinciple: string;
|
|
154
|
+
ai4ctfWelcomeNoReveal: string;
|
|
155
|
+
ai4ctfOrChat: string;
|
|
156
|
+
ai4ctfOrChatExample: string;
|
|
157
|
+
ai4ctfCmdHintLine: string;
|
|
158
|
+
ai4ctfCmdShellLine: string;
|
|
159
|
+
ai4ctfHintABody: string;
|
|
160
|
+
ai4ctfHintBBody: string;
|
|
161
|
+
ai4ctfHintCBody: string;
|
|
162
|
+
ai4ctfHintNextA: string;
|
|
163
|
+
ai4ctfHintNextB: string;
|
|
164
|
+
ai4ctfWrapTitle: string;
|
|
165
|
+
ai4ctfWrapLine1Head: string;
|
|
166
|
+
ai4ctfWrapLine1Body: string;
|
|
167
|
+
ai4ctfWrapLine2Head: string;
|
|
168
|
+
ai4ctfWrapLine2Body: string;
|
|
169
|
+
ai4ctfWrapQuotasTitle: string;
|
|
170
|
+
ai4ctfWrapQuotaA: string;
|
|
171
|
+
ai4ctfWrapQuotaAHint: string;
|
|
172
|
+
ai4ctfWrapQuotaB: string;
|
|
173
|
+
ai4ctfWrapQuotaBHint: string;
|
|
174
|
+
ai4ctfWrapQuotaC: string;
|
|
175
|
+
ai4ctfWrapQuotaCHint: string;
|
|
176
|
+
ai4ctfWrapQuotaFooter: string;
|
|
177
|
+
ai4ctfWrapNextTitle: string;
|
|
178
|
+
ai4ctfWrapNextSub: string;
|
|
179
|
+
ai4ctfWrapNextBody: string;
|
|
180
|
+
ai4ctfWrapNoProg: string;
|
|
181
|
+
ai4ctfWrapTypeCtf4ai: string;
|
|
182
|
+
ai4ctfRevealTitle: string;
|
|
183
|
+
ai4ctfRevealBody: string;
|
|
184
|
+
ai4ctfRevealSeeFlag: string;
|
|
185
|
+
ai4ctfRevealThenSubmit: string;
|
|
186
|
+
ai4ctfRevealLockNote: string;
|
|
187
|
+
ai4ctfLockedTitle: string;
|
|
188
|
+
ai4ctfLockedUse: string;
|
|
189
|
+
ai4ctfLockedThen: string;
|
|
142
190
|
};
|
|
143
191
|
export declare function t(key: keyof Strings): string;
|
|
144
192
|
export declare function hasFullTranslation(lang: string): boolean;
|