icoa-cli 2.19.99 → 2.19.101

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.
Files changed (45) hide show
  1. package/dist/commands/ai4ctf.js +1 -700
  2. package/dist/commands/connect.js +1 -66
  3. package/dist/commands/ctf.js +1 -620
  4. package/dist/commands/ctf4ai-demo.js +1 -525
  5. package/dist/commands/env.js +1 -737
  6. package/dist/commands/exam.js +1 -2353
  7. package/dist/commands/files.js +1 -52
  8. package/dist/commands/hint.js +1 -119
  9. package/dist/commands/lang.js +1 -155
  10. package/dist/commands/log.js +1 -163
  11. package/dist/commands/note.js +1 -32
  12. package/dist/commands/ref.js +1 -63
  13. package/dist/commands/setup.js +1 -103
  14. package/dist/commands/shell.js +1 -55
  15. package/dist/commands/theme.js +1 -50
  16. package/dist/index.js +1 -225
  17. package/dist/lib/access.js +1 -246
  18. package/dist/lib/budget.js +1 -42
  19. package/dist/lib/colors.js +1 -21
  20. package/dist/lib/config.js +1 -60
  21. package/dist/lib/ctfd-client.js +1 -274
  22. package/dist/lib/demo-exam.js +1 -249
  23. package/dist/lib/demo-flags.js +1 -27
  24. package/dist/lib/demo-stats.js +1 -65
  25. package/dist/lib/exam-client.js +1 -57
  26. package/dist/lib/exam-setup.js +1 -23
  27. package/dist/lib/exam-state.js +1 -112
  28. package/dist/lib/gemini.js +1 -235
  29. package/dist/lib/i18n.js +1 -273
  30. package/dist/lib/log-sync.js +1 -110
  31. package/dist/lib/logger.js +1 -59
  32. package/dist/lib/paper-upgrade.js +1 -117
  33. package/dist/lib/platform.js +1 -86
  34. package/dist/lib/sandbox.js +1 -93
  35. package/dist/lib/terminal.js +1 -49
  36. package/dist/lib/theme.js +1 -108
  37. package/dist/lib/translation.js +1 -66
  38. package/dist/lib/ui.js +1 -80
  39. package/dist/lib/update-check.js +1 -102
  40. package/dist/postinstall.js +1 -48
  41. package/dist/repl.js +1 -1259
  42. package/dist/types/index.d.ts +1 -1
  43. package/dist/types/index.js +1 -38
  44. package/package.json +6 -2
  45. package/translations/sw/i18n-snippet.ts +1 -0
@@ -1,246 +1 @@
1
- import { createHash } from 'node:crypto';
2
- import { execSync } from 'node:child_process';
3
- import { hostname, platform, arch, networkInterfaces } from 'node:os';
4
- import { getConfig, saveConfig, getIcoaDir } from './config.js';
5
- import { readFileSync, writeFileSync, existsSync } from 'node:fs';
6
- import { join } from 'node:path';
7
- // SHA-256 hashes of 100 pre-generated access tokens (ICOA-XXXX-XXXX-XXXX)
8
- const TOKEN_HASHES = new Set([
9
- "93490bf664679467b4ab5af12e240175364b7af988b72cb7d000e309b7c68c15",
10
- "cba7a6f075a4bd8c2fc973336cc0b1966669fc481381a065ce670730bbe0b7d3",
11
- "f6773f614341acb8d2c35e8f466f2876095a2c8026a207e77de621050fa64559",
12
- "d060ab36056fdac449a561fd3340c4b79ad4cde10c9a21c3397aa74574583a2b",
13
- "523c11774e103298c15eb9d138872295194078f2d29486d0a6bd210436a592c3",
14
- "1e16864067470f0a97088f067d8df4b655753ff498a91353b5f9b75989b6be39",
15
- "f1031aac52879c776d4db5ba43eb25bb40f1a841b91304f8adf65a838fb8c666",
16
- "bcd9e25014633ec6556345ab43d0cd213c454bb10d4ea0bd5be5ba02e1a6622c",
17
- "9239ba9c3db74eadbb6dd05949c2a3cbe1b22e14e375ab3ca93d050e2e2ce38b",
18
- "80fc0a899ed4d37138ae3172dafd466de2d3b1ce9630d67e6b00bec9315964d7",
19
- "33ed35ce028824519d3a013ca326d6a58b1ca3723ec182527a7367e1ffc2712b",
20
- "7e90933e760ce5e8df48bdb6bab0e95962bdc1098fceedecf617c0dac37b2a11",
21
- "33fa6e3639a691b217ed0f927a8e2e2aef5eaa15eab7bd90c57874c2df2a28ac",
22
- "67013663fb4536a47f6ea46b434fb7a00574bd4fc4f579e9439ba07f748db31b",
23
- "10c83ad26fc965fcb1d228018f6b54d331e4a2e6087603920b75b500e191c5e4",
24
- "3079268d847dc7eb196ce8cdc0af8a8506b9636539a1b7cce53dc5cb3f4cbe15",
25
- "985eb5309c546d2f9d5018976973d6da06a374b897c73c830fc9d1305e78efa0",
26
- "3a7326d4a7f40cc356b17769f4c5fc0d832d926aff9f067efd60f34c053bf9ef",
27
- "129f408a98ad6c1b13924cf2c831c752b0c726bf1975d6b46f212a178ced52e1",
28
- "ec44bc0b4eb6a929b969caaa561492527c369cc07efa50e40c2c6c16162f0c2c",
29
- "07610942d9da62dd5b91c0ba48602bc44973a9d374ed10ab6c708151677ec626",
30
- "8ce3165bb8e23f3b67ac53b39191aca3e2f0a620b7f932fe6a43e2c42315efcc",
31
- "69938b605e652afc1cf8bc7c0dcf6a99820878367dfb3b2ec954ba90b36014f5",
32
- "660377ce87d378285ab7263fdad86208c8563367d2cc36b4c1402520e45dd5f0",
33
- "bef8a3727dffc94861a1dfa7d6a336ceac30aab9f0679dcab662cb9f682079dd",
34
- "02318a3597b64a2c7de56b01fc25f33cc4142c76315136186df680f490681294",
35
- "b7179114b42b90e9557399ae505050111b6afc55f9295d3ee84d5db6873470c5",
36
- "e227ec0a6b22773500b35bee46f21bc6bc6a00fb001d54e71479f15b8fdfd72b",
37
- "1c9802ae1e932d55e73994ce173a996d170e4d274aeccb1b784c9d9b69913f3d",
38
- "5ed51694773bd1b46a085d10e9a369786a997c50b72ec2bdb6e68921ffca5c51",
39
- "478e457279a41e9b76a3dc5894418e38246d2af31e0f4776dda8aa89c74c88c8",
40
- "a7ec7e047c0e62862e9be64b0a65d3d7894d41efe6eb16ca6cfca45d8007f16f",
41
- "88cf2b75604486ac5f1a0db9afbab28e8e866f9ea00f3e4b4353a7ecc81f6b55",
42
- "dc4daa9ef4149f122979ffd5a8b23bca3cbb83b24a87ba99a1d00dc09e39936e",
43
- "cffd9a3637b5ae30c27cae4ae42dc21374caa27dd818b5d361f112406bf3c0e7",
44
- "33b3e85a964f606e857280ba379de46508f9343cbe1d2722abebbed21b82a106",
45
- "a3754074df08f9c9407c73e680eac1868175cee3beac3f0e7d2bd211bdf51f58",
46
- "f9eb5fd82f3360e22ad45d4797f3a95b907a766ef5a61d856bf959b60a4930dc",
47
- "1c53d3145cb38501a2422bf70f55a0c206b68c14e46da31e0e3dc63c7bee78d6",
48
- "20bc5f2dedbf6423a543ba25183fab3c7268cdd2762e080f6d0b3387c4b3cad8",
49
- "654faf29e2a177dba2409db4942007630674b86d3ff87d2b11d428e8b4d0db7f",
50
- "c27979d019266887a1b86225d3c85b2d4553e85814ab2d791547ffc3f9dc664a",
51
- "74f982351453468e39aff8373cb2649d57344b8002b85fc9c0df118d051817fc",
52
- "891e59d7896f29a9af2bd1a9aec98ae2ebcc57d9685027e3f07067734e603923",
53
- "4a8a234bbad11dc98aa27871ed69d351385f9476af0c15b8b426cfa5630cc3db",
54
- "e42c967f02a434a061152d86d68fa0a3da70235f6f8262a792abeeace14fc419",
55
- "c1560c78197abd62252f8932abf73d5f7506fcd157e98390230aec81fdf5e5ac",
56
- "afa2cc8fe8b9b8785921f2e649d90d239f729223b2ce7460c0f22d79427c7b5e",
57
- "d574f129616c989797b3a4a7988e9d4ca3afb59ed1de67136d459307b9a1807a",
58
- "94b1c1e2fab8c51bb76d9d7bc07d23f8b509919009feb141f12562cab696d49a",
59
- "79bf74936c7274d1ee529fb888f30fbf2a33a15308bedb8c77c1c50793790b42",
60
- "2ee8962250f82c51fdbbf170c6c7fa9b69dca336434714ba607c6f816034cb08",
61
- "6e8e665df73c6934d5b432f5aa898ba33cc9a40d630b049404a23fa5d2776298",
62
- "3561d1bd9ae8c916eace5bdd1eb788cd743ad461cff58acf58ed5b2064b30b7b",
63
- "46a48aa8aef9f09dabb9cf340dacc1889cf3eeebc49c6d2f26ff017cd087857c",
64
- "561e0536b3cf214a4bf41b2bfb2209c8d659990a871e44bef9bc0136613a4ab9",
65
- "7c1f3e331c8f59cc6dab7e310d9ad151628f72e5ca3db5a6ff592c8c976c1974",
66
- "fb9d9d484edfa2c0a531a3e08074f52b6988f1082606f1eecaf0c58f117dbf3d",
67
- "2810e928a4ce6e2ae016751a7e8b73496de47fe1926abe6ff486bc0eed23e3d7",
68
- "723c3ede92f08e9ac12b7dc0b9e6a857ab0426d3418524f4eb50ad69f0228ccd",
69
- "66a07cdf0c9d56558ad4f853203071b56adfa990a4fb065b49c10108f4996fe7",
70
- "dc826253950962dbc2e5699dc5c138490c4233a23b39a5cf471a931cbbc689b8",
71
- "ec29a6c60c70a25a5a238ba1d03407dadafee78c01bc9f921549da428c4fbc03",
72
- "0564c17382a344aa22b5452989d2950f514bbd366e7b8289a458a4604c987641",
73
- "157ca17a0c1fc9faed3c2557cdf83323210a40020e72497e8e48e1d0055e54c7",
74
- "e643beaf8a92e574da88b9efa424852d34261be06496ca78d08acd84c38861b7",
75
- "df982789a1598f53bbcf44f1b2991c86bfd7713b36b04a06cf52640cfc9c579d",
76
- "e135e4dd1aebe24484909d56fb47619eb975f9790ef4541fdc87f63a3478ecf4",
77
- "823235bafe4f9e523cc4ffeb16789a2e2d6b246ab5c248335eba364d54474241",
78
- "a314bda9257484bbbabc1159b957d3aae1de0bca777bcd1462fdc52abf5a62fe",
79
- "65f6699712af969820645bbe271f66fe92f5da41fd834e329dadeae7801bc112",
80
- "17e812f25ef6d73de97b3464ca3fd2109433d9b5bc567e4e74feda35bf660492",
81
- "37ff30e4c4384b810bd86e4472e9ada4b447cd6057daf8df3f923fac3b8b3d77",
82
- "c55f13e79ce2bb698606f787551591e050e33e576cb845a2f40b03edac56f819",
83
- "2124d3353d3f105c3780c937f1eaf377f756e59c6ab6a97ef780a718f3a47c7b",
84
- "e581535019c839a7c383d0eca3de97a6a5701025d4a24ea56f01932f910cb99c",
85
- "eb089f8a27da4b94b79e5d125ed6205849b1909d0a6c1d0f51c351be2d5b8466",
86
- "36ee22c148c0282e112950f8e9939fed4b95d2f8a52c9cd2fd3744070df54333",
87
- "c81b6509d23e889c5b5ec79fdfaf64fed1bf00ced8f4b224aa37b5a37821ccfe",
88
- "b529c4de4a2fff86266d9b0318f15246ed30f4641b4156778ff9f3fca3099e32",
89
- "647c2aa42b094baf52537a8f7ffb015b7aa212c67ca779853d263d420760d8b6",
90
- "8043ea259b8bbb2bf488643376c2a2b9a3864e5617ea9ac5dc72966e289c07c2",
91
- "bba0397ebaf1a6093a8adb117e84198bb5d2dcf9e8e7792221af9215cda8c10b",
92
- "978ec66df04567ef8e4f02aa67b903535859f7bf24a5b63298cae1c938a72ab7",
93
- "124befb26711b599a311b0b0d7352b6e980a594cd56c8447e32c1aba26818fd1",
94
- "990ddff1fd05882796d2081ebc0d966a39c04af7120a9440562d71db2f48d65d",
95
- "f396be48a42c9cca6b6fec0a8ee7f5d15f93a57fba3baf04ab5a7d86af68bea5",
96
- "4f2487f0af254ea067e853bb6874d80d05c46f6322ca6e3a8815b37931533aea",
97
- "dbacdcc317d0cc436dd93c8be4d1471c712bcc567bda8e9a47dc0c1543d33e19",
98
- "6658cb8824afdf853e9cf3e667ac9d6bf566d54cc0f3b81ad62f7d7eeadff530",
99
- "b2c4ea7f091911a1c3733e42a52c75d3ee1666ceb62faa4e8ddb15c8a4b12b14",
100
- "0f29f04bebfe26d9b0ef7b802e3b2c725e85cdc03407915a3d5753436977f24e",
101
- "7eadf05c33f72431c7414e60e4068051143154d647452e3888de4c61316950ea",
102
- "45237d7cbb04c768d25f2dd13708f448f3c50af5262015d468ccbdb51fe0c090",
103
- "21f14816d480bc5c2e5f0a3387a0897d928e926a4341df3d32d65416b6e387f1",
104
- "a39bd710b9489e8bef21362c8df87ed76008939e89dbf8e6708a2c574f0727e0",
105
- "cf365a79503e1457c23cd1ea8c9fa8c398d168288f90b5c1920af798508c2b56",
106
- "d123f90b3a932edf596fd561e74fc8cc0adc481c3be118a7fa6a5834cd7b787c",
107
- "cde02309ad295648d86fa4acefdf7224809abb2ab9b025f14ae41e021512c5ed",
108
- "39835a1337c2afd9a9690cb9946752899a110df312d9d3aa68e10f85fad49dea",
109
- ]);
110
- // Check if first run or version upgrade
111
- export function isFirstRunOrUpgrade(currentVersion) {
112
- const config = getConfig();
113
- return config.lastVersion !== currentVersion;
114
- }
115
- export function markVersionSeen(version) {
116
- saveConfig({ lastVersion: version });
117
- }
118
- // Free commands that don't require token
119
- const FREE_COMMANDS = new Set(['ref', 'help', 'exit', 'quit', 'q', 'clear', 'cls', 'activate']);
120
- function hashToken(token) {
121
- return createHash('sha256').update(token.trim().toUpperCase()).digest('hex');
122
- }
123
- export function validateToken(token) {
124
- return TOKEN_HASHES.has(hashToken(token));
125
- }
126
- export function isActivated() {
127
- const config = getConfig();
128
- return !!(config.accessToken && TOKEN_HASHES.has(hashToken(config.accessToken)));
129
- }
130
- export function getDeviceFingerprint() {
131
- const parts = [hostname(), platform(), arch()];
132
- // Add hardware UUID where possible
133
- try {
134
- if (platform() === 'darwin') {
135
- const out = execSync('ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID', { encoding: 'utf-8' });
136
- const match = out.match(/"([A-F0-9-]+)"/);
137
- if (match)
138
- parts.push(match[1]);
139
- }
140
- else if (platform() === 'linux') {
141
- if (existsSync('/etc/machine-id')) {
142
- parts.push(readFileSync('/etc/machine-id', 'utf-8').trim());
143
- }
144
- }
145
- else if (platform() === 'win32') {
146
- const out = execSync('powershell -Command "(Get-CimInstance Win32_ComputerSystemProduct).UUID"', { encoding: 'utf-8' });
147
- parts.push(out.trim());
148
- }
149
- }
150
- catch {
151
- // Fallback: use first non-internal MAC address
152
- const nets = networkInterfaces();
153
- for (const ifaces of Object.values(nets)) {
154
- if (!ifaces)
155
- continue;
156
- for (const iface of ifaces) {
157
- if (!iface.internal && iface.mac !== '00:00:00:00:00:00') {
158
- parts.push(iface.mac);
159
- break;
160
- }
161
- }
162
- if (parts.length > 3)
163
- break;
164
- }
165
- }
166
- return createHash('sha256').update(parts.join('|')).digest('hex');
167
- }
168
- export function activateToken(token) {
169
- if (!validateToken(token))
170
- return 'invalid';
171
- const fingerprint = getDeviceFingerprint();
172
- const bindingFile = join(getIcoaDir(), 'token-bindings.json');
173
- // Load existing bindings
174
- let bindings = {};
175
- if (existsSync(bindingFile)) {
176
- try {
177
- bindings = JSON.parse(readFileSync(bindingFile, 'utf-8'));
178
- }
179
- catch { /* ignore */ }
180
- }
181
- const tokenHash = hashToken(token);
182
- const existingDevice = bindings[tokenHash];
183
- if (existingDevice && existingDevice !== fingerprint) {
184
- // Token already bound to a different device
185
- return 'already_bound';
186
- }
187
- // Bind token to this device
188
- bindings[tokenHash] = fingerprint;
189
- writeFileSync(bindingFile, JSON.stringify(bindings, null, 2));
190
- saveConfig({ accessToken: token.trim().toUpperCase(), deviceFingerprint: fingerprint });
191
- return 'ok';
192
- }
193
- export function isDeviceMatch() {
194
- const config = getConfig();
195
- if (!config.deviceFingerprint)
196
- return true; // Legacy: no fingerprint yet
197
- return config.deviceFingerprint === getDeviceFingerprint();
198
- }
199
- export function isFreeCommand(cmd) {
200
- return FREE_COMMANDS.has(cmd.toLowerCase());
201
- }
202
- // Session tracking for anti-cheat
203
- const SESSION_FILE = () => join(getIcoaDir(), 'session-state.json');
204
- function getDefaultSession() {
205
- return {
206
- startedAt: new Date().toISOString(),
207
- lastExitAt: null,
208
- lastResumeAt: null,
209
- exitCount: 0,
210
- totalAwaySeconds: 0,
211
- };
212
- }
213
- export function getSession() {
214
- const file = SESSION_FILE();
215
- if (!existsSync(file))
216
- return getDefaultSession();
217
- try {
218
- return { ...getDefaultSession(), ...JSON.parse(readFileSync(file, 'utf-8')) };
219
- }
220
- catch {
221
- return getDefaultSession();
222
- }
223
- }
224
- export function saveSession(session) {
225
- const current = getSession();
226
- const merged = { ...current, ...session };
227
- writeFileSync(SESSION_FILE(), JSON.stringify(merged, null, 2));
228
- }
229
- export function recordExit() {
230
- const session = getSession();
231
- session.lastExitAt = new Date().toISOString();
232
- session.exitCount++;
233
- saveSession(session);
234
- }
235
- export function recordResume() {
236
- const session = getSession();
237
- if (!session.lastExitAt)
238
- return null;
239
- const exitTime = new Date(session.lastExitAt).getTime();
240
- const now = Date.now();
241
- const awaySeconds = Math.round((now - exitTime) / 1000);
242
- session.lastResumeAt = new Date().toISOString();
243
- session.totalAwaySeconds += awaySeconds;
244
- saveSession(session);
245
- return { awaySeconds, exitCount: session.exitCount };
246
- }
1
+ import{createHash as e}from"node:crypto";import{execSync as c}from"node:child_process";import{hostname as a,platform as f,arch as d,networkInterfaces as b}from"node:os";import{getConfig as t,saveConfig as n,getIcoaDir as o}from"./config.js";import{readFileSync as r,writeFileSync as i,existsSync as s}from"node:fs";import{join as u}from"node:path";const p=new Set(["93490bf664679467b4ab5af12e240175364b7af988b72cb7d000e309b7c68c15","cba7a6f075a4bd8c2fc973336cc0b1966669fc481381a065ce670730bbe0b7d3","f6773f614341acb8d2c35e8f466f2876095a2c8026a207e77de621050fa64559","d060ab36056fdac449a561fd3340c4b79ad4cde10c9a21c3397aa74574583a2b","523c11774e103298c15eb9d138872295194078f2d29486d0a6bd210436a592c3","1e16864067470f0a97088f067d8df4b655753ff498a91353b5f9b75989b6be39","f1031aac52879c776d4db5ba43eb25bb40f1a841b91304f8adf65a838fb8c666","bcd9e25014633ec6556345ab43d0cd213c454bb10d4ea0bd5be5ba02e1a6622c","9239ba9c3db74eadbb6dd05949c2a3cbe1b22e14e375ab3ca93d050e2e2ce38b","80fc0a899ed4d37138ae3172dafd466de2d3b1ce9630d67e6b00bec9315964d7","33ed35ce028824519d3a013ca326d6a58b1ca3723ec182527a7367e1ffc2712b","7e90933e760ce5e8df48bdb6bab0e95962bdc1098fceedecf617c0dac37b2a11","33fa6e3639a691b217ed0f927a8e2e2aef5eaa15eab7bd90c57874c2df2a28ac","67013663fb4536a47f6ea46b434fb7a00574bd4fc4f579e9439ba07f748db31b","10c83ad26fc965fcb1d228018f6b54d331e4a2e6087603920b75b500e191c5e4","3079268d847dc7eb196ce8cdc0af8a8506b9636539a1b7cce53dc5cb3f4cbe15","985eb5309c546d2f9d5018976973d6da06a374b897c73c830fc9d1305e78efa0","3a7326d4a7f40cc356b17769f4c5fc0d832d926aff9f067efd60f34c053bf9ef","129f408a98ad6c1b13924cf2c831c752b0c726bf1975d6b46f212a178ced52e1","ec44bc0b4eb6a929b969caaa561492527c369cc07efa50e40c2c6c16162f0c2c","07610942d9da62dd5b91c0ba48602bc44973a9d374ed10ab6c708151677ec626","8ce3165bb8e23f3b67ac53b39191aca3e2f0a620b7f932fe6a43e2c42315efcc","69938b605e652afc1cf8bc7c0dcf6a99820878367dfb3b2ec954ba90b36014f5","660377ce87d378285ab7263fdad86208c8563367d2cc36b4c1402520e45dd5f0","bef8a3727dffc94861a1dfa7d6a336ceac30aab9f0679dcab662cb9f682079dd","02318a3597b64a2c7de56b01fc25f33cc4142c76315136186df680f490681294","b7179114b42b90e9557399ae505050111b6afc55f9295d3ee84d5db6873470c5","e227ec0a6b22773500b35bee46f21bc6bc6a00fb001d54e71479f15b8fdfd72b","1c9802ae1e932d55e73994ce173a996d170e4d274aeccb1b784c9d9b69913f3d","5ed51694773bd1b46a085d10e9a369786a997c50b72ec2bdb6e68921ffca5c51","478e457279a41e9b76a3dc5894418e38246d2af31e0f4776dda8aa89c74c88c8","a7ec7e047c0e62862e9be64b0a65d3d7894d41efe6eb16ca6cfca45d8007f16f","88cf2b75604486ac5f1a0db9afbab28e8e866f9ea00f3e4b4353a7ecc81f6b55","dc4daa9ef4149f122979ffd5a8b23bca3cbb83b24a87ba99a1d00dc09e39936e","cffd9a3637b5ae30c27cae4ae42dc21374caa27dd818b5d361f112406bf3c0e7","33b3e85a964f606e857280ba379de46508f9343cbe1d2722abebbed21b82a106","a3754074df08f9c9407c73e680eac1868175cee3beac3f0e7d2bd211bdf51f58","f9eb5fd82f3360e22ad45d4797f3a95b907a766ef5a61d856bf959b60a4930dc","1c53d3145cb38501a2422bf70f55a0c206b68c14e46da31e0e3dc63c7bee78d6","20bc5f2dedbf6423a543ba25183fab3c7268cdd2762e080f6d0b3387c4b3cad8","654faf29e2a177dba2409db4942007630674b86d3ff87d2b11d428e8b4d0db7f","c27979d019266887a1b86225d3c85b2d4553e85814ab2d791547ffc3f9dc664a","74f982351453468e39aff8373cb2649d57344b8002b85fc9c0df118d051817fc","891e59d7896f29a9af2bd1a9aec98ae2ebcc57d9685027e3f07067734e603923","4a8a234bbad11dc98aa27871ed69d351385f9476af0c15b8b426cfa5630cc3db","e42c967f02a434a061152d86d68fa0a3da70235f6f8262a792abeeace14fc419","c1560c78197abd62252f8932abf73d5f7506fcd157e98390230aec81fdf5e5ac","afa2cc8fe8b9b8785921f2e649d90d239f729223b2ce7460c0f22d79427c7b5e","d574f129616c989797b3a4a7988e9d4ca3afb59ed1de67136d459307b9a1807a","94b1c1e2fab8c51bb76d9d7bc07d23f8b509919009feb141f12562cab696d49a","79bf74936c7274d1ee529fb888f30fbf2a33a15308bedb8c77c1c50793790b42","2ee8962250f82c51fdbbf170c6c7fa9b69dca336434714ba607c6f816034cb08","6e8e665df73c6934d5b432f5aa898ba33cc9a40d630b049404a23fa5d2776298","3561d1bd9ae8c916eace5bdd1eb788cd743ad461cff58acf58ed5b2064b30b7b","46a48aa8aef9f09dabb9cf340dacc1889cf3eeebc49c6d2f26ff017cd087857c","561e0536b3cf214a4bf41b2bfb2209c8d659990a871e44bef9bc0136613a4ab9","7c1f3e331c8f59cc6dab7e310d9ad151628f72e5ca3db5a6ff592c8c976c1974","fb9d9d484edfa2c0a531a3e08074f52b6988f1082606f1eecaf0c58f117dbf3d","2810e928a4ce6e2ae016751a7e8b73496de47fe1926abe6ff486bc0eed23e3d7","723c3ede92f08e9ac12b7dc0b9e6a857ab0426d3418524f4eb50ad69f0228ccd","66a07cdf0c9d56558ad4f853203071b56adfa990a4fb065b49c10108f4996fe7","dc826253950962dbc2e5699dc5c138490c4233a23b39a5cf471a931cbbc689b8","ec29a6c60c70a25a5a238ba1d03407dadafee78c01bc9f921549da428c4fbc03","0564c17382a344aa22b5452989d2950f514bbd366e7b8289a458a4604c987641","157ca17a0c1fc9faed3c2557cdf83323210a40020e72497e8e48e1d0055e54c7","e643beaf8a92e574da88b9efa424852d34261be06496ca78d08acd84c38861b7","df982789a1598f53bbcf44f1b2991c86bfd7713b36b04a06cf52640cfc9c579d","e135e4dd1aebe24484909d56fb47619eb975f9790ef4541fdc87f63a3478ecf4","823235bafe4f9e523cc4ffeb16789a2e2d6b246ab5c248335eba364d54474241","a314bda9257484bbbabc1159b957d3aae1de0bca777bcd1462fdc52abf5a62fe","65f6699712af969820645bbe271f66fe92f5da41fd834e329dadeae7801bc112","17e812f25ef6d73de97b3464ca3fd2109433d9b5bc567e4e74feda35bf660492","37ff30e4c4384b810bd86e4472e9ada4b447cd6057daf8df3f923fac3b8b3d77","c55f13e79ce2bb698606f787551591e050e33e576cb845a2f40b03edac56f819","2124d3353d3f105c3780c937f1eaf377f756e59c6ab6a97ef780a718f3a47c7b","e581535019c839a7c383d0eca3de97a6a5701025d4a24ea56f01932f910cb99c","eb089f8a27da4b94b79e5d125ed6205849b1909d0a6c1d0f51c351be2d5b8466","36ee22c148c0282e112950f8e9939fed4b95d2f8a52c9cd2fd3744070df54333","c81b6509d23e889c5b5ec79fdfaf64fed1bf00ced8f4b224aa37b5a37821ccfe","b529c4de4a2fff86266d9b0318f15246ed30f4641b4156778ff9f3fca3099e32","647c2aa42b094baf52537a8f7ffb015b7aa212c67ca779853d263d420760d8b6","8043ea259b8bbb2bf488643376c2a2b9a3864e5617ea9ac5dc72966e289c07c2","bba0397ebaf1a6093a8adb117e84198bb5d2dcf9e8e7792221af9215cda8c10b","978ec66df04567ef8e4f02aa67b903535859f7bf24a5b63298cae1c938a72ab7","124befb26711b599a311b0b0d7352b6e980a594cd56c8447e32c1aba26818fd1","990ddff1fd05882796d2081ebc0d966a39c04af7120a9440562d71db2f48d65d","f396be48a42c9cca6b6fec0a8ee7f5d15f93a57fba3baf04ab5a7d86af68bea5","4f2487f0af254ea067e853bb6874d80d05c46f6322ca6e3a8815b37931533aea","dbacdcc317d0cc436dd93c8be4d1471c712bcc567bda8e9a47dc0c1543d33e19","6658cb8824afdf853e9cf3e667ac9d6bf566d54cc0f3b81ad62f7d7eeadff530","b2c4ea7f091911a1c3733e42a52c75d3ee1666ceb62faa4e8ddb15c8a4b12b14","0f29f04bebfe26d9b0ef7b802e3b2c725e85cdc03407915a3d5753436977f24e","7eadf05c33f72431c7414e60e4068051143154d647452e3888de4c61316950ea","45237d7cbb04c768d25f2dd13708f448f3c50af5262015d468ccbdb51fe0c090","21f14816d480bc5c2e5f0a3387a0897d928e926a4341df3d32d65416b6e387f1","a39bd710b9489e8bef21362c8df87ed76008939e89dbf8e6708a2c574f0727e0","cf365a79503e1457c23cd1ea8c9fa8c398d168288f90b5c1920af798508c2b56","d123f90b3a932edf596fd561e74fc8cc0adc481c3be118a7fa6a5834cd7b787c","cde02309ad295648d86fa4acefdf7224809abb2ab9b025f14ae41e021512c5ed","39835a1337c2afd9a9690cb9946752899a110df312d9d3aa68e10f85fad49dea"]);export function isFirstRunOrUpgrade(e){return t().lastVersion!==e}export function markVersionSeen(e){n({lastVersion:e})}const l=new Set(["ref","help","exit","quit","q","clear","cls","activate"]);function m(c){return e("sha256").update(c.trim().toUpperCase()).digest("hex")}export function validateToken(e){return p.has(m(e))}export function isActivated(){const e=t();return!(!e.accessToken||!p.has(m(e.accessToken)))}export function getDeviceFingerprint(){const t=[a(),f(),d()];try{if("darwin"===f()){const e=c("ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID",{encoding:"utf-8"}).match(/"([A-F0-9-]+)"/);e&&t.push(e[1])}else if("linux"===f())s("/etc/machine-id")&&t.push(r("/etc/machine-id","utf-8").trim());else if("win32"===f()){const e=c('powershell -Command "(Get-CimInstance Win32_ComputerSystemProduct).UUID"',{encoding:"utf-8"});t.push(e.trim())}}catch{const e=b();for(const c of Object.values(e))if(c){for(const e of c)if(!e.internal&&"00:00:00:00:00:00"!==e.mac){t.push(e.mac);break}if(t.length>3)break}}return e("sha256").update(t.join("|")).digest("hex")}export function activateToken(e){if(!validateToken(e))return"invalid";const c=getDeviceFingerprint(),a=u(o(),"token-bindings.json");let f={};if(s(a))try{f=JSON.parse(r(a,"utf-8"))}catch{}const d=m(e),b=f[d];return b&&b!==c?"already_bound":(f[d]=c,i(a,JSON.stringify(f,null,2)),n({accessToken:e.trim().toUpperCase(),deviceFingerprint:c}),"ok")}export function isDeviceMatch(){const e=t();return!e.deviceFingerprint||e.deviceFingerprint===getDeviceFingerprint()}export function isFreeCommand(e){return l.has(e.toLowerCase())}const g=()=>u(o(),"session-state.json");function x(){return{startedAt:(new Date).toISOString(),lastExitAt:null,lastResumeAt:null,exitCount:0,totalAwaySeconds:0}}export function getSession(){const e=g();if(!s(e))return x();try{return{...x(),...JSON.parse(r(e,"utf-8"))}}catch{return x()}}export function saveSession(e){const c={...getSession(),...e};i(g(),JSON.stringify(c,null,2))}export function recordExit(){const e=getSession();e.lastExitAt=(new Date).toISOString(),e.exitCount++,saveSession(e)}export function recordResume(){const e=getSession();if(!e.lastExitAt)return null;const c=new Date(e.lastExitAt).getTime(),a=Date.now(),f=Math.round((a-c)/1e3);return e.lastResumeAt=(new Date).toISOString(),e.totalAwaySeconds+=f,saveSession(e),{awaySeconds:f,exitCount:e.exitCount}}
@@ -1,42 +1 @@
1
- import { getBudget, saveBudget } from './config.js';
2
- export function checkBudget(level) {
3
- const budget = getBudget();
4
- const key = level.toLowerCase();
5
- return {
6
- allowed: budget[key] > 0,
7
- remaining: budget[key],
8
- };
9
- }
10
- export function deductBudget(level, tokensUsed) {
11
- const budget = getBudget();
12
- const key = level.toLowerCase();
13
- budget[key] = Math.max(0, budget[key] - 1);
14
- budget.tokensUsed += tokensUsed;
15
- saveBudget(budget);
16
- }
17
- export function getBudgetDisplay() {
18
- const budget = getBudget();
19
- return [
20
- ` Level A (General Guidance): ${budget.a}/50`,
21
- ` Level B (Deep Analysis): ${budget.b}/10`,
22
- ` Level C (Critical Assist): ${budget.c}/2`,
23
- ` Token Usage: ${budget.tokensUsed.toLocaleString()}/${budget.tokenCap.toLocaleString()}`,
24
- ].join('\n');
25
- }
26
- export function isTokenCapReached() {
27
- const budget = getBudget();
28
- return budget.tokensUsed >= budget.tokenCap;
29
- }
30
- export function addTokenUsage(tokensUsed) {
31
- const budget = getBudget();
32
- budget.tokensUsed += tokensUsed;
33
- saveBudget(budget);
34
- }
35
- export function getTokenUsage() {
36
- const budget = getBudget();
37
- return {
38
- used: budget.tokensUsed,
39
- cap: budget.tokenCap,
40
- remaining: Math.max(0, budget.tokenCap - budget.tokensUsed),
41
- };
42
- }
1
+ import{getBudget as e,saveBudget as t}from"./config.js";export function checkBudget(t){const n=e(),o=t.toLowerCase();return{allowed:n[o]>0,remaining:n[o]}}export function deductBudget(n,o){const s=e(),a=n.toLowerCase();s[a]=Math.max(0,s[a]-1),s.tokensUsed+=o,t(s)}export function getBudgetDisplay(){const t=e();return[` Level A (General Guidance): ${t.a}/50`,` Level B (Deep Analysis): ${t.b}/10`,` Level C (Critical Assist): ${t.c}/2`,` Token Usage: ${t.tokensUsed.toLocaleString()}/${t.tokenCap.toLocaleString()}`].join("\n")}export function isTokenCapReached(){const t=e();return t.tokensUsed>=t.tokenCap}export function addTokenUsage(n){const o=e();o.tokensUsed+=n,t(o)}export function getTokenUsage(){const t=e();return{used:t.tokensUsed,cap:t.tokenCap,remaining:Math.max(0,t.tokenCap-t.tokensUsed)}}
@@ -1,21 +1 @@
1
- // Darcula palette from ICOA Terminal xterm.js theme spec.
2
- // Use c.* helpers when you need brand-accurate truecolor (e.g. the orange
3
- // accent #CC7832). For generic success/error/warning, chalk.green/.red/.yellow
4
- // remain fine — they render as the terminal's Darcula 16-color when using an
5
- // ICOA theme and as close-enough defaults elsewhere.
6
- const tc = (r, g, b) => (s) => `\x1b[38;2;${r};${g};${b}m${s}\x1b[39m`;
7
- export const c = {
8
- fg: tc(169, 183, 198), // #A9B7C6 body text
9
- muted: tc(85, 85, 85), // #555555 comments / secondary
10
- red: tc(255, 107, 104), // #FF6B68 error
11
- green: tc(168, 192, 35), // #A8C023 success
12
- yellow: tc(214, 191, 85), // #D6BF55 warning
13
- blue: tc(126, 174, 241), // #7EAEF1 link
14
- cyan: tc(40, 123, 222), // #287BDE command / path
15
- orange: tc(204, 120, 50), // #CC7832 brand accent
16
- white: tc(255, 255, 255), // #FFFFFF highlight
17
- };
18
- export const DARCULA_BG_HEX = '#2B2B2B';
19
- export const DARCULA_FG_HEX = '#A9B7C6';
20
- export const DARCULA_BG_RGB = [43, 43, 43];
21
- export const DARCULA_FG_RGB = [169, 183, 198];
1
+ const e=(e,o,t)=>n=>`[38;2;${e};${o};${t}m${n}`;export const c={fg:e(169,183,198),muted:e(85,85,85),red:e(255,107,104),green:e(168,192,35),yellow:e(214,191,85),blue:e(126,174,241),cyan:e(40,123,222),orange:e(204,120,50),white:e(255,255,255)};export const DARCULA_BG_HEX="#2B2B2B";export const DARCULA_FG_HEX="#A9B7C6";export const DARCULA_BG_RGB=[43,43,43];export const DARCULA_FG_RGB=[169,183,198];
@@ -1,60 +1 @@
1
- import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { homedir } from 'node:os';
4
- import { randomUUID } from 'node:crypto';
5
- import { DEFAULT_CONFIG, DEFAULT_BUDGET } from '../types/index.js';
6
- const ICOA_DIR = join(homedir(), '.icoa');
7
- const CONFIG_FILE = join(ICOA_DIR, 'config.json');
8
- const BUDGET_FILE = join(ICOA_DIR, 'budget.json');
9
- function ensureDir() {
10
- if (!existsSync(ICOA_DIR)) {
11
- mkdirSync(ICOA_DIR, { recursive: true });
12
- }
13
- }
14
- export function getConfig() {
15
- ensureDir();
16
- if (!existsSync(CONFIG_FILE)) {
17
- const config = { ...DEFAULT_CONFIG, sessionId: randomUUID() };
18
- writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
19
- return config;
20
- }
21
- try {
22
- const raw = readFileSync(CONFIG_FILE, 'utf-8');
23
- return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
24
- }
25
- catch {
26
- return { ...DEFAULT_CONFIG, sessionId: randomUUID() };
27
- }
28
- }
29
- export function saveConfig(config) {
30
- ensureDir();
31
- const current = getConfig();
32
- const merged = { ...current, ...config };
33
- writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
34
- }
35
- export function getBudget() {
36
- ensureDir();
37
- if (!existsSync(BUDGET_FILE)) {
38
- writeFileSync(BUDGET_FILE, JSON.stringify(DEFAULT_BUDGET, null, 2));
39
- return { ...DEFAULT_BUDGET };
40
- }
41
- try {
42
- const raw = readFileSync(BUDGET_FILE, 'utf-8');
43
- return { ...DEFAULT_BUDGET, ...JSON.parse(raw) };
44
- }
45
- catch {
46
- return { ...DEFAULT_BUDGET };
47
- }
48
- }
49
- export function saveBudget(budget) {
50
- ensureDir();
51
- writeFileSync(BUDGET_FILE, JSON.stringify(budget, null, 2));
52
- }
53
- export function getIcoaDir() {
54
- ensureDir();
55
- return ICOA_DIR;
56
- }
57
- export function isConnected() {
58
- const config = getConfig();
59
- return !!(config.ctfdUrl && config.token);
60
- }
1
+ import{mkdirSync as t,readFileSync as n,writeFileSync as o,existsSync as r}from"node:fs";import{join as e}from"node:path";import{homedir as i}from"node:os";import{randomUUID as s}from"node:crypto";import{DEFAULT_CONFIG as f,DEFAULT_BUDGET as u}from"../types/index.js";const c=e(i(),".icoa"),g=e(c,"config.json"),p=e(c,"budget.json");function d(){r(c)||t(c,{recursive:!0})}export function getConfig(){if(d(),!r(g)){const t={...f,sessionId:s()};return o(g,JSON.stringify(t,null,2)),t}try{const t=n(g,"utf-8");return{...f,...JSON.parse(t)}}catch{return{...f,sessionId:s()}}}export function saveConfig(t){d();const n={...getConfig(),...t};o(g,JSON.stringify(n,null,2))}export function getBudget(){if(d(),!r(p))return o(p,JSON.stringify(u,null,2)),{...u};try{const t=n(p,"utf-8");return{...u,...JSON.parse(t)}}catch{return{...u}}}export function saveBudget(t){d(),o(p,JSON.stringify(t,null,2))}export function getIcoaDir(){return d(),c}export function isConnected(){const t=getConfig();return!(!t.ctfdUrl||!t.token)}