@jvittechs/jai1-cli 0.1.99 → 0.1.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.
- package/dist/cli.js +1055 -406
- package/dist/cli.js.map +1 -1
- package/dist/web-chat/app.js +490 -5
- package/dist/web-chat/style.css +227 -0
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command61 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/errors/index.ts
|
|
7
7
|
var Jai1Error = class extends Error {
|
|
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
|
|
|
33
33
|
// package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@jvittechs/jai1-cli",
|
|
36
|
-
version: "0.1.
|
|
36
|
+
version: "0.1.101",
|
|
37
37
|
description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
|
|
38
38
|
type: "module",
|
|
39
39
|
bin: {
|
|
@@ -88,6 +88,7 @@ var package_default = {
|
|
|
88
88
|
cronstrue: "^2.50.0",
|
|
89
89
|
execa: "^9.6.1",
|
|
90
90
|
"gray-matter": "^4.0.3",
|
|
91
|
+
ignore: "^7.0.5",
|
|
91
92
|
ink: "^5.0.1",
|
|
92
93
|
"ink-spinner": "^5.0.0",
|
|
93
94
|
"ink-text-input": "^6.0.0",
|
|
@@ -1322,9 +1323,9 @@ var UnifiedApplyApp = ({
|
|
|
1322
1323
|
(c) => c.filepath.toLowerCase().includes(query) || c.tags?.some((t) => t.toLowerCase().includes(query))
|
|
1323
1324
|
);
|
|
1324
1325
|
}, [components, searchQuery]);
|
|
1325
|
-
useInput((
|
|
1326
|
+
useInput((input5, key) => {
|
|
1326
1327
|
if (viewState === "done") {
|
|
1327
|
-
if (key.return ||
|
|
1328
|
+
if (key.return || input5 === "q" || key.escape) {
|
|
1328
1329
|
onExit();
|
|
1329
1330
|
}
|
|
1330
1331
|
return;
|
|
@@ -1332,7 +1333,7 @@ var UnifiedApplyApp = ({
|
|
|
1332
1333
|
if (viewState === "summary") {
|
|
1333
1334
|
if (key.return) {
|
|
1334
1335
|
setViewState("ide-sync");
|
|
1335
|
-
} else if (
|
|
1336
|
+
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1336
1337
|
onExit();
|
|
1337
1338
|
}
|
|
1338
1339
|
return;
|
|
@@ -1342,7 +1343,7 @@ var UnifiedApplyApp = ({
|
|
|
1342
1343
|
setIdeCursorIndex((prev) => Math.max(0, prev - 1));
|
|
1343
1344
|
} else if (key.downArrow) {
|
|
1344
1345
|
setIdeCursorIndex((prev) => Math.min(availableIdes.length - 1, prev + 1));
|
|
1345
|
-
} else if (
|
|
1346
|
+
} else if (input5 === " ") {
|
|
1346
1347
|
const ide = availableIdes[ideCursorIndex];
|
|
1347
1348
|
if (ide) {
|
|
1348
1349
|
setSelectedIdes((prev) => {
|
|
@@ -1355,15 +1356,15 @@ var UnifiedApplyApp = ({
|
|
|
1355
1356
|
return next;
|
|
1356
1357
|
});
|
|
1357
1358
|
}
|
|
1358
|
-
} else if (
|
|
1359
|
+
} else if (input5 === "a") {
|
|
1359
1360
|
setSelectedIdes(new Set(availableIdes));
|
|
1360
|
-
} else if (
|
|
1361
|
+
} else if (input5 === "c") {
|
|
1361
1362
|
setSelectedIdes(/* @__PURE__ */ new Set());
|
|
1362
1363
|
} else if (key.return) {
|
|
1363
1364
|
if (selectedIdes.size > 0) {
|
|
1364
1365
|
handleIdeSync();
|
|
1365
1366
|
}
|
|
1366
|
-
} else if (
|
|
1367
|
+
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1367
1368
|
onExit();
|
|
1368
1369
|
}
|
|
1369
1370
|
return;
|
|
@@ -1380,7 +1381,7 @@ var UnifiedApplyApp = ({
|
|
|
1380
1381
|
else setFocusArea("packages");
|
|
1381
1382
|
return;
|
|
1382
1383
|
}
|
|
1383
|
-
if (key.escape ||
|
|
1384
|
+
if (key.escape || input5 === "q") {
|
|
1384
1385
|
onExit();
|
|
1385
1386
|
return;
|
|
1386
1387
|
}
|
|
@@ -1391,14 +1392,14 @@ var UnifiedApplyApp = ({
|
|
|
1391
1392
|
return;
|
|
1392
1393
|
}
|
|
1393
1394
|
if (focusArea !== "search") {
|
|
1394
|
-
if (
|
|
1395
|
+
if (input5 === "a") {
|
|
1395
1396
|
setSelectedPaths((prev) => {
|
|
1396
1397
|
const next = new Set(prev);
|
|
1397
1398
|
filteredComponents.forEach((c) => next.add(c.filepath));
|
|
1398
1399
|
return next;
|
|
1399
1400
|
});
|
|
1400
1401
|
return;
|
|
1401
|
-
} else if (
|
|
1402
|
+
} else if (input5 === "c") {
|
|
1402
1403
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1403
1404
|
return;
|
|
1404
1405
|
}
|
|
@@ -1408,7 +1409,7 @@ var UnifiedApplyApp = ({
|
|
|
1408
1409
|
setCursorIndex((prev) => Math.max(0, prev - 1));
|
|
1409
1410
|
} else if (key.downArrow) {
|
|
1410
1411
|
setCursorIndex((prev) => Math.min(filteredComponents.length - 1, prev + 1));
|
|
1411
|
-
} else if (
|
|
1412
|
+
} else if (input5 === " ") {
|
|
1412
1413
|
const current = filteredComponents[cursorIndex];
|
|
1413
1414
|
if (current) {
|
|
1414
1415
|
setSelectedPaths((prev) => {
|
|
@@ -1428,7 +1429,7 @@ var UnifiedApplyApp = ({
|
|
|
1428
1429
|
setSelectedPackageIndex((prev) => Math.max(0, prev - 1));
|
|
1429
1430
|
} else if (key.rightArrow) {
|
|
1430
1431
|
setSelectedPackageIndex((prev) => Math.min(tags.length - 1, prev + 1));
|
|
1431
|
-
} else if (
|
|
1432
|
+
} else if (input5 === " " || key.return) {
|
|
1432
1433
|
const tag = tags[selectedPackageIndex];
|
|
1433
1434
|
if (tag) {
|
|
1434
1435
|
const packageComponents = components.filter((c) => c.tags?.includes(tag.tag));
|
|
@@ -1860,7 +1861,7 @@ var MainMenuView = ({ ideContexts, onSelect }) => {
|
|
|
1860
1861
|
available: ideContexts.some((ctx) => ctx.ide === "jai1")
|
|
1861
1862
|
}
|
|
1862
1863
|
];
|
|
1863
|
-
useInput2((
|
|
1864
|
+
useInput2((input5, key) => {
|
|
1864
1865
|
if (key.upArrow) {
|
|
1865
1866
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
1866
1867
|
} else if (key.downArrow) {
|
|
@@ -1962,13 +1963,13 @@ var IDEOverviewView = ({
|
|
|
1962
1963
|
count: ideContext.stats.byType.context
|
|
1963
1964
|
});
|
|
1964
1965
|
}
|
|
1965
|
-
useInput3((
|
|
1966
|
+
useInput3((input5, key) => {
|
|
1966
1967
|
if (key.tab || key.rightArrow) {
|
|
1967
1968
|
setSelectedTabIndex((prev) => Math.min(tabs.length - 1, prev + 1));
|
|
1968
1969
|
} else if (key.leftArrow) {
|
|
1969
1970
|
setSelectedTabIndex((prev) => Math.max(0, prev - 1));
|
|
1970
1971
|
}
|
|
1971
|
-
const num = parseInt(
|
|
1972
|
+
const num = parseInt(input5, 10);
|
|
1972
1973
|
if (!isNaN(num) && num >= 1 && num <= tabs.length) {
|
|
1973
1974
|
setSelectedTabIndex(num - 1);
|
|
1974
1975
|
}
|
|
@@ -2030,7 +2031,7 @@ import React7, { useState as useState4 } from "react";
|
|
|
2030
2031
|
import { Box as Box5, Text as Text6, useInput as useInput4 } from "ink";
|
|
2031
2032
|
var ListView = ({ items, contentType, onSelect, onBack }) => {
|
|
2032
2033
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
2033
|
-
useInput4((
|
|
2034
|
+
useInput4((input5, key) => {
|
|
2034
2035
|
if (key.upArrow) {
|
|
2035
2036
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
2036
2037
|
} else if (key.downArrow) {
|
|
@@ -2081,18 +2082,18 @@ var DetailView = ({ item, scrollPosition: initialScroll, onBack }) => {
|
|
|
2081
2082
|
const [scrollPosition, setScrollPosition] = useState5(initialScroll);
|
|
2082
2083
|
const maxVisibleLines = 25;
|
|
2083
2084
|
const maxScroll = Math.max(0, item.previewLines.length - maxVisibleLines);
|
|
2084
|
-
useInput5((
|
|
2085
|
-
if (key.upArrow ||
|
|
2085
|
+
useInput5((input5, key) => {
|
|
2086
|
+
if (key.upArrow || input5 === "k") {
|
|
2086
2087
|
setScrollPosition((prev) => Math.max(0, prev - 1));
|
|
2087
|
-
} else if (key.downArrow ||
|
|
2088
|
+
} else if (key.downArrow || input5 === "j") {
|
|
2088
2089
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 1));
|
|
2089
|
-
} else if (key.pageDown ||
|
|
2090
|
+
} else if (key.pageDown || input5 === "d") {
|
|
2090
2091
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 5));
|
|
2091
|
-
} else if (key.pageUp ||
|
|
2092
|
+
} else if (key.pageUp || input5 === "u") {
|
|
2092
2093
|
setScrollPosition((prev) => Math.max(0, prev - 5));
|
|
2093
|
-
} else if (
|
|
2094
|
+
} else if (input5 === "g") {
|
|
2094
2095
|
setScrollPosition(0);
|
|
2095
|
-
} else if (
|
|
2096
|
+
} else if (input5 === "G") {
|
|
2096
2097
|
setScrollPosition(maxScroll);
|
|
2097
2098
|
} else if (key.escape || key.backspace) {
|
|
2098
2099
|
onBack();
|
|
@@ -2496,8 +2497,8 @@ var ContextApp = ({ initialIDE, initialType, onExit }) => {
|
|
|
2496
2497
|
setLoading(false);
|
|
2497
2498
|
});
|
|
2498
2499
|
}, [initialIDE]);
|
|
2499
|
-
useInput6((
|
|
2500
|
-
if (
|
|
2500
|
+
useInput6((input5, key) => {
|
|
2501
|
+
if (input5 === "q") {
|
|
2501
2502
|
onExit();
|
|
2502
2503
|
return;
|
|
2503
2504
|
}
|
|
@@ -3389,9 +3390,9 @@ var IdeDetectionService = class {
|
|
|
3389
3390
|
/**
|
|
3390
3391
|
* Check if a path exists
|
|
3391
3392
|
*/
|
|
3392
|
-
async pathExists(
|
|
3393
|
+
async pathExists(path10) {
|
|
3393
3394
|
try {
|
|
3394
|
-
await fs7.access(
|
|
3395
|
+
await fs7.access(path10);
|
|
3395
3396
|
return true;
|
|
3396
3397
|
} catch {
|
|
3397
3398
|
return false;
|
|
@@ -3616,7 +3617,7 @@ var MENU_ITEMS = [
|
|
|
3616
3617
|
];
|
|
3617
3618
|
var MenuView = ({ onSelect }) => {
|
|
3618
3619
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
3619
|
-
useInput7((
|
|
3620
|
+
useInput7((input5, key) => {
|
|
3620
3621
|
if (key.upArrow) {
|
|
3621
3622
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
3622
3623
|
} else if (key.downArrow) {
|
|
@@ -4229,7 +4230,7 @@ var AgenticGuideView = ({ onBack }) => {
|
|
|
4229
4230
|
const [isTyping, setIsTyping] = useState8(false);
|
|
4230
4231
|
const [selectedSuggestion, setSelectedSuggestion] = useState8(0);
|
|
4231
4232
|
const [focusArea, setFocusArea] = useState8("input");
|
|
4232
|
-
useInput8((
|
|
4233
|
+
useInput8((input5, key) => {
|
|
4233
4234
|
if (key.escape) {
|
|
4234
4235
|
onBack();
|
|
4235
4236
|
return;
|
|
@@ -4361,7 +4362,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
4361
4362
|
setCurrentTopic(TOPIC_MAP[initialTopic]);
|
|
4362
4363
|
}
|
|
4363
4364
|
}, [initialTopic]);
|
|
4364
|
-
useInput9((
|
|
4365
|
+
useInput9((input5, key) => {
|
|
4365
4366
|
if (key.escape || currentTopic !== "menu" && key.backspace) {
|
|
4366
4367
|
if (currentTopic === "menu") {
|
|
4367
4368
|
onExit();
|
|
@@ -4371,7 +4372,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
4371
4372
|
}
|
|
4372
4373
|
return;
|
|
4373
4374
|
}
|
|
4374
|
-
if (
|
|
4375
|
+
if (input5 === "q") {
|
|
4375
4376
|
onExit();
|
|
4376
4377
|
return;
|
|
4377
4378
|
}
|
|
@@ -4890,7 +4891,7 @@ var ModelSelector = ({
|
|
|
4890
4891
|
const allowedModels = models.filter((m) => m.allowed);
|
|
4891
4892
|
const currentIndex = allowedModels.findIndex((m) => m.id === currentModel);
|
|
4892
4893
|
const [selectedIndex, setSelectedIndex] = useState12(Math.max(0, currentIndex));
|
|
4893
|
-
useInput10((
|
|
4894
|
+
useInput10((input5, key) => {
|
|
4894
4895
|
if (key.escape) {
|
|
4895
4896
|
onCancel();
|
|
4896
4897
|
return;
|
|
@@ -5016,7 +5017,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
5016
5017
|
}
|
|
5017
5018
|
return false;
|
|
5018
5019
|
}, [refetch, exit]);
|
|
5019
|
-
useInput11((
|
|
5020
|
+
useInput11((input5, key) => {
|
|
5020
5021
|
if (showSlashMenu) {
|
|
5021
5022
|
if (key.upArrow) {
|
|
5022
5023
|
setSlashMenuIndex((i) => Math.max(0, i - 1));
|
|
@@ -5044,7 +5045,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
5044
5045
|
}
|
|
5045
5046
|
return;
|
|
5046
5047
|
}
|
|
5047
|
-
if (currentView === "error" && (key.return ||
|
|
5048
|
+
if (currentView === "error" && (key.return || input5 === "r")) {
|
|
5048
5049
|
setCurrentView("loading");
|
|
5049
5050
|
refetch();
|
|
5050
5051
|
return;
|
|
@@ -5113,8 +5114,8 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
5113
5114
|
|
|
5114
5115
|
// src/server/web-chat-server.ts
|
|
5115
5116
|
import http from "http";
|
|
5116
|
-
import
|
|
5117
|
-
import
|
|
5117
|
+
import fs9 from "fs";
|
|
5118
|
+
import path5 from "path";
|
|
5118
5119
|
import { fileURLToPath } from "url";
|
|
5119
5120
|
|
|
5120
5121
|
// src/server/session.ts
|
|
@@ -5246,9 +5247,363 @@ var SessionManager = class {
|
|
|
5246
5247
|
}
|
|
5247
5248
|
};
|
|
5248
5249
|
|
|
5250
|
+
// src/server/file-service.ts
|
|
5251
|
+
import fs8 from "fs";
|
|
5252
|
+
import path4 from "path";
|
|
5253
|
+
import ignore from "ignore";
|
|
5254
|
+
var ALWAYS_EXCLUDED = [
|
|
5255
|
+
"node_modules",
|
|
5256
|
+
"vendor",
|
|
5257
|
+
".git",
|
|
5258
|
+
".env",
|
|
5259
|
+
".env.*",
|
|
5260
|
+
".env.local",
|
|
5261
|
+
".env.*.local",
|
|
5262
|
+
"dist",
|
|
5263
|
+
"build",
|
|
5264
|
+
".next",
|
|
5265
|
+
".nuxt",
|
|
5266
|
+
".output",
|
|
5267
|
+
".cache",
|
|
5268
|
+
"*.lock",
|
|
5269
|
+
"package-lock.json",
|
|
5270
|
+
"pnpm-lock.yaml",
|
|
5271
|
+
"yarn.lock",
|
|
5272
|
+
"composer.lock",
|
|
5273
|
+
".DS_Store",
|
|
5274
|
+
"Thumbs.db",
|
|
5275
|
+
"*.log",
|
|
5276
|
+
"*.tmp",
|
|
5277
|
+
"*.temp",
|
|
5278
|
+
".idea",
|
|
5279
|
+
".vscode",
|
|
5280
|
+
"*.min.js",
|
|
5281
|
+
"*.min.css",
|
|
5282
|
+
"*.map",
|
|
5283
|
+
"coverage",
|
|
5284
|
+
".nyc_output",
|
|
5285
|
+
"__pycache__",
|
|
5286
|
+
"*.pyc",
|
|
5287
|
+
".pytest_cache",
|
|
5288
|
+
".mypy_cache"
|
|
5289
|
+
];
|
|
5290
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5291
|
+
// Web
|
|
5292
|
+
".html",
|
|
5293
|
+
".htm",
|
|
5294
|
+
".css",
|
|
5295
|
+
".scss",
|
|
5296
|
+
".sass",
|
|
5297
|
+
".less",
|
|
5298
|
+
".js",
|
|
5299
|
+
".jsx",
|
|
5300
|
+
".ts",
|
|
5301
|
+
".tsx",
|
|
5302
|
+
".mjs",
|
|
5303
|
+
".cjs",
|
|
5304
|
+
".vue",
|
|
5305
|
+
".svelte",
|
|
5306
|
+
".astro",
|
|
5307
|
+
// Data
|
|
5308
|
+
".json",
|
|
5309
|
+
".yaml",
|
|
5310
|
+
".yml",
|
|
5311
|
+
".toml",
|
|
5312
|
+
".xml",
|
|
5313
|
+
".csv",
|
|
5314
|
+
// Docs
|
|
5315
|
+
".md",
|
|
5316
|
+
".mdx",
|
|
5317
|
+
".txt",
|
|
5318
|
+
".rst",
|
|
5319
|
+
".adoc",
|
|
5320
|
+
// Config
|
|
5321
|
+
".env.example",
|
|
5322
|
+
".gitignore",
|
|
5323
|
+
".dockerignore",
|
|
5324
|
+
".npmrc",
|
|
5325
|
+
".nvmrc",
|
|
5326
|
+
".editorconfig",
|
|
5327
|
+
".prettierrc",
|
|
5328
|
+
".eslintrc",
|
|
5329
|
+
".babelrc",
|
|
5330
|
+
// Server
|
|
5331
|
+
".php",
|
|
5332
|
+
".py",
|
|
5333
|
+
".rb",
|
|
5334
|
+
".go",
|
|
5335
|
+
".java",
|
|
5336
|
+
".kt",
|
|
5337
|
+
".scala",
|
|
5338
|
+
".rs",
|
|
5339
|
+
".swift",
|
|
5340
|
+
".c",
|
|
5341
|
+
".cpp",
|
|
5342
|
+
".h",
|
|
5343
|
+
".hpp",
|
|
5344
|
+
".cs",
|
|
5345
|
+
// Shell
|
|
5346
|
+
".sh",
|
|
5347
|
+
".bash",
|
|
5348
|
+
".zsh",
|
|
5349
|
+
".fish",
|
|
5350
|
+
".ps1",
|
|
5351
|
+
".bat",
|
|
5352
|
+
".cmd",
|
|
5353
|
+
// Database
|
|
5354
|
+
".sql",
|
|
5355
|
+
".prisma",
|
|
5356
|
+
".graphql",
|
|
5357
|
+
".gql",
|
|
5358
|
+
// Other
|
|
5359
|
+
".dockerfile",
|
|
5360
|
+
".makefile",
|
|
5361
|
+
".rake",
|
|
5362
|
+
".gradle"
|
|
5363
|
+
]);
|
|
5364
|
+
var TEXT_FILES = /* @__PURE__ */ new Set([
|
|
5365
|
+
"Makefile",
|
|
5366
|
+
"Dockerfile",
|
|
5367
|
+
"Vagrantfile",
|
|
5368
|
+
"Gemfile",
|
|
5369
|
+
"Rakefile",
|
|
5370
|
+
"Procfile",
|
|
5371
|
+
"Brewfile",
|
|
5372
|
+
".gitignore",
|
|
5373
|
+
".dockerignore",
|
|
5374
|
+
".npmrc",
|
|
5375
|
+
".nvmrc",
|
|
5376
|
+
".env.example",
|
|
5377
|
+
"LICENSE",
|
|
5378
|
+
"README",
|
|
5379
|
+
"CHANGELOG",
|
|
5380
|
+
"CONTRIBUTING",
|
|
5381
|
+
"AUTHORS",
|
|
5382
|
+
"CODEOWNERS"
|
|
5383
|
+
]);
|
|
5384
|
+
function getLanguage(filePath) {
|
|
5385
|
+
const ext = path4.extname(filePath).toLowerCase();
|
|
5386
|
+
const langMap = {
|
|
5387
|
+
".ts": "typescript",
|
|
5388
|
+
".tsx": "typescript",
|
|
5389
|
+
".js": "javascript",
|
|
5390
|
+
".jsx": "javascript",
|
|
5391
|
+
".mjs": "javascript",
|
|
5392
|
+
".cjs": "javascript",
|
|
5393
|
+
".py": "python",
|
|
5394
|
+
".rb": "ruby",
|
|
5395
|
+
".php": "php",
|
|
5396
|
+
".java": "java",
|
|
5397
|
+
".kt": "kotlin",
|
|
5398
|
+
".go": "go",
|
|
5399
|
+
".rs": "rust",
|
|
5400
|
+
".swift": "swift",
|
|
5401
|
+
".c": "c",
|
|
5402
|
+
".h": "c",
|
|
5403
|
+
".cpp": "cpp",
|
|
5404
|
+
".hpp": "cpp",
|
|
5405
|
+
".cs": "csharp",
|
|
5406
|
+
".css": "css",
|
|
5407
|
+
".scss": "scss",
|
|
5408
|
+
".sass": "sass",
|
|
5409
|
+
".less": "less",
|
|
5410
|
+
".html": "html",
|
|
5411
|
+
".htm": "html",
|
|
5412
|
+
".vue": "vue",
|
|
5413
|
+
".svelte": "svelte",
|
|
5414
|
+
".json": "json",
|
|
5415
|
+
".yaml": "yaml",
|
|
5416
|
+
".yml": "yaml",
|
|
5417
|
+
".xml": "xml",
|
|
5418
|
+
".md": "markdown",
|
|
5419
|
+
".mdx": "markdown",
|
|
5420
|
+
".sql": "sql",
|
|
5421
|
+
".graphql": "graphql",
|
|
5422
|
+
".gql": "graphql",
|
|
5423
|
+
".sh": "bash",
|
|
5424
|
+
".bash": "bash",
|
|
5425
|
+
".zsh": "bash",
|
|
5426
|
+
".dockerfile": "dockerfile",
|
|
5427
|
+
".prisma": "prisma"
|
|
5428
|
+
};
|
|
5429
|
+
return langMap[ext] || "text";
|
|
5430
|
+
}
|
|
5431
|
+
function isTextFile(filePath) {
|
|
5432
|
+
const ext = path4.extname(filePath).toLowerCase();
|
|
5433
|
+
const name = path4.basename(filePath);
|
|
5434
|
+
if (TEXT_FILES.has(name)) return true;
|
|
5435
|
+
if (ext && TEXT_EXTENSIONS.has(ext)) return true;
|
|
5436
|
+
if (name.endsWith("rc") || name.endsWith("config")) return true;
|
|
5437
|
+
return false;
|
|
5438
|
+
}
|
|
5439
|
+
var FileService = class {
|
|
5440
|
+
workingDir;
|
|
5441
|
+
maxFileSize;
|
|
5442
|
+
maxFilesPerRequest;
|
|
5443
|
+
maxSearchResults;
|
|
5444
|
+
ignoreFilter;
|
|
5445
|
+
constructor(options) {
|
|
5446
|
+
this.workingDir = path4.resolve(options.workingDir);
|
|
5447
|
+
this.maxFileSize = options.maxFileSize ?? 1024 * 1024;
|
|
5448
|
+
this.maxFilesPerRequest = options.maxFilesPerRequest ?? 5;
|
|
5449
|
+
this.maxSearchResults = options.maxSearchResults ?? 20;
|
|
5450
|
+
this.ignoreFilter = ignore();
|
|
5451
|
+
this.loadIgnorePatterns();
|
|
5452
|
+
}
|
|
5453
|
+
/**
|
|
5454
|
+
* Load ignore patterns from .gitignore and add always-excluded patterns
|
|
5455
|
+
*/
|
|
5456
|
+
loadIgnorePatterns() {
|
|
5457
|
+
this.ignoreFilter.add(ALWAYS_EXCLUDED);
|
|
5458
|
+
const gitignorePath = path4.join(this.workingDir, ".gitignore");
|
|
5459
|
+
try {
|
|
5460
|
+
if (fs8.existsSync(gitignorePath)) {
|
|
5461
|
+
const content = fs8.readFileSync(gitignorePath, "utf-8");
|
|
5462
|
+
this.ignoreFilter.add(content);
|
|
5463
|
+
}
|
|
5464
|
+
} catch {
|
|
5465
|
+
}
|
|
5466
|
+
}
|
|
5467
|
+
/**
|
|
5468
|
+
* Check if a path should be ignored
|
|
5469
|
+
*/
|
|
5470
|
+
isIgnored(relativePath) {
|
|
5471
|
+
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
5472
|
+
return this.ignoreFilter.ignores(normalizedPath);
|
|
5473
|
+
}
|
|
5474
|
+
/**
|
|
5475
|
+
* Validate path is within working directory (prevent path traversal)
|
|
5476
|
+
*/
|
|
5477
|
+
validatePath(relativePath) {
|
|
5478
|
+
const cleanPath = relativePath.replace(/^\/+/, "");
|
|
5479
|
+
const absolutePath = path4.resolve(this.workingDir, cleanPath);
|
|
5480
|
+
if (!absolutePath.startsWith(this.workingDir + path4.sep) && absolutePath !== this.workingDir) {
|
|
5481
|
+
throw new Error("Path traversal detected");
|
|
5482
|
+
}
|
|
5483
|
+
return absolutePath;
|
|
5484
|
+
}
|
|
5485
|
+
/**
|
|
5486
|
+
* Get relative path from working directory
|
|
5487
|
+
*/
|
|
5488
|
+
getRelativePath(absolutePath) {
|
|
5489
|
+
return path4.relative(this.workingDir, absolutePath);
|
|
5490
|
+
}
|
|
5491
|
+
/**
|
|
5492
|
+
* Search files matching a query (for autocomplete)
|
|
5493
|
+
* Returns files where path contains the query string
|
|
5494
|
+
*/
|
|
5495
|
+
async searchFiles(query, limit) {
|
|
5496
|
+
const maxResults = Math.min(limit ?? this.maxSearchResults, 50);
|
|
5497
|
+
const results = [];
|
|
5498
|
+
const normalizedQuery = query.toLowerCase().replace(/\\/g, "/");
|
|
5499
|
+
const searchDir = async (dirPath, depth = 0) => {
|
|
5500
|
+
if (depth > 10 || results.length >= maxResults) return;
|
|
5501
|
+
try {
|
|
5502
|
+
const entries = await fs8.promises.readdir(dirPath, { withFileTypes: true });
|
|
5503
|
+
for (const entry of entries) {
|
|
5504
|
+
if (results.length >= maxResults) break;
|
|
5505
|
+
const entryPath = path4.join(dirPath, entry.name);
|
|
5506
|
+
const relativePath = this.getRelativePath(entryPath);
|
|
5507
|
+
if (this.isIgnored(relativePath)) continue;
|
|
5508
|
+
const normalizedRelPath = relativePath.toLowerCase().replace(/\\/g, "/");
|
|
5509
|
+
if (normalizedRelPath.includes(normalizedQuery)) {
|
|
5510
|
+
if (entry.isFile() && isTextFile(entry.name)) {
|
|
5511
|
+
try {
|
|
5512
|
+
const stat = await fs8.promises.stat(entryPath);
|
|
5513
|
+
results.push({
|
|
5514
|
+
path: relativePath,
|
|
5515
|
+
name: entry.name,
|
|
5516
|
+
size: stat.size,
|
|
5517
|
+
type: "file",
|
|
5518
|
+
extension: path4.extname(entry.name).slice(1) || void 0
|
|
5519
|
+
});
|
|
5520
|
+
} catch {
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5524
|
+
if (entry.isDirectory()) {
|
|
5525
|
+
await searchDir(entryPath, depth + 1);
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
} catch {
|
|
5529
|
+
}
|
|
5530
|
+
};
|
|
5531
|
+
await searchDir(this.workingDir);
|
|
5532
|
+
results.sort((a, b) => {
|
|
5533
|
+
if (a.path.length !== b.path.length) {
|
|
5534
|
+
return a.path.length - b.path.length;
|
|
5535
|
+
}
|
|
5536
|
+
return a.path.localeCompare(b.path);
|
|
5537
|
+
});
|
|
5538
|
+
return results;
|
|
5539
|
+
}
|
|
5540
|
+
/**
|
|
5541
|
+
* Read a single file
|
|
5542
|
+
*/
|
|
5543
|
+
async readFile(relativePath) {
|
|
5544
|
+
const absolutePath = this.validatePath(relativePath);
|
|
5545
|
+
const normalizedRelPath = this.getRelativePath(absolutePath);
|
|
5546
|
+
if (this.isIgnored(normalizedRelPath)) {
|
|
5547
|
+
throw new Error("File is excluded by ignore rules");
|
|
5548
|
+
}
|
|
5549
|
+
if (!isTextFile(absolutePath)) {
|
|
5550
|
+
throw new Error("Only text files can be read");
|
|
5551
|
+
}
|
|
5552
|
+
const stat = await fs8.promises.stat(absolutePath);
|
|
5553
|
+
if (!stat.isFile()) {
|
|
5554
|
+
throw new Error("Path is not a file");
|
|
5555
|
+
}
|
|
5556
|
+
if (stat.size > this.maxFileSize) {
|
|
5557
|
+
throw new Error(`File exceeds maximum size of ${Math.round(this.maxFileSize / 1024)}KB`);
|
|
5558
|
+
}
|
|
5559
|
+
const content = await fs8.promises.readFile(absolutePath, "utf-8");
|
|
5560
|
+
return {
|
|
5561
|
+
path: normalizedRelPath,
|
|
5562
|
+
content,
|
|
5563
|
+
size: stat.size,
|
|
5564
|
+
language: getLanguage(absolutePath)
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
/**
|
|
5568
|
+
* Read multiple files (batch)
|
|
5569
|
+
*/
|
|
5570
|
+
async readFiles(relativePaths) {
|
|
5571
|
+
const paths = relativePaths.slice(0, this.maxFilesPerRequest);
|
|
5572
|
+
const results = await Promise.all(
|
|
5573
|
+
paths.map(async (filePath) => {
|
|
5574
|
+
try {
|
|
5575
|
+
const content = await this.readFile(filePath);
|
|
5576
|
+
return content;
|
|
5577
|
+
} catch (error) {
|
|
5578
|
+
return {
|
|
5579
|
+
path: filePath,
|
|
5580
|
+
content: "",
|
|
5581
|
+
size: 0,
|
|
5582
|
+
language: "text",
|
|
5583
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5584
|
+
};
|
|
5585
|
+
}
|
|
5586
|
+
})
|
|
5587
|
+
);
|
|
5588
|
+
return results;
|
|
5589
|
+
}
|
|
5590
|
+
/**
|
|
5591
|
+
* Get working directory info
|
|
5592
|
+
*/
|
|
5593
|
+
getWorkingDir() {
|
|
5594
|
+
return this.workingDir;
|
|
5595
|
+
}
|
|
5596
|
+
/**
|
|
5597
|
+
* Get max files per request limit
|
|
5598
|
+
*/
|
|
5599
|
+
getMaxFilesLimit() {
|
|
5600
|
+
return this.maxFilesPerRequest;
|
|
5601
|
+
}
|
|
5602
|
+
};
|
|
5603
|
+
|
|
5249
5604
|
// src/server/web-chat-server.ts
|
|
5250
5605
|
var __filename = fileURLToPath(import.meta.url);
|
|
5251
|
-
var __dirname =
|
|
5606
|
+
var __dirname = path5.dirname(__filename);
|
|
5252
5607
|
var MIME_TYPES = {
|
|
5253
5608
|
".html": "text/html",
|
|
5254
5609
|
".css": "text/css",
|
|
@@ -5322,22 +5677,23 @@ function createWebChatServer(options) {
|
|
|
5322
5677
|
const sessionManager = new SessionManager();
|
|
5323
5678
|
let server = null;
|
|
5324
5679
|
let session = null;
|
|
5325
|
-
const
|
|
5680
|
+
const fileService = new FileService({ workingDir: process.cwd() });
|
|
5681
|
+
const staticDir = path5.join(__dirname, "web-chat");
|
|
5326
5682
|
async function serveStaticFile(res, filePath) {
|
|
5327
|
-
const fullPath =
|
|
5683
|
+
const fullPath = path5.join(staticDir, filePath);
|
|
5328
5684
|
if (!fullPath.startsWith(staticDir)) {
|
|
5329
5685
|
sendError(res, 403, "ERR-WC-006", "Forbidden");
|
|
5330
5686
|
return;
|
|
5331
5687
|
}
|
|
5332
5688
|
try {
|
|
5333
|
-
const stat = await
|
|
5689
|
+
const stat = await fs9.promises.stat(fullPath);
|
|
5334
5690
|
if (!stat.isFile()) {
|
|
5335
5691
|
sendError(res, 404, "ERR-WC-007", "Not found");
|
|
5336
5692
|
return;
|
|
5337
5693
|
}
|
|
5338
|
-
const ext =
|
|
5694
|
+
const ext = path5.extname(fullPath);
|
|
5339
5695
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
5340
|
-
const content = await
|
|
5696
|
+
const content = await fs9.promises.readFile(fullPath);
|
|
5341
5697
|
res.writeHead(200, { "Content-Type": contentType });
|
|
5342
5698
|
res.end(content);
|
|
5343
5699
|
} catch (error) {
|
|
@@ -5440,6 +5796,83 @@ function createWebChatServer(options) {
|
|
|
5440
5796
|
}
|
|
5441
5797
|
return;
|
|
5442
5798
|
}
|
|
5799
|
+
if (pathname === "/api/files/search" && req.method === "GET") {
|
|
5800
|
+
try {
|
|
5801
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
5802
|
+
const query = url.searchParams.get("q") || "";
|
|
5803
|
+
const limit = parseInt(url.searchParams.get("limit") || "10", 10);
|
|
5804
|
+
if (!query || query.length < 1) {
|
|
5805
|
+
sendJson(res, 200, { success: true, data: { files: [] } });
|
|
5806
|
+
return;
|
|
5807
|
+
}
|
|
5808
|
+
const files = await fileService.searchFiles(query, Math.min(limit, 20));
|
|
5809
|
+
sendJson(res, 200, {
|
|
5810
|
+
success: true,
|
|
5811
|
+
data: { files }
|
|
5812
|
+
});
|
|
5813
|
+
} catch (error) {
|
|
5814
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
5815
|
+
sendError(res, 500, "ERR-WC-011", `File search failed: ${errorMessage}`);
|
|
5816
|
+
}
|
|
5817
|
+
return;
|
|
5818
|
+
}
|
|
5819
|
+
if (pathname === "/api/files/read" && req.method === "GET") {
|
|
5820
|
+
try {
|
|
5821
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
5822
|
+
const filePath = url.searchParams.get("path");
|
|
5823
|
+
if (!filePath) {
|
|
5824
|
+
sendError(res, 400, "ERR-WC-012", "Missing file path");
|
|
5825
|
+
return;
|
|
5826
|
+
}
|
|
5827
|
+
const fileContent = await fileService.readFile(filePath);
|
|
5828
|
+
sendJson(res, 200, {
|
|
5829
|
+
success: true,
|
|
5830
|
+
data: fileContent
|
|
5831
|
+
});
|
|
5832
|
+
} catch (error) {
|
|
5833
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
5834
|
+
if (errorMessage.includes("Path traversal")) {
|
|
5835
|
+
sendError(res, 403, "ERR-WC-013", "Access denied");
|
|
5836
|
+
} else if (errorMessage.includes("ENOENT")) {
|
|
5837
|
+
sendError(res, 404, "ERR-WC-014", "File not found");
|
|
5838
|
+
} else {
|
|
5839
|
+
sendError(res, 400, "ERR-WC-015", errorMessage);
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5842
|
+
return;
|
|
5843
|
+
}
|
|
5844
|
+
if (pathname === "/api/files/batch" && req.method === "POST") {
|
|
5845
|
+
try {
|
|
5846
|
+
const body = await parseJsonBody(req);
|
|
5847
|
+
if (!body.paths || !Array.isArray(body.paths) || body.paths.length === 0) {
|
|
5848
|
+
sendError(res, 400, "ERR-WC-016", "Missing or invalid paths array");
|
|
5849
|
+
return;
|
|
5850
|
+
}
|
|
5851
|
+
if (body.paths.length > fileService.getMaxFilesLimit()) {
|
|
5852
|
+
sendError(res, 400, "ERR-WC-017", `Maximum ${fileService.getMaxFilesLimit()} files allowed per request`);
|
|
5853
|
+
return;
|
|
5854
|
+
}
|
|
5855
|
+
const files = await fileService.readFiles(body.paths);
|
|
5856
|
+
sendJson(res, 200, {
|
|
5857
|
+
success: true,
|
|
5858
|
+
data: { files }
|
|
5859
|
+
});
|
|
5860
|
+
} catch (error) {
|
|
5861
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
5862
|
+
sendError(res, 500, "ERR-WC-018", `Batch read failed: ${errorMessage}`);
|
|
5863
|
+
}
|
|
5864
|
+
return;
|
|
5865
|
+
}
|
|
5866
|
+
if (pathname === "/api/files/info" && req.method === "GET") {
|
|
5867
|
+
sendJson(res, 200, {
|
|
5868
|
+
success: true,
|
|
5869
|
+
data: {
|
|
5870
|
+
workingDir: fileService.getWorkingDir(),
|
|
5871
|
+
maxFiles: fileService.getMaxFilesLimit()
|
|
5872
|
+
}
|
|
5873
|
+
});
|
|
5874
|
+
return;
|
|
5875
|
+
}
|
|
5443
5876
|
if (pathname === "/api/chat" && req.method === "POST") {
|
|
5444
5877
|
try {
|
|
5445
5878
|
const body = await parseJsonBody(req);
|
|
@@ -5793,8 +6226,8 @@ function createStatsCommand() {
|
|
|
5793
6226
|
import { Command as Command15 } from "commander";
|
|
5794
6227
|
|
|
5795
6228
|
// src/services/translation.service.ts
|
|
5796
|
-
import { promises as
|
|
5797
|
-
import
|
|
6229
|
+
import { promises as fs10 } from "fs";
|
|
6230
|
+
import path6 from "path";
|
|
5798
6231
|
import pLimit from "p-limit";
|
|
5799
6232
|
import pRetry from "p-retry";
|
|
5800
6233
|
var TRANSLATABLE_EXTS = [".md", ".txt", ".json", ".yaml", ".yml"];
|
|
@@ -5810,9 +6243,9 @@ var TranslationService = class {
|
|
|
5810
6243
|
/**
|
|
5811
6244
|
* Detect input type
|
|
5812
6245
|
*/
|
|
5813
|
-
async detectInputType(
|
|
6246
|
+
async detectInputType(input5) {
|
|
5814
6247
|
try {
|
|
5815
|
-
const stat = await
|
|
6248
|
+
const stat = await fs10.stat(input5);
|
|
5816
6249
|
if (stat.isDirectory()) return "folder";
|
|
5817
6250
|
if (stat.isFile()) return "file";
|
|
5818
6251
|
} catch {
|
|
@@ -5849,13 +6282,13 @@ var TranslationService = class {
|
|
|
5849
6282
|
*/
|
|
5850
6283
|
async translateFile(filePath) {
|
|
5851
6284
|
try {
|
|
5852
|
-
const content = await
|
|
5853
|
-
const ext =
|
|
6285
|
+
const content = await fs10.readFile(filePath, "utf-8");
|
|
6286
|
+
const ext = path6.extname(filePath).toLowerCase();
|
|
5854
6287
|
const fileType = this.getFileType(ext);
|
|
5855
6288
|
const translatedContent = await this.translateWithRetry(content, fileType);
|
|
5856
6289
|
const outputPath = this.generateOutputPath(filePath);
|
|
5857
6290
|
if (!this.options.dryRun) {
|
|
5858
|
-
await
|
|
6291
|
+
await fs10.writeFile(outputPath, translatedContent, "utf-8");
|
|
5859
6292
|
}
|
|
5860
6293
|
return {
|
|
5861
6294
|
inputPath: filePath,
|
|
@@ -5910,27 +6343,27 @@ var TranslationService = class {
|
|
|
5910
6343
|
if (this.options.output) {
|
|
5911
6344
|
return this.options.output;
|
|
5912
6345
|
}
|
|
5913
|
-
const ext =
|
|
5914
|
-
const base =
|
|
5915
|
-
const dir =
|
|
6346
|
+
const ext = path6.extname(inputPath);
|
|
6347
|
+
const base = path6.basename(inputPath, ext);
|
|
6348
|
+
const dir = path6.dirname(inputPath);
|
|
5916
6349
|
const lang = this.options.to;
|
|
5917
|
-
return
|
|
6350
|
+
return path6.join(dir, `${base}.${lang}${ext}`);
|
|
5918
6351
|
}
|
|
5919
6352
|
/**
|
|
5920
6353
|
* Discover translatable files in folder recursively
|
|
5921
6354
|
*/
|
|
5922
6355
|
async discoverFiles(folderPath) {
|
|
5923
|
-
const entries = await
|
|
6356
|
+
const entries = await fs10.readdir(folderPath, { withFileTypes: true });
|
|
5924
6357
|
const files = [];
|
|
5925
6358
|
for (const entry of entries) {
|
|
5926
|
-
const fullPath =
|
|
6359
|
+
const fullPath = path6.join(folderPath, entry.name);
|
|
5927
6360
|
if (entry.isDirectory()) {
|
|
5928
6361
|
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
5929
6362
|
const subFiles = await this.discoverFiles(fullPath);
|
|
5930
6363
|
files.push(...subFiles);
|
|
5931
6364
|
}
|
|
5932
6365
|
} else if (entry.isFile()) {
|
|
5933
|
-
const ext =
|
|
6366
|
+
const ext = path6.extname(entry.name).toLowerCase();
|
|
5934
6367
|
if (TRANSLATABLE_EXTS.includes(ext)) {
|
|
5935
6368
|
if (!this.isTranslatedFile(entry.name)) {
|
|
5936
6369
|
files.push(fullPath);
|
|
@@ -6044,7 +6477,7 @@ Return ONLY the translated content, no explanations.`;
|
|
|
6044
6477
|
};
|
|
6045
6478
|
|
|
6046
6479
|
// src/commands/translate.ts
|
|
6047
|
-
async function handleTranslate(
|
|
6480
|
+
async function handleTranslate(input5, options) {
|
|
6048
6481
|
const configService = new ConfigService();
|
|
6049
6482
|
const config = await configService.load();
|
|
6050
6483
|
if (!config) {
|
|
@@ -6052,16 +6485,16 @@ async function handleTranslate(input4, options) {
|
|
|
6052
6485
|
}
|
|
6053
6486
|
const llmService = new LlmProxyService(config);
|
|
6054
6487
|
const translationService = new TranslationService(llmService, options, options.model);
|
|
6055
|
-
const inputType = await translationService.detectInputType(
|
|
6488
|
+
const inputType = await translationService.detectInputType(input5);
|
|
6056
6489
|
switch (inputType) {
|
|
6057
6490
|
case "text":
|
|
6058
|
-
await handleTextTranslation(translationService,
|
|
6491
|
+
await handleTextTranslation(translationService, input5, options);
|
|
6059
6492
|
break;
|
|
6060
6493
|
case "file":
|
|
6061
|
-
await handleFileTranslation(translationService,
|
|
6494
|
+
await handleFileTranslation(translationService, input5, options);
|
|
6062
6495
|
break;
|
|
6063
6496
|
case "folder":
|
|
6064
|
-
await handleFolderTranslation(translationService,
|
|
6497
|
+
await handleFolderTranslation(translationService, input5, options);
|
|
6065
6498
|
break;
|
|
6066
6499
|
}
|
|
6067
6500
|
}
|
|
@@ -6138,8 +6571,8 @@ async function handleFolderTranslation(service, folderPath, options) {
|
|
|
6138
6571
|
}
|
|
6139
6572
|
}
|
|
6140
6573
|
function createTranslateCommand() {
|
|
6141
|
-
const cmd = new Command15("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (
|
|
6142
|
-
await handleTranslate(
|
|
6574
|
+
const cmd = new Command15("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (input5, options) => {
|
|
6575
|
+
await handleTranslate(input5, options);
|
|
6143
6576
|
});
|
|
6144
6577
|
return cmd;
|
|
6145
6578
|
}
|
|
@@ -6428,11 +6861,226 @@ function createImageCommand() {
|
|
|
6428
6861
|
return cmd;
|
|
6429
6862
|
}
|
|
6430
6863
|
|
|
6864
|
+
// src/commands/feedback.ts
|
|
6865
|
+
import { Command as Command21 } from "commander";
|
|
6866
|
+
import { select as select2, input, confirm as confirm5 } from "@inquirer/prompts";
|
|
6867
|
+
import os from "os";
|
|
6868
|
+
import { promises as fs11 } from "fs";
|
|
6869
|
+
import { join as join5 } from "path";
|
|
6870
|
+
async function collectContext() {
|
|
6871
|
+
const context = {
|
|
6872
|
+
os: `${os.platform()} ${os.release()}`
|
|
6873
|
+
};
|
|
6874
|
+
try {
|
|
6875
|
+
const packageJsonPath = new URL("../../package.json", import.meta.url);
|
|
6876
|
+
const packageJson = JSON.parse(await fs11.readFile(packageJsonPath, "utf-8"));
|
|
6877
|
+
context.cli_version = packageJson.version;
|
|
6878
|
+
} catch {
|
|
6879
|
+
}
|
|
6880
|
+
try {
|
|
6881
|
+
const projectPackageJson = await fs11.readFile(join5(process.cwd(), "package.json"), "utf-8");
|
|
6882
|
+
const projectData = JSON.parse(projectPackageJson);
|
|
6883
|
+
context.project_name = projectData.name;
|
|
6884
|
+
} catch {
|
|
6885
|
+
}
|
|
6886
|
+
return context;
|
|
6887
|
+
}
|
|
6888
|
+
async function submitFeedback(apiUrl, accessKey, data) {
|
|
6889
|
+
const response = await fetch(`${apiUrl}/api/feedback`, {
|
|
6890
|
+
method: "POST",
|
|
6891
|
+
headers: {
|
|
6892
|
+
"Content-Type": "application/json",
|
|
6893
|
+
"JAI1-Access-Key": accessKey
|
|
6894
|
+
},
|
|
6895
|
+
body: JSON.stringify({
|
|
6896
|
+
type: data.type,
|
|
6897
|
+
title: data.title,
|
|
6898
|
+
message: data.message,
|
|
6899
|
+
context: data.context,
|
|
6900
|
+
source: "cli"
|
|
6901
|
+
})
|
|
6902
|
+
});
|
|
6903
|
+
const result = await response.json();
|
|
6904
|
+
if (!response.ok) {
|
|
6905
|
+
return { success: false, error: result.error || "Failed to submit feedback" };
|
|
6906
|
+
}
|
|
6907
|
+
return { success: true, feedback_id: result.data.feedback_id };
|
|
6908
|
+
}
|
|
6909
|
+
async function handleInteractiveFeedback(config) {
|
|
6910
|
+
console.log("\u{1F4DD} Submit Feedback to Jai1\n");
|
|
6911
|
+
const type = await select2({
|
|
6912
|
+
message: "What type of feedback?",
|
|
6913
|
+
choices: [
|
|
6914
|
+
{
|
|
6915
|
+
name: "\u{1F41B} Bug Report - Report an error or issue",
|
|
6916
|
+
value: "bug"
|
|
6917
|
+
},
|
|
6918
|
+
{
|
|
6919
|
+
name: "\u{1F4A1} Feature Request - Suggest a new feature",
|
|
6920
|
+
value: "feature"
|
|
6921
|
+
},
|
|
6922
|
+
{
|
|
6923
|
+
name: "\u{1F4DD} Suggestion - Share ideas or improvements",
|
|
6924
|
+
value: "suggestion"
|
|
6925
|
+
}
|
|
6926
|
+
]
|
|
6927
|
+
});
|
|
6928
|
+
const title = await input({
|
|
6929
|
+
message: "Title (max 200 characters):",
|
|
6930
|
+
validate: (value) => {
|
|
6931
|
+
if (!value || value.trim().length === 0) {
|
|
6932
|
+
return "Title is required";
|
|
6933
|
+
}
|
|
6934
|
+
if (value.length > 200) {
|
|
6935
|
+
return "Title must be 200 characters or less";
|
|
6936
|
+
}
|
|
6937
|
+
return true;
|
|
6938
|
+
}
|
|
6939
|
+
});
|
|
6940
|
+
const message = await input({
|
|
6941
|
+
message: "Description (max 4000 characters):",
|
|
6942
|
+
validate: (value) => {
|
|
6943
|
+
if (!value || value.trim().length === 0) {
|
|
6944
|
+
return "Description is required";
|
|
6945
|
+
}
|
|
6946
|
+
if (value.length > 4e3) {
|
|
6947
|
+
return "Description must be 4000 characters or less";
|
|
6948
|
+
}
|
|
6949
|
+
return true;
|
|
6950
|
+
}
|
|
6951
|
+
});
|
|
6952
|
+
const context = await collectContext();
|
|
6953
|
+
console.log("\n\u{1F4CB} Summary:\n");
|
|
6954
|
+
console.log(`Type: ${type}`);
|
|
6955
|
+
console.log(`Title: ${title}`);
|
|
6956
|
+
console.log(`Description: ${message.substring(0, 100)}${message.length > 100 ? "..." : ""}`);
|
|
6957
|
+
if (context) {
|
|
6958
|
+
console.log(`Context: OS: ${context.os}, CLI: ${context.cli_version || "unknown"}`);
|
|
6959
|
+
}
|
|
6960
|
+
const confirmed = await confirm5({
|
|
6961
|
+
message: "\nSubmit feedback?",
|
|
6962
|
+
default: true
|
|
6963
|
+
});
|
|
6964
|
+
if (!confirmed) {
|
|
6965
|
+
console.log("\n\u274C Cancelled.");
|
|
6966
|
+
return;
|
|
6967
|
+
}
|
|
6968
|
+
console.log("\n\u23F3 Submitting feedback...");
|
|
6969
|
+
try {
|
|
6970
|
+
const result = await submitFeedback(config.apiUrl, config.accessKey, {
|
|
6971
|
+
type,
|
|
6972
|
+
title: title.trim(),
|
|
6973
|
+
message: message.trim(),
|
|
6974
|
+
context
|
|
6975
|
+
});
|
|
6976
|
+
if (result.success) {
|
|
6977
|
+
console.log(`
|
|
6978
|
+
\u2705 Feedback submitted successfully!`);
|
|
6979
|
+
console.log(` Feedback ID: ${result.feedback_id}
|
|
6980
|
+
`);
|
|
6981
|
+
console.log(" Thank you for your feedback! We will review it soon.");
|
|
6982
|
+
} else {
|
|
6983
|
+
console.error(`
|
|
6984
|
+
\u274C Failed to submit feedback: ${result.error}`);
|
|
6985
|
+
process.exit(1);
|
|
6986
|
+
}
|
|
6987
|
+
} catch (error) {
|
|
6988
|
+
console.error("\n\u274C Network error:", error instanceof Error ? error.message : String(error));
|
|
6989
|
+
process.exit(1);
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
async function handleNonInteractiveFeedback(config, options) {
|
|
6993
|
+
if (!options.type || !options.title || !options.message) {
|
|
6994
|
+
throw new ValidationError("Missing required fields: --type, --title, --message");
|
|
6995
|
+
}
|
|
6996
|
+
const validTypes = ["bug", "feature", "suggestion"];
|
|
6997
|
+
if (!validTypes.includes(options.type)) {
|
|
6998
|
+
throw new ValidationError(`Invalid type. Must be one of: ${validTypes.join(", ")}`);
|
|
6999
|
+
}
|
|
7000
|
+
if (options.title.length > 200) {
|
|
7001
|
+
throw new ValidationError("Title must be 200 characters or less");
|
|
7002
|
+
}
|
|
7003
|
+
if (options.message.length > 4e3) {
|
|
7004
|
+
throw new ValidationError("Message must be 4000 characters or less");
|
|
7005
|
+
}
|
|
7006
|
+
let context;
|
|
7007
|
+
if (!options.noContext) {
|
|
7008
|
+
context = await collectContext();
|
|
7009
|
+
if (options.context) {
|
|
7010
|
+
try {
|
|
7011
|
+
const customContext = JSON.parse(options.context);
|
|
7012
|
+
context = { ...context, ...customContext };
|
|
7013
|
+
} catch {
|
|
7014
|
+
throw new ValidationError("Invalid JSON in --context");
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
}
|
|
7018
|
+
try {
|
|
7019
|
+
const result = await submitFeedback(config.apiUrl, config.accessKey, {
|
|
7020
|
+
type: options.type,
|
|
7021
|
+
title: options.title.trim(),
|
|
7022
|
+
message: options.message.trim(),
|
|
7023
|
+
context
|
|
7024
|
+
});
|
|
7025
|
+
if (result.success) {
|
|
7026
|
+
if (options.json) {
|
|
7027
|
+
console.log(JSON.stringify({ success: true, feedback_id: result.feedback_id }));
|
|
7028
|
+
} else {
|
|
7029
|
+
console.log(`\u2705 Feedback submitted: ${result.feedback_id}`);
|
|
7030
|
+
}
|
|
7031
|
+
} else {
|
|
7032
|
+
if (options.json) {
|
|
7033
|
+
console.log(JSON.stringify({ success: false, error: result.error }));
|
|
7034
|
+
} else {
|
|
7035
|
+
console.error(`\u274C Error: ${result.error}`);
|
|
7036
|
+
}
|
|
7037
|
+
process.exit(1);
|
|
7038
|
+
}
|
|
7039
|
+
} catch (error) {
|
|
7040
|
+
if (options.json) {
|
|
7041
|
+
console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error" }));
|
|
7042
|
+
} else {
|
|
7043
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
7044
|
+
}
|
|
7045
|
+
process.exit(1);
|
|
7046
|
+
}
|
|
7047
|
+
}
|
|
7048
|
+
async function handleFeedbackCommand(options) {
|
|
7049
|
+
const configService = new ConfigService();
|
|
7050
|
+
const config = await configService.load();
|
|
7051
|
+
if (!config) {
|
|
7052
|
+
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
7053
|
+
}
|
|
7054
|
+
let stdinMessage = "";
|
|
7055
|
+
if (!process.stdin.isTTY && !options.message) {
|
|
7056
|
+
const chunks = [];
|
|
7057
|
+
for await (const chunk of process.stdin) {
|
|
7058
|
+
chunks.push(chunk);
|
|
7059
|
+
}
|
|
7060
|
+
stdinMessage = Buffer.concat(chunks).toString("utf-8").trim();
|
|
7061
|
+
}
|
|
7062
|
+
if (stdinMessage) {
|
|
7063
|
+
options.message = stdinMessage;
|
|
7064
|
+
}
|
|
7065
|
+
const isInteractive = !options.type && !options.title && !options.message;
|
|
7066
|
+
if (isInteractive) {
|
|
7067
|
+
await handleInteractiveFeedback(config);
|
|
7068
|
+
} else {
|
|
7069
|
+
await handleNonInteractiveFeedback(config, options);
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
function createFeedbackCommand() {
|
|
7073
|
+
const cmd = new Command21("feedback").alias("report").description("Submit bug reports, feature requests, or suggestions").option("--type <type>", "Feedback type: bug, feature, suggestion").option("--title <title>", "Feedback title (max 200 chars)").option("--message <message>", "Feedback message (max 4000 chars)").option("--context <json>", "Additional context as JSON").option("--no-context", "Do not include automatic context").option("--json", "Output JSON format").action(async (options) => {
|
|
7074
|
+
await handleFeedbackCommand(options);
|
|
7075
|
+
});
|
|
7076
|
+
return cmd;
|
|
7077
|
+
}
|
|
7078
|
+
|
|
6431
7079
|
// src/commands/utils/index.ts
|
|
6432
|
-
import { Command as
|
|
7080
|
+
import { Command as Command35 } from "commander";
|
|
6433
7081
|
|
|
6434
7082
|
// src/commands/utils/password.ts
|
|
6435
|
-
import { Command as
|
|
7083
|
+
import { Command as Command22 } from "commander";
|
|
6436
7084
|
|
|
6437
7085
|
// src/services/utils.service.ts
|
|
6438
7086
|
import crypto2 from "crypto";
|
|
@@ -6483,12 +7131,12 @@ var UtilsService = class {
|
|
|
6483
7131
|
/**
|
|
6484
7132
|
* Hash text or file using specified algorithm
|
|
6485
7133
|
*/
|
|
6486
|
-
async hash(
|
|
7134
|
+
async hash(input5, algorithm) {
|
|
6487
7135
|
if (algorithm === "bcrypt") {
|
|
6488
7136
|
throw new Error("Use hashBcrypt for bcrypt algorithm");
|
|
6489
7137
|
}
|
|
6490
7138
|
const hash = crypto2.createHash(algorithm);
|
|
6491
|
-
hash.update(
|
|
7139
|
+
hash.update(input5);
|
|
6492
7140
|
return hash.digest("hex");
|
|
6493
7141
|
}
|
|
6494
7142
|
/**
|
|
@@ -6501,14 +7149,14 @@ var UtilsService = class {
|
|
|
6501
7149
|
/**
|
|
6502
7150
|
* Hash using bcrypt
|
|
6503
7151
|
*/
|
|
6504
|
-
async hashBcrypt(
|
|
6505
|
-
return bcrypt.hash(
|
|
7152
|
+
async hashBcrypt(input5, rounds = 10) {
|
|
7153
|
+
return bcrypt.hash(input5, rounds);
|
|
6506
7154
|
}
|
|
6507
7155
|
/**
|
|
6508
7156
|
* Base64 encode
|
|
6509
7157
|
*/
|
|
6510
|
-
base64Encode(
|
|
6511
|
-
const buffer = typeof
|
|
7158
|
+
base64Encode(input5, urlSafe = false) {
|
|
7159
|
+
const buffer = typeof input5 === "string" ? Buffer.from(input5, "utf-8") : input5;
|
|
6512
7160
|
let encoded = buffer.toString("base64");
|
|
6513
7161
|
if (urlSafe) {
|
|
6514
7162
|
encoded = encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
@@ -6518,8 +7166,8 @@ var UtilsService = class {
|
|
|
6518
7166
|
/**
|
|
6519
7167
|
* Base64 decode
|
|
6520
7168
|
*/
|
|
6521
|
-
base64Decode(
|
|
6522
|
-
let normalized =
|
|
7169
|
+
base64Decode(input5) {
|
|
7170
|
+
let normalized = input5.replace(/-/g, "+").replace(/_/g, "/");
|
|
6523
7171
|
while (normalized.length % 4) {
|
|
6524
7172
|
normalized += "=";
|
|
6525
7173
|
}
|
|
@@ -6648,14 +7296,14 @@ var UtilsService = class {
|
|
|
6648
7296
|
/**
|
|
6649
7297
|
* URL encode
|
|
6650
7298
|
*/
|
|
6651
|
-
urlEncode(
|
|
6652
|
-
return full ? encodeURI(
|
|
7299
|
+
urlEncode(input5, full = false) {
|
|
7300
|
+
return full ? encodeURI(input5) : encodeURIComponent(input5);
|
|
6653
7301
|
}
|
|
6654
7302
|
/**
|
|
6655
7303
|
* URL decode
|
|
6656
7304
|
*/
|
|
6657
|
-
urlDecode(
|
|
6658
|
-
return full ? decodeURI(
|
|
7305
|
+
urlDecode(input5, full = false) {
|
|
7306
|
+
return full ? decodeURI(input5) : decodeURIComponent(input5);
|
|
6659
7307
|
}
|
|
6660
7308
|
/**
|
|
6661
7309
|
* Format bytes to human-readable size
|
|
@@ -6701,7 +7349,7 @@ async function handlePasswordGeneration(options) {
|
|
|
6701
7349
|
}
|
|
6702
7350
|
}
|
|
6703
7351
|
function createPasswordCommand() {
|
|
6704
|
-
const cmd = new
|
|
7352
|
+
const cmd = new Command22("password").description("Generate secure random password").option("-l, --length <number>", "Password length", "16").option("--no-lowercase", "Exclude lowercase letters").option("--no-uppercase", "Exclude uppercase letters").option("--no-digits", "Exclude digits").option("--no-symbols", "Exclude symbols").option("--symbol-chars <chars>", "Custom symbol characters").option("-c, --count <number>", "Number of passwords to generate", "1").addHelpText("after", `
|
|
6705
7353
|
Examples:
|
|
6706
7354
|
$ jai1 utils password
|
|
6707
7355
|
$ jai1 utils password --length 24
|
|
@@ -6719,7 +7367,7 @@ Examples:
|
|
|
6719
7367
|
}
|
|
6720
7368
|
|
|
6721
7369
|
// src/commands/utils/uuid.ts
|
|
6722
|
-
import { Command as
|
|
7370
|
+
import { Command as Command23 } from "commander";
|
|
6723
7371
|
async function handleUuidGeneration(options) {
|
|
6724
7372
|
const service = new UtilsService();
|
|
6725
7373
|
try {
|
|
@@ -6747,7 +7395,7 @@ async function handleUuidGeneration(options) {
|
|
|
6747
7395
|
}
|
|
6748
7396
|
}
|
|
6749
7397
|
function createUuidCommand() {
|
|
6750
|
-
const cmd = new
|
|
7398
|
+
const cmd = new Command23("uuid").description("Generate UUID v4 identifier").option("-c, --count <number>", "Number of UUIDs to generate", "1").option("--uppercase", "Output in uppercase").option("--no-hyphens", "Remove hyphens from output").addHelpText("after", `
|
|
6751
7399
|
Examples:
|
|
6752
7400
|
$ jai1 utils uuid
|
|
6753
7401
|
$ jai1 utils uuid --count 10
|
|
@@ -6764,8 +7412,8 @@ Examples:
|
|
|
6764
7412
|
}
|
|
6765
7413
|
|
|
6766
7414
|
// src/commands/utils/hash.ts
|
|
6767
|
-
import { Command as
|
|
6768
|
-
async function handleHashGeneration(
|
|
7415
|
+
import { Command as Command24 } from "commander";
|
|
7416
|
+
async function handleHashGeneration(input5, options) {
|
|
6769
7417
|
const service = new UtilsService();
|
|
6770
7418
|
try {
|
|
6771
7419
|
let hash;
|
|
@@ -6776,14 +7424,14 @@ async function handleHashGeneration(input4, options) {
|
|
|
6776
7424
|
}
|
|
6777
7425
|
hash = await service.hashFile(options.file, options.algorithm);
|
|
6778
7426
|
} else {
|
|
6779
|
-
if (!
|
|
7427
|
+
if (!input5) {
|
|
6780
7428
|
console.error("\u274C Please provide input text or use --file option");
|
|
6781
7429
|
process.exit(1);
|
|
6782
7430
|
}
|
|
6783
7431
|
if (options.algorithm === "bcrypt") {
|
|
6784
|
-
hash = await service.hashBcrypt(
|
|
7432
|
+
hash = await service.hashBcrypt(input5, options.rounds);
|
|
6785
7433
|
} else {
|
|
6786
|
-
hash = await service.hash(
|
|
7434
|
+
hash = await service.hash(input5, options.algorithm);
|
|
6787
7435
|
}
|
|
6788
7436
|
}
|
|
6789
7437
|
console.log("\u{1F512} Hash Result:");
|
|
@@ -6804,7 +7452,7 @@ async function handleHashGeneration(input4, options) {
|
|
|
6804
7452
|
}
|
|
6805
7453
|
}
|
|
6806
7454
|
function createHashCommand() {
|
|
6807
|
-
const cmd = new
|
|
7455
|
+
const cmd = new Command24("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
|
|
6808
7456
|
"-a, --algorithm <algorithm>",
|
|
6809
7457
|
"Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
|
|
6810
7458
|
"sha256"
|
|
@@ -6816,8 +7464,8 @@ Examples:
|
|
|
6816
7464
|
$ jai1 utils hash "password" --algorithm bcrypt --rounds 12
|
|
6817
7465
|
$ jai1 utils hash --file ./myfile.txt
|
|
6818
7466
|
$ jai1 utils hash --file ./image.png --algorithm sha512
|
|
6819
|
-
`).action(async (
|
|
6820
|
-
await handleHashGeneration(
|
|
7467
|
+
`).action(async (input5, options) => {
|
|
7468
|
+
await handleHashGeneration(input5, {
|
|
6821
7469
|
...options,
|
|
6822
7470
|
rounds: parseInt(options.rounds, 10)
|
|
6823
7471
|
});
|
|
@@ -6826,9 +7474,9 @@ Examples:
|
|
|
6826
7474
|
}
|
|
6827
7475
|
|
|
6828
7476
|
// src/commands/utils/base64-encode.ts
|
|
6829
|
-
import { Command as
|
|
7477
|
+
import { Command as Command25 } from "commander";
|
|
6830
7478
|
import { readFile as readFile2 } from "fs/promises";
|
|
6831
|
-
async function handleBase64Encode(
|
|
7479
|
+
async function handleBase64Encode(input5, options) {
|
|
6832
7480
|
const service = new UtilsService();
|
|
6833
7481
|
try {
|
|
6834
7482
|
let encoded;
|
|
@@ -6836,11 +7484,11 @@ async function handleBase64Encode(input4, options) {
|
|
|
6836
7484
|
const content = await readFile2(options.file);
|
|
6837
7485
|
encoded = service.base64Encode(content, options.urlSafe);
|
|
6838
7486
|
} else {
|
|
6839
|
-
if (!
|
|
7487
|
+
if (!input5) {
|
|
6840
7488
|
console.error("\u274C Please provide input text or use --file option");
|
|
6841
7489
|
process.exit(1);
|
|
6842
7490
|
}
|
|
6843
|
-
encoded = service.base64Encode(
|
|
7491
|
+
encoded = service.base64Encode(input5, options.urlSafe);
|
|
6844
7492
|
}
|
|
6845
7493
|
console.log("\u{1F4DD} Base64 Encoded:");
|
|
6846
7494
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
@@ -6859,33 +7507,33 @@ async function handleBase64Encode(input4, options) {
|
|
|
6859
7507
|
}
|
|
6860
7508
|
}
|
|
6861
7509
|
function createBase64EncodeCommand() {
|
|
6862
|
-
const cmd = new
|
|
7510
|
+
const cmd = new Command25("base64-encode").description("Encode text or file to Base64").argument("[input]", "Text to encode").option("-f, --file <path>", "Encode file contents").option("--url-safe", "Use URL-safe Base64 encoding").addHelpText("after", `
|
|
6863
7511
|
Examples:
|
|
6864
7512
|
$ jai1 utils base64-encode "hello world"
|
|
6865
7513
|
$ jai1 utils base64-encode "hello world" --url-safe
|
|
6866
7514
|
$ jai1 utils base64-encode --file ./document.txt
|
|
6867
7515
|
$ jai1 utils base64-encode --file ./image.png
|
|
6868
|
-
`).action(async (
|
|
6869
|
-
await handleBase64Encode(
|
|
7516
|
+
`).action(async (input5, options) => {
|
|
7517
|
+
await handleBase64Encode(input5, options);
|
|
6870
7518
|
});
|
|
6871
7519
|
return cmd;
|
|
6872
7520
|
}
|
|
6873
7521
|
|
|
6874
7522
|
// src/commands/utils/base64-decode.ts
|
|
6875
|
-
import { Command as
|
|
7523
|
+
import { Command as Command26 } from "commander";
|
|
6876
7524
|
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
6877
|
-
async function handleBase64Decode(
|
|
7525
|
+
async function handleBase64Decode(input5, options) {
|
|
6878
7526
|
const service = new UtilsService();
|
|
6879
7527
|
try {
|
|
6880
7528
|
let encodedInput;
|
|
6881
7529
|
if (options.file) {
|
|
6882
7530
|
encodedInput = await readFile3(options.file, "utf-8");
|
|
6883
7531
|
} else {
|
|
6884
|
-
if (!
|
|
7532
|
+
if (!input5) {
|
|
6885
7533
|
console.error("\u274C Please provide Base64 input or use --file option");
|
|
6886
7534
|
process.exit(1);
|
|
6887
7535
|
}
|
|
6888
|
-
encodedInput =
|
|
7536
|
+
encodedInput = input5;
|
|
6889
7537
|
}
|
|
6890
7538
|
const decoded = service.base64Decode(encodedInput.trim());
|
|
6891
7539
|
if (options.output) {
|
|
@@ -6904,20 +7552,20 @@ async function handleBase64Decode(input4, options) {
|
|
|
6904
7552
|
}
|
|
6905
7553
|
}
|
|
6906
7554
|
function createBase64DecodeCommand() {
|
|
6907
|
-
const cmd = new
|
|
7555
|
+
const cmd = new Command26("base64-decode").description("Decode Base64 string").argument("[input]", "Base64 string to decode").option("-f, --file <path>", "Decode from file").option("-o, --output <path>", "Write decoded output to file").addHelpText("after", `
|
|
6908
7556
|
Examples:
|
|
6909
7557
|
$ jai1 utils base64-decode "aGVsbG8gd29ybGQ="
|
|
6910
7558
|
$ jai1 utils base64-decode --file ./encoded.txt
|
|
6911
7559
|
$ jai1 utils base64-decode "aGVsbG8=" --output ./decoded.txt
|
|
6912
7560
|
$ jai1 utils base64-decode --file ./encoded.txt --output ./image.png
|
|
6913
|
-
`).action(async (
|
|
6914
|
-
await handleBase64Decode(
|
|
7561
|
+
`).action(async (input5, options) => {
|
|
7562
|
+
await handleBase64Decode(input5, options);
|
|
6915
7563
|
});
|
|
6916
7564
|
return cmd;
|
|
6917
7565
|
}
|
|
6918
7566
|
|
|
6919
7567
|
// src/commands/utils/http.ts
|
|
6920
|
-
import { Command as
|
|
7568
|
+
import { Command as Command27 } from "commander";
|
|
6921
7569
|
import { readFile as readFile4 } from "fs/promises";
|
|
6922
7570
|
async function handleHttpRequest(url, options) {
|
|
6923
7571
|
const service = new UtilsService();
|
|
@@ -6983,7 +7631,7 @@ async function handleHttpRequest(url, options) {
|
|
|
6983
7631
|
}
|
|
6984
7632
|
}
|
|
6985
7633
|
function createHttpCommand() {
|
|
6986
|
-
const cmd = new
|
|
7634
|
+
const cmd = new Command27("http").description("Make HTTP request with formatted output").argument("<url>", "Target URL").option("-X, --method <method>", "HTTP method", "GET").option("-H, --header <header...>", "Request headers (repeatable)").option("-d, --data <data>", "Request body (JSON string)").option("--file <path>", "Read body from file").option("--timeout <ms>", "Request timeout in milliseconds", "30000").option("--no-follow", "Do not follow redirects").option("--only-headers", "Show only response headers").option("--only-body", "Show only response body").addHelpText("after", `
|
|
6987
7635
|
Examples:
|
|
6988
7636
|
$ jai1 utils http https://api.example.com/users
|
|
6989
7637
|
$ jai1 utils http https://api.example.com/users -X POST -d '{"name":"John"}'
|
|
@@ -7001,7 +7649,7 @@ Examples:
|
|
|
7001
7649
|
}
|
|
7002
7650
|
|
|
7003
7651
|
// src/commands/utils/jwt.ts
|
|
7004
|
-
import { Command as
|
|
7652
|
+
import { Command as Command28 } from "commander";
|
|
7005
7653
|
async function handleJwtDecode(token) {
|
|
7006
7654
|
const service = new UtilsService();
|
|
7007
7655
|
try {
|
|
@@ -7040,7 +7688,7 @@ async function handleJwtEncode(options) {
|
|
|
7040
7688
|
}
|
|
7041
7689
|
}
|
|
7042
7690
|
function createJwtCommand() {
|
|
7043
|
-
const jwtCommand = new
|
|
7691
|
+
const jwtCommand = new Command28("jwt").description("Decode and encode JWT tokens");
|
|
7044
7692
|
jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").addHelpText("after", `
|
|
7045
7693
|
Examples:
|
|
7046
7694
|
$ jai1 utils jwt decode "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
|
@@ -7061,11 +7709,11 @@ Examples:
|
|
|
7061
7709
|
}
|
|
7062
7710
|
|
|
7063
7711
|
// src/commands/utils/unix-time.ts
|
|
7064
|
-
import { Command as
|
|
7065
|
-
async function handleUnixTime(
|
|
7712
|
+
import { Command as Command29 } from "commander";
|
|
7713
|
+
async function handleUnixTime(input5, options) {
|
|
7066
7714
|
const service = new UtilsService();
|
|
7067
7715
|
try {
|
|
7068
|
-
if (!
|
|
7716
|
+
if (!input5) {
|
|
7069
7717
|
const now = /* @__PURE__ */ new Date();
|
|
7070
7718
|
const timestamp = service.dateToUnix(now, options.ms);
|
|
7071
7719
|
console.log("\u{1F552} Current Unix Timestamp:");
|
|
@@ -7075,8 +7723,8 @@ async function handleUnixTime(input4, options) {
|
|
|
7075
7723
|
console.log(` ISO: ${now.toISOString()}`);
|
|
7076
7724
|
console.log(` Local: ${now.toLocaleString()}`);
|
|
7077
7725
|
console.log();
|
|
7078
|
-
} else if (/^\d+$/.test(
|
|
7079
|
-
const timestamp = parseInt(
|
|
7726
|
+
} else if (/^\d+$/.test(input5)) {
|
|
7727
|
+
const timestamp = parseInt(input5, 10);
|
|
7080
7728
|
const date = service.unixToDate(timestamp, options.ms);
|
|
7081
7729
|
console.log("\u{1F552} Unix Timestamp to Date:");
|
|
7082
7730
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
@@ -7089,7 +7737,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7089
7737
|
}
|
|
7090
7738
|
console.log();
|
|
7091
7739
|
} else {
|
|
7092
|
-
const date = new Date(
|
|
7740
|
+
const date = new Date(input5);
|
|
7093
7741
|
if (isNaN(date.getTime())) {
|
|
7094
7742
|
console.error("\u274C Invalid date format");
|
|
7095
7743
|
process.exit(1);
|
|
@@ -7097,7 +7745,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7097
7745
|
const timestamp = service.dateToUnix(date, options.ms);
|
|
7098
7746
|
console.log("\u{1F552} Date to Unix Timestamp:");
|
|
7099
7747
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7100
|
-
console.log(` Input: ${
|
|
7748
|
+
console.log(` Input: ${input5}`);
|
|
7101
7749
|
console.log(` Parsed: ${date.toISOString()}`);
|
|
7102
7750
|
console.log();
|
|
7103
7751
|
console.log(` ${timestamp}${options.ms ? " (ms)" : ""}`);
|
|
@@ -7109,7 +7757,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7109
7757
|
}
|
|
7110
7758
|
}
|
|
7111
7759
|
function createUnixTimeCommand() {
|
|
7112
|
-
const cmd = new
|
|
7760
|
+
const cmd = new Command29("unix-time").description("Convert unix timestamps to/from dates").argument("[input]", "Unix timestamp or date string").option("-f, --format <format>", "Output format (iso, local, utc)", "iso").option("--ms", "Use milliseconds instead of seconds").addHelpText("after", `
|
|
7113
7761
|
Examples:
|
|
7114
7762
|
$ jai1 utils unix-time
|
|
7115
7763
|
$ jai1 utils unix-time 1702550400
|
|
@@ -7117,14 +7765,14 @@ Examples:
|
|
|
7117
7765
|
$ jai1 utils unix-time "2024-01-15 10:30:00"
|
|
7118
7766
|
$ jai1 utils unix-time "2024-01-15" --format local
|
|
7119
7767
|
$ jai1 utils unix-time --ms
|
|
7120
|
-
`).action(async (
|
|
7121
|
-
await handleUnixTime(
|
|
7768
|
+
`).action(async (input5, options) => {
|
|
7769
|
+
await handleUnixTime(input5, options);
|
|
7122
7770
|
});
|
|
7123
7771
|
return cmd;
|
|
7124
7772
|
}
|
|
7125
7773
|
|
|
7126
7774
|
// src/commands/utils/timezone.ts
|
|
7127
|
-
import { Command as
|
|
7775
|
+
import { Command as Command30 } from "commander";
|
|
7128
7776
|
async function handleTimezoneConversion(time, options) {
|
|
7129
7777
|
const service = new UtilsService();
|
|
7130
7778
|
try {
|
|
@@ -7161,7 +7809,7 @@ async function handleTimezoneConversion(time, options) {
|
|
|
7161
7809
|
}
|
|
7162
7810
|
}
|
|
7163
7811
|
function createTimezoneCommand() {
|
|
7164
|
-
const cmd = new
|
|
7812
|
+
const cmd = new Command30("timezone").description("Convert time between timezones").argument("[time]", 'Time to convert (e.g., "2024-01-15 10:00")').option("--from <timezone>", "Source timezone").option("--to <timezone>", "Target timezone").option("--list", "Show available timezones").addHelpText("after", `
|
|
7165
7813
|
Examples:
|
|
7166
7814
|
$ jai1 utils timezone --list
|
|
7167
7815
|
$ jai1 utils timezone "2024-01-15 10:00" --from "America/New_York" --to "Asia/Tokyo"
|
|
@@ -7174,11 +7822,11 @@ Examples:
|
|
|
7174
7822
|
}
|
|
7175
7823
|
|
|
7176
7824
|
// src/commands/utils/url-encode.ts
|
|
7177
|
-
import { Command as
|
|
7178
|
-
async function handleUrlEncode(
|
|
7825
|
+
import { Command as Command31 } from "commander";
|
|
7826
|
+
async function handleUrlEncode(input5, options) {
|
|
7179
7827
|
const service = new UtilsService();
|
|
7180
7828
|
try {
|
|
7181
|
-
const encoded = service.urlEncode(
|
|
7829
|
+
const encoded = service.urlEncode(input5, options.full);
|
|
7182
7830
|
console.log("\u{1F517} URL Encoded:");
|
|
7183
7831
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7184
7832
|
if (options.full) {
|
|
@@ -7195,24 +7843,24 @@ async function handleUrlEncode(input4, options) {
|
|
|
7195
7843
|
}
|
|
7196
7844
|
}
|
|
7197
7845
|
function createUrlEncodeCommand() {
|
|
7198
|
-
const cmd = new
|
|
7846
|
+
const cmd = new Command31("url-encode").description("Encode URL component or full URL").argument("<input>", "Text to encode").option("--full", "Encode full URL (use encodeURI instead of encodeURIComponent)").addHelpText("after", `
|
|
7199
7847
|
Examples:
|
|
7200
7848
|
$ jai1 utils url-encode "hello world"
|
|
7201
7849
|
$ jai1 utils url-encode "hello world & test"
|
|
7202
7850
|
$ jai1 utils url-encode "name=John Doe&age=30"
|
|
7203
7851
|
$ jai1 utils url-encode "https://example.com/path with spaces" --full
|
|
7204
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
7205
|
-
await handleUrlEncode(
|
|
7852
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input5, options) => {
|
|
7853
|
+
await handleUrlEncode(input5, options);
|
|
7206
7854
|
});
|
|
7207
7855
|
return cmd;
|
|
7208
7856
|
}
|
|
7209
7857
|
|
|
7210
7858
|
// src/commands/utils/url-decode.ts
|
|
7211
|
-
import { Command as
|
|
7212
|
-
async function handleUrlDecode(
|
|
7859
|
+
import { Command as Command32 } from "commander";
|
|
7860
|
+
async function handleUrlDecode(input5, options) {
|
|
7213
7861
|
const service = new UtilsService();
|
|
7214
7862
|
try {
|
|
7215
|
-
const decoded = service.urlDecode(
|
|
7863
|
+
const decoded = service.urlDecode(input5, options.full);
|
|
7216
7864
|
console.log("\u{1F517} URL Decoded:");
|
|
7217
7865
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7218
7866
|
if (options.full) {
|
|
@@ -7229,20 +7877,20 @@ async function handleUrlDecode(input4, options) {
|
|
|
7229
7877
|
}
|
|
7230
7878
|
}
|
|
7231
7879
|
function createUrlDecodeCommand() {
|
|
7232
|
-
const cmd = new
|
|
7880
|
+
const cmd = new Command32("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").addHelpText("after", `
|
|
7233
7881
|
Examples:
|
|
7234
7882
|
$ jai1 utils url-decode "hello%20world"
|
|
7235
7883
|
$ jai1 utils url-decode "hello%20world%20%26%20test"
|
|
7236
7884
|
$ jai1 utils url-decode "name%3DJohn%20Doe%26age%3D30"
|
|
7237
7885
|
$ jai1 utils url-decode "https://example.com/path%20with%20spaces" --full
|
|
7238
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
7239
|
-
await handleUrlDecode(
|
|
7886
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input5, options) => {
|
|
7887
|
+
await handleUrlDecode(input5, options);
|
|
7240
7888
|
});
|
|
7241
7889
|
return cmd;
|
|
7242
7890
|
}
|
|
7243
7891
|
|
|
7244
7892
|
// src/commands/utils/cron.ts
|
|
7245
|
-
import { Command as
|
|
7893
|
+
import { Command as Command33 } from "commander";
|
|
7246
7894
|
import cronstrue from "cronstrue";
|
|
7247
7895
|
async function handleCronParse(expression) {
|
|
7248
7896
|
try {
|
|
@@ -7285,7 +7933,7 @@ async function handleCronParse(expression) {
|
|
|
7285
7933
|
}
|
|
7286
7934
|
}
|
|
7287
7935
|
function createCronCommand() {
|
|
7288
|
-
const cmd = new
|
|
7936
|
+
const cmd = new Command33("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
|
|
7289
7937
|
Examples:
|
|
7290
7938
|
$ jai1 utils cron "0 5 * * *"
|
|
7291
7939
|
$ jai1 utils cron "*/15 * * * *"
|
|
@@ -7299,7 +7947,7 @@ Examples:
|
|
|
7299
7947
|
}
|
|
7300
7948
|
|
|
7301
7949
|
// src/commands/utils/markdown-preview.ts
|
|
7302
|
-
import { Command as
|
|
7950
|
+
import { Command as Command34 } from "commander";
|
|
7303
7951
|
import { readFile as readFile5 } from "fs/promises";
|
|
7304
7952
|
import { marked } from "marked";
|
|
7305
7953
|
import TerminalRenderer from "marked-terminal";
|
|
@@ -7338,7 +7986,7 @@ ${code.trim()}
|
|
|
7338
7986
|
}
|
|
7339
7987
|
}
|
|
7340
7988
|
function createMarkdownPreviewCommand() {
|
|
7341
|
-
const cmd = new
|
|
7989
|
+
const cmd = new Command34("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").addHelpText("after", `
|
|
7342
7990
|
Examples:
|
|
7343
7991
|
$ jai1 utils markdown-preview README.md
|
|
7344
7992
|
$ jai1 utils markdown-preview ./docs/guide.md
|
|
@@ -7372,14 +8020,14 @@ var PasswordView = () => {
|
|
|
7372
8020
|
React27.useEffect(() => {
|
|
7373
8021
|
handleGenerate();
|
|
7374
8022
|
}, []);
|
|
7375
|
-
useInput12((
|
|
8023
|
+
useInput12((input5, key) => {
|
|
7376
8024
|
if (key.tab) {
|
|
7377
8025
|
if (focusedField === "length") setFocusedField("count");
|
|
7378
8026
|
else if (focusedField === "count") setFocusedField("generate");
|
|
7379
8027
|
else setFocusedField("length");
|
|
7380
8028
|
} else if (key.return) {
|
|
7381
8029
|
handleGenerate();
|
|
7382
|
-
} else if (
|
|
8030
|
+
} else if (input5 === "c" && passwords.length > 0) {
|
|
7383
8031
|
handleCopy(0);
|
|
7384
8032
|
}
|
|
7385
8033
|
});
|
|
@@ -7462,7 +8110,7 @@ var UuidView = () => {
|
|
|
7462
8110
|
React28.useEffect(() => {
|
|
7463
8111
|
handleGenerate();
|
|
7464
8112
|
}, []);
|
|
7465
|
-
useInput13((
|
|
8113
|
+
useInput13((input5, key) => {
|
|
7466
8114
|
if (key.tab) {
|
|
7467
8115
|
const fields = ["count", "uppercase", "hyphens", "generate"];
|
|
7468
8116
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7475,7 +8123,7 @@ var UuidView = () => {
|
|
|
7475
8123
|
} else {
|
|
7476
8124
|
handleGenerate();
|
|
7477
8125
|
}
|
|
7478
|
-
} else if (
|
|
8126
|
+
} else if (input5 === "c" && uuids.length > 0) {
|
|
7479
8127
|
handleCopy(0);
|
|
7480
8128
|
}
|
|
7481
8129
|
});
|
|
@@ -7550,7 +8198,7 @@ var HashView = () => {
|
|
|
7550
8198
|
React29.useEffect(() => {
|
|
7551
8199
|
handleGenerate();
|
|
7552
8200
|
}, []);
|
|
7553
|
-
useInput14((
|
|
8201
|
+
useInput14((input5, key) => {
|
|
7554
8202
|
if (key.tab) {
|
|
7555
8203
|
const fields = ["text", "algorithm", "generate"];
|
|
7556
8204
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7563,7 +8211,7 @@ var HashView = () => {
|
|
|
7563
8211
|
} else if (key.rightArrow && focusedField === "algorithm") {
|
|
7564
8212
|
const currentIndex = ALGORITHMS.indexOf(algorithm);
|
|
7565
8213
|
setAlgorithm(ALGORITHMS[(currentIndex + 1) % ALGORITHMS.length]);
|
|
7566
|
-
} else if (
|
|
8214
|
+
} else if (input5 === "c" && hash) {
|
|
7567
8215
|
handleCopy();
|
|
7568
8216
|
}
|
|
7569
8217
|
});
|
|
@@ -7629,7 +8277,7 @@ import React30, { useState as useState17 } from "react";
|
|
|
7629
8277
|
import { Box as Box20, Text as Text21, useInput as useInput15 } from "ink";
|
|
7630
8278
|
import TextInput7 from "ink-text-input";
|
|
7631
8279
|
var Base64View = () => {
|
|
7632
|
-
const [
|
|
8280
|
+
const [input5, setInput] = useState17("");
|
|
7633
8281
|
const [mode, setMode] = useState17("encode");
|
|
7634
8282
|
const [urlSafe, setUrlSafe] = useState17(false);
|
|
7635
8283
|
const [result, setResult] = useState17("");
|
|
@@ -7637,7 +8285,7 @@ var Base64View = () => {
|
|
|
7637
8285
|
const [focusedField, setFocusedField] = useState17("input");
|
|
7638
8286
|
const [copied, setCopied] = useState17(false);
|
|
7639
8287
|
const service = new UtilsService();
|
|
7640
|
-
useInput15((
|
|
8288
|
+
useInput15((input6, key) => {
|
|
7641
8289
|
if (key.tab) {
|
|
7642
8290
|
const fields = ["input", "mode", "urlsafe", "convert"];
|
|
7643
8291
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7652,22 +8300,22 @@ var Base64View = () => {
|
|
|
7652
8300
|
} else {
|
|
7653
8301
|
handleConvert();
|
|
7654
8302
|
}
|
|
7655
|
-
} else if (
|
|
8303
|
+
} else if (input6 === "c" && result) {
|
|
7656
8304
|
handleCopy();
|
|
7657
8305
|
}
|
|
7658
8306
|
});
|
|
7659
8307
|
const handleConvert = () => {
|
|
7660
|
-
if (!
|
|
8308
|
+
if (!input5) {
|
|
7661
8309
|
setError("Input cannot be empty");
|
|
7662
8310
|
return;
|
|
7663
8311
|
}
|
|
7664
8312
|
try {
|
|
7665
8313
|
setError("");
|
|
7666
8314
|
if (mode === "encode") {
|
|
7667
|
-
const encoded = service.base64Encode(
|
|
8315
|
+
const encoded = service.base64Encode(input5, urlSafe);
|
|
7668
8316
|
setResult(encoded);
|
|
7669
8317
|
} else {
|
|
7670
|
-
const decoded = service.base64Decode(
|
|
8318
|
+
const decoded = service.base64Decode(input5);
|
|
7671
8319
|
setResult(decoded.toString("utf-8"));
|
|
7672
8320
|
}
|
|
7673
8321
|
setCopied(false);
|
|
@@ -7696,7 +8344,7 @@ var Base64View = () => {
|
|
|
7696
8344
|
marginBottom: 1
|
|
7697
8345
|
},
|
|
7698
8346
|
/* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
7699
|
-
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 0 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React30.createElement(TextInput7, { value:
|
|
8347
|
+
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 0 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React30.createElement(TextInput7, { value: input5, onChange: setInput, placeholder: "Enter text..." }) : /* @__PURE__ */ React30.createElement(Text21, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7700
8348
|
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Box20, { width: 20 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, " (Enter to toggle)")),
|
|
7701
8349
|
mode === "encode" && /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "urlsafe" ? "green" : void 0 }, focusedField === "urlsafe" ? "\u25B6 " : " ", "[", urlSafe ? "\u2713" : " ", "] URL-Safe (+ \u2192 -, / \u2192 _)")),
|
|
7702
8350
|
/* @__PURE__ */ React30.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(
|
|
@@ -7741,14 +8389,14 @@ import React31, { useState as useState18 } from "react";
|
|
|
7741
8389
|
import { Box as Box21, Text as Text22, useInput as useInput16 } from "ink";
|
|
7742
8390
|
import TextInput8 from "ink-text-input";
|
|
7743
8391
|
var UrlView = () => {
|
|
7744
|
-
const [
|
|
8392
|
+
const [input5, setInput] = useState18("");
|
|
7745
8393
|
const [mode, setMode] = useState18("encode");
|
|
7746
8394
|
const [fullUrl, setFullUrl] = useState18(false);
|
|
7747
8395
|
const [result, setResult] = useState18("");
|
|
7748
8396
|
const [focusedField, setFocusedField] = useState18("input");
|
|
7749
8397
|
const [copied, setCopied] = useState18(false);
|
|
7750
8398
|
const service = new UtilsService();
|
|
7751
|
-
useInput16((
|
|
8399
|
+
useInput16((input6, key) => {
|
|
7752
8400
|
if (key.tab) {
|
|
7753
8401
|
const fields = ["input", "mode", "full", "convert"];
|
|
7754
8402
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7762,17 +8410,17 @@ var UrlView = () => {
|
|
|
7762
8410
|
} else {
|
|
7763
8411
|
handleConvert();
|
|
7764
8412
|
}
|
|
7765
|
-
} else if (
|
|
8413
|
+
} else if (input6 === "c" && result) {
|
|
7766
8414
|
handleCopy();
|
|
7767
8415
|
}
|
|
7768
8416
|
});
|
|
7769
8417
|
const handleConvert = () => {
|
|
7770
|
-
if (!
|
|
8418
|
+
if (!input5) return;
|
|
7771
8419
|
if (mode === "encode") {
|
|
7772
|
-
const encoded = fullUrl ? service.urlEncode(
|
|
8420
|
+
const encoded = fullUrl ? service.urlEncode(input5, true) : service.urlEncode(input5, false);
|
|
7773
8421
|
setResult(encoded);
|
|
7774
8422
|
} else {
|
|
7775
|
-
const decoded = fullUrl ? service.urlDecode(
|
|
8423
|
+
const decoded = fullUrl ? service.urlDecode(input5, true) : service.urlDecode(input5, false);
|
|
7776
8424
|
setResult(decoded);
|
|
7777
8425
|
}
|
|
7778
8426
|
setCopied(false);
|
|
@@ -7797,7 +8445,7 @@ var UrlView = () => {
|
|
|
7797
8445
|
marginBottom: 1
|
|
7798
8446
|
},
|
|
7799
8447
|
/* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
7800
|
-
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 0 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React31.createElement(TextInput8, { value:
|
|
8448
|
+
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 0 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React31.createElement(TextInput8, { value: input5, onChange: setInput, placeholder: "Enter text or URL..." }) : /* @__PURE__ */ React31.createElement(Text22, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7801
8449
|
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Box21, { width: 20 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React31.createElement(Text22, { dimColor: true }, " (Enter to toggle)")),
|
|
7802
8450
|
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "full" ? "green" : void 0 }, focusedField === "full" ? "\u25B6 " : " ", "[", fullUrl ? "\u2713" : " ", "] Full URL (encode/decode entire URL)")),
|
|
7803
8451
|
/* @__PURE__ */ React31.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(
|
|
@@ -7831,7 +8479,7 @@ import React32, { useState as useState19 } from "react";
|
|
|
7831
8479
|
import { Box as Box22, Text as Text23, useInput as useInput17 } from "ink";
|
|
7832
8480
|
import TextInput9 from "ink-text-input";
|
|
7833
8481
|
var UnixTimeView = () => {
|
|
7834
|
-
const [
|
|
8482
|
+
const [input5, setInput] = useState19("");
|
|
7835
8483
|
const [mode, setMode] = useState19("now");
|
|
7836
8484
|
const [format, setFormat] = useState19("iso");
|
|
7837
8485
|
const [useMs, setUseMs] = useState19(false);
|
|
@@ -7840,7 +8488,7 @@ var UnixTimeView = () => {
|
|
|
7840
8488
|
const [focusedField, setFocusedField] = useState19("mode");
|
|
7841
8489
|
const [copied, setCopied] = useState19(false);
|
|
7842
8490
|
const service = new UtilsService();
|
|
7843
|
-
useInput17((
|
|
8491
|
+
useInput17((input6, key) => {
|
|
7844
8492
|
if (key.tab) {
|
|
7845
8493
|
const fields = mode === "now" ? ["mode", "ms", "convert"] : mode === "to-human" ? ["mode", "input", "format", "convert"] : ["mode", "input", "convert"];
|
|
7846
8494
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7861,7 +8509,7 @@ var UnixTimeView = () => {
|
|
|
7861
8509
|
} else {
|
|
7862
8510
|
handleConvert();
|
|
7863
8511
|
}
|
|
7864
|
-
} else if (
|
|
8512
|
+
} else if (input6 === "c" && result) {
|
|
7865
8513
|
handleCopy();
|
|
7866
8514
|
}
|
|
7867
8515
|
});
|
|
@@ -7872,18 +8520,18 @@ var UnixTimeView = () => {
|
|
|
7872
8520
|
const timestamp = service.unixTimeCurrent(useMs);
|
|
7873
8521
|
setResult(timestamp.toString());
|
|
7874
8522
|
} else if (mode === "to-human") {
|
|
7875
|
-
if (!
|
|
8523
|
+
if (!input5) {
|
|
7876
8524
|
setError("Please enter a timestamp");
|
|
7877
8525
|
return;
|
|
7878
8526
|
}
|
|
7879
|
-
const human = service.unixTimeToHuman(parseInt(
|
|
8527
|
+
const human = service.unixTimeToHuman(parseInt(input5, 10), format);
|
|
7880
8528
|
setResult(human);
|
|
7881
8529
|
} else {
|
|
7882
|
-
if (!
|
|
8530
|
+
if (!input5) {
|
|
7883
8531
|
setError("Please enter a date string");
|
|
7884
8532
|
return;
|
|
7885
8533
|
}
|
|
7886
|
-
const timestamp = service.unixTimeFromString(
|
|
8534
|
+
const timestamp = service.unixTimeFromString(input5);
|
|
7887
8535
|
setResult(timestamp.toString());
|
|
7888
8536
|
}
|
|
7889
8537
|
setCopied(false);
|
|
@@ -7916,11 +8564,11 @@ var UnixTimeView = () => {
|
|
|
7916
8564
|
mode !== "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 0 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", mode === "to-human" ? "Timestamp:" : "Date string:")), /* @__PURE__ */ React32.createElement(Box22, { marginLeft: 2, width: 50 }, focusedField === "input" ? /* @__PURE__ */ React32.createElement(
|
|
7917
8565
|
TextInput9,
|
|
7918
8566
|
{
|
|
7919
|
-
value:
|
|
8567
|
+
value: input5,
|
|
7920
8568
|
onChange: setInput,
|
|
7921
8569
|
placeholder: mode === "to-human" ? "1702550400" : "2024-01-15 10:30:00"
|
|
7922
8570
|
}
|
|
7923
|
-
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !
|
|
8571
|
+
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7924
8572
|
mode === "to-human" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Box22, { width: 20 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "format" ? "green" : void 0 }, focusedField === "format" ? "\u25B6 " : " ", "Format:")), /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: focusedField === "format" ? "yellow" : void 0 }, format.toUpperCase()), focusedField === "format" && /* @__PURE__ */ React32.createElement(Text23, { dimColor: true }, " (Enter to cycle)")),
|
|
7925
8573
|
mode === "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "ms" ? "green" : void 0 }, focusedField === "ms" ? "\u25B6 " : " ", "[", useMs ? "\u2713" : " ", "] Milliseconds")),
|
|
7926
8574
|
/* @__PURE__ */ React32.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(
|
|
@@ -7974,7 +8622,7 @@ var JwtView = () => {
|
|
|
7974
8622
|
const [focusedField, setFocusedField] = useState20("mode");
|
|
7975
8623
|
const [copied, setCopied] = useState20(false);
|
|
7976
8624
|
const service = new UtilsService();
|
|
7977
|
-
useInput18((
|
|
8625
|
+
useInput18((input5, key) => {
|
|
7978
8626
|
if (key.tab) {
|
|
7979
8627
|
const fields = mode === "decode" ? ["mode", "token", "process"] : ["mode", "payload", "secret", "process"];
|
|
7980
8628
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7987,7 +8635,7 @@ var JwtView = () => {
|
|
|
7987
8635
|
} else {
|
|
7988
8636
|
handleProcess();
|
|
7989
8637
|
}
|
|
7990
|
-
} else if (
|
|
8638
|
+
} else if (input5 === "c" && result.token) {
|
|
7991
8639
|
handleCopy();
|
|
7992
8640
|
}
|
|
7993
8641
|
});
|
|
@@ -8112,12 +8760,12 @@ var CronView = () => {
|
|
|
8112
8760
|
const [focusedField, setFocusedField] = useState21("expression");
|
|
8113
8761
|
const [copied, setCopied] = useState21(false);
|
|
8114
8762
|
const service = new UtilsService();
|
|
8115
|
-
useInput19((
|
|
8763
|
+
useInput19((input5, key) => {
|
|
8116
8764
|
if (key.tab) {
|
|
8117
8765
|
setFocusedField(focusedField === "expression" ? "parse" : "expression");
|
|
8118
8766
|
} else if (key.return) {
|
|
8119
8767
|
handleParse();
|
|
8120
|
-
} else if (
|
|
8768
|
+
} else if (input5 === "c" && result) {
|
|
8121
8769
|
handleCopy();
|
|
8122
8770
|
}
|
|
8123
8771
|
});
|
|
@@ -8218,14 +8866,14 @@ var TimezoneView = () => {
|
|
|
8218
8866
|
const [focusedField, setFocusedField] = useState22("time");
|
|
8219
8867
|
const [copied, setCopied] = useState22(false);
|
|
8220
8868
|
const service = new UtilsService();
|
|
8221
|
-
useInput20((
|
|
8869
|
+
useInput20((input5, key) => {
|
|
8222
8870
|
if (key.tab) {
|
|
8223
8871
|
const fields = ["time", "from", "to", "convert"];
|
|
8224
8872
|
const currentIndex = fields.indexOf(focusedField);
|
|
8225
8873
|
setFocusedField(fields[(currentIndex + 1) % fields.length]);
|
|
8226
8874
|
} else if (key.return) {
|
|
8227
8875
|
handleConvert();
|
|
8228
|
-
} else if (
|
|
8876
|
+
} else if (input5 === "c" && result) {
|
|
8229
8877
|
handleCopy();
|
|
8230
8878
|
}
|
|
8231
8879
|
});
|
|
@@ -8344,7 +8992,7 @@ var HttpView = () => {
|
|
|
8344
8992
|
const [focusedField, setFocusedField] = useState23("url");
|
|
8345
8993
|
const [copied, setCopied] = useState23(false);
|
|
8346
8994
|
const service = new UtilsService();
|
|
8347
|
-
useInput21((
|
|
8995
|
+
useInput21((input5, key) => {
|
|
8348
8996
|
if (loading) return;
|
|
8349
8997
|
if (key.tab) {
|
|
8350
8998
|
const fields = ["url", "method", "headers", "body", "send"];
|
|
@@ -8358,7 +9006,7 @@ var HttpView = () => {
|
|
|
8358
9006
|
setMethod(METHODS[(currentIndex + 1) % METHODS.length]);
|
|
8359
9007
|
} else if (key.return && focusedField === "send") {
|
|
8360
9008
|
handleSend();
|
|
8361
|
-
} else if (
|
|
9009
|
+
} else if (input5 === "c" && response) {
|
|
8362
9010
|
handleCopy();
|
|
8363
9011
|
}
|
|
8364
9012
|
});
|
|
@@ -8482,14 +9130,14 @@ var HttpView = () => {
|
|
|
8482
9130
|
import React37, { useState as useState24 } from "react";
|
|
8483
9131
|
import { Box as Box27, Text as Text28, useInput as useInput22 } from "ink";
|
|
8484
9132
|
import TextInput14 from "ink-text-input";
|
|
8485
|
-
import * as
|
|
8486
|
-
import * as
|
|
9133
|
+
import * as fs12 from "fs";
|
|
9134
|
+
import * as path7 from "path";
|
|
8487
9135
|
var MarkdownView = () => {
|
|
8488
9136
|
const [filePath, setFilePath] = useState24("");
|
|
8489
9137
|
const [content, setContent] = useState24("");
|
|
8490
9138
|
const [error, setError] = useState24("");
|
|
8491
9139
|
const [focusedField, setFocusedField] = useState24("file");
|
|
8492
|
-
useInput22((
|
|
9140
|
+
useInput22((input5, key) => {
|
|
8493
9141
|
if (key.tab) {
|
|
8494
9142
|
setFocusedField(focusedField === "file" ? "preview" : "file");
|
|
8495
9143
|
} else if (key.return) {
|
|
@@ -8503,12 +9151,12 @@ var MarkdownView = () => {
|
|
|
8503
9151
|
}
|
|
8504
9152
|
try {
|
|
8505
9153
|
setError("");
|
|
8506
|
-
const resolvedPath =
|
|
8507
|
-
if (!
|
|
9154
|
+
const resolvedPath = path7.resolve(filePath);
|
|
9155
|
+
if (!fs12.existsSync(resolvedPath)) {
|
|
8508
9156
|
setError(`File not found: ${resolvedPath}`);
|
|
8509
9157
|
return;
|
|
8510
9158
|
}
|
|
8511
|
-
let fileContent =
|
|
9159
|
+
let fileContent = fs12.readFileSync(resolvedPath, "utf-8");
|
|
8512
9160
|
fileContent = fileContent.replace(/```mermaid\n([\s\S]*?)```/g, (match, code) => {
|
|
8513
9161
|
return `
|
|
8514
9162
|
\u{1F3A8} **Mermaid Diagram**
|
|
@@ -8604,20 +9252,20 @@ var UtilsApp = ({ onExit }) => {
|
|
|
8604
9252
|
const [selectedIndex, setSelectedIndex] = useState25(0);
|
|
8605
9253
|
const [activeView, setActiveView] = useState25(null);
|
|
8606
9254
|
const { exit } = useApp5();
|
|
8607
|
-
useInput23((
|
|
9255
|
+
useInput23((input5, key) => {
|
|
8608
9256
|
if (activeView) {
|
|
8609
9257
|
if (key.escape) {
|
|
8610
9258
|
setActiveView(null);
|
|
8611
9259
|
}
|
|
8612
9260
|
return;
|
|
8613
9261
|
}
|
|
8614
|
-
if (key.upArrow ||
|
|
9262
|
+
if (key.upArrow || input5 === "k") {
|
|
8615
9263
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : MENU_ITEMS2.length - 1);
|
|
8616
|
-
} else if (key.downArrow ||
|
|
9264
|
+
} else if (key.downArrow || input5 === "j") {
|
|
8617
9265
|
setSelectedIndex((prev) => prev < MENU_ITEMS2.length - 1 ? prev + 1 : 0);
|
|
8618
9266
|
} else if (key.return) {
|
|
8619
9267
|
setActiveView(MENU_ITEMS2[selectedIndex].id);
|
|
8620
|
-
} else if (
|
|
9268
|
+
} else if (input5 === "q" || key.escape) {
|
|
8621
9269
|
onExit();
|
|
8622
9270
|
exit();
|
|
8623
9271
|
}
|
|
@@ -8747,7 +9395,7 @@ async function runInteractiveMode() {
|
|
|
8747
9395
|
|
|
8748
9396
|
// src/commands/utils/index.ts
|
|
8749
9397
|
function createUtilsCommand() {
|
|
8750
|
-
const utilsCommand = new
|
|
9398
|
+
const utilsCommand = new Command35("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
|
|
8751
9399
|
Interactive Mode:
|
|
8752
9400
|
$ jai1 utils --interactive
|
|
8753
9401
|
$ jai1 utils -i
|
|
@@ -8782,15 +9430,15 @@ Quick Usage:
|
|
|
8782
9430
|
}
|
|
8783
9431
|
|
|
8784
9432
|
// src/commands/deps/index.ts
|
|
8785
|
-
import { Command as
|
|
9433
|
+
import { Command as Command37 } from "commander";
|
|
8786
9434
|
|
|
8787
9435
|
// src/commands/deps/upgrade.ts
|
|
8788
|
-
import { Command as
|
|
8789
|
-
import { checkbox as checkbox3, confirm as
|
|
9436
|
+
import { Command as Command36 } from "commander";
|
|
9437
|
+
import { checkbox as checkbox3, confirm as confirm6 } from "@inquirer/prompts";
|
|
8790
9438
|
|
|
8791
9439
|
// src/services/deps.service.ts
|
|
8792
|
-
import { promises as
|
|
8793
|
-
import
|
|
9440
|
+
import { promises as fs13 } from "fs";
|
|
9441
|
+
import path8 from "path";
|
|
8794
9442
|
import { execSync } from "child_process";
|
|
8795
9443
|
import pLimit2 from "p-limit";
|
|
8796
9444
|
var DepsService = class {
|
|
@@ -8799,9 +9447,9 @@ var DepsService = class {
|
|
|
8799
9447
|
* Đọc package.json từ thư mục
|
|
8800
9448
|
*/
|
|
8801
9449
|
async readPackageJson(cwd) {
|
|
8802
|
-
const pkgPath =
|
|
9450
|
+
const pkgPath = path8.join(cwd, "package.json");
|
|
8803
9451
|
try {
|
|
8804
|
-
const content = await
|
|
9452
|
+
const content = await fs13.readFile(pkgPath, "utf-8");
|
|
8805
9453
|
return JSON.parse(content);
|
|
8806
9454
|
} catch (error) {
|
|
8807
9455
|
if (error.code === "ENOENT") {
|
|
@@ -8907,7 +9555,7 @@ var DepsService = class {
|
|
|
8907
9555
|
];
|
|
8908
9556
|
for (const { file, pm } of lockFiles) {
|
|
8909
9557
|
try {
|
|
8910
|
-
await
|
|
9558
|
+
await fs13.access(path8.join(cwd, file));
|
|
8911
9559
|
return pm;
|
|
8912
9560
|
} catch {
|
|
8913
9561
|
}
|
|
@@ -8999,7 +9647,7 @@ var colors2 = {
|
|
|
8999
9647
|
dim: "\x1B[2m"
|
|
9000
9648
|
};
|
|
9001
9649
|
function createDepsUpgradeCommand() {
|
|
9002
|
-
return new
|
|
9650
|
+
return new Command36("upgrade").description("Upgrade npm packages l\xEAn version m\u1EDBi nh\u1EA5t").option("--check", "Ch\u1EC9 ki\u1EC3m tra, kh\xF4ng upgrade").option("--all", "Upgrade t\u1EA5t c\u1EA3 kh\xF4ng c\u1EA7n ch\u1ECDn").option("--deps-only", "Ch\u1EC9 upgrade dependencies").option("--dev-only", "Ch\u1EC9 upgrade devDependencies").action(async (options) => {
|
|
9003
9651
|
await handleDepsUpgrade(options);
|
|
9004
9652
|
});
|
|
9005
9653
|
}
|
|
@@ -9091,7 +9739,7 @@ ${colors2.yellow}\u23F8\uFE0F \u0110\xE3 h\u1EE7y${colors2.reset}
|
|
|
9091
9739
|
}
|
|
9092
9740
|
let shouldProceed;
|
|
9093
9741
|
try {
|
|
9094
|
-
shouldProceed = await
|
|
9742
|
+
shouldProceed = await confirm6({
|
|
9095
9743
|
message: `Ti\u1EBFn h\xE0nh upgrade ${selectedPackages.length} packages?`,
|
|
9096
9744
|
default: true
|
|
9097
9745
|
});
|
|
@@ -9179,20 +9827,20 @@ function displayUpgradeTable(packages) {
|
|
|
9179
9827
|
|
|
9180
9828
|
// src/commands/deps/index.ts
|
|
9181
9829
|
function createDepsCommand() {
|
|
9182
|
-
const depsCommand = new
|
|
9830
|
+
const depsCommand = new Command37("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
|
|
9183
9831
|
depsCommand.addCommand(createDepsUpgradeCommand());
|
|
9184
9832
|
return depsCommand;
|
|
9185
9833
|
}
|
|
9186
9834
|
|
|
9187
9835
|
// src/commands/kit/index.ts
|
|
9188
|
-
import { Command as
|
|
9836
|
+
import { Command as Command41 } from "commander";
|
|
9189
9837
|
|
|
9190
9838
|
// src/commands/kit/list.ts
|
|
9191
|
-
import { Command as
|
|
9839
|
+
import { Command as Command38 } from "commander";
|
|
9192
9840
|
|
|
9193
9841
|
// src/services/starter-kit.service.ts
|
|
9194
|
-
import { promises as
|
|
9195
|
-
import { join as
|
|
9842
|
+
import { promises as fs14 } from "fs";
|
|
9843
|
+
import { join as join6 } from "path";
|
|
9196
9844
|
import AdmZip from "adm-zip";
|
|
9197
9845
|
var StarterKitService = class {
|
|
9198
9846
|
/**
|
|
@@ -9239,23 +9887,23 @@ var StarterKitService = class {
|
|
|
9239
9887
|
throw new NetworkError(`Failed to download kit: HTTP ${response.status}`);
|
|
9240
9888
|
}
|
|
9241
9889
|
if (onProgress) onProgress(30);
|
|
9242
|
-
const tmpDir =
|
|
9243
|
-
await
|
|
9244
|
-
const tmpFile =
|
|
9890
|
+
const tmpDir = join6(process.env.TMPDIR || "/tmp", "jai1-kits");
|
|
9891
|
+
await fs14.mkdir(tmpDir, { recursive: true });
|
|
9892
|
+
const tmpFile = join6(tmpDir, `${slug}.zip`);
|
|
9245
9893
|
const buffer = await response.arrayBuffer();
|
|
9246
|
-
await
|
|
9894
|
+
await fs14.writeFile(tmpFile, Buffer.from(buffer));
|
|
9247
9895
|
if (onProgress) onProgress(60);
|
|
9248
9896
|
const zip = new AdmZip(tmpFile);
|
|
9249
|
-
await
|
|
9897
|
+
await fs14.mkdir(targetDir, { recursive: true });
|
|
9250
9898
|
zip.extractAllTo(targetDir, true);
|
|
9251
9899
|
if (onProgress) onProgress(100);
|
|
9252
|
-
await
|
|
9900
|
+
await fs14.unlink(tmpFile);
|
|
9253
9901
|
}
|
|
9254
9902
|
};
|
|
9255
9903
|
|
|
9256
9904
|
// src/commands/kit/list.ts
|
|
9257
9905
|
function createKitListCommand() {
|
|
9258
|
-
return new
|
|
9906
|
+
return new Command38("list").description("List available starter kits").option("-c, --category <category>", "Filter by category (backend, frontend, fullstack)").option("-s, --search <term>", "Search kits by name or description").action(async (options) => {
|
|
9259
9907
|
const configService = new ConfigService();
|
|
9260
9908
|
const config = await configService.load();
|
|
9261
9909
|
if (!config) {
|
|
@@ -9292,9 +9940,9 @@ function createKitListCommand() {
|
|
|
9292
9940
|
}
|
|
9293
9941
|
|
|
9294
9942
|
// src/commands/kit/info.ts
|
|
9295
|
-
import { Command as
|
|
9943
|
+
import { Command as Command39 } from "commander";
|
|
9296
9944
|
function createKitInfoCommand() {
|
|
9297
|
-
return new
|
|
9945
|
+
return new Command39("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
|
|
9298
9946
|
const configService = new ConfigService();
|
|
9299
9947
|
const config = await configService.load();
|
|
9300
9948
|
if (!config) {
|
|
@@ -9343,10 +9991,10 @@ Post-Init Commands:`);
|
|
|
9343
9991
|
}
|
|
9344
9992
|
|
|
9345
9993
|
// src/commands/kit/create.ts
|
|
9346
|
-
import { Command as
|
|
9347
|
-
import { promises as
|
|
9348
|
-
import { join as
|
|
9349
|
-
import { select as
|
|
9994
|
+
import { Command as Command40 } from "commander";
|
|
9995
|
+
import { promises as fs15 } from "fs";
|
|
9996
|
+
import { join as join7 } from "path";
|
|
9997
|
+
import { select as select3, input as input2, checkbox as checkbox4 } from "@inquirer/prompts";
|
|
9350
9998
|
import { execa as execa2 } from "execa";
|
|
9351
9999
|
|
|
9352
10000
|
// src/services/hook-executor.service.ts
|
|
@@ -9388,7 +10036,7 @@ var HookExecutor = class {
|
|
|
9388
10036
|
|
|
9389
10037
|
// src/commands/kit/create.ts
|
|
9390
10038
|
function createKitCreateCommand() {
|
|
9391
|
-
return new
|
|
10039
|
+
return new Command40("create").description("Create a new project from a starter kit").argument("<slug>", "Starter kit slug").argument("[directory]", "Project directory (default: ./<slug>)").option("-y, --yes", "Auto mode - use defaults, no prompts").option("--name <name>", "Project name").option("--skip-install", "Skip dependency installation").option("--skip-git", "Skip git initialization").option("--skip-framework", "Skip framework apply").option("--skip-ide", "Skip IDE sync").action(async (slug, directory, options) => {
|
|
9392
10040
|
const configService = new ConfigService();
|
|
9393
10041
|
const config = await configService.load();
|
|
9394
10042
|
if (!config) {
|
|
@@ -9408,9 +10056,9 @@ function createKitCreateCommand() {
|
|
|
9408
10056
|
}
|
|
9409
10057
|
}
|
|
9410
10058
|
}
|
|
9411
|
-
const targetDir = directory ||
|
|
10059
|
+
const targetDir = directory || join7(process.cwd(), options.name || slug);
|
|
9412
10060
|
try {
|
|
9413
|
-
await
|
|
10061
|
+
await fs15.access(targetDir);
|
|
9414
10062
|
throw new Error(`Directory already exists: ${targetDir}`);
|
|
9415
10063
|
} catch (error) {
|
|
9416
10064
|
if (error.code !== "ENOENT") {
|
|
@@ -9444,14 +10092,14 @@ function createKitCreateCommand() {
|
|
|
9444
10092
|
console.log("\u{1F4DD} Please provide project details:");
|
|
9445
10093
|
for (const v of kit.config.variables) {
|
|
9446
10094
|
if (v.type === "select" && v.options) {
|
|
9447
|
-
const answer = await
|
|
10095
|
+
const answer = await select3({
|
|
9448
10096
|
message: v.prompt,
|
|
9449
10097
|
choices: v.options.map((opt) => ({ name: opt, value: opt })),
|
|
9450
10098
|
default: v.default
|
|
9451
10099
|
});
|
|
9452
10100
|
variables[v.name] = answer;
|
|
9453
10101
|
} else {
|
|
9454
|
-
const answer = await
|
|
10102
|
+
const answer = await input2({
|
|
9455
10103
|
message: v.prompt,
|
|
9456
10104
|
default: v.default
|
|
9457
10105
|
});
|
|
@@ -9528,7 +10176,7 @@ function createKitCreateCommand() {
|
|
|
9528
10176
|
async function applyVariableSubstitution(dir, variables) {
|
|
9529
10177
|
const files = await getAllFiles(dir);
|
|
9530
10178
|
for (const file of files) {
|
|
9531
|
-
let content = await
|
|
10179
|
+
let content = await fs15.readFile(file, "utf-8");
|
|
9532
10180
|
let modified = false;
|
|
9533
10181
|
for (const [key, value] of Object.entries(variables)) {
|
|
9534
10182
|
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
@@ -9538,15 +10186,15 @@ async function applyVariableSubstitution(dir, variables) {
|
|
|
9538
10186
|
}
|
|
9539
10187
|
}
|
|
9540
10188
|
if (modified) {
|
|
9541
|
-
await
|
|
10189
|
+
await fs15.writeFile(file, content, "utf-8");
|
|
9542
10190
|
}
|
|
9543
10191
|
}
|
|
9544
10192
|
}
|
|
9545
10193
|
async function getAllFiles(dir) {
|
|
9546
10194
|
const files = [];
|
|
9547
|
-
const entries = await
|
|
10195
|
+
const entries = await fs15.readdir(dir, { withFileTypes: true });
|
|
9548
10196
|
for (const entry of entries) {
|
|
9549
|
-
const fullPath =
|
|
10197
|
+
const fullPath = join7(dir, entry.name);
|
|
9550
10198
|
if (entry.isDirectory()) {
|
|
9551
10199
|
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
9552
10200
|
files.push(...await getAllFiles(fullPath));
|
|
@@ -9560,7 +10208,7 @@ async function getAllFiles(dir) {
|
|
|
9560
10208
|
|
|
9561
10209
|
// src/commands/kit/index.ts
|
|
9562
10210
|
function createKitCommand() {
|
|
9563
|
-
const cmd = new
|
|
10211
|
+
const cmd = new Command41("kit").description("Manage starter kits for new projects").action(() => {
|
|
9564
10212
|
cmd.help();
|
|
9565
10213
|
});
|
|
9566
10214
|
cmd.addCommand(createKitListCommand());
|
|
@@ -9570,12 +10218,12 @@ function createKitCommand() {
|
|
|
9570
10218
|
}
|
|
9571
10219
|
|
|
9572
10220
|
// src/commands/rules/index.ts
|
|
9573
|
-
import { Command as
|
|
10221
|
+
import { Command as Command48 } from "commander";
|
|
9574
10222
|
|
|
9575
10223
|
// src/commands/rules/list.ts
|
|
9576
|
-
import { Command as
|
|
10224
|
+
import { Command as Command42 } from "commander";
|
|
9577
10225
|
function createRulesListCommand() {
|
|
9578
|
-
return new
|
|
10226
|
+
return new Command42("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
|
|
9579
10227
|
const configService = new ConfigService();
|
|
9580
10228
|
const config = await configService.load();
|
|
9581
10229
|
if (!config) {
|
|
@@ -9630,12 +10278,12 @@ function createRulesListCommand() {
|
|
|
9630
10278
|
}
|
|
9631
10279
|
|
|
9632
10280
|
// src/commands/rules/init.ts
|
|
9633
|
-
import { Command as
|
|
9634
|
-
import { promises as
|
|
9635
|
-
import { join as
|
|
9636
|
-
import { select as
|
|
10281
|
+
import { Command as Command43 } from "commander";
|
|
10282
|
+
import { promises as fs16 } from "fs";
|
|
10283
|
+
import { join as join8 } from "path";
|
|
10284
|
+
import { select as select4, confirm as confirm7 } from "@inquirer/prompts";
|
|
9637
10285
|
function createRulesInitCommand() {
|
|
9638
|
-
return new
|
|
10286
|
+
return new Command43("init").description("Apply rule preset to project").option("--preset <slug>", "Preset slug to apply").option("--output <format>", "Output format: cursor, agents-md, both (default: cursor)", "cursor").option("-y, --yes", "Skip confirmations").action(async (options) => {
|
|
9639
10287
|
const configService = new ConfigService();
|
|
9640
10288
|
const config = await configService.load();
|
|
9641
10289
|
if (!config) {
|
|
@@ -9657,7 +10305,7 @@ function createRulesInitCommand() {
|
|
|
9657
10305
|
console.log("No presets available.");
|
|
9658
10306
|
return;
|
|
9659
10307
|
}
|
|
9660
|
-
presetSlug = await
|
|
10308
|
+
presetSlug = await select4({
|
|
9661
10309
|
message: "Select a preset:",
|
|
9662
10310
|
choices: data.presets.map((p) => ({
|
|
9663
10311
|
name: `${p.name} - ${p.description}`,
|
|
@@ -9685,7 +10333,7 @@ function createRulesInitCommand() {
|
|
|
9685
10333
|
console.log(` Files: ${Object.keys(bundle.files).length}`);
|
|
9686
10334
|
let outputFormat = options.output;
|
|
9687
10335
|
if (!["cursor", "agents-md", "both"].includes(outputFormat)) {
|
|
9688
|
-
outputFormat = await
|
|
10336
|
+
outputFormat = await select4({
|
|
9689
10337
|
message: "Select output format:",
|
|
9690
10338
|
choices: [
|
|
9691
10339
|
{ name: "Cursor (.cursor/rules/)", value: "cursor" },
|
|
@@ -9695,7 +10343,7 @@ function createRulesInitCommand() {
|
|
|
9695
10343
|
});
|
|
9696
10344
|
}
|
|
9697
10345
|
if (!options.yes) {
|
|
9698
|
-
const proceed = await
|
|
10346
|
+
const proceed = await confirm7({
|
|
9699
10347
|
message: `Apply preset '${bundle.preset.name}' to current directory?`,
|
|
9700
10348
|
default: true
|
|
9701
10349
|
});
|
|
@@ -9717,7 +10365,7 @@ function createRulesInitCommand() {
|
|
|
9717
10365
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9718
10366
|
customContext: "09-custom.mdc"
|
|
9719
10367
|
};
|
|
9720
|
-
await
|
|
10368
|
+
await fs16.writeFile("jai1-rules.json", JSON.stringify(projectConfig, null, 2));
|
|
9721
10369
|
console.log("\u2713 Created jai1-rules.json");
|
|
9722
10370
|
console.log("\n\u2705 Preset applied successfully!\n");
|
|
9723
10371
|
console.log("Next steps:");
|
|
@@ -9727,11 +10375,11 @@ function createRulesInitCommand() {
|
|
|
9727
10375
|
});
|
|
9728
10376
|
}
|
|
9729
10377
|
async function applyCursorFormat(bundle) {
|
|
9730
|
-
const rulesDir =
|
|
9731
|
-
await
|
|
10378
|
+
const rulesDir = join8(process.cwd(), ".cursor", "rules");
|
|
10379
|
+
await fs16.mkdir(rulesDir, { recursive: true });
|
|
9732
10380
|
for (const [filename, content] of Object.entries(bundle.files)) {
|
|
9733
|
-
const filePath =
|
|
9734
|
-
await
|
|
10381
|
+
const filePath = join8(rulesDir, filename);
|
|
10382
|
+
await fs16.writeFile(filePath, content, "utf-8");
|
|
9735
10383
|
console.log(`\u2713 Created .cursor/rules/${filename}`);
|
|
9736
10384
|
}
|
|
9737
10385
|
}
|
|
@@ -9758,15 +10406,15 @@ async function applyAgentsMdFormat(bundle) {
|
|
|
9758
10406
|
}
|
|
9759
10407
|
}
|
|
9760
10408
|
const agentsMd = sections.join("\n");
|
|
9761
|
-
await
|
|
10409
|
+
await fs16.writeFile("AGENTS.md", agentsMd, "utf-8");
|
|
9762
10410
|
console.log("\u2713 Created AGENTS.md");
|
|
9763
10411
|
}
|
|
9764
10412
|
|
|
9765
10413
|
// src/commands/rules/apply.ts
|
|
9766
|
-
import { Command as
|
|
9767
|
-
import { promises as
|
|
9768
|
-
import { join as
|
|
9769
|
-
import { select as
|
|
10414
|
+
import { Command as Command44 } from "commander";
|
|
10415
|
+
import { promises as fs18 } from "fs";
|
|
10416
|
+
import { join as join10 } from "path";
|
|
10417
|
+
import { select as select5, confirm as confirm8, checkbox as checkbox5 } from "@inquirer/prompts";
|
|
9770
10418
|
|
|
9771
10419
|
// src/services/rules-generator.service.ts
|
|
9772
10420
|
var RulesGeneratorService = class {
|
|
@@ -10125,8 +10773,8 @@ Follow all instructions and patterns defined in AGENTS.md above.
|
|
|
10125
10773
|
};
|
|
10126
10774
|
|
|
10127
10775
|
// src/services/backup.service.ts
|
|
10128
|
-
import { promises as
|
|
10129
|
-
import { join as
|
|
10776
|
+
import { promises as fs17 } from "fs";
|
|
10777
|
+
import { join as join9, dirname } from "path";
|
|
10130
10778
|
var BackupService = class {
|
|
10131
10779
|
backupDir = ".jai1/backups";
|
|
10132
10780
|
/**
|
|
@@ -10134,7 +10782,7 @@ var BackupService = class {
|
|
|
10134
10782
|
*/
|
|
10135
10783
|
async createBackup(ides, presetSlug) {
|
|
10136
10784
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10137
|
-
const backupPath =
|
|
10785
|
+
const backupPath = join9(this.backupDir, timestamp);
|
|
10138
10786
|
const backedUpFiles = [];
|
|
10139
10787
|
let hasContent = false;
|
|
10140
10788
|
for (const ideId of ides) {
|
|
@@ -10143,7 +10791,7 @@ var BackupService = class {
|
|
|
10143
10791
|
console.warn(`Unknown IDE format: ${ideId}, skipping backup`);
|
|
10144
10792
|
continue;
|
|
10145
10793
|
}
|
|
10146
|
-
const rulesPath = format.rulesPath === "." ? process.cwd() :
|
|
10794
|
+
const rulesPath = format.rulesPath === "." ? process.cwd() : join9(process.cwd(), format.rulesPath);
|
|
10147
10795
|
try {
|
|
10148
10796
|
const exists = await this.pathExists(rulesPath);
|
|
10149
10797
|
if (!exists) {
|
|
@@ -10156,19 +10804,19 @@ var BackupService = class {
|
|
|
10156
10804
|
await this.backupSingleFile("GEMINI.md", backupPath, ideId, backedUpFiles);
|
|
10157
10805
|
hasContent = true;
|
|
10158
10806
|
} else {
|
|
10159
|
-
const stats = await
|
|
10807
|
+
const stats = await fs17.stat(rulesPath);
|
|
10160
10808
|
if (stats.isDirectory()) {
|
|
10161
|
-
const files = await
|
|
10809
|
+
const files = await fs17.readdir(rulesPath);
|
|
10162
10810
|
for (const file of files) {
|
|
10163
10811
|
if (file.endsWith(format.fileExtension)) {
|
|
10164
|
-
const originalPath =
|
|
10165
|
-
const relativePath =
|
|
10166
|
-
const destPath =
|
|
10167
|
-
await
|
|
10168
|
-
await
|
|
10812
|
+
const originalPath = join9(rulesPath, file);
|
|
10813
|
+
const relativePath = join9(format.rulesPath, file);
|
|
10814
|
+
const destPath = join9(backupPath, ideId, file);
|
|
10815
|
+
await fs17.mkdir(dirname(destPath), { recursive: true });
|
|
10816
|
+
await fs17.copyFile(originalPath, destPath);
|
|
10169
10817
|
backedUpFiles.push({
|
|
10170
10818
|
originalPath: relativePath,
|
|
10171
|
-
backupPath:
|
|
10819
|
+
backupPath: join9(ideId, file),
|
|
10172
10820
|
ide: ideId
|
|
10173
10821
|
});
|
|
10174
10822
|
hasContent = true;
|
|
@@ -10189,9 +10837,9 @@ var BackupService = class {
|
|
|
10189
10837
|
ides,
|
|
10190
10838
|
files: backedUpFiles
|
|
10191
10839
|
};
|
|
10192
|
-
await
|
|
10193
|
-
await
|
|
10194
|
-
|
|
10840
|
+
await fs17.mkdir(backupPath, { recursive: true });
|
|
10841
|
+
await fs17.writeFile(
|
|
10842
|
+
join9(backupPath, "metadata.json"),
|
|
10195
10843
|
JSON.stringify(metadata, null, 2),
|
|
10196
10844
|
"utf-8"
|
|
10197
10845
|
);
|
|
@@ -10201,18 +10849,18 @@ var BackupService = class {
|
|
|
10201
10849
|
* Backup a single file (for AGENTS.md, GEMINI.md)
|
|
10202
10850
|
*/
|
|
10203
10851
|
async backupSingleFile(filename, backupPath, ideId, backedUpFiles) {
|
|
10204
|
-
const originalPath =
|
|
10852
|
+
const originalPath = join9(process.cwd(), filename);
|
|
10205
10853
|
try {
|
|
10206
10854
|
const exists = await this.pathExists(originalPath);
|
|
10207
10855
|
if (!exists) {
|
|
10208
10856
|
return;
|
|
10209
10857
|
}
|
|
10210
|
-
const destPath =
|
|
10211
|
-
await
|
|
10212
|
-
await
|
|
10858
|
+
const destPath = join9(backupPath, ideId, filename);
|
|
10859
|
+
await fs17.mkdir(dirname(destPath), { recursive: true });
|
|
10860
|
+
await fs17.copyFile(originalPath, destPath);
|
|
10213
10861
|
backedUpFiles.push({
|
|
10214
10862
|
originalPath: filename,
|
|
10215
|
-
backupPath:
|
|
10863
|
+
backupPath: join9(ideId, filename),
|
|
10216
10864
|
ide: ideId
|
|
10217
10865
|
});
|
|
10218
10866
|
} catch (error) {
|
|
@@ -10222,16 +10870,16 @@ var BackupService = class {
|
|
|
10222
10870
|
* Restore files from a backup
|
|
10223
10871
|
*/
|
|
10224
10872
|
async restoreBackup(backupPath) {
|
|
10225
|
-
const metadataPath =
|
|
10226
|
-
const metadataContent = await
|
|
10873
|
+
const metadataPath = join9(backupPath, "metadata.json");
|
|
10874
|
+
const metadataContent = await fs17.readFile(metadataPath, "utf-8");
|
|
10227
10875
|
const metadata = JSON.parse(metadataContent);
|
|
10228
10876
|
console.log(`
|
|
10229
10877
|
Restoring backup from ${metadata.timestamp}...`);
|
|
10230
10878
|
for (const file of metadata.files) {
|
|
10231
|
-
const sourcePath =
|
|
10232
|
-
const destPath =
|
|
10233
|
-
await
|
|
10234
|
-
await
|
|
10879
|
+
const sourcePath = join9(backupPath, file.backupPath);
|
|
10880
|
+
const destPath = join9(process.cwd(), file.originalPath);
|
|
10881
|
+
await fs17.mkdir(dirname(destPath), { recursive: true });
|
|
10882
|
+
await fs17.copyFile(sourcePath, destPath);
|
|
10235
10883
|
console.log(`\u2713 Restored ${file.originalPath}`);
|
|
10236
10884
|
}
|
|
10237
10885
|
console.log("\n\u2705 Backup restored successfully!");
|
|
@@ -10241,18 +10889,18 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10241
10889
|
*/
|
|
10242
10890
|
async listBackups() {
|
|
10243
10891
|
try {
|
|
10244
|
-
const backupDirPath =
|
|
10892
|
+
const backupDirPath = join9(process.cwd(), this.backupDir);
|
|
10245
10893
|
const exists = await this.pathExists(backupDirPath);
|
|
10246
10894
|
if (!exists) {
|
|
10247
10895
|
return [];
|
|
10248
10896
|
}
|
|
10249
|
-
const entries = await
|
|
10897
|
+
const entries = await fs17.readdir(backupDirPath, { withFileTypes: true });
|
|
10250
10898
|
const backups = [];
|
|
10251
10899
|
for (const entry of entries) {
|
|
10252
10900
|
if (entry.isDirectory()) {
|
|
10253
|
-
const metadataPath =
|
|
10901
|
+
const metadataPath = join9(backupDirPath, entry.name, "metadata.json");
|
|
10254
10902
|
try {
|
|
10255
|
-
const metadataContent = await
|
|
10903
|
+
const metadataContent = await fs17.readFile(metadataPath, "utf-8");
|
|
10256
10904
|
const metadata = JSON.parse(metadataContent);
|
|
10257
10905
|
backups.push(metadata);
|
|
10258
10906
|
} catch {
|
|
@@ -10269,7 +10917,7 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10269
10917
|
* Delete a specific backup
|
|
10270
10918
|
*/
|
|
10271
10919
|
async deleteBackup(timestamp) {
|
|
10272
|
-
const backupPath =
|
|
10920
|
+
const backupPath = join9(process.cwd(), this.backupDir, timestamp);
|
|
10273
10921
|
await this.deleteDirectory(backupPath);
|
|
10274
10922
|
}
|
|
10275
10923
|
/**
|
|
@@ -10299,9 +10947,9 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10299
10947
|
/**
|
|
10300
10948
|
* Check if a path exists
|
|
10301
10949
|
*/
|
|
10302
|
-
async pathExists(
|
|
10950
|
+
async pathExists(path10) {
|
|
10303
10951
|
try {
|
|
10304
|
-
await
|
|
10952
|
+
await fs17.access(path10);
|
|
10305
10953
|
return true;
|
|
10306
10954
|
} catch {
|
|
10307
10955
|
return false;
|
|
@@ -10310,22 +10958,22 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10310
10958
|
/**
|
|
10311
10959
|
* Recursively delete a directory
|
|
10312
10960
|
*/
|
|
10313
|
-
async deleteDirectory(
|
|
10961
|
+
async deleteDirectory(path10) {
|
|
10314
10962
|
try {
|
|
10315
|
-
const exists = await this.pathExists(
|
|
10963
|
+
const exists = await this.pathExists(path10);
|
|
10316
10964
|
if (!exists) {
|
|
10317
10965
|
return;
|
|
10318
10966
|
}
|
|
10319
|
-
const entries = await
|
|
10967
|
+
const entries = await fs17.readdir(path10, { withFileTypes: true });
|
|
10320
10968
|
for (const entry of entries) {
|
|
10321
|
-
const fullPath =
|
|
10969
|
+
const fullPath = join9(path10, entry.name);
|
|
10322
10970
|
if (entry.isDirectory()) {
|
|
10323
10971
|
await this.deleteDirectory(fullPath);
|
|
10324
10972
|
} else {
|
|
10325
|
-
await
|
|
10973
|
+
await fs17.unlink(fullPath);
|
|
10326
10974
|
}
|
|
10327
10975
|
}
|
|
10328
|
-
await
|
|
10976
|
+
await fs17.rmdir(path10);
|
|
10329
10977
|
} catch (error) {
|
|
10330
10978
|
}
|
|
10331
10979
|
}
|
|
@@ -10333,20 +10981,20 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10333
10981
|
* Get backup directory path
|
|
10334
10982
|
*/
|
|
10335
10983
|
getBackupDir() {
|
|
10336
|
-
return
|
|
10984
|
+
return join9(process.cwd(), this.backupDir);
|
|
10337
10985
|
}
|
|
10338
10986
|
/**
|
|
10339
10987
|
* Ensure backup directory exists
|
|
10340
10988
|
*/
|
|
10341
10989
|
async ensureBackupDir() {
|
|
10342
|
-
const backupDirPath =
|
|
10343
|
-
await
|
|
10990
|
+
const backupDirPath = join9(process.cwd(), this.backupDir);
|
|
10991
|
+
await fs17.mkdir(backupDirPath, { recursive: true });
|
|
10344
10992
|
}
|
|
10345
10993
|
};
|
|
10346
10994
|
|
|
10347
10995
|
// src/commands/rules/apply.ts
|
|
10348
10996
|
function createRulesApplyCommand() {
|
|
10349
|
-
return new
|
|
10997
|
+
return new Command44("apply").description("Apply rule preset to project with multi-IDE support").argument("[preset]", "Preset slug to apply (optional)").option("--ides <ides>", "Comma-separated list of IDE formats (cursor,windsurf,antigravity,claude,agentsmd,gemini)").option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
|
|
10350
10998
|
const configService = new ConfigService();
|
|
10351
10999
|
const config = await configService.load();
|
|
10352
11000
|
if (!config) {
|
|
@@ -10378,7 +11026,7 @@ function createRulesApplyCommand() {
|
|
|
10378
11026
|
console.log("No presets available.");
|
|
10379
11027
|
return;
|
|
10380
11028
|
}
|
|
10381
|
-
presetSlug = await
|
|
11029
|
+
presetSlug = await select5({
|
|
10382
11030
|
message: "Select a preset:",
|
|
10383
11031
|
choices: data.presets.map((p) => ({
|
|
10384
11032
|
name: `${p.name} - ${p.description}`,
|
|
@@ -10486,7 +11134,7 @@ function createRulesApplyCommand() {
|
|
|
10486
11134
|
if (backupPath) {
|
|
10487
11135
|
console.log(` Backup: ${backupPath}`);
|
|
10488
11136
|
}
|
|
10489
|
-
const proceed = await
|
|
11137
|
+
const proceed = await confirm8({
|
|
10490
11138
|
message: "Apply these rules to the current directory?",
|
|
10491
11139
|
default: true
|
|
10492
11140
|
});
|
|
@@ -10496,21 +11144,21 @@ function createRulesApplyCommand() {
|
|
|
10496
11144
|
}
|
|
10497
11145
|
}
|
|
10498
11146
|
console.log("\n\u{1F4DD} Applying preset...\n");
|
|
10499
|
-
const rulePresetDir =
|
|
11147
|
+
const rulePresetDir = join10(process.cwd(), ".jai1", "rule-preset");
|
|
10500
11148
|
try {
|
|
10501
|
-
await
|
|
11149
|
+
await fs18.rm(rulePresetDir, { recursive: true, force: true });
|
|
10502
11150
|
} catch {
|
|
10503
11151
|
}
|
|
10504
|
-
await
|
|
10505
|
-
await
|
|
10506
|
-
|
|
11152
|
+
await fs18.mkdir(rulePresetDir, { recursive: true });
|
|
11153
|
+
await fs18.writeFile(
|
|
11154
|
+
join10(rulePresetDir, "preset.json"),
|
|
10507
11155
|
JSON.stringify(bundle.preset, null, 2),
|
|
10508
11156
|
"utf-8"
|
|
10509
11157
|
);
|
|
10510
11158
|
for (const [filename, content] of Object.entries(bundle.files)) {
|
|
10511
|
-
const filePath =
|
|
10512
|
-
await
|
|
10513
|
-
await
|
|
11159
|
+
const filePath = join10(rulePresetDir, filename);
|
|
11160
|
+
await fs18.mkdir(join10(filePath, ".."), { recursive: true });
|
|
11161
|
+
await fs18.writeFile(filePath, content, "utf-8");
|
|
10514
11162
|
}
|
|
10515
11163
|
console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
|
|
10516
11164
|
const allGeneratedFiles = [];
|
|
@@ -10518,9 +11166,9 @@ function createRulesApplyCommand() {
|
|
|
10518
11166
|
try {
|
|
10519
11167
|
const files = generatorService.generateForIde(bundle, ideId);
|
|
10520
11168
|
for (const file of files) {
|
|
10521
|
-
const fullPath =
|
|
10522
|
-
await
|
|
10523
|
-
await
|
|
11169
|
+
const fullPath = join10(process.cwd(), file.path);
|
|
11170
|
+
await fs18.mkdir(join10(fullPath, ".."), { recursive: true });
|
|
11171
|
+
await fs18.writeFile(fullPath, file.content, "utf-8");
|
|
10524
11172
|
console.log(`\u2713 [${ideId}] ${file.path}`);
|
|
10525
11173
|
allGeneratedFiles.push({
|
|
10526
11174
|
ide: ideId,
|
|
@@ -10547,8 +11195,8 @@ function createRulesApplyCommand() {
|
|
|
10547
11195
|
] : []
|
|
10548
11196
|
};
|
|
10549
11197
|
try {
|
|
10550
|
-
const existingConfigPath =
|
|
10551
|
-
const existingConfigContent = await
|
|
11198
|
+
const existingConfigPath = join10(process.cwd(), "jai1-rules.json");
|
|
11199
|
+
const existingConfigContent = await fs18.readFile(existingConfigPath, "utf-8");
|
|
10552
11200
|
const existingConfig = JSON.parse(existingConfigContent);
|
|
10553
11201
|
if (existingConfig.backups && existingConfig.backups.length > 0) {
|
|
10554
11202
|
projectConfig.backups = [
|
|
@@ -10559,8 +11207,8 @@ function createRulesApplyCommand() {
|
|
|
10559
11207
|
}
|
|
10560
11208
|
} catch {
|
|
10561
11209
|
}
|
|
10562
|
-
await
|
|
10563
|
-
|
|
11210
|
+
await fs18.writeFile(
|
|
11211
|
+
join10(process.cwd(), "jai1-rules.json"),
|
|
10564
11212
|
JSON.stringify(projectConfig, null, 2),
|
|
10565
11213
|
"utf-8"
|
|
10566
11214
|
);
|
|
@@ -10591,11 +11239,11 @@ function createRulesApplyCommand() {
|
|
|
10591
11239
|
}
|
|
10592
11240
|
|
|
10593
11241
|
// src/commands/rules/restore.ts
|
|
10594
|
-
import { Command as
|
|
10595
|
-
import { join as
|
|
10596
|
-
import { select as
|
|
11242
|
+
import { Command as Command45 } from "commander";
|
|
11243
|
+
import { join as join11 } from "path";
|
|
11244
|
+
import { select as select6, confirm as confirm9 } from "@inquirer/prompts";
|
|
10597
11245
|
function createRulesRestoreCommand() {
|
|
10598
|
-
return new
|
|
11246
|
+
return new Command45("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
10599
11247
|
const backupService = new BackupService();
|
|
10600
11248
|
const backups = await backupService.listBackups();
|
|
10601
11249
|
if (backups.length === 0) {
|
|
@@ -10608,7 +11256,7 @@ function createRulesRestoreCommand() {
|
|
|
10608
11256
|
console.log(`\u{1F4E6} Selected latest backup: ${selectedBackup.timestamp}`);
|
|
10609
11257
|
} else {
|
|
10610
11258
|
console.log("\u{1F4CB} Available backups:\n");
|
|
10611
|
-
const backupTimestamp = await
|
|
11259
|
+
const backupTimestamp = await select6({
|
|
10612
11260
|
message: "Select a backup to restore:",
|
|
10613
11261
|
choices: backups.map((backup) => ({
|
|
10614
11262
|
name: formatBackupInfo(backup),
|
|
@@ -10627,7 +11275,7 @@ function createRulesRestoreCommand() {
|
|
|
10627
11275
|
console.log(` IDEs: ${selectedBackup.ides.join(", ")}`);
|
|
10628
11276
|
console.log(` Files: ${selectedBackup.files.length}`);
|
|
10629
11277
|
if (!options.yes) {
|
|
10630
|
-
const proceed = await
|
|
11278
|
+
const proceed = await confirm9({
|
|
10631
11279
|
message: "This will overwrite current rules. Continue?",
|
|
10632
11280
|
default: false
|
|
10633
11281
|
});
|
|
@@ -10638,7 +11286,7 @@ function createRulesRestoreCommand() {
|
|
|
10638
11286
|
}
|
|
10639
11287
|
console.log("\n\u{1F504} Restoring backup...\n");
|
|
10640
11288
|
try {
|
|
10641
|
-
const backupPath =
|
|
11289
|
+
const backupPath = join11(backupService.getBackupDir(), selectedBackup.timestamp);
|
|
10642
11290
|
await backupService.restoreBackup(backupPath);
|
|
10643
11291
|
console.log("\n\u2705 Backup restored successfully!\n");
|
|
10644
11292
|
console.log("\u{1F4A1} Tip: Your IDE may need to be restarted to pick up the changes.");
|
|
@@ -10663,16 +11311,16 @@ function formatTimestamp(timestamp) {
|
|
|
10663
11311
|
}
|
|
10664
11312
|
|
|
10665
11313
|
// src/commands/rules/sync.ts
|
|
10666
|
-
import { Command as
|
|
10667
|
-
import { promises as
|
|
10668
|
-
import { join as
|
|
10669
|
-
import { confirm as
|
|
11314
|
+
import { Command as Command46 } from "commander";
|
|
11315
|
+
import { promises as fs19 } from "fs";
|
|
11316
|
+
import { join as join12 } from "path";
|
|
11317
|
+
import { confirm as confirm10 } from "@inquirer/prompts";
|
|
10670
11318
|
function createRulesSyncCommand() {
|
|
10671
|
-
return new
|
|
10672
|
-
const configPath =
|
|
11319
|
+
return new Command46("sync").description("Regenerate rule outputs for all configured IDEs").option("--ides <ides>", "Comma-separated list of IDEs to sync (default: all configured)").option("--detect", "Auto-detect active IDEs instead of using config").option("-y, --yes", "Skip confirmations").action(async (options) => {
|
|
11320
|
+
const configPath = join12(process.cwd(), "jai1-rules.json");
|
|
10673
11321
|
let projectConfig;
|
|
10674
11322
|
try {
|
|
10675
|
-
const configContent = await
|
|
11323
|
+
const configContent = await fs19.readFile(configPath, "utf-8");
|
|
10676
11324
|
projectConfig = JSON.parse(configContent);
|
|
10677
11325
|
} catch {
|
|
10678
11326
|
throw new ValidationError(
|
|
@@ -10699,7 +11347,7 @@ Detected ${detected.length} active IDE(s):
|
|
|
10699
11347
|
console.log(` ${confidence} ${d.name} - ${d.ruleCount} rules`);
|
|
10700
11348
|
});
|
|
10701
11349
|
if (!options.yes) {
|
|
10702
|
-
const proceed = await
|
|
11350
|
+
const proceed = await confirm10({
|
|
10703
11351
|
message: "\nSync these detected IDEs?",
|
|
10704
11352
|
default: true
|
|
10705
11353
|
});
|
|
@@ -10752,14 +11400,14 @@ Detected ${detected.length} active IDE(s):
|
|
|
10752
11400
|
throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
|
|
10753
11401
|
}
|
|
10754
11402
|
const bundle = await presetResponse.json();
|
|
10755
|
-
const rulePresetDir =
|
|
11403
|
+
const rulePresetDir = join12(process.cwd(), ".jai1", "rule-preset");
|
|
10756
11404
|
const presetExists = await checkPathExists(rulePresetDir);
|
|
10757
11405
|
if (presetExists) {
|
|
10758
|
-
const files = await
|
|
11406
|
+
const files = await fs19.readdir(rulePresetDir);
|
|
10759
11407
|
for (const file of files) {
|
|
10760
11408
|
if (file.endsWith(".mdc")) {
|
|
10761
|
-
const filePath =
|
|
10762
|
-
const content = await
|
|
11409
|
+
const filePath = join12(rulePresetDir, file);
|
|
11410
|
+
const content = await fs19.readFile(filePath, "utf-8");
|
|
10763
11411
|
bundle.files[file] = content;
|
|
10764
11412
|
}
|
|
10765
11413
|
}
|
|
@@ -10778,9 +11426,9 @@ Detected ${detected.length} active IDE(s):
|
|
|
10778
11426
|
}
|
|
10779
11427
|
const files = generatorService.generateForIde(bundle, ideId);
|
|
10780
11428
|
for (const file of files) {
|
|
10781
|
-
const fullPath =
|
|
10782
|
-
await
|
|
10783
|
-
await
|
|
11429
|
+
const fullPath = join12(process.cwd(), file.path);
|
|
11430
|
+
await fs19.mkdir(join12(fullPath, ".."), { recursive: true });
|
|
11431
|
+
await fs19.writeFile(fullPath, file.content, "utf-8");
|
|
10784
11432
|
}
|
|
10785
11433
|
console.log(`\u2713 ${format.name} - ${files.length} files regenerated`);
|
|
10786
11434
|
} catch (error) {
|
|
@@ -10789,8 +11437,8 @@ Detected ${detected.length} active IDE(s):
|
|
|
10789
11437
|
}
|
|
10790
11438
|
if (JSON.stringify(projectConfig.ides) !== JSON.stringify(idesToSync)) {
|
|
10791
11439
|
projectConfig.ides = idesToSync;
|
|
10792
|
-
await
|
|
10793
|
-
|
|
11440
|
+
await fs19.writeFile(
|
|
11441
|
+
join12(process.cwd(), "jai1-rules.json"),
|
|
10794
11442
|
JSON.stringify(projectConfig, null, 2),
|
|
10795
11443
|
"utf-8"
|
|
10796
11444
|
);
|
|
@@ -10805,7 +11453,7 @@ Detected ${detected.length} active IDE(s):
|
|
|
10805
11453
|
}
|
|
10806
11454
|
async function checkPathExists(absolutePath) {
|
|
10807
11455
|
try {
|
|
10808
|
-
await
|
|
11456
|
+
await fs19.access(absolutePath);
|
|
10809
11457
|
return true;
|
|
10810
11458
|
} catch {
|
|
10811
11459
|
return false;
|
|
@@ -10813,15 +11461,15 @@ async function checkPathExists(absolutePath) {
|
|
|
10813
11461
|
}
|
|
10814
11462
|
|
|
10815
11463
|
// src/commands/rules/info.ts
|
|
10816
|
-
import { Command as
|
|
10817
|
-
import { promises as
|
|
10818
|
-
import { join as
|
|
11464
|
+
import { Command as Command47 } from "commander";
|
|
11465
|
+
import { promises as fs20 } from "fs";
|
|
11466
|
+
import { join as join13 } from "path";
|
|
10819
11467
|
function createRulesInfoCommand() {
|
|
10820
|
-
return new
|
|
10821
|
-
const configPath =
|
|
11468
|
+
return new Command47("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
|
|
11469
|
+
const configPath = join13(process.cwd(), "jai1-rules.json");
|
|
10822
11470
|
let projectConfig;
|
|
10823
11471
|
try {
|
|
10824
|
-
const configContent = await
|
|
11472
|
+
const configContent = await fs20.readFile(configPath, "utf-8");
|
|
10825
11473
|
projectConfig = JSON.parse(configContent);
|
|
10826
11474
|
} catch {
|
|
10827
11475
|
throw new ValidationError(
|
|
@@ -10833,14 +11481,14 @@ function createRulesInfoCommand() {
|
|
|
10833
11481
|
return;
|
|
10834
11482
|
}
|
|
10835
11483
|
console.log("\u{1F4CB} Current Preset Information\n");
|
|
10836
|
-
const rulePresetDir =
|
|
10837
|
-
const presetJsonPath =
|
|
11484
|
+
const rulePresetDir = join13(process.cwd(), ".jai1", "rule-preset");
|
|
11485
|
+
const presetJsonPath = join13(rulePresetDir, "preset.json");
|
|
10838
11486
|
let presetMetadata = null;
|
|
10839
11487
|
let presetFiles = [];
|
|
10840
11488
|
try {
|
|
10841
|
-
const presetContent = await
|
|
11489
|
+
const presetContent = await fs20.readFile(presetJsonPath, "utf-8");
|
|
10842
11490
|
presetMetadata = JSON.parse(presetContent);
|
|
10843
|
-
const files = await
|
|
11491
|
+
const files = await fs20.readdir(rulePresetDir);
|
|
10844
11492
|
presetFiles = files.filter((f) => f.endsWith(".mdc"));
|
|
10845
11493
|
} catch {
|
|
10846
11494
|
}
|
|
@@ -10899,9 +11547,9 @@ Available Backups (${projectConfig.backups.length}):`);
|
|
|
10899
11547
|
console.log(' \u2022 "jai1 rules apply" - Apply a different preset (replaces current)');
|
|
10900
11548
|
});
|
|
10901
11549
|
}
|
|
10902
|
-
async function checkPathExists2(
|
|
11550
|
+
async function checkPathExists2(path10) {
|
|
10903
11551
|
try {
|
|
10904
|
-
await
|
|
11552
|
+
await fs20.access(join13(process.cwd(), path10));
|
|
10905
11553
|
return true;
|
|
10906
11554
|
} catch {
|
|
10907
11555
|
return false;
|
|
@@ -10923,7 +11571,7 @@ async function checkIdeFilesExist(ideId, format) {
|
|
|
10923
11571
|
|
|
10924
11572
|
// src/commands/rules/index.ts
|
|
10925
11573
|
function createRulesCommand() {
|
|
10926
|
-
const rulesCommand = new
|
|
11574
|
+
const rulesCommand = new Command48("rules").description("Manage rule presets for AI agents");
|
|
10927
11575
|
rulesCommand.addCommand(createRulesListCommand());
|
|
10928
11576
|
rulesCommand.addCommand(createRulesInitCommand());
|
|
10929
11577
|
rulesCommand.addCommand(createRulesApplyCommand());
|
|
@@ -10934,8 +11582,8 @@ function createRulesCommand() {
|
|
|
10934
11582
|
}
|
|
10935
11583
|
|
|
10936
11584
|
// src/commands/upgrade.ts
|
|
10937
|
-
import { Command as
|
|
10938
|
-
import { confirm as
|
|
11585
|
+
import { Command as Command49 } from "commander";
|
|
11586
|
+
import { confirm as confirm11 } from "@inquirer/prompts";
|
|
10939
11587
|
import { execSync as execSync2 } from "child_process";
|
|
10940
11588
|
var colors3 = {
|
|
10941
11589
|
yellow: "\x1B[33m",
|
|
@@ -10946,7 +11594,7 @@ var colors3 = {
|
|
|
10946
11594
|
bold: "\x1B[1m"
|
|
10947
11595
|
};
|
|
10948
11596
|
function createUpgradeCommand() {
|
|
10949
|
-
return new
|
|
11597
|
+
return new Command49("upgrade").description("Upgrade jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force upgrade without confirmation").action(async (options) => {
|
|
10950
11598
|
await handleUpgrade(options);
|
|
10951
11599
|
});
|
|
10952
11600
|
}
|
|
@@ -10990,7 +11638,7 @@ ${colors3.bold}Current version:${colors3.reset} ${currentVersion}`);
|
|
|
10990
11638
|
return;
|
|
10991
11639
|
}
|
|
10992
11640
|
if (!options.force) {
|
|
10993
|
-
const shouldUpdate = await
|
|
11641
|
+
const shouldUpdate = await confirm11({
|
|
10994
11642
|
message: "Update to the latest version now?",
|
|
10995
11643
|
default: true
|
|
10996
11644
|
});
|
|
@@ -11094,11 +11742,11 @@ function getInstallCommand(packageManager2) {
|
|
|
11094
11742
|
}
|
|
11095
11743
|
|
|
11096
11744
|
// src/commands/clean.ts
|
|
11097
|
-
import { Command as
|
|
11098
|
-
import { confirm as
|
|
11099
|
-
import { join as
|
|
11745
|
+
import { Command as Command50 } from "commander";
|
|
11746
|
+
import { confirm as confirm12, select as select7 } from "@inquirer/prompts";
|
|
11747
|
+
import { join as join14 } from "path";
|
|
11100
11748
|
function createCleanCommand() {
|
|
11101
|
-
return new
|
|
11749
|
+
return new Command50("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
|
|
11102
11750
|
await handleClean(options);
|
|
11103
11751
|
});
|
|
11104
11752
|
}
|
|
@@ -11109,7 +11757,7 @@ async function handleClean(options) {
|
|
|
11109
11757
|
{
|
|
11110
11758
|
name: "Backups",
|
|
11111
11759
|
description: "Component backup files (.jai1_backup/)",
|
|
11112
|
-
path:
|
|
11760
|
+
path: join14(cwd, ".jai1_backup"),
|
|
11113
11761
|
check: async () => {
|
|
11114
11762
|
const backups = await service.listBackups(cwd);
|
|
11115
11763
|
return { exists: backups.length > 0, count: backups.length };
|
|
@@ -11159,7 +11807,7 @@ async function handleClean(options) {
|
|
|
11159
11807
|
console.log(` Path: ${target.path}
|
|
11160
11808
|
`);
|
|
11161
11809
|
}
|
|
11162
|
-
const action = await
|
|
11810
|
+
const action = await select7({
|
|
11163
11811
|
message: "What do you want to clean?",
|
|
11164
11812
|
choices: [
|
|
11165
11813
|
...availableTargets.map(({ target, info }) => ({
|
|
@@ -11193,7 +11841,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
11193
11841
|
}
|
|
11194
11842
|
const countStr = info.count ? ` (${info.count} items)` : "";
|
|
11195
11843
|
if (!skipConfirm) {
|
|
11196
|
-
const confirmed = await
|
|
11844
|
+
const confirmed = await confirm12({
|
|
11197
11845
|
message: `Delete ${target.name}${countStr}?`,
|
|
11198
11846
|
default: false
|
|
11199
11847
|
});
|
|
@@ -11211,7 +11859,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
11211
11859
|
}
|
|
11212
11860
|
|
|
11213
11861
|
// src/commands/redmine/check.ts
|
|
11214
|
-
import { Command as
|
|
11862
|
+
import { Command as Command51 } from "commander";
|
|
11215
11863
|
|
|
11216
11864
|
// src/services/redmine-config.service.ts
|
|
11217
11865
|
import { readFile as readFile6 } from "fs/promises";
|
|
@@ -11332,8 +11980,8 @@ var RedmineApiClient = class {
|
|
|
11332
11980
|
this.retryConfig = config.defaults.retry;
|
|
11333
11981
|
this.concurrencyLimit = pLimit3(config.defaults.concurrency);
|
|
11334
11982
|
}
|
|
11335
|
-
async request(
|
|
11336
|
-
const url = `${this.baseUrl}${
|
|
11983
|
+
async request(path10, options = {}) {
|
|
11984
|
+
const url = `${this.baseUrl}${path10}`;
|
|
11337
11985
|
const headers = {
|
|
11338
11986
|
"X-Redmine-API-Key": this.apiAccessToken,
|
|
11339
11987
|
"Content-Type": "application/json",
|
|
@@ -11394,8 +12042,8 @@ var RedmineApiClient = class {
|
|
|
11394
12042
|
if (include && include.length > 0) {
|
|
11395
12043
|
params.append("include", include.join(","));
|
|
11396
12044
|
}
|
|
11397
|
-
const
|
|
11398
|
-
return this.request(
|
|
12045
|
+
const path10 = `/issues/${issueId}.json${params.toString() ? `?${params.toString()}` : ""}`;
|
|
12046
|
+
return this.request(path10);
|
|
11399
12047
|
}
|
|
11400
12048
|
async getIssues(projectId, options = {}) {
|
|
11401
12049
|
const params = new URLSearchParams();
|
|
@@ -11415,8 +12063,8 @@ var RedmineApiClient = class {
|
|
|
11415
12063
|
if (options.updatedSince) {
|
|
11416
12064
|
params.append("updated_on", `>=${options.updatedSince}`);
|
|
11417
12065
|
}
|
|
11418
|
-
const
|
|
11419
|
-
return this.request(
|
|
12066
|
+
const path10 = `/issues.json?${params.toString()}`;
|
|
12067
|
+
return this.request(path10);
|
|
11420
12068
|
}
|
|
11421
12069
|
async getAllIssues(projectId, options = {}) {
|
|
11422
12070
|
const pageSize = options.pageSize || 100;
|
|
@@ -11518,7 +12166,7 @@ async function checkConnectivity(config) {
|
|
|
11518
12166
|
|
|
11519
12167
|
// src/commands/redmine/check.ts
|
|
11520
12168
|
function createRedmineCheckCommand() {
|
|
11521
|
-
const cmd = new
|
|
12169
|
+
const cmd = new Command51("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
|
|
11522
12170
|
await handleRedmineCheck(options);
|
|
11523
12171
|
});
|
|
11524
12172
|
return cmd;
|
|
@@ -11546,7 +12194,7 @@ async function handleRedmineCheck(options) {
|
|
|
11546
12194
|
}
|
|
11547
12195
|
|
|
11548
12196
|
// src/commands/redmine/sync-issue.ts
|
|
11549
|
-
import { Command as
|
|
12197
|
+
import { Command as Command52 } from "commander";
|
|
11550
12198
|
|
|
11551
12199
|
// src/sync-issue.ts
|
|
11552
12200
|
import { resolve as resolve3, relative } from "path";
|
|
@@ -11930,7 +12578,7 @@ function extractIssueIdFromUrl(url) {
|
|
|
11930
12578
|
|
|
11931
12579
|
// src/commands/redmine/sync-issue.ts
|
|
11932
12580
|
function createSyncIssueCommand() {
|
|
11933
|
-
const cmd = new
|
|
12581
|
+
const cmd = new Command52("issue").description("Sync a single issue").option("-i, --id <number>", "Issue ID").option("-u, --url <url>", "Issue URL").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
|
|
11934
12582
|
await handleSyncIssue(options);
|
|
11935
12583
|
});
|
|
11936
12584
|
return cmd;
|
|
@@ -11974,7 +12622,7 @@ async function handleSyncIssue(options) {
|
|
|
11974
12622
|
}
|
|
11975
12623
|
|
|
11976
12624
|
// src/commands/redmine/sync-project.ts
|
|
11977
|
-
import { Command as
|
|
12625
|
+
import { Command as Command53 } from "commander";
|
|
11978
12626
|
|
|
11979
12627
|
// src/sync-project.ts
|
|
11980
12628
|
async function syncProject(config, options = {}) {
|
|
@@ -12044,7 +12692,7 @@ async function syncProject(config, options = {}) {
|
|
|
12044
12692
|
|
|
12045
12693
|
// src/commands/redmine/sync-project.ts
|
|
12046
12694
|
function createSyncProjectCommand() {
|
|
12047
|
-
const cmd = new
|
|
12695
|
+
const cmd = new Command53("project").description("Sync all issues in a project").option("-s, --status <status>", "Filter by status (default: *)", "*").option("--updated-since <date>", "Only sync issues updated since YYYY-MM-DD").option("--concurrency <number>", "Number of concurrent requests").option("--page-size <number>", "Page size for API requests").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
|
|
12048
12696
|
await handleSyncProject(options);
|
|
12049
12697
|
});
|
|
12050
12698
|
return cmd;
|
|
@@ -12099,12 +12747,12 @@ async function handleSyncProject(options) {
|
|
|
12099
12747
|
}
|
|
12100
12748
|
|
|
12101
12749
|
// src/commands/framework/info.ts
|
|
12102
|
-
import { Command as
|
|
12103
|
-
import { promises as
|
|
12104
|
-
import { join as
|
|
12750
|
+
import { Command as Command54 } from "commander";
|
|
12751
|
+
import { promises as fs21 } from "fs";
|
|
12752
|
+
import { join as join15 } from "path";
|
|
12105
12753
|
import { homedir as homedir5 } from "os";
|
|
12106
12754
|
function createInfoCommand() {
|
|
12107
|
-
const cmd = new
|
|
12755
|
+
const cmd = new Command54("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
|
|
12108
12756
|
await handleInfo(options);
|
|
12109
12757
|
});
|
|
12110
12758
|
return cmd;
|
|
@@ -12115,7 +12763,7 @@ async function handleInfo(options) {
|
|
|
12115
12763
|
if (!config) {
|
|
12116
12764
|
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
12117
12765
|
}
|
|
12118
|
-
const frameworkPath =
|
|
12766
|
+
const frameworkPath = join15(homedir5(), ".jai1", "framework");
|
|
12119
12767
|
const projectStatus = await getProjectStatus2();
|
|
12120
12768
|
const info = {
|
|
12121
12769
|
configPath: configService.getConfigPath(),
|
|
@@ -12150,9 +12798,9 @@ function maskKey3(key) {
|
|
|
12150
12798
|
return "****" + key.slice(-4);
|
|
12151
12799
|
}
|
|
12152
12800
|
async function getProjectStatus2() {
|
|
12153
|
-
const projectJai1 =
|
|
12801
|
+
const projectJai1 = join15(process.cwd(), ".jai1");
|
|
12154
12802
|
try {
|
|
12155
|
-
await
|
|
12803
|
+
await fs21.access(projectJai1);
|
|
12156
12804
|
return { exists: true, version: "Synced" };
|
|
12157
12805
|
} catch {
|
|
12158
12806
|
return { exists: false };
|
|
@@ -12160,8 +12808,8 @@ async function getProjectStatus2() {
|
|
|
12160
12808
|
}
|
|
12161
12809
|
|
|
12162
12810
|
// src/commands/self-update.ts
|
|
12163
|
-
import { Command as
|
|
12164
|
-
import { confirm as
|
|
12811
|
+
import { Command as Command55 } from "commander";
|
|
12812
|
+
import { confirm as confirm13 } from "@inquirer/prompts";
|
|
12165
12813
|
import { execSync as execSync3 } from "child_process";
|
|
12166
12814
|
var colors4 = {
|
|
12167
12815
|
yellow: "\x1B[33m",
|
|
@@ -12172,7 +12820,7 @@ var colors4 = {
|
|
|
12172
12820
|
bold: "\x1B[1m"
|
|
12173
12821
|
};
|
|
12174
12822
|
function createSelfUpdateCommand() {
|
|
12175
|
-
return new
|
|
12823
|
+
return new Command55("self-update").description("Update jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
|
|
12176
12824
|
await handleSelfUpdate(options);
|
|
12177
12825
|
});
|
|
12178
12826
|
}
|
|
@@ -12216,7 +12864,7 @@ ${colors4.bold}Current version:${colors4.reset} ${currentVersion}`);
|
|
|
12216
12864
|
return;
|
|
12217
12865
|
}
|
|
12218
12866
|
if (!options.force) {
|
|
12219
|
-
const shouldUpdate = await
|
|
12867
|
+
const shouldUpdate = await confirm13({
|
|
12220
12868
|
message: "Update to the latest version now?",
|
|
12221
12869
|
default: true
|
|
12222
12870
|
});
|
|
@@ -12312,10 +12960,10 @@ function getInstallCommand2(packageManager2) {
|
|
|
12312
12960
|
}
|
|
12313
12961
|
|
|
12314
12962
|
// src/commands/clear-backups.ts
|
|
12315
|
-
import { Command as
|
|
12316
|
-
import { confirm as
|
|
12963
|
+
import { Command as Command56 } from "commander";
|
|
12964
|
+
import { confirm as confirm14 } from "@inquirer/prompts";
|
|
12317
12965
|
function createClearBackupsCommand() {
|
|
12318
|
-
return new
|
|
12966
|
+
return new Command56("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
12319
12967
|
const service = new ComponentsService();
|
|
12320
12968
|
const backups = await service.listBackups(process.cwd());
|
|
12321
12969
|
if (backups.length === 0) {
|
|
@@ -12331,7 +12979,7 @@ function createClearBackupsCommand() {
|
|
|
12331
12979
|
}
|
|
12332
12980
|
console.log();
|
|
12333
12981
|
if (!options.yes) {
|
|
12334
|
-
const ok = await
|
|
12982
|
+
const ok = await confirm14({ message: "Delete all backups?", default: false });
|
|
12335
12983
|
if (!ok) return;
|
|
12336
12984
|
}
|
|
12337
12985
|
await service.clearBackups(process.cwd());
|
|
@@ -12340,10 +12988,10 @@ function createClearBackupsCommand() {
|
|
|
12340
12988
|
}
|
|
12341
12989
|
|
|
12342
12990
|
// src/commands/vscode/index.ts
|
|
12343
|
-
import { Command as
|
|
12344
|
-
import { checkbox as checkbox7, confirm as
|
|
12345
|
-
import
|
|
12346
|
-
import
|
|
12991
|
+
import { Command as Command57 } from "commander";
|
|
12992
|
+
import { checkbox as checkbox7, confirm as confirm15, select as select8 } from "@inquirer/prompts";
|
|
12993
|
+
import fs22 from "fs/promises";
|
|
12994
|
+
import path9 from "path";
|
|
12347
12995
|
import { existsSync as existsSync3 } from "fs";
|
|
12348
12996
|
var PERFORMANCE_GROUPS2 = {
|
|
12349
12997
|
telemetry: {
|
|
@@ -12480,7 +13128,7 @@ var PERFORMANCE_GROUPS2 = {
|
|
|
12480
13128
|
}
|
|
12481
13129
|
};
|
|
12482
13130
|
function createVSCodeCommand() {
|
|
12483
|
-
const vscodeCommand = new
|
|
13131
|
+
const vscodeCommand = new Command57("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
|
|
12484
13132
|
vscodeCommand.action(async () => {
|
|
12485
13133
|
await interactiveMode2();
|
|
12486
13134
|
});
|
|
@@ -12524,7 +13172,7 @@ async function interactiveMode2() {
|
|
|
12524
13172
|
console.log("\u2502 \u2022 Nh\u1EA5n ENTER \u0111\u1EC3 x\xE1c nh\u1EADn v\xE0 \xE1p d\u1EE5ng \u2502");
|
|
12525
13173
|
console.log("\u2502 \u2022 Nh\u1EA5n Ctrl+C \u0111\u1EC3 h\u1EE7y \u2502");
|
|
12526
13174
|
console.log("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F\n");
|
|
12527
|
-
const action = await
|
|
13175
|
+
const action = await select8({
|
|
12528
13176
|
message: "B\u1EA1n mu\u1ED1n l\xE0m g\xEC?",
|
|
12529
13177
|
choices: [
|
|
12530
13178
|
{ name: "\u2705 Enable c\xE1c nh\xF3m t\u1ED1i \u01B0u", value: "enable" },
|
|
@@ -12563,8 +13211,8 @@ async function selectGroupsToApply2(action) {
|
|
|
12563
13211
|
}
|
|
12564
13212
|
}
|
|
12565
13213
|
async function applyGroups2(groupKeys, action) {
|
|
12566
|
-
const vscodeDir =
|
|
12567
|
-
const settingsPath =
|
|
13214
|
+
const vscodeDir = path9.join(process.cwd(), ".vscode");
|
|
13215
|
+
const settingsPath = path9.join(vscodeDir, "settings.json");
|
|
12568
13216
|
const invalidGroups = groupKeys.filter((key) => !PERFORMANCE_GROUPS2[key]);
|
|
12569
13217
|
if (invalidGroups.length > 0) {
|
|
12570
13218
|
console.log(`
|
|
@@ -12573,18 +13221,18 @@ async function applyGroups2(groupKeys, action) {
|
|
|
12573
13221
|
return;
|
|
12574
13222
|
}
|
|
12575
13223
|
if (!existsSync3(vscodeDir)) {
|
|
12576
|
-
await
|
|
13224
|
+
await fs22.mkdir(vscodeDir, { recursive: true });
|
|
12577
13225
|
console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
|
|
12578
13226
|
}
|
|
12579
13227
|
let currentSettings = {};
|
|
12580
13228
|
if (existsSync3(settingsPath)) {
|
|
12581
13229
|
try {
|
|
12582
|
-
const content = await
|
|
13230
|
+
const content = await fs22.readFile(settingsPath, "utf-8");
|
|
12583
13231
|
currentSettings = JSON.parse(content);
|
|
12584
13232
|
console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
|
|
12585
13233
|
} catch {
|
|
12586
13234
|
console.warn("\u26A0\uFE0F Kh\xF4ng th\u1EC3 \u0111\u1ECDc settings.json (c\xF3 th\u1EC3 ch\u1EE9a comments).");
|
|
12587
|
-
const confirmOverwrite = await
|
|
13235
|
+
const confirmOverwrite = await confirm15({
|
|
12588
13236
|
message: "Ghi \u0111\xE8 file settings.json hi\u1EC7n t\u1EA1i?",
|
|
12589
13237
|
default: false
|
|
12590
13238
|
});
|
|
@@ -12619,19 +13267,19 @@ async function applyGroups2(groupKeys, action) {
|
|
|
12619
13267
|
}
|
|
12620
13268
|
}
|
|
12621
13269
|
}
|
|
12622
|
-
await
|
|
13270
|
+
await fs22.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
|
12623
13271
|
console.log(`
|
|
12624
13272
|
\u2705 \u0110\xE3 c\u1EADp nh\u1EADt c\xE0i \u0111\u1EB7t VSCode t\u1EA1i: ${settingsPath}`);
|
|
12625
13273
|
console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
|
|
12626
13274
|
}
|
|
12627
13275
|
async function resetSettings2(groupKeys) {
|
|
12628
|
-
const vscodeDir =
|
|
12629
|
-
const settingsPath =
|
|
13276
|
+
const vscodeDir = path9.join(process.cwd(), ".vscode");
|
|
13277
|
+
const settingsPath = path9.join(vscodeDir, "settings.json");
|
|
12630
13278
|
if (!existsSync3(settingsPath)) {
|
|
12631
13279
|
console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
|
|
12632
13280
|
return;
|
|
12633
13281
|
}
|
|
12634
|
-
const confirmReset = await
|
|
13282
|
+
const confirmReset = await confirm15({
|
|
12635
13283
|
message: groupKeys.length === 0 ? "Reset T\u1EA4T C\u1EA2 settings v\u1EC1 m\u1EB7c \u0111\u1ECBnh (x\xF3a to\xE0n b\u1ED9 file)?" : `Reset c\xE1c nh\xF3m: ${groupKeys.join(", ")}?`,
|
|
12636
13284
|
default: false
|
|
12637
13285
|
});
|
|
@@ -12640,7 +13288,7 @@ async function resetSettings2(groupKeys) {
|
|
|
12640
13288
|
return;
|
|
12641
13289
|
}
|
|
12642
13290
|
if (groupKeys.length === 0) {
|
|
12643
|
-
await
|
|
13291
|
+
await fs22.unlink(settingsPath);
|
|
12644
13292
|
console.log("\n\u2705 \u0110\xE3 x\xF3a file settings.json");
|
|
12645
13293
|
} else {
|
|
12646
13294
|
await applyGroups2(groupKeys, "disable");
|
|
@@ -12651,9 +13299,9 @@ async function resetSettings2(groupKeys) {
|
|
|
12651
13299
|
// src/commands/guide.ts
|
|
12652
13300
|
import React40 from "react";
|
|
12653
13301
|
import { render as render6 } from "ink";
|
|
12654
|
-
import { Command as
|
|
13302
|
+
import { Command as Command58 } from "commander";
|
|
12655
13303
|
function createGuideCommand() {
|
|
12656
|
-
const cmd = new
|
|
13304
|
+
const cmd = new Command58("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
|
|
12657
13305
|
const { waitUntilExit } = render6(
|
|
12658
13306
|
React40.createElement(GuideApp, {
|
|
12659
13307
|
initialTopic: options.topic,
|
|
@@ -12670,9 +13318,9 @@ function createGuideCommand() {
|
|
|
12670
13318
|
// src/commands/context.ts
|
|
12671
13319
|
import React41 from "react";
|
|
12672
13320
|
import { render as render7 } from "ink";
|
|
12673
|
-
import { Command as
|
|
13321
|
+
import { Command as Command59 } from "commander";
|
|
12674
13322
|
function createContextCommand() {
|
|
12675
|
-
const cmd = new
|
|
13323
|
+
const cmd = new Command59("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
|
|
12676
13324
|
let initialIDE;
|
|
12677
13325
|
if (options.ide) {
|
|
12678
13326
|
const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
|
|
@@ -12749,10 +13397,10 @@ async function printStats2() {
|
|
|
12749
13397
|
}
|
|
12750
13398
|
|
|
12751
13399
|
// src/commands/migrate-ide.ts
|
|
12752
|
-
import { Command as
|
|
12753
|
-
import { checkbox as checkbox8, confirm as
|
|
13400
|
+
import { Command as Command60 } from "commander";
|
|
13401
|
+
import { checkbox as checkbox8, confirm as confirm16 } from "@inquirer/prompts";
|
|
12754
13402
|
function createMigrateIdeCommand() {
|
|
12755
|
-
const cmd = new
|
|
13403
|
+
const cmd = new Command60("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
|
|
12756
13404
|
await runMigrateIde(options);
|
|
12757
13405
|
});
|
|
12758
13406
|
return cmd;
|
|
@@ -12821,7 +13469,7 @@ async function runMigrateIde(options) {
|
|
|
12821
13469
|
if (options.dryRun) {
|
|
12822
13470
|
console.log("\u{1F50D} DRY RUN - No files will be written\n");
|
|
12823
13471
|
}
|
|
12824
|
-
const confirmed = await
|
|
13472
|
+
const confirmed = await confirm16({
|
|
12825
13473
|
message: "Proceed with migration?",
|
|
12826
13474
|
default: true
|
|
12827
13475
|
});
|
|
@@ -12858,7 +13506,7 @@ async function runMigrateIde(options) {
|
|
|
12858
13506
|
}
|
|
12859
13507
|
|
|
12860
13508
|
// src/cli.ts
|
|
12861
|
-
var program = new
|
|
13509
|
+
var program = new Command61();
|
|
12862
13510
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
12863
13511
|
console.log(package_default.version);
|
|
12864
13512
|
if (!process.argv.includes("--skip-update-check")) {
|
|
@@ -12880,15 +13528,16 @@ program.addCommand(createOpenAiKeysCommand());
|
|
|
12880
13528
|
program.addCommand(createStatsCommand());
|
|
12881
13529
|
program.addCommand(createTranslateCommand());
|
|
12882
13530
|
program.addCommand(createImageCommand());
|
|
13531
|
+
program.addCommand(createFeedbackCommand());
|
|
12883
13532
|
program.addCommand(createUtilsCommand());
|
|
12884
13533
|
program.addCommand(createDepsCommand());
|
|
12885
13534
|
program.addCommand(createKitCommand());
|
|
12886
13535
|
program.addCommand(createRulesCommand());
|
|
12887
13536
|
program.addCommand(createUpgradeCommand());
|
|
12888
13537
|
program.addCommand(createCleanCommand());
|
|
12889
|
-
var redmineCommand = new
|
|
13538
|
+
var redmineCommand = new Command61("redmine").description("Redmine context sync commands");
|
|
12890
13539
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
12891
|
-
var syncCommand = new
|
|
13540
|
+
var syncCommand = new Command61("sync").description("Sync Redmine issues to markdown files");
|
|
12892
13541
|
syncCommand.addCommand(createSyncIssueCommand());
|
|
12893
13542
|
syncCommand.addCommand(createSyncProjectCommand());
|
|
12894
13543
|
redmineCommand.addCommand(syncCommand);
|