@jvittechs/jai1-cli 0.1.99 → 0.1.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +585 -365
- 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 Command61 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/errors/index.ts
|
|
7
7
|
var Jai1Error = class extends Error {
|
|
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
|
|
|
33
33
|
// package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@jvittechs/jai1-cli",
|
|
36
|
-
version: "0.1.
|
|
36
|
+
version: "0.1.100",
|
|
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: {
|
|
@@ -1322,9 +1322,9 @@ var UnifiedApplyApp = ({
|
|
|
1322
1322
|
(c) => c.filepath.toLowerCase().includes(query) || c.tags?.some((t) => t.toLowerCase().includes(query))
|
|
1323
1323
|
);
|
|
1324
1324
|
}, [components, searchQuery]);
|
|
1325
|
-
useInput((
|
|
1325
|
+
useInput((input5, key) => {
|
|
1326
1326
|
if (viewState === "done") {
|
|
1327
|
-
if (key.return ||
|
|
1327
|
+
if (key.return || input5 === "q" || key.escape) {
|
|
1328
1328
|
onExit();
|
|
1329
1329
|
}
|
|
1330
1330
|
return;
|
|
@@ -1332,7 +1332,7 @@ var UnifiedApplyApp = ({
|
|
|
1332
1332
|
if (viewState === "summary") {
|
|
1333
1333
|
if (key.return) {
|
|
1334
1334
|
setViewState("ide-sync");
|
|
1335
|
-
} else if (
|
|
1335
|
+
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1336
1336
|
onExit();
|
|
1337
1337
|
}
|
|
1338
1338
|
return;
|
|
@@ -1342,7 +1342,7 @@ var UnifiedApplyApp = ({
|
|
|
1342
1342
|
setIdeCursorIndex((prev) => Math.max(0, prev - 1));
|
|
1343
1343
|
} else if (key.downArrow) {
|
|
1344
1344
|
setIdeCursorIndex((prev) => Math.min(availableIdes.length - 1, prev + 1));
|
|
1345
|
-
} else if (
|
|
1345
|
+
} else if (input5 === " ") {
|
|
1346
1346
|
const ide = availableIdes[ideCursorIndex];
|
|
1347
1347
|
if (ide) {
|
|
1348
1348
|
setSelectedIdes((prev) => {
|
|
@@ -1355,15 +1355,15 @@ var UnifiedApplyApp = ({
|
|
|
1355
1355
|
return next;
|
|
1356
1356
|
});
|
|
1357
1357
|
}
|
|
1358
|
-
} else if (
|
|
1358
|
+
} else if (input5 === "a") {
|
|
1359
1359
|
setSelectedIdes(new Set(availableIdes));
|
|
1360
|
-
} else if (
|
|
1360
|
+
} else if (input5 === "c") {
|
|
1361
1361
|
setSelectedIdes(/* @__PURE__ */ new Set());
|
|
1362
1362
|
} else if (key.return) {
|
|
1363
1363
|
if (selectedIdes.size > 0) {
|
|
1364
1364
|
handleIdeSync();
|
|
1365
1365
|
}
|
|
1366
|
-
} else if (
|
|
1366
|
+
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1367
1367
|
onExit();
|
|
1368
1368
|
}
|
|
1369
1369
|
return;
|
|
@@ -1380,7 +1380,7 @@ var UnifiedApplyApp = ({
|
|
|
1380
1380
|
else setFocusArea("packages");
|
|
1381
1381
|
return;
|
|
1382
1382
|
}
|
|
1383
|
-
if (key.escape ||
|
|
1383
|
+
if (key.escape || input5 === "q") {
|
|
1384
1384
|
onExit();
|
|
1385
1385
|
return;
|
|
1386
1386
|
}
|
|
@@ -1391,14 +1391,14 @@ var UnifiedApplyApp = ({
|
|
|
1391
1391
|
return;
|
|
1392
1392
|
}
|
|
1393
1393
|
if (focusArea !== "search") {
|
|
1394
|
-
if (
|
|
1394
|
+
if (input5 === "a") {
|
|
1395
1395
|
setSelectedPaths((prev) => {
|
|
1396
1396
|
const next = new Set(prev);
|
|
1397
1397
|
filteredComponents.forEach((c) => next.add(c.filepath));
|
|
1398
1398
|
return next;
|
|
1399
1399
|
});
|
|
1400
1400
|
return;
|
|
1401
|
-
} else if (
|
|
1401
|
+
} else if (input5 === "c") {
|
|
1402
1402
|
setSelectedPaths(/* @__PURE__ */ new Set());
|
|
1403
1403
|
return;
|
|
1404
1404
|
}
|
|
@@ -1408,7 +1408,7 @@ var UnifiedApplyApp = ({
|
|
|
1408
1408
|
setCursorIndex((prev) => Math.max(0, prev - 1));
|
|
1409
1409
|
} else if (key.downArrow) {
|
|
1410
1410
|
setCursorIndex((prev) => Math.min(filteredComponents.length - 1, prev + 1));
|
|
1411
|
-
} else if (
|
|
1411
|
+
} else if (input5 === " ") {
|
|
1412
1412
|
const current = filteredComponents[cursorIndex];
|
|
1413
1413
|
if (current) {
|
|
1414
1414
|
setSelectedPaths((prev) => {
|
|
@@ -1428,7 +1428,7 @@ var UnifiedApplyApp = ({
|
|
|
1428
1428
|
setSelectedPackageIndex((prev) => Math.max(0, prev - 1));
|
|
1429
1429
|
} else if (key.rightArrow) {
|
|
1430
1430
|
setSelectedPackageIndex((prev) => Math.min(tags.length - 1, prev + 1));
|
|
1431
|
-
} else if (
|
|
1431
|
+
} else if (input5 === " " || key.return) {
|
|
1432
1432
|
const tag = tags[selectedPackageIndex];
|
|
1433
1433
|
if (tag) {
|
|
1434
1434
|
const packageComponents = components.filter((c) => c.tags?.includes(tag.tag));
|
|
@@ -1860,7 +1860,7 @@ var MainMenuView = ({ ideContexts, onSelect }) => {
|
|
|
1860
1860
|
available: ideContexts.some((ctx) => ctx.ide === "jai1")
|
|
1861
1861
|
}
|
|
1862
1862
|
];
|
|
1863
|
-
useInput2((
|
|
1863
|
+
useInput2((input5, key) => {
|
|
1864
1864
|
if (key.upArrow) {
|
|
1865
1865
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
1866
1866
|
} else if (key.downArrow) {
|
|
@@ -1962,13 +1962,13 @@ var IDEOverviewView = ({
|
|
|
1962
1962
|
count: ideContext.stats.byType.context
|
|
1963
1963
|
});
|
|
1964
1964
|
}
|
|
1965
|
-
useInput3((
|
|
1965
|
+
useInput3((input5, key) => {
|
|
1966
1966
|
if (key.tab || key.rightArrow) {
|
|
1967
1967
|
setSelectedTabIndex((prev) => Math.min(tabs.length - 1, prev + 1));
|
|
1968
1968
|
} else if (key.leftArrow) {
|
|
1969
1969
|
setSelectedTabIndex((prev) => Math.max(0, prev - 1));
|
|
1970
1970
|
}
|
|
1971
|
-
const num = parseInt(
|
|
1971
|
+
const num = parseInt(input5, 10);
|
|
1972
1972
|
if (!isNaN(num) && num >= 1 && num <= tabs.length) {
|
|
1973
1973
|
setSelectedTabIndex(num - 1);
|
|
1974
1974
|
}
|
|
@@ -2030,7 +2030,7 @@ import React7, { useState as useState4 } from "react";
|
|
|
2030
2030
|
import { Box as Box5, Text as Text6, useInput as useInput4 } from "ink";
|
|
2031
2031
|
var ListView = ({ items, contentType, onSelect, onBack }) => {
|
|
2032
2032
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
2033
|
-
useInput4((
|
|
2033
|
+
useInput4((input5, key) => {
|
|
2034
2034
|
if (key.upArrow) {
|
|
2035
2035
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
2036
2036
|
} else if (key.downArrow) {
|
|
@@ -2081,18 +2081,18 @@ var DetailView = ({ item, scrollPosition: initialScroll, onBack }) => {
|
|
|
2081
2081
|
const [scrollPosition, setScrollPosition] = useState5(initialScroll);
|
|
2082
2082
|
const maxVisibleLines = 25;
|
|
2083
2083
|
const maxScroll = Math.max(0, item.previewLines.length - maxVisibleLines);
|
|
2084
|
-
useInput5((
|
|
2085
|
-
if (key.upArrow ||
|
|
2084
|
+
useInput5((input5, key) => {
|
|
2085
|
+
if (key.upArrow || input5 === "k") {
|
|
2086
2086
|
setScrollPosition((prev) => Math.max(0, prev - 1));
|
|
2087
|
-
} else if (key.downArrow ||
|
|
2087
|
+
} else if (key.downArrow || input5 === "j") {
|
|
2088
2088
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 1));
|
|
2089
|
-
} else if (key.pageDown ||
|
|
2089
|
+
} else if (key.pageDown || input5 === "d") {
|
|
2090
2090
|
setScrollPosition((prev) => Math.min(maxScroll, prev + 5));
|
|
2091
|
-
} else if (key.pageUp ||
|
|
2091
|
+
} else if (key.pageUp || input5 === "u") {
|
|
2092
2092
|
setScrollPosition((prev) => Math.max(0, prev - 5));
|
|
2093
|
-
} else if (
|
|
2093
|
+
} else if (input5 === "g") {
|
|
2094
2094
|
setScrollPosition(0);
|
|
2095
|
-
} else if (
|
|
2095
|
+
} else if (input5 === "G") {
|
|
2096
2096
|
setScrollPosition(maxScroll);
|
|
2097
2097
|
} else if (key.escape || key.backspace) {
|
|
2098
2098
|
onBack();
|
|
@@ -2496,8 +2496,8 @@ var ContextApp = ({ initialIDE, initialType, onExit }) => {
|
|
|
2496
2496
|
setLoading(false);
|
|
2497
2497
|
});
|
|
2498
2498
|
}, [initialIDE]);
|
|
2499
|
-
useInput6((
|
|
2500
|
-
if (
|
|
2499
|
+
useInput6((input5, key) => {
|
|
2500
|
+
if (input5 === "q") {
|
|
2501
2501
|
onExit();
|
|
2502
2502
|
return;
|
|
2503
2503
|
}
|
|
@@ -3616,7 +3616,7 @@ var MENU_ITEMS = [
|
|
|
3616
3616
|
];
|
|
3617
3617
|
var MenuView = ({ onSelect }) => {
|
|
3618
3618
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
3619
|
-
useInput7((
|
|
3619
|
+
useInput7((input5, key) => {
|
|
3620
3620
|
if (key.upArrow) {
|
|
3621
3621
|
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
3622
3622
|
} else if (key.downArrow) {
|
|
@@ -4229,7 +4229,7 @@ var AgenticGuideView = ({ onBack }) => {
|
|
|
4229
4229
|
const [isTyping, setIsTyping] = useState8(false);
|
|
4230
4230
|
const [selectedSuggestion, setSelectedSuggestion] = useState8(0);
|
|
4231
4231
|
const [focusArea, setFocusArea] = useState8("input");
|
|
4232
|
-
useInput8((
|
|
4232
|
+
useInput8((input5, key) => {
|
|
4233
4233
|
if (key.escape) {
|
|
4234
4234
|
onBack();
|
|
4235
4235
|
return;
|
|
@@ -4361,7 +4361,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
4361
4361
|
setCurrentTopic(TOPIC_MAP[initialTopic]);
|
|
4362
4362
|
}
|
|
4363
4363
|
}, [initialTopic]);
|
|
4364
|
-
useInput9((
|
|
4364
|
+
useInput9((input5, key) => {
|
|
4365
4365
|
if (key.escape || currentTopic !== "menu" && key.backspace) {
|
|
4366
4366
|
if (currentTopic === "menu") {
|
|
4367
4367
|
onExit();
|
|
@@ -4371,7 +4371,7 @@ var GuideApp = ({ initialTopic, onExit }) => {
|
|
|
4371
4371
|
}
|
|
4372
4372
|
return;
|
|
4373
4373
|
}
|
|
4374
|
-
if (
|
|
4374
|
+
if (input5 === "q") {
|
|
4375
4375
|
onExit();
|
|
4376
4376
|
return;
|
|
4377
4377
|
}
|
|
@@ -4890,7 +4890,7 @@ var ModelSelector = ({
|
|
|
4890
4890
|
const allowedModels = models.filter((m) => m.allowed);
|
|
4891
4891
|
const currentIndex = allowedModels.findIndex((m) => m.id === currentModel);
|
|
4892
4892
|
const [selectedIndex, setSelectedIndex] = useState12(Math.max(0, currentIndex));
|
|
4893
|
-
useInput10((
|
|
4893
|
+
useInput10((input5, key) => {
|
|
4894
4894
|
if (key.escape) {
|
|
4895
4895
|
onCancel();
|
|
4896
4896
|
return;
|
|
@@ -5016,7 +5016,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
5016
5016
|
}
|
|
5017
5017
|
return false;
|
|
5018
5018
|
}, [refetch, exit]);
|
|
5019
|
-
useInput11((
|
|
5019
|
+
useInput11((input5, key) => {
|
|
5020
5020
|
if (showSlashMenu) {
|
|
5021
5021
|
if (key.upArrow) {
|
|
5022
5022
|
setSlashMenuIndex((i) => Math.max(0, i - 1));
|
|
@@ -5044,7 +5044,7 @@ var ChatApp = ({ service, initialModel }) => {
|
|
|
5044
5044
|
}
|
|
5045
5045
|
return;
|
|
5046
5046
|
}
|
|
5047
|
-
if (currentView === "error" && (key.return ||
|
|
5047
|
+
if (currentView === "error" && (key.return || input5 === "r")) {
|
|
5048
5048
|
setCurrentView("loading");
|
|
5049
5049
|
refetch();
|
|
5050
5050
|
return;
|
|
@@ -5810,9 +5810,9 @@ var TranslationService = class {
|
|
|
5810
5810
|
/**
|
|
5811
5811
|
* Detect input type
|
|
5812
5812
|
*/
|
|
5813
|
-
async detectInputType(
|
|
5813
|
+
async detectInputType(input5) {
|
|
5814
5814
|
try {
|
|
5815
|
-
const stat = await fs9.stat(
|
|
5815
|
+
const stat = await fs9.stat(input5);
|
|
5816
5816
|
if (stat.isDirectory()) return "folder";
|
|
5817
5817
|
if (stat.isFile()) return "file";
|
|
5818
5818
|
} catch {
|
|
@@ -6044,7 +6044,7 @@ Return ONLY the translated content, no explanations.`;
|
|
|
6044
6044
|
};
|
|
6045
6045
|
|
|
6046
6046
|
// src/commands/translate.ts
|
|
6047
|
-
async function handleTranslate(
|
|
6047
|
+
async function handleTranslate(input5, options) {
|
|
6048
6048
|
const configService = new ConfigService();
|
|
6049
6049
|
const config = await configService.load();
|
|
6050
6050
|
if (!config) {
|
|
@@ -6052,16 +6052,16 @@ async function handleTranslate(input4, options) {
|
|
|
6052
6052
|
}
|
|
6053
6053
|
const llmService = new LlmProxyService(config);
|
|
6054
6054
|
const translationService = new TranslationService(llmService, options, options.model);
|
|
6055
|
-
const inputType = await translationService.detectInputType(
|
|
6055
|
+
const inputType = await translationService.detectInputType(input5);
|
|
6056
6056
|
switch (inputType) {
|
|
6057
6057
|
case "text":
|
|
6058
|
-
await handleTextTranslation(translationService,
|
|
6058
|
+
await handleTextTranslation(translationService, input5, options);
|
|
6059
6059
|
break;
|
|
6060
6060
|
case "file":
|
|
6061
|
-
await handleFileTranslation(translationService,
|
|
6061
|
+
await handleFileTranslation(translationService, input5, options);
|
|
6062
6062
|
break;
|
|
6063
6063
|
case "folder":
|
|
6064
|
-
await handleFolderTranslation(translationService,
|
|
6064
|
+
await handleFolderTranslation(translationService, input5, options);
|
|
6065
6065
|
break;
|
|
6066
6066
|
}
|
|
6067
6067
|
}
|
|
@@ -6138,8 +6138,8 @@ async function handleFolderTranslation(service, folderPath, options) {
|
|
|
6138
6138
|
}
|
|
6139
6139
|
}
|
|
6140
6140
|
function createTranslateCommand() {
|
|
6141
|
-
const cmd = new Command15("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (
|
|
6142
|
-
await handleTranslate(
|
|
6141
|
+
const cmd = new Command15("translate").description("D\u1ECBch v\u0103n b\u1EA3n, file ho\u1EB7c th\u01B0 m\u1EE5c b\u1EB1ng AI").argument("<input>", "Chu\u1ED7i v\u0103n b\u1EA3n, \u0111\u01B0\u1EDDng d\u1EABn file ho\u1EB7c th\u01B0 m\u1EE5c").option("--to <language>", "M\xE3 ng\xF4n ng\u1EEF \u0111\xEDch (m\u1EB7c \u0111\u1ECBnh: vi)", "vi").option("-o, --output <path>", "\u0110\u01B0\u1EDDng d\u1EABn output (file/th\u01B0 m\u1EE5c)").option("--dry-run", "Xem tr\u01B0\u1EDBc kh\xF4ng l\u01B0u file").option("--concurrency <number>", "S\u1ED1 file x\u1EED l\xFD song song (m\u1EB7c \u0111\u1ECBnh: 3)", "3").option("--model <model>", "Model LLM (m\u1EB7c \u0111\u1ECBnh: gpt-5.1-codex-mini)").option("--json", "Xu\u1EA5t k\u1EBFt qu\u1EA3 d\u1EA1ng JSON").action(async (input5, options) => {
|
|
6142
|
+
await handleTranslate(input5, options);
|
|
6143
6143
|
});
|
|
6144
6144
|
return cmd;
|
|
6145
6145
|
}
|
|
@@ -6428,11 +6428,230 @@ function createImageCommand() {
|
|
|
6428
6428
|
return cmd;
|
|
6429
6429
|
}
|
|
6430
6430
|
|
|
6431
|
+
// src/commands/feedback.ts
|
|
6432
|
+
import { Command as Command21 } from "commander";
|
|
6433
|
+
import { select as select2, input, confirm as confirm5 } from "@inquirer/prompts";
|
|
6434
|
+
import os from "os";
|
|
6435
|
+
import { promises as fs10 } from "fs";
|
|
6436
|
+
import { join as join5 } from "path";
|
|
6437
|
+
async function collectContext() {
|
|
6438
|
+
const context = {
|
|
6439
|
+
os: `${os.platform()} ${os.release()}`
|
|
6440
|
+
};
|
|
6441
|
+
try {
|
|
6442
|
+
const packageJsonPath = new URL("../../package.json", import.meta.url);
|
|
6443
|
+
const packageJson = JSON.parse(await fs10.readFile(packageJsonPath, "utf-8"));
|
|
6444
|
+
context.cli_version = packageJson.version;
|
|
6445
|
+
} catch {
|
|
6446
|
+
}
|
|
6447
|
+
try {
|
|
6448
|
+
const projectPackageJson = await fs10.readFile(join5(process.cwd(), "package.json"), "utf-8");
|
|
6449
|
+
const projectData = JSON.parse(projectPackageJson);
|
|
6450
|
+
context.project_name = projectData.name;
|
|
6451
|
+
} catch {
|
|
6452
|
+
}
|
|
6453
|
+
return context;
|
|
6454
|
+
}
|
|
6455
|
+
async function submitFeedback(apiUrl, accessKey, data) {
|
|
6456
|
+
const response = await fetch(`${apiUrl}/api/feedback`, {
|
|
6457
|
+
method: "POST",
|
|
6458
|
+
headers: {
|
|
6459
|
+
"Content-Type": "application/json",
|
|
6460
|
+
"JAI1-Access-Key": accessKey
|
|
6461
|
+
},
|
|
6462
|
+
body: JSON.stringify({
|
|
6463
|
+
type: data.type,
|
|
6464
|
+
title: data.title,
|
|
6465
|
+
message: data.message,
|
|
6466
|
+
context: data.context,
|
|
6467
|
+
source: "cli"
|
|
6468
|
+
})
|
|
6469
|
+
});
|
|
6470
|
+
const result = await response.json();
|
|
6471
|
+
if (!response.ok) {
|
|
6472
|
+
return { success: false, error: result.error || "Failed to submit feedback" };
|
|
6473
|
+
}
|
|
6474
|
+
return { success: true, feedback_id: result.data.feedback_id };
|
|
6475
|
+
}
|
|
6476
|
+
async function handleInteractiveFeedback(config) {
|
|
6477
|
+
console.log("\u{1F4DD} Submit Feedback to Jai1\n");
|
|
6478
|
+
const type = await select2({
|
|
6479
|
+
message: "What type of feedback?",
|
|
6480
|
+
choices: [
|
|
6481
|
+
{
|
|
6482
|
+
name: "\u{1F41B} Bug Report - Report an error or issue",
|
|
6483
|
+
value: "bug"
|
|
6484
|
+
},
|
|
6485
|
+
{
|
|
6486
|
+
name: "\u{1F4A1} Feature Request - Suggest a new feature",
|
|
6487
|
+
value: "feature"
|
|
6488
|
+
},
|
|
6489
|
+
{
|
|
6490
|
+
name: "\u{1F4DD} Suggestion - Share ideas or improvements",
|
|
6491
|
+
value: "suggestion"
|
|
6492
|
+
}
|
|
6493
|
+
]
|
|
6494
|
+
});
|
|
6495
|
+
const title = await input({
|
|
6496
|
+
message: "Title (max 200 characters):",
|
|
6497
|
+
validate: (value) => {
|
|
6498
|
+
if (!value || value.trim().length === 0) {
|
|
6499
|
+
return "Title is required";
|
|
6500
|
+
}
|
|
6501
|
+
if (value.length > 200) {
|
|
6502
|
+
return "Title must be 200 characters or less";
|
|
6503
|
+
}
|
|
6504
|
+
return true;
|
|
6505
|
+
}
|
|
6506
|
+
});
|
|
6507
|
+
const message = await input({
|
|
6508
|
+
message: "Description (max 4000 characters):",
|
|
6509
|
+
validate: (value) => {
|
|
6510
|
+
if (!value || value.trim().length === 0) {
|
|
6511
|
+
return "Description is required";
|
|
6512
|
+
}
|
|
6513
|
+
if (value.length > 4e3) {
|
|
6514
|
+
return "Description must be 4000 characters or less";
|
|
6515
|
+
}
|
|
6516
|
+
return true;
|
|
6517
|
+
}
|
|
6518
|
+
});
|
|
6519
|
+
const includeContext = await confirm5({
|
|
6520
|
+
message: "Include system context (OS, CLI version)?",
|
|
6521
|
+
default: true
|
|
6522
|
+
});
|
|
6523
|
+
const context = includeContext ? await collectContext() : void 0;
|
|
6524
|
+
console.log("\n\u{1F4CB} Summary:\n");
|
|
6525
|
+
console.log(`Type: ${type}`);
|
|
6526
|
+
console.log(`Title: ${title}`);
|
|
6527
|
+
console.log(`Description: ${message.substring(0, 100)}${message.length > 100 ? "..." : ""}`);
|
|
6528
|
+
if (context) {
|
|
6529
|
+
console.log(`Context: OS: ${context.os}, CLI: ${context.cli_version || "unknown"}`);
|
|
6530
|
+
}
|
|
6531
|
+
const confirmed = await confirm5({
|
|
6532
|
+
message: "\nSubmit feedback?",
|
|
6533
|
+
default: true
|
|
6534
|
+
});
|
|
6535
|
+
if (!confirmed) {
|
|
6536
|
+
console.log("\n\u274C Cancelled.");
|
|
6537
|
+
return;
|
|
6538
|
+
}
|
|
6539
|
+
console.log("\n\u23F3 Submitting feedback...");
|
|
6540
|
+
try {
|
|
6541
|
+
const result = await submitFeedback(config.apiUrl, config.accessKey, {
|
|
6542
|
+
type,
|
|
6543
|
+
title: title.trim(),
|
|
6544
|
+
message: message.trim(),
|
|
6545
|
+
context
|
|
6546
|
+
});
|
|
6547
|
+
if (result.success) {
|
|
6548
|
+
console.log(`
|
|
6549
|
+
\u2705 Feedback submitted successfully!`);
|
|
6550
|
+
console.log(` Feedback ID: ${result.feedback_id}
|
|
6551
|
+
`);
|
|
6552
|
+
console.log(" Thank you for your feedback! We will review it soon.");
|
|
6553
|
+
} else {
|
|
6554
|
+
console.error(`
|
|
6555
|
+
\u274C Failed to submit feedback: ${result.error}`);
|
|
6556
|
+
process.exit(1);
|
|
6557
|
+
}
|
|
6558
|
+
} catch (error) {
|
|
6559
|
+
console.error("\n\u274C Network error:", error instanceof Error ? error.message : String(error));
|
|
6560
|
+
process.exit(1);
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
async function handleNonInteractiveFeedback(config, options) {
|
|
6564
|
+
if (!options.type || !options.title || !options.message) {
|
|
6565
|
+
throw new ValidationError("Missing required fields: --type, --title, --message");
|
|
6566
|
+
}
|
|
6567
|
+
const validTypes = ["bug", "feature", "suggestion"];
|
|
6568
|
+
if (!validTypes.includes(options.type)) {
|
|
6569
|
+
throw new ValidationError(`Invalid type. Must be one of: ${validTypes.join(", ")}`);
|
|
6570
|
+
}
|
|
6571
|
+
if (options.title.length > 200) {
|
|
6572
|
+
throw new ValidationError("Title must be 200 characters or less");
|
|
6573
|
+
}
|
|
6574
|
+
if (options.message.length > 4e3) {
|
|
6575
|
+
throw new ValidationError("Message must be 4000 characters or less");
|
|
6576
|
+
}
|
|
6577
|
+
let context;
|
|
6578
|
+
if (!options.noContext) {
|
|
6579
|
+
context = await collectContext();
|
|
6580
|
+
if (options.context) {
|
|
6581
|
+
try {
|
|
6582
|
+
const customContext = JSON.parse(options.context);
|
|
6583
|
+
context = { ...context, ...customContext };
|
|
6584
|
+
} catch {
|
|
6585
|
+
throw new ValidationError("Invalid JSON in --context");
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
try {
|
|
6590
|
+
const result = await submitFeedback(config.apiUrl, config.accessKey, {
|
|
6591
|
+
type: options.type,
|
|
6592
|
+
title: options.title.trim(),
|
|
6593
|
+
message: options.message.trim(),
|
|
6594
|
+
context
|
|
6595
|
+
});
|
|
6596
|
+
if (result.success) {
|
|
6597
|
+
if (options.json) {
|
|
6598
|
+
console.log(JSON.stringify({ success: true, feedback_id: result.feedback_id }));
|
|
6599
|
+
} else {
|
|
6600
|
+
console.log(`\u2705 Feedback submitted: ${result.feedback_id}`);
|
|
6601
|
+
}
|
|
6602
|
+
} else {
|
|
6603
|
+
if (options.json) {
|
|
6604
|
+
console.log(JSON.stringify({ success: false, error: result.error }));
|
|
6605
|
+
} else {
|
|
6606
|
+
console.error(`\u274C Error: ${result.error}`);
|
|
6607
|
+
}
|
|
6608
|
+
process.exit(1);
|
|
6609
|
+
}
|
|
6610
|
+
} catch (error) {
|
|
6611
|
+
if (options.json) {
|
|
6612
|
+
console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error" }));
|
|
6613
|
+
} else {
|
|
6614
|
+
console.error("\u274C Error:", error instanceof Error ? error.message : String(error));
|
|
6615
|
+
}
|
|
6616
|
+
process.exit(1);
|
|
6617
|
+
}
|
|
6618
|
+
}
|
|
6619
|
+
async function handleFeedbackCommand(options) {
|
|
6620
|
+
const configService = new ConfigService();
|
|
6621
|
+
const config = await configService.load();
|
|
6622
|
+
if (!config) {
|
|
6623
|
+
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
6624
|
+
}
|
|
6625
|
+
let stdinMessage = "";
|
|
6626
|
+
if (!process.stdin.isTTY && !options.message) {
|
|
6627
|
+
const chunks = [];
|
|
6628
|
+
for await (const chunk of process.stdin) {
|
|
6629
|
+
chunks.push(chunk);
|
|
6630
|
+
}
|
|
6631
|
+
stdinMessage = Buffer.concat(chunks).toString("utf-8").trim();
|
|
6632
|
+
}
|
|
6633
|
+
if (stdinMessage) {
|
|
6634
|
+
options.message = stdinMessage;
|
|
6635
|
+
}
|
|
6636
|
+
const isInteractive = !options.type && !options.title && !options.message;
|
|
6637
|
+
if (isInteractive) {
|
|
6638
|
+
await handleInteractiveFeedback(config);
|
|
6639
|
+
} else {
|
|
6640
|
+
await handleNonInteractiveFeedback(config, options);
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6643
|
+
function createFeedbackCommand() {
|
|
6644
|
+
const cmd = new Command21("feedback").alias("report").description("Submit bug reports, feature requests, or suggestions").option("--type <type>", "Feedback type: bug, feature, suggestion").option("--title <title>", "Feedback title (max 200 chars)").option("--message <message>", "Feedback message (max 4000 chars)").option("--context <json>", "Additional context as JSON").option("--no-context", "Do not include automatic context").option("--json", "Output JSON format").action(async (options) => {
|
|
6645
|
+
await handleFeedbackCommand(options);
|
|
6646
|
+
});
|
|
6647
|
+
return cmd;
|
|
6648
|
+
}
|
|
6649
|
+
|
|
6431
6650
|
// src/commands/utils/index.ts
|
|
6432
|
-
import { Command as
|
|
6651
|
+
import { Command as Command35 } from "commander";
|
|
6433
6652
|
|
|
6434
6653
|
// src/commands/utils/password.ts
|
|
6435
|
-
import { Command as
|
|
6654
|
+
import { Command as Command22 } from "commander";
|
|
6436
6655
|
|
|
6437
6656
|
// src/services/utils.service.ts
|
|
6438
6657
|
import crypto2 from "crypto";
|
|
@@ -6483,12 +6702,12 @@ var UtilsService = class {
|
|
|
6483
6702
|
/**
|
|
6484
6703
|
* Hash text or file using specified algorithm
|
|
6485
6704
|
*/
|
|
6486
|
-
async hash(
|
|
6705
|
+
async hash(input5, algorithm) {
|
|
6487
6706
|
if (algorithm === "bcrypt") {
|
|
6488
6707
|
throw new Error("Use hashBcrypt for bcrypt algorithm");
|
|
6489
6708
|
}
|
|
6490
6709
|
const hash = crypto2.createHash(algorithm);
|
|
6491
|
-
hash.update(
|
|
6710
|
+
hash.update(input5);
|
|
6492
6711
|
return hash.digest("hex");
|
|
6493
6712
|
}
|
|
6494
6713
|
/**
|
|
@@ -6501,14 +6720,14 @@ var UtilsService = class {
|
|
|
6501
6720
|
/**
|
|
6502
6721
|
* Hash using bcrypt
|
|
6503
6722
|
*/
|
|
6504
|
-
async hashBcrypt(
|
|
6505
|
-
return bcrypt.hash(
|
|
6723
|
+
async hashBcrypt(input5, rounds = 10) {
|
|
6724
|
+
return bcrypt.hash(input5, rounds);
|
|
6506
6725
|
}
|
|
6507
6726
|
/**
|
|
6508
6727
|
* Base64 encode
|
|
6509
6728
|
*/
|
|
6510
|
-
base64Encode(
|
|
6511
|
-
const buffer = typeof
|
|
6729
|
+
base64Encode(input5, urlSafe = false) {
|
|
6730
|
+
const buffer = typeof input5 === "string" ? Buffer.from(input5, "utf-8") : input5;
|
|
6512
6731
|
let encoded = buffer.toString("base64");
|
|
6513
6732
|
if (urlSafe) {
|
|
6514
6733
|
encoded = encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
@@ -6518,8 +6737,8 @@ var UtilsService = class {
|
|
|
6518
6737
|
/**
|
|
6519
6738
|
* Base64 decode
|
|
6520
6739
|
*/
|
|
6521
|
-
base64Decode(
|
|
6522
|
-
let normalized =
|
|
6740
|
+
base64Decode(input5) {
|
|
6741
|
+
let normalized = input5.replace(/-/g, "+").replace(/_/g, "/");
|
|
6523
6742
|
while (normalized.length % 4) {
|
|
6524
6743
|
normalized += "=";
|
|
6525
6744
|
}
|
|
@@ -6648,14 +6867,14 @@ var UtilsService = class {
|
|
|
6648
6867
|
/**
|
|
6649
6868
|
* URL encode
|
|
6650
6869
|
*/
|
|
6651
|
-
urlEncode(
|
|
6652
|
-
return full ? encodeURI(
|
|
6870
|
+
urlEncode(input5, full = false) {
|
|
6871
|
+
return full ? encodeURI(input5) : encodeURIComponent(input5);
|
|
6653
6872
|
}
|
|
6654
6873
|
/**
|
|
6655
6874
|
* URL decode
|
|
6656
6875
|
*/
|
|
6657
|
-
urlDecode(
|
|
6658
|
-
return full ? decodeURI(
|
|
6876
|
+
urlDecode(input5, full = false) {
|
|
6877
|
+
return full ? decodeURI(input5) : decodeURIComponent(input5);
|
|
6659
6878
|
}
|
|
6660
6879
|
/**
|
|
6661
6880
|
* Format bytes to human-readable size
|
|
@@ -6701,7 +6920,7 @@ async function handlePasswordGeneration(options) {
|
|
|
6701
6920
|
}
|
|
6702
6921
|
}
|
|
6703
6922
|
function createPasswordCommand() {
|
|
6704
|
-
const cmd = new
|
|
6923
|
+
const cmd = new Command22("password").description("Generate secure random password").option("-l, --length <number>", "Password length", "16").option("--no-lowercase", "Exclude lowercase letters").option("--no-uppercase", "Exclude uppercase letters").option("--no-digits", "Exclude digits").option("--no-symbols", "Exclude symbols").option("--symbol-chars <chars>", "Custom symbol characters").option("-c, --count <number>", "Number of passwords to generate", "1").addHelpText("after", `
|
|
6705
6924
|
Examples:
|
|
6706
6925
|
$ jai1 utils password
|
|
6707
6926
|
$ jai1 utils password --length 24
|
|
@@ -6719,7 +6938,7 @@ Examples:
|
|
|
6719
6938
|
}
|
|
6720
6939
|
|
|
6721
6940
|
// src/commands/utils/uuid.ts
|
|
6722
|
-
import { Command as
|
|
6941
|
+
import { Command as Command23 } from "commander";
|
|
6723
6942
|
async function handleUuidGeneration(options) {
|
|
6724
6943
|
const service = new UtilsService();
|
|
6725
6944
|
try {
|
|
@@ -6747,7 +6966,7 @@ async function handleUuidGeneration(options) {
|
|
|
6747
6966
|
}
|
|
6748
6967
|
}
|
|
6749
6968
|
function createUuidCommand() {
|
|
6750
|
-
const cmd = new
|
|
6969
|
+
const cmd = new Command23("uuid").description("Generate UUID v4 identifier").option("-c, --count <number>", "Number of UUIDs to generate", "1").option("--uppercase", "Output in uppercase").option("--no-hyphens", "Remove hyphens from output").addHelpText("after", `
|
|
6751
6970
|
Examples:
|
|
6752
6971
|
$ jai1 utils uuid
|
|
6753
6972
|
$ jai1 utils uuid --count 10
|
|
@@ -6764,8 +6983,8 @@ Examples:
|
|
|
6764
6983
|
}
|
|
6765
6984
|
|
|
6766
6985
|
// src/commands/utils/hash.ts
|
|
6767
|
-
import { Command as
|
|
6768
|
-
async function handleHashGeneration(
|
|
6986
|
+
import { Command as Command24 } from "commander";
|
|
6987
|
+
async function handleHashGeneration(input5, options) {
|
|
6769
6988
|
const service = new UtilsService();
|
|
6770
6989
|
try {
|
|
6771
6990
|
let hash;
|
|
@@ -6776,14 +6995,14 @@ async function handleHashGeneration(input4, options) {
|
|
|
6776
6995
|
}
|
|
6777
6996
|
hash = await service.hashFile(options.file, options.algorithm);
|
|
6778
6997
|
} else {
|
|
6779
|
-
if (!
|
|
6998
|
+
if (!input5) {
|
|
6780
6999
|
console.error("\u274C Please provide input text or use --file option");
|
|
6781
7000
|
process.exit(1);
|
|
6782
7001
|
}
|
|
6783
7002
|
if (options.algorithm === "bcrypt") {
|
|
6784
|
-
hash = await service.hashBcrypt(
|
|
7003
|
+
hash = await service.hashBcrypt(input5, options.rounds);
|
|
6785
7004
|
} else {
|
|
6786
|
-
hash = await service.hash(
|
|
7005
|
+
hash = await service.hash(input5, options.algorithm);
|
|
6787
7006
|
}
|
|
6788
7007
|
}
|
|
6789
7008
|
console.log("\u{1F512} Hash Result:");
|
|
@@ -6804,7 +7023,7 @@ async function handleHashGeneration(input4, options) {
|
|
|
6804
7023
|
}
|
|
6805
7024
|
}
|
|
6806
7025
|
function createHashCommand() {
|
|
6807
|
-
const cmd = new
|
|
7026
|
+
const cmd = new Command24("hash").description("Generate hash (MD5, SHA, bcrypt)").argument("[input]", "Text to hash").option(
|
|
6808
7027
|
"-a, --algorithm <algorithm>",
|
|
6809
7028
|
"Hash algorithm (md5, sha1, sha256, sha512, bcrypt)",
|
|
6810
7029
|
"sha256"
|
|
@@ -6816,8 +7035,8 @@ Examples:
|
|
|
6816
7035
|
$ jai1 utils hash "password" --algorithm bcrypt --rounds 12
|
|
6817
7036
|
$ jai1 utils hash --file ./myfile.txt
|
|
6818
7037
|
$ jai1 utils hash --file ./image.png --algorithm sha512
|
|
6819
|
-
`).action(async (
|
|
6820
|
-
await handleHashGeneration(
|
|
7038
|
+
`).action(async (input5, options) => {
|
|
7039
|
+
await handleHashGeneration(input5, {
|
|
6821
7040
|
...options,
|
|
6822
7041
|
rounds: parseInt(options.rounds, 10)
|
|
6823
7042
|
});
|
|
@@ -6826,9 +7045,9 @@ Examples:
|
|
|
6826
7045
|
}
|
|
6827
7046
|
|
|
6828
7047
|
// src/commands/utils/base64-encode.ts
|
|
6829
|
-
import { Command as
|
|
7048
|
+
import { Command as Command25 } from "commander";
|
|
6830
7049
|
import { readFile as readFile2 } from "fs/promises";
|
|
6831
|
-
async function handleBase64Encode(
|
|
7050
|
+
async function handleBase64Encode(input5, options) {
|
|
6832
7051
|
const service = new UtilsService();
|
|
6833
7052
|
try {
|
|
6834
7053
|
let encoded;
|
|
@@ -6836,11 +7055,11 @@ async function handleBase64Encode(input4, options) {
|
|
|
6836
7055
|
const content = await readFile2(options.file);
|
|
6837
7056
|
encoded = service.base64Encode(content, options.urlSafe);
|
|
6838
7057
|
} else {
|
|
6839
|
-
if (!
|
|
7058
|
+
if (!input5) {
|
|
6840
7059
|
console.error("\u274C Please provide input text or use --file option");
|
|
6841
7060
|
process.exit(1);
|
|
6842
7061
|
}
|
|
6843
|
-
encoded = service.base64Encode(
|
|
7062
|
+
encoded = service.base64Encode(input5, options.urlSafe);
|
|
6844
7063
|
}
|
|
6845
7064
|
console.log("\u{1F4DD} Base64 Encoded:");
|
|
6846
7065
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
@@ -6859,33 +7078,33 @@ async function handleBase64Encode(input4, options) {
|
|
|
6859
7078
|
}
|
|
6860
7079
|
}
|
|
6861
7080
|
function createBase64EncodeCommand() {
|
|
6862
|
-
const cmd = new
|
|
7081
|
+
const cmd = new Command25("base64-encode").description("Encode text or file to Base64").argument("[input]", "Text to encode").option("-f, --file <path>", "Encode file contents").option("--url-safe", "Use URL-safe Base64 encoding").addHelpText("after", `
|
|
6863
7082
|
Examples:
|
|
6864
7083
|
$ jai1 utils base64-encode "hello world"
|
|
6865
7084
|
$ jai1 utils base64-encode "hello world" --url-safe
|
|
6866
7085
|
$ jai1 utils base64-encode --file ./document.txt
|
|
6867
7086
|
$ jai1 utils base64-encode --file ./image.png
|
|
6868
|
-
`).action(async (
|
|
6869
|
-
await handleBase64Encode(
|
|
7087
|
+
`).action(async (input5, options) => {
|
|
7088
|
+
await handleBase64Encode(input5, options);
|
|
6870
7089
|
});
|
|
6871
7090
|
return cmd;
|
|
6872
7091
|
}
|
|
6873
7092
|
|
|
6874
7093
|
// src/commands/utils/base64-decode.ts
|
|
6875
|
-
import { Command as
|
|
7094
|
+
import { Command as Command26 } from "commander";
|
|
6876
7095
|
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
6877
|
-
async function handleBase64Decode(
|
|
7096
|
+
async function handleBase64Decode(input5, options) {
|
|
6878
7097
|
const service = new UtilsService();
|
|
6879
7098
|
try {
|
|
6880
7099
|
let encodedInput;
|
|
6881
7100
|
if (options.file) {
|
|
6882
7101
|
encodedInput = await readFile3(options.file, "utf-8");
|
|
6883
7102
|
} else {
|
|
6884
|
-
if (!
|
|
7103
|
+
if (!input5) {
|
|
6885
7104
|
console.error("\u274C Please provide Base64 input or use --file option");
|
|
6886
7105
|
process.exit(1);
|
|
6887
7106
|
}
|
|
6888
|
-
encodedInput =
|
|
7107
|
+
encodedInput = input5;
|
|
6889
7108
|
}
|
|
6890
7109
|
const decoded = service.base64Decode(encodedInput.trim());
|
|
6891
7110
|
if (options.output) {
|
|
@@ -6904,20 +7123,20 @@ async function handleBase64Decode(input4, options) {
|
|
|
6904
7123
|
}
|
|
6905
7124
|
}
|
|
6906
7125
|
function createBase64DecodeCommand() {
|
|
6907
|
-
const cmd = new
|
|
7126
|
+
const cmd = new Command26("base64-decode").description("Decode Base64 string").argument("[input]", "Base64 string to decode").option("-f, --file <path>", "Decode from file").option("-o, --output <path>", "Write decoded output to file").addHelpText("after", `
|
|
6908
7127
|
Examples:
|
|
6909
7128
|
$ jai1 utils base64-decode "aGVsbG8gd29ybGQ="
|
|
6910
7129
|
$ jai1 utils base64-decode --file ./encoded.txt
|
|
6911
7130
|
$ jai1 utils base64-decode "aGVsbG8=" --output ./decoded.txt
|
|
6912
7131
|
$ jai1 utils base64-decode --file ./encoded.txt --output ./image.png
|
|
6913
|
-
`).action(async (
|
|
6914
|
-
await handleBase64Decode(
|
|
7132
|
+
`).action(async (input5, options) => {
|
|
7133
|
+
await handleBase64Decode(input5, options);
|
|
6915
7134
|
});
|
|
6916
7135
|
return cmd;
|
|
6917
7136
|
}
|
|
6918
7137
|
|
|
6919
7138
|
// src/commands/utils/http.ts
|
|
6920
|
-
import { Command as
|
|
7139
|
+
import { Command as Command27 } from "commander";
|
|
6921
7140
|
import { readFile as readFile4 } from "fs/promises";
|
|
6922
7141
|
async function handleHttpRequest(url, options) {
|
|
6923
7142
|
const service = new UtilsService();
|
|
@@ -6983,7 +7202,7 @@ async function handleHttpRequest(url, options) {
|
|
|
6983
7202
|
}
|
|
6984
7203
|
}
|
|
6985
7204
|
function createHttpCommand() {
|
|
6986
|
-
const cmd = new
|
|
7205
|
+
const cmd = new Command27("http").description("Make HTTP request with formatted output").argument("<url>", "Target URL").option("-X, --method <method>", "HTTP method", "GET").option("-H, --header <header...>", "Request headers (repeatable)").option("-d, --data <data>", "Request body (JSON string)").option("--file <path>", "Read body from file").option("--timeout <ms>", "Request timeout in milliseconds", "30000").option("--no-follow", "Do not follow redirects").option("--only-headers", "Show only response headers").option("--only-body", "Show only response body").addHelpText("after", `
|
|
6987
7206
|
Examples:
|
|
6988
7207
|
$ jai1 utils http https://api.example.com/users
|
|
6989
7208
|
$ jai1 utils http https://api.example.com/users -X POST -d '{"name":"John"}'
|
|
@@ -7001,7 +7220,7 @@ Examples:
|
|
|
7001
7220
|
}
|
|
7002
7221
|
|
|
7003
7222
|
// src/commands/utils/jwt.ts
|
|
7004
|
-
import { Command as
|
|
7223
|
+
import { Command as Command28 } from "commander";
|
|
7005
7224
|
async function handleJwtDecode(token) {
|
|
7006
7225
|
const service = new UtilsService();
|
|
7007
7226
|
try {
|
|
@@ -7040,7 +7259,7 @@ async function handleJwtEncode(options) {
|
|
|
7040
7259
|
}
|
|
7041
7260
|
}
|
|
7042
7261
|
function createJwtCommand() {
|
|
7043
|
-
const jwtCommand = new
|
|
7262
|
+
const jwtCommand = new Command28("jwt").description("Decode and encode JWT tokens");
|
|
7044
7263
|
jwtCommand.command("decode").description("Decode JWT token").argument("<token>", "JWT token to decode").addHelpText("after", `
|
|
7045
7264
|
Examples:
|
|
7046
7265
|
$ jai1 utils jwt decode "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
|
@@ -7061,11 +7280,11 @@ Examples:
|
|
|
7061
7280
|
}
|
|
7062
7281
|
|
|
7063
7282
|
// src/commands/utils/unix-time.ts
|
|
7064
|
-
import { Command as
|
|
7065
|
-
async function handleUnixTime(
|
|
7283
|
+
import { Command as Command29 } from "commander";
|
|
7284
|
+
async function handleUnixTime(input5, options) {
|
|
7066
7285
|
const service = new UtilsService();
|
|
7067
7286
|
try {
|
|
7068
|
-
if (!
|
|
7287
|
+
if (!input5) {
|
|
7069
7288
|
const now = /* @__PURE__ */ new Date();
|
|
7070
7289
|
const timestamp = service.dateToUnix(now, options.ms);
|
|
7071
7290
|
console.log("\u{1F552} Current Unix Timestamp:");
|
|
@@ -7075,8 +7294,8 @@ async function handleUnixTime(input4, options) {
|
|
|
7075
7294
|
console.log(` ISO: ${now.toISOString()}`);
|
|
7076
7295
|
console.log(` Local: ${now.toLocaleString()}`);
|
|
7077
7296
|
console.log();
|
|
7078
|
-
} else if (/^\d+$/.test(
|
|
7079
|
-
const timestamp = parseInt(
|
|
7297
|
+
} else if (/^\d+$/.test(input5)) {
|
|
7298
|
+
const timestamp = parseInt(input5, 10);
|
|
7080
7299
|
const date = service.unixToDate(timestamp, options.ms);
|
|
7081
7300
|
console.log("\u{1F552} Unix Timestamp to Date:");
|
|
7082
7301
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
@@ -7089,7 +7308,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7089
7308
|
}
|
|
7090
7309
|
console.log();
|
|
7091
7310
|
} else {
|
|
7092
|
-
const date = new Date(
|
|
7311
|
+
const date = new Date(input5);
|
|
7093
7312
|
if (isNaN(date.getTime())) {
|
|
7094
7313
|
console.error("\u274C Invalid date format");
|
|
7095
7314
|
process.exit(1);
|
|
@@ -7097,7 +7316,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7097
7316
|
const timestamp = service.dateToUnix(date, options.ms);
|
|
7098
7317
|
console.log("\u{1F552} Date to Unix Timestamp:");
|
|
7099
7318
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7100
|
-
console.log(` Input: ${
|
|
7319
|
+
console.log(` Input: ${input5}`);
|
|
7101
7320
|
console.log(` Parsed: ${date.toISOString()}`);
|
|
7102
7321
|
console.log();
|
|
7103
7322
|
console.log(` ${timestamp}${options.ms ? " (ms)" : ""}`);
|
|
@@ -7109,7 +7328,7 @@ async function handleUnixTime(input4, options) {
|
|
|
7109
7328
|
}
|
|
7110
7329
|
}
|
|
7111
7330
|
function createUnixTimeCommand() {
|
|
7112
|
-
const cmd = new
|
|
7331
|
+
const cmd = new Command29("unix-time").description("Convert unix timestamps to/from dates").argument("[input]", "Unix timestamp or date string").option("-f, --format <format>", "Output format (iso, local, utc)", "iso").option("--ms", "Use milliseconds instead of seconds").addHelpText("after", `
|
|
7113
7332
|
Examples:
|
|
7114
7333
|
$ jai1 utils unix-time
|
|
7115
7334
|
$ jai1 utils unix-time 1702550400
|
|
@@ -7117,14 +7336,14 @@ Examples:
|
|
|
7117
7336
|
$ jai1 utils unix-time "2024-01-15 10:30:00"
|
|
7118
7337
|
$ jai1 utils unix-time "2024-01-15" --format local
|
|
7119
7338
|
$ jai1 utils unix-time --ms
|
|
7120
|
-
`).action(async (
|
|
7121
|
-
await handleUnixTime(
|
|
7339
|
+
`).action(async (input5, options) => {
|
|
7340
|
+
await handleUnixTime(input5, options);
|
|
7122
7341
|
});
|
|
7123
7342
|
return cmd;
|
|
7124
7343
|
}
|
|
7125
7344
|
|
|
7126
7345
|
// src/commands/utils/timezone.ts
|
|
7127
|
-
import { Command as
|
|
7346
|
+
import { Command as Command30 } from "commander";
|
|
7128
7347
|
async function handleTimezoneConversion(time, options) {
|
|
7129
7348
|
const service = new UtilsService();
|
|
7130
7349
|
try {
|
|
@@ -7161,7 +7380,7 @@ async function handleTimezoneConversion(time, options) {
|
|
|
7161
7380
|
}
|
|
7162
7381
|
}
|
|
7163
7382
|
function createTimezoneCommand() {
|
|
7164
|
-
const cmd = new
|
|
7383
|
+
const cmd = new Command30("timezone").description("Convert time between timezones").argument("[time]", 'Time to convert (e.g., "2024-01-15 10:00")').option("--from <timezone>", "Source timezone").option("--to <timezone>", "Target timezone").option("--list", "Show available timezones").addHelpText("after", `
|
|
7165
7384
|
Examples:
|
|
7166
7385
|
$ jai1 utils timezone --list
|
|
7167
7386
|
$ jai1 utils timezone "2024-01-15 10:00" --from "America/New_York" --to "Asia/Tokyo"
|
|
@@ -7174,11 +7393,11 @@ Examples:
|
|
|
7174
7393
|
}
|
|
7175
7394
|
|
|
7176
7395
|
// src/commands/utils/url-encode.ts
|
|
7177
|
-
import { Command as
|
|
7178
|
-
async function handleUrlEncode(
|
|
7396
|
+
import { Command as Command31 } from "commander";
|
|
7397
|
+
async function handleUrlEncode(input5, options) {
|
|
7179
7398
|
const service = new UtilsService();
|
|
7180
7399
|
try {
|
|
7181
|
-
const encoded = service.urlEncode(
|
|
7400
|
+
const encoded = service.urlEncode(input5, options.full);
|
|
7182
7401
|
console.log("\u{1F517} URL Encoded:");
|
|
7183
7402
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7184
7403
|
if (options.full) {
|
|
@@ -7195,24 +7414,24 @@ async function handleUrlEncode(input4, options) {
|
|
|
7195
7414
|
}
|
|
7196
7415
|
}
|
|
7197
7416
|
function createUrlEncodeCommand() {
|
|
7198
|
-
const cmd = new
|
|
7417
|
+
const cmd = new Command31("url-encode").description("Encode URL component or full URL").argument("<input>", "Text to encode").option("--full", "Encode full URL (use encodeURI instead of encodeURIComponent)").addHelpText("after", `
|
|
7199
7418
|
Examples:
|
|
7200
7419
|
$ jai1 utils url-encode "hello world"
|
|
7201
7420
|
$ jai1 utils url-encode "hello world & test"
|
|
7202
7421
|
$ jai1 utils url-encode "name=John Doe&age=30"
|
|
7203
7422
|
$ jai1 utils url-encode "https://example.com/path with spaces" --full
|
|
7204
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
7205
|
-
await handleUrlEncode(
|
|
7423
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input5, options) => {
|
|
7424
|
+
await handleUrlEncode(input5, options);
|
|
7206
7425
|
});
|
|
7207
7426
|
return cmd;
|
|
7208
7427
|
}
|
|
7209
7428
|
|
|
7210
7429
|
// src/commands/utils/url-decode.ts
|
|
7211
|
-
import { Command as
|
|
7212
|
-
async function handleUrlDecode(
|
|
7430
|
+
import { Command as Command32 } from "commander";
|
|
7431
|
+
async function handleUrlDecode(input5, options) {
|
|
7213
7432
|
const service = new UtilsService();
|
|
7214
7433
|
try {
|
|
7215
|
-
const decoded = service.urlDecode(
|
|
7434
|
+
const decoded = service.urlDecode(input5, options.full);
|
|
7216
7435
|
console.log("\u{1F517} URL Decoded:");
|
|
7217
7436
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
7218
7437
|
if (options.full) {
|
|
@@ -7229,20 +7448,20 @@ async function handleUrlDecode(input4, options) {
|
|
|
7229
7448
|
}
|
|
7230
7449
|
}
|
|
7231
7450
|
function createUrlDecodeCommand() {
|
|
7232
|
-
const cmd = new
|
|
7451
|
+
const cmd = new Command32("url-decode").description("Decode URL-encoded string").argument("<input>", "Text to decode").option("--full", "Decode full URL (use decodeURI instead of decodeURIComponent)").addHelpText("after", `
|
|
7233
7452
|
Examples:
|
|
7234
7453
|
$ jai1 utils url-decode "hello%20world"
|
|
7235
7454
|
$ jai1 utils url-decode "hello%20world%20%26%20test"
|
|
7236
7455
|
$ jai1 utils url-decode "name%3DJohn%20Doe%26age%3D30"
|
|
7237
7456
|
$ jai1 utils url-decode "https://example.com/path%20with%20spaces" --full
|
|
7238
|
-
`).showHelpAfterError("(add --help for additional examples)").action(async (
|
|
7239
|
-
await handleUrlDecode(
|
|
7457
|
+
`).showHelpAfterError("(add --help for additional examples)").action(async (input5, options) => {
|
|
7458
|
+
await handleUrlDecode(input5, options);
|
|
7240
7459
|
});
|
|
7241
7460
|
return cmd;
|
|
7242
7461
|
}
|
|
7243
7462
|
|
|
7244
7463
|
// src/commands/utils/cron.ts
|
|
7245
|
-
import { Command as
|
|
7464
|
+
import { Command as Command33 } from "commander";
|
|
7246
7465
|
import cronstrue from "cronstrue";
|
|
7247
7466
|
async function handleCronParse(expression) {
|
|
7248
7467
|
try {
|
|
@@ -7285,7 +7504,7 @@ async function handleCronParse(expression) {
|
|
|
7285
7504
|
}
|
|
7286
7505
|
}
|
|
7287
7506
|
function createCronCommand() {
|
|
7288
|
-
const cmd = new
|
|
7507
|
+
const cmd = new Command33("cron").description("Parse and explain cron expression").argument("<expression>", 'Cron expression (e.g., "0 5 * * *")').addHelpText("after", `
|
|
7289
7508
|
Examples:
|
|
7290
7509
|
$ jai1 utils cron "0 5 * * *"
|
|
7291
7510
|
$ jai1 utils cron "*/15 * * * *"
|
|
@@ -7299,7 +7518,7 @@ Examples:
|
|
|
7299
7518
|
}
|
|
7300
7519
|
|
|
7301
7520
|
// src/commands/utils/markdown-preview.ts
|
|
7302
|
-
import { Command as
|
|
7521
|
+
import { Command as Command34 } from "commander";
|
|
7303
7522
|
import { readFile as readFile5 } from "fs/promises";
|
|
7304
7523
|
import { marked } from "marked";
|
|
7305
7524
|
import TerminalRenderer from "marked-terminal";
|
|
@@ -7338,7 +7557,7 @@ ${code.trim()}
|
|
|
7338
7557
|
}
|
|
7339
7558
|
}
|
|
7340
7559
|
function createMarkdownPreviewCommand() {
|
|
7341
|
-
const cmd = new
|
|
7560
|
+
const cmd = new Command34("markdown-preview").description("Preview markdown file in terminal").argument("<file>", "Markdown file path").option("--raw", "Show raw markdown instead of rendered").addHelpText("after", `
|
|
7342
7561
|
Examples:
|
|
7343
7562
|
$ jai1 utils markdown-preview README.md
|
|
7344
7563
|
$ jai1 utils markdown-preview ./docs/guide.md
|
|
@@ -7372,14 +7591,14 @@ var PasswordView = () => {
|
|
|
7372
7591
|
React27.useEffect(() => {
|
|
7373
7592
|
handleGenerate();
|
|
7374
7593
|
}, []);
|
|
7375
|
-
useInput12((
|
|
7594
|
+
useInput12((input5, key) => {
|
|
7376
7595
|
if (key.tab) {
|
|
7377
7596
|
if (focusedField === "length") setFocusedField("count");
|
|
7378
7597
|
else if (focusedField === "count") setFocusedField("generate");
|
|
7379
7598
|
else setFocusedField("length");
|
|
7380
7599
|
} else if (key.return) {
|
|
7381
7600
|
handleGenerate();
|
|
7382
|
-
} else if (
|
|
7601
|
+
} else if (input5 === "c" && passwords.length > 0) {
|
|
7383
7602
|
handleCopy(0);
|
|
7384
7603
|
}
|
|
7385
7604
|
});
|
|
@@ -7462,7 +7681,7 @@ var UuidView = () => {
|
|
|
7462
7681
|
React28.useEffect(() => {
|
|
7463
7682
|
handleGenerate();
|
|
7464
7683
|
}, []);
|
|
7465
|
-
useInput13((
|
|
7684
|
+
useInput13((input5, key) => {
|
|
7466
7685
|
if (key.tab) {
|
|
7467
7686
|
const fields = ["count", "uppercase", "hyphens", "generate"];
|
|
7468
7687
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7475,7 +7694,7 @@ var UuidView = () => {
|
|
|
7475
7694
|
} else {
|
|
7476
7695
|
handleGenerate();
|
|
7477
7696
|
}
|
|
7478
|
-
} else if (
|
|
7697
|
+
} else if (input5 === "c" && uuids.length > 0) {
|
|
7479
7698
|
handleCopy(0);
|
|
7480
7699
|
}
|
|
7481
7700
|
});
|
|
@@ -7550,7 +7769,7 @@ var HashView = () => {
|
|
|
7550
7769
|
React29.useEffect(() => {
|
|
7551
7770
|
handleGenerate();
|
|
7552
7771
|
}, []);
|
|
7553
|
-
useInput14((
|
|
7772
|
+
useInput14((input5, key) => {
|
|
7554
7773
|
if (key.tab) {
|
|
7555
7774
|
const fields = ["text", "algorithm", "generate"];
|
|
7556
7775
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7563,7 +7782,7 @@ var HashView = () => {
|
|
|
7563
7782
|
} else if (key.rightArrow && focusedField === "algorithm") {
|
|
7564
7783
|
const currentIndex = ALGORITHMS.indexOf(algorithm);
|
|
7565
7784
|
setAlgorithm(ALGORITHMS[(currentIndex + 1) % ALGORITHMS.length]);
|
|
7566
|
-
} else if (
|
|
7785
|
+
} else if (input5 === "c" && hash) {
|
|
7567
7786
|
handleCopy();
|
|
7568
7787
|
}
|
|
7569
7788
|
});
|
|
@@ -7629,7 +7848,7 @@ import React30, { useState as useState17 } from "react";
|
|
|
7629
7848
|
import { Box as Box20, Text as Text21, useInput as useInput15 } from "ink";
|
|
7630
7849
|
import TextInput7 from "ink-text-input";
|
|
7631
7850
|
var Base64View = () => {
|
|
7632
|
-
const [
|
|
7851
|
+
const [input5, setInput] = useState17("");
|
|
7633
7852
|
const [mode, setMode] = useState17("encode");
|
|
7634
7853
|
const [urlSafe, setUrlSafe] = useState17(false);
|
|
7635
7854
|
const [result, setResult] = useState17("");
|
|
@@ -7637,7 +7856,7 @@ var Base64View = () => {
|
|
|
7637
7856
|
const [focusedField, setFocusedField] = useState17("input");
|
|
7638
7857
|
const [copied, setCopied] = useState17(false);
|
|
7639
7858
|
const service = new UtilsService();
|
|
7640
|
-
useInput15((
|
|
7859
|
+
useInput15((input6, key) => {
|
|
7641
7860
|
if (key.tab) {
|
|
7642
7861
|
const fields = ["input", "mode", "urlsafe", "convert"];
|
|
7643
7862
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7652,22 +7871,22 @@ var Base64View = () => {
|
|
|
7652
7871
|
} else {
|
|
7653
7872
|
handleConvert();
|
|
7654
7873
|
}
|
|
7655
|
-
} else if (
|
|
7874
|
+
} else if (input6 === "c" && result) {
|
|
7656
7875
|
handleCopy();
|
|
7657
7876
|
}
|
|
7658
7877
|
});
|
|
7659
7878
|
const handleConvert = () => {
|
|
7660
|
-
if (!
|
|
7879
|
+
if (!input5) {
|
|
7661
7880
|
setError("Input cannot be empty");
|
|
7662
7881
|
return;
|
|
7663
7882
|
}
|
|
7664
7883
|
try {
|
|
7665
7884
|
setError("");
|
|
7666
7885
|
if (mode === "encode") {
|
|
7667
|
-
const encoded = service.base64Encode(
|
|
7886
|
+
const encoded = service.base64Encode(input5, urlSafe);
|
|
7668
7887
|
setResult(encoded);
|
|
7669
7888
|
} else {
|
|
7670
|
-
const decoded = service.base64Decode(
|
|
7889
|
+
const decoded = service.base64Decode(input5);
|
|
7671
7890
|
setResult(decoded.toString("utf-8"));
|
|
7672
7891
|
}
|
|
7673
7892
|
setCopied(false);
|
|
@@ -7696,7 +7915,7 @@ var Base64View = () => {
|
|
|
7696
7915
|
marginBottom: 1
|
|
7697
7916
|
},
|
|
7698
7917
|
/* @__PURE__ */ React30.createElement(Text21, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
7699
|
-
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 0 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React30.createElement(TextInput7, { value:
|
|
7918
|
+
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 0 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React30.createElement(Box20, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React30.createElement(TextInput7, { value: input5, onChange: setInput, placeholder: "Enter text..." }) : /* @__PURE__ */ React30.createElement(Text21, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7700
7919
|
/* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Box20, { width: 20 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React30.createElement(Text21, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React30.createElement(Text21, { dimColor: true }, " (Enter to toggle)")),
|
|
7701
7920
|
mode === "encode" && /* @__PURE__ */ React30.createElement(Box20, { marginBottom: 1 }, /* @__PURE__ */ React30.createElement(Text21, { color: focusedField === "urlsafe" ? "green" : void 0 }, focusedField === "urlsafe" ? "\u25B6 " : " ", "[", urlSafe ? "\u2713" : " ", "] URL-Safe (+ \u2192 -, / \u2192 _)")),
|
|
7702
7921
|
/* @__PURE__ */ React30.createElement(Box20, { marginTop: 1 }, /* @__PURE__ */ React30.createElement(
|
|
@@ -7741,14 +7960,14 @@ import React31, { useState as useState18 } from "react";
|
|
|
7741
7960
|
import { Box as Box21, Text as Text22, useInput as useInput16 } from "ink";
|
|
7742
7961
|
import TextInput8 from "ink-text-input";
|
|
7743
7962
|
var UrlView = () => {
|
|
7744
|
-
const [
|
|
7963
|
+
const [input5, setInput] = useState18("");
|
|
7745
7964
|
const [mode, setMode] = useState18("encode");
|
|
7746
7965
|
const [fullUrl, setFullUrl] = useState18(false);
|
|
7747
7966
|
const [result, setResult] = useState18("");
|
|
7748
7967
|
const [focusedField, setFocusedField] = useState18("input");
|
|
7749
7968
|
const [copied, setCopied] = useState18(false);
|
|
7750
7969
|
const service = new UtilsService();
|
|
7751
|
-
useInput16((
|
|
7970
|
+
useInput16((input6, key) => {
|
|
7752
7971
|
if (key.tab) {
|
|
7753
7972
|
const fields = ["input", "mode", "full", "convert"];
|
|
7754
7973
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7762,17 +7981,17 @@ var UrlView = () => {
|
|
|
7762
7981
|
} else {
|
|
7763
7982
|
handleConvert();
|
|
7764
7983
|
}
|
|
7765
|
-
} else if (
|
|
7984
|
+
} else if (input6 === "c" && result) {
|
|
7766
7985
|
handleCopy();
|
|
7767
7986
|
}
|
|
7768
7987
|
});
|
|
7769
7988
|
const handleConvert = () => {
|
|
7770
|
-
if (!
|
|
7989
|
+
if (!input5) return;
|
|
7771
7990
|
if (mode === "encode") {
|
|
7772
|
-
const encoded = fullUrl ? service.urlEncode(
|
|
7991
|
+
const encoded = fullUrl ? service.urlEncode(input5, true) : service.urlEncode(input5, false);
|
|
7773
7992
|
setResult(encoded);
|
|
7774
7993
|
} else {
|
|
7775
|
-
const decoded = fullUrl ? service.urlDecode(
|
|
7994
|
+
const decoded = fullUrl ? service.urlDecode(input5, true) : service.urlDecode(input5, false);
|
|
7776
7995
|
setResult(decoded);
|
|
7777
7996
|
}
|
|
7778
7997
|
setCopied(false);
|
|
@@ -7797,7 +8016,7 @@ var UrlView = () => {
|
|
|
7797
8016
|
marginBottom: 1
|
|
7798
8017
|
},
|
|
7799
8018
|
/* @__PURE__ */ React31.createElement(Text22, { bold: true, color: "yellow", marginBottom: 1 }, "Options:"),
|
|
7800
|
-
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 0 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React31.createElement(TextInput8, { value:
|
|
8019
|
+
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React31.createElement(Box21, { marginBottom: 0 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", "Input text:")), /* @__PURE__ */ React31.createElement(Box21, { marginLeft: 2, width: 60 }, focusedField === "input" ? /* @__PURE__ */ React31.createElement(TextInput8, { value: input5, onChange: setInput, placeholder: "Enter text or URL..." }) : /* @__PURE__ */ React31.createElement(Text22, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7801
8020
|
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Box21, { width: 20 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "mode" ? "green" : void 0 }, focusedField === "mode" ? "\u25B6 " : " ", "Mode:")), /* @__PURE__ */ React31.createElement(Text22, { bold: true, color: focusedField === "mode" ? "yellow" : void 0 }, mode === "encode" ? "ENCODE" : "DECODE"), focusedField === "mode" && /* @__PURE__ */ React31.createElement(Text22, { dimColor: true }, " (Enter to toggle)")),
|
|
7802
8021
|
/* @__PURE__ */ React31.createElement(Box21, { marginBottom: 1 }, /* @__PURE__ */ React31.createElement(Text22, { color: focusedField === "full" ? "green" : void 0 }, focusedField === "full" ? "\u25B6 " : " ", "[", fullUrl ? "\u2713" : " ", "] Full URL (encode/decode entire URL)")),
|
|
7803
8022
|
/* @__PURE__ */ React31.createElement(Box21, { marginTop: 1 }, /* @__PURE__ */ React31.createElement(
|
|
@@ -7831,7 +8050,7 @@ import React32, { useState as useState19 } from "react";
|
|
|
7831
8050
|
import { Box as Box22, Text as Text23, useInput as useInput17 } from "ink";
|
|
7832
8051
|
import TextInput9 from "ink-text-input";
|
|
7833
8052
|
var UnixTimeView = () => {
|
|
7834
|
-
const [
|
|
8053
|
+
const [input5, setInput] = useState19("");
|
|
7835
8054
|
const [mode, setMode] = useState19("now");
|
|
7836
8055
|
const [format, setFormat] = useState19("iso");
|
|
7837
8056
|
const [useMs, setUseMs] = useState19(false);
|
|
@@ -7840,7 +8059,7 @@ var UnixTimeView = () => {
|
|
|
7840
8059
|
const [focusedField, setFocusedField] = useState19("mode");
|
|
7841
8060
|
const [copied, setCopied] = useState19(false);
|
|
7842
8061
|
const service = new UtilsService();
|
|
7843
|
-
useInput17((
|
|
8062
|
+
useInput17((input6, key) => {
|
|
7844
8063
|
if (key.tab) {
|
|
7845
8064
|
const fields = mode === "now" ? ["mode", "ms", "convert"] : mode === "to-human" ? ["mode", "input", "format", "convert"] : ["mode", "input", "convert"];
|
|
7846
8065
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7861,7 +8080,7 @@ var UnixTimeView = () => {
|
|
|
7861
8080
|
} else {
|
|
7862
8081
|
handleConvert();
|
|
7863
8082
|
}
|
|
7864
|
-
} else if (
|
|
8083
|
+
} else if (input6 === "c" && result) {
|
|
7865
8084
|
handleCopy();
|
|
7866
8085
|
}
|
|
7867
8086
|
});
|
|
@@ -7872,18 +8091,18 @@ var UnixTimeView = () => {
|
|
|
7872
8091
|
const timestamp = service.unixTimeCurrent(useMs);
|
|
7873
8092
|
setResult(timestamp.toString());
|
|
7874
8093
|
} else if (mode === "to-human") {
|
|
7875
|
-
if (!
|
|
8094
|
+
if (!input5) {
|
|
7876
8095
|
setError("Please enter a timestamp");
|
|
7877
8096
|
return;
|
|
7878
8097
|
}
|
|
7879
|
-
const human = service.unixTimeToHuman(parseInt(
|
|
8098
|
+
const human = service.unixTimeToHuman(parseInt(input5, 10), format);
|
|
7880
8099
|
setResult(human);
|
|
7881
8100
|
} else {
|
|
7882
|
-
if (!
|
|
8101
|
+
if (!input5) {
|
|
7883
8102
|
setError("Please enter a date string");
|
|
7884
8103
|
return;
|
|
7885
8104
|
}
|
|
7886
|
-
const timestamp = service.unixTimeFromString(
|
|
8105
|
+
const timestamp = service.unixTimeFromString(input5);
|
|
7887
8106
|
setResult(timestamp.toString());
|
|
7888
8107
|
}
|
|
7889
8108
|
setCopied(false);
|
|
@@ -7916,11 +8135,11 @@ var UnixTimeView = () => {
|
|
|
7916
8135
|
mode !== "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1, flexDirection: "column" }, /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 0 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "input" ? "green" : void 0 }, focusedField === "input" ? "\u25B6 " : " ", mode === "to-human" ? "Timestamp:" : "Date string:")), /* @__PURE__ */ React32.createElement(Box22, { marginLeft: 2, width: 50 }, focusedField === "input" ? /* @__PURE__ */ React32.createElement(
|
|
7917
8136
|
TextInput9,
|
|
7918
8137
|
{
|
|
7919
|
-
value:
|
|
8138
|
+
value: input5,
|
|
7920
8139
|
onChange: setInput,
|
|
7921
8140
|
placeholder: mode === "to-human" ? "1702550400" : "2024-01-15 10:30:00"
|
|
7922
8141
|
}
|
|
7923
|
-
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !
|
|
8142
|
+
) : /* @__PURE__ */ React32.createElement(Text23, { dimColor: !input5 }, input5 || "(empty)"))),
|
|
7924
8143
|
mode === "to-human" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Box22, { width: 20 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "format" ? "green" : void 0 }, focusedField === "format" ? "\u25B6 " : " ", "Format:")), /* @__PURE__ */ React32.createElement(Text23, { bold: true, color: focusedField === "format" ? "yellow" : void 0 }, format.toUpperCase()), focusedField === "format" && /* @__PURE__ */ React32.createElement(Text23, { dimColor: true }, " (Enter to cycle)")),
|
|
7925
8144
|
mode === "now" && /* @__PURE__ */ React32.createElement(Box22, { marginBottom: 1 }, /* @__PURE__ */ React32.createElement(Text23, { color: focusedField === "ms" ? "green" : void 0 }, focusedField === "ms" ? "\u25B6 " : " ", "[", useMs ? "\u2713" : " ", "] Milliseconds")),
|
|
7926
8145
|
/* @__PURE__ */ React32.createElement(Box22, { marginTop: 1 }, /* @__PURE__ */ React32.createElement(
|
|
@@ -7974,7 +8193,7 @@ var JwtView = () => {
|
|
|
7974
8193
|
const [focusedField, setFocusedField] = useState20("mode");
|
|
7975
8194
|
const [copied, setCopied] = useState20(false);
|
|
7976
8195
|
const service = new UtilsService();
|
|
7977
|
-
useInput18((
|
|
8196
|
+
useInput18((input5, key) => {
|
|
7978
8197
|
if (key.tab) {
|
|
7979
8198
|
const fields = mode === "decode" ? ["mode", "token", "process"] : ["mode", "payload", "secret", "process"];
|
|
7980
8199
|
const currentIndex = fields.indexOf(focusedField);
|
|
@@ -7987,7 +8206,7 @@ var JwtView = () => {
|
|
|
7987
8206
|
} else {
|
|
7988
8207
|
handleProcess();
|
|
7989
8208
|
}
|
|
7990
|
-
} else if (
|
|
8209
|
+
} else if (input5 === "c" && result.token) {
|
|
7991
8210
|
handleCopy();
|
|
7992
8211
|
}
|
|
7993
8212
|
});
|
|
@@ -8112,12 +8331,12 @@ var CronView = () => {
|
|
|
8112
8331
|
const [focusedField, setFocusedField] = useState21("expression");
|
|
8113
8332
|
const [copied, setCopied] = useState21(false);
|
|
8114
8333
|
const service = new UtilsService();
|
|
8115
|
-
useInput19((
|
|
8334
|
+
useInput19((input5, key) => {
|
|
8116
8335
|
if (key.tab) {
|
|
8117
8336
|
setFocusedField(focusedField === "expression" ? "parse" : "expression");
|
|
8118
8337
|
} else if (key.return) {
|
|
8119
8338
|
handleParse();
|
|
8120
|
-
} else if (
|
|
8339
|
+
} else if (input5 === "c" && result) {
|
|
8121
8340
|
handleCopy();
|
|
8122
8341
|
}
|
|
8123
8342
|
});
|
|
@@ -8218,14 +8437,14 @@ var TimezoneView = () => {
|
|
|
8218
8437
|
const [focusedField, setFocusedField] = useState22("time");
|
|
8219
8438
|
const [copied, setCopied] = useState22(false);
|
|
8220
8439
|
const service = new UtilsService();
|
|
8221
|
-
useInput20((
|
|
8440
|
+
useInput20((input5, key) => {
|
|
8222
8441
|
if (key.tab) {
|
|
8223
8442
|
const fields = ["time", "from", "to", "convert"];
|
|
8224
8443
|
const currentIndex = fields.indexOf(focusedField);
|
|
8225
8444
|
setFocusedField(fields[(currentIndex + 1) % fields.length]);
|
|
8226
8445
|
} else if (key.return) {
|
|
8227
8446
|
handleConvert();
|
|
8228
|
-
} else if (
|
|
8447
|
+
} else if (input5 === "c" && result) {
|
|
8229
8448
|
handleCopy();
|
|
8230
8449
|
}
|
|
8231
8450
|
});
|
|
@@ -8344,7 +8563,7 @@ var HttpView = () => {
|
|
|
8344
8563
|
const [focusedField, setFocusedField] = useState23("url");
|
|
8345
8564
|
const [copied, setCopied] = useState23(false);
|
|
8346
8565
|
const service = new UtilsService();
|
|
8347
|
-
useInput21((
|
|
8566
|
+
useInput21((input5, key) => {
|
|
8348
8567
|
if (loading) return;
|
|
8349
8568
|
if (key.tab) {
|
|
8350
8569
|
const fields = ["url", "method", "headers", "body", "send"];
|
|
@@ -8358,7 +8577,7 @@ var HttpView = () => {
|
|
|
8358
8577
|
setMethod(METHODS[(currentIndex + 1) % METHODS.length]);
|
|
8359
8578
|
} else if (key.return && focusedField === "send") {
|
|
8360
8579
|
handleSend();
|
|
8361
|
-
} else if (
|
|
8580
|
+
} else if (input5 === "c" && response) {
|
|
8362
8581
|
handleCopy();
|
|
8363
8582
|
}
|
|
8364
8583
|
});
|
|
@@ -8482,14 +8701,14 @@ var HttpView = () => {
|
|
|
8482
8701
|
import React37, { useState as useState24 } from "react";
|
|
8483
8702
|
import { Box as Box27, Text as Text28, useInput as useInput22 } from "ink";
|
|
8484
8703
|
import TextInput14 from "ink-text-input";
|
|
8485
|
-
import * as
|
|
8704
|
+
import * as fs11 from "fs";
|
|
8486
8705
|
import * as path6 from "path";
|
|
8487
8706
|
var MarkdownView = () => {
|
|
8488
8707
|
const [filePath, setFilePath] = useState24("");
|
|
8489
8708
|
const [content, setContent] = useState24("");
|
|
8490
8709
|
const [error, setError] = useState24("");
|
|
8491
8710
|
const [focusedField, setFocusedField] = useState24("file");
|
|
8492
|
-
useInput22((
|
|
8711
|
+
useInput22((input5, key) => {
|
|
8493
8712
|
if (key.tab) {
|
|
8494
8713
|
setFocusedField(focusedField === "file" ? "preview" : "file");
|
|
8495
8714
|
} else if (key.return) {
|
|
@@ -8504,11 +8723,11 @@ var MarkdownView = () => {
|
|
|
8504
8723
|
try {
|
|
8505
8724
|
setError("");
|
|
8506
8725
|
const resolvedPath = path6.resolve(filePath);
|
|
8507
|
-
if (!
|
|
8726
|
+
if (!fs11.existsSync(resolvedPath)) {
|
|
8508
8727
|
setError(`File not found: ${resolvedPath}`);
|
|
8509
8728
|
return;
|
|
8510
8729
|
}
|
|
8511
|
-
let fileContent =
|
|
8730
|
+
let fileContent = fs11.readFileSync(resolvedPath, "utf-8");
|
|
8512
8731
|
fileContent = fileContent.replace(/```mermaid\n([\s\S]*?)```/g, (match, code) => {
|
|
8513
8732
|
return `
|
|
8514
8733
|
\u{1F3A8} **Mermaid Diagram**
|
|
@@ -8604,20 +8823,20 @@ var UtilsApp = ({ onExit }) => {
|
|
|
8604
8823
|
const [selectedIndex, setSelectedIndex] = useState25(0);
|
|
8605
8824
|
const [activeView, setActiveView] = useState25(null);
|
|
8606
8825
|
const { exit } = useApp5();
|
|
8607
|
-
useInput23((
|
|
8826
|
+
useInput23((input5, key) => {
|
|
8608
8827
|
if (activeView) {
|
|
8609
8828
|
if (key.escape) {
|
|
8610
8829
|
setActiveView(null);
|
|
8611
8830
|
}
|
|
8612
8831
|
return;
|
|
8613
8832
|
}
|
|
8614
|
-
if (key.upArrow ||
|
|
8833
|
+
if (key.upArrow || input5 === "k") {
|
|
8615
8834
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : MENU_ITEMS2.length - 1);
|
|
8616
|
-
} else if (key.downArrow ||
|
|
8835
|
+
} else if (key.downArrow || input5 === "j") {
|
|
8617
8836
|
setSelectedIndex((prev) => prev < MENU_ITEMS2.length - 1 ? prev + 1 : 0);
|
|
8618
8837
|
} else if (key.return) {
|
|
8619
8838
|
setActiveView(MENU_ITEMS2[selectedIndex].id);
|
|
8620
|
-
} else if (
|
|
8839
|
+
} else if (input5 === "q" || key.escape) {
|
|
8621
8840
|
onExit();
|
|
8622
8841
|
exit();
|
|
8623
8842
|
}
|
|
@@ -8747,7 +8966,7 @@ async function runInteractiveMode() {
|
|
|
8747
8966
|
|
|
8748
8967
|
// src/commands/utils/index.ts
|
|
8749
8968
|
function createUtilsCommand() {
|
|
8750
|
-
const utilsCommand = new
|
|
8969
|
+
const utilsCommand = new Command35("utils").description("Developer utilities for common tasks").option("-i, --interactive", "Run in interactive mode").addHelpText("after", `
|
|
8751
8970
|
Interactive Mode:
|
|
8752
8971
|
$ jai1 utils --interactive
|
|
8753
8972
|
$ jai1 utils -i
|
|
@@ -8782,14 +9001,14 @@ Quick Usage:
|
|
|
8782
9001
|
}
|
|
8783
9002
|
|
|
8784
9003
|
// src/commands/deps/index.ts
|
|
8785
|
-
import { Command as
|
|
9004
|
+
import { Command as Command37 } from "commander";
|
|
8786
9005
|
|
|
8787
9006
|
// src/commands/deps/upgrade.ts
|
|
8788
|
-
import { Command as
|
|
8789
|
-
import { checkbox as checkbox3, confirm as
|
|
9007
|
+
import { Command as Command36 } from "commander";
|
|
9008
|
+
import { checkbox as checkbox3, confirm as confirm6 } from "@inquirer/prompts";
|
|
8790
9009
|
|
|
8791
9010
|
// src/services/deps.service.ts
|
|
8792
|
-
import { promises as
|
|
9011
|
+
import { promises as fs12 } from "fs";
|
|
8793
9012
|
import path7 from "path";
|
|
8794
9013
|
import { execSync } from "child_process";
|
|
8795
9014
|
import pLimit2 from "p-limit";
|
|
@@ -8801,7 +9020,7 @@ var DepsService = class {
|
|
|
8801
9020
|
async readPackageJson(cwd) {
|
|
8802
9021
|
const pkgPath = path7.join(cwd, "package.json");
|
|
8803
9022
|
try {
|
|
8804
|
-
const content = await
|
|
9023
|
+
const content = await fs12.readFile(pkgPath, "utf-8");
|
|
8805
9024
|
return JSON.parse(content);
|
|
8806
9025
|
} catch (error) {
|
|
8807
9026
|
if (error.code === "ENOENT") {
|
|
@@ -8907,7 +9126,7 @@ var DepsService = class {
|
|
|
8907
9126
|
];
|
|
8908
9127
|
for (const { file, pm } of lockFiles) {
|
|
8909
9128
|
try {
|
|
8910
|
-
await
|
|
9129
|
+
await fs12.access(path7.join(cwd, file));
|
|
8911
9130
|
return pm;
|
|
8912
9131
|
} catch {
|
|
8913
9132
|
}
|
|
@@ -8999,7 +9218,7 @@ var colors2 = {
|
|
|
8999
9218
|
dim: "\x1B[2m"
|
|
9000
9219
|
};
|
|
9001
9220
|
function createDepsUpgradeCommand() {
|
|
9002
|
-
return new
|
|
9221
|
+
return new Command36("upgrade").description("Upgrade npm packages l\xEAn version m\u1EDBi nh\u1EA5t").option("--check", "Ch\u1EC9 ki\u1EC3m tra, kh\xF4ng upgrade").option("--all", "Upgrade t\u1EA5t c\u1EA3 kh\xF4ng c\u1EA7n ch\u1ECDn").option("--deps-only", "Ch\u1EC9 upgrade dependencies").option("--dev-only", "Ch\u1EC9 upgrade devDependencies").action(async (options) => {
|
|
9003
9222
|
await handleDepsUpgrade(options);
|
|
9004
9223
|
});
|
|
9005
9224
|
}
|
|
@@ -9091,7 +9310,7 @@ ${colors2.yellow}\u23F8\uFE0F \u0110\xE3 h\u1EE7y${colors2.reset}
|
|
|
9091
9310
|
}
|
|
9092
9311
|
let shouldProceed;
|
|
9093
9312
|
try {
|
|
9094
|
-
shouldProceed = await
|
|
9313
|
+
shouldProceed = await confirm6({
|
|
9095
9314
|
message: `Ti\u1EBFn h\xE0nh upgrade ${selectedPackages.length} packages?`,
|
|
9096
9315
|
default: true
|
|
9097
9316
|
});
|
|
@@ -9179,20 +9398,20 @@ function displayUpgradeTable(packages) {
|
|
|
9179
9398
|
|
|
9180
9399
|
// src/commands/deps/index.ts
|
|
9181
9400
|
function createDepsCommand() {
|
|
9182
|
-
const depsCommand = new
|
|
9401
|
+
const depsCommand = new Command37("deps").description("Qu\u1EA3n l\xFD dependencies trong project");
|
|
9183
9402
|
depsCommand.addCommand(createDepsUpgradeCommand());
|
|
9184
9403
|
return depsCommand;
|
|
9185
9404
|
}
|
|
9186
9405
|
|
|
9187
9406
|
// src/commands/kit/index.ts
|
|
9188
|
-
import { Command as
|
|
9407
|
+
import { Command as Command41 } from "commander";
|
|
9189
9408
|
|
|
9190
9409
|
// src/commands/kit/list.ts
|
|
9191
|
-
import { Command as
|
|
9410
|
+
import { Command as Command38 } from "commander";
|
|
9192
9411
|
|
|
9193
9412
|
// src/services/starter-kit.service.ts
|
|
9194
|
-
import { promises as
|
|
9195
|
-
import { join as
|
|
9413
|
+
import { promises as fs13 } from "fs";
|
|
9414
|
+
import { join as join6 } from "path";
|
|
9196
9415
|
import AdmZip from "adm-zip";
|
|
9197
9416
|
var StarterKitService = class {
|
|
9198
9417
|
/**
|
|
@@ -9239,23 +9458,23 @@ var StarterKitService = class {
|
|
|
9239
9458
|
throw new NetworkError(`Failed to download kit: HTTP ${response.status}`);
|
|
9240
9459
|
}
|
|
9241
9460
|
if (onProgress) onProgress(30);
|
|
9242
|
-
const tmpDir =
|
|
9243
|
-
await
|
|
9244
|
-
const tmpFile =
|
|
9461
|
+
const tmpDir = join6(process.env.TMPDIR || "/tmp", "jai1-kits");
|
|
9462
|
+
await fs13.mkdir(tmpDir, { recursive: true });
|
|
9463
|
+
const tmpFile = join6(tmpDir, `${slug}.zip`);
|
|
9245
9464
|
const buffer = await response.arrayBuffer();
|
|
9246
|
-
await
|
|
9465
|
+
await fs13.writeFile(tmpFile, Buffer.from(buffer));
|
|
9247
9466
|
if (onProgress) onProgress(60);
|
|
9248
9467
|
const zip = new AdmZip(tmpFile);
|
|
9249
|
-
await
|
|
9468
|
+
await fs13.mkdir(targetDir, { recursive: true });
|
|
9250
9469
|
zip.extractAllTo(targetDir, true);
|
|
9251
9470
|
if (onProgress) onProgress(100);
|
|
9252
|
-
await
|
|
9471
|
+
await fs13.unlink(tmpFile);
|
|
9253
9472
|
}
|
|
9254
9473
|
};
|
|
9255
9474
|
|
|
9256
9475
|
// src/commands/kit/list.ts
|
|
9257
9476
|
function createKitListCommand() {
|
|
9258
|
-
return new
|
|
9477
|
+
return new Command38("list").description("List available starter kits").option("-c, --category <category>", "Filter by category (backend, frontend, fullstack)").option("-s, --search <term>", "Search kits by name or description").action(async (options) => {
|
|
9259
9478
|
const configService = new ConfigService();
|
|
9260
9479
|
const config = await configService.load();
|
|
9261
9480
|
if (!config) {
|
|
@@ -9292,9 +9511,9 @@ function createKitListCommand() {
|
|
|
9292
9511
|
}
|
|
9293
9512
|
|
|
9294
9513
|
// src/commands/kit/info.ts
|
|
9295
|
-
import { Command as
|
|
9514
|
+
import { Command as Command39 } from "commander";
|
|
9296
9515
|
function createKitInfoCommand() {
|
|
9297
|
-
return new
|
|
9516
|
+
return new Command39("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
|
|
9298
9517
|
const configService = new ConfigService();
|
|
9299
9518
|
const config = await configService.load();
|
|
9300
9519
|
if (!config) {
|
|
@@ -9343,10 +9562,10 @@ Post-Init Commands:`);
|
|
|
9343
9562
|
}
|
|
9344
9563
|
|
|
9345
9564
|
// src/commands/kit/create.ts
|
|
9346
|
-
import { Command as
|
|
9347
|
-
import { promises as
|
|
9348
|
-
import { join as
|
|
9349
|
-
import { select as
|
|
9565
|
+
import { Command as Command40 } from "commander";
|
|
9566
|
+
import { promises as fs14 } from "fs";
|
|
9567
|
+
import { join as join7 } from "path";
|
|
9568
|
+
import { select as select3, input as input2, checkbox as checkbox4 } from "@inquirer/prompts";
|
|
9350
9569
|
import { execa as execa2 } from "execa";
|
|
9351
9570
|
|
|
9352
9571
|
// src/services/hook-executor.service.ts
|
|
@@ -9388,7 +9607,7 @@ var HookExecutor = class {
|
|
|
9388
9607
|
|
|
9389
9608
|
// src/commands/kit/create.ts
|
|
9390
9609
|
function createKitCreateCommand() {
|
|
9391
|
-
return new
|
|
9610
|
+
return new Command40("create").description("Create a new project from a starter kit").argument("<slug>", "Starter kit slug").argument("[directory]", "Project directory (default: ./<slug>)").option("-y, --yes", "Auto mode - use defaults, no prompts").option("--name <name>", "Project name").option("--skip-install", "Skip dependency installation").option("--skip-git", "Skip git initialization").option("--skip-framework", "Skip framework apply").option("--skip-ide", "Skip IDE sync").action(async (slug, directory, options) => {
|
|
9392
9611
|
const configService = new ConfigService();
|
|
9393
9612
|
const config = await configService.load();
|
|
9394
9613
|
if (!config) {
|
|
@@ -9408,9 +9627,9 @@ function createKitCreateCommand() {
|
|
|
9408
9627
|
}
|
|
9409
9628
|
}
|
|
9410
9629
|
}
|
|
9411
|
-
const targetDir = directory ||
|
|
9630
|
+
const targetDir = directory || join7(process.cwd(), options.name || slug);
|
|
9412
9631
|
try {
|
|
9413
|
-
await
|
|
9632
|
+
await fs14.access(targetDir);
|
|
9414
9633
|
throw new Error(`Directory already exists: ${targetDir}`);
|
|
9415
9634
|
} catch (error) {
|
|
9416
9635
|
if (error.code !== "ENOENT") {
|
|
@@ -9444,14 +9663,14 @@ function createKitCreateCommand() {
|
|
|
9444
9663
|
console.log("\u{1F4DD} Please provide project details:");
|
|
9445
9664
|
for (const v of kit.config.variables) {
|
|
9446
9665
|
if (v.type === "select" && v.options) {
|
|
9447
|
-
const answer = await
|
|
9666
|
+
const answer = await select3({
|
|
9448
9667
|
message: v.prompt,
|
|
9449
9668
|
choices: v.options.map((opt) => ({ name: opt, value: opt })),
|
|
9450
9669
|
default: v.default
|
|
9451
9670
|
});
|
|
9452
9671
|
variables[v.name] = answer;
|
|
9453
9672
|
} else {
|
|
9454
|
-
const answer = await
|
|
9673
|
+
const answer = await input2({
|
|
9455
9674
|
message: v.prompt,
|
|
9456
9675
|
default: v.default
|
|
9457
9676
|
});
|
|
@@ -9528,7 +9747,7 @@ function createKitCreateCommand() {
|
|
|
9528
9747
|
async function applyVariableSubstitution(dir, variables) {
|
|
9529
9748
|
const files = await getAllFiles(dir);
|
|
9530
9749
|
for (const file of files) {
|
|
9531
|
-
let content = await
|
|
9750
|
+
let content = await fs14.readFile(file, "utf-8");
|
|
9532
9751
|
let modified = false;
|
|
9533
9752
|
for (const [key, value] of Object.entries(variables)) {
|
|
9534
9753
|
const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
@@ -9538,15 +9757,15 @@ async function applyVariableSubstitution(dir, variables) {
|
|
|
9538
9757
|
}
|
|
9539
9758
|
}
|
|
9540
9759
|
if (modified) {
|
|
9541
|
-
await
|
|
9760
|
+
await fs14.writeFile(file, content, "utf-8");
|
|
9542
9761
|
}
|
|
9543
9762
|
}
|
|
9544
9763
|
}
|
|
9545
9764
|
async function getAllFiles(dir) {
|
|
9546
9765
|
const files = [];
|
|
9547
|
-
const entries = await
|
|
9766
|
+
const entries = await fs14.readdir(dir, { withFileTypes: true });
|
|
9548
9767
|
for (const entry of entries) {
|
|
9549
|
-
const fullPath =
|
|
9768
|
+
const fullPath = join7(dir, entry.name);
|
|
9550
9769
|
if (entry.isDirectory()) {
|
|
9551
9770
|
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
9552
9771
|
files.push(...await getAllFiles(fullPath));
|
|
@@ -9560,7 +9779,7 @@ async function getAllFiles(dir) {
|
|
|
9560
9779
|
|
|
9561
9780
|
// src/commands/kit/index.ts
|
|
9562
9781
|
function createKitCommand() {
|
|
9563
|
-
const cmd = new
|
|
9782
|
+
const cmd = new Command41("kit").description("Manage starter kits for new projects").action(() => {
|
|
9564
9783
|
cmd.help();
|
|
9565
9784
|
});
|
|
9566
9785
|
cmd.addCommand(createKitListCommand());
|
|
@@ -9570,12 +9789,12 @@ function createKitCommand() {
|
|
|
9570
9789
|
}
|
|
9571
9790
|
|
|
9572
9791
|
// src/commands/rules/index.ts
|
|
9573
|
-
import { Command as
|
|
9792
|
+
import { Command as Command48 } from "commander";
|
|
9574
9793
|
|
|
9575
9794
|
// src/commands/rules/list.ts
|
|
9576
|
-
import { Command as
|
|
9795
|
+
import { Command as Command42 } from "commander";
|
|
9577
9796
|
function createRulesListCommand() {
|
|
9578
|
-
return new
|
|
9797
|
+
return new Command42("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
|
|
9579
9798
|
const configService = new ConfigService();
|
|
9580
9799
|
const config = await configService.load();
|
|
9581
9800
|
if (!config) {
|
|
@@ -9630,12 +9849,12 @@ function createRulesListCommand() {
|
|
|
9630
9849
|
}
|
|
9631
9850
|
|
|
9632
9851
|
// src/commands/rules/init.ts
|
|
9633
|
-
import { Command as
|
|
9634
|
-
import { promises as
|
|
9635
|
-
import { join as
|
|
9636
|
-
import { select as
|
|
9852
|
+
import { Command as Command43 } from "commander";
|
|
9853
|
+
import { promises as fs15 } from "fs";
|
|
9854
|
+
import { join as join8 } from "path";
|
|
9855
|
+
import { select as select4, confirm as confirm7 } from "@inquirer/prompts";
|
|
9637
9856
|
function createRulesInitCommand() {
|
|
9638
|
-
return new
|
|
9857
|
+
return new Command43("init").description("Apply rule preset to project").option("--preset <slug>", "Preset slug to apply").option("--output <format>", "Output format: cursor, agents-md, both (default: cursor)", "cursor").option("-y, --yes", "Skip confirmations").action(async (options) => {
|
|
9639
9858
|
const configService = new ConfigService();
|
|
9640
9859
|
const config = await configService.load();
|
|
9641
9860
|
if (!config) {
|
|
@@ -9657,7 +9876,7 @@ function createRulesInitCommand() {
|
|
|
9657
9876
|
console.log("No presets available.");
|
|
9658
9877
|
return;
|
|
9659
9878
|
}
|
|
9660
|
-
presetSlug = await
|
|
9879
|
+
presetSlug = await select4({
|
|
9661
9880
|
message: "Select a preset:",
|
|
9662
9881
|
choices: data.presets.map((p) => ({
|
|
9663
9882
|
name: `${p.name} - ${p.description}`,
|
|
@@ -9685,7 +9904,7 @@ function createRulesInitCommand() {
|
|
|
9685
9904
|
console.log(` Files: ${Object.keys(bundle.files).length}`);
|
|
9686
9905
|
let outputFormat = options.output;
|
|
9687
9906
|
if (!["cursor", "agents-md", "both"].includes(outputFormat)) {
|
|
9688
|
-
outputFormat = await
|
|
9907
|
+
outputFormat = await select4({
|
|
9689
9908
|
message: "Select output format:",
|
|
9690
9909
|
choices: [
|
|
9691
9910
|
{ name: "Cursor (.cursor/rules/)", value: "cursor" },
|
|
@@ -9695,7 +9914,7 @@ function createRulesInitCommand() {
|
|
|
9695
9914
|
});
|
|
9696
9915
|
}
|
|
9697
9916
|
if (!options.yes) {
|
|
9698
|
-
const proceed = await
|
|
9917
|
+
const proceed = await confirm7({
|
|
9699
9918
|
message: `Apply preset '${bundle.preset.name}' to current directory?`,
|
|
9700
9919
|
default: true
|
|
9701
9920
|
});
|
|
@@ -9717,7 +9936,7 @@ function createRulesInitCommand() {
|
|
|
9717
9936
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9718
9937
|
customContext: "09-custom.mdc"
|
|
9719
9938
|
};
|
|
9720
|
-
await
|
|
9939
|
+
await fs15.writeFile("jai1-rules.json", JSON.stringify(projectConfig, null, 2));
|
|
9721
9940
|
console.log("\u2713 Created jai1-rules.json");
|
|
9722
9941
|
console.log("\n\u2705 Preset applied successfully!\n");
|
|
9723
9942
|
console.log("Next steps:");
|
|
@@ -9727,11 +9946,11 @@ function createRulesInitCommand() {
|
|
|
9727
9946
|
});
|
|
9728
9947
|
}
|
|
9729
9948
|
async function applyCursorFormat(bundle) {
|
|
9730
|
-
const rulesDir =
|
|
9731
|
-
await
|
|
9949
|
+
const rulesDir = join8(process.cwd(), ".cursor", "rules");
|
|
9950
|
+
await fs15.mkdir(rulesDir, { recursive: true });
|
|
9732
9951
|
for (const [filename, content] of Object.entries(bundle.files)) {
|
|
9733
|
-
const filePath =
|
|
9734
|
-
await
|
|
9952
|
+
const filePath = join8(rulesDir, filename);
|
|
9953
|
+
await fs15.writeFile(filePath, content, "utf-8");
|
|
9735
9954
|
console.log(`\u2713 Created .cursor/rules/${filename}`);
|
|
9736
9955
|
}
|
|
9737
9956
|
}
|
|
@@ -9758,15 +9977,15 @@ async function applyAgentsMdFormat(bundle) {
|
|
|
9758
9977
|
}
|
|
9759
9978
|
}
|
|
9760
9979
|
const agentsMd = sections.join("\n");
|
|
9761
|
-
await
|
|
9980
|
+
await fs15.writeFile("AGENTS.md", agentsMd, "utf-8");
|
|
9762
9981
|
console.log("\u2713 Created AGENTS.md");
|
|
9763
9982
|
}
|
|
9764
9983
|
|
|
9765
9984
|
// src/commands/rules/apply.ts
|
|
9766
|
-
import { Command as
|
|
9767
|
-
import { promises as
|
|
9768
|
-
import { join as
|
|
9769
|
-
import { select as
|
|
9985
|
+
import { Command as Command44 } from "commander";
|
|
9986
|
+
import { promises as fs17 } from "fs";
|
|
9987
|
+
import { join as join10 } from "path";
|
|
9988
|
+
import { select as select5, confirm as confirm8, checkbox as checkbox5 } from "@inquirer/prompts";
|
|
9770
9989
|
|
|
9771
9990
|
// src/services/rules-generator.service.ts
|
|
9772
9991
|
var RulesGeneratorService = class {
|
|
@@ -10125,8 +10344,8 @@ Follow all instructions and patterns defined in AGENTS.md above.
|
|
|
10125
10344
|
};
|
|
10126
10345
|
|
|
10127
10346
|
// src/services/backup.service.ts
|
|
10128
|
-
import { promises as
|
|
10129
|
-
import { join as
|
|
10347
|
+
import { promises as fs16 } from "fs";
|
|
10348
|
+
import { join as join9, dirname } from "path";
|
|
10130
10349
|
var BackupService = class {
|
|
10131
10350
|
backupDir = ".jai1/backups";
|
|
10132
10351
|
/**
|
|
@@ -10134,7 +10353,7 @@ var BackupService = class {
|
|
|
10134
10353
|
*/
|
|
10135
10354
|
async createBackup(ides, presetSlug) {
|
|
10136
10355
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10137
|
-
const backupPath =
|
|
10356
|
+
const backupPath = join9(this.backupDir, timestamp);
|
|
10138
10357
|
const backedUpFiles = [];
|
|
10139
10358
|
let hasContent = false;
|
|
10140
10359
|
for (const ideId of ides) {
|
|
@@ -10143,7 +10362,7 @@ var BackupService = class {
|
|
|
10143
10362
|
console.warn(`Unknown IDE format: ${ideId}, skipping backup`);
|
|
10144
10363
|
continue;
|
|
10145
10364
|
}
|
|
10146
|
-
const rulesPath = format.rulesPath === "." ? process.cwd() :
|
|
10365
|
+
const rulesPath = format.rulesPath === "." ? process.cwd() : join9(process.cwd(), format.rulesPath);
|
|
10147
10366
|
try {
|
|
10148
10367
|
const exists = await this.pathExists(rulesPath);
|
|
10149
10368
|
if (!exists) {
|
|
@@ -10156,19 +10375,19 @@ var BackupService = class {
|
|
|
10156
10375
|
await this.backupSingleFile("GEMINI.md", backupPath, ideId, backedUpFiles);
|
|
10157
10376
|
hasContent = true;
|
|
10158
10377
|
} else {
|
|
10159
|
-
const stats = await
|
|
10378
|
+
const stats = await fs16.stat(rulesPath);
|
|
10160
10379
|
if (stats.isDirectory()) {
|
|
10161
|
-
const files = await
|
|
10380
|
+
const files = await fs16.readdir(rulesPath);
|
|
10162
10381
|
for (const file of files) {
|
|
10163
10382
|
if (file.endsWith(format.fileExtension)) {
|
|
10164
|
-
const originalPath =
|
|
10165
|
-
const relativePath =
|
|
10166
|
-
const destPath =
|
|
10167
|
-
await
|
|
10168
|
-
await
|
|
10383
|
+
const originalPath = join9(rulesPath, file);
|
|
10384
|
+
const relativePath = join9(format.rulesPath, file);
|
|
10385
|
+
const destPath = join9(backupPath, ideId, file);
|
|
10386
|
+
await fs16.mkdir(dirname(destPath), { recursive: true });
|
|
10387
|
+
await fs16.copyFile(originalPath, destPath);
|
|
10169
10388
|
backedUpFiles.push({
|
|
10170
10389
|
originalPath: relativePath,
|
|
10171
|
-
backupPath:
|
|
10390
|
+
backupPath: join9(ideId, file),
|
|
10172
10391
|
ide: ideId
|
|
10173
10392
|
});
|
|
10174
10393
|
hasContent = true;
|
|
@@ -10189,9 +10408,9 @@ var BackupService = class {
|
|
|
10189
10408
|
ides,
|
|
10190
10409
|
files: backedUpFiles
|
|
10191
10410
|
};
|
|
10192
|
-
await
|
|
10193
|
-
await
|
|
10194
|
-
|
|
10411
|
+
await fs16.mkdir(backupPath, { recursive: true });
|
|
10412
|
+
await fs16.writeFile(
|
|
10413
|
+
join9(backupPath, "metadata.json"),
|
|
10195
10414
|
JSON.stringify(metadata, null, 2),
|
|
10196
10415
|
"utf-8"
|
|
10197
10416
|
);
|
|
@@ -10201,18 +10420,18 @@ var BackupService = class {
|
|
|
10201
10420
|
* Backup a single file (for AGENTS.md, GEMINI.md)
|
|
10202
10421
|
*/
|
|
10203
10422
|
async backupSingleFile(filename, backupPath, ideId, backedUpFiles) {
|
|
10204
|
-
const originalPath =
|
|
10423
|
+
const originalPath = join9(process.cwd(), filename);
|
|
10205
10424
|
try {
|
|
10206
10425
|
const exists = await this.pathExists(originalPath);
|
|
10207
10426
|
if (!exists) {
|
|
10208
10427
|
return;
|
|
10209
10428
|
}
|
|
10210
|
-
const destPath =
|
|
10211
|
-
await
|
|
10212
|
-
await
|
|
10429
|
+
const destPath = join9(backupPath, ideId, filename);
|
|
10430
|
+
await fs16.mkdir(dirname(destPath), { recursive: true });
|
|
10431
|
+
await fs16.copyFile(originalPath, destPath);
|
|
10213
10432
|
backedUpFiles.push({
|
|
10214
10433
|
originalPath: filename,
|
|
10215
|
-
backupPath:
|
|
10434
|
+
backupPath: join9(ideId, filename),
|
|
10216
10435
|
ide: ideId
|
|
10217
10436
|
});
|
|
10218
10437
|
} catch (error) {
|
|
@@ -10222,16 +10441,16 @@ var BackupService = class {
|
|
|
10222
10441
|
* Restore files from a backup
|
|
10223
10442
|
*/
|
|
10224
10443
|
async restoreBackup(backupPath) {
|
|
10225
|
-
const metadataPath =
|
|
10226
|
-
const metadataContent = await
|
|
10444
|
+
const metadataPath = join9(backupPath, "metadata.json");
|
|
10445
|
+
const metadataContent = await fs16.readFile(metadataPath, "utf-8");
|
|
10227
10446
|
const metadata = JSON.parse(metadataContent);
|
|
10228
10447
|
console.log(`
|
|
10229
10448
|
Restoring backup from ${metadata.timestamp}...`);
|
|
10230
10449
|
for (const file of metadata.files) {
|
|
10231
|
-
const sourcePath =
|
|
10232
|
-
const destPath =
|
|
10233
|
-
await
|
|
10234
|
-
await
|
|
10450
|
+
const sourcePath = join9(backupPath, file.backupPath);
|
|
10451
|
+
const destPath = join9(process.cwd(), file.originalPath);
|
|
10452
|
+
await fs16.mkdir(dirname(destPath), { recursive: true });
|
|
10453
|
+
await fs16.copyFile(sourcePath, destPath);
|
|
10235
10454
|
console.log(`\u2713 Restored ${file.originalPath}`);
|
|
10236
10455
|
}
|
|
10237
10456
|
console.log("\n\u2705 Backup restored successfully!");
|
|
@@ -10241,18 +10460,18 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10241
10460
|
*/
|
|
10242
10461
|
async listBackups() {
|
|
10243
10462
|
try {
|
|
10244
|
-
const backupDirPath =
|
|
10463
|
+
const backupDirPath = join9(process.cwd(), this.backupDir);
|
|
10245
10464
|
const exists = await this.pathExists(backupDirPath);
|
|
10246
10465
|
if (!exists) {
|
|
10247
10466
|
return [];
|
|
10248
10467
|
}
|
|
10249
|
-
const entries = await
|
|
10468
|
+
const entries = await fs16.readdir(backupDirPath, { withFileTypes: true });
|
|
10250
10469
|
const backups = [];
|
|
10251
10470
|
for (const entry of entries) {
|
|
10252
10471
|
if (entry.isDirectory()) {
|
|
10253
|
-
const metadataPath =
|
|
10472
|
+
const metadataPath = join9(backupDirPath, entry.name, "metadata.json");
|
|
10254
10473
|
try {
|
|
10255
|
-
const metadataContent = await
|
|
10474
|
+
const metadataContent = await fs16.readFile(metadataPath, "utf-8");
|
|
10256
10475
|
const metadata = JSON.parse(metadataContent);
|
|
10257
10476
|
backups.push(metadata);
|
|
10258
10477
|
} catch {
|
|
@@ -10269,7 +10488,7 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10269
10488
|
* Delete a specific backup
|
|
10270
10489
|
*/
|
|
10271
10490
|
async deleteBackup(timestamp) {
|
|
10272
|
-
const backupPath =
|
|
10491
|
+
const backupPath = join9(process.cwd(), this.backupDir, timestamp);
|
|
10273
10492
|
await this.deleteDirectory(backupPath);
|
|
10274
10493
|
}
|
|
10275
10494
|
/**
|
|
@@ -10301,7 +10520,7 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10301
10520
|
*/
|
|
10302
10521
|
async pathExists(path9) {
|
|
10303
10522
|
try {
|
|
10304
|
-
await
|
|
10523
|
+
await fs16.access(path9);
|
|
10305
10524
|
return true;
|
|
10306
10525
|
} catch {
|
|
10307
10526
|
return false;
|
|
@@ -10316,16 +10535,16 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10316
10535
|
if (!exists) {
|
|
10317
10536
|
return;
|
|
10318
10537
|
}
|
|
10319
|
-
const entries = await
|
|
10538
|
+
const entries = await fs16.readdir(path9, { withFileTypes: true });
|
|
10320
10539
|
for (const entry of entries) {
|
|
10321
|
-
const fullPath =
|
|
10540
|
+
const fullPath = join9(path9, entry.name);
|
|
10322
10541
|
if (entry.isDirectory()) {
|
|
10323
10542
|
await this.deleteDirectory(fullPath);
|
|
10324
10543
|
} else {
|
|
10325
|
-
await
|
|
10544
|
+
await fs16.unlink(fullPath);
|
|
10326
10545
|
}
|
|
10327
10546
|
}
|
|
10328
|
-
await
|
|
10547
|
+
await fs16.rmdir(path9);
|
|
10329
10548
|
} catch (error) {
|
|
10330
10549
|
}
|
|
10331
10550
|
}
|
|
@@ -10333,20 +10552,20 @@ Restoring backup from ${metadata.timestamp}...`);
|
|
|
10333
10552
|
* Get backup directory path
|
|
10334
10553
|
*/
|
|
10335
10554
|
getBackupDir() {
|
|
10336
|
-
return
|
|
10555
|
+
return join9(process.cwd(), this.backupDir);
|
|
10337
10556
|
}
|
|
10338
10557
|
/**
|
|
10339
10558
|
* Ensure backup directory exists
|
|
10340
10559
|
*/
|
|
10341
10560
|
async ensureBackupDir() {
|
|
10342
|
-
const backupDirPath =
|
|
10343
|
-
await
|
|
10561
|
+
const backupDirPath = join9(process.cwd(), this.backupDir);
|
|
10562
|
+
await fs16.mkdir(backupDirPath, { recursive: true });
|
|
10344
10563
|
}
|
|
10345
10564
|
};
|
|
10346
10565
|
|
|
10347
10566
|
// src/commands/rules/apply.ts
|
|
10348
10567
|
function createRulesApplyCommand() {
|
|
10349
|
-
return new
|
|
10568
|
+
return new Command44("apply").description("Apply rule preset to project with multi-IDE support").argument("[preset]", "Preset slug to apply (optional)").option("--ides <ides>", "Comma-separated list of IDE formats (cursor,windsurf,antigravity,claude,agentsmd,gemini)").option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
|
|
10350
10569
|
const configService = new ConfigService();
|
|
10351
10570
|
const config = await configService.load();
|
|
10352
10571
|
if (!config) {
|
|
@@ -10378,7 +10597,7 @@ function createRulesApplyCommand() {
|
|
|
10378
10597
|
console.log("No presets available.");
|
|
10379
10598
|
return;
|
|
10380
10599
|
}
|
|
10381
|
-
presetSlug = await
|
|
10600
|
+
presetSlug = await select5({
|
|
10382
10601
|
message: "Select a preset:",
|
|
10383
10602
|
choices: data.presets.map((p) => ({
|
|
10384
10603
|
name: `${p.name} - ${p.description}`,
|
|
@@ -10486,7 +10705,7 @@ function createRulesApplyCommand() {
|
|
|
10486
10705
|
if (backupPath) {
|
|
10487
10706
|
console.log(` Backup: ${backupPath}`);
|
|
10488
10707
|
}
|
|
10489
|
-
const proceed = await
|
|
10708
|
+
const proceed = await confirm8({
|
|
10490
10709
|
message: "Apply these rules to the current directory?",
|
|
10491
10710
|
default: true
|
|
10492
10711
|
});
|
|
@@ -10496,21 +10715,21 @@ function createRulesApplyCommand() {
|
|
|
10496
10715
|
}
|
|
10497
10716
|
}
|
|
10498
10717
|
console.log("\n\u{1F4DD} Applying preset...\n");
|
|
10499
|
-
const rulePresetDir =
|
|
10718
|
+
const rulePresetDir = join10(process.cwd(), ".jai1", "rule-preset");
|
|
10500
10719
|
try {
|
|
10501
|
-
await
|
|
10720
|
+
await fs17.rm(rulePresetDir, { recursive: true, force: true });
|
|
10502
10721
|
} catch {
|
|
10503
10722
|
}
|
|
10504
|
-
await
|
|
10505
|
-
await
|
|
10506
|
-
|
|
10723
|
+
await fs17.mkdir(rulePresetDir, { recursive: true });
|
|
10724
|
+
await fs17.writeFile(
|
|
10725
|
+
join10(rulePresetDir, "preset.json"),
|
|
10507
10726
|
JSON.stringify(bundle.preset, null, 2),
|
|
10508
10727
|
"utf-8"
|
|
10509
10728
|
);
|
|
10510
10729
|
for (const [filename, content] of Object.entries(bundle.files)) {
|
|
10511
|
-
const filePath =
|
|
10512
|
-
await
|
|
10513
|
-
await
|
|
10730
|
+
const filePath = join10(rulePresetDir, filename);
|
|
10731
|
+
await fs17.mkdir(join10(filePath, ".."), { recursive: true });
|
|
10732
|
+
await fs17.writeFile(filePath, content, "utf-8");
|
|
10514
10733
|
}
|
|
10515
10734
|
console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
|
|
10516
10735
|
const allGeneratedFiles = [];
|
|
@@ -10518,9 +10737,9 @@ function createRulesApplyCommand() {
|
|
|
10518
10737
|
try {
|
|
10519
10738
|
const files = generatorService.generateForIde(bundle, ideId);
|
|
10520
10739
|
for (const file of files) {
|
|
10521
|
-
const fullPath =
|
|
10522
|
-
await
|
|
10523
|
-
await
|
|
10740
|
+
const fullPath = join10(process.cwd(), file.path);
|
|
10741
|
+
await fs17.mkdir(join10(fullPath, ".."), { recursive: true });
|
|
10742
|
+
await fs17.writeFile(fullPath, file.content, "utf-8");
|
|
10524
10743
|
console.log(`\u2713 [${ideId}] ${file.path}`);
|
|
10525
10744
|
allGeneratedFiles.push({
|
|
10526
10745
|
ide: ideId,
|
|
@@ -10547,8 +10766,8 @@ function createRulesApplyCommand() {
|
|
|
10547
10766
|
] : []
|
|
10548
10767
|
};
|
|
10549
10768
|
try {
|
|
10550
|
-
const existingConfigPath =
|
|
10551
|
-
const existingConfigContent = await
|
|
10769
|
+
const existingConfigPath = join10(process.cwd(), "jai1-rules.json");
|
|
10770
|
+
const existingConfigContent = await fs17.readFile(existingConfigPath, "utf-8");
|
|
10552
10771
|
const existingConfig = JSON.parse(existingConfigContent);
|
|
10553
10772
|
if (existingConfig.backups && existingConfig.backups.length > 0) {
|
|
10554
10773
|
projectConfig.backups = [
|
|
@@ -10559,8 +10778,8 @@ function createRulesApplyCommand() {
|
|
|
10559
10778
|
}
|
|
10560
10779
|
} catch {
|
|
10561
10780
|
}
|
|
10562
|
-
await
|
|
10563
|
-
|
|
10781
|
+
await fs17.writeFile(
|
|
10782
|
+
join10(process.cwd(), "jai1-rules.json"),
|
|
10564
10783
|
JSON.stringify(projectConfig, null, 2),
|
|
10565
10784
|
"utf-8"
|
|
10566
10785
|
);
|
|
@@ -10591,11 +10810,11 @@ function createRulesApplyCommand() {
|
|
|
10591
10810
|
}
|
|
10592
10811
|
|
|
10593
10812
|
// src/commands/rules/restore.ts
|
|
10594
|
-
import { Command as
|
|
10595
|
-
import { join as
|
|
10596
|
-
import { select as
|
|
10813
|
+
import { Command as Command45 } from "commander";
|
|
10814
|
+
import { join as join11 } from "path";
|
|
10815
|
+
import { select as select6, confirm as confirm9 } from "@inquirer/prompts";
|
|
10597
10816
|
function createRulesRestoreCommand() {
|
|
10598
|
-
return new
|
|
10817
|
+
return new Command45("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
10599
10818
|
const backupService = new BackupService();
|
|
10600
10819
|
const backups = await backupService.listBackups();
|
|
10601
10820
|
if (backups.length === 0) {
|
|
@@ -10608,7 +10827,7 @@ function createRulesRestoreCommand() {
|
|
|
10608
10827
|
console.log(`\u{1F4E6} Selected latest backup: ${selectedBackup.timestamp}`);
|
|
10609
10828
|
} else {
|
|
10610
10829
|
console.log("\u{1F4CB} Available backups:\n");
|
|
10611
|
-
const backupTimestamp = await
|
|
10830
|
+
const backupTimestamp = await select6({
|
|
10612
10831
|
message: "Select a backup to restore:",
|
|
10613
10832
|
choices: backups.map((backup) => ({
|
|
10614
10833
|
name: formatBackupInfo(backup),
|
|
@@ -10627,7 +10846,7 @@ function createRulesRestoreCommand() {
|
|
|
10627
10846
|
console.log(` IDEs: ${selectedBackup.ides.join(", ")}`);
|
|
10628
10847
|
console.log(` Files: ${selectedBackup.files.length}`);
|
|
10629
10848
|
if (!options.yes) {
|
|
10630
|
-
const proceed = await
|
|
10849
|
+
const proceed = await confirm9({
|
|
10631
10850
|
message: "This will overwrite current rules. Continue?",
|
|
10632
10851
|
default: false
|
|
10633
10852
|
});
|
|
@@ -10638,7 +10857,7 @@ function createRulesRestoreCommand() {
|
|
|
10638
10857
|
}
|
|
10639
10858
|
console.log("\n\u{1F504} Restoring backup...\n");
|
|
10640
10859
|
try {
|
|
10641
|
-
const backupPath =
|
|
10860
|
+
const backupPath = join11(backupService.getBackupDir(), selectedBackup.timestamp);
|
|
10642
10861
|
await backupService.restoreBackup(backupPath);
|
|
10643
10862
|
console.log("\n\u2705 Backup restored successfully!\n");
|
|
10644
10863
|
console.log("\u{1F4A1} Tip: Your IDE may need to be restarted to pick up the changes.");
|
|
@@ -10663,16 +10882,16 @@ function formatTimestamp(timestamp) {
|
|
|
10663
10882
|
}
|
|
10664
10883
|
|
|
10665
10884
|
// src/commands/rules/sync.ts
|
|
10666
|
-
import { Command as
|
|
10667
|
-
import { promises as
|
|
10668
|
-
import { join as
|
|
10669
|
-
import { confirm as
|
|
10885
|
+
import { Command as Command46 } from "commander";
|
|
10886
|
+
import { promises as fs18 } from "fs";
|
|
10887
|
+
import { join as join12 } from "path";
|
|
10888
|
+
import { confirm as confirm10 } from "@inquirer/prompts";
|
|
10670
10889
|
function createRulesSyncCommand() {
|
|
10671
|
-
return new
|
|
10672
|
-
const configPath =
|
|
10890
|
+
return new Command46("sync").description("Regenerate rule outputs for all configured IDEs").option("--ides <ides>", "Comma-separated list of IDEs to sync (default: all configured)").option("--detect", "Auto-detect active IDEs instead of using config").option("-y, --yes", "Skip confirmations").action(async (options) => {
|
|
10891
|
+
const configPath = join12(process.cwd(), "jai1-rules.json");
|
|
10673
10892
|
let projectConfig;
|
|
10674
10893
|
try {
|
|
10675
|
-
const configContent = await
|
|
10894
|
+
const configContent = await fs18.readFile(configPath, "utf-8");
|
|
10676
10895
|
projectConfig = JSON.parse(configContent);
|
|
10677
10896
|
} catch {
|
|
10678
10897
|
throw new ValidationError(
|
|
@@ -10699,7 +10918,7 @@ Detected ${detected.length} active IDE(s):
|
|
|
10699
10918
|
console.log(` ${confidence} ${d.name} - ${d.ruleCount} rules`);
|
|
10700
10919
|
});
|
|
10701
10920
|
if (!options.yes) {
|
|
10702
|
-
const proceed = await
|
|
10921
|
+
const proceed = await confirm10({
|
|
10703
10922
|
message: "\nSync these detected IDEs?",
|
|
10704
10923
|
default: true
|
|
10705
10924
|
});
|
|
@@ -10752,14 +10971,14 @@ Detected ${detected.length} active IDE(s):
|
|
|
10752
10971
|
throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
|
|
10753
10972
|
}
|
|
10754
10973
|
const bundle = await presetResponse.json();
|
|
10755
|
-
const rulePresetDir =
|
|
10974
|
+
const rulePresetDir = join12(process.cwd(), ".jai1", "rule-preset");
|
|
10756
10975
|
const presetExists = await checkPathExists(rulePresetDir);
|
|
10757
10976
|
if (presetExists) {
|
|
10758
|
-
const files = await
|
|
10977
|
+
const files = await fs18.readdir(rulePresetDir);
|
|
10759
10978
|
for (const file of files) {
|
|
10760
10979
|
if (file.endsWith(".mdc")) {
|
|
10761
|
-
const filePath =
|
|
10762
|
-
const content = await
|
|
10980
|
+
const filePath = join12(rulePresetDir, file);
|
|
10981
|
+
const content = await fs18.readFile(filePath, "utf-8");
|
|
10763
10982
|
bundle.files[file] = content;
|
|
10764
10983
|
}
|
|
10765
10984
|
}
|
|
@@ -10778,9 +10997,9 @@ Detected ${detected.length} active IDE(s):
|
|
|
10778
10997
|
}
|
|
10779
10998
|
const files = generatorService.generateForIde(bundle, ideId);
|
|
10780
10999
|
for (const file of files) {
|
|
10781
|
-
const fullPath =
|
|
10782
|
-
await
|
|
10783
|
-
await
|
|
11000
|
+
const fullPath = join12(process.cwd(), file.path);
|
|
11001
|
+
await fs18.mkdir(join12(fullPath, ".."), { recursive: true });
|
|
11002
|
+
await fs18.writeFile(fullPath, file.content, "utf-8");
|
|
10784
11003
|
}
|
|
10785
11004
|
console.log(`\u2713 ${format.name} - ${files.length} files regenerated`);
|
|
10786
11005
|
} catch (error) {
|
|
@@ -10789,8 +11008,8 @@ Detected ${detected.length} active IDE(s):
|
|
|
10789
11008
|
}
|
|
10790
11009
|
if (JSON.stringify(projectConfig.ides) !== JSON.stringify(idesToSync)) {
|
|
10791
11010
|
projectConfig.ides = idesToSync;
|
|
10792
|
-
await
|
|
10793
|
-
|
|
11011
|
+
await fs18.writeFile(
|
|
11012
|
+
join12(process.cwd(), "jai1-rules.json"),
|
|
10794
11013
|
JSON.stringify(projectConfig, null, 2),
|
|
10795
11014
|
"utf-8"
|
|
10796
11015
|
);
|
|
@@ -10805,7 +11024,7 @@ Detected ${detected.length} active IDE(s):
|
|
|
10805
11024
|
}
|
|
10806
11025
|
async function checkPathExists(absolutePath) {
|
|
10807
11026
|
try {
|
|
10808
|
-
await
|
|
11027
|
+
await fs18.access(absolutePath);
|
|
10809
11028
|
return true;
|
|
10810
11029
|
} catch {
|
|
10811
11030
|
return false;
|
|
@@ -10813,15 +11032,15 @@ async function checkPathExists(absolutePath) {
|
|
|
10813
11032
|
}
|
|
10814
11033
|
|
|
10815
11034
|
// src/commands/rules/info.ts
|
|
10816
|
-
import { Command as
|
|
10817
|
-
import { promises as
|
|
10818
|
-
import { join as
|
|
11035
|
+
import { Command as Command47 } from "commander";
|
|
11036
|
+
import { promises as fs19 } from "fs";
|
|
11037
|
+
import { join as join13 } from "path";
|
|
10819
11038
|
function createRulesInfoCommand() {
|
|
10820
|
-
return new
|
|
10821
|
-
const configPath =
|
|
11039
|
+
return new Command47("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
|
|
11040
|
+
const configPath = join13(process.cwd(), "jai1-rules.json");
|
|
10822
11041
|
let projectConfig;
|
|
10823
11042
|
try {
|
|
10824
|
-
const configContent = await
|
|
11043
|
+
const configContent = await fs19.readFile(configPath, "utf-8");
|
|
10825
11044
|
projectConfig = JSON.parse(configContent);
|
|
10826
11045
|
} catch {
|
|
10827
11046
|
throw new ValidationError(
|
|
@@ -10833,14 +11052,14 @@ function createRulesInfoCommand() {
|
|
|
10833
11052
|
return;
|
|
10834
11053
|
}
|
|
10835
11054
|
console.log("\u{1F4CB} Current Preset Information\n");
|
|
10836
|
-
const rulePresetDir =
|
|
10837
|
-
const presetJsonPath =
|
|
11055
|
+
const rulePresetDir = join13(process.cwd(), ".jai1", "rule-preset");
|
|
11056
|
+
const presetJsonPath = join13(rulePresetDir, "preset.json");
|
|
10838
11057
|
let presetMetadata = null;
|
|
10839
11058
|
let presetFiles = [];
|
|
10840
11059
|
try {
|
|
10841
|
-
const presetContent = await
|
|
11060
|
+
const presetContent = await fs19.readFile(presetJsonPath, "utf-8");
|
|
10842
11061
|
presetMetadata = JSON.parse(presetContent);
|
|
10843
|
-
const files = await
|
|
11062
|
+
const files = await fs19.readdir(rulePresetDir);
|
|
10844
11063
|
presetFiles = files.filter((f) => f.endsWith(".mdc"));
|
|
10845
11064
|
} catch {
|
|
10846
11065
|
}
|
|
@@ -10901,7 +11120,7 @@ Available Backups (${projectConfig.backups.length}):`);
|
|
|
10901
11120
|
}
|
|
10902
11121
|
async function checkPathExists2(path9) {
|
|
10903
11122
|
try {
|
|
10904
|
-
await
|
|
11123
|
+
await fs19.access(join13(process.cwd(), path9));
|
|
10905
11124
|
return true;
|
|
10906
11125
|
} catch {
|
|
10907
11126
|
return false;
|
|
@@ -10923,7 +11142,7 @@ async function checkIdeFilesExist(ideId, format) {
|
|
|
10923
11142
|
|
|
10924
11143
|
// src/commands/rules/index.ts
|
|
10925
11144
|
function createRulesCommand() {
|
|
10926
|
-
const rulesCommand = new
|
|
11145
|
+
const rulesCommand = new Command48("rules").description("Manage rule presets for AI agents");
|
|
10927
11146
|
rulesCommand.addCommand(createRulesListCommand());
|
|
10928
11147
|
rulesCommand.addCommand(createRulesInitCommand());
|
|
10929
11148
|
rulesCommand.addCommand(createRulesApplyCommand());
|
|
@@ -10934,8 +11153,8 @@ function createRulesCommand() {
|
|
|
10934
11153
|
}
|
|
10935
11154
|
|
|
10936
11155
|
// src/commands/upgrade.ts
|
|
10937
|
-
import { Command as
|
|
10938
|
-
import { confirm as
|
|
11156
|
+
import { Command as Command49 } from "commander";
|
|
11157
|
+
import { confirm as confirm11 } from "@inquirer/prompts";
|
|
10939
11158
|
import { execSync as execSync2 } from "child_process";
|
|
10940
11159
|
var colors3 = {
|
|
10941
11160
|
yellow: "\x1B[33m",
|
|
@@ -10946,7 +11165,7 @@ var colors3 = {
|
|
|
10946
11165
|
bold: "\x1B[1m"
|
|
10947
11166
|
};
|
|
10948
11167
|
function createUpgradeCommand() {
|
|
10949
|
-
return new
|
|
11168
|
+
return new Command49("upgrade").description("Upgrade jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force upgrade without confirmation").action(async (options) => {
|
|
10950
11169
|
await handleUpgrade(options);
|
|
10951
11170
|
});
|
|
10952
11171
|
}
|
|
@@ -10990,7 +11209,7 @@ ${colors3.bold}Current version:${colors3.reset} ${currentVersion}`);
|
|
|
10990
11209
|
return;
|
|
10991
11210
|
}
|
|
10992
11211
|
if (!options.force) {
|
|
10993
|
-
const shouldUpdate = await
|
|
11212
|
+
const shouldUpdate = await confirm11({
|
|
10994
11213
|
message: "Update to the latest version now?",
|
|
10995
11214
|
default: true
|
|
10996
11215
|
});
|
|
@@ -11094,11 +11313,11 @@ function getInstallCommand(packageManager2) {
|
|
|
11094
11313
|
}
|
|
11095
11314
|
|
|
11096
11315
|
// src/commands/clean.ts
|
|
11097
|
-
import { Command as
|
|
11098
|
-
import { confirm as
|
|
11099
|
-
import { join as
|
|
11316
|
+
import { Command as Command50 } from "commander";
|
|
11317
|
+
import { confirm as confirm12, select as select7 } from "@inquirer/prompts";
|
|
11318
|
+
import { join as join14 } from "path";
|
|
11100
11319
|
function createCleanCommand() {
|
|
11101
|
-
return new
|
|
11320
|
+
return new Command50("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
|
|
11102
11321
|
await handleClean(options);
|
|
11103
11322
|
});
|
|
11104
11323
|
}
|
|
@@ -11109,7 +11328,7 @@ async function handleClean(options) {
|
|
|
11109
11328
|
{
|
|
11110
11329
|
name: "Backups",
|
|
11111
11330
|
description: "Component backup files (.jai1_backup/)",
|
|
11112
|
-
path:
|
|
11331
|
+
path: join14(cwd, ".jai1_backup"),
|
|
11113
11332
|
check: async () => {
|
|
11114
11333
|
const backups = await service.listBackups(cwd);
|
|
11115
11334
|
return { exists: backups.length > 0, count: backups.length };
|
|
@@ -11159,7 +11378,7 @@ async function handleClean(options) {
|
|
|
11159
11378
|
console.log(` Path: ${target.path}
|
|
11160
11379
|
`);
|
|
11161
11380
|
}
|
|
11162
|
-
const action = await
|
|
11381
|
+
const action = await select7({
|
|
11163
11382
|
message: "What do you want to clean?",
|
|
11164
11383
|
choices: [
|
|
11165
11384
|
...availableTargets.map(({ target, info }) => ({
|
|
@@ -11193,7 +11412,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
11193
11412
|
}
|
|
11194
11413
|
const countStr = info.count ? ` (${info.count} items)` : "";
|
|
11195
11414
|
if (!skipConfirm) {
|
|
11196
|
-
const confirmed = await
|
|
11415
|
+
const confirmed = await confirm12({
|
|
11197
11416
|
message: `Delete ${target.name}${countStr}?`,
|
|
11198
11417
|
default: false
|
|
11199
11418
|
});
|
|
@@ -11211,7 +11430,7 @@ async function cleanTarget(target, skipConfirm) {
|
|
|
11211
11430
|
}
|
|
11212
11431
|
|
|
11213
11432
|
// src/commands/redmine/check.ts
|
|
11214
|
-
import { Command as
|
|
11433
|
+
import { Command as Command51 } from "commander";
|
|
11215
11434
|
|
|
11216
11435
|
// src/services/redmine-config.service.ts
|
|
11217
11436
|
import { readFile as readFile6 } from "fs/promises";
|
|
@@ -11518,7 +11737,7 @@ async function checkConnectivity(config) {
|
|
|
11518
11737
|
|
|
11519
11738
|
// src/commands/redmine/check.ts
|
|
11520
11739
|
function createRedmineCheckCommand() {
|
|
11521
|
-
const cmd = new
|
|
11740
|
+
const cmd = new Command51("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
|
|
11522
11741
|
await handleRedmineCheck(options);
|
|
11523
11742
|
});
|
|
11524
11743
|
return cmd;
|
|
@@ -11546,7 +11765,7 @@ async function handleRedmineCheck(options) {
|
|
|
11546
11765
|
}
|
|
11547
11766
|
|
|
11548
11767
|
// src/commands/redmine/sync-issue.ts
|
|
11549
|
-
import { Command as
|
|
11768
|
+
import { Command as Command52 } from "commander";
|
|
11550
11769
|
|
|
11551
11770
|
// src/sync-issue.ts
|
|
11552
11771
|
import { resolve as resolve3, relative } from "path";
|
|
@@ -11930,7 +12149,7 @@ function extractIssueIdFromUrl(url) {
|
|
|
11930
12149
|
|
|
11931
12150
|
// src/commands/redmine/sync-issue.ts
|
|
11932
12151
|
function createSyncIssueCommand() {
|
|
11933
|
-
const cmd = new
|
|
12152
|
+
const cmd = new Command52("issue").description("Sync a single issue").option("-i, --id <number>", "Issue ID").option("-u, --url <url>", "Issue URL").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
|
|
11934
12153
|
await handleSyncIssue(options);
|
|
11935
12154
|
});
|
|
11936
12155
|
return cmd;
|
|
@@ -11974,7 +12193,7 @@ async function handleSyncIssue(options) {
|
|
|
11974
12193
|
}
|
|
11975
12194
|
|
|
11976
12195
|
// src/commands/redmine/sync-project.ts
|
|
11977
|
-
import { Command as
|
|
12196
|
+
import { Command as Command53 } from "commander";
|
|
11978
12197
|
|
|
11979
12198
|
// src/sync-project.ts
|
|
11980
12199
|
async function syncProject(config, options = {}) {
|
|
@@ -12044,7 +12263,7 @@ async function syncProject(config, options = {}) {
|
|
|
12044
12263
|
|
|
12045
12264
|
// src/commands/redmine/sync-project.ts
|
|
12046
12265
|
function createSyncProjectCommand() {
|
|
12047
|
-
const cmd = new
|
|
12266
|
+
const cmd = new Command53("project").description("Sync all issues in a project").option("-s, --status <status>", "Filter by status (default: *)", "*").option("--updated-since <date>", "Only sync issues updated since YYYY-MM-DD").option("--concurrency <number>", "Number of concurrent requests").option("--page-size <number>", "Page size for API requests").option("--dry-run", "Preview without making changes").option("-c, --config <path>", "Config file path").option("-o, --output-dir <path>", "Output directory").option("--json", "Output as JSON").action(async (options) => {
|
|
12048
12267
|
await handleSyncProject(options);
|
|
12049
12268
|
});
|
|
12050
12269
|
return cmd;
|
|
@@ -12099,12 +12318,12 @@ async function handleSyncProject(options) {
|
|
|
12099
12318
|
}
|
|
12100
12319
|
|
|
12101
12320
|
// src/commands/framework/info.ts
|
|
12102
|
-
import { Command as
|
|
12103
|
-
import { promises as
|
|
12104
|
-
import { join as
|
|
12321
|
+
import { Command as Command54 } from "commander";
|
|
12322
|
+
import { promises as fs20 } from "fs";
|
|
12323
|
+
import { join as join15 } from "path";
|
|
12105
12324
|
import { homedir as homedir5 } from "os";
|
|
12106
12325
|
function createInfoCommand() {
|
|
12107
|
-
const cmd = new
|
|
12326
|
+
const cmd = new Command54("info").description("Show jai1-client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
|
|
12108
12327
|
await handleInfo(options);
|
|
12109
12328
|
});
|
|
12110
12329
|
return cmd;
|
|
@@ -12115,7 +12334,7 @@ async function handleInfo(options) {
|
|
|
12115
12334
|
if (!config) {
|
|
12116
12335
|
throw new ValidationError('Not initialized. Run "jai1 auth" first.');
|
|
12117
12336
|
}
|
|
12118
|
-
const frameworkPath =
|
|
12337
|
+
const frameworkPath = join15(homedir5(), ".jai1", "framework");
|
|
12119
12338
|
const projectStatus = await getProjectStatus2();
|
|
12120
12339
|
const info = {
|
|
12121
12340
|
configPath: configService.getConfigPath(),
|
|
@@ -12150,9 +12369,9 @@ function maskKey3(key) {
|
|
|
12150
12369
|
return "****" + key.slice(-4);
|
|
12151
12370
|
}
|
|
12152
12371
|
async function getProjectStatus2() {
|
|
12153
|
-
const projectJai1 =
|
|
12372
|
+
const projectJai1 = join15(process.cwd(), ".jai1");
|
|
12154
12373
|
try {
|
|
12155
|
-
await
|
|
12374
|
+
await fs20.access(projectJai1);
|
|
12156
12375
|
return { exists: true, version: "Synced" };
|
|
12157
12376
|
} catch {
|
|
12158
12377
|
return { exists: false };
|
|
@@ -12160,8 +12379,8 @@ async function getProjectStatus2() {
|
|
|
12160
12379
|
}
|
|
12161
12380
|
|
|
12162
12381
|
// src/commands/self-update.ts
|
|
12163
|
-
import { Command as
|
|
12164
|
-
import { confirm as
|
|
12382
|
+
import { Command as Command55 } from "commander";
|
|
12383
|
+
import { confirm as confirm13 } from "@inquirer/prompts";
|
|
12165
12384
|
import { execSync as execSync3 } from "child_process";
|
|
12166
12385
|
var colors4 = {
|
|
12167
12386
|
yellow: "\x1B[33m",
|
|
@@ -12172,7 +12391,7 @@ var colors4 = {
|
|
|
12172
12391
|
bold: "\x1B[1m"
|
|
12173
12392
|
};
|
|
12174
12393
|
function createSelfUpdateCommand() {
|
|
12175
|
-
return new
|
|
12394
|
+
return new Command55("self-update").description("Update jai1-client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
|
|
12176
12395
|
await handleSelfUpdate(options);
|
|
12177
12396
|
});
|
|
12178
12397
|
}
|
|
@@ -12216,7 +12435,7 @@ ${colors4.bold}Current version:${colors4.reset} ${currentVersion}`);
|
|
|
12216
12435
|
return;
|
|
12217
12436
|
}
|
|
12218
12437
|
if (!options.force) {
|
|
12219
|
-
const shouldUpdate = await
|
|
12438
|
+
const shouldUpdate = await confirm13({
|
|
12220
12439
|
message: "Update to the latest version now?",
|
|
12221
12440
|
default: true
|
|
12222
12441
|
});
|
|
@@ -12312,10 +12531,10 @@ function getInstallCommand2(packageManager2) {
|
|
|
12312
12531
|
}
|
|
12313
12532
|
|
|
12314
12533
|
// src/commands/clear-backups.ts
|
|
12315
|
-
import { Command as
|
|
12316
|
-
import { confirm as
|
|
12534
|
+
import { Command as Command56 } from "commander";
|
|
12535
|
+
import { confirm as confirm14 } from "@inquirer/prompts";
|
|
12317
12536
|
function createClearBackupsCommand() {
|
|
12318
|
-
return new
|
|
12537
|
+
return new Command56("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
|
|
12319
12538
|
const service = new ComponentsService();
|
|
12320
12539
|
const backups = await service.listBackups(process.cwd());
|
|
12321
12540
|
if (backups.length === 0) {
|
|
@@ -12331,7 +12550,7 @@ function createClearBackupsCommand() {
|
|
|
12331
12550
|
}
|
|
12332
12551
|
console.log();
|
|
12333
12552
|
if (!options.yes) {
|
|
12334
|
-
const ok = await
|
|
12553
|
+
const ok = await confirm14({ message: "Delete all backups?", default: false });
|
|
12335
12554
|
if (!ok) return;
|
|
12336
12555
|
}
|
|
12337
12556
|
await service.clearBackups(process.cwd());
|
|
@@ -12340,9 +12559,9 @@ function createClearBackupsCommand() {
|
|
|
12340
12559
|
}
|
|
12341
12560
|
|
|
12342
12561
|
// src/commands/vscode/index.ts
|
|
12343
|
-
import { Command as
|
|
12344
|
-
import { checkbox as checkbox7, confirm as
|
|
12345
|
-
import
|
|
12562
|
+
import { Command as Command57 } from "commander";
|
|
12563
|
+
import { checkbox as checkbox7, confirm as confirm15, select as select8 } from "@inquirer/prompts";
|
|
12564
|
+
import fs21 from "fs/promises";
|
|
12346
12565
|
import path8 from "path";
|
|
12347
12566
|
import { existsSync as existsSync3 } from "fs";
|
|
12348
12567
|
var PERFORMANCE_GROUPS2 = {
|
|
@@ -12480,7 +12699,7 @@ var PERFORMANCE_GROUPS2 = {
|
|
|
12480
12699
|
}
|
|
12481
12700
|
};
|
|
12482
12701
|
function createVSCodeCommand() {
|
|
12483
|
-
const vscodeCommand = new
|
|
12702
|
+
const vscodeCommand = new Command57("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
|
|
12484
12703
|
vscodeCommand.action(async () => {
|
|
12485
12704
|
await interactiveMode2();
|
|
12486
12705
|
});
|
|
@@ -12524,7 +12743,7 @@ async function interactiveMode2() {
|
|
|
12524
12743
|
console.log("\u2502 \u2022 Nh\u1EA5n ENTER \u0111\u1EC3 x\xE1c nh\u1EADn v\xE0 \xE1p d\u1EE5ng \u2502");
|
|
12525
12744
|
console.log("\u2502 \u2022 Nh\u1EA5n Ctrl+C \u0111\u1EC3 h\u1EE7y \u2502");
|
|
12526
12745
|
console.log("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F\n");
|
|
12527
|
-
const action = await
|
|
12746
|
+
const action = await select8({
|
|
12528
12747
|
message: "B\u1EA1n mu\u1ED1n l\xE0m g\xEC?",
|
|
12529
12748
|
choices: [
|
|
12530
12749
|
{ name: "\u2705 Enable c\xE1c nh\xF3m t\u1ED1i \u01B0u", value: "enable" },
|
|
@@ -12573,18 +12792,18 @@ async function applyGroups2(groupKeys, action) {
|
|
|
12573
12792
|
return;
|
|
12574
12793
|
}
|
|
12575
12794
|
if (!existsSync3(vscodeDir)) {
|
|
12576
|
-
await
|
|
12795
|
+
await fs21.mkdir(vscodeDir, { recursive: true });
|
|
12577
12796
|
console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
|
|
12578
12797
|
}
|
|
12579
12798
|
let currentSettings = {};
|
|
12580
12799
|
if (existsSync3(settingsPath)) {
|
|
12581
12800
|
try {
|
|
12582
|
-
const content = await
|
|
12801
|
+
const content = await fs21.readFile(settingsPath, "utf-8");
|
|
12583
12802
|
currentSettings = JSON.parse(content);
|
|
12584
12803
|
console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
|
|
12585
12804
|
} catch {
|
|
12586
12805
|
console.warn("\u26A0\uFE0F Kh\xF4ng th\u1EC3 \u0111\u1ECDc settings.json (c\xF3 th\u1EC3 ch\u1EE9a comments).");
|
|
12587
|
-
const confirmOverwrite = await
|
|
12806
|
+
const confirmOverwrite = await confirm15({
|
|
12588
12807
|
message: "Ghi \u0111\xE8 file settings.json hi\u1EC7n t\u1EA1i?",
|
|
12589
12808
|
default: false
|
|
12590
12809
|
});
|
|
@@ -12619,7 +12838,7 @@ async function applyGroups2(groupKeys, action) {
|
|
|
12619
12838
|
}
|
|
12620
12839
|
}
|
|
12621
12840
|
}
|
|
12622
|
-
await
|
|
12841
|
+
await fs21.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
|
|
12623
12842
|
console.log(`
|
|
12624
12843
|
\u2705 \u0110\xE3 c\u1EADp nh\u1EADt c\xE0i \u0111\u1EB7t VSCode t\u1EA1i: ${settingsPath}`);
|
|
12625
12844
|
console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
|
|
@@ -12631,7 +12850,7 @@ async function resetSettings2(groupKeys) {
|
|
|
12631
12850
|
console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
|
|
12632
12851
|
return;
|
|
12633
12852
|
}
|
|
12634
|
-
const confirmReset = await
|
|
12853
|
+
const confirmReset = await confirm15({
|
|
12635
12854
|
message: groupKeys.length === 0 ? "Reset T\u1EA4T C\u1EA2 settings v\u1EC1 m\u1EB7c \u0111\u1ECBnh (x\xF3a to\xE0n b\u1ED9 file)?" : `Reset c\xE1c nh\xF3m: ${groupKeys.join(", ")}?`,
|
|
12636
12855
|
default: false
|
|
12637
12856
|
});
|
|
@@ -12640,7 +12859,7 @@ async function resetSettings2(groupKeys) {
|
|
|
12640
12859
|
return;
|
|
12641
12860
|
}
|
|
12642
12861
|
if (groupKeys.length === 0) {
|
|
12643
|
-
await
|
|
12862
|
+
await fs21.unlink(settingsPath);
|
|
12644
12863
|
console.log("\n\u2705 \u0110\xE3 x\xF3a file settings.json");
|
|
12645
12864
|
} else {
|
|
12646
12865
|
await applyGroups2(groupKeys, "disable");
|
|
@@ -12651,9 +12870,9 @@ async function resetSettings2(groupKeys) {
|
|
|
12651
12870
|
// src/commands/guide.ts
|
|
12652
12871
|
import React40 from "react";
|
|
12653
12872
|
import { render as render6 } from "ink";
|
|
12654
|
-
import { Command as
|
|
12873
|
+
import { Command as Command58 } from "commander";
|
|
12655
12874
|
function createGuideCommand() {
|
|
12656
|
-
const cmd = new
|
|
12875
|
+
const cmd = new Command58("guide").description("Interactive guide center for Agentic Coding").option("--topic <topic>", "Open specific topic (intro, rules, workflows, prompts, skills)").action(async (options) => {
|
|
12657
12876
|
const { waitUntilExit } = render6(
|
|
12658
12877
|
React40.createElement(GuideApp, {
|
|
12659
12878
|
initialTopic: options.topic,
|
|
@@ -12670,9 +12889,9 @@ function createGuideCommand() {
|
|
|
12670
12889
|
// src/commands/context.ts
|
|
12671
12890
|
import React41 from "react";
|
|
12672
12891
|
import { render as render7 } from "ink";
|
|
12673
|
-
import { Command as
|
|
12892
|
+
import { Command as Command59 } from "commander";
|
|
12674
12893
|
function createContextCommand() {
|
|
12675
|
-
const cmd = new
|
|
12894
|
+
const cmd = new Command59("context").description("Kh\xE1m ph\xE1 v\xE0 qu\u1EA3n l\xFD context d\u1EF1 \xE1n cho c\xE1c IDE").option("--ide <ide>", "M\u1EDF tr\u1EF1c ti\u1EBFp IDE c\u1EE5 th\u1EC3 (cursor, windsurf, antigravity, jai1)").option("--type <type>", "Hi\u1EC3n th\u1ECB lo\u1EA1i context c\u1EE5 th\u1EC3 (rules, workflows, skills, agents, prompts)").option("--stats", "Hi\u1EC3n th\u1ECB th\u1ED1ng k\xEA context (non-interactive)").action(async (options) => {
|
|
12676
12895
|
let initialIDE;
|
|
12677
12896
|
if (options.ide) {
|
|
12678
12897
|
const validIDEs = ["cursor", "windsurf", "antigravity", "jai1"];
|
|
@@ -12749,10 +12968,10 @@ async function printStats2() {
|
|
|
12749
12968
|
}
|
|
12750
12969
|
|
|
12751
12970
|
// src/commands/migrate-ide.ts
|
|
12752
|
-
import { Command as
|
|
12753
|
-
import { checkbox as checkbox8, confirm as
|
|
12971
|
+
import { Command as Command60 } from "commander";
|
|
12972
|
+
import { checkbox as checkbox8, confirm as confirm16 } from "@inquirer/prompts";
|
|
12754
12973
|
function createMigrateIdeCommand() {
|
|
12755
|
-
const cmd = new
|
|
12974
|
+
const cmd = new Command60("migrate-ide").description("Migrate .jai1 rules v\xE0 workflows sang IDEs (Cursor, Windsurf, Claude Code, etc.)").option("--ide <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--type <types...>", "Content types (rules, workflows, commands)").option("--dry-run", "Preview changes without writing files").action(async (options) => {
|
|
12756
12975
|
await runMigrateIde(options);
|
|
12757
12976
|
});
|
|
12758
12977
|
return cmd;
|
|
@@ -12821,7 +13040,7 @@ async function runMigrateIde(options) {
|
|
|
12821
13040
|
if (options.dryRun) {
|
|
12822
13041
|
console.log("\u{1F50D} DRY RUN - No files will be written\n");
|
|
12823
13042
|
}
|
|
12824
|
-
const confirmed = await
|
|
13043
|
+
const confirmed = await confirm16({
|
|
12825
13044
|
message: "Proceed with migration?",
|
|
12826
13045
|
default: true
|
|
12827
13046
|
});
|
|
@@ -12858,7 +13077,7 @@ async function runMigrateIde(options) {
|
|
|
12858
13077
|
}
|
|
12859
13078
|
|
|
12860
13079
|
// src/cli.ts
|
|
12861
|
-
var program = new
|
|
13080
|
+
var program = new Command61();
|
|
12862
13081
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
12863
13082
|
console.log(package_default.version);
|
|
12864
13083
|
if (!process.argv.includes("--skip-update-check")) {
|
|
@@ -12880,15 +13099,16 @@ program.addCommand(createOpenAiKeysCommand());
|
|
|
12880
13099
|
program.addCommand(createStatsCommand());
|
|
12881
13100
|
program.addCommand(createTranslateCommand());
|
|
12882
13101
|
program.addCommand(createImageCommand());
|
|
13102
|
+
program.addCommand(createFeedbackCommand());
|
|
12883
13103
|
program.addCommand(createUtilsCommand());
|
|
12884
13104
|
program.addCommand(createDepsCommand());
|
|
12885
13105
|
program.addCommand(createKitCommand());
|
|
12886
13106
|
program.addCommand(createRulesCommand());
|
|
12887
13107
|
program.addCommand(createUpgradeCommand());
|
|
12888
13108
|
program.addCommand(createCleanCommand());
|
|
12889
|
-
var redmineCommand = new
|
|
13109
|
+
var redmineCommand = new Command61("redmine").description("Redmine context sync commands");
|
|
12890
13110
|
redmineCommand.addCommand(createRedmineCheckCommand());
|
|
12891
|
-
var syncCommand = new
|
|
13111
|
+
var syncCommand = new Command61("sync").description("Sync Redmine issues to markdown files");
|
|
12892
13112
|
syncCommand.addCommand(createSyncIssueCommand());
|
|
12893
13113
|
syncCommand.addCommand(createSyncProjectCommand());
|
|
12894
13114
|
redmineCommand.addCommand(syncCommand);
|