icoa-cli 2.19.11 → 2.19.13
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/LICENSE +71 -0
- package/dist/commands/ai4ctf.js +39 -38
- package/dist/commands/ctf4ai-demo.js +46 -45
- package/dist/commands/exam.js +18 -23
- package/dist/lib/gemini.js +7 -6
- package/dist/lib/i18n.d.ts +20 -0
- package/dist/lib/i18n.js +56 -13
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: ASRA — Australia STEM and Robotics Advancement Association Inc
|
|
6
|
+
Licensed Work: ICOA CLI v2.19.11 and later versions
|
|
7
|
+
The Licensed Work is (c) 2026 ASRA.
|
|
8
|
+
Additional Use Grant: You may use the Licensed Work freely for:
|
|
9
|
+
(a) Personal learning, research, and education
|
|
10
|
+
(b) Classroom and non-commercial educational use
|
|
11
|
+
(c) ICOA-accredited national selection competitions
|
|
12
|
+
(d) Contributions back to this project
|
|
13
|
+
|
|
14
|
+
For commercial training, CTF/AI security event
|
|
15
|
+
organization, or government/military training use,
|
|
16
|
+
contact australia@icoa2026.au for a commercial license.
|
|
17
|
+
|
|
18
|
+
Change Date: April 9, 2029
|
|
19
|
+
|
|
20
|
+
Change License: Apache License, Version 2.0
|
|
21
|
+
|
|
22
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
23
|
+
please contact: australia@icoa2026.au
|
|
24
|
+
|
|
25
|
+
-----------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
Business Source License 1.1
|
|
28
|
+
|
|
29
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
30
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
31
|
+
|
|
32
|
+
Terms
|
|
33
|
+
|
|
34
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
35
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
36
|
+
Licensor may make an Additional Use Grant, above, permitting limited production
|
|
37
|
+
use.
|
|
38
|
+
|
|
39
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
40
|
+
available distribution of a specific version of the Licensed Work under this
|
|
41
|
+
License, whichever comes first, the Licensor hereby grants you rights under the
|
|
42
|
+
terms of the Change License, and the rights granted in the paragraph above
|
|
43
|
+
terminate.
|
|
44
|
+
|
|
45
|
+
If your use of the Licensed Work does not comply with the requirements currently
|
|
46
|
+
in effect as described in this License, you must purchase a commercial license
|
|
47
|
+
from the Licensor, its affiliated entities, or authorized resellers, or you must
|
|
48
|
+
refrain from using the Licensed Work.
|
|
49
|
+
|
|
50
|
+
All copies of the original and modified Licensed Work, and derivative works of
|
|
51
|
+
the Licensed Work, are subject to this License. This License applies separately
|
|
52
|
+
for each version of the Licensed Work and the Change Date may vary for each
|
|
53
|
+
version of the Licensed Work released by Licensor.
|
|
54
|
+
|
|
55
|
+
You must conspicuously display this License on each original or modified copy of
|
|
56
|
+
the Licensed Work. If you receive the Licensed Work in original or modified form
|
|
57
|
+
from a third party, the terms and conditions set forth in this License apply to
|
|
58
|
+
your use of that work.
|
|
59
|
+
|
|
60
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
61
|
+
terminate your rights under this License for the current and all other versions
|
|
62
|
+
of the Licensed Work.
|
|
63
|
+
|
|
64
|
+
This License does not grant you any right in any trademark or logo of Licensor
|
|
65
|
+
or its affiliates (provided that you may use a trademark or logo of Licensor as
|
|
66
|
+
expressly required by this License).
|
|
67
|
+
|
|
68
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
69
|
+
"AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS
|
|
70
|
+
OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
|
|
71
|
+
FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
|
package/dist/commands/ai4ctf.js
CHANGED
|
@@ -4,6 +4,7 @@ import { addTokenUsage } from '../lib/budget.js';
|
|
|
4
4
|
import { getConfig } from '../lib/config.js';
|
|
5
5
|
import { logCommand } from '../lib/logger.js';
|
|
6
6
|
import { printMarkdown, printError } from '../lib/ui.js';
|
|
7
|
+
import { t } from '../lib/i18n.js';
|
|
7
8
|
function getChallengeContext() {
|
|
8
9
|
const config = getConfig();
|
|
9
10
|
if (config.currentChallengeName && config.currentChallengeCategory) {
|
|
@@ -40,11 +41,11 @@ export async function handleChatMessage(input) {
|
|
|
40
41
|
if (flag === DEMO_FLAG) {
|
|
41
42
|
console.log();
|
|
42
43
|
console.log(chalk.green.bold(' ════════════════════════════════════'));
|
|
43
|
-
console.log(chalk.green.bold(
|
|
44
|
+
console.log(chalk.green.bold(` ${t('ai4ctfCorrectFlag')}`));
|
|
44
45
|
console.log(chalk.green.bold(' ════════════════════════════════════'));
|
|
45
46
|
console.log();
|
|
46
|
-
console.log(chalk.white(
|
|
47
|
-
console.log(chalk.gray(
|
|
47
|
+
console.log(chalk.white(` ${t('ai4ctfDecoded')}`));
|
|
48
|
+
console.log(chalk.gray(` ${t('ai4ctfWouldEarn')}`));
|
|
48
49
|
console.log();
|
|
49
50
|
drawTokenBar();
|
|
50
51
|
chatActive = false;
|
|
@@ -55,14 +56,14 @@ export async function handleChatMessage(input) {
|
|
|
55
56
|
body: JSON.stringify({ type: 'ai4ctf', solved: true, tokensUsed: chatTokensUsed, timestamp: new Date().toISOString() }),
|
|
56
57
|
signal: AbortSignal.timeout(5000),
|
|
57
58
|
}).catch(() => { });
|
|
58
|
-
console.log(chalk.white(
|
|
59
|
+
console.log(chalk.white(` ${t('ai4ctfNext')}`));
|
|
59
60
|
console.log();
|
|
60
61
|
return 'exit';
|
|
61
62
|
}
|
|
62
63
|
else {
|
|
63
64
|
console.log();
|
|
64
|
-
console.log(chalk.red(
|
|
65
|
-
console.log(chalk.gray(
|
|
65
|
+
console.log(chalk.red(` ${t('ai4ctfWrongFlag')}`));
|
|
66
|
+
console.log(chalk.gray(` ${t('ai4ctfFlagHint')}`));
|
|
66
67
|
console.log();
|
|
67
68
|
return 'continue';
|
|
68
69
|
}
|
|
@@ -79,7 +80,7 @@ export async function handleChatMessage(input) {
|
|
|
79
80
|
console.log(chalk.gray(' $ ') + chalk.white(cmd));
|
|
80
81
|
console.log(chalk.white(' ' + output.split('\n').join('\n ')));
|
|
81
82
|
console.log();
|
|
82
|
-
console.log(chalk.gray(
|
|
83
|
+
console.log(chalk.gray(` ${t('ai4ctfFoundFlag')}`));
|
|
83
84
|
console.log();
|
|
84
85
|
}
|
|
85
86
|
catch (err) {
|
|
@@ -101,12 +102,12 @@ export async function handleChatMessage(input) {
|
|
|
101
102
|
}).catch(() => { });
|
|
102
103
|
console.log();
|
|
103
104
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
104
|
-
console.log(chalk.white(
|
|
105
|
-
console.log(chalk.gray(`
|
|
106
|
-
console.log(chalk.gray(`
|
|
105
|
+
console.log(chalk.white(` ${t('ai4ctfReport')}`));
|
|
106
|
+
console.log(chalk.gray(` ${t('ai4ctfTokens')}: ${chatTokensUsed}/${DEMO_TOKEN_CAP}`));
|
|
107
|
+
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (gemma-4-31b-it)`));
|
|
107
108
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
108
109
|
console.log();
|
|
109
|
-
console.log(chalk.white(
|
|
110
|
+
console.log(chalk.white(` ${t('ai4ctfNext')}`));
|
|
110
111
|
console.log();
|
|
111
112
|
return 'exit';
|
|
112
113
|
}
|
|
@@ -114,21 +115,21 @@ export async function handleChatMessage(input) {
|
|
|
114
115
|
chatActive = false;
|
|
115
116
|
chatSession = null;
|
|
116
117
|
console.log();
|
|
117
|
-
console.log(chalk.yellow(
|
|
118
|
+
console.log(chalk.yellow(` ${t('tokenLimit')}`));
|
|
118
119
|
drawTokenBar();
|
|
119
120
|
console.log();
|
|
120
121
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
121
|
-
console.log(chalk.white(
|
|
122
|
-
console.log(chalk.gray(`
|
|
123
|
-
console.log(chalk.gray(`
|
|
122
|
+
console.log(chalk.white(` ${t('ai4ctfReport')}`));
|
|
123
|
+
console.log(chalk.gray(` ${t('ai4ctfTokens')}: ${chatTokensUsed}/${DEMO_TOKEN_CAP}`));
|
|
124
|
+
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (gemma-4-31b-it)`));
|
|
124
125
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
125
126
|
console.log();
|
|
126
|
-
console.log(chalk.white(
|
|
127
|
+
console.log(chalk.white(` ${t('ai4ctfNext')}`));
|
|
127
128
|
console.log();
|
|
128
129
|
return 'exit';
|
|
129
130
|
}
|
|
130
131
|
logCommand(`ai4ctf: ${input}`);
|
|
131
|
-
console.log(chalk.gray(
|
|
132
|
+
console.log(chalk.gray(` ${t('ai4ctfThinking')}`));
|
|
132
133
|
try {
|
|
133
134
|
const response = await chatSession.sendMessage(input);
|
|
134
135
|
process.stdout.write('\x1b[1A\x1b[2K');
|
|
@@ -170,42 +171,42 @@ export function registerAi4ctfCommand(program) {
|
|
|
170
171
|
chatTokensUsed = 0;
|
|
171
172
|
// Guided welcome
|
|
172
173
|
console.log();
|
|
173
|
-
console.log(chalk.green.bold(
|
|
174
|
+
console.log(chalk.green.bold(` ═══ ${t('ai4ctfTitle')} ═══`));
|
|
174
175
|
console.log();
|
|
175
|
-
console.log(chalk.white(
|
|
176
|
+
console.log(chalk.white(` ${t('ai4ctfSample')}`));
|
|
176
177
|
console.log();
|
|
177
178
|
console.log(chalk.cyan(' ┌─────────────────────────────────────────────────┐'));
|
|
178
|
-
console.log(chalk.cyan(' │') + chalk.bold.white(
|
|
179
|
+
console.log(chalk.cyan(' │') + chalk.bold.white(` ${t('ai4ctfChallenge')}`.padEnd(50)) + chalk.cyan('│'));
|
|
179
180
|
console.log(chalk.cyan(' │') + chalk.white(' ') + chalk.cyan('│'));
|
|
180
|
-
console.log(chalk.cyan(' │') + chalk.white(
|
|
181
|
+
console.log(chalk.cyan(' │') + chalk.white(` ${t('ai4ctfIntercepted')}`.padEnd(50)) + chalk.cyan('│'));
|
|
181
182
|
console.log(chalk.cyan(' │') + chalk.green(' aWNvYXt3M2xjMG1lXzJfYWk0Y3RmfQ== ') + chalk.cyan('│'));
|
|
182
183
|
console.log(chalk.cyan(' │') + chalk.white(' ') + chalk.cyan('│'));
|
|
183
|
-
console.log(chalk.cyan(' │') + chalk.white(
|
|
184
|
+
console.log(chalk.cyan(' │') + chalk.white(` ${t('ai4ctfDecode')}`.padEnd(50)) + chalk.cyan('│'));
|
|
184
185
|
console.log(chalk.cyan(' │') + chalk.gray(' Flag format: icoa{...} ') + chalk.cyan('│'));
|
|
185
186
|
console.log(chalk.cyan(' └─────────────────────────────────────────────────┘'));
|
|
186
187
|
console.log();
|
|
187
|
-
console.log(chalk.white(
|
|
188
|
+
console.log(chalk.white(` ${t('ai4ctfLevels')}`));
|
|
188
189
|
console.log();
|
|
189
|
-
console.log(chalk.yellow(' hint a') + chalk.gray(
|
|
190
|
-
console.log(chalk.gray(
|
|
191
|
-
console.log(chalk.yellow(' hint b') + chalk.gray(
|
|
192
|
-
console.log(chalk.gray(
|
|
193
|
-
console.log(chalk.yellow(' hint c') + chalk.gray(
|
|
194
|
-
console.log(chalk.gray(
|
|
190
|
+
console.log(chalk.yellow(' hint a') + chalk.gray(` ${t('ai4ctfHintA')}`));
|
|
191
|
+
console.log(chalk.gray(` ${t('ai4ctfHintAUses')}`));
|
|
192
|
+
console.log(chalk.yellow(' hint b') + chalk.gray(` ${t('ai4ctfHintB')}`));
|
|
193
|
+
console.log(chalk.gray(` ${t('ai4ctfHintBUses')}`));
|
|
194
|
+
console.log(chalk.yellow(' hint c') + chalk.gray(` ${t('ai4ctfHintC')}`));
|
|
195
|
+
console.log(chalk.gray(` ${t('ai4ctfHintCUses')}`));
|
|
195
196
|
console.log();
|
|
196
197
|
console.log(chalk.gray(' ─────────────────────────────────────────'));
|
|
197
|
-
console.log(chalk.white(
|
|
198
|
-
console.log(chalk.gray(
|
|
199
|
-
console.log(chalk.gray(
|
|
198
|
+
console.log(chalk.white(` ${t('ai4ctfTryNow')}`));
|
|
199
|
+
console.log(chalk.gray(` ${t('ai4ctfExample')}`));
|
|
200
|
+
console.log(chalk.gray(` ${t('ai4ctfFreeChat')}`));
|
|
200
201
|
console.log();
|
|
201
|
-
console.log(chalk.yellow(
|
|
202
|
-
console.log(chalk.white(' submit <flag>') + chalk.gray(
|
|
203
|
-
console.log(chalk.white(' !<command>') + chalk.gray(
|
|
204
|
-
console.log(chalk.gray(
|
|
202
|
+
console.log(chalk.yellow(` ${t('ai4ctfCommands')}`));
|
|
203
|
+
console.log(chalk.white(' submit <flag>') + chalk.gray(` ${t('ai4ctfSubmitCmd')}`));
|
|
204
|
+
console.log(chalk.white(' !<command>') + chalk.gray(` ${t('ai4ctfShellCmd')}`));
|
|
205
|
+
console.log(chalk.gray(` exit ${t('ai4ctfEndSession')}`));
|
|
205
206
|
console.log();
|
|
206
207
|
drawTokenBar();
|
|
207
|
-
console.log(chalk.gray(`
|
|
208
|
-
console.log(chalk.gray(
|
|
208
|
+
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (${modelName})`));
|
|
209
|
+
console.log(chalk.gray(` ${t('ai4ctfExit')}`));
|
|
209
210
|
console.log();
|
|
210
211
|
});
|
|
211
212
|
}
|
|
@@ -2,47 +2,48 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { logCommand } from '../lib/logger.js';
|
|
3
3
|
import { printError } from '../lib/ui.js';
|
|
4
4
|
import { getConfig } from '../lib/config.js';
|
|
5
|
+
import { t } from '../lib/i18n.js';
|
|
5
6
|
function printDemoReport(ctf4aiSolved, ctf4aiTokens) {
|
|
6
7
|
const config = getConfig();
|
|
7
8
|
const modelName = config.geminiModel || 'gemma-4-31b-it';
|
|
8
9
|
console.log();
|
|
9
10
|
console.log(chalk.cyan(' ═══════════════════════════════════════════════'));
|
|
10
|
-
console.log(chalk.bold.white(
|
|
11
|
+
console.log(chalk.bold.white(` ${t('reportTitle')}`));
|
|
11
12
|
console.log(chalk.cyan(' ═══════════════════════════════════════════════'));
|
|
12
13
|
console.log();
|
|
13
|
-
console.log(chalk.white(
|
|
14
|
-
console.log(chalk.green(
|
|
14
|
+
console.log(chalk.white(` ${t('reportStage1')}`));
|
|
15
|
+
console.log(chalk.green(` ${t('reportCompleted')}`));
|
|
15
16
|
console.log();
|
|
16
|
-
console.log(chalk.white(
|
|
17
|
-
console.log(chalk.green(
|
|
18
|
-
console.log(chalk.gray(
|
|
19
|
-
console.log(chalk.gray(
|
|
17
|
+
console.log(chalk.white(` ${t('reportStage2')}`));
|
|
18
|
+
console.log(chalk.green(` ${t('reportExperienced')}`));
|
|
19
|
+
console.log(chalk.gray(` ${t('reportStage2Sub')}`));
|
|
20
|
+
console.log(chalk.gray(` ${t('reportStage2Hints')}`));
|
|
20
21
|
console.log();
|
|
21
|
-
console.log(chalk.white(
|
|
22
|
+
console.log(chalk.white(` ${t('reportStage3')}`));
|
|
22
23
|
if (ctf4aiSolved) {
|
|
23
|
-
console.log(chalk.green(
|
|
24
|
+
console.log(chalk.green(` ${t('reportSolved')}`));
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
|
-
console.log(chalk.yellow(
|
|
27
|
+
console.log(chalk.yellow(` ${t('reportNotSolved')}`));
|
|
27
28
|
}
|
|
28
|
-
console.log(chalk.gray(`
|
|
29
|
+
console.log(chalk.gray(` ${t('ai4ctfTokens')}: ${ctf4aiTokens}/${CTF4AI_TOKEN_LIMIT}`));
|
|
29
30
|
console.log();
|
|
30
31
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
31
32
|
console.log();
|
|
32
|
-
console.log(chalk.bold.white(
|
|
33
|
-
console.log(chalk.gray(
|
|
34
|
-
console.log(chalk.gray(
|
|
35
|
-
console.log(chalk.gray(
|
|
36
|
-
console.log(chalk.gray(
|
|
33
|
+
console.log(chalk.bold.white(` ${t('reportRecommend')}`));
|
|
34
|
+
console.log(chalk.gray(` · ${t('reportRec1')}`));
|
|
35
|
+
console.log(chalk.gray(` · ${t('reportRec2')}`));
|
|
36
|
+
console.log(chalk.gray(` · ${t('reportRec3')}`));
|
|
37
|
+
console.log(chalk.gray(` · ${t('reportRec4')}`));
|
|
37
38
|
console.log();
|
|
38
|
-
console.log(chalk.gray(`
|
|
39
|
+
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (${modelName})`));
|
|
39
40
|
console.log();
|
|
40
41
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
41
42
|
console.log();
|
|
42
|
-
console.log(chalk.white(
|
|
43
|
-
console.log(chalk.white(' nations') + chalk.gray(
|
|
44
|
-
console.log(chalk.white(' about') + chalk.gray(
|
|
45
|
-
console.log(chalk.white(' demo') + chalk.gray(
|
|
43
|
+
console.log(chalk.white(` ${t('reportReady')}`));
|
|
44
|
+
console.log(chalk.white(' nations') + chalk.gray(` ${t('reportNations')}`));
|
|
45
|
+
console.log(chalk.white(' about') + chalk.gray(` ${t('reportAbout')}`));
|
|
46
|
+
console.log(chalk.white(' demo') + chalk.gray(` ${t('reportDemo')}`));
|
|
46
47
|
console.log();
|
|
47
48
|
console.log(chalk.yellow(' ICOA 2026 · Sydney, Australia · Jun 27 - Jul 2'));
|
|
48
49
|
console.log(chalk.cyan.underline(' https://icoa2026.au'));
|
|
@@ -80,14 +81,14 @@ export async function handleCtf4aiMessage(input) {
|
|
|
80
81
|
signal: AbortSignal.timeout(5000),
|
|
81
82
|
}).catch(() => { });
|
|
82
83
|
console.log();
|
|
83
|
-
console.log(chalk.gray(
|
|
84
|
+
console.log(chalk.gray(` ${t('ctf4aiEnded')}`));
|
|
84
85
|
printDemoReport(false, ctf4aiTokens);
|
|
85
86
|
return 'exit';
|
|
86
87
|
}
|
|
87
88
|
if (ctf4aiTokens >= CTF4AI_TOKEN_LIMIT) {
|
|
88
89
|
console.log();
|
|
89
|
-
console.log(chalk.yellow(
|
|
90
|
-
console.log(chalk.white(
|
|
90
|
+
console.log(chalk.yellow(` ${t('tokenLimit')}`));
|
|
91
|
+
console.log(chalk.white(` ${t('ctf4aiHeld')}`));
|
|
91
92
|
ctf4aiActive = false;
|
|
92
93
|
ctf4aiSession = null;
|
|
93
94
|
fetch('https://practice.icoa2026.au/api/icoa/demo-stats', {
|
|
@@ -101,7 +102,7 @@ export async function handleCtf4aiMessage(input) {
|
|
|
101
102
|
}
|
|
102
103
|
logCommand(`ctf4ai: ${input}`);
|
|
103
104
|
try {
|
|
104
|
-
console.log(chalk.gray(
|
|
105
|
+
console.log(chalk.gray(` ${t('ctf4aiThinking')}`));
|
|
105
106
|
const { text, tokensUsed } = await ctf4aiSession.sendMessage(input);
|
|
106
107
|
ctf4aiTokens += tokensUsed;
|
|
107
108
|
// Clear "Thinking..." line
|
|
@@ -117,11 +118,11 @@ export async function handleCtf4aiMessage(input) {
|
|
|
117
118
|
if (strictMatch || spelledMatch) {
|
|
118
119
|
console.log();
|
|
119
120
|
console.log(chalk.green.bold(' ════════════════════════════════════'));
|
|
120
|
-
console.log(chalk.green.bold(
|
|
121
|
+
console.log(chalk.green.bold(` ${t('ctf4aiSuccess')}`));
|
|
121
122
|
console.log(chalk.green.bold(' ════════════════════════════════════'));
|
|
122
123
|
console.log();
|
|
123
|
-
console.log(chalk.white(
|
|
124
|
-
console.log(chalk.gray(
|
|
124
|
+
console.log(chalk.white(` ${t('ctf4aiDefense')}`));
|
|
125
|
+
console.log(chalk.gray(` ${t('ctf4aiInjection')}`));
|
|
125
126
|
ctf4aiActive = false;
|
|
126
127
|
ctf4aiSession = null;
|
|
127
128
|
fetch('https://practice.icoa2026.au/api/icoa/demo-stats', {
|
|
@@ -147,34 +148,34 @@ export function registerCtf4aiDemoCommand(program) {
|
|
|
147
148
|
.action(async () => {
|
|
148
149
|
logCommand('ctf4ai');
|
|
149
150
|
if (ctf4aiActive) {
|
|
150
|
-
console.log(chalk.gray(
|
|
151
|
+
console.log(chalk.gray(` ${t('ctf4aiAlready')}`));
|
|
151
152
|
return;
|
|
152
153
|
}
|
|
153
154
|
const config = getConfig();
|
|
154
155
|
const modelName = config.geminiModel || 'gemma-4-31b-it';
|
|
155
156
|
console.log();
|
|
156
|
-
console.log(chalk.red.bold(
|
|
157
|
+
console.log(chalk.red.bold(` ═══ ${t('ctf4aiTitle')} ═══`));
|
|
157
158
|
console.log();
|
|
158
|
-
console.log(chalk.white(
|
|
159
|
+
console.log(chalk.white(` ${t('ctf4aiChallenge')}`));
|
|
159
160
|
console.log();
|
|
160
|
-
console.log(chalk.gray(
|
|
161
|
-
console.log(chalk.gray(
|
|
161
|
+
console.log(chalk.gray(` ${t('ctf4aiIntro1')}`));
|
|
162
|
+
console.log(chalk.gray(` ${t('ctf4aiIntro2')}`));
|
|
162
163
|
console.log();
|
|
163
164
|
console.log(chalk.gray(' ┌─────────────────────────────────────────────────┐'));
|
|
164
|
-
console.log(chalk.gray(' │') + chalk.white(
|
|
165
|
-
console.log(chalk.gray(' │') + chalk.white(
|
|
165
|
+
console.log(chalk.gray(' │') + chalk.white(` ${t('ctf4aiRule')}`.padEnd(50)) + chalk.gray('│'));
|
|
166
|
+
console.log(chalk.gray(' │') + chalk.white(` ${t('ctf4aiMission')}`.padEnd(50)) + chalk.gray('│'));
|
|
166
167
|
console.log(chalk.gray(' │') + chalk.white(' ') + chalk.gray('│'));
|
|
167
|
-
console.log(chalk.gray(' │') + chalk.yellow(
|
|
168
|
-
console.log(chalk.gray(' │') + chalk.gray(
|
|
169
|
-
console.log(chalk.gray(' │') + chalk.gray(
|
|
170
|
-
console.log(chalk.gray(' │') + chalk.gray(
|
|
171
|
-
console.log(chalk.gray(' │') + chalk.gray(
|
|
168
|
+
console.log(chalk.gray(' │') + chalk.yellow(` ${t('ctf4aiIdeas')}`.padEnd(50)) + chalk.gray('│'));
|
|
169
|
+
console.log(chalk.gray(' │') + chalk.gray(` · ${t('ctf4aiIdea1')}`.padEnd(50)) + chalk.gray('│'));
|
|
170
|
+
console.log(chalk.gray(' │') + chalk.gray(` · ${t('ctf4aiIdea2')}`.padEnd(50)) + chalk.gray('│'));
|
|
171
|
+
console.log(chalk.gray(' │') + chalk.gray(` · ${t('ctf4aiIdea3')}`.padEnd(50)) + chalk.gray('│'));
|
|
172
|
+
console.log(chalk.gray(' │') + chalk.gray(` · ${t('ctf4aiIdea4')}`.padEnd(50)) + chalk.gray('│'));
|
|
172
173
|
console.log(chalk.gray(' └─────────────────────────────────────────────────┘'));
|
|
173
174
|
console.log();
|
|
174
|
-
console.log(chalk.gray(`
|
|
175
|
-
console.log(chalk.gray(
|
|
176
|
-
console.log(chalk.gray(`
|
|
177
|
-
console.log(chalk.gray(
|
|
175
|
+
console.log(chalk.gray(` ${t('ctf4aiBudget')}: ~${Math.round(CTF4AI_TOKEN_LIMIT / 4)} words (${CTF4AI_TOKEN_LIMIT} tokens)`));
|
|
176
|
+
console.log(chalk.gray(` ${t('ctf4aiRelaxed')}`));
|
|
177
|
+
console.log(chalk.gray(` ${t('ai4ctfModel')}: Google Gemma 4 (${modelName})`));
|
|
178
|
+
console.log(chalk.gray(` ${t('ctf4aiQuit')}`));
|
|
178
179
|
console.log();
|
|
179
180
|
try {
|
|
180
181
|
// Create chat with restrictive system prompt
|
|
@@ -196,7 +197,7 @@ export function registerCtf4aiDemoCommand(program) {
|
|
|
196
197
|
};
|
|
197
198
|
ctf4aiActive = true;
|
|
198
199
|
ctf4aiTokens = 0;
|
|
199
|
-
console.log(chalk.red(' ctf4ai> ') + chalk.gray('
|
|
200
|
+
console.log(chalk.red(' ctf4ai> ') + chalk.gray(`${t('ctf4aiPrompt')}`));
|
|
200
201
|
console.log();
|
|
201
202
|
}
|
|
202
203
|
catch (err) {
|
package/dist/commands/exam.js
CHANGED
|
@@ -739,36 +739,31 @@ export function registerExamCommand(program) {
|
|
|
739
739
|
}
|
|
740
740
|
console.log();
|
|
741
741
|
// ─── What is CTF + Dual-track introduction ───
|
|
742
|
-
console.log(chalk.white(
|
|
742
|
+
console.log(chalk.white(` ${t('theoryDone')}`));
|
|
743
|
+
console.log(chalk.white(` ${t('theoryDone2')}`));
|
|
743
744
|
console.log();
|
|
744
|
-
console.log(chalk.yellow(
|
|
745
|
-
console.log(chalk.gray(
|
|
746
|
-
console.log(chalk.gray(
|
|
747
|
-
console.log(chalk.
|
|
748
|
-
console.log(chalk.gray(
|
|
745
|
+
console.log(chalk.yellow(` ${t('didYouKnow')}`));
|
|
746
|
+
console.log(chalk.gray(` ${t('ctfFlags1')}`));
|
|
747
|
+
console.log(chalk.gray(` ${t('ctfFlags2')}`));
|
|
748
|
+
console.log(chalk.green(' icoa{example_flag_here}'));
|
|
749
|
+
console.log(chalk.gray(` ${t('ctfFlags3')}`));
|
|
749
750
|
console.log();
|
|
750
|
-
console.log(chalk.white(
|
|
751
|
+
console.log(chalk.white(` ${t('twoTracks')}`));
|
|
751
752
|
console.log();
|
|
752
|
-
console.log(chalk.green.bold(' AI4CTF') + chalk.white(
|
|
753
|
-
console.log(chalk.gray(
|
|
754
|
-
console.log(chalk.gray(' and work together to crack cybersecurity puzzles.'));
|
|
753
|
+
console.log(chalk.green.bold(' AI4CTF') + chalk.white(` — ${t('ai4ctfDesc')}`));
|
|
754
|
+
console.log(chalk.gray(` ${t('ai4ctfSub')}`));
|
|
755
755
|
console.log();
|
|
756
|
-
console.log(chalk.red.bold(' CTF4AI') + chalk.white(
|
|
757
|
-
console.log(chalk.gray(
|
|
758
|
-
console.log(chalk.gray(' This is a real skill used to test AI security.'));
|
|
756
|
+
console.log(chalk.red.bold(' CTF4AI') + chalk.white(` — ${t('ctf4aiDesc')}`));
|
|
757
|
+
console.log(chalk.gray(` ${t('ctf4aiSub')}`));
|
|
759
758
|
console.log();
|
|
760
759
|
console.log(chalk.cyan(' ─────────────────────────────────────────────'));
|
|
761
|
-
console.log(chalk.
|
|
762
|
-
console.log(chalk.
|
|
763
|
-
console.log(chalk.
|
|
764
|
-
console.log();
|
|
765
|
-
console.log(chalk.white(' Ready to try? Type a command:'));
|
|
766
|
-
console.log(chalk.green.bold(' ai4ctf') + chalk.gray(' Chat with AI teammate (start here!)'));
|
|
767
|
-
console.log(chalk.red.bold(' ctf4ai') + chalk.gray(' Trick the AI — make it say "koala"'));
|
|
760
|
+
console.log(chalk.white(` ${t('readyToTry')}`));
|
|
761
|
+
console.log(chalk.green.bold(' ai4ctf') + chalk.gray(` ${t('ai4ctfDesc')}`));
|
|
762
|
+
console.log(chalk.red.bold(' ctf4ai') + chalk.gray(` ${t('ctf4aiDesc')}`));
|
|
768
763
|
console.log();
|
|
769
|
-
console.log(chalk.gray(
|
|
770
|
-
console.log(chalk.white(' nations') + chalk.gray(
|
|
771
|
-
console.log(chalk.white(' exam AU') + chalk.gray(
|
|
764
|
+
console.log(chalk.gray(` ${t('forNational')}`));
|
|
765
|
+
console.log(chalk.white(' nations') + chalk.gray(` ${t('viewRegions')}`));
|
|
766
|
+
console.log(chalk.white(' exam AU') + chalk.gray(` ${t('enterExam')}`));
|
|
772
767
|
console.log();
|
|
773
768
|
}
|
|
774
769
|
catch (err) {
|
package/dist/lib/gemini.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GoogleGenAI } from '@google/genai';
|
|
2
|
+
import chalk from 'chalk';
|
|
2
3
|
import { getConfig, saveConfig } from './config.js';
|
|
3
4
|
const SYSTEM_PROMPTS = {
|
|
4
5
|
A: `You are an AI assistant in a cybersecurity CTF competition called ICOA.
|
|
@@ -60,14 +61,14 @@ export async function generateHint(level, question, context) {
|
|
|
60
61
|
try {
|
|
61
62
|
const { input } = await import('@inquirer/prompts');
|
|
62
63
|
console.log();
|
|
63
|
-
console.log(' Gemini API key not configured.');
|
|
64
|
-
console.log(' Get one free at: https://aistudio.google.com/apikey');
|
|
64
|
+
console.log(chalk.yellow(' Gemini API key not configured.'));
|
|
65
|
+
console.log(chalk.gray(' Get one free at: ') + chalk.cyan('https://aistudio.google.com/apikey'));
|
|
65
66
|
console.log();
|
|
66
67
|
apiKey = await input({ message: 'Enter your Gemini API Key:' });
|
|
67
68
|
if (apiKey.trim()) {
|
|
68
69
|
apiKey = apiKey.trim();
|
|
69
70
|
saveConfig({ geminiApiKey: apiKey });
|
|
70
|
-
console.log(' Key saved for future use.');
|
|
71
|
+
console.log(chalk.green(' Key saved for future use.'));
|
|
71
72
|
console.log();
|
|
72
73
|
}
|
|
73
74
|
else {
|
|
@@ -146,14 +147,14 @@ export async function createChatSession(context) {
|
|
|
146
147
|
try {
|
|
147
148
|
const { input } = await import('@inquirer/prompts');
|
|
148
149
|
console.log();
|
|
149
|
-
console.log(' Gemini API key not configured.');
|
|
150
|
-
console.log(' Get one free at: https://aistudio.google.com/apikey');
|
|
150
|
+
console.log(chalk.yellow(' Gemini API key not configured.'));
|
|
151
|
+
console.log(chalk.gray(' Get one free at: ') + chalk.cyan('https://aistudio.google.com/apikey'));
|
|
151
152
|
console.log();
|
|
152
153
|
apiKey = await input({ message: 'Enter your Gemini API Key:' });
|
|
153
154
|
if (apiKey.trim()) {
|
|
154
155
|
apiKey = apiKey.trim();
|
|
155
156
|
saveConfig({ geminiApiKey: apiKey });
|
|
156
|
-
console.log(' Key saved for future use.');
|
|
157
|
+
console.log(chalk.green(' Key saved for future use.'));
|
|
157
158
|
console.log();
|
|
158
159
|
}
|
|
159
160
|
else {
|
package/dist/lib/i18n.d.ts
CHANGED
|
@@ -119,6 +119,26 @@ declare const EN: {
|
|
|
119
119
|
continueTry: string;
|
|
120
120
|
continueChat: string;
|
|
121
121
|
continueAfter: string;
|
|
122
|
+
ai4ctfCommands: string;
|
|
123
|
+
ai4ctfSubmitCmd: string;
|
|
124
|
+
ai4ctfShellCmd: string;
|
|
125
|
+
ai4ctfEndSession: string;
|
|
126
|
+
ai4ctfCorrectFlag: string;
|
|
127
|
+
ai4ctfDecoded: string;
|
|
128
|
+
ai4ctfWouldEarn: string;
|
|
129
|
+
ai4ctfWrongFlag: string;
|
|
130
|
+
ai4ctfFlagHint: string;
|
|
131
|
+
ai4ctfFoundFlag: string;
|
|
132
|
+
ai4ctfThinking: string;
|
|
133
|
+
ctf4aiRelaxed: string;
|
|
134
|
+
ctf4aiEnded: string;
|
|
135
|
+
ctf4aiAlready: string;
|
|
136
|
+
ctf4aiPrompt: string;
|
|
137
|
+
ctf4aiThinking: string;
|
|
138
|
+
readyToTry: string;
|
|
139
|
+
forNational: string;
|
|
140
|
+
viewRegions: string;
|
|
141
|
+
enterExam: string;
|
|
122
142
|
};
|
|
123
143
|
export declare function t(key: keyof Strings): string;
|
|
124
144
|
export declare function hasFullTranslation(lang: string): boolean;
|