@jvittechs/jai1-cli 0.1.84 → 0.1.86
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/README.md +2 -2
- package/dist/cli.js +1012 -256
- package/dist/cli.js.map +1 -1
- package/package.json +1 -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 Command52 } 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.86",
|
|
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: {
|
|
@@ -895,9 +895,9 @@ var UnifiedApplyApp = ({
|
|
|
895
895
|
(c) => c.filepath.toLowerCase().includes(query) || c.name.toLowerCase().includes(query) || c.tags && c.tags.some((t) => t.toLowerCase().includes(query))
|
|
896
896
|
);
|
|
897
897
|
}, [components, searchQuery]);
|
|
898
|
-
useInput((
|
|
898
|
+
useInput((input3, key) => {
|
|
899
899
|
if (viewState === "summary") {
|
|
900
|
-
if (key.return ||
|
|
900
|
+
if (key.return || input3 === "q" || key.escape) {
|
|
901
901
|
onExit();
|
|
902
902
|
}
|
|
903
903
|
return;
|
|
@@ -911,7 +911,7 @@ var UnifiedApplyApp = ({
|
|
|
911
911
|
else setFocusArea("search");
|
|
912
912
|
return;
|
|
913
913
|
}
|
|
914
|
-
if (key.escape ||
|
|
914
|
+
if (key.escape || input3 === "q") {
|
|
915
915
|
onExit();
|
|
916
916
|
return;
|
|
917
917
|
}
|
|
@@ -926,7 +926,7 @@ var UnifiedApplyApp = ({
|
|
|
926
926
|
setCursorIndex((prev) => Math.max(0, prev - 1));
|
|
927
927
|
} else if (key.downArrow) {
|
|
928
928
|
setCursorIndex((prev) => Math.min(filteredComponents.length - 1, prev + 1));
|
|
929
|
-
} else if (
|
|
929
|
+
} else if (input3 === " ") {
|
|
930
930
|
const current = filteredComponents[cursorIndex];
|
|
931
931
|
if (current) {
|
|
932
932
|
setSelectedPaths((prev) => {
|
|
@@ -939,13 +939,13 @@ var UnifiedApplyApp = ({
|
|
|
939
939
|
return next;
|
|
940
940
|
});
|
|
941
941
|
}
|
|
942
|
-
} else if (
|
|
942
|
+
} else if (input3 === "a") {
|
|
943
943
|
setSelectedPaths((prev) => {
|
|
944
944
|
const next = new Set(prev);
|
|
945
945
|
filteredComponents.forEach((c) => next.add(c.filepath));
|
|
946
946
|
return next;
|
|
947
947
|
});
|
|
948
|
-
} else if (
|
|
948
|
+
} else if (input3 === "c") {
|
|
949
949
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
950
950
|
}
|
|
951
951
|
}
|
|
@@ -954,7 +954,7 @@ var UnifiedApplyApp = ({
|
|
|
954
954
|
setSelectedPackageIndex((prev) => Math.max(0, prev - 1));
|
|
955
955
|
} else if (key.rightArrow) {
|
|
956
956
|
setSelectedPackageIndex((prev) => Math.min(tags.length - 1, prev + 1));
|
|
957
|
-
} else if (
|
|
957
|
+
} else if (input3 === " " || key.return) {
|
|
958
958
|
const tag = tags[selectedPackageIndex];
|
|
959
959
|
if (tag) {
|
|
960
960
|
const packageComponents = components.filter((c) => c.tags?.includes(tag.tag));
|
|
@@ -1332,7 +1332,7 @@ var MainMenuView = ({ ideContexts, onSelect }) => {
|
|
|
1332
1332
|
available: ideContexts.some((ctx) => ctx.ide === "jai1")
|
|
1333
1333
|
}
|
|
1334
1334
|
];
|
|
1335
|
-
useInput2((
|
|
1335
|
+
useInput2((input3, key) => {
|
|
1336
1336
|
if (key.upArrow) {
|
|
1337
1337
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
1338
1338
|
} else if (key.downArrow) {
|
|
@@ -1434,13 +1434,13 @@ var IDEOverviewView = ({
|
|
|
1434
1434
|
count: ideContext.stats.byType.context
|
|
1435
1435
|
});
|
|
1436
1436
|
}
|
|
1437
|
-
useInput3((
|
|
1437
|
+
useInput3((input3, key) => {
|
|
1438
1438
|
if (key.tab || key.rightArrow) {
|
|
1439
1439
|
setSelectedTabIndex((prev) => Math.min(tabs.length - 1, prev + 1));
|
|
1440
1440
|
} else if (key.leftArrow) {
|
|
1441
1441
|
setSelectedTabIndex((prev) => Math.max(0, prev - 1));
|
|
1442
1442
|
}
|
|
1443
|
-
const num = parseInt(
|
|
1443
|
+
const num = parseInt(input3, 10);
|
|
1444
1444
|
if (!isNaN(num) && num >= 1 && num <= tabs.length) {
|
|
1445
1445
|
setSelectedTabIndex(num - 1);
|
|
1446
1446
|
}
|
|
@@ -1502,7 +1502,7 @@ import React7, { useState as useState4 } from "react";
|
|
|
1502
1502
|
import { Box as Box5, Text as Text6, useInput as useInput4 } from "ink";
|
|
1503
1503
|
var ListView = ({ items, contentType, onSelect, onBack }) => {
|
|
1504
1504
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
1505
|
-
useInput4((
|
|
1505
|
+
useInput4((input3, key) => {
|
|
1506
1506
|
if (key.upArrow) {
|
|
1507
1507
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
1508
1508
|
} else if (key.downArrow) {
|
|
@@ -1553,18 +1553,18 @@ var DetailView = ({ item, scrollPosition: initialScroll, onBack }) => {
|
|
|
1553
1553
|
const [scrollPosition, setScrollPosition] = useState5(initialScroll);
|
|
1554
1554
|
const maxVisibleLines = 25;
|
|
1555
1555
|
const maxScroll = Math.max(0, item.previewLines.length - maxVisibleLines);
|
|
1556
|
-
useInput5((
|
|
1557
|
-
if (key.upArrow ||
|
|
1556
|
+
useInput5((input3, key) => {
|
|
1557
|
+
if (key.upArrow || input3 === "k") {
|
|
1558
1558
|
setScrollPosition((prev) => Math.max(0, prev - 1));
|
|
1559
|
-
} else if (key.downArrow ||
|
|
1559
|
+
} else if (key.downArrow || input3 === "j") {
|
|
1560
1560
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 1));
|
|
1561
|
-
} else if (key.pageDown ||
|
|
1561
|
+
} else if (key.pageDown || input3 === "d") {
|
|
1562
1562
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 5));
|
|
1563
|
-
} else if (key.pageUp ||
|
|
1563
|
+
} else if (key.pageUp || input3 === "u") {
|
|
1564
1564
|
setScrollPosition((prev) => Math.max(0, prev - 5));
|
|
1565
|
-
} else if (
|
|
1565
|
+
} else if (input3 === "g") {
|
|
1566
1566
|
setScrollPosition(0);
|
|
1567
|
-
} else if (
|
|
1567
|
+
} else if (input3 === "G") {
|
|
1568
1568
|
setScrollPosition(maxScroll);
|
|
1569
1569
|
} else if (key.escape || key.backspace) {
|
|
1570
1570
|
onBack();
|
|
@@ -1960,8 +1960,8 @@ var ContextApp = ({ initialIDE, initialType, onExit }) => {
|
|
|
1960
1960
|
setLoading(false);
|
|
1961
1961
|
});
|
|
1962
1962
|
}, [initialIDE]);
|
|
1963
|
-
useInput6((
|
|
1964
|
-
if (
|
|
1963
|
+
useInput6((input3, key) => {
|
|
1964
|
+
if (input3 === "q") {
|
|
1965
1965
|
onExit();
|
|
1966
1966
|
return;
|
|
1967
1967
|
}
|
|
@@ -2888,7 +2888,7 @@ var MENU_ITEMS = [
|
|
|
2888
2888
|
];
|
|
2889
2889
|
var MenuView = ({ onSelect }) => {
|
|
2890
2890
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
2891
|
-
useInput7((
|
|
2891
|
+
useInput7((input3, key) => {
|
|
2892
2892
|
if (key.upArrow) {
|
|
2893
2893
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
2894
2894
|
} else if (key.downArrow) {
|
|
@@ -3501,7 +3501,7 @@ var AgenticGuideView = ({ onBack }) => {
|
|
|
3501
3501
|
const [isTyping, setIsTyping] = useState8(false);
|
|
3502
3502
|
const [selectedSuggestion, setSelectedSuggestion] = useState8(0);
|
|
3503
3503
|
const [focusArea, setFocusArea] = useState8("input");
|
|
3504
|
-
useInput8((
|
|
3504
|
+
useInput8((input3, key) => {
|
|
3505
3505
|
if (key.escape) {
|
|
3506
3506
|
onBack();
|
|
3507
3507
|
return;
|
|
@@ -3633,7 +3633,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
3633
3633
|
setCurrentTopic(TOPIC_MAP[initialTopic]);
|
|
3634
3634
|
}
|
|
3635
3635
|
}, [initialTopic]);
|
|
3636
|
-
useInput9((
|
|
3636
|
+
useInput9((input3, key) => {
|
|
3637
3637
|
if (key.escape || currentTopic !== "menu" && key.backspace) {
|
|
3638
3638
|
if (currentTopic === "menu") {
|
|
3639
3639
|
onExit();
|
|
@@ -3643,7 +3643,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
3643
3643
|
}
|
|
3644
3644
|
return;
|
|
3645
3645
|
}
|
|
3646
|
-
if (
|
|
3646
|
+
if (input3 === "q") {
|
|
3647
3647
|
onExit();
|
|
3648
3648
|
return;
|
|
3649
3649
|
}
|
|
@@ -4142,7 +4142,7 @@ var ModelSelector = ({
|
|
|
4142
4142
|
const allowedModels = models.filter((m) => m.allowed);
|
|
4143
4143
|
const currentIndex = allowedModels.findIndex((m) => m.id === currentModel);
|
|
4144
4144
|
const [selectedIndex, setSelectedIndex] = useState12(Math.max(0, currentIndex));
|
|
4145
|
-
useInput10((
|
|
4145
|
+
useInput10((input3, key) => {
|
|
4146
4146
|
if (key.escape) {
|
|
4147
4147
|
onCancel();
|
|
4148
4148
|
return;
|
|
@@ -4268,7 +4268,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
4268
4268
|
}
|
|
4269
4269
|
return false;
|
|
4270
4270
|
}, [refetch, exit]);
|
|
4271
|
-
useInput11((
|
|
4271
|
+
useInput11((input3, key) => {
|
|
4272
4272
|
if (showSlashMenu) {
|
|
4273
4273
|
if (key.upArrow) {
|
|
4274
4274
|
setSlashMenuIndex((i) => Math.max(0, i - 1));
|
|
@@ -4296,7 +4296,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
4296
4296
|
}
|
|
4297
4297
|
return;
|
|
4298
4298
|
}
|
|
4299
|
-
if (currentView === "error" && (key.return ||
|
|
4299
|
+
if (currentView === "error" && (key.return || input3 === "r")) {
|
|
4300
4300
|
setCurrentView("loading");
|
|
4301
4301
|
refetch();
|
|
4302
4302
|
return;
|
|
@@ -4551,9 +4551,9 @@ var TranslationService = class {
|
|
|
4551
4551
|
/**
|
|
4552
4552
|
* Detect input type
|
|
4553
4553
|
*/
|
|
4554
|
-
async detectInputType(
|
|
4554
|
+
async detectInputType(input3) {
|
|
4555
4555
|
try {
|
|
4556
|
-
const stat = await fs7.stat(
|
|
4556
|
+
const stat = await fs7.stat(input3);
|
|
4557
4557
|
if (stat.isDirectory()) return "folder";
|
|
4558
4558
|
if (stat.isFile()) return "file";
|
|
4559
4559
|
} catch {
|
|
@@ -4785,7 +4785,7 @@ Return ONLY the translated content, no explanations.`;
|
|
|
4785
4785
|
};
|
|
4786
4786
|
|
|
4787
4787
|
// src/commands/translate.ts
|
|
4788
|
-
async function handleTranslate(
|
|
4788
|
+
async function handleTranslate(input3, options) {
|
|
4789
4789
|
const configService = new ConfigService();
|
|
4790
4790
|
const config = await configService.load();
|
|
4791
4791
|
if (!config) {
|
|
@@ -4793,16 +4793,16 @@ async function handleTranslate(input2, options) {
|
|
|
4793
4793
|
}
|
|
4794
4794
|
const llmService = new LlmProxyService(config);
|
|
4795
4795
|
const translationService = new TranslationService(llmService, options, options.model);
|
|
4796
|
-
const inputType = await translationService.detectInputType(
|
|
4796
|
+
const inputType = await translationService.detectInputType(input3);
|
|
4797
4797
|
switch (inputType) {
|
|
4798
4798
|
case "text":
|
|
4799
|
-
await handleTextTranslation(translationService,
|
|
4799
|
+
await handleTextTranslation(translationService, input3, options);
|
|
4800
4800
|
break;
|
|
4801
4801
|
case "file":
|
|
4802
|
-
await handleFileTranslation(translationService,
|
|
4802
|
+
await handleFileTranslation(translationService, input3, options);
|
|
4803
4803
|
break;
|
|
4804
4804
|
case "folder":
|
|
4805
|
-
await handleFolderTranslation(translationService,
|
|
4805
|
+
await handleFolderTranslation(translationService, input3, options);
|
|
4806
4806
|
break;
|
|
4807
4807
|
}
|
|
4808
4808
|
}
|
|
@@ -4879,8 +4879,8 @@ async function handleFolderTranslation(service, folderPath, options) {
|
|
|
4879
4879
|
}
|
|
4880
4880
|
}
|
|
4881
4881
|
function createTranslateCommand() {
|
|
4882
|
-
const cmd = new Command14("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 (
|
|
4883
|
-
await handleTranslate(
|
|
4882
|
+
const cmd = new Command14("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 (input3, options) => {
|
|
4883
|
+
await handleTranslate(input3, options);
|
|
4884
4884
|
});
|
|
4885
4885
|
return cmd;
|
|
4886
4886
|
}
|
|
@@ -4940,12 +4940,12 @@ var UtilsService = class {
|
|
|
4940
4940
|
/**
|
|
4941
4941
|
* Hash text or file using specified algorithm
|
|
4942
4942
|
*/
|
|
4943
|
-
async hash(
|
|
4943
|
+
async hash(input3, algorithm) {
|
|
4944
4944
|
if (algorithm === "bcrypt") {
|
|
4945
4945
|
throw new Error("Use hashBcrypt for bcrypt algorithm");
|
|
4946
4946
|
}
|
|
4947
4947
|
const hash = crypto.createHash(algorithm);
|
|
4948
|
-
hash.update(
|
|
4948
|
+
hash.update(input3);
|
|
4949
4949
|
return hash.digest("hex");
|
|
4950
4950
|
}
|
|
4951
4951
|
/**
|
|
@@ -4958,14 +4958,14 @@ var UtilsService = class {
|
|
|
4958
4958
|
/**
|
|
4959
4959
|
* Hash using bcrypt
|
|
4960
4960
|
*/
|
|
4961
|
-
async hashBcrypt(
|
|
4962
|
-
return bcrypt.hash(
|
|
4961
|
+
async hashBcrypt(input3, rounds = 10) {
|
|
4962
|
+
return bcrypt.hash(input3, rounds);
|
|
4963
4963
|
}
|
|
4964
4964
|
/**
|
|
4965
4965
|
* Base64 encode
|
|
4966
4966
|
*/
|
|
4967
|
-
base64Encode(
|
|
4968
|
-
const buffer = typeof
|
|
4967
|
+
base64Encode(input3, urlSafe = false) {
|
|
4968
|
+
const buffer = typeof input3 === "string" ? Buffer.from(input3, "utf-8") : input3;
|
|
4969
4969
|
let encoded = buffer.toString("base64");
|
|
4970
4970
|
if (urlSafe) {
|
|
4971
4971
|
encoded = encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
@@ -4975,8 +4975,8 @@ var UtilsService = class {
|
|
|
4975
4975
|
/**
|
|
4976
4976
|
* Base64 decode
|
|
4977
4977
|
*/
|
|
4978
|
-
base64Decode(
|
|
4979
|
-
let normalized =
|
|
4978
|
+
base64Decode(input3) {
|
|
4979
|
+
let normalized = input3.replace(/-/g, "+").replace(/_/g, "/");
|
|
4980
4980
|
while (normalized.length % 4) {
|
|
4981
4981
|
normalized += "=";
|
|
4982
4982
|
}
|
|
@@ -5105,14 +5105,14 @@ var UtilsService = class {
|
|
|
5105
5105
|
/**
|
|
5106
5106
|
* URL encode
|
|
5107
5107
|
*/
|
|
5108
|
-
urlEncode(
|
|
5109
|
-
return full ? encodeURI(
|
|
5108
|
+
urlEncode(input3, full = false) {
|
|
5109
|
+
return full ? encodeURI(input3) : encodeURIComponent(input3);
|
|
5110
5110
|
}
|
|
5111
5111
|
/**
|
|
5112
5112
|
* URL decode
|
|
5113
5113
|
*/
|
|
5114
|
-
urlDecode(
|
|
5115
|
-
return full ? decodeURI(
|
|
5114
|
+
urlDecode(input3, full = false) {
|
|
5115
|
+
return full ? decodeURI(input3) : decodeURIComponent(input3);
|
|
5116
5116
|
}
|
|
5117
5117
|
/**
|
|
5118
5118
|
* Format bytes to human-readable size
|
|
@@ -5222,7 +5222,7 @@ Examples:
|
|
|
5222
5222
|
|
|
5223
5223
|
// src/commands/utils/hash.ts
|
|
5224
5224
|
import { Command as Command17 } from "commander";
|
|
5225
|
-
async function handleHashGeneration(
|
|
5225
|
+
async function handleHashGeneration(input3, options) {
|
|
5226
5226
|
const service = new UtilsService();
|
|
5227
5227
|
try {
|
|
5228
5228
|
let hash;
|
|
@@ -5233,14 +5233,14 @@ async function handleHashGeneration(input2, options) {
|
|
|
5233
5233
|
}
|
|
5234
5234
|
hash = await service.hashFile(options.file, options.algorithm);
|
|
5235
5235
|
} else {
|
|
5236
|
-
if (!
|
|
5236
|
+
if (!input3) {
|
|
5237
5237
|
console.error("\u274C Please provide input text or use --file option");
|
|
5238
5238
|
process.exit(1);
|
|
5239
5239
|
}
|
|
5240
5240
|
if (options.algorithm === "bcrypt") {
|
|
5241
|
-
hash = await service.hashBcrypt(
|
|
5241
|
+
hash = await service.hashBcrypt(input3, options.rounds);
|
|
5242
5242
|
} else {
|
|
5243
|
-
hash = await service.hash(
|
|
5243
|
+
hash = await service.hash(input3, options.algorithm);
|
|
5244
5244
|
}
|
|
5245
5245
|
}
|
|
5246
5246
|
console.log("\u{1F512} Hash Result:");
|
|
@@ -5273,8 +5273,8 @@ Examples:
|
|
|
5273
5273
|
$ jai1 utils hash "password" --algorithm bcrypt --rounds 12
|
|
5274
5274
|
$ jai1 utils hash --file ./myfile.txt
|
|
5275
5275
|
$ jai1 utils hash --file ./image.png --algorithm sha512
|
|
5276
|
-
`).action(async (
|
|
5277
|
-
await handleHashGeneration(
|
|
5276
|
+
`).action(async (input3, options) => {
|
|
5277
|
+
await handleHashGeneration(input3, {
|
|
5278
5278
|
...options,
|
|
5279
5279
|
rounds: parseInt(options.rounds, 10)
|
|
5280
5280
|
});
|
|
@@ -5285,7 +5285,7 @@ Examples:
|
|
|
5285
5285
|
// src/commands/utils/base64-encode.ts
|
|
5286
5286
|
import { Command as Command18 } from "commander";
|
|
5287
5287
|
import { readFile as readFile2 } from "fs/promises";
|
|
5288
|
-
async function handleBase64Encode(
|
|
5288
|
+
async function handleBase64Encode(input3, options) {
|
|
5289
5289
|
const service = new UtilsService();
|
|
5290
5290
|
try {
|
|
5291
5291
|
let encoded;
|
|
@@ -5293,11 +5293,11 @@ async function handleBase64Encode(input2, options) {
|
|
|
5293
5293
|
const content = await readFile2(options.file);
|
|
5294
5294
|
encoded = service.base64Encode(content, options.urlSafe);
|
|
5295
5295
|
} else {
|
|
5296
|
-
if (!
|
|
5296
|
+
if (!input3) {
|
|
5297
5297
|
console.error("\u274C Please provide input text or use --file option");
|
|
5298
5298
|
process.exit(1);
|
|
5299
5299
|
}
|
|
5300
|
-
encoded = service.base64Encode(
|
|
5300
|
+
encoded = service.base64Encode(input3, options.urlSafe);
|
|
5301
5301
|
}
|
|
5302
5302
|
console.log("\u{1F4DD} Base64 Encoded:");
|
|
5303
5303
|
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");
|
|
@@ -5322,8 +5322,8 @@ Examples:
|
|
|
5322
5322
|
$ jai1 utils base64-encode "hello world" --url-safe
|
|
5323
5323
|
$ jai1 utils base64-encode --file ./document.txt
|
|
5324
5324
|
$ jai1 utils base64-encode --file ./image.png
|
|
5325
|
-
`).action(async (
|
|
5326
|
-
await handleBase64Encode(
|
|
5325
|
+
`).action(async (input3, options) => {
|
|
5326
|
+
await handleBase64Encode(input3, options);
|
|
5327
5327
|
});
|
|
5328
5328
|
return cmd;
|
|
5329
5329
|
}
|
|
@@ -5331,18 +5331,18 @@ Examples:
|
|
|
5331
5331
|
// src/commands/utils/base64-decode.ts
|
|
5332
5332
|
import { Command as Command19 } from "commander";
|
|
5333
5333
|
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
5334
|
-
async function handleBase64Decode(
|
|
5334
|
+
async function handleBase64Decode(input3, options) {
|
|
5335
5335
|
const service = new UtilsService();
|
|
5336
5336
|
try {
|
|
5337
5337
|
let encodedInput;
|
|
5338
5338
|
if (options.file) {
|
|
5339
5339
|
encodedInput = await readFile3(options.file, "utf-8");
|
|
5340
5340
|
} else {
|
|
5341
|
-
if (!
|
|
5341
|
+
if (!input3) {
|
|
5342
5342
|
console.error("\u274C Please provide Base64 input or use --file option");
|
|
5343
5343
|
process.exit(1);
|
|
5344
5344
|
}
|
|
5345
|
-
encodedInput =
|
|
5345
|
+
encodedInput = input3;
|
|
5346
5346
|
}
|
|
5347
5347
|
const decoded = service.base64Decode(encodedInput.trim());
|
|
5348
5348
|
if (options.output) {
|
|
@@ -5367,8 +5367,8 @@ Examples:
|
|
|
5367
5367
|
$ jai1 utils base64-decode --file ./encoded.txt
|
|
5368
5368
|
$ jai1 utils base64-decode "aGVsbG8=" --output ./decoded.txt
|
|
5369
5369
|
$ jai1 utils base64-decode --file ./encoded.txt --output ./image.png
|
|
5370
|
-
`).action(async (
|
|
5371
|
-
await handleBase64Decode(
|
|
5370
|
+
`).action(async (input3, options) => {
|
|
5371
|
+
await handleBase64Decode(input3, options);
|
|
5372
5372
|
});
|
|
5373
5373
|
return cmd;
|
|
5374
5374
|
}
|
|
@@ -5519,10 +5519,10 @@ Examples:
|
|
|
5519
5519
|
|
|
5520
5520
|
// src/commands/utils/unix-time.ts
|
|
5521
5521
|
import { Command as Command22 } from "commander";
|
|
5522
|
-
async function handleUnixTime(
|
|
5522
|
+
async function handleUnixTime(input3, options) {
|
|
5523
5523
|
const service = new UtilsService();
|
|
5524
5524
|
try {
|
|
5525
|
-
if (!
|
|
5525
|
+
if (!input3) {
|
|
5526
5526
|
const now = /* @__PURE__ */ new Date();
|
|
5527
5527
|
const timestamp = service.dateToUnix(now, options.ms);
|
|
5528
5528
|
console.log("\u{1F552} Current Unix Timestamp:");
|
|
@@ -5532,8 +5532,8 @@ async function handleUnixTime(input2, options) {
|
|
|
5532
5532
|
console.log(` ISO: ${now.toISOString()}`);
|
|
5533
5533
|
console.log(` Local: ${now.toLocaleString()}`);
|
|
5534
5534
|
console.log();
|
|
5535
|
-
} else if (/^\d+$/.test(
|
|
5536
|
-
const timestamp = parseInt(
|
|
5535
|
+
} else if (/^\d+$/.test(input3)) {
|
|
5536
|
+
const timestamp = parseInt(input3, 10);
|
|
5537
5537
|
const date = service.unixToDate(timestamp, options.ms);
|
|
5538
5538
|
console.log("\u{1F552} Unix Timestamp to Date:");
|
|
5539
5539
|
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");
|
|
@@ -5546,7 +5546,7 @@ async function handleUnixTime(input2, options) {
|
|
|
5546
5546
|
}
|
|
5547
5547
|
console.log();
|
|
5548
5548
|
} else {
|
|
5549
|
-
const date = new Date(
|
|
5549
|
+
const date = new Date(input3);
|
|
5550
5550
|
if (isNaN(date.getTime())) {
|
|
5551
5551
|
console.error("\u274C Invalid date format");
|
|
5552
5552
|
process.exit(1);
|
|
@@ -5554,7 +5554,7 @@ async function handleUnixTime(input2, options) {
|
|
|
5554
5554
|
const timestamp = service.dateToUnix(date, options.ms);
|
|
5555
5555
|
console.log("\u{1F552} Date to Unix Timestamp:");
|
|
5556
5556
|
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");
|
|
5557
|
-
console.log(` Input: ${
|
|
5557
|
+
console.log(` Input: ${input3}`);
|
|
5558
5558
|
console.log(` Parsed: ${date.toISOString()}`);
|
|
5559
5559
|
console.log();
|
|
5560
5560
|
console.log(` ${timestamp}${options.ms ? " (ms)" : ""}`);
|
|
@@ -5574,8 +5574,8 @@ Examples:
|
|
|
5574
5574
|
$ jai1 utils unix-time "2024-01-15 10:30:00"
|
|
5575
5575
|
$ jai1 utils unix-time "2024-01-15" --format local
|
|
5576
5576
|
$ jai1 utils unix-time --ms
|
|
5577
|
-
`).action(async (
|
|
5578
|
-
await handleUnixTime(
|
|
5577
|
+
`).action(async (input3, options) => {
|
|
5578
|
+
await handleUnixTime(input3, options);
|
|
5579
5579
|
});
|
|
5580
5580
|
return cmd;
|
|
5581
5581
|
}
|
|
@@ -5632,10 +5632,10 @@ Examples:
|
|
|
5632
5632
|
|
|
5633
5633
|
// src/commands/utils/url-encode.ts
|
|
5634
5634
|
import { Command as Command24 } from "commander";
|
|
5635
|
-
async function handleUrlEncode(
|
|
5635
|
+
async function handleUrlEncode(input3, options) {
|
|
5636
5636
|
const service = new UtilsService();
|
|
5637
5637
|
try {
|
|
5638
|
-
const encoded = service.urlEncode(
|
|
5638
|
+
const encoded = service.urlEncode(input3, options.full);
|
|
5639
5639
|
console.log("\u{1F517} URL Encoded:");
|
|
5640
5640
|
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");
|
|
5641
5641
|
if (options.full) {
|
|
@@ -5658,18 +5658,18 @@ Examples:
|
|
|
5658
5658
|
$ jai1 utils url-encode "hello world & test"
|
|
5659
5659
|
$ jai1 utils url-encode "name=John Doe&age=30"
|
|
5660
5660
|
$ jai1 utils url-encode "https://example.com/path with spaces" --full
|
|
5661
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
5662
|
-
await handleUrlEncode(
|
|
5661
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input3, options) => {
|
|
5662
|
+
await handleUrlEncode(input3, options);
|
|
5663
5663
|
});
|
|
5664
5664
|
return cmd;
|
|
5665
5665
|
}
|
|
5666
5666
|
|
|
5667
5667
|
// src/commands/utils/url-decode.ts
|
|
5668
5668
|
import { Command as Command25 } from "commander";
|
|
5669
|
-
async function handleUrlDecode(
|
|
5669
|
+
async function handleUrlDecode(input3, options) {
|
|
5670
5670
|
const service = new UtilsService();
|
|
5671
5671
|
try {
|
|
5672
|
-
const decoded = service.urlDecode(
|
|
5672
|
+
const decoded = service.urlDecode(input3, options.full);
|
|
5673
5673
|
console.log("\u{1F517} URL Decoded:");
|
|
5674
5674
|
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");
|
|
5675
5675
|
if (options.full) {
|
|
@@ -5692,8 +5692,8 @@ Examples:
|
|
|
5692
5692
|
$ jai1 utils url-decode "hello%20world%20%26%20test"
|
|
5693
5693
|
$ jai1 utils url-decode "name%3DJohn%20Doe%26age%3D30"
|
|
5694
5694
|
$ jai1 utils url-decode "https://example.com/path%20with%20spaces" --full
|
|
5695
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
5696
|
-
await handleUrlDecode(
|
|
5695
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input3, options) => {
|
|
5696
|
+
await handleUrlDecode(input3, options);
|
|
5697
5697
|
});
|
|
5698
5698
|
return cmd;
|
|
5699
5699
|
}
|
|
@@ -5829,14 +5829,14 @@ var PasswordView = () => {
|
|
|
5829
5829
|
React27.useEffect(() => {
|
|
5830
5830
|
handleGenerate();
|
|
5831
5831
|
}, []);
|
|
5832
|
-
useInput12((
|
|
5832
|
+
useInput12((input3, key) => {
|
|
5833
5833
|
if (key.tab) {
|
|
5834
5834
|
if (focusedField === "length") setFocusedField("count");
|
|
5835
5835
|
else if (focusedField === "count") setFocusedField("generate");
|
|
5836
5836
|
else setFocusedField("length");
|
|
5837
5837
|
} else if (key.return) {
|
|
5838
5838
|
handleGenerate();
|
|
5839
|
-
} else if (
|
|
5839
|
+
} else if (input3 === "c" && passwords.length > 0) {
|
|
5840
5840
|
handleCopy(0);
|
|
5841
5841
|
}
|
|
5842
5842
|
});
|
|
@@ -5919,7 +5919,7 @@ var UuidView = () => {
|
|
|
5919
5919
|
React28.useEffect(() => {
|
|
5920
5920
|
handleGenerate();
|
|
5921
5921
|
}, []);
|
|
5922
|
-
useInput13((
|
|
5922
|
+
useInput13((input3, key) => {
|
|
5923
5923
|
if (key.tab) {
|
|
5924
5924
|
const fields = ["count", "uppercase", "hyphens", "generate"];
|
|
5925
5925
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -5932,7 +5932,7 @@ var UuidView = () => {
|
|
|
5932
5932
|
} else {
|
|
5933
5933
|
handleGenerate();
|
|
5934
5934
|
}
|
|
5935
|
-
} else if (
|
|
5935
|
+
} else if (input3 === "c" && uuids.length > 0) {
|
|
5936
5936
|
handleCopy(0);
|
|
5937
5937
|
}
|
|
5938
5938
|
});
|
|
@@ -6007,7 +6007,7 @@ var HashView = () => {
|
|
|
6007
6007
|
React29.useEffect(() => {
|
|
6008
6008
|
handleGenerate();
|
|
6009
6009
|
}, []);
|
|
6010
|
-
useInput14((
|
|
6010
|
+
useInput14((input3, key) => {
|
|
6011
6011
|
if (key.tab) {
|
|
6012
6012
|
const fields = ["text", "algorithm", "generate"];
|
|
6013
6013
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -6020,7 +6020,7 @@ var HashView = () => {
|
|
|
6020
6020
|
} else if (key.rightArrow && focusedField === "algorithm") {
|
|
6021
6021
|
const currentIndex = ALGORITHMS.indexOf(algorithm);
|
|
6022
6022
|
setAlgorithm(ALGORITHMS[(currentIndex + 1) % ALGORITHMS.length]);
|
|
6023
|
-
} else if (
|
|
6023
|
+
} else if (input3 === "c" && hash) {
|
|
6024
6024
|
handleCopy();
|
|
6025
6025
|
}
|
|
6026
6026
|
});
|
|
@@ -6086,7 +6086,7 @@ import React30, { useState as useState17 } from "react";
|
|
|
6086
6086
|
import { Box as Box20, Text as Text21, useInput as useInput15 } from "ink";
|
|
6087
6087
|
import TextInput7 from "ink-text-input";
|
|
6088
6088
|
var Base64View = () => {
|
|
6089
|
-
const [
|
|
6089
|
+
const [input3, setInput] = useState17("");
|
|
6090
6090
|
const [mode, setMode] = useState17("encode");
|
|
6091
6091
|
const [urlSafe, setUrlSafe] = useState17(false);
|
|
6092
6092
|
const [result, setResult] = useState17("");
|
|
@@ -6094,7 +6094,7 @@ var Base64View = () => {
|
|
|
6094
6094
|
const [focusedField, setFocusedField] = useState17("input");
|
|
6095
6095
|
const [copied, setCopied] = useState17(false);
|
|
6096
6096
|
const service = new UtilsService();
|
|
6097
|
-
useInput15((
|
|
6097
|
+
useInput15((input4, key) => {
|
|
6098
6098
|
if (key.tab) {
|
|
6099
6099
|
const fields = ["input", "mode", "urlsafe", "convert"];
|
|
6100
6100
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -6109,22 +6109,22 @@ var Base64View = () => {
|
|
|
6109
6109
|
} else {
|
|
6110
6110
|
handleConvert();
|
|
6111
6111
|
}
|
|
6112
|
-
} else if (
|
|
6112
|
+
} else if (input4 === "c" && result) {
|
|
6113
6113
|
handleCopy();
|
|
6114
6114
|
}
|
|
6115
6115
|
});
|
|
6116
6116
|
const handleConvert = () => {
|
|
6117
|
-
if (!
|
|
6117
|
+
if (!input3) {
|
|
6118
6118
|
setError("Input cannot be empty");
|
|
6119
6119
|
return;
|
|
6120
6120
|
}
|
|
6121
6121
|
try {
|
|
6122
6122
|
setError("");
|
|
6123
6123
|
if (mode === "encode") {
|
|
6124
|
-
const encoded = service.base64Encode(
|
|
6124
|
+
const encoded = service.base64Encode(input3, urlSafe);
|
|
6125
6125
|
setResult(encoded);
|
|
6126
6126
|
} else {
|
|
6127
|
-
const decoded = service.base64Decode(
|
|
6127
|
+
const decoded = service.base64Decode(input3);
|
|
6128
6128
|
setResult(decoded.toString("utf-8"));
|
|
6129
6129
|
}
|
|
6130
6130
|
setCopied(false);
|
|
@@ -6153,7 +6153,7 @@ var Base64View = () => {
|
|
|
6153
6153
|
marginBottom: 1
|
|
6154
6154
|
},
|
|
6155
6155
|
/* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
6156
|
-
/* @__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:
|
|
6156
|
+
/* @__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: input3, onChange: setInput, placeholder: "Enter text..." }) : /* @__PURE__ */ React30.createElement(Text21, { dimColor: !input3 }, input3 || "(empty)"))),
|
|
6157
6157
|
/* @__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)")),
|
|
6158
6158
|
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 _)")),
|
|
6159
6159
|
/* @__PURE__ */ React30.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(
|
|
@@ -6198,14 +6198,14 @@ import React31, { useState as useState18 } from "react";
|
|
|
6198
6198
|
import { Box as Box21, Text as Text22, useInput as useInput16 } from "ink";
|
|
6199
6199
|
import TextInput8 from "ink-text-input";
|
|
6200
6200
|
var UrlView = () => {
|
|
6201
|
-
const [
|
|
6201
|
+
const [input3, setInput] = useState18("");
|
|
6202
6202
|
const [mode, setMode] = useState18("encode");
|
|
6203
6203
|
const [fullUrl, setFullUrl] = useState18(false);
|
|
6204
6204
|
const [result, setResult] = useState18("");
|
|
6205
6205
|
const [focusedField, setFocusedField] = useState18("input");
|
|
6206
6206
|
const [copied, setCopied] = useState18(false);
|
|
6207
6207
|
const service = new UtilsService();
|
|
6208
|
-
useInput16((
|
|
6208
|
+
useInput16((input4, key) => {
|
|
6209
6209
|
if (key.tab) {
|
|
6210
6210
|
const fields = ["input", "mode", "full", "convert"];
|
|
6211
6211
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -6219,17 +6219,17 @@ var UrlView = () => {
|
|
|
6219
6219
|
} else {
|
|
6220
6220
|
handleConvert();
|
|
6221
6221
|
}
|
|
6222
|
-
} else if (
|
|
6222
|
+
} else if (input4 === "c" && result) {
|
|
6223
6223
|
handleCopy();
|
|
6224
6224
|
}
|
|
6225
6225
|
});
|
|
6226
6226
|
const handleConvert = () => {
|
|
6227
|
-
if (!
|
|
6227
|
+
if (!input3) return;
|
|
6228
6228
|
if (mode === "encode") {
|
|
6229
|
-
const encoded = fullUrl ? service.urlEncode(
|
|
6229
|
+
const encoded = fullUrl ? service.urlEncode(input3, true) : service.urlEncode(input3, false);
|
|
6230
6230
|
setResult(encoded);
|
|
6231
6231
|
} else {
|
|
6232
|
-
const decoded = fullUrl ? service.urlDecode(
|
|
6232
|
+
const decoded = fullUrl ? service.urlDecode(input3, true) : service.urlDecode(input3, false);
|
|
6233
6233
|
setResult(decoded);
|
|
6234
6234
|
}
|
|
6235
6235
|
setCopied(false);
|
|
@@ -6254,7 +6254,7 @@ var UrlView = () => {
|
|
|
6254
6254
|
marginBottom: 1
|
|
6255
6255
|
},
|
|
6256
6256
|
/* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
6257
|
-
/* @__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:
|
|
6257
|
+
/* @__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: input3, onChange: setInput, placeholder: "Enter text or URL..." }) : /* @__PURE__ */ React31.createElement(Text22, { dimColor: !input3 }, input3 || "(empty)"))),
|
|
6258
6258
|
/* @__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)")),
|
|
6259
6259
|
/* @__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)")),
|
|
6260
6260
|
/* @__PURE__ */ React31.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(
|
|
@@ -6288,7 +6288,7 @@ import React32, { useState as useState19 } from "react";
|
|
|
6288
6288
|
import { Box as Box22, Text as Text23, useInput as useInput17 } from "ink";
|
|
6289
6289
|
import TextInput9 from "ink-text-input";
|
|
6290
6290
|
var UnixTimeView = () => {
|
|
6291
|
-
const [
|
|
6291
|
+
const [input3, setInput] = useState19("");
|
|
6292
6292
|
const [mode, setMode] = useState19("now");
|
|
6293
6293
|
const [format, setFormat] = useState19("iso");
|
|
6294
6294
|
const [useMs, setUseMs] = useState19(false);
|
|
@@ -6297,7 +6297,7 @@ var UnixTimeView = () => {
|
|
|
6297
6297
|
const [focusedField, setFocusedField] = useState19("mode");
|
|
6298
6298
|
const [copied, setCopied] = useState19(false);
|
|
6299
6299
|
const service = new UtilsService();
|
|
6300
|
-
useInput17((
|
|
6300
|
+
useInput17((input4, key) => {
|
|
6301
6301
|
if (key.tab) {
|
|
6302
6302
|
const fields = mode === "now" ? ["mode", "ms", "convert"] : mode === "to-human" ? ["mode", "input", "format", "convert"] : ["mode", "input", "convert"];
|
|
6303
6303
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -6318,7 +6318,7 @@ var UnixTimeView = () => {
|
|
|
6318
6318
|
} else {
|
|
6319
6319
|
handleConvert();
|
|
6320
6320
|
}
|
|
6321
|
-
} else if (
|
|
6321
|
+
} else if (input4 === "c" && result) {
|
|
6322
6322
|
handleCopy();
|
|
6323
6323
|
}
|
|
6324
6324
|
});
|
|
@@ -6329,18 +6329,18 @@ var UnixTimeView = () => {
|
|
|
6329
6329
|
const timestamp = service.unixTimeCurrent(useMs);
|
|
6330
6330
|
setResult(timestamp.toString());
|
|
6331
6331
|
} else if (mode === "to-human") {
|
|
6332
|
-
if (!
|
|
6332
|
+
if (!input3) {
|
|
6333
6333
|
setError("Please enter a timestamp");
|
|
6334
6334
|
return;
|
|
6335
6335
|
}
|
|
6336
|
-
const human = service.unixTimeToHuman(parseInt(
|
|
6336
|
+
const human = service.unixTimeToHuman(parseInt(input3, 10), format);
|
|
6337
6337
|
setResult(human);
|
|
6338
6338
|
} else {
|
|
6339
|
-
if (!
|
|
6339
|
+
if (!input3) {
|
|
6340
6340
|
setError("Please enter a date string");
|
|
6341
6341
|
return;
|
|
6342
6342
|
}
|
|
6343
|
-
const timestamp = service.unixTimeFromString(
|
|
6343
|
+
const timestamp = service.unixTimeFromString(input3);
|
|
6344
6344
|
setResult(timestamp.toString());
|
|
6345
6345
|
}
|
|
6346
6346
|
setCopied(false);
|
|
@@ -6373,11 +6373,11 @@ var UnixTimeView = () => {
|
|
|
6373
6373
|
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(
|
|
6374
6374
|
TextInput9,
|
|
6375
6375
|
{
|
|
6376
|
-
value:
|
|
6376
|
+
value: input3,
|
|
6377
6377
|
onChange: setInput,
|
|
6378
6378
|
placeholder: mode === "to-human" ? "1702550400" : "2024-01-15 10:30:00"
|
|
6379
6379
|
}
|
|
6380
|
-
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !
|
|
6380
|
+
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !input3 }, input3 || "(empty)"))),
|
|
6381
6381
|
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)")),
|
|
6382
6382
|
mode === "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "ms" ? "green" : void 0 }, focusedField === "ms" ? "\u25B6 " : " ", "[", useMs ? "\u2713" : " ", "] Milliseconds")),
|
|
6383
6383
|
/* @__PURE__ */ React32.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(
|
|
@@ -6431,7 +6431,7 @@ var JwtView = () => {
|
|
|
6431
6431
|
const [focusedField, setFocusedField] = useState20("mode");
|
|
6432
6432
|
const [copied, setCopied] = useState20(false);
|
|
6433
6433
|
const service = new UtilsService();
|
|
6434
|
-
useInput18((
|
|
6434
|
+
useInput18((input3, key) => {
|
|
6435
6435
|
if (key.tab) {
|
|
6436
6436
|
const fields = mode === "decode" ? ["mode", "token", "process"] : ["mode", "payload", "secret", "process"];
|
|
6437
6437
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -6444,7 +6444,7 @@ var JwtView = () => {
|
|
|
6444
6444
|
} else {
|
|
6445
6445
|
handleProcess();
|
|
6446
6446
|
}
|
|
6447
|
-
} else if (
|
|
6447
|
+
} else if (input3 === "c" && result.token) {
|
|
6448
6448
|
handleCopy();
|
|
6449
6449
|
}
|
|
6450
6450
|
});
|
|
@@ -6569,12 +6569,12 @@ var CronView = () => {
|
|
|
6569
6569
|
const [focusedField, setFocusedField] = useState21("expression");
|
|
6570
6570
|
const [copied, setCopied] = useState21(false);
|
|
6571
6571
|
const service = new UtilsService();
|
|
6572
|
-
useInput19((
|
|
6572
|
+
useInput19((input3, key) => {
|
|
6573
6573
|
if (key.tab) {
|
|
6574
6574
|
setFocusedField(focusedField === "expression" ? "parse" : "expression");
|
|
6575
6575
|
} else if (key.return) {
|
|
6576
6576
|
handleParse();
|
|
6577
|
-
} else if (
|
|
6577
|
+
} else if (input3 === "c" && result) {
|
|
6578
6578
|
handleCopy();
|
|
6579
6579
|
}
|
|
6580
6580
|
});
|
|
@@ -6675,14 +6675,14 @@ var TimezoneView = () => {
|
|
|
6675
6675
|
const [focusedField, setFocusedField] = useState22("time");
|
|
6676
6676
|
const [copied, setCopied] = useState22(false);
|
|
6677
6677
|
const service = new UtilsService();
|
|
6678
|
-
useInput20((
|
|
6678
|
+
useInput20((input3, key) => {
|
|
6679
6679
|
if (key.tab) {
|
|
6680
6680
|
const fields = ["time", "from", "to", "convert"];
|
|
6681
6681
|
const currentIndex = fields.indexOf(focusedField);
|
|
6682
6682
|
setFocusedField(fields[(currentIndex + 1) % fields.length]);
|
|
6683
6683
|
} else if (key.return) {
|
|
6684
6684
|
handleConvert();
|
|
6685
|
-
} else if (
|
|
6685
|
+
} else if (input3 === "c" && result) {
|
|
6686
6686
|
handleCopy();
|
|
6687
6687
|
}
|
|
6688
6688
|
});
|
|
@@ -6801,7 +6801,7 @@ var HttpView = () => {
|
|
|
6801
6801
|
const [focusedField, setFocusedField] = useState23("url");
|
|
6802
6802
|
const [copied, setCopied] = useState23(false);
|
|
6803
6803
|
const service = new UtilsService();
|
|
6804
|
-
useInput21((
|
|
6804
|
+
useInput21((input3, key) => {
|
|
6805
6805
|
if (loading) return;
|
|
6806
6806
|
if (key.tab) {
|
|
6807
6807
|
const fields = ["url", "method", "headers", "body", "send"];
|
|
@@ -6815,7 +6815,7 @@ var HttpView = () => {
|
|
|
6815
6815
|
setMethod(METHODS[(currentIndex + 1) % METHODS.length]);
|
|
6816
6816
|
} else if (key.return && focusedField === "send") {
|
|
6817
6817
|
handleSend();
|
|
6818
|
-
} else if (
|
|
6818
|
+
} else if (input3 === "c" && response) {
|
|
6819
6819
|
handleCopy();
|
|
6820
6820
|
}
|
|
6821
6821
|
});
|
|
@@ -6946,7 +6946,7 @@ var MarkdownView = () => {
|
|
|
6946
6946
|
const [content, setContent] = useState24("");
|
|
6947
6947
|
const [error, setError] = useState24("");
|
|
6948
6948
|
const [focusedField, setFocusedField] = useState24("file");
|
|
6949
|
-
useInput22((
|
|
6949
|
+
useInput22((input3, key) => {
|
|
6950
6950
|
if (key.tab) {
|
|
6951
6951
|
setFocusedField(focusedField === "file" ? "preview" : "file");
|
|
6952
6952
|
} else if (key.return) {
|
|
@@ -7061,20 +7061,20 @@ var UtilsApp = ({ onExit }) => {
|
|
|
7061
7061
|
const [selectedIndex, setSelectedIndex] = useState25(0);
|
|
7062
7062
|
const [activeView, setActiveView] = useState25(null);
|
|
7063
7063
|
const { exit } = useApp5();
|
|
7064
|
-
useInput23((
|
|
7064
|
+
useInput23((input3, key) => {
|
|
7065
7065
|
if (activeView) {
|
|
7066
7066
|
if (key.escape) {
|
|
7067
7067
|
setActiveView(null);
|
|
7068
7068
|
}
|
|
7069
7069
|
return;
|
|
7070
7070
|
}
|
|
7071
|
-
if (key.upArrow ||
|
|
7071
|
+
if (key.upArrow || input3 === "k") {
|
|
7072
7072
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : MENU_ITEMS2.length - 1);
|
|
7073
|
-
} else if (key.downArrow ||
|
|
7073
|
+
} else if (key.downArrow || input3 === "j") {
|
|
7074
7074
|
setSelectedIndex((prev) => prev < MENU_ITEMS2.length - 1 ? prev + 1 : 0);
|
|
7075
7075
|
} else if (key.return) {
|
|
7076
7076
|
setActiveView(MENU_ITEMS2[selectedIndex].id);
|
|
7077
|
-
} else if (
|
|
7077
|
+
} else if (input3 === "q" || key.escape) {
|
|
7078
7078
|
onExit();
|
|
7079
7079
|
exit();
|
|
7080
7080
|
}
|
|
@@ -7238,14 +7238,417 @@ Quick Usage:
|
|
|
7238
7238
|
return utilsCommand;
|
|
7239
7239
|
}
|
|
7240
7240
|
|
|
7241
|
+
// src/commands/deps/index.ts
|
|
7242
|
+
import { Command as Command30 } from "commander";
|
|
7243
|
+
|
|
7244
|
+
// src/commands/deps/upgrade.ts
|
|
7245
|
+
import { Command as Command29 } from "commander";
|
|
7246
|
+
import { checkbox as checkbox3, confirm as confirm4 } from "@inquirer/prompts";
|
|
7247
|
+
|
|
7248
|
+
// src/services/deps.service.ts
|
|
7249
|
+
import { promises as fs9 } from "fs";
|
|
7250
|
+
import path6 from "path";
|
|
7251
|
+
import { execSync } from "child_process";
|
|
7252
|
+
import pLimit2 from "p-limit";
|
|
7253
|
+
var DepsService = class {
|
|
7254
|
+
versionCache = /* @__PURE__ */ new Map();
|
|
7255
|
+
/**
|
|
7256
|
+
* Đọc package.json từ thư mục
|
|
7257
|
+
*/
|
|
7258
|
+
async readPackageJson(cwd) {
|
|
7259
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
7260
|
+
try {
|
|
7261
|
+
const content = await fs9.readFile(pkgPath, "utf-8");
|
|
7262
|
+
return JSON.parse(content);
|
|
7263
|
+
} catch (error) {
|
|
7264
|
+
if (error.code === "ENOENT") {
|
|
7265
|
+
throw new Error("Kh\xF4ng t\xECm th\u1EA5y package.json trong th\u01B0 m\u1EE5c hi\u1EC7n t\u1EA1i");
|
|
7266
|
+
}
|
|
7267
|
+
throw new Error(`L\u1ED7i \u0111\u1ECDc package.json: ${error.message}`);
|
|
7268
|
+
}
|
|
7269
|
+
}
|
|
7270
|
+
/**
|
|
7271
|
+
* Lấy version mới nhất từ npm registry
|
|
7272
|
+
*/
|
|
7273
|
+
async fetchLatestVersion(packageName) {
|
|
7274
|
+
if (this.versionCache.has(packageName)) {
|
|
7275
|
+
return this.versionCache.get(packageName);
|
|
7276
|
+
}
|
|
7277
|
+
try {
|
|
7278
|
+
const response = await fetch(
|
|
7279
|
+
`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`,
|
|
7280
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
7281
|
+
);
|
|
7282
|
+
if (!response.ok) {
|
|
7283
|
+
return null;
|
|
7284
|
+
}
|
|
7285
|
+
const data = await response.json();
|
|
7286
|
+
this.versionCache.set(packageName, data.version);
|
|
7287
|
+
return data.version;
|
|
7288
|
+
} catch {
|
|
7289
|
+
return null;
|
|
7290
|
+
}
|
|
7291
|
+
}
|
|
7292
|
+
/**
|
|
7293
|
+
* Fetch nhiều packages cùng lúc với giới hạn concurrent
|
|
7294
|
+
*/
|
|
7295
|
+
async fetchBulkVersions(packages, onProgress) {
|
|
7296
|
+
const limit = pLimit2(10);
|
|
7297
|
+
const total = packages.length;
|
|
7298
|
+
let completed = 0;
|
|
7299
|
+
const results = await Promise.all(
|
|
7300
|
+
packages.map(
|
|
7301
|
+
(pkg) => limit(async () => {
|
|
7302
|
+
const latest = await this.fetchLatestVersion(pkg.name);
|
|
7303
|
+
completed++;
|
|
7304
|
+
onProgress?.(completed, total);
|
|
7305
|
+
if (!latest) {
|
|
7306
|
+
return null;
|
|
7307
|
+
}
|
|
7308
|
+
const currentClean = this.stripSemverPrefix(pkg.current);
|
|
7309
|
+
const canUpgrade = this.isNewerVersion(latest, currentClean);
|
|
7310
|
+
return {
|
|
7311
|
+
name: pkg.name,
|
|
7312
|
+
current: pkg.current,
|
|
7313
|
+
latest,
|
|
7314
|
+
latestWithPrefix: this.preserveSemverPrefix(pkg.current, latest),
|
|
7315
|
+
type: pkg.type,
|
|
7316
|
+
canUpgrade
|
|
7317
|
+
};
|
|
7318
|
+
})
|
|
7319
|
+
)
|
|
7320
|
+
);
|
|
7321
|
+
return results.filter((r) => r !== null && r.canUpgrade);
|
|
7322
|
+
}
|
|
7323
|
+
/**
|
|
7324
|
+
* Loại bỏ semver prefix (^, ~, >=, etc.)
|
|
7325
|
+
*/
|
|
7326
|
+
stripSemverPrefix(version) {
|
|
7327
|
+
return version.replace(/^[~^>=<]+/, "");
|
|
7328
|
+
}
|
|
7329
|
+
/**
|
|
7330
|
+
* Giữ nguyên semver prefix khi upgrade
|
|
7331
|
+
*/
|
|
7332
|
+
preserveSemverPrefix(current, latest) {
|
|
7333
|
+
const match = current.match(/^([~^>=<]*)/);
|
|
7334
|
+
const prefix = match?.[1] || "";
|
|
7335
|
+
return prefix + latest;
|
|
7336
|
+
}
|
|
7337
|
+
/**
|
|
7338
|
+
* So sánh version để xác định có cần upgrade không
|
|
7339
|
+
*/
|
|
7340
|
+
isNewerVersion(remote, local) {
|
|
7341
|
+
const remoteParts = remote.split(".").map(Number);
|
|
7342
|
+
const localParts = local.split(".").map(Number);
|
|
7343
|
+
for (let i = 0; i < 3; i++) {
|
|
7344
|
+
const r = remoteParts[i] || 0;
|
|
7345
|
+
const l = localParts[i] || 0;
|
|
7346
|
+
if (r > l) return true;
|
|
7347
|
+
if (r < l) return false;
|
|
7348
|
+
}
|
|
7349
|
+
return false;
|
|
7350
|
+
}
|
|
7351
|
+
/**
|
|
7352
|
+
* Detect package manager từ lock files
|
|
7353
|
+
* Priority:
|
|
7354
|
+
* 1. Lock file trong project
|
|
7355
|
+
* 2. pnpm nếu có cài đặt trong máy
|
|
7356
|
+
* 3. npm (fallback)
|
|
7357
|
+
*/
|
|
7358
|
+
async detectPackageManager(cwd) {
|
|
7359
|
+
const lockFiles = [
|
|
7360
|
+
{ file: "pnpm-lock.yaml", pm: "pnpm" },
|
|
7361
|
+
{ file: "yarn.lock", pm: "yarn" },
|
|
7362
|
+
{ file: "bun.lockb", pm: "bun" },
|
|
7363
|
+
{ file: "package-lock.json", pm: "npm" }
|
|
7364
|
+
];
|
|
7365
|
+
for (const { file, pm } of lockFiles) {
|
|
7366
|
+
try {
|
|
7367
|
+
await fs9.access(path6.join(cwd, file));
|
|
7368
|
+
return pm;
|
|
7369
|
+
} catch {
|
|
7370
|
+
}
|
|
7371
|
+
}
|
|
7372
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
7373
|
+
if (userAgent.includes("pnpm")) return "pnpm";
|
|
7374
|
+
if (userAgent.includes("yarn")) return "yarn";
|
|
7375
|
+
if (userAgent.includes("bun")) return "bun";
|
|
7376
|
+
if (userAgent.includes("npm")) return "npm";
|
|
7377
|
+
if (this.isCommandAvailable("pnpm")) return "pnpm";
|
|
7378
|
+
return "npm";
|
|
7379
|
+
}
|
|
7380
|
+
/**
|
|
7381
|
+
* Kiểm tra command có sẵn trong hệ thống không
|
|
7382
|
+
*/
|
|
7383
|
+
isCommandAvailable(command) {
|
|
7384
|
+
try {
|
|
7385
|
+
execSync(`${command} --version`, {
|
|
7386
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7387
|
+
});
|
|
7388
|
+
return true;
|
|
7389
|
+
} catch {
|
|
7390
|
+
return false;
|
|
7391
|
+
}
|
|
7392
|
+
}
|
|
7393
|
+
/**
|
|
7394
|
+
* Tạo command để upgrade packages
|
|
7395
|
+
*/
|
|
7396
|
+
getUpgradeCommands(packages, pm) {
|
|
7397
|
+
const deps = packages.filter((p) => p.type === "dep");
|
|
7398
|
+
const devDeps = packages.filter((p) => p.type === "dev");
|
|
7399
|
+
const formatPackages = (pkgs) => pkgs.map((p) => `${p.name}@${p.latestWithPrefix}`).join(" ");
|
|
7400
|
+
let depsCmd = null;
|
|
7401
|
+
let devDepsCmd = null;
|
|
7402
|
+
if (deps.length > 0) {
|
|
7403
|
+
const pkgList = formatPackages(deps);
|
|
7404
|
+
switch (pm) {
|
|
7405
|
+
case "pnpm":
|
|
7406
|
+
depsCmd = `pnpm add ${pkgList}`;
|
|
7407
|
+
break;
|
|
7408
|
+
case "yarn":
|
|
7409
|
+
depsCmd = `yarn add ${pkgList}`;
|
|
7410
|
+
break;
|
|
7411
|
+
case "bun":
|
|
7412
|
+
depsCmd = `bun add ${pkgList}`;
|
|
7413
|
+
break;
|
|
7414
|
+
default:
|
|
7415
|
+
depsCmd = `npm install ${pkgList}`;
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
if (devDeps.length > 0) {
|
|
7419
|
+
const pkgList = formatPackages(devDeps);
|
|
7420
|
+
switch (pm) {
|
|
7421
|
+
case "pnpm":
|
|
7422
|
+
devDepsCmd = `pnpm add -D ${pkgList}`;
|
|
7423
|
+
break;
|
|
7424
|
+
case "yarn":
|
|
7425
|
+
devDepsCmd = `yarn add -D ${pkgList}`;
|
|
7426
|
+
break;
|
|
7427
|
+
case "bun":
|
|
7428
|
+
devDepsCmd = `bun add -D ${pkgList}`;
|
|
7429
|
+
break;
|
|
7430
|
+
default:
|
|
7431
|
+
devDepsCmd = `npm install -D ${pkgList}`;
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7434
|
+
return { deps: depsCmd, devDeps: devDepsCmd };
|
|
7435
|
+
}
|
|
7436
|
+
/**
|
|
7437
|
+
* Thực thi upgrade command
|
|
7438
|
+
*/
|
|
7439
|
+
executeUpgrade(command) {
|
|
7440
|
+
execSync(command, {
|
|
7441
|
+
stdio: "inherit",
|
|
7442
|
+
env: { ...process.env, FORCE_COLOR: "1" }
|
|
7443
|
+
});
|
|
7444
|
+
}
|
|
7445
|
+
};
|
|
7446
|
+
|
|
7447
|
+
// src/commands/deps/upgrade.ts
|
|
7448
|
+
var colors2 = {
|
|
7449
|
+
yellow: "\x1B[33m",
|
|
7450
|
+
green: "\x1B[32m",
|
|
7451
|
+
cyan: "\x1B[36m",
|
|
7452
|
+
red: "\x1B[31m",
|
|
7453
|
+
gray: "\x1B[90m",
|
|
7454
|
+
reset: "\x1B[0m",
|
|
7455
|
+
bold: "\x1B[1m",
|
|
7456
|
+
dim: "\x1B[2m"
|
|
7457
|
+
};
|
|
7458
|
+
function createDepsUpgradeCommand() {
|
|
7459
|
+
return new Command29("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) => {
|
|
7460
|
+
await handleDepsUpgrade(options);
|
|
7461
|
+
});
|
|
7462
|
+
}
|
|
7463
|
+
async function handleDepsUpgrade(options) {
|
|
7464
|
+
const depsService = new DepsService();
|
|
7465
|
+
const cwd = process.cwd();
|
|
7466
|
+
try {
|
|
7467
|
+
console.log(`
|
|
7468
|
+
${colors2.cyan}\u{1F50D} \u0110ang \u0111\u1ECDc package.json...${colors2.reset}`);
|
|
7469
|
+
const pkg = await depsService.readPackageJson(cwd);
|
|
7470
|
+
const packagesToCheck = [];
|
|
7471
|
+
if (!options.devOnly && pkg.dependencies) {
|
|
7472
|
+
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
7473
|
+
if (isNpmVersion(version)) {
|
|
7474
|
+
packagesToCheck.push({ name, current: version, type: "dep" });
|
|
7475
|
+
}
|
|
7476
|
+
}
|
|
7477
|
+
}
|
|
7478
|
+
if (!options.depsOnly && pkg.devDependencies) {
|
|
7479
|
+
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
7480
|
+
if (isNpmVersion(version)) {
|
|
7481
|
+
packagesToCheck.push({ name, current: version, type: "dev" });
|
|
7482
|
+
}
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
if (packagesToCheck.length === 0) {
|
|
7486
|
+
console.log(`${colors2.yellow}\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y packages \u0111\u1EC3 ki\u1EC3m tra${colors2.reset}
|
|
7487
|
+
`);
|
|
7488
|
+
return;
|
|
7489
|
+
}
|
|
7490
|
+
const depsCount = packagesToCheck.filter((p) => p.type === "dep").length;
|
|
7491
|
+
const devCount = packagesToCheck.filter((p) => p.type === "dev").length;
|
|
7492
|
+
console.log(
|
|
7493
|
+
`${colors2.bold}\u{1F4E6} T\xECm th\u1EA5y ${depsCount} dependencies v\xE0 ${devCount} devDependencies${colors2.reset}
|
|
7494
|
+
`
|
|
7495
|
+
);
|
|
7496
|
+
console.log(`${colors2.cyan}\u23F3 Ki\u1EC3m tra phi\xEAn b\u1EA3n m\u1EDBi nh\u1EA5t...${colors2.reset}`);
|
|
7497
|
+
const upgradablePackages = await depsService.fetchBulkVersions(
|
|
7498
|
+
packagesToCheck,
|
|
7499
|
+
(completed, total) => {
|
|
7500
|
+
const progress = Math.round(completed / total * 100);
|
|
7501
|
+
const bar = "\u2588".repeat(Math.floor(progress / 5)) + "\u2591".repeat(20 - Math.floor(progress / 5));
|
|
7502
|
+
process.stdout.write(`\r[${bar}] ${completed}/${total} packages`);
|
|
7503
|
+
}
|
|
7504
|
+
);
|
|
7505
|
+
console.log("\n");
|
|
7506
|
+
if (upgradablePackages.length === 0) {
|
|
7507
|
+
console.log(`${colors2.green}\u2705 T\u1EA5t c\u1EA3 packages \u0111\xE3 l\xE0 phi\xEAn b\u1EA3n m\u1EDBi nh\u1EA5t!${colors2.reset}
|
|
7508
|
+
`);
|
|
7509
|
+
return;
|
|
7510
|
+
}
|
|
7511
|
+
displayUpgradeTable(upgradablePackages);
|
|
7512
|
+
if (options.check) {
|
|
7513
|
+
console.log(
|
|
7514
|
+
`${colors2.cyan}\u{1F4A1} Ch\u1EA1y "jai1 deps upgrade" \u0111\u1EC3 ti\u1EBFn h\xE0nh upgrade.${colors2.reset}
|
|
7515
|
+
`
|
|
7516
|
+
);
|
|
7517
|
+
return;
|
|
7518
|
+
}
|
|
7519
|
+
let selectedPackages;
|
|
7520
|
+
if (options.all) {
|
|
7521
|
+
selectedPackages = upgradablePackages;
|
|
7522
|
+
console.log(`${colors2.cyan}\u{1F4CB} \u0110\xE3 ch\u1ECDn t\u1EA5t c\u1EA3 ${selectedPackages.length} packages${colors2.reset}
|
|
7523
|
+
`);
|
|
7524
|
+
} else {
|
|
7525
|
+
try {
|
|
7526
|
+
const selected = await checkbox3({
|
|
7527
|
+
message: "Ch\u1ECDn packages \u0111\u1EC3 upgrade (ESC \u0111\u1EC3 h\u1EE7y):",
|
|
7528
|
+
choices: upgradablePackages.map((pkg2) => ({
|
|
7529
|
+
name: `${pkg2.name} (${pkg2.current} \u2192 ${pkg2.latestWithPrefix}) [${pkg2.type}]`,
|
|
7530
|
+
value: pkg2.name,
|
|
7531
|
+
checked: true
|
|
7532
|
+
// Mặc định chọn tất cả
|
|
7533
|
+
})),
|
|
7534
|
+
instructions: "\u2191\u2193 navigate \u2022 space select \u2022 a all \u2022 i invert \u2022 \u23CE submit \u2022 esc cancel"
|
|
7535
|
+
});
|
|
7536
|
+
if (selected.length === 0) {
|
|
7537
|
+
console.log(`${colors2.yellow}\u23F8\uFE0F Kh\xF4ng c\xF3 packages n\xE0o \u0111\u01B0\u1EE3c ch\u1ECDn${colors2.reset}
|
|
7538
|
+
`);
|
|
7539
|
+
return;
|
|
7540
|
+
}
|
|
7541
|
+
selectedPackages = upgradablePackages.filter((pkg2) => selected.includes(pkg2.name));
|
|
7542
|
+
} catch {
|
|
7543
|
+
console.log(`
|
|
7544
|
+
${colors2.yellow}\u23F8\uFE0F \u0110\xE3 h\u1EE7y${colors2.reset}
|
|
7545
|
+
`);
|
|
7546
|
+
return;
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
let shouldProceed;
|
|
7550
|
+
try {
|
|
7551
|
+
shouldProceed = await confirm4({
|
|
7552
|
+
message: `Ti\u1EBFn h\xE0nh upgrade ${selectedPackages.length} packages?`,
|
|
7553
|
+
default: true
|
|
7554
|
+
});
|
|
7555
|
+
} catch {
|
|
7556
|
+
console.log(`
|
|
7557
|
+
${colors2.yellow}\u23F8\uFE0F \u0110\xE3 h\u1EE7y${colors2.reset}
|
|
7558
|
+
`);
|
|
7559
|
+
return;
|
|
7560
|
+
}
|
|
7561
|
+
if (!shouldProceed) {
|
|
7562
|
+
console.log(`${colors2.yellow}\u23F8\uFE0F Upgrade \u0111\xE3 h\u1EE7y${colors2.reset}
|
|
7563
|
+
`);
|
|
7564
|
+
return;
|
|
7565
|
+
}
|
|
7566
|
+
const pm = await depsService.detectPackageManager(cwd);
|
|
7567
|
+
console.log(`
|
|
7568
|
+
${colors2.cyan}\u{1F527} Package manager: ${pm}${colors2.reset}`);
|
|
7569
|
+
console.log(`${colors2.cyan}\u{1F4E5} \u0110ang upgrade...${colors2.reset}
|
|
7570
|
+
`);
|
|
7571
|
+
const commands = depsService.getUpgradeCommands(selectedPackages, pm);
|
|
7572
|
+
try {
|
|
7573
|
+
if (commands.deps) {
|
|
7574
|
+
console.log(`${colors2.dim}$ ${commands.deps}${colors2.reset}
|
|
7575
|
+
`);
|
|
7576
|
+
depsService.executeUpgrade(commands.deps);
|
|
7577
|
+
}
|
|
7578
|
+
if (commands.devDeps) {
|
|
7579
|
+
console.log(`
|
|
7580
|
+
${colors2.dim}$ ${commands.devDeps}${colors2.reset}
|
|
7581
|
+
`);
|
|
7582
|
+
depsService.executeUpgrade(commands.devDeps);
|
|
7583
|
+
}
|
|
7584
|
+
console.log(
|
|
7585
|
+
`
|
|
7586
|
+
${colors2.green}\u2705 \u0110\xE3 upgrade ${selectedPackages.length} packages th\xE0nh c\xF4ng!${colors2.reset}
|
|
7587
|
+
`
|
|
7588
|
+
);
|
|
7589
|
+
} catch (error) {
|
|
7590
|
+
console.error(`
|
|
7591
|
+
${colors2.red}\u274C L\u1ED7i khi upgrade:${colors2.reset}`);
|
|
7592
|
+
console.error(`${colors2.red}${error.message}${colors2.reset}
|
|
7593
|
+
`);
|
|
7594
|
+
console.log(`${colors2.yellow}\u{1F4A1} B\u1EA1n c\xF3 th\u1EC3 th\u1EED upgrade th\u1EE7 c\xF4ng:${colors2.reset}`);
|
|
7595
|
+
if (commands.deps) console.log(` ${colors2.cyan}${commands.deps}${colors2.reset}`);
|
|
7596
|
+
if (commands.devDeps) console.log(` ${colors2.cyan}${commands.devDeps}${colors2.reset}`);
|
|
7597
|
+
console.log("");
|
|
7598
|
+
process.exit(1);
|
|
7599
|
+
}
|
|
7600
|
+
} catch (error) {
|
|
7601
|
+
console.error(`
|
|
7602
|
+
${colors2.red}\u274C ${error.message}${colors2.reset}
|
|
7603
|
+
`);
|
|
7604
|
+
process.exit(1);
|
|
7605
|
+
}
|
|
7606
|
+
}
|
|
7607
|
+
function isNpmVersion(version) {
|
|
7608
|
+
if (version.startsWith("git") || version.startsWith("github") || version.startsWith("file:") || version.startsWith("link:") || version.startsWith("workspace:") || version.includes("://")) {
|
|
7609
|
+
return false;
|
|
7610
|
+
}
|
|
7611
|
+
return true;
|
|
7612
|
+
}
|
|
7613
|
+
function displayUpgradeTable(packages) {
|
|
7614
|
+
console.log(`${colors2.bold}\u{1F4CA} C\xF3 th\u1EC3 upgrade:${colors2.reset}
|
|
7615
|
+
`);
|
|
7616
|
+
const nameWidth = Math.max(7, ...packages.map((p) => p.name.length));
|
|
7617
|
+
const currentWidth = Math.max(8, ...packages.map((p) => p.current.length));
|
|
7618
|
+
const latestWidth = Math.max(8, ...packages.map((p) => p.latestWithPrefix.length));
|
|
7619
|
+
const header = `\u2502 ${"Package".padEnd(nameWidth)} \u2502 ${"Hi\u1EC7n t\u1EA1i".padEnd(currentWidth)} \u2502 ${"M\u1EDBi nh\u1EA5t".padEnd(latestWidth)} \u2502 Lo\u1EA1i \u2502`;
|
|
7620
|
+
const separator = `\u251C${"\u2500".repeat(nameWidth + 2)}\u253C${"\u2500".repeat(currentWidth + 2)}\u253C${"\u2500".repeat(latestWidth + 2)}\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2524`;
|
|
7621
|
+
const topBorder = `\u250C${"\u2500".repeat(nameWidth + 2)}\u252C${"\u2500".repeat(currentWidth + 2)}\u252C${"\u2500".repeat(latestWidth + 2)}\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2510`;
|
|
7622
|
+
const bottomBorder = `\u2514${"\u2500".repeat(nameWidth + 2)}\u2534${"\u2500".repeat(currentWidth + 2)}\u2534${"\u2500".repeat(latestWidth + 2)}\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2518`;
|
|
7623
|
+
console.log(topBorder);
|
|
7624
|
+
console.log(header);
|
|
7625
|
+
console.log(separator);
|
|
7626
|
+
for (const pkg of packages) {
|
|
7627
|
+
const typeLabel = pkg.type === "dep" ? "dep " : "dev ";
|
|
7628
|
+
const typeColor = pkg.type === "dep" ? colors2.cyan : colors2.yellow;
|
|
7629
|
+
console.log(
|
|
7630
|
+
`\u2502 ${pkg.name.padEnd(nameWidth)} \u2502 ${colors2.gray}${pkg.current.padEnd(currentWidth)}${colors2.reset} \u2502 ${colors2.green}${pkg.latestWithPrefix.padEnd(latestWidth)}${colors2.reset} \u2502 ${typeColor}${typeLabel}${colors2.reset}\u2502`
|
|
7631
|
+
);
|
|
7632
|
+
}
|
|
7633
|
+
console.log(bottomBorder);
|
|
7634
|
+
console.log("");
|
|
7635
|
+
}
|
|
7636
|
+
|
|
7637
|
+
// src/commands/deps/index.ts
|
|
7638
|
+
function createDepsCommand() {
|
|
7639
|
+
const depsCommand = new Command30("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
|
|
7640
|
+
depsCommand.addCommand(createDepsUpgradeCommand());
|
|
7641
|
+
return depsCommand;
|
|
7642
|
+
}
|
|
7643
|
+
|
|
7241
7644
|
// src/commands/kit/index.ts
|
|
7242
|
-
import { Command as
|
|
7645
|
+
import { Command as Command34 } from "commander";
|
|
7243
7646
|
|
|
7244
7647
|
// src/commands/kit/list.ts
|
|
7245
|
-
import { Command as
|
|
7648
|
+
import { Command as Command31 } from "commander";
|
|
7246
7649
|
|
|
7247
7650
|
// src/services/starter-kit.service.ts
|
|
7248
|
-
import { promises as
|
|
7651
|
+
import { promises as fs10 } from "fs";
|
|
7249
7652
|
import { join as join4 } from "path";
|
|
7250
7653
|
import AdmZip from "adm-zip";
|
|
7251
7654
|
var StarterKitService = class {
|
|
@@ -7294,22 +7697,22 @@ var StarterKitService = class {
|
|
|
7294
7697
|
}
|
|
7295
7698
|
if (onProgress) onProgress(30);
|
|
7296
7699
|
const tmpDir = join4(process.env.TMPDIR || "/tmp", "jai1-kits");
|
|
7297
|
-
await
|
|
7700
|
+
await fs10.mkdir(tmpDir, { recursive: true });
|
|
7298
7701
|
const tmpFile = join4(tmpDir, `${slug}.zip`);
|
|
7299
7702
|
const buffer = await response.arrayBuffer();
|
|
7300
|
-
await
|
|
7703
|
+
await fs10.writeFile(tmpFile, Buffer.from(buffer));
|
|
7301
7704
|
if (onProgress) onProgress(60);
|
|
7302
7705
|
const zip = new AdmZip(tmpFile);
|
|
7303
|
-
await
|
|
7706
|
+
await fs10.mkdir(targetDir, { recursive: true });
|
|
7304
7707
|
zip.extractAllTo(targetDir, true);
|
|
7305
7708
|
if (onProgress) onProgress(100);
|
|
7306
|
-
await
|
|
7709
|
+
await fs10.unlink(tmpFile);
|
|
7307
7710
|
}
|
|
7308
7711
|
};
|
|
7309
7712
|
|
|
7310
7713
|
// src/commands/kit/list.ts
|
|
7311
7714
|
function createKitListCommand() {
|
|
7312
|
-
return new
|
|
7715
|
+
return new Command31("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) => {
|
|
7313
7716
|
const configService = new ConfigService();
|
|
7314
7717
|
const config = await configService.load();
|
|
7315
7718
|
if (!config) {
|
|
@@ -7346,9 +7749,9 @@ function createKitListCommand() {
|
|
|
7346
7749
|
}
|
|
7347
7750
|
|
|
7348
7751
|
// src/commands/kit/info.ts
|
|
7349
|
-
import { Command as
|
|
7752
|
+
import { Command as Command32 } from "commander";
|
|
7350
7753
|
function createKitInfoCommand() {
|
|
7351
|
-
return new
|
|
7754
|
+
return new Command32("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
|
|
7352
7755
|
const configService = new ConfigService();
|
|
7353
7756
|
const config = await configService.load();
|
|
7354
7757
|
if (!config) {
|
|
@@ -7397,10 +7800,10 @@ Post-Init Commands:`);
|
|
|
7397
7800
|
}
|
|
7398
7801
|
|
|
7399
7802
|
// src/commands/kit/create.ts
|
|
7400
|
-
import { Command as
|
|
7401
|
-
import { promises as
|
|
7803
|
+
import { Command as Command33 } from "commander";
|
|
7804
|
+
import { promises as fs11 } from "fs";
|
|
7402
7805
|
import { join as join5 } from "path";
|
|
7403
|
-
import { select as select2, input, checkbox as
|
|
7806
|
+
import { select as select2, input, checkbox as checkbox4 } from "@inquirer/prompts";
|
|
7404
7807
|
import { execa as execa2 } from "execa";
|
|
7405
7808
|
|
|
7406
7809
|
// src/services/hook-executor.service.ts
|
|
@@ -7442,7 +7845,7 @@ var HookExecutor = class {
|
|
|
7442
7845
|
|
|
7443
7846
|
// src/commands/kit/create.ts
|
|
7444
7847
|
function createKitCreateCommand() {
|
|
7445
|
-
return new
|
|
7848
|
+
return new Command33("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) => {
|
|
7446
7849
|
const configService = new ConfigService();
|
|
7447
7850
|
const config = await configService.load();
|
|
7448
7851
|
if (!config) {
|
|
@@ -7464,7 +7867,7 @@ function createKitCreateCommand() {
|
|
|
7464
7867
|
}
|
|
7465
7868
|
const targetDir = directory || join5(process.cwd(), options.name || slug);
|
|
7466
7869
|
try {
|
|
7467
|
-
await
|
|
7870
|
+
await fs11.access(targetDir);
|
|
7468
7871
|
throw new Error(`Directory already exists: ${targetDir}`);
|
|
7469
7872
|
} catch (error) {
|
|
7470
7873
|
if (error.code !== "ENOENT") {
|
|
@@ -7555,7 +7958,7 @@ function createKitCreateCommand() {
|
|
|
7555
7958
|
}
|
|
7556
7959
|
} else {
|
|
7557
7960
|
const defaultTargets = kit.config.ide?.defaultTargets || [];
|
|
7558
|
-
const answer = await
|
|
7961
|
+
const answer = await checkbox4({
|
|
7559
7962
|
message: "Ch\u1ECDn IDE \u0111\u1EC3 sync framework:",
|
|
7560
7963
|
choices: ideChoices.map((c) => ({
|
|
7561
7964
|
...c,
|
|
@@ -7582,7 +7985,7 @@ function createKitCreateCommand() {
|
|
|
7582
7985
|
async function applyVariableSubstitution(dir, variables) {
|
|
7583
7986
|
const files = await getAllFiles(dir);
|
|
7584
7987
|
for (const file of files) {
|
|
7585
|
-
let content = await
|
|
7988
|
+
let content = await fs11.readFile(file, "utf-8");
|
|
7586
7989
|
let modified = false;
|
|
7587
7990
|
for (const [key, value] of Object.entries(variables)) {
|
|
7588
7991
|
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
@@ -7592,13 +7995,13 @@ async function applyVariableSubstitution(dir, variables) {
|
|
|
7592
7995
|
}
|
|
7593
7996
|
}
|
|
7594
7997
|
if (modified) {
|
|
7595
|
-
await
|
|
7998
|
+
await fs11.writeFile(file, content, "utf-8");
|
|
7596
7999
|
}
|
|
7597
8000
|
}
|
|
7598
8001
|
}
|
|
7599
8002
|
async function getAllFiles(dir) {
|
|
7600
8003
|
const files = [];
|
|
7601
|
-
const entries = await
|
|
8004
|
+
const entries = await fs11.readdir(dir, { withFileTypes: true });
|
|
7602
8005
|
for (const entry of entries) {
|
|
7603
8006
|
const fullPath = join5(dir, entry.name);
|
|
7604
8007
|
if (entry.isDirectory()) {
|
|
@@ -7614,7 +8017,7 @@ async function getAllFiles(dir) {
|
|
|
7614
8017
|
|
|
7615
8018
|
// src/commands/kit/index.ts
|
|
7616
8019
|
function createKitCommand() {
|
|
7617
|
-
const cmd = new
|
|
8020
|
+
const cmd = new Command34("kit").description("Manage starter kits for new projects").action(() => {
|
|
7618
8021
|
cmd.help();
|
|
7619
8022
|
});
|
|
7620
8023
|
cmd.addCommand(createKitListCommand());
|
|
@@ -7623,11 +8026,355 @@ function createKitCommand() {
|
|
|
7623
8026
|
return cmd;
|
|
7624
8027
|
}
|
|
7625
8028
|
|
|
8029
|
+
// src/commands/rules/index.ts
|
|
8030
|
+
import { Command as Command39 } from "commander";
|
|
8031
|
+
|
|
8032
|
+
// src/commands/rules/list.ts
|
|
8033
|
+
import { Command as Command35 } from "commander";
|
|
8034
|
+
function createRulesListCommand() {
|
|
8035
|
+
return new Command35("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
|
|
8036
|
+
const configService = new ConfigService();
|
|
8037
|
+
const config = await configService.load();
|
|
8038
|
+
if (!config) {
|
|
8039
|
+
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
8040
|
+
}
|
|
8041
|
+
console.log("\u{1F4CB} Fetching available rule presets...\n");
|
|
8042
|
+
try {
|
|
8043
|
+
const response = await fetch(`${config.apiUrl}/api/rules/presets`, {
|
|
8044
|
+
headers: {
|
|
8045
|
+
"JAI1-Access-Key": config.accessKey
|
|
8046
|
+
}
|
|
8047
|
+
});
|
|
8048
|
+
if (!response.ok) {
|
|
8049
|
+
throw new Error(`Failed to fetch presets: ${response.statusText}`);
|
|
8050
|
+
}
|
|
8051
|
+
const data = await response.json();
|
|
8052
|
+
if (options.json) {
|
|
8053
|
+
console.log(JSON.stringify(data, null, 2));
|
|
8054
|
+
return;
|
|
8055
|
+
}
|
|
8056
|
+
if (data.total === 0) {
|
|
8057
|
+
console.log("No presets available.");
|
|
8058
|
+
return;
|
|
8059
|
+
}
|
|
8060
|
+
console.log(`Found ${data.total} preset${data.total > 1 ? "s" : ""}:
|
|
8061
|
+
`);
|
|
8062
|
+
for (const preset of data.presets) {
|
|
8063
|
+
console.log(`\u{1F4E6} ${preset.slug}`);
|
|
8064
|
+
console.log(` Name: ${preset.name}`);
|
|
8065
|
+
console.log(` Description: ${preset.description}`);
|
|
8066
|
+
console.log(` Version: ${preset.version}`);
|
|
8067
|
+
const stackParts = [];
|
|
8068
|
+
if (preset.stack.frontend) stackParts.push(preset.stack.frontend);
|
|
8069
|
+
if (preset.stack.backend) stackParts.push(preset.stack.backend);
|
|
8070
|
+
if (preset.stack.css) stackParts.push(preset.stack.css);
|
|
8071
|
+
if (preset.stack.database) stackParts.push(preset.stack.database);
|
|
8072
|
+
if (stackParts.length > 0) {
|
|
8073
|
+
console.log(` Stack: ${stackParts.join(" + ")}`);
|
|
8074
|
+
}
|
|
8075
|
+
console.log(` Tags: ${preset.tags.join(", ")}`);
|
|
8076
|
+
console.log(` Downloads: ${preset.downloads}`);
|
|
8077
|
+
console.log("");
|
|
8078
|
+
}
|
|
8079
|
+
console.log(`
|
|
8080
|
+
\u2139\uFE0F Use 'jai1 rules init --preset=<slug>' to apply a preset`);
|
|
8081
|
+
} catch (error) {
|
|
8082
|
+
throw new Error(
|
|
8083
|
+
`Failed to list presets: ${error instanceof Error ? error.message : String(error)}`
|
|
8084
|
+
);
|
|
8085
|
+
}
|
|
8086
|
+
});
|
|
8087
|
+
}
|
|
8088
|
+
|
|
8089
|
+
// src/commands/rules/init.ts
|
|
8090
|
+
import { Command as Command36 } from "commander";
|
|
8091
|
+
import { promises as fs12 } from "fs";
|
|
8092
|
+
import { join as join6 } from "path";
|
|
8093
|
+
import { select as select3, confirm as confirm5 } from "@inquirer/prompts";
|
|
8094
|
+
function createRulesInitCommand() {
|
|
8095
|
+
return new Command36("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) => {
|
|
8096
|
+
const configService = new ConfigService();
|
|
8097
|
+
const config = await configService.load();
|
|
8098
|
+
if (!config) {
|
|
8099
|
+
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
8100
|
+
}
|
|
8101
|
+
let presetSlug = options.preset;
|
|
8102
|
+
if (!presetSlug) {
|
|
8103
|
+
console.log("\u{1F4CB} Fetching available presets...\n");
|
|
8104
|
+
const response = await fetch(`${config.apiUrl}/api/rules/presets`, {
|
|
8105
|
+
headers: {
|
|
8106
|
+
"JAI1-Access-Key": config.accessKey
|
|
8107
|
+
}
|
|
8108
|
+
});
|
|
8109
|
+
if (!response.ok) {
|
|
8110
|
+
throw new Error(`Failed to fetch presets: ${response.statusText}`);
|
|
8111
|
+
}
|
|
8112
|
+
const data = await response.json();
|
|
8113
|
+
if (data.total === 0) {
|
|
8114
|
+
console.log("No presets available.");
|
|
8115
|
+
return;
|
|
8116
|
+
}
|
|
8117
|
+
presetSlug = await select3({
|
|
8118
|
+
message: "Select a preset:",
|
|
8119
|
+
choices: data.presets.map((p) => ({
|
|
8120
|
+
name: `${p.name} - ${p.description}`,
|
|
8121
|
+
value: p.slug,
|
|
8122
|
+
description: `v${p.version} | ${p.tags.join(", ")}`
|
|
8123
|
+
}))
|
|
8124
|
+
});
|
|
8125
|
+
}
|
|
8126
|
+
console.log(`
|
|
8127
|
+
\u{1F4E6} Fetching preset: ${presetSlug}...
|
|
8128
|
+
`);
|
|
8129
|
+
const presetResponse = await fetch(`${config.apiUrl}/api/rules/presets/${presetSlug}`, {
|
|
8130
|
+
headers: {
|
|
8131
|
+
"JAI1-Access-Key": config.accessKey
|
|
8132
|
+
}
|
|
8133
|
+
});
|
|
8134
|
+
if (!presetResponse.ok) {
|
|
8135
|
+
if (presetResponse.status === 404) {
|
|
8136
|
+
throw new Error(`Preset '${presetSlug}' not found`);
|
|
8137
|
+
}
|
|
8138
|
+
throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
|
|
8139
|
+
}
|
|
8140
|
+
const bundle = await presetResponse.json();
|
|
8141
|
+
console.log(`\u2713 Preset: ${bundle.preset.name} v${bundle.preset.version}`);
|
|
8142
|
+
console.log(` Files: ${Object.keys(bundle.files).length}`);
|
|
8143
|
+
let outputFormat = options.output;
|
|
8144
|
+
if (!["cursor", "agents-md", "both"].includes(outputFormat)) {
|
|
8145
|
+
outputFormat = await select3({
|
|
8146
|
+
message: "Select output format:",
|
|
8147
|
+
choices: [
|
|
8148
|
+
{ name: "Cursor (.cursor/rules/)", value: "cursor" },
|
|
8149
|
+
{ name: "AGENTS.md (single file)", value: "agents-md" },
|
|
8150
|
+
{ name: "Both", value: "both" }
|
|
8151
|
+
]
|
|
8152
|
+
});
|
|
8153
|
+
}
|
|
8154
|
+
if (!options.yes) {
|
|
8155
|
+
const proceed = await confirm5({
|
|
8156
|
+
message: `Apply preset '${bundle.preset.name}' to current directory?`,
|
|
8157
|
+
default: true
|
|
8158
|
+
});
|
|
8159
|
+
if (!proceed) {
|
|
8160
|
+
console.log("Cancelled.");
|
|
8161
|
+
return;
|
|
8162
|
+
}
|
|
8163
|
+
}
|
|
8164
|
+
console.log("\n\u{1F4DD} Applying preset...\n");
|
|
8165
|
+
if (outputFormat === "cursor" || outputFormat === "both") {
|
|
8166
|
+
await applyCursorFormat(bundle);
|
|
8167
|
+
}
|
|
8168
|
+
if (outputFormat === "agents-md" || outputFormat === "both") {
|
|
8169
|
+
await applyAgentsMdFormat(bundle);
|
|
8170
|
+
}
|
|
8171
|
+
const projectConfig = {
|
|
8172
|
+
preset: bundle.preset.slug,
|
|
8173
|
+
version: bundle.preset.version,
|
|
8174
|
+
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8175
|
+
customContext: "09-custom.mdc"
|
|
8176
|
+
};
|
|
8177
|
+
await fs12.writeFile("jai1-rules.json", JSON.stringify(projectConfig, null, 2));
|
|
8178
|
+
console.log("\u2713 Created jai1-rules.json");
|
|
8179
|
+
console.log("\n\u2705 Preset applied successfully!\n");
|
|
8180
|
+
console.log("Next steps:");
|
|
8181
|
+
console.log(" 1. Edit 09-custom.mdc to add project-specific rules");
|
|
8182
|
+
console.log(" 2. Commit the rules to git");
|
|
8183
|
+
console.log(' 3. Use "jai1 rules sync" to regenerate outputs after editing\n');
|
|
8184
|
+
});
|
|
8185
|
+
}
|
|
8186
|
+
async function applyCursorFormat(bundle) {
|
|
8187
|
+
const rulesDir = join6(process.cwd(), ".cursor", "rules");
|
|
8188
|
+
await fs12.mkdir(rulesDir, { recursive: true });
|
|
8189
|
+
for (const [filename, content] of Object.entries(bundle.files)) {
|
|
8190
|
+
const filePath = join6(rulesDir, filename);
|
|
8191
|
+
await fs12.writeFile(filePath, content, "utf-8");
|
|
8192
|
+
console.log(`\u2713 Created .cursor/rules/${filename}`);
|
|
8193
|
+
}
|
|
8194
|
+
}
|
|
8195
|
+
async function applyAgentsMdFormat(bundle) {
|
|
8196
|
+
const sections = [];
|
|
8197
|
+
sections.push("# AGENTS.md\n");
|
|
8198
|
+
sections.push(`<!-- Generated by jai1 rules - Preset: ${bundle.preset.slug} v${bundle.preset.version} -->
|
|
8199
|
+
`);
|
|
8200
|
+
const fileOrder = [
|
|
8201
|
+
"01-project.mdc",
|
|
8202
|
+
"02-standards.mdc",
|
|
8203
|
+
"03-frontend.mdc",
|
|
8204
|
+
"04-backend.mdc",
|
|
8205
|
+
"05-testing.mdc",
|
|
8206
|
+
"06-workflow.mdc",
|
|
8207
|
+
"09-custom.mdc"
|
|
8208
|
+
];
|
|
8209
|
+
for (const filename of fileOrder) {
|
|
8210
|
+
if (bundle.files[filename]) {
|
|
8211
|
+
const content = bundle.files[filename];
|
|
8212
|
+
const withoutFrontmatter = content.replace(/^---\n[\s\S]*?\n---\n/, "");
|
|
8213
|
+
sections.push(withoutFrontmatter.trim());
|
|
8214
|
+
sections.push("\n");
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
const agentsMd = sections.join("\n");
|
|
8218
|
+
await fs12.writeFile("AGENTS.md", agentsMd, "utf-8");
|
|
8219
|
+
console.log("\u2713 Created AGENTS.md");
|
|
8220
|
+
}
|
|
8221
|
+
|
|
8222
|
+
// src/commands/rules/sync.ts
|
|
8223
|
+
import { Command as Command37 } from "commander";
|
|
8224
|
+
import { promises as fs13 } from "fs";
|
|
8225
|
+
import { join as join7 } from "path";
|
|
8226
|
+
function createRulesSyncCommand() {
|
|
8227
|
+
return new Command37("sync").description("Regenerate rule outputs after editing custom context").action(async () => {
|
|
8228
|
+
const configPath = join7(process.cwd(), "jai1-rules.json");
|
|
8229
|
+
let projectConfig;
|
|
8230
|
+
try {
|
|
8231
|
+
const configContent = await fs13.readFile(configPath, "utf-8");
|
|
8232
|
+
projectConfig = JSON.parse(configContent);
|
|
8233
|
+
} catch {
|
|
8234
|
+
throw new ValidationError(
|
|
8235
|
+
'No jai1-rules.json found. Run "jai1 rules init" first.'
|
|
8236
|
+
);
|
|
8237
|
+
}
|
|
8238
|
+
console.log("\u{1F504} Syncing rules...\n");
|
|
8239
|
+
console.log(`Preset: ${projectConfig.preset} v${projectConfig.version}`);
|
|
8240
|
+
const hasCursorRules = await checkPathExists(".cursor/rules");
|
|
8241
|
+
const hasAgentsMd = await checkPathExists("AGENTS.md");
|
|
8242
|
+
if (!hasCursorRules && !hasAgentsMd) {
|
|
8243
|
+
throw new ValidationError(
|
|
8244
|
+
'No rule outputs found. Run "jai1 rules init" first.'
|
|
8245
|
+
);
|
|
8246
|
+
}
|
|
8247
|
+
if (hasCursorRules) {
|
|
8248
|
+
await syncCursorFormat(projectConfig);
|
|
8249
|
+
}
|
|
8250
|
+
if (hasAgentsMd) {
|
|
8251
|
+
await syncAgentsMdFormat(projectConfig);
|
|
8252
|
+
}
|
|
8253
|
+
console.log("\n\u2705 Rules synced successfully!\n");
|
|
8254
|
+
});
|
|
8255
|
+
}
|
|
8256
|
+
async function checkPathExists(path8) {
|
|
8257
|
+
try {
|
|
8258
|
+
await fs13.access(join7(process.cwd(), path8));
|
|
8259
|
+
return true;
|
|
8260
|
+
} catch {
|
|
8261
|
+
return false;
|
|
8262
|
+
}
|
|
8263
|
+
}
|
|
8264
|
+
async function syncCursorFormat(config) {
|
|
8265
|
+
const customPath = join7(process.cwd(), ".cursor", "rules", config.customContext);
|
|
8266
|
+
try {
|
|
8267
|
+
await fs13.access(customPath);
|
|
8268
|
+
console.log(`\u2713 Custom context found: ${config.customContext}`);
|
|
8269
|
+
} catch {
|
|
8270
|
+
console.log(`\u26A0\uFE0F Warning: ${config.customContext} not found in .cursor/rules/`);
|
|
8271
|
+
}
|
|
8272
|
+
console.log("\u2713 Cursor rules (.cursor/rules/) - no changes needed");
|
|
8273
|
+
console.log(" (Files are already in place, edit them directly)");
|
|
8274
|
+
}
|
|
8275
|
+
async function syncAgentsMdFormat(config) {
|
|
8276
|
+
const rulesDir = join7(process.cwd(), ".cursor", "rules");
|
|
8277
|
+
try {
|
|
8278
|
+
await fs13.access(rulesDir);
|
|
8279
|
+
} catch {
|
|
8280
|
+
console.log("\u26A0\uFE0F Warning: .cursor/rules/ not found, cannot regenerate AGENTS.md");
|
|
8281
|
+
return;
|
|
8282
|
+
}
|
|
8283
|
+
const sections = [];
|
|
8284
|
+
sections.push("# AGENTS.md\n");
|
|
8285
|
+
sections.push(`<!-- Generated by jai1 rules - Preset: ${config.preset} v${config.version} -->
|
|
8286
|
+
`);
|
|
8287
|
+
sections.push(`<!-- Last synced: ${(/* @__PURE__ */ new Date()).toISOString()} -->
|
|
8288
|
+
`);
|
|
8289
|
+
const fileOrder = [
|
|
8290
|
+
"01-project.mdc",
|
|
8291
|
+
"02-standards.mdc",
|
|
8292
|
+
"03-frontend.mdc",
|
|
8293
|
+
"04-backend.mdc",
|
|
8294
|
+
"05-testing.mdc",
|
|
8295
|
+
"06-workflow.mdc",
|
|
8296
|
+
"09-custom.mdc"
|
|
8297
|
+
];
|
|
8298
|
+
for (const filename of fileOrder) {
|
|
8299
|
+
const filePath = join7(rulesDir, filename);
|
|
8300
|
+
try {
|
|
8301
|
+
const content = await fs13.readFile(filePath, "utf-8");
|
|
8302
|
+
const withoutFrontmatter = content.replace(/^---\n[\s\S]*?\n---\n/, "");
|
|
8303
|
+
sections.push(withoutFrontmatter.trim());
|
|
8304
|
+
sections.push("\n");
|
|
8305
|
+
} catch {
|
|
8306
|
+
continue;
|
|
8307
|
+
}
|
|
8308
|
+
}
|
|
8309
|
+
const agentsMd = sections.join("\n");
|
|
8310
|
+
await fs13.writeFile("AGENTS.md", agentsMd, "utf-8");
|
|
8311
|
+
console.log("\u2713 Regenerated AGENTS.md");
|
|
8312
|
+
}
|
|
8313
|
+
|
|
8314
|
+
// src/commands/rules/info.ts
|
|
8315
|
+
import { Command as Command38 } from "commander";
|
|
8316
|
+
import { promises as fs14 } from "fs";
|
|
8317
|
+
import { join as join8 } from "path";
|
|
8318
|
+
function createRulesInfoCommand() {
|
|
8319
|
+
return new Command38("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
|
|
8320
|
+
const configPath = join8(process.cwd(), "jai1-rules.json");
|
|
8321
|
+
let projectConfig;
|
|
8322
|
+
try {
|
|
8323
|
+
const configContent = await fs14.readFile(configPath, "utf-8");
|
|
8324
|
+
projectConfig = JSON.parse(configContent);
|
|
8325
|
+
} catch {
|
|
8326
|
+
throw new ValidationError(
|
|
8327
|
+
'No jai1-rules.json found. Run "jai1 rules init" first.'
|
|
8328
|
+
);
|
|
8329
|
+
}
|
|
8330
|
+
if (options.json) {
|
|
8331
|
+
console.log(JSON.stringify(projectConfig, null, 2));
|
|
8332
|
+
return;
|
|
8333
|
+
}
|
|
8334
|
+
console.log("\u{1F4CB} Current Preset Information\n");
|
|
8335
|
+
console.log(`Preset: ${projectConfig.preset}`);
|
|
8336
|
+
console.log(`Version: ${projectConfig.version}`);
|
|
8337
|
+
console.log(`Applied at: ${new Date(projectConfig.appliedAt).toLocaleString()}`);
|
|
8338
|
+
console.log(`Custom rules: ${projectConfig.customContext}`);
|
|
8339
|
+
console.log("\nOutput files:");
|
|
8340
|
+
const cursorRulesExists = await checkPathExists2(".cursor/rules");
|
|
8341
|
+
const agentsMdExists = await checkPathExists2("AGENTS.md");
|
|
8342
|
+
if (cursorRulesExists) {
|
|
8343
|
+
console.log(" \u2713 .cursor/rules/");
|
|
8344
|
+
}
|
|
8345
|
+
if (agentsMdExists) {
|
|
8346
|
+
console.log(" \u2713 AGENTS.md");
|
|
8347
|
+
}
|
|
8348
|
+
if (!cursorRulesExists && !agentsMdExists) {
|
|
8349
|
+
console.log(" (none found)");
|
|
8350
|
+
}
|
|
8351
|
+
console.log('\n\u2139\uFE0F Use "jai1 rules sync" to regenerate outputs after editing');
|
|
8352
|
+
});
|
|
8353
|
+
}
|
|
8354
|
+
async function checkPathExists2(path8) {
|
|
8355
|
+
try {
|
|
8356
|
+
await fs14.access(join8(process.cwd(), path8));
|
|
8357
|
+
return true;
|
|
8358
|
+
} catch {
|
|
8359
|
+
return false;
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
8362
|
+
|
|
8363
|
+
// src/commands/rules/index.ts
|
|
8364
|
+
function createRulesCommand() {
|
|
8365
|
+
const rulesCommand = new Command39("rules").description("Manage rule presets for AI agents");
|
|
8366
|
+
rulesCommand.addCommand(createRulesListCommand());
|
|
8367
|
+
rulesCommand.addCommand(createRulesInitCommand());
|
|
8368
|
+
rulesCommand.addCommand(createRulesSyncCommand());
|
|
8369
|
+
rulesCommand.addCommand(createRulesInfoCommand());
|
|
8370
|
+
return rulesCommand;
|
|
8371
|
+
}
|
|
8372
|
+
|
|
7626
8373
|
// src/commands/upgrade.ts
|
|
7627
|
-
import { Command as
|
|
7628
|
-
import { confirm as
|
|
7629
|
-
import { execSync } from "child_process";
|
|
7630
|
-
var
|
|
8374
|
+
import { Command as Command40 } from "commander";
|
|
8375
|
+
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
8376
|
+
import { execSync as execSync2 } from "child_process";
|
|
8377
|
+
var colors3 = {
|
|
7631
8378
|
yellow: "\x1B[33m",
|
|
7632
8379
|
green: "\x1B[32m",
|
|
7633
8380
|
cyan: "\x1B[36m",
|
|
@@ -7636,7 +8383,7 @@ var colors2 = {
|
|
|
7636
8383
|
bold: "\x1B[1m"
|
|
7637
8384
|
};
|
|
7638
8385
|
function createUpgradeCommand() {
|
|
7639
|
-
return new
|
|
8386
|
+
return new Command40("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) => {
|
|
7640
8387
|
await handleUpgrade(options);
|
|
7641
8388
|
});
|
|
7642
8389
|
}
|
|
@@ -7647,7 +8394,7 @@ async function handleUpgrade(options) {
|
|
|
7647
8394
|
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
7648
8395
|
}
|
|
7649
8396
|
try {
|
|
7650
|
-
console.log(`${
|
|
8397
|
+
console.log(`${colors3.cyan}\u{1F50D} Checking for updates...${colors3.reset}`);
|
|
7651
8398
|
const response = await fetch(`${config.apiUrl}/api/versions/client`, {
|
|
7652
8399
|
headers: {
|
|
7653
8400
|
"JAI1-Access-Key": config.accessKey
|
|
@@ -7662,47 +8409,47 @@ async function handleUpgrade(options) {
|
|
|
7662
8409
|
const latestVersion = data.version;
|
|
7663
8410
|
const currentVersion = package_default.version;
|
|
7664
8411
|
console.log(`
|
|
7665
|
-
${
|
|
7666
|
-
console.log(`${
|
|
8412
|
+
${colors3.bold}Current version:${colors3.reset} ${currentVersion}`);
|
|
8413
|
+
console.log(`${colors3.bold}Latest version:${colors3.reset} ${latestVersion}
|
|
7667
8414
|
`);
|
|
7668
8415
|
if (!isNewerVersion2(latestVersion, currentVersion)) {
|
|
7669
|
-
console.log(`${
|
|
8416
|
+
console.log(`${colors3.green}\u2705 You're already on the latest version!${colors3.reset}
|
|
7670
8417
|
`);
|
|
7671
8418
|
return;
|
|
7672
8419
|
}
|
|
7673
|
-
console.log(`${
|
|
7674
|
-
console.log(`${
|
|
7675
|
-
console.log(`${
|
|
8420
|
+
console.log(`${colors3.yellow}\u256D\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\u2500\u2500\u2500\u2500\u2500\u256E${colors3.reset}`);
|
|
8421
|
+
console.log(`${colors3.yellow}\u2502${colors3.reset} ${colors3.bold}\u2B06\uFE0F Update available!${colors3.reset} ${currentVersion} \u2192 ${colors3.cyan}${latestVersion}${colors3.reset} ${colors3.yellow}\u2502${colors3.reset}`);
|
|
8422
|
+
console.log(`${colors3.yellow}\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\u2500\u2500\u2500\u2500\u2500\u256F${colors3.reset}
|
|
7676
8423
|
`);
|
|
7677
8424
|
if (options.check) {
|
|
7678
|
-
console.log(`${
|
|
8425
|
+
console.log(`${colors3.cyan}Run "jai1 upgrade" to install the latest version.${colors3.reset}
|
|
7679
8426
|
`);
|
|
7680
8427
|
return;
|
|
7681
8428
|
}
|
|
7682
8429
|
if (!options.force) {
|
|
7683
|
-
const shouldUpdate = await
|
|
8430
|
+
const shouldUpdate = await confirm6({
|
|
7684
8431
|
message: "Update to the latest version now?",
|
|
7685
8432
|
default: true
|
|
7686
8433
|
});
|
|
7687
8434
|
if (!shouldUpdate) {
|
|
7688
|
-
console.log(`${
|
|
8435
|
+
console.log(`${colors3.yellow}\u23F8\uFE0F Upgrade cancelled.${colors3.reset}
|
|
7689
8436
|
`);
|
|
7690
8437
|
return;
|
|
7691
8438
|
}
|
|
7692
8439
|
}
|
|
7693
8440
|
console.log(`
|
|
7694
|
-
${
|
|
8441
|
+
${colors3.cyan}\u{1F4E5} Installing latest version...${colors3.reset}
|
|
7695
8442
|
`);
|
|
7696
8443
|
try {
|
|
7697
8444
|
const packageManager2 = detectPackageManager();
|
|
7698
8445
|
const installCommand = getInstallCommand(packageManager2);
|
|
7699
|
-
console.log(`${
|
|
7700
|
-
|
|
8446
|
+
console.log(`${colors3.cyan}Using ${packageManager2}...${colors3.reset}`);
|
|
8447
|
+
execSync2(installCommand, {
|
|
7701
8448
|
stdio: "inherit",
|
|
7702
8449
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
7703
8450
|
});
|
|
7704
8451
|
console.log(`
|
|
7705
|
-
${
|
|
8452
|
+
${colors3.green}\u2705 Successfully upgraded to version ${latestVersion}!${colors3.reset}
|
|
7706
8453
|
`);
|
|
7707
8454
|
trackAction("upgrade", {
|
|
7708
8455
|
from_version: currentVersion,
|
|
@@ -7712,17 +8459,17 @@ ${colors2.green}\u2705 Successfully upgraded to version ${latestVersion}!${color
|
|
|
7712
8459
|
disableUpdateCheck();
|
|
7713
8460
|
} catch (error) {
|
|
7714
8461
|
console.error(`
|
|
7715
|
-
${
|
|
7716
|
-
console.error(`${
|
|
8462
|
+
${colors3.red}\u274C Upgrade failed!${colors3.reset}`);
|
|
8463
|
+
console.error(`${colors3.red}Error: ${error instanceof Error ? error.message : "Unknown error"}${colors3.reset}
|
|
7717
8464
|
`);
|
|
7718
|
-
console.error(`${
|
|
8465
|
+
console.error(`${colors3.yellow}\u{1F4A1} You can try manually upgrading with:${colors3.reset}`);
|
|
7719
8466
|
const manualCommands = {
|
|
7720
8467
|
npm: `npm install -g @jvittechs/jai1-cli@latest`,
|
|
7721
8468
|
pnpm: `pnpm add -g @jvittechs/jai1-cli@latest`,
|
|
7722
8469
|
yarn: `yarn global add @jvittechs/jai1-cli@latest`,
|
|
7723
8470
|
bun: `bun add -g @jvittechs/jai1-cli@latest`
|
|
7724
8471
|
};
|
|
7725
|
-
console.error(` ${
|
|
8472
|
+
console.error(` ${colors3.cyan}${manualCommands[packageManager]}${colors3.reset}
|
|
7726
8473
|
`);
|
|
7727
8474
|
throw error;
|
|
7728
8475
|
}
|
|
@@ -7746,7 +8493,7 @@ function isNewerVersion2(remote, local) {
|
|
|
7746
8493
|
}
|
|
7747
8494
|
function detectPackageManager() {
|
|
7748
8495
|
try {
|
|
7749
|
-
const jai1Path =
|
|
8496
|
+
const jai1Path = execSync2("which jai1 || where jai1", {
|
|
7750
8497
|
encoding: "utf-8",
|
|
7751
8498
|
stdio: ["pipe", "pipe", "ignore"]
|
|
7752
8499
|
}).trim();
|
|
@@ -7784,11 +8531,11 @@ function getInstallCommand(packageManager2) {
|
|
|
7784
8531
|
}
|
|
7785
8532
|
|
|
7786
8533
|
// src/commands/clean.ts
|
|
7787
|
-
import { Command as
|
|
7788
|
-
import { confirm as
|
|
7789
|
-
import { join as
|
|
8534
|
+
import { Command as Command41 } from "commander";
|
|
8535
|
+
import { confirm as confirm7, select as select4 } from "@inquirer/prompts";
|
|
8536
|
+
import { join as join9 } from "path";
|
|
7790
8537
|
function createCleanCommand() {
|
|
7791
|
-
return new
|
|
8538
|
+
return new Command41("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) => {
|
|
7792
8539
|
await handleClean(options);
|
|
7793
8540
|
});
|
|
7794
8541
|
}
|
|
@@ -7799,7 +8546,7 @@ async function handleClean(options) {
|
|
|
7799
8546
|
{
|
|
7800
8547
|
name: "Backups",
|
|
7801
8548
|
description: "Component backup files (.jai1_backup/)",
|
|
7802
|
-
path:
|
|
8549
|
+
path: join9(cwd, ".jai1_backup"),
|
|
7803
8550
|
check: async () => {
|
|
7804
8551
|
const backups = await service.listBackups(cwd);
|
|
7805
8552
|
return { exists: backups.length > 0, count: backups.length };
|
|
@@ -7849,7 +8596,7 @@ async function handleClean(options) {
|
|
|
7849
8596
|
console.log(` Path: ${target.path}
|
|
7850
8597
|
`);
|
|
7851
8598
|
}
|
|
7852
|
-
const action = await
|
|
8599
|
+
const action = await select4({
|
|
7853
8600
|
message: "What do you want to clean?",
|
|
7854
8601
|
choices: [
|
|
7855
8602
|
...availableTargets.map(({ target, info }) => ({
|
|
@@ -7883,7 +8630,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
7883
8630
|
}
|
|
7884
8631
|
const countStr = info.count ? ` (${info.count} items)` : "";
|
|
7885
8632
|
if (!skipConfirm) {
|
|
7886
|
-
const confirmed = await
|
|
8633
|
+
const confirmed = await confirm7({
|
|
7887
8634
|
message: `Delete ${target.name}${countStr}?`,
|
|
7888
8635
|
default: false
|
|
7889
8636
|
});
|
|
@@ -7901,7 +8648,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
7901
8648
|
}
|
|
7902
8649
|
|
|
7903
8650
|
// src/commands/redmine/check.ts
|
|
7904
|
-
import { Command as
|
|
8651
|
+
import { Command as Command42 } from "commander";
|
|
7905
8652
|
|
|
7906
8653
|
// src/services/redmine-config.service.ts
|
|
7907
8654
|
import { readFile as readFile6 } from "fs/promises";
|
|
@@ -8002,7 +8749,7 @@ var RedmineConfigService = class {
|
|
|
8002
8749
|
// src/api.ts
|
|
8003
8750
|
import { fetch as fetch2 } from "undici";
|
|
8004
8751
|
import pRetry2 from "p-retry";
|
|
8005
|
-
import
|
|
8752
|
+
import pLimit3 from "p-limit";
|
|
8006
8753
|
var RedmineApiError = class extends Error {
|
|
8007
8754
|
constructor(message, status, response) {
|
|
8008
8755
|
super(message);
|
|
@@ -8020,10 +8767,10 @@ var RedmineApiClient = class {
|
|
|
8020
8767
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
8021
8768
|
this.apiAccessToken = config.apiAccessToken;
|
|
8022
8769
|
this.retryConfig = config.defaults.retry;
|
|
8023
|
-
this.concurrencyLimit =
|
|
8770
|
+
this.concurrencyLimit = pLimit3(config.defaults.concurrency);
|
|
8024
8771
|
}
|
|
8025
|
-
async request(
|
|
8026
|
-
const url = `${this.baseUrl}${
|
|
8772
|
+
async request(path8, options = {}) {
|
|
8773
|
+
const url = `${this.baseUrl}${path8}`;
|
|
8027
8774
|
const headers = {
|
|
8028
8775
|
"X-Redmine-API-Key": this.apiAccessToken,
|
|
8029
8776
|
"Content-Type": "application/json",
|
|
@@ -8084,8 +8831,8 @@ var RedmineApiClient = class {
|
|
|
8084
8831
|
if (include && include.length > 0) {
|
|
8085
8832
|
params.append("include", include.join(","));
|
|
8086
8833
|
}
|
|
8087
|
-
const
|
|
8088
|
-
return this.request(
|
|
8834
|
+
const path8 = `/issues/${issueId}.json${params.toString() ? `?${params.toString()}` : ""}`;
|
|
8835
|
+
return this.request(path8);
|
|
8089
8836
|
}
|
|
8090
8837
|
async getIssues(projectId, options = {}) {
|
|
8091
8838
|
const params = new URLSearchParams();
|
|
@@ -8105,8 +8852,8 @@ var RedmineApiClient = class {
|
|
|
8105
8852
|
if (options.updatedSince) {
|
|
8106
8853
|
params.append("updated_on", `>=${options.updatedSince}`);
|
|
8107
8854
|
}
|
|
8108
|
-
const
|
|
8109
|
-
return this.request(
|
|
8855
|
+
const path8 = `/issues.json?${params.toString()}`;
|
|
8856
|
+
return this.request(path8);
|
|
8110
8857
|
}
|
|
8111
8858
|
async getAllIssues(projectId, options = {}) {
|
|
8112
8859
|
const pageSize = options.pageSize || 100;
|
|
@@ -8208,7 +8955,7 @@ async function checkConnectivity(config) {
|
|
|
8208
8955
|
|
|
8209
8956
|
// src/commands/redmine/check.ts
|
|
8210
8957
|
function createRedmineCheckCommand() {
|
|
8211
|
-
const cmd = new
|
|
8958
|
+
const cmd = new Command42("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
|
|
8212
8959
|
await handleRedmineCheck(options);
|
|
8213
8960
|
});
|
|
8214
8961
|
return cmd;
|
|
@@ -8236,7 +8983,7 @@ async function handleRedmineCheck(options) {
|
|
|
8236
8983
|
}
|
|
8237
8984
|
|
|
8238
8985
|
// src/commands/redmine/sync-issue.ts
|
|
8239
|
-
import { Command as
|
|
8986
|
+
import { Command as Command43 } from "commander";
|
|
8240
8987
|
|
|
8241
8988
|
// src/sync-issue.ts
|
|
8242
8989
|
import { resolve as resolve3, relative } from "path";
|
|
@@ -8612,7 +9359,7 @@ function extractIssueIdFromUrl(url) {
|
|
|
8612
9359
|
|
|
8613
9360
|
// src/commands/redmine/sync-issue.ts
|
|
8614
9361
|
function createSyncIssueCommand() {
|
|
8615
|
-
const cmd = new
|
|
9362
|
+
const cmd = new Command43("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) => {
|
|
8616
9363
|
await handleSyncIssue(options);
|
|
8617
9364
|
});
|
|
8618
9365
|
return cmd;
|
|
@@ -8656,7 +9403,7 @@ async function handleSyncIssue(options) {
|
|
|
8656
9403
|
}
|
|
8657
9404
|
|
|
8658
9405
|
// src/commands/redmine/sync-project.ts
|
|
8659
|
-
import { Command as
|
|
9406
|
+
import { Command as Command44 } from "commander";
|
|
8660
9407
|
|
|
8661
9408
|
// src/sync-project.ts
|
|
8662
9409
|
async function syncProject(config, options = {}) {
|
|
@@ -8726,7 +9473,7 @@ async function syncProject(config, options = {}) {
|
|
|
8726
9473
|
|
|
8727
9474
|
// src/commands/redmine/sync-project.ts
|
|
8728
9475
|
function createSyncProjectCommand() {
|
|
8729
|
-
const cmd = new
|
|
9476
|
+
const cmd = new Command44("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) => {
|
|
8730
9477
|
await handleSyncProject(options);
|
|
8731
9478
|
});
|
|
8732
9479
|
return cmd;
|
|
@@ -8781,12 +9528,12 @@ async function handleSyncProject(options) {
|
|
|
8781
9528
|
}
|
|
8782
9529
|
|
|
8783
9530
|
// src/commands/framework/info.ts
|
|
8784
|
-
import { Command as
|
|
8785
|
-
import { promises as
|
|
8786
|
-
import { join as
|
|
9531
|
+
import { Command as Command45 } from "commander";
|
|
9532
|
+
import { promises as fs15 } from "fs";
|
|
9533
|
+
import { join as join10 } from "path";
|
|
8787
9534
|
import { homedir as homedir5 } from "os";
|
|
8788
9535
|
function createInfoCommand() {
|
|
8789
|
-
const cmd = new
|
|
9536
|
+
const cmd = new Command45("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
|
|
8790
9537
|
await handleInfo(options);
|
|
8791
9538
|
});
|
|
8792
9539
|
return cmd;
|
|
@@ -8797,7 +9544,7 @@ async function handleInfo(options) {
|
|
|
8797
9544
|
if (!config) {
|
|
8798
9545
|
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
8799
9546
|
}
|
|
8800
|
-
const frameworkPath =
|
|
9547
|
+
const frameworkPath = join10(homedir5(), ".jai1", "framework");
|
|
8801
9548
|
const projectStatus = await getProjectStatus2();
|
|
8802
9549
|
const info = {
|
|
8803
9550
|
configPath: configService.getConfigPath(),
|
|
@@ -8832,9 +9579,9 @@ function maskKey3(key) {
|
|
|
8832
9579
|
return "****" + key.slice(-4);
|
|
8833
9580
|
}
|
|
8834
9581
|
async function getProjectStatus2() {
|
|
8835
|
-
const projectJai1 =
|
|
9582
|
+
const projectJai1 = join10(process.cwd(), ".jai1");
|
|
8836
9583
|
try {
|
|
8837
|
-
await
|
|
9584
|
+
await fs15.access(projectJai1);
|
|
8838
9585
|
return { exists: true, version: "Synced" };
|
|
8839
9586
|
} catch {
|
|
8840
9587
|
return { exists: false };
|
|
@@ -8842,10 +9589,10 @@ async function getProjectStatus2() {
|
|
|
8842
9589
|
}
|
|
8843
9590
|
|
|
8844
9591
|
// src/commands/self-update.ts
|
|
8845
|
-
import { Command as
|
|
8846
|
-
import { confirm as
|
|
8847
|
-
import { execSync as
|
|
8848
|
-
var
|
|
9592
|
+
import { Command as Command46 } from "commander";
|
|
9593
|
+
import { confirm as confirm8 } from "@inquirer/prompts";
|
|
9594
|
+
import { execSync as execSync3 } from "child_process";
|
|
9595
|
+
var colors4 = {
|
|
8849
9596
|
yellow: "\x1B[33m",
|
|
8850
9597
|
green: "\x1B[32m",
|
|
8851
9598
|
cyan: "\x1B[36m",
|
|
@@ -8854,7 +9601,7 @@ var colors3 = {
|
|
|
8854
9601
|
bold: "\x1B[1m"
|
|
8855
9602
|
};
|
|
8856
9603
|
function createSelfUpdateCommand() {
|
|
8857
|
-
return new
|
|
9604
|
+
return new Command46("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) => {
|
|
8858
9605
|
await handleSelfUpdate(options);
|
|
8859
9606
|
});
|
|
8860
9607
|
}
|
|
@@ -8865,7 +9612,7 @@ async function handleSelfUpdate(options) {
|
|
|
8865
9612
|
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
8866
9613
|
}
|
|
8867
9614
|
try {
|
|
8868
|
-
console.log(`${
|
|
9615
|
+
console.log(`${colors4.cyan}\u{1F50D} Checking for updates...${colors4.reset}`);
|
|
8869
9616
|
const response = await fetch(`${config.apiUrl}/api/versions/client`, {
|
|
8870
9617
|
headers: {
|
|
8871
9618
|
"JAI1-Access-Key": config.accessKey
|
|
@@ -8880,47 +9627,47 @@ async function handleSelfUpdate(options) {
|
|
|
8880
9627
|
const latestVersion = data.version;
|
|
8881
9628
|
const currentVersion = package_default.version;
|
|
8882
9629
|
console.log(`
|
|
8883
|
-
${
|
|
8884
|
-
console.log(`${
|
|
9630
|
+
${colors4.bold}Current version:${colors4.reset} ${currentVersion}`);
|
|
9631
|
+
console.log(`${colors4.bold}Latest version:${colors4.reset} ${latestVersion}
|
|
8885
9632
|
`);
|
|
8886
9633
|
if (!isNewerVersion3(latestVersion, currentVersion)) {
|
|
8887
|
-
console.log(`${
|
|
9634
|
+
console.log(`${colors4.green}\u2705 You're already on the latest version!${colors4.reset}
|
|
8888
9635
|
`);
|
|
8889
9636
|
return;
|
|
8890
9637
|
}
|
|
8891
|
-
console.log(`${
|
|
8892
|
-
console.log(`${
|
|
8893
|
-
console.log(`${
|
|
9638
|
+
console.log(`${colors4.yellow}\u256D\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\u2500\u2500\u2500\u2500\u2500\u256E${colors4.reset}`);
|
|
9639
|
+
console.log(`${colors4.yellow}\u2502${colors4.reset} ${colors4.bold}\u2B06\uFE0F Update available!${colors4.reset} ${currentVersion} \u2192 ${colors4.cyan}${latestVersion}${colors4.reset} ${colors4.yellow}\u2502${colors4.reset}`);
|
|
9640
|
+
console.log(`${colors4.yellow}\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\u2500\u2500\u2500\u2500\u2500\u256F${colors4.reset}
|
|
8894
9641
|
`);
|
|
8895
9642
|
if (options.check) {
|
|
8896
|
-
console.log(`${
|
|
9643
|
+
console.log(`${colors4.cyan}Run "jai1 self-update" to install the latest version.${colors4.reset}
|
|
8897
9644
|
`);
|
|
8898
9645
|
return;
|
|
8899
9646
|
}
|
|
8900
9647
|
if (!options.force) {
|
|
8901
|
-
const shouldUpdate = await
|
|
9648
|
+
const shouldUpdate = await confirm8({
|
|
8902
9649
|
message: "Update to the latest version now?",
|
|
8903
9650
|
default: true
|
|
8904
9651
|
});
|
|
8905
9652
|
if (!shouldUpdate) {
|
|
8906
|
-
console.log(`${
|
|
9653
|
+
console.log(`${colors4.yellow}\u23F8\uFE0F Update cancelled.${colors4.reset}
|
|
8907
9654
|
`);
|
|
8908
9655
|
return;
|
|
8909
9656
|
}
|
|
8910
9657
|
}
|
|
8911
9658
|
console.log(`
|
|
8912
|
-
${
|
|
9659
|
+
${colors4.cyan}\u{1F4E5} Installing latest version...${colors4.reset}
|
|
8913
9660
|
`);
|
|
8914
9661
|
try {
|
|
8915
9662
|
const packageManager2 = detectPackageManager2();
|
|
8916
9663
|
const installCommand = getInstallCommand2(packageManager2);
|
|
8917
|
-
console.log(`${
|
|
8918
|
-
|
|
9664
|
+
console.log(`${colors4.cyan}Using ${packageManager2}...${colors4.reset}`);
|
|
9665
|
+
execSync3(installCommand, {
|
|
8919
9666
|
stdio: "inherit",
|
|
8920
9667
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
8921
9668
|
});
|
|
8922
9669
|
console.log(`
|
|
8923
|
-
${
|
|
9670
|
+
${colors4.green}\u2705 Successfully updated to version ${latestVersion}!${colors4.reset}
|
|
8924
9671
|
`);
|
|
8925
9672
|
trackAction("self_update", {
|
|
8926
9673
|
from_version: currentVersion,
|
|
@@ -8930,11 +9677,11 @@ ${colors3.green}\u2705 Successfully updated to version ${latestVersion}!${colors
|
|
|
8930
9677
|
disableUpdateCheck();
|
|
8931
9678
|
} catch (error) {
|
|
8932
9679
|
console.error(`
|
|
8933
|
-
${
|
|
8934
|
-
console.error(`${
|
|
9680
|
+
${colors4.red}\u274C Update failed!${colors4.reset}`);
|
|
9681
|
+
console.error(`${colors4.red}Error: ${error instanceof Error ? error.message : "Unknown error"}${colors4.reset}
|
|
8935
9682
|
`);
|
|
8936
|
-
console.error(`${
|
|
8937
|
-
console.error(` ${
|
|
9683
|
+
console.error(`${colors4.yellow}\u{1F4A1} You can try manually updating with:${colors4.reset}`);
|
|
9684
|
+
console.error(` ${colors4.cyan}npm install -g @jvittechs/jai1-cli@latest${colors4.reset}
|
|
8938
9685
|
`);
|
|
8939
9686
|
throw error;
|
|
8940
9687
|
}
|
|
@@ -8962,17 +9709,17 @@ function detectPackageManager2() {
|
|
|
8962
9709
|
if (userAgent.includes("yarn")) return "yarn";
|
|
8963
9710
|
if (userAgent.includes("bun")) return "bun";
|
|
8964
9711
|
try {
|
|
8965
|
-
|
|
9712
|
+
execSync3("pnpm --version", { stdio: "ignore" });
|
|
8966
9713
|
return "pnpm";
|
|
8967
9714
|
} catch {
|
|
8968
9715
|
}
|
|
8969
9716
|
try {
|
|
8970
|
-
|
|
9717
|
+
execSync3("yarn --version", { stdio: "ignore" });
|
|
8971
9718
|
return "yarn";
|
|
8972
9719
|
} catch {
|
|
8973
9720
|
}
|
|
8974
9721
|
try {
|
|
8975
|
-
|
|
9722
|
+
execSync3("bun --version", { stdio: "ignore" });
|
|
8976
9723
|
return "bun";
|
|
8977
9724
|
} catch {
|
|
8978
9725
|
}
|
|
@@ -8994,10 +9741,10 @@ function getInstallCommand2(packageManager2) {
|
|
|
8994
9741
|
}
|
|
8995
9742
|
|
|
8996
9743
|
// src/commands/clear-backups.ts
|
|
8997
|
-
import { Command as
|
|
8998
|
-
import { confirm as
|
|
9744
|
+
import { Command as Command47 } from "commander";
|
|
9745
|
+
import { confirm as confirm9 } from "@inquirer/prompts";
|
|
8999
9746
|
function createClearBackupsCommand() {
|
|
9000
|
-
return new
|
|
9747
|
+
return new Command47("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
9001
9748
|
const service = new ComponentsService();
|
|
9002
9749
|
const backups = await service.listBackups(process.cwd());
|
|
9003
9750
|
if (backups.length === 0) {
|
|
@@ -9013,7 +9760,7 @@ function createClearBackupsCommand() {
|
|
|
9013
9760
|
}
|
|
9014
9761
|
console.log();
|
|
9015
9762
|
if (!options.yes) {
|
|
9016
|
-
const ok = await
|
|
9763
|
+
const ok = await confirm9({ message: "Delete all backups?", default: false });
|
|
9017
9764
|
if (!ok) return;
|
|
9018
9765
|
}
|
|
9019
9766
|
await service.clearBackups(process.cwd());
|
|
@@ -9022,10 +9769,10 @@ function createClearBackupsCommand() {
|
|
|
9022
9769
|
}
|
|
9023
9770
|
|
|
9024
9771
|
// src/commands/vscode/index.ts
|
|
9025
|
-
import { Command as
|
|
9026
|
-
import { checkbox as
|
|
9027
|
-
import
|
|
9028
|
-
import
|
|
9772
|
+
import { Command as Command48 } from "commander";
|
|
9773
|
+
import { checkbox as checkbox5, confirm as confirm10, select as select5 } from "@inquirer/prompts";
|
|
9774
|
+
import fs16 from "fs/promises";
|
|
9775
|
+
import path7 from "path";
|
|
9029
9776
|
import { existsSync as existsSync3 } from "fs";
|
|
9030
9777
|
var PERFORMANCE_GROUPS2 = {
|
|
9031
9778
|
telemetry: {
|
|
@@ -9162,7 +9909,7 @@ var PERFORMANCE_GROUPS2 = {
|
|
|
9162
9909
|
}
|
|
9163
9910
|
};
|
|
9164
9911
|
function createVSCodeCommand() {
|
|
9165
|
-
const vscodeCommand = new
|
|
9912
|
+
const vscodeCommand = new Command48("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
|
|
9166
9913
|
vscodeCommand.action(async () => {
|
|
9167
9914
|
await interactiveMode2();
|
|
9168
9915
|
});
|
|
@@ -9206,7 +9953,7 @@ async function interactiveMode2() {
|
|
|
9206
9953
|
console.log("\u2502 \u2022 Nh\u1EA5n ENTER \u0111\u1EC3 x\xE1c nh\u1EADn v\xE0 \xE1p d\u1EE5ng \u2502");
|
|
9207
9954
|
console.log("\u2502 \u2022 Nh\u1EA5n Ctrl+C \u0111\u1EC3 h\u1EE7y \u2502");
|
|
9208
9955
|
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");
|
|
9209
|
-
const action = await
|
|
9956
|
+
const action = await select5({
|
|
9210
9957
|
message: "B\u1EA1n mu\u1ED1n l\xE0m g\xEC?",
|
|
9211
9958
|
choices: [
|
|
9212
9959
|
{ name: "\u2705 Enable c\xE1c nh\xF3m t\u1ED1i \u01B0u", value: "enable" },
|
|
@@ -9230,7 +9977,7 @@ async function selectGroupsToApply2(action) {
|
|
|
9230
9977
|
value: key
|
|
9231
9978
|
}));
|
|
9232
9979
|
try {
|
|
9233
|
-
const selectedGroups = await
|
|
9980
|
+
const selectedGroups = await checkbox5({
|
|
9234
9981
|
message: `Ch\u1ECDn c\xE1c nh\xF3m \u0111\u1EC3 ${action === "enable" ? "enable" : "disable"} (SPACE \u0111\u1EC3 ch\u1ECDn, ENTER \u0111\u1EC3 x\xE1c nh\u1EADn):`,
|
|
9235
9982
|
choices
|
|
9236
9983
|
});
|
|
@@ -9245,8 +9992,8 @@ async function selectGroupsToApply2(action) {
|
|
|
9245
9992
|
}
|
|
9246
9993
|
}
|
|
9247
9994
|
async function applyGroups2(groupKeys, action) {
|
|
9248
|
-
const vscodeDir =
|
|
9249
|
-
const settingsPath =
|
|
9995
|
+
const vscodeDir = path7.join(process.cwd(), ".vscode");
|
|
9996
|
+
const settingsPath = path7.join(vscodeDir, "settings.json");
|
|
9250
9997
|
const invalidGroups = groupKeys.filter((key) => !PERFORMANCE_GROUPS2[key]);
|
|
9251
9998
|
if (invalidGroups.length > 0) {
|
|
9252
9999
|
console.log(`
|
|
@@ -9255,18 +10002,18 @@ async function applyGroups2(groupKeys, action) {
|
|
|
9255
10002
|
return;
|
|
9256
10003
|
}
|
|
9257
10004
|
if (!existsSync3(vscodeDir)) {
|
|
9258
|
-
await
|
|
10005
|
+
await fs16.mkdir(vscodeDir, { recursive: true });
|
|
9259
10006
|
console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
|
|
9260
10007
|
}
|
|
9261
10008
|
let currentSettings = {};
|
|
9262
10009
|
if (existsSync3(settingsPath)) {
|
|
9263
10010
|
try {
|
|
9264
|
-
const content = await
|
|
10011
|
+
const content = await fs16.readFile(settingsPath, "utf-8");
|
|
9265
10012
|
currentSettings = JSON.parse(content);
|
|
9266
10013
|
console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
|
|
9267
10014
|
} catch {
|
|
9268
10015
|
console.warn("\u26A0\uFE0F Kh\xF4ng th\u1EC3 \u0111\u1ECDc settings.json (c\xF3 th\u1EC3 ch\u1EE9a comments).");
|
|
9269
|
-
const confirmOverwrite = await
|
|
10016
|
+
const confirmOverwrite = await confirm10({
|
|
9270
10017
|
message: "Ghi \u0111\xE8 file settings.json hi\u1EC7n t\u1EA1i?",
|
|
9271
10018
|
default: false
|
|
9272
10019
|
});
|
|
@@ -9301,19 +10048,19 @@ async function applyGroups2(groupKeys, action) {
|
|
|
9301
10048
|
}
|
|
9302
10049
|
}
|
|
9303
10050
|
}
|
|
9304
|
-
await
|
|
10051
|
+
await fs16.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
|
9305
10052
|
console.log(`
|
|
9306
10053
|
\u2705 \u0110\xE3 c\u1EADp nh\u1EADt c\xE0i \u0111\u1EB7t VSCode t\u1EA1i: ${settingsPath}`);
|
|
9307
10054
|
console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
|
|
9308
10055
|
}
|
|
9309
10056
|
async function resetSettings2(groupKeys) {
|
|
9310
|
-
const vscodeDir =
|
|
9311
|
-
const settingsPath =
|
|
10057
|
+
const vscodeDir = path7.join(process.cwd(), ".vscode");
|
|
10058
|
+
const settingsPath = path7.join(vscodeDir, "settings.json");
|
|
9312
10059
|
if (!existsSync3(settingsPath)) {
|
|
9313
10060
|
console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
|
|
9314
10061
|
return;
|
|
9315
10062
|
}
|
|
9316
|
-
const confirmReset = await
|
|
10063
|
+
const confirmReset = await confirm10({
|
|
9317
10064
|
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(", ")}?`,
|
|
9318
10065
|
default: false
|
|
9319
10066
|
});
|
|
@@ -9322,7 +10069,7 @@ async function resetSettings2(groupKeys) {
|
|
|
9322
10069
|
return;
|
|
9323
10070
|
}
|
|
9324
10071
|
if (groupKeys.length === 0) {
|
|
9325
|
-
await
|
|
10072
|
+
await fs16.unlink(settingsPath);
|
|
9326
10073
|
console.log("\n\u2705 \u0110\xE3 x\xF3a file settings.json");
|
|
9327
10074
|
} else {
|
|
9328
10075
|
await applyGroups2(groupKeys, "disable");
|
|
@@ -9333,9 +10080,9 @@ async function resetSettings2(groupKeys) {
|
|
|
9333
10080
|
// src/commands/guide.ts
|
|
9334
10081
|
import React40 from "react";
|
|
9335
10082
|
import { render as render6 } from "ink";
|
|
9336
|
-
import { Command as
|
|
10083
|
+
import { Command as Command49 } from "commander";
|
|
9337
10084
|
function createGuideCommand() {
|
|
9338
|
-
const cmd = new
|
|
10085
|
+
const cmd = new Command49("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
|
|
9339
10086
|
const { waitUntilExit } = render6(
|
|
9340
10087
|
React40.createElement(GuideApp, {
|
|
9341
10088
|
initialTopic: options.topic,
|
|
@@ -9352,9 +10099,9 @@ function createGuideCommand() {
|
|
|
9352
10099
|
// src/commands/context.ts
|
|
9353
10100
|
import React41 from "react";
|
|
9354
10101
|
import { render as render7 } from "ink";
|
|
9355
|
-
import { Command as
|
|
10102
|
+
import { Command as Command50 } from "commander";
|
|
9356
10103
|
function createContextCommand() {
|
|
9357
|
-
const cmd = new
|
|
10104
|
+
const cmd = new Command50("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) => {
|
|
9358
10105
|
let initialIDE;
|
|
9359
10106
|
if (options.ide) {
|
|
9360
10107
|
const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
|
|
@@ -9431,10 +10178,10 @@ async function printStats2() {
|
|
|
9431
10178
|
}
|
|
9432
10179
|
|
|
9433
10180
|
// src/commands/migrate-ide.ts
|
|
9434
|
-
import { Command as
|
|
9435
|
-
import { checkbox as
|
|
10181
|
+
import { Command as Command51 } from "commander";
|
|
10182
|
+
import { checkbox as checkbox6, confirm as confirm11 } from "@inquirer/prompts";
|
|
9436
10183
|
function createMigrateIdeCommand() {
|
|
9437
|
-
const cmd = new
|
|
10184
|
+
const cmd = new Command51("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) => {
|
|
9438
10185
|
await runMigrateIde(options);
|
|
9439
10186
|
});
|
|
9440
10187
|
return cmd;
|
|
@@ -9462,7 +10209,7 @@ async function runMigrateIde(options) {
|
|
|
9462
10209
|
value: ide
|
|
9463
10210
|
};
|
|
9464
10211
|
});
|
|
9465
|
-
selectedIdes = await
|
|
10212
|
+
selectedIdes = await checkbox6({
|
|
9466
10213
|
message: "Ch\u1ECDn IDE(s) \u0111\u1EC3 migrate (SPACE \u0111\u1EC3 ch\u1ECDn, ENTER \u0111\u1EC3 x\xE1c nh\u1EADn):",
|
|
9467
10214
|
choices: ideChoices
|
|
9468
10215
|
});
|
|
@@ -9481,7 +10228,7 @@ async function runMigrateIde(options) {
|
|
|
9481
10228
|
{ name: `Workflows (${content.workflows.length} files)`, value: "workflows" },
|
|
9482
10229
|
{ name: `Commands (${content.commands.length} files)`, value: "commands" }
|
|
9483
10230
|
];
|
|
9484
|
-
selectedTypes = await
|
|
10231
|
+
selectedTypes = await checkbox6({
|
|
9485
10232
|
message: "Ch\u1ECDn content types \u0111\u1EC3 migrate:",
|
|
9486
10233
|
choices: typeChoices
|
|
9487
10234
|
});
|
|
@@ -9503,7 +10250,7 @@ async function runMigrateIde(options) {
|
|
|
9503
10250
|
if (options.dryRun) {
|
|
9504
10251
|
console.log("\u{1F50D} DRY RUN - No files will be written\n");
|
|
9505
10252
|
}
|
|
9506
|
-
const confirmed = await
|
|
10253
|
+
const confirmed = await confirm11({
|
|
9507
10254
|
message: "Proceed with migration?",
|
|
9508
10255
|
default: true
|
|
9509
10256
|
});
|
|
@@ -9540,7 +10287,7 @@ async function runMigrateIde(options) {
|
|
|
9540
10287
|
}
|
|
9541
10288
|
|
|
9542
10289
|
// src/cli.ts
|
|
9543
|
-
var program = new
|
|
10290
|
+
var program = new Command52();
|
|
9544
10291
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
9545
10292
|
console.log(package_default.version);
|
|
9546
10293
|
if (!process.argv.includes("--skip-update-check")) {
|
|
@@ -9562,12 +10309,14 @@ program.addCommand(createOpenAiKeysCommand());
|
|
|
9562
10309
|
program.addCommand(createStatsCommand());
|
|
9563
10310
|
program.addCommand(createTranslateCommand());
|
|
9564
10311
|
program.addCommand(createUtilsCommand());
|
|
10312
|
+
program.addCommand(createDepsCommand());
|
|
9565
10313
|
program.addCommand(createKitCommand());
|
|
10314
|
+
program.addCommand(createRulesCommand());
|
|
9566
10315
|
program.addCommand(createUpgradeCommand());
|
|
9567
10316
|
program.addCommand(createCleanCommand());
|
|
9568
|
-
var redmineCommand = new
|
|
10317
|
+
var redmineCommand = new Command52("redmine").description("Redmine context sync commands");
|
|
9569
10318
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
9570
|
-
var syncCommand = new
|
|
10319
|
+
var syncCommand = new Command52("sync").description("Sync Redmine issues to markdown files");
|
|
9571
10320
|
syncCommand.addCommand(createSyncIssueCommand());
|
|
9572
10321
|
syncCommand.addCommand(createSyncProjectCommand());
|
|
9573
10322
|
redmineCommand.addCommand(syncCommand);
|
|
@@ -9607,8 +10356,15 @@ program.on("command:*", (operands) => {
|
|
|
9607
10356
|
console.error(" translate Translate text, files, or folders using AI");
|
|
9608
10357
|
console.error("");
|
|
9609
10358
|
console.error(" \u{1F6E0}\uFE0F Developer Utilities");
|
|
10359
|
+
console.error(" deps Manage project dependencies");
|
|
9610
10360
|
console.error(" utils Developer tools (password, uuid, hash, jwt, etc.)");
|
|
9611
10361
|
console.error("");
|
|
10362
|
+
console.error(" \u{1F4CB} Rule Presets");
|
|
10363
|
+
console.error(" rules list List available rule presets");
|
|
10364
|
+
console.error(" rules init Apply preset to project");
|
|
10365
|
+
console.error(" rules sync Regenerate outputs after editing");
|
|
10366
|
+
console.error(" rules info Show current preset information");
|
|
10367
|
+
console.error("");
|
|
9612
10368
|
console.error(" \u{1F527} Maintenance");
|
|
9613
10369
|
console.error(" upgrade Upgrade jai1-client to latest version");
|
|
9614
10370
|
console.error(" clean Clean up backups and cache");
|