@kruzic/cli 0.1.0
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/index.js +487 -0
- package/package.json +34 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/login.ts
|
|
7
|
+
import prompts from "prompts";
|
|
8
|
+
|
|
9
|
+
// src/lib/config.ts
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from "fs";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
var CONFIG_DIR = join(homedir(), ".kruzic");
|
|
14
|
+
var CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
|
|
15
|
+
function ensureConfigDir() {
|
|
16
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
17
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getApiKey() {
|
|
21
|
+
const envKey = process.env.KRUZIC_API_KEY;
|
|
22
|
+
if (envKey) return envKey;
|
|
23
|
+
if (!existsSync(CREDENTIALS_FILE)) return null;
|
|
24
|
+
try {
|
|
25
|
+
const data = JSON.parse(readFileSync(CREDENTIALS_FILE, "utf-8"));
|
|
26
|
+
return data.apiKey || null;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function saveApiKey(apiKey) {
|
|
32
|
+
ensureConfigDir();
|
|
33
|
+
const data = { apiKey };
|
|
34
|
+
writeFileSync(CREDENTIALS_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
35
|
+
chmodSync(CREDENTIALS_FILE, 384);
|
|
36
|
+
}
|
|
37
|
+
function removeCredentials() {
|
|
38
|
+
if (!existsSync(CREDENTIALS_FILE)) return false;
|
|
39
|
+
unlinkSync(CREDENTIALS_FILE);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/lib/api.ts
|
|
44
|
+
var BASE_URL = process.env.KRUZIC_API_URL || "https://www.kruzic.rs";
|
|
45
|
+
async function request(path, options) {
|
|
46
|
+
const headers = {
|
|
47
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
48
|
+
...options.headers
|
|
49
|
+
};
|
|
50
|
+
if (typeof options.body === "string") {
|
|
51
|
+
headers["Content-Type"] = "application/json";
|
|
52
|
+
}
|
|
53
|
+
const response = await fetch(`${BASE_URL}${path}`, {
|
|
54
|
+
method: options.method || "GET",
|
|
55
|
+
headers,
|
|
56
|
+
body: options.body
|
|
57
|
+
});
|
|
58
|
+
const data = await response.json();
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorData = data;
|
|
61
|
+
throw new Error(errorData.error || `Request failed with status ${response.status}`);
|
|
62
|
+
}
|
|
63
|
+
return data;
|
|
64
|
+
}
|
|
65
|
+
function whoami(apiKey) {
|
|
66
|
+
return request("/api/cli/whoami", { apiKey });
|
|
67
|
+
}
|
|
68
|
+
function latestVersion(apiKey) {
|
|
69
|
+
return request("/api/cli/latest-version", { apiKey });
|
|
70
|
+
}
|
|
71
|
+
function deploy(apiKey, formData) {
|
|
72
|
+
return request("/api/cli/deploy", {
|
|
73
|
+
apiKey,
|
|
74
|
+
method: "POST",
|
|
75
|
+
body: formData
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/lib/ui.ts
|
|
80
|
+
import pc from "picocolors";
|
|
81
|
+
import { default as default2 } from "ora";
|
|
82
|
+
function success(message) {
|
|
83
|
+
console.log(pc.green(` ${message}`));
|
|
84
|
+
}
|
|
85
|
+
function error(message) {
|
|
86
|
+
console.error(pc.red(` ${message}`));
|
|
87
|
+
}
|
|
88
|
+
function info(message) {
|
|
89
|
+
console.log(pc.cyan(` ${message}`));
|
|
90
|
+
}
|
|
91
|
+
function warn(message) {
|
|
92
|
+
console.log(pc.yellow(` ${message}`));
|
|
93
|
+
}
|
|
94
|
+
function label(key, value) {
|
|
95
|
+
console.log(` ${pc.dim(key)} ${value}`);
|
|
96
|
+
}
|
|
97
|
+
function header(text) {
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(pc.bold(` ${text}`));
|
|
100
|
+
console.log();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/commands/login.ts
|
|
104
|
+
async function loginCommand() {
|
|
105
|
+
const existing = getApiKey();
|
|
106
|
+
if (existing) {
|
|
107
|
+
info("Ve\u0107 ste prijavljeni. Pokrenite `kruzic logout` da promenite nalog.");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const response = await prompts({
|
|
111
|
+
type: "password",
|
|
112
|
+
name: "apiKey",
|
|
113
|
+
message: "Unesite va\u0161 API klju\u010D",
|
|
114
|
+
validate: (value) => value.startsWith("kruzic_") ? true : "API klju\u010D mora po\u010Dinjati sa kruzic_"
|
|
115
|
+
});
|
|
116
|
+
if (!response.apiKey) {
|
|
117
|
+
error("Prijava otkazana.");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const spinner = default2("Provera API klju\u010Da...").start();
|
|
121
|
+
try {
|
|
122
|
+
const data = await whoami(response.apiKey);
|
|
123
|
+
spinner.stop();
|
|
124
|
+
saveApiKey(response.apiKey);
|
|
125
|
+
header("Uspe\u0161no ste se prijavili!");
|
|
126
|
+
label("Programer:", data.developerName);
|
|
127
|
+
label("Igra:", `${data.gameTitle} (${data.gameId})`);
|
|
128
|
+
console.log();
|
|
129
|
+
info("Kredencijali sa\u010Duvani u ~/.kruzic/credentials.json");
|
|
130
|
+
} catch (err) {
|
|
131
|
+
spinner.stop();
|
|
132
|
+
error(err instanceof Error ? err.message : "Provera API klju\u010Da nije uspela");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/commands/logout.ts
|
|
137
|
+
async function logoutCommand() {
|
|
138
|
+
const removed = removeCredentials();
|
|
139
|
+
if (removed) {
|
|
140
|
+
success("Odjavljeni ste. Kredencijali su uklonjeni.");
|
|
141
|
+
} else {
|
|
142
|
+
info("Niste prijavljeni.");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/commands/whoami.ts
|
|
147
|
+
async function whoamiCommand() {
|
|
148
|
+
const apiKey = getApiKey();
|
|
149
|
+
if (!apiKey) {
|
|
150
|
+
error("Niste prijavljeni. Pokrenite `kruzic login`.");
|
|
151
|
+
process.exitCode = 1;
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const spinner = default2("U\u010Ditavanje podataka o nalogu...").start();
|
|
155
|
+
try {
|
|
156
|
+
const data = await whoami(apiKey);
|
|
157
|
+
spinner.stop();
|
|
158
|
+
header("Podaci o nalogu");
|
|
159
|
+
label("Programer:", data.developerName);
|
|
160
|
+
label("ID programera:", data.developerId);
|
|
161
|
+
label("Igra:", data.gameTitle);
|
|
162
|
+
label("ID igre:", data.gameId);
|
|
163
|
+
console.log();
|
|
164
|
+
} catch (err) {
|
|
165
|
+
spinner.stop();
|
|
166
|
+
error(err instanceof Error ? err.message : "U\u010Ditavanje podataka nije uspelo");
|
|
167
|
+
process.exitCode = 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// src/commands/link.ts
|
|
172
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
173
|
+
import { resolve } from "path";
|
|
174
|
+
import prompts2 from "prompts";
|
|
175
|
+
|
|
176
|
+
// src/lib/project.ts
|
|
177
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
178
|
+
import { join as join2 } from "path";
|
|
179
|
+
var PROJECT_FILE = ".kruzic.json";
|
|
180
|
+
function getProjectPath() {
|
|
181
|
+
return join2(process.cwd(), PROJECT_FILE);
|
|
182
|
+
}
|
|
183
|
+
function getProjectConfig() {
|
|
184
|
+
const path = getProjectPath();
|
|
185
|
+
if (!existsSync2(path)) return null;
|
|
186
|
+
try {
|
|
187
|
+
return JSON.parse(readFileSync2(path, "utf-8"));
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function saveProjectConfig(config) {
|
|
193
|
+
writeFileSync2(getProjectPath(), JSON.stringify(config, null, 2) + "\n");
|
|
194
|
+
}
|
|
195
|
+
function removeProjectConfig() {
|
|
196
|
+
const path = getProjectPath();
|
|
197
|
+
if (!existsSync2(path)) return false;
|
|
198
|
+
unlinkSync2(path);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/commands/link.ts
|
|
203
|
+
async function linkCommand() {
|
|
204
|
+
const existing = getProjectConfig();
|
|
205
|
+
if (existing) {
|
|
206
|
+
info(`Ve\u0107 povezano sa igrom "${existing.gameId}" (izvor: ${existing.sourceDir})`);
|
|
207
|
+
info("Pokrenite `kruzic unlink` da ponovo pove\u017Eete.");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const apiKey = getApiKey();
|
|
211
|
+
if (!apiKey) {
|
|
212
|
+
error("Niste prijavljeni. Pokrenite `kruzic login`.");
|
|
213
|
+
process.exitCode = 1;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const spinner = default2("U\u010Ditavanje podataka o igri...").start();
|
|
217
|
+
let gameId;
|
|
218
|
+
let gameTitle;
|
|
219
|
+
try {
|
|
220
|
+
const data = await whoami(apiKey);
|
|
221
|
+
gameId = data.gameId;
|
|
222
|
+
gameTitle = data.gameTitle;
|
|
223
|
+
spinner.stop();
|
|
224
|
+
} catch (err) {
|
|
225
|
+
spinner.stop();
|
|
226
|
+
error(err instanceof Error ? err.message : "U\u010Ditavanje podataka o igri nije uspelo");
|
|
227
|
+
process.exitCode = 1;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
header(`Povezivanje sa: ${gameTitle} (${gameId})`);
|
|
231
|
+
const response = await prompts2({
|
|
232
|
+
type: "text",
|
|
233
|
+
name: "sourceDir",
|
|
234
|
+
message: "Direktorijum sa fajlovima igre",
|
|
235
|
+
initial: ".",
|
|
236
|
+
validate: (value) => {
|
|
237
|
+
const dir2 = resolve(value);
|
|
238
|
+
if (!existsSync3(dir2)) return `Direktorijum nije prona\u0111en: ${dir2}`;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
if (!response.sourceDir) {
|
|
243
|
+
error("Povezivanje otkazano.");
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const dir = resolve(response.sourceDir);
|
|
247
|
+
const hasHtml = hasHtmlFiles(dir);
|
|
248
|
+
if (!hasHtml) {
|
|
249
|
+
warn("HTML fajlovi nisu prona\u0111eni u izvornom direktorijumu.");
|
|
250
|
+
const confirm = await prompts2({
|
|
251
|
+
type: "confirm",
|
|
252
|
+
name: "proceed",
|
|
253
|
+
message: "Nastavite svejedno?",
|
|
254
|
+
initial: false
|
|
255
|
+
});
|
|
256
|
+
if (!confirm.proceed) return;
|
|
257
|
+
}
|
|
258
|
+
saveProjectConfig({ gameId, sourceDir: response.sourceDir });
|
|
259
|
+
success("Projekat je povezan!");
|
|
260
|
+
label("Konfiguracija:", ".kruzic.json");
|
|
261
|
+
console.log();
|
|
262
|
+
const gitignorePath = resolve(".gitignore");
|
|
263
|
+
if (existsSync3(gitignorePath)) {
|
|
264
|
+
const gitignore = readFileSync3(gitignorePath, "utf-8");
|
|
265
|
+
if (!gitignore.includes(".kruzic.json")) {
|
|
266
|
+
warn("Preporu\u010Dujemo da dodate .kruzic.json u va\u0161 .gitignore");
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
warn("Preporu\u010Dujemo da dodate .kruzic.json u va\u0161 .gitignore");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function hasHtmlFiles(dir) {
|
|
273
|
+
try {
|
|
274
|
+
const files = readdirSync(dir, { recursive: true });
|
|
275
|
+
return files.some(
|
|
276
|
+
(f) => typeof f === "string" && (f.endsWith(".html") || f.endsWith(".htm"))
|
|
277
|
+
);
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/commands/unlink.ts
|
|
284
|
+
async function unlinkCommand() {
|
|
285
|
+
const removed = removeProjectConfig();
|
|
286
|
+
if (removed) {
|
|
287
|
+
success("Projekat je odvojen. Fajl .kruzic.json je uklonjen.");
|
|
288
|
+
} else {
|
|
289
|
+
info("Konfiguracija projekta nije prona\u0111ena.");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/commands/deploy.ts
|
|
294
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync } from "fs";
|
|
295
|
+
import { resolve as resolve2 } from "path";
|
|
296
|
+
import prompts3 from "prompts";
|
|
297
|
+
|
|
298
|
+
// src/lib/version.ts
|
|
299
|
+
function bumpPatch(version) {
|
|
300
|
+
const parts = version.split(".");
|
|
301
|
+
if (parts.length !== 3) return version;
|
|
302
|
+
const [major, minor, patch] = parts;
|
|
303
|
+
const next = parseInt(patch, 10) + 1;
|
|
304
|
+
return `${major}.${minor}.${next}`;
|
|
305
|
+
}
|
|
306
|
+
function isValidVersion(version) {
|
|
307
|
+
return /^\d+\.\d+\.\d+$/.test(version);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/lib/zip.ts
|
|
311
|
+
import archiver from "archiver";
|
|
312
|
+
import { createWriteStream, unlinkSync as unlinkSync3 } from "fs";
|
|
313
|
+
import { tmpdir } from "os";
|
|
314
|
+
import { join as join3 } from "path";
|
|
315
|
+
import { randomBytes } from "crypto";
|
|
316
|
+
async function createZip(sourceDir) {
|
|
317
|
+
const tempPath = join3(tmpdir(), `kruzic-deploy-${randomBytes(8).toString("hex")}.zip`);
|
|
318
|
+
return new Promise((resolve3, reject) => {
|
|
319
|
+
const output = createWriteStream(tempPath);
|
|
320
|
+
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
321
|
+
output.on("close", () => {
|
|
322
|
+
resolve3({ path: tempPath, size: archive.pointer() });
|
|
323
|
+
});
|
|
324
|
+
archive.on("error", (err) => {
|
|
325
|
+
reject(err);
|
|
326
|
+
});
|
|
327
|
+
archive.pipe(output);
|
|
328
|
+
archive.directory(sourceDir, false);
|
|
329
|
+
archive.finalize();
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
function cleanupZip(path) {
|
|
333
|
+
try {
|
|
334
|
+
unlinkSync3(path);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/commands/deploy.ts
|
|
340
|
+
async function deployCommand(options) {
|
|
341
|
+
const apiKey = getApiKey();
|
|
342
|
+
if (!apiKey) {
|
|
343
|
+
error("Niste prijavljeni. Pokrenite `kruzic login`.");
|
|
344
|
+
process.exitCode = 1;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const config = getProjectConfig();
|
|
348
|
+
if (!config) {
|
|
349
|
+
error("Projekat nije povezan. Pokrenite `kruzic link`.");
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const sourceDir = resolve2(config.sourceDir);
|
|
354
|
+
if (!existsSync4(sourceDir)) {
|
|
355
|
+
error(`Izvorni direktorijum nije prona\u0111en: ${sourceDir}`);
|
|
356
|
+
process.exitCode = 1;
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (!statSync(sourceDir).isDirectory()) {
|
|
360
|
+
error(`Nije direktorijum: ${sourceDir}`);
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const spinner = default2("U\u010Ditavanje poslednje verzije...").start();
|
|
365
|
+
let currentVersion;
|
|
366
|
+
try {
|
|
367
|
+
const data = await latestVersion(apiKey);
|
|
368
|
+
currentVersion = data.version;
|
|
369
|
+
spinner.stop();
|
|
370
|
+
} catch (err) {
|
|
371
|
+
spinner.stop();
|
|
372
|
+
error(err instanceof Error ? err.message : "U\u010Ditavanje poslednje verzije nije uspelo");
|
|
373
|
+
process.exitCode = 1;
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (currentVersion) {
|
|
377
|
+
info(`Trenutna verzija: ${currentVersion}`);
|
|
378
|
+
} else {
|
|
379
|
+
info("Nema postoje\u0107ih izdanja. Ovo \u0107e biti prva objava.");
|
|
380
|
+
}
|
|
381
|
+
let version = options.version;
|
|
382
|
+
if (!version) {
|
|
383
|
+
const defaultVersion = currentVersion ? bumpPatch(currentVersion) : "0.1.0";
|
|
384
|
+
if (options.yes) {
|
|
385
|
+
version = defaultVersion;
|
|
386
|
+
} else {
|
|
387
|
+
const response = await prompts3({
|
|
388
|
+
type: "text",
|
|
389
|
+
name: "version",
|
|
390
|
+
message: "Verzija",
|
|
391
|
+
initial: defaultVersion,
|
|
392
|
+
validate: (v) => isValidVersion(v) ? true : "Koristite X.Y.Z format"
|
|
393
|
+
});
|
|
394
|
+
if (!response.version) {
|
|
395
|
+
error("Objava otkazana.");
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
version = response.version;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!version || !isValidVersion(version)) {
|
|
402
|
+
error("Neispravan format verzije. Koristite X.Y.Z (npr. 1.0.0)");
|
|
403
|
+
process.exitCode = 1;
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const finalVersion = version;
|
|
407
|
+
let changelog = options.changelog;
|
|
408
|
+
if (!changelog && !options.yes) {
|
|
409
|
+
const response = await prompts3({
|
|
410
|
+
type: "text",
|
|
411
|
+
name: "changelog",
|
|
412
|
+
message: "Opis izmena (opciono)"
|
|
413
|
+
});
|
|
414
|
+
changelog = response.changelog || void 0;
|
|
415
|
+
}
|
|
416
|
+
if (!options.yes) {
|
|
417
|
+
console.log();
|
|
418
|
+
label("Igra:", config.gameId);
|
|
419
|
+
label("Izvor:", sourceDir);
|
|
420
|
+
label("Verzija:", finalVersion);
|
|
421
|
+
if (changelog) label("Izmene:", changelog);
|
|
422
|
+
console.log();
|
|
423
|
+
const confirm = await prompts3({
|
|
424
|
+
type: "confirm",
|
|
425
|
+
name: "proceed",
|
|
426
|
+
message: "Objavite ovu verziju?",
|
|
427
|
+
initial: true
|
|
428
|
+
});
|
|
429
|
+
if (!confirm.proceed) {
|
|
430
|
+
error("Objava otkazana.");
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const zipSpinner = default2("Kreiranje ZIP arhive...").start();
|
|
435
|
+
let zipPath;
|
|
436
|
+
let zipSize;
|
|
437
|
+
try {
|
|
438
|
+
const result = await createZip(sourceDir);
|
|
439
|
+
zipPath = result.path;
|
|
440
|
+
zipSize = result.size;
|
|
441
|
+
zipSpinner.succeed(`Arhiva kreirana (${formatSize(zipSize)})`);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
zipSpinner.fail("Kreiranje arhive nije uspelo");
|
|
444
|
+
error(err instanceof Error ? err.message : String(err));
|
|
445
|
+
process.exitCode = 1;
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const uploadSpinner = default2("Otpremanje...").start();
|
|
449
|
+
try {
|
|
450
|
+
const zipBuffer = readFileSync4(zipPath);
|
|
451
|
+
const blob = new Blob([zipBuffer]);
|
|
452
|
+
const formData = new FormData();
|
|
453
|
+
formData.append("file", blob, "release.zip");
|
|
454
|
+
formData.append("version", finalVersion);
|
|
455
|
+
if (changelog) formData.append("changelog", changelog);
|
|
456
|
+
const result = await deploy(apiKey, formData);
|
|
457
|
+
uploadSpinner.stop();
|
|
458
|
+
cleanupZip(zipPath);
|
|
459
|
+
header("Uspe\u0161no objavljeno!");
|
|
460
|
+
label("Verzija:", result.version);
|
|
461
|
+
label("ID izdanja:", result.releaseId);
|
|
462
|
+
label("Kanal:", "testing");
|
|
463
|
+
label("Test URL:", `https://www.kruzic.rs/game/${result.gameId}?track=testing`);
|
|
464
|
+
console.log();
|
|
465
|
+
} catch (err) {
|
|
466
|
+
uploadSpinner.stop();
|
|
467
|
+
cleanupZip(zipPath);
|
|
468
|
+
error(err instanceof Error ? err.message : "Otpremanje nije uspelo");
|
|
469
|
+
process.exitCode = 1;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function formatSize(bytes) {
|
|
473
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
474
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
475
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/index.ts
|
|
479
|
+
var program = new Command();
|
|
480
|
+
program.name("kruzic").description("Kruzic CLI \u2014 objavite igre iz terminala").version("0.1.0");
|
|
481
|
+
program.command("login").description("Prijavite se pomo\u0107u API klju\u010Da").action(loginCommand);
|
|
482
|
+
program.command("logout").description("Uklonite sa\u010Duvane kredencijale").action(logoutCommand);
|
|
483
|
+
program.command("whoami").description("Prika\u017Eite informacije o programeru i igri").action(whoamiCommand);
|
|
484
|
+
program.command("link").description("Pove\u017Eite direktorijum sa igrom").action(linkCommand);
|
|
485
|
+
program.command("unlink").description("Uklonite konfiguraciju projekta (.kruzic.json)").action(unlinkCommand);
|
|
486
|
+
program.command("deploy").description("Objavite novu verziju").option("-v, --version <version>", "Verzija izdanja (X.Y.Z)").option("-c, --changelog <text>", "Opis izmena").option("-y, --yes", "Presko\u010Dite potvrde (za CI)").action(deployCommand);
|
|
487
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kruzic/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Kruzic CLI — objavite igre iz terminala",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kruzic": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "tsx src/index.ts",
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"check-types": "tsc --noEmit",
|
|
17
|
+
"prepublishOnly": "pnpm build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"commander": "^13.0.0",
|
|
21
|
+
"picocolors": "^1.1.0",
|
|
22
|
+
"ora": "^8.1.0",
|
|
23
|
+
"prompts": "^2.4.2",
|
|
24
|
+
"archiver": "^7.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.10.0",
|
|
28
|
+
"@types/prompts": "^2.4.9",
|
|
29
|
+
"@types/archiver": "^6.0.0",
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"tsx": "^4.19.0",
|
|
32
|
+
"typescript": "^5.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|