@jvittechs/j 1.0.57 → 1.0.58

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 CHANGED
@@ -6,14 +6,22 @@ import {
6
6
  NotFoundError,
7
7
  ValidationError
8
8
  } from "./chunk-XZ7VS36G.js";
9
+ import {
10
+ createSettingsShowCommand
11
+ } from "./chunk-DVBQLA4R.js";
9
12
  import {
10
13
  BLOCKED_ICON,
14
+ ConfigService,
11
15
  PRIORITY_ICONS,
12
16
  PRIORITY_LABELS,
13
17
  STATUS_ICONS,
14
18
  TaskService,
15
19
  createTaskSummaryCommand
16
- } from "./chunk-FZBVI5AX.js";
20
+ } from "./chunk-S7QUPWSM.js";
21
+ import {
22
+ SettingsService
23
+ } from "./chunk-Z464RBPB.js";
24
+ import "./chunk-DGUM43GV.js";
17
25
 
18
26
  // src/utils/node-version-check.ts
19
27
  import chalk from "chalk";
@@ -49,7 +57,7 @@ function checkNodeVersion() {
49
57
  }
50
58
 
51
59
  // src/cli.ts
52
- import { Command as Command99 } from "commander";
60
+ import { Command as Command103 } from "commander";
53
61
 
54
62
  // src/services/error-log.service.ts
55
63
  import { promises as fs } from "fs";
@@ -149,7 +157,7 @@ import { basename as basename5 } from "path";
149
157
  // package.json
150
158
  var package_default = {
151
159
  name: "@jvittechs/j",
152
- version: "1.0.57",
160
+ version: "1.0.58",
153
161
  description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Supports both `j` and `jai1` commands. Please contact TeamAI for usage instructions.",
154
162
  type: "module",
155
163
  bin: {
@@ -249,76 +257,6 @@ var package_default = {
249
257
  }
250
258
  };
251
259
 
252
- // src/services/config.service.ts
253
- import { promises as fs2 } from "fs";
254
- import { join as join2 } from "path";
255
- import { homedir as homedir2 } from "os";
256
- var ConfigService = class {
257
- configDir;
258
- configPath;
259
- constructor() {
260
- this.configDir = join2(homedir2(), ".jai1");
261
- this.configPath = join2(this.configDir, "config.json");
262
- }
263
- /**
264
- * Check if config file exists
265
- */
266
- async exists() {
267
- try {
268
- await fs2.access(this.configPath);
269
- return true;
270
- } catch {
271
- return false;
272
- }
273
- }
274
- /**
275
- * Load configuration from file
276
- * @returns Config object or null if not found
277
- */
278
- async load() {
279
- if (!await this.exists()) {
280
- return null;
281
- }
282
- try {
283
- const content = await fs2.readFile(this.configPath, "utf-8");
284
- return JSON.parse(content);
285
- } catch (error) {
286
- throw new Error(
287
- `Failed to load config: ${error instanceof Error ? error.message : String(error)}`
288
- );
289
- }
290
- }
291
- /**
292
- * Save configuration to file
293
- * Creates directory if it doesn't exist
294
- * Sets proper file permissions (600)
295
- */
296
- async save(config) {
297
- try {
298
- await fs2.mkdir(this.configDir, { recursive: true, mode: 448 });
299
- await fs2.writeFile(this.configPath, JSON.stringify(config, null, 2), {
300
- mode: 384
301
- });
302
- } catch (error) {
303
- throw new Error(
304
- `Failed to save config: ${error instanceof Error ? error.message : String(error)}`
305
- );
306
- }
307
- }
308
- /**
309
- * Get config file path
310
- */
311
- getConfigPath() {
312
- return this.configPath;
313
- }
314
- /**
315
- * Get config directory path
316
- */
317
- getConfigDir() {
318
- return this.configDir;
319
- }
320
- };
321
-
322
260
  // src/utils/cli-name.ts
323
261
  import { basename } from "path";
324
262
  function getCliName() {
@@ -400,7 +338,7 @@ import chalk2 from "chalk";
400
338
  import boxen from "boxen";
401
339
 
402
340
  // src/services/tracking.service.ts
403
- import { platform, release, arch, hostname, homedir as homedir3 } from "os";
341
+ import { platform, release, arch, hostname, homedir as homedir2 } from "os";
404
342
  import { version as nodeVersion } from "process";
405
343
  function getSystemInfo() {
406
344
  return {
@@ -409,7 +347,7 @@ function getSystemInfo() {
409
347
  arch: arch(),
410
348
  nodeVersion,
411
349
  hostname: hostname(),
412
- homeDir: homedir3()
350
+ homeDir: homedir2()
413
351
  };
414
352
  }
415
353
  var TrackingService = class {
@@ -592,9 +530,9 @@ async function handleAuth(options) {
592
530
  import { Command as Command2 } from "commander";
593
531
  import chalk3 from "chalk";
594
532
  import boxen2 from "boxen";
595
- import { promises as fs3 } from "fs";
596
- import { join as join3 } from "path";
597
- import { homedir as homedir4 } from "os";
533
+ import { promises as fs2 } from "fs";
534
+ import { join as join2 } from "path";
535
+ import { homedir as homedir3 } from "os";
598
536
  function createStatusCommand() {
599
537
  const cmd = new Command2("status").description("Hi\u1EC3n th\u1ECB tr\u1EA1ng th\xE1i c\u1EA5u h\xECnh v\xE0 components").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
600
538
  await handleStatus(options);
@@ -608,7 +546,7 @@ async function handleStatus(options) {
608
546
  throw new ValidationError(`Not initialized. Run "${getCliName()} auth" first.`);
609
547
  }
610
548
  const componentsService = new ComponentsService();
611
- const frameworkPath = join3(homedir4(), ".jai1", "framework");
549
+ const frameworkPath = join2(homedir3(), ".jai1", "framework");
612
550
  const projectStatus = await getProjectStatus();
613
551
  const installedComponents = await componentsService.getInstalled();
614
552
  const componentCount = Object.keys(installedComponents).length;
@@ -665,9 +603,9 @@ function maskKey(key) {
665
603
  return "****" + key.slice(-4);
666
604
  }
667
605
  async function getProjectStatus() {
668
- const projectJai1 = join3(process.cwd(), ".jai1");
606
+ const projectJai1 = join2(process.cwd(), ".jai1");
669
607
  try {
670
- await fs3.access(projectJai1);
608
+ await fs2.access(projectJai1);
671
609
  return { exists: true, version: "Synced" };
672
610
  } catch {
673
611
  return { exists: false };
@@ -686,7 +624,7 @@ import Spinner from "ink-spinner";
686
624
  import TextInput from "ink-text-input";
687
625
 
688
626
  // src/services/migrate-ide.service.ts
689
- import { promises as fs4 } from "fs";
627
+ import { promises as fs3 } from "fs";
690
628
  import path from "path";
691
629
  import matter from "gray-matter";
692
630
 
@@ -876,18 +814,18 @@ var MigrateIdeService = class {
876
814
  const items = [];
877
815
  const presetDir = path.join(this.jai1Path, "rule-preset");
878
816
  try {
879
- await fs4.access(presetDir);
817
+ await fs3.access(presetDir);
880
818
  } catch {
881
819
  return items;
882
820
  }
883
- const files = await fs4.readdir(presetDir);
821
+ const files = await fs3.readdir(presetDir);
884
822
  for (const file of files) {
885
823
  if (!file.endsWith(".md") && !file.endsWith(".mdc")) continue;
886
824
  if (file === "preset.json") continue;
887
825
  const filepath = path.join(presetDir, file);
888
- const stat = await fs4.stat(filepath);
826
+ const stat = await fs3.stat(filepath);
889
827
  if (!stat.isFile()) continue;
890
- const content = await fs4.readFile(filepath, "utf-8");
828
+ const content = await fs3.readFile(filepath, "utf-8");
891
829
  let frontmatter = {};
892
830
  try {
893
831
  const { data } = matter(content);
@@ -917,13 +855,13 @@ var MigrateIdeService = class {
917
855
  const items = [];
918
856
  const dirPath = path.join(this.jai1Path, type);
919
857
  try {
920
- await fs4.access(dirPath);
858
+ await fs3.access(dirPath);
921
859
  } catch {
922
860
  return items;
923
861
  }
924
862
  const mdFiles = await this.collectMdFiles(dirPath, dirPath);
925
863
  for (const { filepath, relativeName } of mdFiles) {
926
- const content = await fs4.readFile(filepath, "utf-8");
864
+ const content = await fs3.readFile(filepath, "utf-8");
927
865
  let frontmatter = {};
928
866
  try {
929
867
  const { data } = matter(content);
@@ -962,7 +900,7 @@ var MigrateIdeService = class {
962
900
  alwaysApply: sourceItem.alwaysApply,
963
901
  sourceFile: sourceItem.relativePath
964
902
  });
965
- const sourceContent = await fs4.readFile(sourceItem.filepath, "utf-8");
903
+ const sourceContent = await fs3.readFile(sourceItem.filepath, "utf-8");
966
904
  const bodyContent = extractBody(sourceContent);
967
905
  if (frontmatter) {
968
906
  return `${frontmatter}
@@ -1008,7 +946,7 @@ ${bodyContent}
1008
946
  try {
1009
947
  let status = "created";
1010
948
  try {
1011
- await fs4.access(agentsPath);
949
+ await fs3.access(agentsPath);
1012
950
  status = "updated";
1013
951
  } catch {
1014
952
  }
@@ -1017,7 +955,7 @@ ${bodyContent}
1017
955
  ""
1018
956
  ];
1019
957
  for (const rule of rules) {
1020
- const content = await fs4.readFile(rule.filepath, "utf-8");
958
+ const content = await fs3.readFile(rule.filepath, "utf-8");
1021
959
  const body = extractBody(content);
1022
960
  if (body.trim()) {
1023
961
  lines.push(downshiftHeadings(body));
@@ -1025,7 +963,7 @@ ${bodyContent}
1025
963
  }
1026
964
  }
1027
965
  lines.push("");
1028
- await fs4.writeFile(agentsPath, lines.join("\n"), "utf-8");
966
+ await fs3.writeFile(agentsPath, lines.join("\n"), "utf-8");
1029
967
  return {
1030
968
  source: {
1031
969
  type: "rules",
@@ -1071,15 +1009,15 @@ ${bodyContent}
1071
1009
  };
1072
1010
  }
1073
1011
  const targetDir = path.dirname(targetPath);
1074
- await fs4.mkdir(targetDir, { recursive: true });
1012
+ await fs3.mkdir(targetDir, { recursive: true });
1075
1013
  let status = "created";
1076
1014
  try {
1077
- await fs4.access(targetPath);
1015
+ await fs3.access(targetPath);
1078
1016
  status = "updated";
1079
1017
  } catch {
1080
1018
  }
1081
1019
  const copiedContent = await this.generateCopiedContent(ide, item);
1082
- await fs4.writeFile(targetPath, copiedContent, "utf-8");
1020
+ await fs3.writeFile(targetPath, copiedContent, "utf-8");
1083
1021
  return {
1084
1022
  source: item,
1085
1023
  targetIDE: ide,
@@ -1134,7 +1072,7 @@ ${bodyContent}
1134
1072
  const results = [];
1135
1073
  let entries;
1136
1074
  try {
1137
- entries = await fs4.readdir(currentDir, { withFileTypes: true });
1075
+ entries = await fs3.readdir(currentDir, { withFileTypes: true });
1138
1076
  } catch {
1139
1077
  return results;
1140
1078
  }
@@ -2352,7 +2290,7 @@ import { Command as Command7 } from "commander";
2352
2290
  import chalk6 from "chalk";
2353
2291
 
2354
2292
  // src/services/context-scanner.service.ts
2355
- import { promises as fs5 } from "fs";
2293
+ import { promises as fs4 } from "fs";
2356
2294
  import path2 from "path";
2357
2295
  import matter2 from "gray-matter";
2358
2296
 
@@ -2573,7 +2511,7 @@ var ContextScannerService = class {
2573
2511
  } else {
2574
2512
  dirPath = path2.join(this.projectPath, config.basePath, relativePath);
2575
2513
  try {
2576
- await fs5.access(dirPath);
2514
+ await fs4.access(dirPath);
2577
2515
  } catch {
2578
2516
  return [];
2579
2517
  }
@@ -2584,10 +2522,10 @@ var ContextScannerService = class {
2584
2522
  const skillItems = await this.scanSkills(dirPath, ide);
2585
2523
  items.push(...skillItems);
2586
2524
  } else {
2587
- const files = await fs5.readdir(dirPath);
2525
+ const files = await fs4.readdir(dirPath);
2588
2526
  for (const file of files) {
2589
2527
  const filepath = path2.join(dirPath, file);
2590
- const stat = await fs5.stat(filepath);
2528
+ const stat = await fs4.stat(filepath);
2591
2529
  if (!stat.isFile()) continue;
2592
2530
  const matchesExtension = extensions.some((ext) => file.endsWith(ext));
2593
2531
  if (!matchesExtension) continue;
@@ -2607,13 +2545,13 @@ var ContextScannerService = class {
2607
2545
  async scanSkills(skillsDir, ide) {
2608
2546
  const items = [];
2609
2547
  try {
2610
- const entries = await fs5.readdir(skillsDir, { withFileTypes: true });
2548
+ const entries = await fs4.readdir(skillsDir, { withFileTypes: true });
2611
2549
  for (const entry of entries) {
2612
2550
  if (!entry.isDirectory()) continue;
2613
2551
  const skillPath = path2.join(skillsDir, entry.name);
2614
2552
  const skillFilePath = path2.join(skillPath, "SKILL.md");
2615
2553
  try {
2616
- await fs5.access(skillFilePath);
2554
+ await fs4.access(skillFilePath);
2617
2555
  } catch {
2618
2556
  continue;
2619
2557
  }
@@ -2648,8 +2586,8 @@ var ContextScannerService = class {
2648
2586
  * Parse a context item from file
2649
2587
  */
2650
2588
  async parseContextItem(filepath, ide, type) {
2651
- const content = await fs5.readFile(filepath, "utf-8");
2652
- const stat = await fs5.stat(filepath);
2589
+ const content = await fs4.readFile(filepath, "utf-8");
2590
+ const stat = await fs4.stat(filepath);
2653
2591
  let frontmatter = {};
2654
2592
  let bodyContent = content;
2655
2593
  try {
@@ -2737,7 +2675,7 @@ var ContextScannerService = class {
2737
2675
  */
2738
2676
  async pathExists(filepath) {
2739
2677
  try {
2740
- await fs5.access(filepath);
2678
+ await fs4.access(filepath);
2741
2679
  return true;
2742
2680
  } catch {
2743
2681
  return false;
@@ -2902,7 +2840,7 @@ function createContextSubcommand() {
2902
2840
  // src/commands/ide/setup.ts
2903
2841
  import { Command as Command8 } from "commander";
2904
2842
  import { checkbox, confirm as confirm2, select } from "@inquirer/prompts";
2905
- import fs6 from "fs/promises";
2843
+ import fs5 from "fs/promises";
2906
2844
  import path3 from "path";
2907
2845
  import { existsSync } from "fs";
2908
2846
 
@@ -3154,13 +3092,13 @@ async function applyGroups(groupKeys, action) {
3154
3092
  return;
3155
3093
  }
3156
3094
  if (!existsSync(vscodeDir)) {
3157
- await fs6.mkdir(vscodeDir, { recursive: true });
3095
+ await fs5.mkdir(vscodeDir, { recursive: true });
3158
3096
  console.log("\u{1F4C1} Created .vscode/ directory");
3159
3097
  }
3160
3098
  let currentSettings = {};
3161
3099
  if (existsSync(settingsPath)) {
3162
3100
  try {
3163
- const content = await fs6.readFile(settingsPath, "utf-8");
3101
+ const content = await fs5.readFile(settingsPath, "utf-8");
3164
3102
  currentSettings = JSON.parse(content);
3165
3103
  console.log("\u{1F4C4} Read current settings from settings.json");
3166
3104
  } catch {
@@ -3200,7 +3138,7 @@ async function applyGroups(groupKeys, action) {
3200
3138
  }
3201
3139
  }
3202
3140
  }
3203
- await fs6.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
3141
+ await fs5.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
3204
3142
  console.log(`
3205
3143
  \u2705 Updated IDE settings at: ${settingsPath}`);
3206
3144
  console.log("\u{1F4A1} Tip: Restart your IDE to apply changes.");
@@ -3221,7 +3159,7 @@ async function resetSettings(groupKeys) {
3221
3159
  return;
3222
3160
  }
3223
3161
  if (groupKeys.length === 0) {
3224
- await fs6.unlink(settingsPath);
3162
+ await fs5.unlink(settingsPath);
3225
3163
  console.log("\n\u2705 Deleted settings.json file");
3226
3164
  } else {
3227
3165
  await applyGroups(groupKeys, "disable");
@@ -3359,8 +3297,8 @@ async function runSync(options) {
3359
3297
  import { Command as Command10 } from "commander";
3360
3298
 
3361
3299
  // src/services/ide-detection.service.ts
3362
- import { promises as fs7 } from "fs";
3363
- import { join as join4 } from "path";
3300
+ import { promises as fs6 } from "fs";
3301
+ import { join as join3 } from "path";
3364
3302
 
3365
3303
  // src/config/ide-formats.ts
3366
3304
  var IDE_FORMATS = {
@@ -3474,7 +3412,7 @@ var IdeDetectionService = class {
3474
3412
  confidence: "low"
3475
3413
  };
3476
3414
  if (ideId === "agentsmd") {
3477
- const agentsPath = join4(this.projectPath, "AGENTS.md");
3415
+ const agentsPath = join3(this.projectPath, "AGENTS.md");
3478
3416
  const exists = await this.pathExists(agentsPath);
3479
3417
  detection.detected = exists;
3480
3418
  if (exists) {
@@ -3486,11 +3424,11 @@ var IdeDetectionService = class {
3486
3424
  return detection;
3487
3425
  }
3488
3426
  if (ideId === "gemini") {
3489
- const geminiPath = join4(this.projectPath, "GEMINI.md");
3427
+ const geminiPath = join3(this.projectPath, "GEMINI.md");
3490
3428
  const exists = await this.pathExists(geminiPath);
3491
3429
  detection.detected = exists;
3492
3430
  if (exists) {
3493
- const agentsPath = join4(this.projectPath, "AGENTS.md");
3431
+ const agentsPath = join3(this.projectPath, "AGENTS.md");
3494
3432
  const agentsExists = await this.pathExists(agentsPath);
3495
3433
  if (agentsExists) {
3496
3434
  const customCount = await this.countAgentsMdCustomSections(agentsPath);
@@ -3502,9 +3440,9 @@ var IdeDetectionService = class {
3502
3440
  return detection;
3503
3441
  }
3504
3442
  if (ideId === "opencode") {
3505
- const agentsPath = join4(this.projectPath, "AGENTS.md");
3443
+ const agentsPath = join3(this.projectPath, "AGENTS.md");
3506
3444
  const hasAgents = await this.pathExists(agentsPath);
3507
- const commandPath = join4(this.projectPath, ".opencode/command");
3445
+ const commandPath = join3(this.projectPath, ".opencode/command");
3508
3446
  const hasCommands = await this.pathExists(commandPath);
3509
3447
  if (hasAgents) {
3510
3448
  const customCount = await this.countAgentsMdCustomSections(agentsPath);
@@ -3519,7 +3457,7 @@ var IdeDetectionService = class {
3519
3457
  detection.confidence = detection.detected ? hasAgents && hasCommands ? "high" : "medium" : "low";
3520
3458
  return detection;
3521
3459
  }
3522
- const rulesPath = join4(this.projectPath, format.rulesPath);
3460
+ const rulesPath = join3(this.projectPath, format.rulesPath);
3523
3461
  const rulesExist = await this.pathExists(rulesPath);
3524
3462
  if (rulesExist) {
3525
3463
  const totalRules = await this.countFiles(rulesPath, format.fileExtension);
@@ -3531,7 +3469,7 @@ var IdeDetectionService = class {
3531
3469
  }
3532
3470
  }
3533
3471
  if (format.workflowsPath) {
3534
- const workflowsPath = join4(this.projectPath, format.workflowsPath);
3472
+ const workflowsPath = join3(this.projectPath, format.workflowsPath);
3535
3473
  const workflowsExist = await this.pathExists(workflowsPath);
3536
3474
  if (workflowsExist) {
3537
3475
  detection.hasWorkflows = true;
@@ -3599,13 +3537,13 @@ var IdeDetectionService = class {
3599
3537
  }
3600
3538
  } else if (ideId === "opencode") {
3601
3539
  const hasAgents = await this.pathExists("AGENTS.md");
3602
- const commandPath = join4(this.projectPath, ".opencode/command");
3540
+ const commandPath = join3(this.projectPath, ".opencode/command");
3603
3541
  const hasCommands = await this.pathExists(commandPath);
3604
3542
  if (hasAgents || hasCommands) {
3605
3543
  detected.push(ideId);
3606
3544
  }
3607
3545
  } else {
3608
- const rulesPath = join4(this.projectPath, format.rulesPath);
3546
+ const rulesPath = join3(this.projectPath, format.rulesPath);
3609
3547
  if (await this.pathExists(rulesPath)) {
3610
3548
  const count = await this.countFiles(rulesPath, format.fileExtension);
3611
3549
  if (count > 0) {
@@ -3638,7 +3576,7 @@ var IdeDetectionService = class {
3638
3576
  */
3639
3577
  async pathExists(path13) {
3640
3578
  try {
3641
- await fs7.access(path13);
3579
+ await fs6.access(path13);
3642
3580
  return true;
3643
3581
  } catch {
3644
3582
  return false;
@@ -3650,12 +3588,12 @@ var IdeDetectionService = class {
3650
3588
  */
3651
3589
  async countFiles(dirPath, extension, excludeKeywords = []) {
3652
3590
  try {
3653
- const entries = await fs7.readdir(dirPath, { withFileTypes: true });
3591
+ const entries = await fs6.readdir(dirPath, { withFileTypes: true });
3654
3592
  let count = 0;
3655
3593
  for (const entry of entries) {
3656
3594
  if (entry.isDirectory()) {
3657
3595
  count += await this.countFiles(
3658
- join4(dirPath, entry.name),
3596
+ join3(dirPath, entry.name),
3659
3597
  extension,
3660
3598
  excludeKeywords
3661
3599
  );
@@ -3680,7 +3618,7 @@ var IdeDetectionService = class {
3680
3618
  */
3681
3619
  async countAgentsMdCustomSections(filePath) {
3682
3620
  try {
3683
- const content = await fs7.readFile(filePath, "utf-8");
3621
+ const content = await fs6.readFile(filePath, "utf-8");
3684
3622
  const h2Headings = content.match(/^## .+$/gm) || [];
3685
3623
  return h2Headings.filter(
3686
3624
  (h) => !h.toLowerCase().includes(DEFAULT_RULE_KEYWORD)
@@ -3700,7 +3638,7 @@ var IdeDetectionService = class {
3700
3638
  */
3701
3639
  async suggestIdes() {
3702
3640
  const suggestions = [];
3703
- if (await this.pathExists(join4(this.projectPath, ".vscode"))) {
3641
+ if (await this.pathExists(join3(this.projectPath, ".vscode"))) {
3704
3642
  suggestions.push({
3705
3643
  ideId: "cursor",
3706
3644
  name: "Cursor",
@@ -3708,7 +3646,7 @@ var IdeDetectionService = class {
3708
3646
  priority: "high"
3709
3647
  });
3710
3648
  }
3711
- if (await this.pathExists(join4(this.projectPath, "package.json"))) {
3649
+ if (await this.pathExists(join3(this.projectPath, "package.json"))) {
3712
3650
  suggestions.push({
3713
3651
  ideId: "windsurf",
3714
3652
  name: "Windsurf",
@@ -3722,7 +3660,7 @@ var IdeDetectionService = class {
3722
3660
  reason: "Universal format, works with all IDEs",
3723
3661
  priority: "high"
3724
3662
  });
3725
- const hasClaudeConfig = await this.pathExists(join4(this.projectPath, ".claude"));
3663
+ const hasClaudeConfig = await this.pathExists(join3(this.projectPath, ".claude"));
3726
3664
  if (hasClaudeConfig) {
3727
3665
  suggestions.push({
3728
3666
  ideId: "claude",
@@ -3731,7 +3669,7 @@ var IdeDetectionService = class {
3731
3669
  priority: "high"
3732
3670
  });
3733
3671
  }
3734
- const hasOpenCodeConfig = await this.pathExists(join4(this.projectPath, ".opencode"));
3672
+ const hasOpenCodeConfig = await this.pathExists(join3(this.projectPath, ".opencode"));
3735
3673
  if (hasOpenCodeConfig) {
3736
3674
  suggestions.push({
3737
3675
  ideId: "opencode",
@@ -4005,8 +3943,8 @@ function showQuickstart(name) {
4005
3943
  // src/commands/doctor.ts
4006
3944
  import { Command as Command14 } from "commander";
4007
3945
  import chalk10 from "chalk";
4008
- import { promises as fs8 } from "fs";
4009
- import { join as join5 } from "path";
3946
+ import { promises as fs7 } from "fs";
3947
+ import { join as join4 } from "path";
4010
3948
  var CORE_FILES_FALLBACK = [
4011
3949
  "context/jv-it-context.md",
4012
3950
  "rules/jai1.md"
@@ -4114,9 +4052,9 @@ async function checkAuth(cliName) {
4114
4052
  }
4115
4053
  }
4116
4054
  async function checkCoreFiles(cliName) {
4117
- const jai1Dir = join5(process.cwd(), ".jai1");
4055
+ const jai1Dir = join4(process.cwd(), ".jai1");
4118
4056
  try {
4119
- await fs8.access(jai1Dir);
4057
+ await fs7.access(jai1Dir);
4120
4058
  } catch {
4121
4059
  return {
4122
4060
  name: "Core Package",
@@ -4127,8 +4065,8 @@ async function checkCoreFiles(cliName) {
4127
4065
  }
4128
4066
  let coreFiles = CORE_FILES_FALLBACK;
4129
4067
  try {
4130
- const manifestPath = join5(jai1Dir, "manifest.json");
4131
- const manifestContent = await fs8.readFile(manifestPath, "utf-8");
4068
+ const manifestPath = join4(jai1Dir, "manifest.json");
4069
+ const manifestContent = await fs7.readFile(manifestPath, "utf-8");
4132
4070
  const manifest = JSON.parse(manifestContent);
4133
4071
  const manifestFiles = Object.keys(manifest);
4134
4072
  if (manifestFiles.length > 0) {
@@ -4139,9 +4077,9 @@ async function checkCoreFiles(cliName) {
4139
4077
  const missing = [];
4140
4078
  const found = [];
4141
4079
  for (const file of coreFiles) {
4142
- const filePath = join5(jai1Dir, file);
4080
+ const filePath = join4(jai1Dir, file);
4143
4081
  try {
4144
- await fs8.access(filePath);
4082
+ await fs7.access(filePath);
4145
4083
  found.push(file);
4146
4084
  } catch {
4147
4085
  missing.push(file);
@@ -4904,7 +4842,7 @@ var ChatApp = ({ service, initialModel }) => {
4904
4842
 
4905
4843
  // src/server/web-chat-server.ts
4906
4844
  import http from "http";
4907
- import fs10 from "fs";
4845
+ import fs9 from "fs";
4908
4846
  import path5 from "path";
4909
4847
  import { fileURLToPath } from "url";
4910
4848
 
@@ -5038,7 +4976,7 @@ var SessionManager = class {
5038
4976
  };
5039
4977
 
5040
4978
  // src/server/file-service.ts
5041
- import fs9 from "fs";
4979
+ import fs8 from "fs";
5042
4980
  import path4 from "path";
5043
4981
  import ignore from "ignore";
5044
4982
  var ALWAYS_EXCLUDED = [
@@ -5247,8 +5185,8 @@ var FileService = class {
5247
5185
  this.ignoreFilter.add(ALWAYS_EXCLUDED);
5248
5186
  const gitignorePath = path4.join(this.workingDir, ".gitignore");
5249
5187
  try {
5250
- if (fs9.existsSync(gitignorePath)) {
5251
- const content = fs9.readFileSync(gitignorePath, "utf-8");
5188
+ if (fs8.existsSync(gitignorePath)) {
5189
+ const content = fs8.readFileSync(gitignorePath, "utf-8");
5252
5190
  this.ignoreFilter.add(content);
5253
5191
  }
5254
5192
  } catch {
@@ -5289,7 +5227,7 @@ var FileService = class {
5289
5227
  const searchDir = async (dirPath, depth = 0) => {
5290
5228
  if (depth > 10 || results.length >= maxResults) return;
5291
5229
  try {
5292
- const entries = await fs9.promises.readdir(dirPath, { withFileTypes: true });
5230
+ const entries = await fs8.promises.readdir(dirPath, { withFileTypes: true });
5293
5231
  for (const entry of entries) {
5294
5232
  if (results.length >= maxResults) break;
5295
5233
  const entryPath = path4.join(dirPath, entry.name);
@@ -5299,7 +5237,7 @@ var FileService = class {
5299
5237
  if (normalizedRelPath.includes(normalizedQuery)) {
5300
5238
  if (entry.isFile() && isTextFile(entry.name)) {
5301
5239
  try {
5302
- const stat = await fs9.promises.stat(entryPath);
5240
+ const stat = await fs8.promises.stat(entryPath);
5303
5241
  results.push({
5304
5242
  path: relativePath,
5305
5243
  name: entry.name,
@@ -5339,14 +5277,14 @@ var FileService = class {
5339
5277
  if (!isTextFile(absolutePath)) {
5340
5278
  throw new Error("Only text files can be read");
5341
5279
  }
5342
- const stat = await fs9.promises.stat(absolutePath);
5280
+ const stat = await fs8.promises.stat(absolutePath);
5343
5281
  if (!stat.isFile()) {
5344
5282
  throw new Error("Path is not a file");
5345
5283
  }
5346
5284
  if (stat.size > this.maxFileSize) {
5347
5285
  throw new Error(`File exceeds maximum size of ${Math.round(this.maxFileSize / 1024)}KB`);
5348
5286
  }
5349
- const content = await fs9.promises.readFile(absolutePath, "utf-8");
5287
+ const content = await fs8.promises.readFile(absolutePath, "utf-8");
5350
5288
  return {
5351
5289
  path: normalizedRelPath,
5352
5290
  content,
@@ -5476,14 +5414,14 @@ function createWebChatServer(options) {
5476
5414
  return;
5477
5415
  }
5478
5416
  try {
5479
- const stat = await fs10.promises.stat(fullPath);
5417
+ const stat = await fs9.promises.stat(fullPath);
5480
5418
  if (!stat.isFile()) {
5481
5419
  sendError(res, 404, "ERR-WC-007", "Not found");
5482
5420
  return;
5483
5421
  }
5484
5422
  const ext = path5.extname(fullPath);
5485
5423
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
5486
- const content = await fs10.promises.readFile(fullPath);
5424
+ const content = await fs9.promises.readFile(fullPath);
5487
5425
  res.writeHead(200, { "Content-Type": contentType });
5488
5426
  res.end(content);
5489
5427
  } catch (error) {
@@ -6057,7 +5995,7 @@ function createStatsCommand() {
6057
5995
  import { Command as Command18 } from "commander";
6058
5996
 
6059
5997
  // src/services/translation.service.ts
6060
- import { promises as fs11 } from "fs";
5998
+ import { promises as fs10 } from "fs";
6061
5999
  import path6 from "path";
6062
6000
  import pLimit from "p-limit";
6063
6001
  import pRetry from "p-retry";
@@ -6076,7 +6014,7 @@ var TranslationService = class {
6076
6014
  */
6077
6015
  async detectInputType(input5) {
6078
6016
  try {
6079
- const stat = await fs11.stat(input5);
6017
+ const stat = await fs10.stat(input5);
6080
6018
  if (stat.isDirectory()) return "folder";
6081
6019
  if (stat.isFile()) return "file";
6082
6020
  } catch {
@@ -6113,13 +6051,13 @@ var TranslationService = class {
6113
6051
  */
6114
6052
  async translateFile(filePath) {
6115
6053
  try {
6116
- const content = await fs11.readFile(filePath, "utf-8");
6054
+ const content = await fs10.readFile(filePath, "utf-8");
6117
6055
  const ext = path6.extname(filePath).toLowerCase();
6118
6056
  const fileType = this.getFileType(ext);
6119
6057
  const translatedContent = await this.translateWithRetry(content, fileType);
6120
6058
  const outputPath = this.generateOutputPath(filePath);
6121
6059
  if (!this.options.dryRun) {
6122
- await fs11.writeFile(outputPath, translatedContent, "utf-8");
6060
+ await fs10.writeFile(outputPath, translatedContent, "utf-8");
6123
6061
  }
6124
6062
  return {
6125
6063
  inputPath: filePath,
@@ -6184,7 +6122,7 @@ var TranslationService = class {
6184
6122
  * Discover translatable files in folder recursively
6185
6123
  */
6186
6124
  async discoverFiles(folderPath) {
6187
- const entries = await fs11.readdir(folderPath, { withFileTypes: true });
6125
+ const entries = await fs10.readdir(folderPath, { withFileTypes: true });
6188
6126
  const files = [];
6189
6127
  for (const entry of entries) {
6190
6128
  const fullPath = path6.join(folderPath, entry.name);
@@ -6717,20 +6655,20 @@ function createImageCommand() {
6717
6655
  import { Command as Command24 } from "commander";
6718
6656
  import { select as select2, input, confirm as confirm5 } from "@inquirer/prompts";
6719
6657
  import os from "os";
6720
- import { promises as fs12 } from "fs";
6721
- import { join as join6 } from "path";
6658
+ import { promises as fs11 } from "fs";
6659
+ import { join as join5 } from "path";
6722
6660
  async function collectContext() {
6723
6661
  const context = {
6724
6662
  os: `${os.platform()} ${os.release()}`
6725
6663
  };
6726
6664
  try {
6727
6665
  const packageJsonPath = new URL("../../package.json", import.meta.url);
6728
- const packageJson = JSON.parse(await fs12.readFile(packageJsonPath, "utf-8"));
6666
+ const packageJson = JSON.parse(await fs11.readFile(packageJsonPath, "utf-8"));
6729
6667
  context.cli_version = packageJson.version;
6730
6668
  } catch {
6731
6669
  }
6732
6670
  try {
6733
- const projectPackageJson = await fs12.readFile(join6(process.cwd(), "package.json"), "utf-8");
6671
+ const projectPackageJson = await fs11.readFile(join5(process.cwd(), "package.json"), "utf-8");
6734
6672
  const projectData = JSON.parse(projectPackageJson);
6735
6673
  context.project_name = projectData.name;
6736
6674
  } catch {
@@ -6933,8 +6871,8 @@ function createFeedbackCommand() {
6933
6871
  import { Command as Command25 } from "commander";
6934
6872
  import { confirm as confirm6 } from "@inquirer/prompts";
6935
6873
  import os2 from "os";
6936
- import { promises as fs13 } from "fs";
6937
- import { basename as basename2, join as join7 } from "path";
6874
+ import { promises as fs12 } from "fs";
6875
+ import { basename as basename2, join as join6 } from "path";
6938
6876
  import { version as nodeVersion2 } from "process";
6939
6877
  function createClientInfoCommand() {
6940
6878
  const cmd = new Command25("client-info").description("T\u1EA1o th\xF4ng tin client \u0111\u1EC3 g\u1EEDi \u0111\u1ED9i ph\xE1t tri\u1EC3n jai1").option("--json", "Output as JSON").option("--full", "Include component list (top 20)").option("--submit", "Submit client info to Jai1 feedback endpoint").option("--message <text>", "Additional message when submitting").option("--show-paths", "Include full project path").action(async (options) => {
@@ -7049,9 +6987,9 @@ async function collectClientInfo(config, options) {
7049
6987
  return payload;
7050
6988
  }
7051
6989
  async function hasProjectJai1() {
7052
- const projectJai1 = join7(process.cwd(), ".jai1");
6990
+ const projectJai1 = join6(process.cwd(), ".jai1");
7053
6991
  try {
7054
- await fs13.access(projectJai1);
6992
+ await fs12.access(projectJai1);
7055
6993
  return true;
7056
6994
  } catch {
7057
6995
  return false;
@@ -9400,7 +9338,7 @@ var HttpView = () => {
9400
9338
  import React23, { useState as useState17 } from "react";
9401
9339
  import { Box as Box19, Text as Text20, useInput as useInput15 } from "ink";
9402
9340
  import TextInput14 from "ink-text-input";
9403
- import * as fs14 from "fs";
9341
+ import * as fs13 from "fs";
9404
9342
  import * as path7 from "path";
9405
9343
  var MarkdownView = () => {
9406
9344
  const [filePath, setFilePath] = useState17("");
@@ -9422,11 +9360,11 @@ var MarkdownView = () => {
9422
9360
  try {
9423
9361
  setError("");
9424
9362
  const resolvedPath = path7.resolve(filePath);
9425
- if (!fs14.existsSync(resolvedPath)) {
9363
+ if (!fs13.existsSync(resolvedPath)) {
9426
9364
  setError(`File not found: ${resolvedPath}`);
9427
9365
  return;
9428
9366
  }
9429
- let fileContent = fs14.readFileSync(resolvedPath, "utf-8");
9367
+ let fileContent = fs13.readFileSync(resolvedPath, "utf-8");
9430
9368
  fileContent = fileContent.replace(/```mermaid\n([\s\S]*?)```/g, (match, code) => {
9431
9369
  return `
9432
9370
  \u{1F3A8} **Mermaid Diagram**
@@ -9736,7 +9674,7 @@ import Table4 from "cli-table3";
9736
9674
  import ora from "ora";
9737
9675
 
9738
9676
  // src/services/deps-detector.service.ts
9739
- import * as fs15 from "fs/promises";
9677
+ import * as fs14 from "fs/promises";
9740
9678
  import * as path8 from "path";
9741
9679
  var DepsDetectorService = class {
9742
9680
  /**
@@ -9804,7 +9742,7 @@ var DepsDetectorService = class {
9804
9742
  async detectLaravel(cwd) {
9805
9743
  try {
9806
9744
  const composerPath = path8.join(cwd, "composer.json");
9807
- const content = await fs15.readFile(composerPath, "utf-8");
9745
+ const content = await fs14.readFile(composerPath, "utf-8");
9808
9746
  const composerJson = JSON.parse(content);
9809
9747
  const deps = {
9810
9748
  ...composerJson.require,
@@ -9820,7 +9758,7 @@ var DepsDetectorService = class {
9820
9758
  */
9821
9759
  async fileExists(cwd, filename) {
9822
9760
  try {
9823
- await fs15.access(path8.join(cwd, filename));
9761
+ await fs14.access(path8.join(cwd, filename));
9824
9762
  return true;
9825
9763
  } catch {
9826
9764
  return false;
@@ -9829,7 +9767,7 @@ var DepsDetectorService = class {
9829
9767
  };
9830
9768
 
9831
9769
  // src/services/deps.service.ts
9832
- import { promises as fs16 } from "fs";
9770
+ import { promises as fs15 } from "fs";
9833
9771
  import path9 from "path";
9834
9772
  import { execSync } from "child_process";
9835
9773
  import pLimit2 from "p-limit";
@@ -9866,7 +9804,7 @@ var DepsService = class {
9866
9804
  async readPackageJson(cwd) {
9867
9805
  const pkgPath = path9.join(cwd, "package.json");
9868
9806
  try {
9869
- const content = await fs16.readFile(pkgPath, "utf-8");
9807
+ const content = await fs15.readFile(pkgPath, "utf-8");
9870
9808
  return JSON.parse(content);
9871
9809
  } catch (error) {
9872
9810
  if (error.code === "ENOENT") {
@@ -9957,7 +9895,7 @@ var DepsService = class {
9957
9895
  ];
9958
9896
  for (const { file, pm } of lockFiles) {
9959
9897
  try {
9960
- await fs16.access(path9.join(cwd, file));
9898
+ await fs15.access(path9.join(cwd, file));
9961
9899
  return pm;
9962
9900
  } catch {
9963
9901
  }
@@ -10028,7 +9966,7 @@ var DepsService = class {
10028
9966
 
10029
9967
  // src/services/deps-php.service.ts
10030
9968
  import { execSync as execSync2 } from "child_process";
10031
- import { promises as fs17 } from "fs";
9969
+ import { promises as fs16 } from "fs";
10032
9970
  import path10 from "path";
10033
9971
  var LARAVEL_PROTECTED_PACKAGES = /^laravel\//;
10034
9972
  var DepsPhpService = class {
@@ -10088,7 +10026,7 @@ var DepsPhpService = class {
10088
10026
  async readComposerJson(cwd) {
10089
10027
  const composerPath = path10.join(cwd, "composer.json");
10090
10028
  try {
10091
- const content = await fs17.readFile(composerPath, "utf-8");
10029
+ const content = await fs16.readFile(composerPath, "utf-8");
10092
10030
  return JSON.parse(content);
10093
10031
  } catch (error) {
10094
10032
  if (error.code === "ENOENT") {
@@ -10150,7 +10088,7 @@ var DepsPhpService = class {
10150
10088
 
10151
10089
  // src/services/deps-python.service.ts
10152
10090
  import { execSync as execSync3 } from "child_process";
10153
- import { promises as fs18 } from "fs";
10091
+ import { promises as fs17 } from "fs";
10154
10092
  import path11 from "path";
10155
10093
  import pLimit3 from "p-limit";
10156
10094
  var DepsPythonService = class {
@@ -10201,7 +10139,7 @@ var DepsPythonService = class {
10201
10139
  async checkPip(cwd, onProgress) {
10202
10140
  const requirementsPath = path11.join(cwd, "requirements.txt");
10203
10141
  try {
10204
- const content = await fs18.readFile(requirementsPath, "utf-8");
10142
+ const content = await fs17.readFile(requirementsPath, "utf-8");
10205
10143
  const packages = this.parseRequirementsTxt(content);
10206
10144
  return await this.fetchBulkVersions(packages, onProgress);
10207
10145
  } catch (error) {
@@ -10313,7 +10251,7 @@ var DepsPythonService = class {
10313
10251
  }
10314
10252
  async fileExists(cwd, filename) {
10315
10253
  try {
10316
- await fs18.access(path11.join(cwd, filename));
10254
+ await fs17.access(path11.join(cwd, filename));
10317
10255
  return true;
10318
10256
  } catch {
10319
10257
  return false;
@@ -11235,7 +11173,7 @@ function createDevCommand() {
11235
11173
  // src/commands/hooks/index.ts
11236
11174
  import { Command as Command57 } from "commander";
11237
11175
  import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, unlinkSync, chmodSync, mkdirSync } from "fs";
11238
- import { join as join9 } from "path";
11176
+ import { join as join8 } from "path";
11239
11177
  import { execSync as execSync4 } from "child_process";
11240
11178
  import chalk30 from "chalk";
11241
11179
  var MARKER_START = "# >>> jai1-hooks";
@@ -11280,7 +11218,7 @@ function getGitHooksDir() {
11280
11218
  encoding: "utf-8",
11281
11219
  stdio: ["pipe", "pipe", "pipe"]
11282
11220
  }).trim();
11283
- return join9(gitDir, "hooks");
11221
+ return join8(gitDir, "hooks");
11284
11222
  } catch {
11285
11223
  throw new Error("Th\u01B0 m\u1EE5c hi\u1EC7n t\u1EA1i kh\xF4ng ph\u1EA3i git repository. H\xE3y ch\u1EA1y l\u1EC7nh n\xE0y trong m\u1ED9t git repo.");
11286
11224
  }
@@ -11324,7 +11262,7 @@ function setupHooks() {
11324
11262
  let installed = 0;
11325
11263
  let skipped = 0;
11326
11264
  for (const def of HOOK_DEFINITIONS) {
11327
- const hookPath = join9(hooksDir, def.hookName);
11265
+ const hookPath = join8(hooksDir, def.hookName);
11328
11266
  const section = buildSection(def.script);
11329
11267
  try {
11330
11268
  if (existsSync3(hookPath)) {
@@ -11366,7 +11304,7 @@ function removeHooks() {
11366
11304
  const hooksDir = getGitHooksDir();
11367
11305
  let removed = 0;
11368
11306
  for (const def of HOOK_DEFINITIONS) {
11369
- const hookPath = join9(hooksDir, def.hookName);
11307
+ const hookPath = join8(hooksDir, def.hookName);
11370
11308
  if (!existsSync3(hookPath)) {
11371
11309
  continue;
11372
11310
  }
@@ -11418,23 +11356,123 @@ function createHooksCommand() {
11418
11356
  return cmd;
11419
11357
  }
11420
11358
 
11421
- // src/commands/tasks/index.ts
11422
- import { Command as Command71 } from "commander";
11359
+ // src/commands/settings/index.ts
11360
+ import { Command as Command61 } from "commander";
11423
11361
 
11424
- // src/commands/tasks/add.ts
11362
+ // src/commands/settings/init.ts
11425
11363
  import { Command as Command58 } from "commander";
11426
11364
  import chalk31 from "chalk";
11365
+ function createSettingsInitCommand() {
11366
+ return new Command58("init").description("T\u1EA1o .jai1/settings.yaml v\u1EDBi defaults").option("-f, --force", "Ghi \u0111\xE8 file c\u0169 n\u1EBFu \u0111\xE3 t\u1ED3n t\u1EA1i").option("-j, --json", "Output JSON").action(async (options) => {
11367
+ try {
11368
+ const service = new SettingsService();
11369
+ const settings = await service.init(options.force);
11370
+ if (options.json) {
11371
+ console.log(JSON.stringify({ success: true, path: service.getSettingsPath(), settings }, null, 2));
11372
+ return;
11373
+ }
11374
+ console.log(chalk31.green("\u2705 Settings initialized"));
11375
+ console.log(` ${chalk31.dim("Path:")} ${service.getSettingsPath()}`);
11376
+ } catch (error) {
11377
+ if (options.json) {
11378
+ console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }));
11379
+ } else {
11380
+ console.error(chalk31.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11381
+ }
11382
+ process.exit(1);
11383
+ }
11384
+ });
11385
+ }
11386
+
11387
+ // src/commands/settings/set.ts
11388
+ import { Command as Command59 } from "commander";
11389
+ import chalk32 from "chalk";
11390
+ function createSettingsSetCommand() {
11391
+ return new Command59("set").description("Set a setting value (dot-notation)").argument("<key>", "Setting key (e.g., tasks.cloud)").argument("<value>", "Setting value").option("-j, --json", "Output JSON").action(async (key, value, options) => {
11392
+ try {
11393
+ const service = new SettingsService();
11394
+ if (!service.exists()) {
11395
+ throw new Error("Settings file not found. Run `j settings init` first.");
11396
+ }
11397
+ const settings = await service.set(key, value);
11398
+ if (options.json) {
11399
+ console.log(JSON.stringify({ success: true, key, value: service.get(key), settings }, null, 2));
11400
+ return;
11401
+ }
11402
+ console.log(chalk32.green(`\u2705 ${key} = ${JSON.stringify(service.get(key))}`));
11403
+ } catch (error) {
11404
+ if (options.json) {
11405
+ console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }));
11406
+ } else {
11407
+ console.error(chalk32.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11408
+ }
11409
+ process.exit(1);
11410
+ }
11411
+ });
11412
+ }
11413
+
11414
+ // src/commands/settings/get.ts
11415
+ import { Command as Command60 } from "commander";
11416
+ import chalk33 from "chalk";
11417
+ function createSettingsGetCommand() {
11418
+ return new Command60("get").description("Get a setting value (dot-notation)").argument("<key>", "Setting key (e.g., tasks.cloud)").option("-j, --json", "Output JSON").action(async (key, options) => {
11419
+ try {
11420
+ const service = new SettingsService();
11421
+ const value = service.get(key);
11422
+ if (options.json) {
11423
+ console.log(JSON.stringify({ key, value }));
11424
+ return;
11425
+ }
11426
+ if (value === void 0) {
11427
+ console.log(chalk33.dim(`${key} is not set`));
11428
+ } else {
11429
+ console.log(`${chalk33.cyan(key)} = ${JSON.stringify(value)}`);
11430
+ }
11431
+ } catch (error) {
11432
+ if (options.json) {
11433
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
11434
+ } else {
11435
+ console.error(chalk33.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11436
+ }
11437
+ process.exit(1);
11438
+ }
11439
+ });
11440
+ }
11441
+
11442
+ // src/commands/settings/index.ts
11443
+ function createSettingsCommand() {
11444
+ const cmd = new Command61("settings").description("Project settings \u2014 manage .jai1/settings.yaml");
11445
+ cmd.addCommand(createSettingsShowCommand());
11446
+ cmd.addCommand(createSettingsInitCommand());
11447
+ cmd.addCommand(createSettingsSetCommand());
11448
+ cmd.addCommand(createSettingsGetCommand());
11449
+ cmd.action(async () => {
11450
+ const { createSettingsShowCommand: showCmd } = await import("./show-AJ5M3SKQ.js");
11451
+ const show = showCmd();
11452
+ await show.parseAsync([], { from: "user" });
11453
+ });
11454
+ return cmd;
11455
+ }
11456
+
11457
+ // src/commands/tasks/index.ts
11458
+ import { Command as Command75 } from "commander";
11459
+
11460
+ // src/commands/tasks/add.ts
11461
+ import { Command as Command62 } from "commander";
11462
+ import chalk34 from "chalk";
11427
11463
  function createTaskAddCommand() {
11428
- return new Command58("add").description("Add a new task").argument("<title>", "Task title").option("-p, --priority <n>", "Priority: 0=critical, 1=high, 2=medium, 3=low", "2").option("-P, --parent <parent>", "Parent: feature/xxx, bug/xxx, plan/xxx, task/xxx, prd/xxx").option("-t, --tags <tags>", "Comma-separated tags").option("-j, --json", "Output JSON").action(async (title, options) => {
11464
+ return new Command62("add").description("Add a new task").argument("<title>", "Task title").option("-p, --priority <n>", "Priority: 0=critical, 1=high, 2=medium, 3=low", "2").option("-P, --parent <parent>", "Parent: feature/xxx, bug/xxx, plan/xxx, task/xxx, prd/xxx").option("-t, --tags <tags>", "Comma-separated tags").option("--prompt", "Type: prompt \u2014 free-form instruction, no doc reference required").option("-j, --json", "Output JSON").action(async (title, options) => {
11429
11465
  const service = new TaskService();
11430
11466
  const priority = Number(options.priority ?? 2);
11431
11467
  if (priority < 0 || priority > 3) {
11432
- console.error(chalk31.red("\u274C Priority must be 0-3"));
11468
+ console.error(chalk34.red("\u274C Priority must be 0-3"));
11433
11469
  process.exit(1);
11434
11470
  }
11435
11471
  const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : [];
11472
+ const taskType = options.prompt ? "prompt" : "task";
11436
11473
  const task = await service.add({
11437
11474
  title,
11475
+ type: taskType,
11438
11476
  parent: options.parent || "",
11439
11477
  priority,
11440
11478
  tags
@@ -11445,23 +11483,24 @@ function createTaskAddCommand() {
11445
11483
  }
11446
11484
  const icon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
11447
11485
  const label = PRIORITY_LABELS[task.priority] || "Medium";
11448
- console.log(chalk31.green(`\u2705 Task added: ${chalk31.bold(task.id)}`));
11449
- console.log(` ${chalk31.dim("Title:")} ${task.title}`);
11450
- console.log(` ${chalk31.dim("Priority:")} ${icon} ${label}`);
11486
+ const typeLabel = task.type === "prompt" ? chalk34.magenta(" [prompt]") : "";
11487
+ console.log(chalk34.green(`\u2705 Task added: ${chalk34.bold(task.id)}${typeLabel}`));
11488
+ console.log(` ${chalk34.dim("Title:")} ${task.title}`);
11489
+ console.log(` ${chalk34.dim("Priority:")} ${icon} ${label}`);
11451
11490
  if (task.parent) {
11452
- console.log(` ${chalk31.dim("Parent:")} ${task.parent}`);
11491
+ console.log(` ${chalk34.dim("Parent:")} ${task.parent}`);
11453
11492
  }
11454
11493
  if (task.tags.length > 0) {
11455
- console.log(` ${chalk31.dim("Tags:")} ${task.tags.join(", ")}`);
11494
+ console.log(` ${chalk34.dim("Tags:")} ${task.tags.join(", ")}`);
11456
11495
  }
11457
11496
  });
11458
11497
  }
11459
11498
 
11460
11499
  // src/commands/tasks/list.ts
11461
- import { Command as Command59 } from "commander";
11462
- import chalk32 from "chalk";
11500
+ import { Command as Command63 } from "commander";
11501
+ import chalk35 from "chalk";
11463
11502
  function createTaskListCommand() {
11464
- return new Command59("list").alias("ls").description("List tasks").option("-s, --status <status>", "Filter by status: todo, in_progress, done, cancelled").option("-P, --parent <parent>", "Filter by parent: feature/xxx, plan/xxx").option("-j, --json", "Output JSON").action(async (options) => {
11503
+ return new Command63("list").alias("ls").description("List tasks").option("-s, --status <status>", "Filter by status: todo, in_progress, done, cancelled").option("-P, --parent <parent>", "Filter by parent: feature/xxx, plan/xxx").option("-j, --json", "Output JSON").action(async (options) => {
11465
11504
  await handleTaskList(options);
11466
11505
  });
11467
11506
  }
@@ -11480,12 +11519,12 @@ async function handleTaskList(options) {
11480
11519
  return;
11481
11520
  }
11482
11521
  if (tasks.length === 0) {
11483
- console.log(chalk32.dim("No tasks found."));
11522
+ console.log(chalk35.dim("No tasks found."));
11484
11523
  return;
11485
11524
  }
11486
11525
  const resolvedIds = new Set(allTasks.filter((t) => t.status === "done" || t.status === "cancelled").map((t) => t.id));
11487
11526
  const header = options.parent ? `\u{1F4CB} ${options.parent} (${tasks.length} tasks)` : `\u{1F4CB} All tasks (${tasks.length})`;
11488
- console.log(chalk32.bold(header));
11527
+ console.log(chalk35.bold(header));
11489
11528
  console.log();
11490
11529
  for (const task of tasks) {
11491
11530
  printTaskLine(task, resolvedIds);
@@ -11495,25 +11534,25 @@ function printTaskLine(task, resolvedIds) {
11495
11534
  const isBlocked = task.status === "todo" && task.depends_on.length > 0 && !task.depends_on.every((id) => resolvedIds.has(id));
11496
11535
  const statusIcon = isBlocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
11497
11536
  const priorityIcon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
11498
- let line = ` ${statusIcon} ${chalk32.dim(task.id)} P${task.priority}${priorityIcon} ${task.title}`;
11537
+ let line = ` ${statusIcon} ${chalk35.dim(task.id)} P${task.priority}${priorityIcon} ${task.title}`;
11499
11538
  if (task.status === "in_progress" && task.assigned_to) {
11500
- line += chalk32.cyan(` @${task.assigned_to}`);
11539
+ line += chalk35.cyan(` @${task.assigned_to}`);
11501
11540
  }
11502
11541
  if (isBlocked) {
11503
11542
  const blockedBy = task.depends_on.filter((id) => !resolvedIds.has(id));
11504
- line += chalk32.red(` (blocked: ${blockedBy.join(", ")})`);
11543
+ line += chalk35.red(` (blocked: ${blockedBy.join(", ")})`);
11505
11544
  }
11506
11545
  if (task.parent) {
11507
- line += chalk32.dim(` [${task.parent}]`);
11546
+ line += chalk35.dim(` [${task.parent}]`);
11508
11547
  }
11509
11548
  console.log(line);
11510
11549
  }
11511
11550
 
11512
11551
  // src/commands/tasks/ready.ts
11513
- import { Command as Command60 } from "commander";
11514
- import chalk33 from "chalk";
11552
+ import { Command as Command64 } from "commander";
11553
+ import chalk36 from "chalk";
11515
11554
  function createTaskReadyCommand() {
11516
- return new Command60("ready").description("Show tasks ready to pick (not blocked, not assigned)").option("-P, --parent <parent>", "Filter by parent").option("-j, --json", "Output JSON").action(async (options) => {
11555
+ return new Command64("ready").description("Show tasks ready to pick (not blocked, not assigned)").option("-P, --parent <parent>", "Filter by parent").option("-j, --json", "Output JSON").action(async (options) => {
11517
11556
  const service = new TaskService();
11518
11557
  const tasks = await service.getReady(options.parent);
11519
11558
  if (options.json) {
@@ -11521,37 +11560,37 @@ function createTaskReadyCommand() {
11521
11560
  return;
11522
11561
  }
11523
11562
  if (tasks.length === 0) {
11524
- console.log(chalk33.dim("No tasks ready to pick."));
11525
- console.log(chalk33.dim("\u{1F4A1} Check blocked tasks: jai1 t list -s todo"));
11563
+ console.log(chalk36.dim("No tasks ready to pick."));
11564
+ console.log(chalk36.dim("\u{1F4A1} Check blocked tasks: jai1 t list -s todo"));
11526
11565
  return;
11527
11566
  }
11528
- console.log(chalk33.bold(`\u{1F4CB} Ready to pick (${tasks.length} tasks):`));
11567
+ console.log(chalk36.bold(`\u{1F4CB} Ready to pick (${tasks.length} tasks):`));
11529
11568
  console.log();
11530
11569
  for (const task of tasks) {
11531
11570
  const icon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
11532
- let line = ` P${task.priority}${icon} ${chalk33.dim(task.id)} ${task.title}`;
11571
+ let line = ` P${task.priority}${icon} ${chalk36.dim(task.id)} ${task.title}`;
11533
11572
  if (task.parent) {
11534
- line += chalk33.dim(` [${task.parent}]`);
11573
+ line += chalk36.dim(` [${task.parent}]`);
11535
11574
  }
11536
11575
  console.log(line);
11537
11576
  }
11538
11577
  console.log();
11539
- console.log(chalk33.dim("\u{1F4A1} Run: jai1 t pick"));
11578
+ console.log(chalk36.dim("\u{1F4A1} Run: jai1 t pick"));
11540
11579
  });
11541
11580
  }
11542
11581
 
11543
11582
  // src/commands/tasks/update.ts
11544
- import { Command as Command61 } from "commander";
11545
- import chalk34 from "chalk";
11583
+ import { Command as Command65 } from "commander";
11584
+ import chalk37 from "chalk";
11546
11585
  var VALID_STATUSES = ["todo", "in_progress", "done", "cancelled"];
11547
11586
  function createTaskUpdateCommand() {
11548
- return new Command61("update").description("Update task status and/or notes").argument("<id>", "Task ID (e.g. T-001)").option("-s, --status <status>", "New status: todo, in_progress, done, cancelled").option("-n, --notes <notes>", 'Task notes (e.g. "files: a.ts, b.ts")').option("-j, --json", "Output JSON").action(async (id, options) => {
11587
+ return new Command65("update").description("Update task status and/or notes").argument("<id>", "Task ID (e.g. T-001)").option("-s, --status <status>", "New status: todo, in_progress, done, cancelled").option("-n, --notes <notes>", 'Task notes (e.g. "files: a.ts, b.ts")').option("-j, --json", "Output JSON").action(async (id, options) => {
11549
11588
  if (!options.status && !options.notes) {
11550
- console.error(chalk34.red("\u274C At least one of --status or --notes is required"));
11589
+ console.error(chalk37.red("\u274C At least one of --status or --notes is required"));
11551
11590
  process.exit(1);
11552
11591
  }
11553
11592
  if (options.status && !VALID_STATUSES.includes(options.status)) {
11554
- console.error(chalk34.red(`\u274C Invalid status. Must be: ${VALID_STATUSES.join(", ")}`));
11593
+ console.error(chalk37.red(`\u274C Invalid status. Must be: ${VALID_STATUSES.join(", ")}`));
11555
11594
  process.exit(1);
11556
11595
  }
11557
11596
  const service = new TaskService();
@@ -11561,8 +11600,8 @@ function createTaskUpdateCommand() {
11561
11600
  if (existingTask) {
11562
11601
  const { blocked, blockedBy } = await service.isBlocked(existingTask);
11563
11602
  if (blocked) {
11564
- console.log(chalk34.yellow(`\u26A0\uFE0F Task ${id} is blocked by: ${blockedBy.join(", ")}`));
11565
- console.log(chalk34.yellow(` Dependencies ch\u01B0a done. Ti\u1EBFp t\u1EE5c update...`));
11603
+ console.log(chalk37.yellow(`\u26A0\uFE0F Task ${id} is blocked by: ${blockedBy.join(", ")}`));
11604
+ console.log(chalk37.yellow(` Dependencies ch\u01B0a done. Ti\u1EBFp t\u1EE5c update...`));
11566
11605
  }
11567
11606
  }
11568
11607
  }
@@ -11582,24 +11621,24 @@ function createTaskUpdateCommand() {
11582
11621
  if (options.notes) {
11583
11622
  parts.push(`\u{1F4DD} notes updated`);
11584
11623
  }
11585
- console.log(chalk34.green(`\u2705 ${task.id} \u2192 ${parts.join(" | ")}`));
11624
+ console.log(chalk37.green(`\u2705 ${task.id} \u2192 ${parts.join(" | ")}`));
11586
11625
  } catch (error) {
11587
- console.error(chalk34.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11626
+ console.error(chalk37.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11588
11627
  process.exit(1);
11589
11628
  }
11590
11629
  });
11591
11630
  }
11592
11631
 
11593
11632
  // src/commands/tasks/show.ts
11594
- import { Command as Command62 } from "commander";
11595
- import chalk35 from "chalk";
11633
+ import { Command as Command66 } from "commander";
11634
+ import chalk38 from "chalk";
11596
11635
  function createTaskShowCommand() {
11597
- return new Command62("show").description("Show task detail or all tasks under a parent").argument("<query>", "Task ID (T-001) or parent (feature/xxx)").option("-j, --json", "Output JSON").action(async (query, options) => {
11636
+ return new Command66("show").description("Show task detail or all tasks under a parent").argument("<query>", "Task ID (T-001) or parent (feature/xxx)").option("-j, --json", "Output JSON").action(async (query, options) => {
11598
11637
  const service = new TaskService();
11599
11638
  if (query.startsWith("T-")) {
11600
11639
  const task = await service.findById(query);
11601
11640
  if (!task) {
11602
- console.error(chalk35.red(`\u274C Task ${query} not found`));
11641
+ console.error(chalk38.red(`\u274C Task ${query} not found`));
11603
11642
  process.exit(1);
11604
11643
  }
11605
11644
  if (options.json) {
@@ -11610,34 +11649,34 @@ function createTaskShowCommand() {
11610
11649
  const statusIcon = blocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
11611
11650
  const priIcon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
11612
11651
  const priLabel = PRIORITY_LABELS[task.priority] || "Medium";
11613
- console.log(chalk35.bold(`
11652
+ console.log(chalk38.bold(`
11614
11653
  \u{1F4CC} ${task.id}: ${task.title}
11615
11654
  `));
11616
- console.log(` ${chalk35.dim("Status:")} ${statusIcon} ${task.status}${blocked ? chalk35.red(" (BLOCKED)") : ""}`);
11617
- console.log(` ${chalk35.dim("Priority:")} ${priIcon} P${task.priority} ${priLabel}`);
11655
+ console.log(` ${chalk38.dim("Status:")} ${statusIcon} ${task.status}${blocked ? chalk38.red(" (BLOCKED)") : ""}`);
11656
+ console.log(` ${chalk38.dim("Priority:")} ${priIcon} P${task.priority} ${priLabel}`);
11618
11657
  if (task.parent) {
11619
- console.log(` ${chalk35.dim("Parent:")} ${task.parent}`);
11658
+ console.log(` ${chalk38.dim("Parent:")} ${task.parent}`);
11620
11659
  }
11621
11660
  if (task.assigned_to) {
11622
- console.log(` ${chalk35.dim("Assigned:")} @${task.assigned_to} (${task.claimed_at})`);
11661
+ console.log(` ${chalk38.dim("Assigned:")} @${task.assigned_to} (${task.claimed_at})`);
11623
11662
  }
11624
11663
  if (task.depends_on.length > 0) {
11625
- console.log(` ${chalk35.dim("Depends on:")} ${task.depends_on.join(", ")}`);
11664
+ console.log(` ${chalk38.dim("Depends on:")} ${task.depends_on.join(", ")}`);
11626
11665
  if (blocked) {
11627
- console.log(` ${chalk35.dim("Blocked by:")} ${chalk35.red(blockedBy.join(", "))}`);
11666
+ console.log(` ${chalk38.dim("Blocked by:")} ${chalk38.red(blockedBy.join(", "))}`);
11628
11667
  }
11629
11668
  }
11630
11669
  if (task.tags.length > 0) {
11631
- console.log(` ${chalk35.dim("Tags:")} ${task.tags.join(", ")}`);
11670
+ console.log(` ${chalk38.dim("Tags:")} ${task.tags.join(", ")}`);
11632
11671
  }
11633
11672
  if (task.branch) {
11634
- console.log(` ${chalk35.dim("Branch:")} ${task.branch}`);
11673
+ console.log(` ${chalk38.dim("Branch:")} ${task.branch}`);
11635
11674
  }
11636
11675
  if (task.notes) {
11637
- console.log(` ${chalk35.dim("Notes:")} ${task.notes}`);
11676
+ console.log(` ${chalk38.dim("Notes:")} ${task.notes}`);
11638
11677
  }
11639
- console.log(` ${chalk35.dim("Created:")} ${task.created}`);
11640
- console.log(` ${chalk35.dim("Updated:")} ${task.updated}`);
11678
+ console.log(` ${chalk38.dim("Created:")} ${task.created}`);
11679
+ console.log(` ${chalk38.dim("Updated:")} ${task.updated}`);
11641
11680
  console.log();
11642
11681
  } else {
11643
11682
  const tasks = await service.filter({ parent: query });
@@ -11646,10 +11685,10 @@ function createTaskShowCommand() {
11646
11685
  return;
11647
11686
  }
11648
11687
  if (tasks.length === 0) {
11649
- console.log(chalk35.dim(`No tasks for parent: ${query}`));
11688
+ console.log(chalk38.dim(`No tasks for parent: ${query}`));
11650
11689
  return;
11651
11690
  }
11652
- console.log(chalk35.bold(`
11691
+ console.log(chalk38.bold(`
11653
11692
  \u{1F4CB} ${query} (${tasks.length} tasks)
11654
11693
  `));
11655
11694
  const allTasks = await service.readAll();
@@ -11657,11 +11696,11 @@ function createTaskShowCommand() {
11657
11696
  for (const task of tasks) {
11658
11697
  const isBlocked = task.status === "todo" && task.depends_on.length > 0 && !task.depends_on.every((id) => doneIds.has(id));
11659
11698
  const icon = isBlocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
11660
- let line = ` ${icon} ${chalk35.dim(task.id)} P${task.priority} ${task.title}`;
11661
- if (task.assigned_to) line += chalk35.cyan(` @${task.assigned_to}`);
11699
+ let line = ` ${icon} ${chalk38.dim(task.id)} P${task.priority} ${task.title}`;
11700
+ if (task.assigned_to) line += chalk38.cyan(` @${task.assigned_to}`);
11662
11701
  if (isBlocked) {
11663
11702
  const bb = task.depends_on.filter((id) => !doneIds.has(id));
11664
- line += chalk35.red(` (blocked: ${bb.join(", ")})`);
11703
+ line += chalk38.red(` (blocked: ${bb.join(", ")})`);
11665
11704
  }
11666
11705
  console.log(line);
11667
11706
  }
@@ -11671,11 +11710,11 @@ function createTaskShowCommand() {
11671
11710
  }
11672
11711
 
11673
11712
  // src/commands/tasks/pick.ts
11674
- import { Command as Command63 } from "commander";
11675
- import chalk36 from "chalk";
11713
+ import { Command as Command67 } from "commander";
11714
+ import chalk39 from "chalk";
11676
11715
  import { confirm as confirm11 } from "@inquirer/prompts";
11677
11716
  function createTaskPickCommand() {
11678
- return new Command63("pick").description("Claim the next available task").option("-j, --json", "Output JSON").action(async (options) => {
11717
+ return new Command67("pick").description("Claim the next available task").option("-j, --json", "Output JSON").action(async (options) => {
11679
11718
  const service = new TaskService();
11680
11719
  const ready = await service.getReady();
11681
11720
  if (ready.length === 0) {
@@ -11683,8 +11722,8 @@ function createTaskPickCommand() {
11683
11722
  console.log(JSON.stringify({ picked: null, message: "No tasks ready" }));
11684
11723
  return;
11685
11724
  }
11686
- console.log(chalk36.dim("No tasks ready to pick."));
11687
- console.log(chalk36.dim('\u{1F4A1} Add tasks first: jai1 t add "..."'));
11725
+ console.log(chalk39.dim("No tasks ready to pick."));
11726
+ console.log(chalk39.dim('\u{1F4A1} Add tasks first: jai1 t add "..."'));
11688
11727
  return;
11689
11728
  }
11690
11729
  const top = ready[0];
@@ -11694,13 +11733,13 @@ function createTaskPickCommand() {
11694
11733
  console.log(JSON.stringify(picked2, null, 2));
11695
11734
  return;
11696
11735
  }
11697
- console.log(chalk36.bold("\n\u{1F4CC} Next available task:"));
11698
- console.log(` ${chalk36.bold(top.id)} P${top.priority}${icon} ${top.title}`);
11736
+ console.log(chalk39.bold("\n\u{1F4CC} Next available task:"));
11737
+ console.log(` ${chalk39.bold(top.id)} P${top.priority}${icon} ${top.title}`);
11699
11738
  if (top.parent) {
11700
- console.log(` ${chalk36.dim("Parent:")} ${top.parent}`);
11739
+ console.log(` ${chalk39.dim("Parent:")} ${top.parent}`);
11701
11740
  }
11702
11741
  if (ready.length > 1) {
11703
- console.log(chalk36.dim(`
11742
+ console.log(chalk39.dim(`
11704
11743
  +${ready.length - 1} more tasks ready`));
11705
11744
  }
11706
11745
  const proceed = await confirm11({
@@ -11708,20 +11747,20 @@ function createTaskPickCommand() {
11708
11747
  default: true
11709
11748
  });
11710
11749
  if (!proceed) {
11711
- console.log(chalk36.dim("\nCancelled."));
11750
+ console.log(chalk39.dim("\nCancelled."));
11712
11751
  return;
11713
11752
  }
11714
11753
  const picked = await service.pick(top.id);
11715
- console.log(chalk36.green(`
11754
+ console.log(chalk39.green(`
11716
11755
  \u2705 ${picked.id} assigned to @${picked.assigned_to}, status \u2192 in_progress`));
11717
11756
  });
11718
11757
  }
11719
11758
 
11720
11759
  // src/commands/tasks/done.ts
11721
- import { Command as Command64 } from "commander";
11722
- import chalk37 from "chalk";
11760
+ import { Command as Command68 } from "commander";
11761
+ import chalk40 from "chalk";
11723
11762
  function createTaskDoneCommand() {
11724
- return new Command64("done").description("Mark task as done").argument("<id>", "Task ID (e.g. T-001)").option("-j, --json", "Output JSON").action(async (id, options) => {
11763
+ return new Command68("done").description("Mark task as done").argument("<id>", "Task ID (e.g. T-001)").option("-j, --json", "Output JSON").action(async (id, options) => {
11725
11764
  const service = new TaskService();
11726
11765
  try {
11727
11766
  const task = await service.markDone(id);
@@ -11729,19 +11768,19 @@ function createTaskDoneCommand() {
11729
11768
  console.log(JSON.stringify(task, null, 2));
11730
11769
  return;
11731
11770
  }
11732
- console.log(chalk37.green(`\u2705 ${task.id}: ${task.title} \u2192 done`));
11771
+ console.log(chalk40.green(`\u2705 ${task.id}: ${task.title} \u2192 done`));
11733
11772
  } catch (error) {
11734
- console.error(chalk37.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11773
+ console.error(chalk40.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11735
11774
  process.exit(1);
11736
11775
  }
11737
11776
  });
11738
11777
  }
11739
11778
 
11740
11779
  // src/commands/tasks/dep.ts
11741
- import { Command as Command65 } from "commander";
11742
- import chalk38 from "chalk";
11780
+ import { Command as Command69 } from "commander";
11781
+ import chalk41 from "chalk";
11743
11782
  function createTaskDepCommand() {
11744
- return new Command65("dep").description("Add dependency: child depends on parent").argument("<childId>", "Child task ID (the one that waits)").argument("<parentId>", "Parent task ID (must be done first)").option("-j, --json", "Output JSON").action(async (childId, parentId, options) => {
11783
+ return new Command69("dep").description("Add dependency: child depends on parent").argument("<childId>", "Child task ID (the one that waits)").argument("<parentId>", "Parent task ID (must be done first)").option("-j, --json", "Output JSON").action(async (childId, parentId, options) => {
11745
11784
  const service = new TaskService();
11746
11785
  try {
11747
11786
  const task = await service.addDependency(childId, parentId);
@@ -11749,138 +11788,203 @@ function createTaskDepCommand() {
11749
11788
  console.log(JSON.stringify(task, null, 2));
11750
11789
  return;
11751
11790
  }
11752
- console.log(chalk38.green(`\u2705 ${childId} now depends on ${parentId}`));
11753
- console.log(chalk38.dim(` ${task.title} \u2192 waits for ${parentId}`));
11791
+ console.log(chalk41.green(`\u2705 ${childId} now depends on ${parentId}`));
11792
+ console.log(chalk41.dim(` ${task.title} \u2192 waits for ${parentId}`));
11754
11793
  } catch (error) {
11755
- console.error(chalk38.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11794
+ console.error(chalk41.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11756
11795
  process.exit(1);
11757
11796
  }
11758
11797
  });
11759
11798
  }
11760
11799
 
11761
11800
  // src/commands/tasks/sync.ts
11762
- import { Command as Command66 } from "commander";
11763
- import chalk39 from "chalk";
11801
+ import { Command as Command70 } from "commander";
11802
+ import chalk42 from "chalk";
11764
11803
  function createTaskSyncCommand() {
11765
- return new Command66("sync").description("Sync tasks via git (t\u1EA1m th\u1EDDi b\u1ECB disable)").option("--pull", "Pull only: merge tasks from origin/jai1").option("--push", "Push only: commit and push tasks to origin/jai1").action(async () => {
11766
- console.log(chalk39.yellow("\u26A0\uFE0F Ch\u1EE9c n\u0103ng `j t sync` t\u1EA1m th\u1EDDi b\u1ECB disable."));
11804
+ return new Command70("sync").description("Sync tasks between cloud and local (requires tasks.cloud = true)").option("--pull", "Pull: cloud \u2192 local (replaces tasks.jsonl)").option("--push", "Push: local \u2192 cloud (upserts all)").option("-j, --json", "Output JSON").action(async (options) => {
11805
+ const settings = new SettingsService();
11806
+ if (!settings.isTaskCloudEnabled()) {
11807
+ console.error(chalk42.red("\u274C tasks.cloud is not enabled in .jai1/settings.yaml"));
11808
+ console.error(chalk42.dim(" Run: j settings set tasks.cloud true"));
11809
+ process.exit(1);
11810
+ }
11811
+ const service = new TaskService();
11812
+ await service._providerReady;
11813
+ if (!service.isCloud) {
11814
+ console.error(chalk42.red("\u274C Cloud provider failed to initialize."));
11815
+ console.error(chalk42.dim(" Check that you are logged in: j auth"));
11816
+ process.exit(1);
11817
+ }
11818
+ const doPull = options.pull || !options.pull && !options.push;
11819
+ const doPush = options.push || !options.pull && !options.push;
11820
+ const isFull = doPull && doPush;
11821
+ if (isFull) {
11822
+ console.log(chalk42.bold("\u{1F504} Full sync: merging cloud \u2194 local..."));
11823
+ } else if (doPull) {
11824
+ console.log(chalk42.bold("\u2B07\uFE0F Pull: cloud \u2192 local..."));
11825
+ } else {
11826
+ console.log(chalk42.bold("\u2B06\uFE0F Push: local \u2192 cloud..."));
11827
+ }
11828
+ try {
11829
+ if (doPull) {
11830
+ const cloudTasks = await service.cloud.pull();
11831
+ console.log(chalk42.dim(` \u2193 ${cloudTasks.length} tasks fetched from cloud`));
11832
+ if (isFull) {
11833
+ const localTasks = await service.readAll();
11834
+ const localMap = new Map(localTasks.map((t) => [t.id, t]));
11835
+ const cloudMap = new Map(cloudTasks.map((t) => [t.id, t]));
11836
+ const merged = /* @__PURE__ */ new Map();
11837
+ for (const [id, local] of localMap) merged.set(id, local);
11838
+ for (const [id, cloud] of cloudMap) {
11839
+ const local = merged.get(id);
11840
+ if (!local || cloud.updated > local.updated) {
11841
+ merged.set(id, cloud);
11842
+ }
11843
+ }
11844
+ for (const [id, cloud] of cloudMap) {
11845
+ if (!localMap.has(id)) merged.set(id, cloud);
11846
+ }
11847
+ const mergedList = Array.from(merged.values());
11848
+ await service.writeAll(mergedList);
11849
+ console.log(chalk42.green(`\u2705 Merged: ${mergedList.length} tasks`));
11850
+ console.log(chalk42.dim(` \u2191 Pushing merged tasks to cloud...`));
11851
+ await service.cloud.push(mergedList);
11852
+ console.log(chalk42.green(`\u2705 Full sync complete`));
11853
+ } else {
11854
+ await service.writeAll(cloudTasks);
11855
+ console.log(chalk42.green(`\u2705 Pull complete: ${cloudTasks.length} tasks written`));
11856
+ }
11857
+ } else if (doPush) {
11858
+ const localTasks = await service.readAll();
11859
+ await service.cloud.push(localTasks);
11860
+ console.log(chalk42.green(`\u2705 Push complete: ${localTasks.length} tasks uploaded`));
11861
+ }
11862
+ } catch (error) {
11863
+ const msg = error instanceof Error ? error.message : String(error);
11864
+ if (options.json) {
11865
+ console.log(JSON.stringify({ success: false, error: msg }));
11866
+ } else {
11867
+ console.error(chalk42.red(`\u274C Sync failed: ${msg}`));
11868
+ }
11869
+ process.exit(1);
11870
+ }
11767
11871
  });
11768
11872
  }
11769
11873
 
11770
11874
  // src/commands/tasks/guide.ts
11771
- import { Command as Command67 } from "commander";
11772
- import chalk40 from "chalk";
11875
+ import { Command as Command71 } from "commander";
11876
+ import chalk43 from "chalk";
11773
11877
  var GUIDE_TEXT = `
11774
- ${chalk40.cyan.bold("\u{1F4D6} Jai1 Task Management Guide")}
11775
-
11776
- ${chalk40.bold("\u2501\u2501\u2501 STATUSES \u2501\u2501\u2501")}
11777
- ${chalk40.dim("todo")} \u{1F4CB} Ch\u01B0a b\u1EAFt \u0111\u1EA7u
11778
- ${chalk40.dim("in_progress")} \u{1F535} \u0110ang l\xE0m (bao g\u1ED3m review)
11779
- ${chalk40.dim("done")} \u2705 Ho\xE0n th\xE0nh
11780
- ${chalk40.dim("cancelled")} \u26AB Hu\u1EF7
11781
- ${chalk40.dim("(blocked)")} \u{1F534} Computed: depends_on ch\u01B0a done
11782
-
11783
- ${chalk40.bold("\u2501\u2501\u2501 PRIORITY \u2501\u2501\u2501")}
11784
- ${chalk40.dim("0")} = \u{1F525} Critical \u2014 Prod down, security, block c\u1EA3 team
11785
- ${chalk40.dim("1")} = \u{1F534} High \u2014 Feature ch\xEDnh, deadline g\u1EA7n
11786
- ${chalk40.dim("2")} = \u{1F7E1} Medium \u2014 B\xECnh th\u01B0\u1EDDng (default)
11787
- ${chalk40.dim("3")} = \u{1F7E2} Low \u2014 Nice-to-have, docs, refactor
11788
-
11789
- ${chalk40.bold("\u2501\u2501\u2501 QUICK START \u2501\u2501\u2501")}
11790
- ${chalk40.cyan("jai1 t add")} "Fix login bug" -p 1 -P bug/login
11791
- ${chalk40.cyan("jai1 t ready")} Show tasks s\u1EB5n s\xE0ng
11792
- ${chalk40.cyan("jai1 t pick")} Claim & start working
11793
- ${chalk40.cyan("jai1 t done")} T-003 Mark complete
11794
-
11795
- ${chalk40.bold("\u2501\u2501\u2501 DAILY WORKFLOW \u2501\u2501\u2501")}
11796
- ${chalk40.cyan("jai1 t sync --pull")} Pull latest tasks
11797
- ${chalk40.cyan("jai1 t summary")} Dashboard t\u1ED5ng quan
11798
- ${chalk40.cyan("jai1 t ready")} Xem tasks s\u1EB5n s\xE0ng
11799
- ${chalk40.cyan("jai1 t pick")} Claim task m\u1EDBi
11800
- ${chalk40.cyan("jai1 t done")} T-xxx Ho\xE0n th\xE0nh task
11801
- ${chalk40.cyan("jai1 t sync --push")} Push l\xEAn git
11802
-
11803
- ${chalk40.bold("\u2501\u2501\u2501 ADDING TASKS \u2501\u2501\u2501")}
11804
- ${chalk40.yellow("\u26A0 Lu\xF4n ki\u1EC3m tra duplicate tr\u01B0\u1EDBc khi add:")}
11805
- ${chalk40.cyan("jai1 t list -P")} feature/xxx
11806
-
11807
- ${chalk40.dim("Add cho feature:")}
11808
- ${chalk40.cyan("jai1 t add")} "Setup DB schema" -p 1 -P feature/xxx
11809
- ${chalk40.cyan("jai1 t add")} "Create API" -p 1 -P feature/xxx
11810
- ${chalk40.cyan("jai1 t add")} "Build UI" -p 2 -P feature/xxx
11811
-
11812
- ${chalk40.dim("Add cho plan:")}
11813
- ${chalk40.cyan("jai1 t add")} "Refactor middleware" -p 2 -P plan/xxx
11814
-
11815
- ${chalk40.dim("Add standalone:")}
11816
- ${chalk40.cyan("jai1 t add")} "Fix README typo" -p 3
11817
-
11818
- ${chalk40.dim("Add bug fix:")}
11819
- ${chalk40.cyan("jai1 t add")} "Fix login redirect" -p 1 -P bug/xxx
11820
-
11821
- ${chalk40.bold("\u2501\u2501\u2501 DEPENDENCY \u2501\u2501\u2501")}
11822
- ${chalk40.dim("Task dependency:")}
11823
- ${chalk40.cyan("jai1 t dep")} T-002 T-001 T-002 ch\u1EDD T-001 done
11824
- ${chalk40.cyan("jai1 t dep")} T-003 T-002 T-003 ch\u1EDD T-002 done
11825
-
11826
- ${chalk40.dim("Feature-level dependency:")}
11827
- ${chalk40.dim("# N\u1EBFu feature/auth ph\u1EE5 thu\u1ED9c feature/user-model:")}
11828
- ${chalk40.cyan("jai1 t add")} "[DEP] Wait for feature/user-model" -p 1 -P feature/auth
11829
- ${chalk40.dim("# R\u1ED3i dep n\xF3 v\u1EDBi tasks cu\u1ED1i c\u1EE7a user-model")}
11830
-
11831
- ${chalk40.dim("View deps:")}
11832
- ${chalk40.cyan("jai1 t show")} T-002 Hi\u1EC7n depends_on
11833
-
11834
- ${chalk40.bold("\u2501\u2501\u2501 TEAM COLLABORATION \u2501\u2501\u2501")}
11835
- ${chalk40.yellow("\u26A0 Assignment ch\u1EC9 qua pick \u2014 kh\xF4ng set th\u1EE7 c\xF4ng.")}
11836
- ${chalk40.dim("Khi b\u1EA1n pick \u2192 team th\u1EA5y task \u0111\xE3 c\xF3 ng\u01B0\u1EDDi nh\u1EADn.")}
11837
-
11838
- ${chalk40.dim("Sync morning:")} ${chalk40.cyan("jai1 t sync --pull")}
11839
- ${chalk40.dim("Sync evening:")} ${chalk40.cyan("jai1 t sync --push")}
11840
-
11841
- ${chalk40.bold("\u2501\u2501\u2501 FOR AI AGENTS (Workflow Integration) \u2501\u2501\u2501")}
11842
- ${chalk40.dim("Khi t\u1EA1o tasks t\u1EEB feature/plan:")}
11843
- 1. ${chalk40.cyan("jai1 t list -P")} <parent> Check existing (tr\xE1nh duplicate)
11844
- 2. ${chalk40.cyan("jai1 t add")} "..." -p <0-3> -P <parent> Add t\u1EEBng task
11845
- 3. ${chalk40.cyan("jai1 t dep")} <child> <parent> Set dependencies
11846
- 4. ${chalk40.cyan("jai1 t done")} <id> Mark complete
11847
-
11848
- ${chalk40.dim("Khi implement task ti\u1EBFp theo:")}
11849
- 1. ${chalk40.cyan("jai1 t pick")} (ho\u1EB7c ${chalk40.cyan("jai1 t ready -P")} <parent>)
11878
+ ${chalk43.cyan.bold("\u{1F4D6} Jai1 Task Management Guide")}
11879
+
11880
+ ${chalk43.bold("\u2501\u2501\u2501 STATUSES \u2501\u2501\u2501")}
11881
+ ${chalk43.dim("todo")} \u{1F4CB} Ch\u01B0a b\u1EAFt \u0111\u1EA7u
11882
+ ${chalk43.dim("in_progress")} \u{1F535} \u0110ang l\xE0m (bao g\u1ED3m review)
11883
+ ${chalk43.dim("done")} \u2705 Ho\xE0n th\xE0nh
11884
+ ${chalk43.dim("cancelled")} \u26AB Hu\u1EF7
11885
+ ${chalk43.dim("(blocked)")} \u{1F534} Computed: depends_on ch\u01B0a done
11886
+
11887
+ ${chalk43.bold("\u2501\u2501\u2501 PRIORITY \u2501\u2501\u2501")}
11888
+ ${chalk43.dim("0")} = \u{1F525} Critical \u2014 Prod down, security, block c\u1EA3 team
11889
+ ${chalk43.dim("1")} = \u{1F534} High \u2014 Feature ch\xEDnh, deadline g\u1EA7n
11890
+ ${chalk43.dim("2")} = \u{1F7E1} Medium \u2014 B\xECnh th\u01B0\u1EDDng (default)
11891
+ ${chalk43.dim("3")} = \u{1F7E2} Low \u2014 Nice-to-have, docs, refactor
11892
+
11893
+ ${chalk43.bold("\u2501\u2501\u2501 QUICK START \u2501\u2501\u2501")}
11894
+ ${chalk43.cyan("jai1 t add")} "Fix login bug" -p 1 -P bug/login
11895
+ ${chalk43.cyan("jai1 t ready")} Show tasks s\u1EB5n s\xE0ng
11896
+ ${chalk43.cyan("jai1 t pick")} Claim & start working
11897
+ ${chalk43.cyan("jai1 t done")} T-003 Mark complete
11898
+
11899
+ ${chalk43.bold("\u2501\u2501\u2501 DAILY WORKFLOW \u2501\u2501\u2501")}
11900
+ ${chalk43.cyan("jai1 t sync --pull")} Pull latest tasks
11901
+ ${chalk43.cyan("jai1 t summary")} Dashboard t\u1ED5ng quan
11902
+ ${chalk43.cyan("jai1 t ready")} Xem tasks s\u1EB5n s\xE0ng
11903
+ ${chalk43.cyan("jai1 t pick")} Claim task m\u1EDBi
11904
+ ${chalk43.cyan("jai1 t done")} T-xxx Ho\xE0n th\xE0nh task
11905
+ ${chalk43.cyan("jai1 t sync --push")} Push l\xEAn git
11906
+
11907
+ ${chalk43.bold("\u2501\u2501\u2501 ADDING TASKS \u2501\u2501\u2501")}
11908
+ ${chalk43.yellow("\u26A0 Lu\xF4n ki\u1EC3m tra duplicate tr\u01B0\u1EDBc khi add:")}
11909
+ ${chalk43.cyan("jai1 t list -P")} feature/xxx
11910
+
11911
+ ${chalk43.dim("Add cho feature:")}
11912
+ ${chalk43.cyan("jai1 t add")} "Setup DB schema" -p 1 -P feature/xxx
11913
+ ${chalk43.cyan("jai1 t add")} "Create API" -p 1 -P feature/xxx
11914
+ ${chalk43.cyan("jai1 t add")} "Build UI" -p 2 -P feature/xxx
11915
+
11916
+ ${chalk43.dim("Add cho plan:")}
11917
+ ${chalk43.cyan("jai1 t add")} "Refactor middleware" -p 2 -P plan/xxx
11918
+
11919
+ ${chalk43.dim("Add standalone:")}
11920
+ ${chalk43.cyan("jai1 t add")} "Fix README typo" -p 3
11921
+
11922
+ ${chalk43.dim("Add bug fix:")}
11923
+ ${chalk43.cyan("jai1 t add")} "Fix login redirect" -p 1 -P bug/xxx
11924
+
11925
+ ${chalk43.bold("\u2501\u2501\u2501 DEPENDENCY \u2501\u2501\u2501")}
11926
+ ${chalk43.dim("Task dependency:")}
11927
+ ${chalk43.cyan("jai1 t dep")} T-002 T-001 T-002 ch\u1EDD T-001 done
11928
+ ${chalk43.cyan("jai1 t dep")} T-003 T-002 T-003 ch\u1EDD T-002 done
11929
+
11930
+ ${chalk43.dim("Feature-level dependency:")}
11931
+ ${chalk43.dim("# N\u1EBFu feature/auth ph\u1EE5 thu\u1ED9c feature/user-model:")}
11932
+ ${chalk43.cyan("jai1 t add")} "[DEP] Wait for feature/user-model" -p 1 -P feature/auth
11933
+ ${chalk43.dim("# R\u1ED3i dep n\xF3 v\u1EDBi tasks cu\u1ED1i c\u1EE7a user-model")}
11934
+
11935
+ ${chalk43.dim("View deps:")}
11936
+ ${chalk43.cyan("jai1 t show")} T-002 Hi\u1EC7n depends_on
11937
+
11938
+ ${chalk43.bold("\u2501\u2501\u2501 TEAM COLLABORATION \u2501\u2501\u2501")}
11939
+ ${chalk43.yellow("\u26A0 Assignment ch\u1EC9 qua pick \u2014 kh\xF4ng set th\u1EE7 c\xF4ng.")}
11940
+ ${chalk43.dim("Khi b\u1EA1n pick \u2192 team th\u1EA5y task \u0111\xE3 c\xF3 ng\u01B0\u1EDDi nh\u1EADn.")}
11941
+
11942
+ ${chalk43.dim("Sync morning:")} ${chalk43.cyan("jai1 t sync --pull")}
11943
+ ${chalk43.dim("Sync evening:")} ${chalk43.cyan("jai1 t sync --push")}
11944
+
11945
+ ${chalk43.bold("\u2501\u2501\u2501 FOR AI AGENTS (Workflow Integration) \u2501\u2501\u2501")}
11946
+ ${chalk43.dim("Khi t\u1EA1o tasks t\u1EEB feature/plan:")}
11947
+ 1. ${chalk43.cyan("jai1 t list -P")} <parent> Check existing (tr\xE1nh duplicate)
11948
+ 2. ${chalk43.cyan("jai1 t add")} "..." -p <0-3> -P <parent> Add t\u1EEBng task
11949
+ 3. ${chalk43.cyan("jai1 t dep")} <child> <parent> Set dependencies
11950
+ 4. ${chalk43.cyan("jai1 t done")} <id> Mark complete
11951
+
11952
+ ${chalk43.dim("Khi implement task ti\u1EBFp theo:")}
11953
+ 1. ${chalk43.cyan("jai1 t pick")} (ho\u1EB7c ${chalk43.cyan("jai1 t ready -P")} <parent>)
11850
11954
  2. Implement task
11851
- 3. ${chalk40.cyan("jai1 t done")} <id>
11955
+ 3. ${chalk43.cyan("jai1 t done")} <id>
11852
11956
 
11853
- ${chalk40.dim("Status transitions:")}
11957
+ ${chalk43.dim("Status transitions:")}
11854
11958
  add \u2192 todo (default)
11855
11959
  pick \u2192 in_progress (auto assign)
11856
11960
  done \u2192 done
11857
11961
  update -s \u2192 any valid status
11858
11962
 
11859
- ${chalk40.bold("\u2501\u2501\u2501 ALL COMMANDS \u2501\u2501\u2501")}
11860
- ${chalk40.cyan("jai1 t list")} [-s status] [-P parent] [-j]
11861
- ${chalk40.cyan("jai1 t ready")} [-P parent] [-j]
11862
- ${chalk40.cyan("jai1 t add")} <title> [-p 0-3] [-P parent] [-t tags] [-j]
11863
- ${chalk40.cyan("jai1 t update")} <id> [-s <status>] [-n <notes>] [-j]
11864
- ${chalk40.cyan("jai1 t show")} <id|parent> [-j]
11865
- ${chalk40.cyan("jai1 t pick")} [-j]
11866
- ${chalk40.cyan("jai1 t done")} <id> [-j]
11867
- ${chalk40.cyan("jai1 t dep")} <childId> <parentId> [-j]
11868
- ${chalk40.cyan("jai1 t sync")} [--pull] [--push]
11869
- ${chalk40.cyan("jai1 t summary")} [-j]
11870
- ${chalk40.cyan("jai1 t groups")} [-s status] [-j] ${chalk40.dim("(alias: parents)")}
11871
- ${chalk40.cyan("jai1 t guide")}
11872
-
11873
- ${chalk40.dim("-j / --json available on all commands (except guide, sync)")}
11963
+ ${chalk43.bold("\u2501\u2501\u2501 ALL COMMANDS \u2501\u2501\u2501")}
11964
+ ${chalk43.cyan("jai1 t list")} [-s status] [-P parent] [-j]
11965
+ ${chalk43.cyan("jai1 t ready")} [-P parent] [-j]
11966
+ ${chalk43.cyan("jai1 t add")} <title> [-p 0-3] [-P parent] [-t tags] [-j]
11967
+ ${chalk43.cyan("jai1 t update")} <id> [-s <status>] [-n <notes>] [-j]
11968
+ ${chalk43.cyan("jai1 t show")} <id|parent> [-j]
11969
+ ${chalk43.cyan("jai1 t pick")} [-j]
11970
+ ${chalk43.cyan("jai1 t done")} <id> [-j]
11971
+ ${chalk43.cyan("jai1 t dep")} <childId> <parentId> [-j]
11972
+ ${chalk43.cyan("jai1 t sync")} [--pull] [--push]
11973
+ ${chalk43.cyan("jai1 t summary")} [-j]
11974
+ ${chalk43.cyan("jai1 t groups")} [-s status] [-j] ${chalk43.dim("(alias: parents)")}
11975
+ ${chalk43.cyan("jai1 t guide")}
11976
+
11977
+ ${chalk43.dim("-j / --json available on all commands (except guide, sync)")}
11874
11978
  `;
11875
11979
  function createTaskGuideCommand() {
11876
- return new Command67("guide").description("Show full task management guide").action(() => {
11980
+ return new Command71("guide").description("Show full task management guide").action(() => {
11877
11981
  console.log(GUIDE_TEXT);
11878
11982
  });
11879
11983
  }
11880
11984
 
11881
11985
  // src/commands/tasks/parents.ts
11882
- import { Command as Command68 } from "commander";
11883
- import chalk41 from "chalk";
11986
+ import { Command as Command72 } from "commander";
11987
+ import chalk44 from "chalk";
11884
11988
  var PARENT_STATUS_ICONS = {
11885
11989
  done: "\u2705",
11886
11990
  in_progress: "\u{1F535}",
@@ -11890,17 +11994,17 @@ var PARENT_STATUS_ICONS = {
11890
11994
  function formatProgress(p) {
11891
11995
  const completed = p.done + p.cancelled;
11892
11996
  if (p.status === "done") {
11893
- return chalk41.green(`${completed}/${p.total} done`);
11997
+ return chalk44.green(`${completed}/${p.total} done`);
11894
11998
  }
11895
11999
  const parts = [];
11896
12000
  if (p.in_progress > 0) parts.push(`${p.in_progress} in_progress`);
11897
12001
  if (p.ready > 0) parts.push(`${p.ready} ready`);
11898
- if (p.blocked > 0) parts.push(chalk41.red(`${p.blocked} blocked`));
12002
+ if (p.blocked > 0) parts.push(chalk44.red(`${p.blocked} blocked`));
11899
12003
  if (p.done > 0) parts.push(`${p.done} done`);
11900
12004
  return `${completed}/${p.total} tasks` + (parts.length > 0 ? ` (${parts.join(", ")})` : "");
11901
12005
  }
11902
12006
  function createTaskParentsCommand() {
11903
- return new Command68("groups").aliases(["parents", "pg"]).description("List task groups with computed status").option("-s, --status <status>", "Filter by computed status: done, in_progress, ready, todo").option("-j, --json", "Output JSON").action(async (options) => {
12007
+ return new Command72("groups").aliases(["parents", "pg"]).description("List task groups with computed status").option("-s, --status <status>", "Filter by computed status: done, in_progress, ready, todo").option("-j, --json", "Output JSON").action(async (options) => {
11904
12008
  const service = new TaskService();
11905
12009
  const parents = await service.getParents(options.status);
11906
12010
  if (options.json) {
@@ -11909,44 +12013,44 @@ function createTaskParentsCommand() {
11909
12013
  }
11910
12014
  if (parents.length === 0) {
11911
12015
  if (options.status) {
11912
- console.log(chalk41.dim(`No groups with status: ${options.status}`));
12016
+ console.log(chalk44.dim(`No groups with status: ${options.status}`));
11913
12017
  } else {
11914
- console.log(chalk41.dim("No task groups found."));
11915
- console.log(chalk41.dim('\u{1F4A1} Add tasks with parent: jai1 t add "..." -P feature/xxx'));
12018
+ console.log(chalk44.dim("No task groups found."));
12019
+ console.log(chalk44.dim('\u{1F4A1} Add tasks with parent: jai1 t add "..." -P feature/xxx'));
11916
12020
  }
11917
12021
  return;
11918
12022
  }
11919
12023
  const header = options.status ? `\u{1F4E6} Task Groups \u2014 ${options.status} (${parents.length})` : `\u{1F4E6} Task Groups (${parents.length})`;
11920
- console.log(chalk41.bold(header));
12024
+ console.log(chalk44.bold(header));
11921
12025
  console.log();
11922
12026
  for (const p of parents) {
11923
12027
  const icon = PARENT_STATUS_ICONS[p.status] || "\u{1F4CB}";
11924
12028
  const progress = formatProgress(p);
11925
- console.log(` ${icon} ${chalk41.bold(p.name)} ${chalk41.dim("\u2014")} ${progress}`);
12029
+ console.log(` ${icon} ${chalk44.bold(p.name)} ${chalk44.dim("\u2014")} ${progress}`);
11926
12030
  }
11927
12031
  console.log();
11928
12032
  });
11929
12033
  }
11930
12034
 
11931
12035
  // src/commands/tasks/cancel.ts
11932
- import { Command as Command69 } from "commander";
11933
- import chalk42 from "chalk";
12036
+ import { Command as Command73 } from "commander";
12037
+ import chalk45 from "chalk";
11934
12038
  import { confirm as confirm12 } from "@inquirer/prompts";
11935
12039
  function createTaskCancelCommand() {
11936
- return new Command69("cancel").description("Cancel a task (with dependency impact check)").argument("<id>", "Task ID (e.g. T-001)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON").action(async (id, options) => {
12040
+ return new Command73("cancel").description("Cancel a task (with dependency impact check)").argument("<id>", "Task ID (e.g. T-001)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON").action(async (id, options) => {
11937
12041
  const service = new TaskService();
11938
12042
  try {
11939
12043
  const task = await service.findById(id);
11940
12044
  if (!task) {
11941
- console.error(chalk42.red(`\u274C Task ${id} not found`));
12045
+ console.error(chalk45.red(`\u274C Task ${id} not found`));
11942
12046
  process.exit(1);
11943
12047
  }
11944
12048
  if (task.status === "cancelled") {
11945
- console.error(chalk42.yellow(`\u26A0\uFE0F Task ${id} is already cancelled`));
12049
+ console.error(chalk45.yellow(`\u26A0\uFE0F Task ${id} is already cancelled`));
11946
12050
  process.exit(0);
11947
12051
  }
11948
12052
  if (task.status === "done") {
11949
- console.error(chalk42.red(`\u274C Task ${id} is already done \u2014 cannot cancel`));
12053
+ console.error(chalk45.red(`\u274C Task ${id} is already done \u2014 cannot cancel`));
11950
12054
  process.exit(1);
11951
12055
  }
11952
12056
  const dependents = await service.getDependents(id);
@@ -11954,17 +12058,17 @@ function createTaskCancelCommand() {
11954
12058
  (t) => t.status !== "done" && t.status !== "cancelled"
11955
12059
  );
11956
12060
  const icon = STATUS_ICONS[task.status] || "\u{1F4CB}";
11957
- console.log(chalk42.bold(`
12061
+ console.log(chalk45.bold(`
11958
12062
  \u26AB Cancel: ${icon} ${task.id} \u2014 ${task.title}
11959
12063
  `));
11960
12064
  if (activeDependents.length > 0) {
11961
- console.log(chalk42.yellow(`\u26A0\uFE0F ${activeDependents.length} task(s) ph\u1EE5 thu\u1ED9c v\xE0o ${id}:`));
12065
+ console.log(chalk45.yellow(`\u26A0\uFE0F ${activeDependents.length} task(s) ph\u1EE5 thu\u1ED9c v\xE0o ${id}:`));
11962
12066
  for (const dep of activeDependents) {
11963
12067
  const depIcon = STATUS_ICONS[dep.status] || "\u{1F4CB}";
11964
- console.log(` ${depIcon} ${chalk42.dim(dep.id)} ${dep.title}`);
12068
+ console.log(` ${depIcon} ${chalk45.dim(dep.id)} ${dep.title}`);
11965
12069
  }
11966
12070
  console.log(
11967
- chalk42.dim(
12071
+ chalk45.dim(
11968
12072
  `
11969
12073
  \u2192 Cancel s\u1EBD resolve dependency, c\xE1c task tr\xEAn c\xF3 th\u1EC3 \u0111\u01B0\u1EE3c unblock.`
11970
12074
  )
@@ -11977,7 +12081,7 @@ function createTaskCancelCommand() {
11977
12081
  default: false
11978
12082
  });
11979
12083
  if (!proceed) {
11980
- console.log(chalk42.dim("\u0110\xE3 hu\u1EF7."));
12084
+ console.log(chalk45.dim("\u0110\xE3 hu\u1EF7."));
11981
12085
  return;
11982
12086
  }
11983
12087
  }
@@ -11986,10 +12090,10 @@ function createTaskCancelCommand() {
11986
12090
  console.log(JSON.stringify(updated, null, 2));
11987
12091
  return;
11988
12092
  }
11989
- console.log(chalk42.green(`\u2705 ${updated.id}: ${updated.title} \u2192 cancelled`));
12093
+ console.log(chalk45.green(`\u2705 ${updated.id}: ${updated.title} \u2192 cancelled`));
11990
12094
  } catch (error) {
11991
12095
  console.error(
11992
- chalk42.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
12096
+ chalk45.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
11993
12097
  );
11994
12098
  process.exit(1);
11995
12099
  }
@@ -11997,13 +12101,13 @@ function createTaskCancelCommand() {
11997
12101
  }
11998
12102
 
11999
12103
  // src/commands/tasks/delete.ts
12000
- import { Command as Command70 } from "commander";
12001
- import chalk43 from "chalk";
12104
+ import { Command as Command74 } from "commander";
12105
+ import chalk46 from "chalk";
12002
12106
  import { confirm as confirm13 } from "@inquirer/prompts";
12003
12107
  function printTaskList(tasks, indent = " ") {
12004
12108
  for (const t of tasks) {
12005
12109
  const icon = STATUS_ICONS[t.status] || "\u{1F4CB}";
12006
- console.log(`${indent}${icon} ${chalk43.dim(t.id)} ${t.title}`);
12110
+ console.log(`${indent}${icon} ${chalk46.dim(t.id)} ${t.title}`);
12007
12111
  }
12008
12112
  }
12009
12113
  function printImpactSummary(tasksToDelete, allDependents) {
@@ -12011,21 +12115,21 @@ function printImpactSummary(tasksToDelete, allDependents) {
12011
12115
  const todo = tasksToDelete.filter((t) => t.status === "todo");
12012
12116
  const done = tasksToDelete.filter((t) => t.status === "done");
12013
12117
  const cancelled = tasksToDelete.filter((t) => t.status === "cancelled");
12014
- console.log(chalk43.bold(`
12118
+ console.log(chalk46.bold(`
12015
12119
  \u{1F5D1}\uFE0F Delete: ${tasksToDelete.length} task(s)
12016
12120
  `));
12017
12121
  if (inProgress.length > 0) {
12018
- console.log(chalk43.yellow.bold(` \u26A0\uFE0F ${inProgress.length} task(s) \u0111ang IN_PROGRESS:`));
12122
+ console.log(chalk46.yellow.bold(` \u26A0\uFE0F ${inProgress.length} task(s) \u0111ang IN_PROGRESS:`));
12019
12123
  printTaskList(inProgress, " ");
12020
12124
  console.log();
12021
12125
  }
12022
12126
  const parts = [];
12023
12127
  if (todo.length > 0) parts.push(`${todo.length} todo`);
12024
- if (inProgress.length > 0) parts.push(chalk43.yellow(`${inProgress.length} in_progress`));
12128
+ if (inProgress.length > 0) parts.push(chalk46.yellow(`${inProgress.length} in_progress`));
12025
12129
  if (done.length > 0) parts.push(`${done.length} done`);
12026
12130
  if (cancelled.length > 0) parts.push(`${cancelled.length} cancelled`);
12027
- console.log(` ${chalk43.dim("Breakdown:")} ${parts.join(", ")}`);
12028
- console.log(` ${chalk43.dim("Tasks:")}`);
12131
+ console.log(` ${chalk46.dim("Breakdown:")} ${parts.join(", ")}`);
12132
+ console.log(` ${chalk46.dim("Tasks:")}`);
12029
12133
  printTaskList(tasksToDelete, " ");
12030
12134
  console.log();
12031
12135
  if (allDependents.length > 0) {
@@ -12033,12 +12137,12 @@ function printImpactSummary(tasksToDelete, allDependents) {
12033
12137
  (t) => t.status !== "done" && t.status !== "cancelled"
12034
12138
  );
12035
12139
  console.log(
12036
- chalk43.yellow(` \u26A0\uFE0F ${allDependents.length} task(s) b\xEAn ngo\xE0i c\xF3 depends_on s\u1EBD b\u1ECB \u1EA3nh h\u01B0\u1EDFng:`)
12140
+ chalk46.yellow(` \u26A0\uFE0F ${allDependents.length} task(s) b\xEAn ngo\xE0i c\xF3 depends_on s\u1EBD b\u1ECB \u1EA3nh h\u01B0\u1EDFng:`)
12037
12141
  );
12038
12142
  printTaskList(allDependents, " ");
12039
12143
  if (activeDependents.length > 0) {
12040
12144
  console.log(
12041
- chalk43.dim(`
12145
+ chalk46.dim(`
12042
12146
  \u2192 ${activeDependents.length} task(s) ch\u01B0a done c\xF3 th\u1EC3 b\u1ECB unblock.`)
12043
12147
  );
12044
12148
  }
@@ -12046,7 +12150,7 @@ function printImpactSummary(tasksToDelete, allDependents) {
12046
12150
  }
12047
12151
  }
12048
12152
  function createTaskDeleteCommand() {
12049
- return new Command70("delete").description("Delete task(s) or entire group permanently (with safe delete)").argument("[ids...]", "Task ID(s) (e.g. T-001 T-002 T-003)").option("-g, --group <name>", "Delete all tasks in a group (e.g. feature/auth)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON").action(async (ids, options) => {
12153
+ return new Command74("delete").description("Delete task(s) or entire group permanently (with safe delete)").argument("[ids...]", "Task ID(s) (e.g. T-001 T-002 T-003)").option("-g, --group <name>", "Delete all tasks in a group (e.g. feature/auth)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON").action(async (ids, options) => {
12050
12154
  const service = new TaskService();
12051
12155
  try {
12052
12156
  let tasksToDelete;
@@ -12054,23 +12158,23 @@ function createTaskDeleteCommand() {
12054
12158
  const allTasks = await service.readAll();
12055
12159
  tasksToDelete = allTasks.filter((t) => t.parent === options.group);
12056
12160
  if (tasksToDelete.length === 0) {
12057
- console.error(chalk43.red(`\u274C No tasks found in group: ${options.group}`));
12161
+ console.error(chalk46.red(`\u274C No tasks found in group: ${options.group}`));
12058
12162
  process.exit(1);
12059
12163
  }
12060
12164
  } else {
12061
12165
  if (!ids || ids.length === 0) {
12062
- console.error(chalk43.red("\u274C C\u1EA7n ch\u1EC9 \u0111\u1ECBnh task ID(s) ho\u1EB7c --group <name>"));
12063
- console.error(chalk43.dim("\nV\xED d\u1EE5:"));
12064
- console.error(chalk43.dim(" j t delete T-001"));
12065
- console.error(chalk43.dim(" j t delete T-001 T-002 T-003"));
12066
- console.error(chalk43.dim(" j t delete --group feature/auth"));
12166
+ console.error(chalk46.red("\u274C C\u1EA7n ch\u1EC9 \u0111\u1ECBnh task ID(s) ho\u1EB7c --group <name>"));
12167
+ console.error(chalk46.dim("\nV\xED d\u1EE5:"));
12168
+ console.error(chalk46.dim(" j t delete T-001"));
12169
+ console.error(chalk46.dim(" j t delete T-001 T-002 T-003"));
12170
+ console.error(chalk46.dim(" j t delete --group feature/auth"));
12067
12171
  process.exit(1);
12068
12172
  }
12069
12173
  tasksToDelete = [];
12070
12174
  for (const id of ids) {
12071
12175
  const task = await service.findById(id);
12072
12176
  if (!task) {
12073
- console.error(chalk43.red(`\u274C Task ${id} not found`));
12177
+ console.error(chalk46.red(`\u274C Task ${id} not found`));
12074
12178
  process.exit(1);
12075
12179
  }
12076
12180
  tasksToDelete.push(task);
@@ -12089,7 +12193,7 @@ function createTaskDeleteCommand() {
12089
12193
  }
12090
12194
  }
12091
12195
  if (options.group) {
12092
- console.log(chalk43.bold.cyan(`
12196
+ console.log(chalk46.bold.cyan(`
12093
12197
  \u{1F4E6} Group: ${options.group}`));
12094
12198
  }
12095
12199
  printImpactSummary(tasksToDelete, allDependents);
@@ -12100,7 +12204,7 @@ function createTaskDeleteCommand() {
12100
12204
  default: false
12101
12205
  });
12102
12206
  if (!proceed) {
12103
- console.log(chalk43.dim("\u0110\xE3 hu\u1EF7."));
12207
+ console.log(chalk46.dim("\u0110\xE3 hu\u1EF7."));
12104
12208
  return;
12105
12209
  }
12106
12210
  }
@@ -12115,15 +12219,15 @@ function createTaskDeleteCommand() {
12115
12219
  await service.deleteTasks(idsToDelete);
12116
12220
  if (!options.json) {
12117
12221
  if (options.group) {
12118
- console.log(chalk43.green(`\u2705 \u0110\xE3 xo\xE1 group "${options.group}" (${tasksToDelete.length} tasks)`));
12222
+ console.log(chalk46.green(`\u2705 \u0110\xE3 xo\xE1 group "${options.group}" (${tasksToDelete.length} tasks)`));
12119
12223
  } else if (tasksToDelete.length === 1) {
12120
- console.log(chalk43.green(`\u2705 \u0110\xE3 xo\xE1 ${tasksToDelete[0].id}: ${tasksToDelete[0].title}`));
12224
+ console.log(chalk46.green(`\u2705 \u0110\xE3 xo\xE1 ${tasksToDelete[0].id}: ${tasksToDelete[0].title}`));
12121
12225
  } else {
12122
- console.log(chalk43.green(`\u2705 \u0110\xE3 xo\xE1 ${tasksToDelete.length} task(s): ${idsToDelete.join(", ")}`));
12226
+ console.log(chalk46.green(`\u2705 \u0110\xE3 xo\xE1 ${tasksToDelete.length} task(s): ${idsToDelete.join(", ")}`));
12123
12227
  }
12124
12228
  if (allDependents.length > 0) {
12125
12229
  console.log(
12126
- chalk43.dim(
12230
+ chalk46.dim(
12127
12231
  ` \u0110\xE3 c\u1EADp nh\u1EADt depends_on cho: ${allDependents.map((d) => d.id).join(", ")}`
12128
12232
  )
12129
12233
  );
@@ -12131,7 +12235,7 @@ function createTaskDeleteCommand() {
12131
12235
  }
12132
12236
  } catch (error) {
12133
12237
  console.error(
12134
- chalk43.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
12238
+ chalk46.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
12135
12239
  );
12136
12240
  process.exit(1);
12137
12241
  }
@@ -12140,7 +12244,7 @@ function createTaskDeleteCommand() {
12140
12244
 
12141
12245
  // src/commands/tasks/index.ts
12142
12246
  function createTasksCommand() {
12143
- const cmd = new Command71("tasks").alias("t").description("Task management \u2014 track, assign, and manage development tasks").hook("preAction", (thisCommand, actionCommand) => {
12247
+ const cmd = new Command75("tasks").alias("t").description("Task management \u2014 track, assign, and manage development tasks").hook("preAction", (thisCommand, actionCommand) => {
12144
12248
  if (actionCommand.name() !== "guide") {
12145
12249
  TaskService.ensureJai1Dir();
12146
12250
  }
@@ -12160,24 +12264,24 @@ function createTasksCommand() {
12160
12264
  cmd.addCommand(createTaskDeleteCommand());
12161
12265
  cmd.addCommand(createTaskGuideCommand());
12162
12266
  cmd.action(async () => {
12163
- const { handleTaskSummary } = await import("./summary-4J2OCCSA.js");
12267
+ const { handleTaskSummary } = await import("./summary-R4WPFJ2U.js");
12164
12268
  await handleTaskSummary({ json: false });
12165
12269
  });
12166
12270
  return cmd;
12167
12271
  }
12168
12272
 
12169
12273
  // src/commands/kit/index.ts
12170
- import { Command as Command75 } from "commander";
12171
- import chalk45 from "chalk";
12274
+ import { Command as Command79 } from "commander";
12275
+ import chalk48 from "chalk";
12172
12276
 
12173
12277
  // src/commands/kit/list.ts
12174
- import { Command as Command72 } from "commander";
12175
- import chalk44 from "chalk";
12278
+ import { Command as Command76 } from "commander";
12279
+ import chalk47 from "chalk";
12176
12280
  import Table6 from "cli-table3";
12177
12281
 
12178
12282
  // src/services/starter-kit.service.ts
12179
- import { promises as fs19 } from "fs";
12180
- import { join as join10 } from "path";
12283
+ import { promises as fs18 } from "fs";
12284
+ import { join as join9 } from "path";
12181
12285
  import AdmZip from "adm-zip";
12182
12286
  var StarterKitService = class {
12183
12287
  /**
@@ -12224,29 +12328,29 @@ var StarterKitService = class {
12224
12328
  throw new NetworkError(`Failed to download kit: HTTP ${response.status}`);
12225
12329
  }
12226
12330
  if (onProgress) onProgress(30);
12227
- const tmpDir = join10(process.env.TMPDIR || "/tmp", "jai1-kits");
12228
- await fs19.mkdir(tmpDir, { recursive: true });
12229
- const tmpFile = join10(tmpDir, `${slug}.zip`);
12331
+ const tmpDir = join9(process.env.TMPDIR || "/tmp", "jai1-kits");
12332
+ await fs18.mkdir(tmpDir, { recursive: true });
12333
+ const tmpFile = join9(tmpDir, `${slug}.zip`);
12230
12334
  const buffer = await response.arrayBuffer();
12231
- await fs19.writeFile(tmpFile, Buffer.from(buffer));
12335
+ await fs18.writeFile(tmpFile, Buffer.from(buffer));
12232
12336
  if (onProgress) onProgress(60);
12233
12337
  const zip = new AdmZip(tmpFile);
12234
- await fs19.mkdir(targetDir, { recursive: true });
12338
+ await fs18.mkdir(targetDir, { recursive: true });
12235
12339
  zip.extractAllTo(targetDir, true);
12236
12340
  if (onProgress) onProgress(100);
12237
- await fs19.unlink(tmpFile);
12341
+ await fs18.unlink(tmpFile);
12238
12342
  }
12239
12343
  };
12240
12344
 
12241
12345
  // src/commands/kit/list.ts
12242
12346
  function createKitListCommand() {
12243
- return new Command72("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) => {
12347
+ return new Command76("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) => {
12244
12348
  const configService = new ConfigService();
12245
12349
  const config = await configService.load();
12246
12350
  if (!config) {
12247
12351
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
12248
12352
  }
12249
- console.log(chalk44.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch starter kits..."));
12353
+ console.log(chalk47.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch starter kits..."));
12250
12354
  console.log();
12251
12355
  const kitService = new StarterKitService();
12252
12356
  const kits = await kitService.list(config, {
@@ -12254,9 +12358,9 @@ function createKitListCommand() {
12254
12358
  search: options.search
12255
12359
  });
12256
12360
  if (kits.length === 0) {
12257
- console.log(chalk44.yellow("Kh\xF4ng t\xECm th\u1EA5y starter kits n\xE0o."));
12361
+ console.log(chalk47.yellow("Kh\xF4ng t\xECm th\u1EA5y starter kits n\xE0o."));
12258
12362
  if (options.category || options.search) {
12259
- console.log(chalk44.dim("Th\u1EED b\u1ECF filter \u0111\u1EC3 xem t\u1EA5t c\u1EA3."));
12363
+ console.log(chalk47.dim("Th\u1EED b\u1ECF filter \u0111\u1EC3 xem t\u1EA5t c\u1EA3."));
12260
12364
  }
12261
12365
  return;
12262
12366
  }
@@ -12280,35 +12384,35 @@ function createKitListCommand() {
12280
12384
  const categoryKits = byCategory[category];
12281
12385
  const categoryIcon = category === "frontend" ? "\u{1F3A8}" : category === "backend" ? "\u2699\uFE0F" : category === "fullstack" ? "\u{1F680}" : "\u{1F4E6}";
12282
12386
  console.log(
12283
- chalk44.bold(`${categoryIcon} ${category.charAt(0).toUpperCase() + category.slice(1)}`)
12387
+ chalk47.bold(`${categoryIcon} ${category.charAt(0).toUpperCase() + category.slice(1)}`)
12284
12388
  );
12285
12389
  const table = new Table6({
12286
12390
  head: [
12287
- chalk44.cyan("Slug"),
12288
- chalk44.cyan("M\xF4 t\u1EA3"),
12289
- chalk44.cyan("Version")
12391
+ chalk47.cyan("Slug"),
12392
+ chalk47.cyan("M\xF4 t\u1EA3"),
12393
+ chalk47.cyan("Version")
12290
12394
  ],
12291
12395
  style: { head: [], border: ["gray"] }
12292
12396
  });
12293
12397
  for (const kit of categoryKits) {
12294
12398
  table.push([
12295
- chalk44.white(kit.slug),
12296
- chalk44.dim(kit.description.slice(0, 50)),
12297
- chalk44.green(`v${kit.version}`)
12399
+ chalk47.white(kit.slug),
12400
+ chalk47.dim(kit.description.slice(0, 50)),
12401
+ chalk47.green(`v${kit.version}`)
12298
12402
  ]);
12299
12403
  }
12300
12404
  console.log(table.toString());
12301
12405
  console.log();
12302
12406
  }
12303
- console.log(chalk44.dim(`T\u1ED5ng c\u1ED9ng: ${kits.length} starter kit(s)`));
12304
- console.log(chalk44.dim('\n\u{1F4A1} Ch\u1EA1y "jai1 kit create <slug>" \u0111\u1EC3 t\u1EA1o project m\u1EDBi'));
12407
+ console.log(chalk47.dim(`T\u1ED5ng c\u1ED9ng: ${kits.length} starter kit(s)`));
12408
+ console.log(chalk47.dim('\n\u{1F4A1} Ch\u1EA1y "jai1 kit create <slug>" \u0111\u1EC3 t\u1EA1o project m\u1EDBi'));
12305
12409
  });
12306
12410
  }
12307
12411
 
12308
12412
  // src/commands/kit/info.ts
12309
- import { Command as Command73 } from "commander";
12413
+ import { Command as Command77 } from "commander";
12310
12414
  function createKitInfoCommand() {
12311
- return new Command73("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
12415
+ return new Command77("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
12312
12416
  const configService = new ConfigService();
12313
12417
  const config = await configService.load();
12314
12418
  if (!config) {
@@ -12357,9 +12461,9 @@ Post-Init Commands:`);
12357
12461
  }
12358
12462
 
12359
12463
  // src/commands/kit/create.ts
12360
- import { Command as Command74 } from "commander";
12361
- import { promises as fs20 } from "fs";
12362
- import { join as join11 } from "path";
12464
+ import { Command as Command78 } from "commander";
12465
+ import { promises as fs19 } from "fs";
12466
+ import { join as join10 } from "path";
12363
12467
  import { select as select3, input as input2, checkbox as checkbox4 } from "@inquirer/prompts";
12364
12468
  import { execa as execa2 } from "execa";
12365
12469
 
@@ -12402,7 +12506,7 @@ var HookExecutor = class {
12402
12506
 
12403
12507
  // src/commands/kit/create.ts
12404
12508
  function createKitCreateCommand() {
12405
- return new Command74("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) => {
12509
+ return new Command78("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) => {
12406
12510
  const configService = new ConfigService();
12407
12511
  const config = await configService.load();
12408
12512
  if (!config) {
@@ -12422,9 +12526,9 @@ function createKitCreateCommand() {
12422
12526
  }
12423
12527
  }
12424
12528
  }
12425
- const targetDir = directory || join11(process.cwd(), options.name || slug);
12529
+ const targetDir = directory || join10(process.cwd(), options.name || slug);
12426
12530
  try {
12427
- await fs20.access(targetDir);
12531
+ await fs19.access(targetDir);
12428
12532
  throw new Error(`Directory already exists: ${targetDir}`);
12429
12533
  } catch (error) {
12430
12534
  if (error.code !== "ENOENT") {
@@ -12487,7 +12591,7 @@ function createKitCreateCommand() {
12487
12591
  );
12488
12592
  for (const filepath of expandedPaths) {
12489
12593
  console.log(` \u{1F4E5} Installing ${filepath}...`);
12490
- await componentsService.install(config, filepath, join11(targetDir, ".jai1"));
12594
+ await componentsService.install(config, filepath, join10(targetDir, ".jai1"));
12491
12595
  }
12492
12596
  console.log(" \u2713 Framework components applied");
12493
12597
  }
@@ -12549,7 +12653,7 @@ function createKitCreateCommand() {
12549
12653
  async function applyVariableSubstitution(dir, variables) {
12550
12654
  const files = await getAllFiles(dir);
12551
12655
  for (const file of files) {
12552
- let content = await fs20.readFile(file, "utf-8");
12656
+ let content = await fs19.readFile(file, "utf-8");
12553
12657
  let modified = false;
12554
12658
  for (const [key, value] of Object.entries(variables)) {
12555
12659
  const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
@@ -12559,15 +12663,15 @@ async function applyVariableSubstitution(dir, variables) {
12559
12663
  }
12560
12664
  }
12561
12665
  if (modified) {
12562
- await fs20.writeFile(file, content, "utf-8");
12666
+ await fs19.writeFile(file, content, "utf-8");
12563
12667
  }
12564
12668
  }
12565
12669
  }
12566
12670
  async function getAllFiles(dir) {
12567
12671
  const files = [];
12568
- const entries = await fs20.readdir(dir, { withFileTypes: true });
12672
+ const entries = await fs19.readdir(dir, { withFileTypes: true });
12569
12673
  for (const entry of entries) {
12570
- const fullPath = join11(dir, entry.name);
12674
+ const fullPath = join10(dir, entry.name);
12571
12675
  if (entry.isDirectory()) {
12572
12676
  if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
12573
12677
  files.push(...await getAllFiles(fullPath));
@@ -12581,23 +12685,23 @@ async function getAllFiles(dir) {
12581
12685
 
12582
12686
  // src/commands/kit/index.ts
12583
12687
  function showKitHelp() {
12584
- console.log(chalk45.bold.cyan("\u{1F4E6} jai1 kit") + chalk45.dim(" - Qu\u1EA3n l\xFD starter kits"));
12688
+ console.log(chalk48.bold.cyan("\u{1F4E6} jai1 kit") + chalk48.dim(" - Qu\u1EA3n l\xFD starter kits"));
12585
12689
  console.log();
12586
- console.log(chalk45.bold("C\xE1c l\u1EC7nh:"));
12587
- console.log(` ${chalk45.cyan("list")} Li\u1EC7t k\xEA c\xE1c starter kits c\xF3 s\u1EB5n`);
12588
- console.log(` ${chalk45.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t starter kit`);
12589
- console.log(` ${chalk45.cyan("create")} T\u1EA1o project m\u1EDBi t\u1EEB starter kit`);
12690
+ console.log(chalk48.bold("C\xE1c l\u1EC7nh:"));
12691
+ console.log(` ${chalk48.cyan("list")} Li\u1EC7t k\xEA c\xE1c starter kits c\xF3 s\u1EB5n`);
12692
+ console.log(` ${chalk48.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t starter kit`);
12693
+ console.log(` ${chalk48.cyan("create")} T\u1EA1o project m\u1EDBi t\u1EEB starter kit`);
12590
12694
  console.log();
12591
- console.log(chalk45.bold("V\xED d\u1EE5:"));
12592
- console.log(chalk45.dim(" $ jai1 kit list"));
12593
- console.log(chalk45.dim(" $ jai1 kit list --category frontend"));
12594
- console.log(chalk45.dim(" $ jai1 kit info next-tw4-shadcn"));
12595
- console.log(chalk45.dim(" $ jai1 kit create next-tw4-shadcn my-project"));
12695
+ console.log(chalk48.bold("V\xED d\u1EE5:"));
12696
+ console.log(chalk48.dim(" $ jai1 kit list"));
12697
+ console.log(chalk48.dim(" $ jai1 kit list --category frontend"));
12698
+ console.log(chalk48.dim(" $ jai1 kit info next-tw4-shadcn"));
12699
+ console.log(chalk48.dim(" $ jai1 kit create next-tw4-shadcn my-project"));
12596
12700
  console.log();
12597
- console.log(chalk45.dim('Ch\u1EA1y "jai1 kit <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
12701
+ console.log(chalk48.dim('Ch\u1EA1y "jai1 kit <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
12598
12702
  }
12599
12703
  function createKitCommand() {
12600
- const cmd = new Command75("kit").description("Manage starter kits for new projects").action(() => {
12704
+ const cmd = new Command79("kit").description("Manage starter kits for new projects").action(() => {
12601
12705
  showKitHelp();
12602
12706
  });
12603
12707
  cmd.addCommand(createKitListCommand());
@@ -12607,21 +12711,21 @@ function createKitCommand() {
12607
12711
  }
12608
12712
 
12609
12713
  // src/commands/rules/index.ts
12610
- import { Command as Command82 } from "commander";
12611
- import chalk47 from "chalk";
12714
+ import { Command as Command86 } from "commander";
12715
+ import chalk50 from "chalk";
12612
12716
 
12613
12717
  // src/commands/rules/list.ts
12614
- import { Command as Command76 } from "commander";
12615
- import chalk46 from "chalk";
12718
+ import { Command as Command80 } from "commander";
12719
+ import chalk49 from "chalk";
12616
12720
  import Table7 from "cli-table3";
12617
12721
  function createRulesListCommand() {
12618
- return new Command76("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
12722
+ return new Command80("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
12619
12723
  const configService = new ConfigService();
12620
12724
  const config = await configService.load();
12621
12725
  if (!config) {
12622
12726
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
12623
12727
  }
12624
- console.log(chalk46.cyan("\u{1F4CB} \u0110ang t\u1EA3i danh s\xE1ch rule presets..."));
12728
+ console.log(chalk49.cyan("\u{1F4CB} \u0110ang t\u1EA3i danh s\xE1ch rule presets..."));
12625
12729
  console.log();
12626
12730
  try {
12627
12731
  const response = await fetch(`${config.apiUrl}/api/rules/presets`, {
@@ -12638,23 +12742,23 @@ function createRulesListCommand() {
12638
12742
  return;
12639
12743
  }
12640
12744
  if (data.total === 0) {
12641
- console.log(chalk46.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
12745
+ console.log(chalk49.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
12642
12746
  return;
12643
12747
  }
12644
12748
  console.log(
12645
- chalk46.green(`\u2713 T\xECm th\u1EA5y ${chalk46.bold(data.total)} preset${data.total > 1 ? "s" : ""}`)
12749
+ chalk49.green(`\u2713 T\xECm th\u1EA5y ${chalk49.bold(data.total)} preset${data.total > 1 ? "s" : ""}`)
12646
12750
  );
12647
12751
  console.log();
12648
12752
  for (const preset of data.presets) {
12649
- console.log(chalk46.bold.cyan(`\u{1F4E6} ${preset.slug}`));
12753
+ console.log(chalk49.bold.cyan(`\u{1F4E6} ${preset.slug}`));
12650
12754
  const table = new Table7({
12651
12755
  style: { head: [], border: ["gray"], compact: true },
12652
12756
  colWidths: [15, 55]
12653
12757
  });
12654
12758
  table.push(
12655
- [chalk46.dim("T\xEAn"), chalk46.white(preset.name)],
12656
- [chalk46.dim("M\xF4 t\u1EA3"), chalk46.white(preset.description)],
12657
- [chalk46.dim("Version"), chalk46.green(`v${preset.version}`)]
12759
+ [chalk49.dim("T\xEAn"), chalk49.white(preset.name)],
12760
+ [chalk49.dim("M\xF4 t\u1EA3"), chalk49.white(preset.description)],
12761
+ [chalk49.dim("Version"), chalk49.green(`v${preset.version}`)]
12658
12762
  );
12659
12763
  const stackParts = [];
12660
12764
  if (preset.stack.frontend) stackParts.push(preset.stack.frontend);
@@ -12662,16 +12766,16 @@ function createRulesListCommand() {
12662
12766
  if (preset.stack.css) stackParts.push(preset.stack.css);
12663
12767
  if (preset.stack.database) stackParts.push(preset.stack.database);
12664
12768
  if (stackParts.length > 0) {
12665
- table.push([chalk46.dim("Stack"), chalk46.yellow(stackParts.join(" + "))]);
12769
+ table.push([chalk49.dim("Stack"), chalk49.yellow(stackParts.join(" + "))]);
12666
12770
  }
12667
12771
  table.push(
12668
- [chalk46.dim("Tags"), chalk46.dim(preset.tags.join(", ") || "-")],
12669
- [chalk46.dim("Downloads"), chalk46.white(preset.downloads.toString())]
12772
+ [chalk49.dim("Tags"), chalk49.dim(preset.tags.join(", ") || "-")],
12773
+ [chalk49.dim("Downloads"), chalk49.white(preset.downloads.toString())]
12670
12774
  );
12671
12775
  console.log(table.toString());
12672
12776
  console.log();
12673
12777
  }
12674
- console.log(chalk46.dim('\u{1F4A1} Ch\u1EA1y "jai1 rules apply <name>" \u0111\u1EC3 \xE1p d\u1EE5ng preset'));
12778
+ console.log(chalk49.dim('\u{1F4A1} Ch\u1EA1y "jai1 rules apply <name>" \u0111\u1EC3 \xE1p d\u1EE5ng preset'));
12675
12779
  } catch (error) {
12676
12780
  throw new Error(
12677
12781
  `L\u1ED7i khi t\u1EA3i presets: ${error instanceof Error ? error.message : String(error)}`
@@ -12681,29 +12785,29 @@ function createRulesListCommand() {
12681
12785
  }
12682
12786
 
12683
12787
  // src/commands/rules/init.ts
12684
- import { Command as Command77 } from "commander";
12685
- import { promises as fs22 } from "fs";
12686
- import { join as join13 } from "path";
12788
+ import { Command as Command81 } from "commander";
12789
+ import { promises as fs21 } from "fs";
12790
+ import { join as join12 } from "path";
12687
12791
  import { select as select4, confirm as confirm14 } from "@inquirer/prompts";
12688
12792
 
12689
12793
  // src/services/project-config.service.ts
12690
- import { promises as fs21 } from "fs";
12691
- import { join as join12 } from "path";
12794
+ import { promises as fs20 } from "fs";
12795
+ import { join as join11 } from "path";
12692
12796
  var ProjectConfigService = class {
12693
12797
  projectRoot;
12694
12798
  configDir;
12695
12799
  configPath;
12696
12800
  constructor(projectRoot = process.cwd()) {
12697
12801
  this.projectRoot = projectRoot;
12698
- this.configDir = join12(this.projectRoot, ".jai1");
12699
- this.configPath = join12(this.configDir, "project.json");
12802
+ this.configDir = join11(this.projectRoot, ".jai1");
12803
+ this.configPath = join11(this.configDir, "project.json");
12700
12804
  }
12701
12805
  /**
12702
12806
  * Check if config file exists
12703
12807
  */
12704
12808
  async exists() {
12705
12809
  try {
12706
- await fs21.access(this.configPath);
12810
+ await fs20.access(this.configPath);
12707
12811
  return true;
12708
12812
  } catch {
12709
12813
  return false;
@@ -12718,7 +12822,7 @@ var ProjectConfigService = class {
12718
12822
  return null;
12719
12823
  }
12720
12824
  try {
12721
- const content = await fs21.readFile(this.configPath, "utf-8");
12825
+ const content = await fs20.readFile(this.configPath, "utf-8");
12722
12826
  return JSON.parse(content);
12723
12827
  } catch (error) {
12724
12828
  throw new Error(
@@ -12732,8 +12836,8 @@ var ProjectConfigService = class {
12732
12836
  */
12733
12837
  async save(config) {
12734
12838
  try {
12735
- await fs21.mkdir(this.configDir, { recursive: true });
12736
- await fs21.writeFile(this.configPath, JSON.stringify(config, null, 2), "utf-8");
12839
+ await fs20.mkdir(this.configDir, { recursive: true });
12840
+ await fs20.writeFile(this.configPath, JSON.stringify(config, null, 2), "utf-8");
12737
12841
  } catch (error) {
12738
12842
  throw new Error(
12739
12843
  `Failed to save project config: ${error instanceof Error ? error.message : String(error)}`
@@ -12806,7 +12910,7 @@ var ProjectConfigService = class {
12806
12910
 
12807
12911
  // src/commands/rules/init.ts
12808
12912
  function createRulesInitCommand() {
12809
- return new Command77("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) => {
12913
+ return new Command81("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) => {
12810
12914
  const configService = new ConfigService();
12811
12915
  const config = await configService.load();
12812
12916
  if (!config) {
@@ -12902,11 +13006,11 @@ function createRulesInitCommand() {
12902
13006
  });
12903
13007
  }
12904
13008
  async function applyCursorFormat(bundle) {
12905
- const rulesDir = join13(process.cwd(), ".cursor", "rules");
12906
- await fs22.mkdir(rulesDir, { recursive: true });
13009
+ const rulesDir = join12(process.cwd(), ".cursor", "rules");
13010
+ await fs21.mkdir(rulesDir, { recursive: true });
12907
13011
  for (const [filename, content] of Object.entries(bundle.files)) {
12908
- const filePath = join13(rulesDir, filename);
12909
- await fs22.writeFile(filePath, content, "utf-8");
13012
+ const filePath = join12(rulesDir, filename);
13013
+ await fs21.writeFile(filePath, content, "utf-8");
12910
13014
  console.log(`\u2713 Created .cursor/rules/${filename}`);
12911
13015
  }
12912
13016
  }
@@ -12933,14 +13037,14 @@ async function applyAgentsMdFormat(bundle) {
12933
13037
  }
12934
13038
  }
12935
13039
  const agentsMd = sections.join("\n");
12936
- await fs22.writeFile("AGENTS.md", agentsMd, "utf-8");
13040
+ await fs21.writeFile("AGENTS.md", agentsMd, "utf-8");
12937
13041
  console.log("\u2713 Created AGENTS.md");
12938
13042
  }
12939
13043
 
12940
13044
  // src/commands/rules/apply.ts
12941
- import { Command as Command78 } from "commander";
12942
- import { promises as fs24 } from "fs";
12943
- import { join as join15 } from "path";
13045
+ import { Command as Command82 } from "commander";
13046
+ import { promises as fs23 } from "fs";
13047
+ import { join as join14 } from "path";
12944
13048
  import { search, confirm as confirm15, checkbox as checkbox5 } from "@inquirer/prompts";
12945
13049
 
12946
13050
  // src/services/rules-generator.service.ts
@@ -13231,8 +13335,8 @@ Follow all instructions and patterns defined in AGENTS.md above.
13231
13335
  };
13232
13336
 
13233
13337
  // src/services/backup.service.ts
13234
- import { promises as fs23 } from "fs";
13235
- import { join as join14, dirname } from "path";
13338
+ import { promises as fs22 } from "fs";
13339
+ import { join as join13, dirname } from "path";
13236
13340
  var BackupService = class {
13237
13341
  backupDir = ".jai1/backups";
13238
13342
  /**
@@ -13240,7 +13344,7 @@ var BackupService = class {
13240
13344
  */
13241
13345
  async createBackup(ides, presetSlug) {
13242
13346
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13243
- const backupPath = join14(this.backupDir, timestamp);
13347
+ const backupPath = join13(this.backupDir, timestamp);
13244
13348
  const backedUpFiles = [];
13245
13349
  let hasContent = false;
13246
13350
  for (const ideId of ides) {
@@ -13249,7 +13353,7 @@ var BackupService = class {
13249
13353
  console.warn(`Unknown IDE format: ${ideId}, skipping backup`);
13250
13354
  continue;
13251
13355
  }
13252
- const rulesPath = format.rulesPath === "." ? process.cwd() : join14(process.cwd(), format.rulesPath);
13356
+ const rulesPath = format.rulesPath === "." ? process.cwd() : join13(process.cwd(), format.rulesPath);
13253
13357
  try {
13254
13358
  const exists = await this.pathExists(rulesPath);
13255
13359
  if (!exists) {
@@ -13262,19 +13366,19 @@ var BackupService = class {
13262
13366
  await this.backupSingleFile("GEMINI.md", backupPath, ideId, backedUpFiles);
13263
13367
  hasContent = true;
13264
13368
  } else {
13265
- const stats = await fs23.stat(rulesPath);
13369
+ const stats = await fs22.stat(rulesPath);
13266
13370
  if (stats.isDirectory()) {
13267
- const files = await fs23.readdir(rulesPath);
13371
+ const files = await fs22.readdir(rulesPath);
13268
13372
  for (const file of files) {
13269
13373
  if (file.endsWith(format.fileExtension)) {
13270
- const originalPath = join14(rulesPath, file);
13271
- const relativePath = join14(format.rulesPath, file);
13272
- const destPath = join14(backupPath, ideId, file);
13273
- await fs23.mkdir(dirname(destPath), { recursive: true });
13274
- await fs23.copyFile(originalPath, destPath);
13374
+ const originalPath = join13(rulesPath, file);
13375
+ const relativePath = join13(format.rulesPath, file);
13376
+ const destPath = join13(backupPath, ideId, file);
13377
+ await fs22.mkdir(dirname(destPath), { recursive: true });
13378
+ await fs22.copyFile(originalPath, destPath);
13275
13379
  backedUpFiles.push({
13276
13380
  originalPath: relativePath,
13277
- backupPath: join14(ideId, file),
13381
+ backupPath: join13(ideId, file),
13278
13382
  ide: ideId
13279
13383
  });
13280
13384
  hasContent = true;
@@ -13295,9 +13399,9 @@ var BackupService = class {
13295
13399
  ides,
13296
13400
  files: backedUpFiles
13297
13401
  };
13298
- await fs23.mkdir(backupPath, { recursive: true });
13299
- await fs23.writeFile(
13300
- join14(backupPath, "metadata.json"),
13402
+ await fs22.mkdir(backupPath, { recursive: true });
13403
+ await fs22.writeFile(
13404
+ join13(backupPath, "metadata.json"),
13301
13405
  JSON.stringify(metadata, null, 2),
13302
13406
  "utf-8"
13303
13407
  );
@@ -13307,18 +13411,18 @@ var BackupService = class {
13307
13411
  * Backup a single file (for AGENTS.md, GEMINI.md)
13308
13412
  */
13309
13413
  async backupSingleFile(filename, backupPath, ideId, backedUpFiles) {
13310
- const originalPath = join14(process.cwd(), filename);
13414
+ const originalPath = join13(process.cwd(), filename);
13311
13415
  try {
13312
13416
  const exists = await this.pathExists(originalPath);
13313
13417
  if (!exists) {
13314
13418
  return;
13315
13419
  }
13316
- const destPath = join14(backupPath, ideId, filename);
13317
- await fs23.mkdir(dirname(destPath), { recursive: true });
13318
- await fs23.copyFile(originalPath, destPath);
13420
+ const destPath = join13(backupPath, ideId, filename);
13421
+ await fs22.mkdir(dirname(destPath), { recursive: true });
13422
+ await fs22.copyFile(originalPath, destPath);
13319
13423
  backedUpFiles.push({
13320
13424
  originalPath: filename,
13321
- backupPath: join14(ideId, filename),
13425
+ backupPath: join13(ideId, filename),
13322
13426
  ide: ideId
13323
13427
  });
13324
13428
  } catch (error) {
@@ -13328,16 +13432,16 @@ var BackupService = class {
13328
13432
  * Restore files from a backup
13329
13433
  */
13330
13434
  async restoreBackup(backupPath) {
13331
- const metadataPath = join14(backupPath, "metadata.json");
13332
- const metadataContent = await fs23.readFile(metadataPath, "utf-8");
13435
+ const metadataPath = join13(backupPath, "metadata.json");
13436
+ const metadataContent = await fs22.readFile(metadataPath, "utf-8");
13333
13437
  const metadata = JSON.parse(metadataContent);
13334
13438
  console.log(`
13335
13439
  Restoring backup from ${metadata.timestamp}...`);
13336
13440
  for (const file of metadata.files) {
13337
- const sourcePath = join14(backupPath, file.backupPath);
13338
- const destPath = join14(process.cwd(), file.originalPath);
13339
- await fs23.mkdir(dirname(destPath), { recursive: true });
13340
- await fs23.copyFile(sourcePath, destPath);
13441
+ const sourcePath = join13(backupPath, file.backupPath);
13442
+ const destPath = join13(process.cwd(), file.originalPath);
13443
+ await fs22.mkdir(dirname(destPath), { recursive: true });
13444
+ await fs22.copyFile(sourcePath, destPath);
13341
13445
  console.log(`\u2713 Restored ${file.originalPath}`);
13342
13446
  }
13343
13447
  console.log("\n\u2705 Backup restored successfully!");
@@ -13347,18 +13451,18 @@ Restoring backup from ${metadata.timestamp}...`);
13347
13451
  */
13348
13452
  async listBackups() {
13349
13453
  try {
13350
- const backupDirPath = join14(process.cwd(), this.backupDir);
13454
+ const backupDirPath = join13(process.cwd(), this.backupDir);
13351
13455
  const exists = await this.pathExists(backupDirPath);
13352
13456
  if (!exists) {
13353
13457
  return [];
13354
13458
  }
13355
- const entries = await fs23.readdir(backupDirPath, { withFileTypes: true });
13459
+ const entries = await fs22.readdir(backupDirPath, { withFileTypes: true });
13356
13460
  const backups = [];
13357
13461
  for (const entry of entries) {
13358
13462
  if (entry.isDirectory()) {
13359
- const metadataPath = join14(backupDirPath, entry.name, "metadata.json");
13463
+ const metadataPath = join13(backupDirPath, entry.name, "metadata.json");
13360
13464
  try {
13361
- const metadataContent = await fs23.readFile(metadataPath, "utf-8");
13465
+ const metadataContent = await fs22.readFile(metadataPath, "utf-8");
13362
13466
  const metadata = JSON.parse(metadataContent);
13363
13467
  backups.push(metadata);
13364
13468
  } catch {
@@ -13375,7 +13479,7 @@ Restoring backup from ${metadata.timestamp}...`);
13375
13479
  * Delete a specific backup
13376
13480
  */
13377
13481
  async deleteBackup(timestamp) {
13378
- const backupPath = join14(process.cwd(), this.backupDir, timestamp);
13482
+ const backupPath = join13(process.cwd(), this.backupDir, timestamp);
13379
13483
  await this.deleteDirectory(backupPath);
13380
13484
  }
13381
13485
  /**
@@ -13407,7 +13511,7 @@ Restoring backup from ${metadata.timestamp}...`);
13407
13511
  */
13408
13512
  async pathExists(path13) {
13409
13513
  try {
13410
- await fs23.access(path13);
13514
+ await fs22.access(path13);
13411
13515
  return true;
13412
13516
  } catch {
13413
13517
  return false;
@@ -13422,16 +13526,16 @@ Restoring backup from ${metadata.timestamp}...`);
13422
13526
  if (!exists) {
13423
13527
  return;
13424
13528
  }
13425
- const entries = await fs23.readdir(path13, { withFileTypes: true });
13529
+ const entries = await fs22.readdir(path13, { withFileTypes: true });
13426
13530
  for (const entry of entries) {
13427
- const fullPath = join14(path13, entry.name);
13531
+ const fullPath = join13(path13, entry.name);
13428
13532
  if (entry.isDirectory()) {
13429
13533
  await this.deleteDirectory(fullPath);
13430
13534
  } else {
13431
- await fs23.unlink(fullPath);
13535
+ await fs22.unlink(fullPath);
13432
13536
  }
13433
13537
  }
13434
- await fs23.rmdir(path13);
13538
+ await fs22.rmdir(path13);
13435
13539
  } catch (error) {
13436
13540
  }
13437
13541
  }
@@ -13439,20 +13543,20 @@ Restoring backup from ${metadata.timestamp}...`);
13439
13543
  * Get backup directory path
13440
13544
  */
13441
13545
  getBackupDir() {
13442
- return join14(process.cwd(), this.backupDir);
13546
+ return join13(process.cwd(), this.backupDir);
13443
13547
  }
13444
13548
  /**
13445
13549
  * Ensure backup directory exists
13446
13550
  */
13447
13551
  async ensureBackupDir() {
13448
- const backupDirPath = join14(process.cwd(), this.backupDir);
13449
- await fs23.mkdir(backupDirPath, { recursive: true });
13552
+ const backupDirPath = join13(process.cwd(), this.backupDir);
13553
+ await fs22.mkdir(backupDirPath, { recursive: true });
13450
13554
  }
13451
13555
  };
13452
13556
 
13453
13557
  // src/commands/rules/apply.ts
13454
13558
  function createRulesApplyCommand() {
13455
- return new Command78("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) or "all"').option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
13559
+ return new Command82("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) or "all"').option("--skip-backup", "Skip backup creation").option("-y, --yes", "Skip all confirmations (auto mode)").action(async (presetSlug, options) => {
13456
13560
  const configService = new ConfigService();
13457
13561
  const config = await configService.load();
13458
13562
  if (!config) {
@@ -13618,21 +13722,21 @@ function createRulesApplyCommand() {
13618
13722
  }
13619
13723
  }
13620
13724
  console.log("\n\u{1F4DD} Applying preset...\n");
13621
- const rulePresetDir = join15(process.cwd(), ".jai1", "rule-preset");
13725
+ const rulePresetDir = join14(process.cwd(), ".jai1", "rule-preset");
13622
13726
  try {
13623
- await fs24.rm(rulePresetDir, { recursive: true, force: true });
13727
+ await fs23.rm(rulePresetDir, { recursive: true, force: true });
13624
13728
  } catch {
13625
13729
  }
13626
- await fs24.mkdir(rulePresetDir, { recursive: true });
13627
- await fs24.writeFile(
13628
- join15(rulePresetDir, "preset.json"),
13730
+ await fs23.mkdir(rulePresetDir, { recursive: true });
13731
+ await fs23.writeFile(
13732
+ join14(rulePresetDir, "preset.json"),
13629
13733
  JSON.stringify(bundle.preset, null, 2),
13630
13734
  "utf-8"
13631
13735
  );
13632
13736
  for (const [filename, content] of Object.entries(bundle.files)) {
13633
- const filePath = join15(rulePresetDir, filename);
13634
- await fs24.mkdir(join15(filePath, ".."), { recursive: true });
13635
- await fs24.writeFile(filePath, content, "utf-8");
13737
+ const filePath = join14(rulePresetDir, filename);
13738
+ await fs23.mkdir(join14(filePath, ".."), { recursive: true });
13739
+ await fs23.writeFile(filePath, content, "utf-8");
13636
13740
  }
13637
13741
  console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
13638
13742
  const allGeneratedFiles = [];
@@ -13640,9 +13744,9 @@ function createRulesApplyCommand() {
13640
13744
  try {
13641
13745
  const files = generatorService.generateForIde(bundle, ideId);
13642
13746
  for (const file of files) {
13643
- const fullPath = join15(process.cwd(), file.path);
13644
- await fs24.mkdir(join15(fullPath, ".."), { recursive: true });
13645
- await fs24.writeFile(fullPath, file.content, "utf-8");
13747
+ const fullPath = join14(process.cwd(), file.path);
13748
+ await fs23.mkdir(join14(fullPath, ".."), { recursive: true });
13749
+ await fs23.writeFile(fullPath, file.content, "utf-8");
13646
13750
  console.log(`\u2713 [${ideId}] ${file.path}`);
13647
13751
  allGeneratedFiles.push({
13648
13752
  ide: ideId,
@@ -13747,11 +13851,11 @@ function createRulesApplyCommand() {
13747
13851
  }
13748
13852
 
13749
13853
  // src/commands/rules/restore.ts
13750
- import { Command as Command79 } from "commander";
13751
- import { join as join16 } from "path";
13854
+ import { Command as Command83 } from "commander";
13855
+ import { join as join15 } from "path";
13752
13856
  import { select as select5, confirm as confirm16 } from "@inquirer/prompts";
13753
13857
  function createRulesRestoreCommand() {
13754
- return new Command79("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
13858
+ return new Command83("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
13755
13859
  const backupService = new BackupService();
13756
13860
  const backups = await backupService.listBackups();
13757
13861
  if (backups.length === 0) {
@@ -13795,7 +13899,7 @@ function createRulesRestoreCommand() {
13795
13899
  }
13796
13900
  console.log("\n\u{1F504} Restoring backup...\n");
13797
13901
  try {
13798
- const backupPath = join16(backupService.getBackupDir(), selectedBackup.timestamp);
13902
+ const backupPath = join15(backupService.getBackupDir(), selectedBackup.timestamp);
13799
13903
  await backupService.restoreBackup(backupPath);
13800
13904
  console.log("\n\u2705 Backup restored successfully!\n");
13801
13905
  console.log("\u{1F4A1} Tip: Your IDE may need to be restarted to pick up the changes.");
@@ -13820,18 +13924,18 @@ function formatTimestamp(timestamp) {
13820
13924
  }
13821
13925
 
13822
13926
  // src/commands/rules/sync.ts
13823
- import { Command as Command80 } from "commander";
13824
- import { promises as fs25 } from "fs";
13825
- import { join as join17 } from "path";
13927
+ import { Command as Command84 } from "commander";
13928
+ import { promises as fs24 } from "fs";
13929
+ import { join as join16 } from "path";
13826
13930
  import { checkbox as checkbox6, confirm as confirm17, Separator } from "@inquirer/prompts";
13827
13931
  function createRulesSyncCommand() {
13828
- return new Command80("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) => {
13829
- const rulePresetDir = join17(process.cwd(), ".jai1", "rule-preset");
13830
- const presetJsonPath = join17(rulePresetDir, "preset.json");
13932
+ return new Command84("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) => {
13933
+ const rulePresetDir = join16(process.cwd(), ".jai1", "rule-preset");
13934
+ const presetJsonPath = join16(rulePresetDir, "preset.json");
13831
13935
  let presetExists = false;
13832
13936
  let presetData = null;
13833
13937
  try {
13834
- const presetContent = await fs25.readFile(presetJsonPath, "utf-8");
13938
+ const presetContent = await fs24.readFile(presetJsonPath, "utf-8");
13835
13939
  presetData = JSON.parse(presetContent);
13836
13940
  presetExists = true;
13837
13941
  } catch {
@@ -13961,11 +14065,11 @@ Current IDE(s): ${currentIdes.join(", ") || "none"}`);
13961
14065
  throw new Error(`Failed to fetch preset: ${presetResponse.statusText}`);
13962
14066
  }
13963
14067
  const bundle = await presetResponse.json();
13964
- const files = await fs25.readdir(rulePresetDir);
14068
+ const files = await fs24.readdir(rulePresetDir);
13965
14069
  for (const file of files) {
13966
14070
  if (file.endsWith(".mdc") || file.endsWith(".md")) {
13967
- const filePath = join17(rulePresetDir, file);
13968
- const content = await fs25.readFile(filePath, "utf-8");
14071
+ const filePath = join16(rulePresetDir, file);
14072
+ const content = await fs24.readFile(filePath, "utf-8");
13969
14073
  bundle.files[file] = content;
13970
14074
  }
13971
14075
  }
@@ -13979,9 +14083,9 @@ Current IDE(s): ${currentIdes.join(", ") || "none"}`);
13979
14083
  }
13980
14084
  const files2 = generatorService.generateForIde(bundle, ideId);
13981
14085
  for (const file of files2) {
13982
- const fullPath = join17(process.cwd(), file.path);
13983
- await fs25.mkdir(join17(fullPath, ".."), { recursive: true });
13984
- await fs25.writeFile(fullPath, file.content, "utf-8");
14086
+ const fullPath = join16(process.cwd(), file.path);
14087
+ await fs24.mkdir(join16(fullPath, ".."), { recursive: true });
14088
+ await fs24.writeFile(fullPath, file.content, "utf-8");
13985
14089
  }
13986
14090
  console.log(`\u2713 ${format.name} - ${files2.length} files regenerated`);
13987
14091
  } catch (error) {
@@ -14043,11 +14147,11 @@ function buildIdeChoices(currentIdes, detected, suggestions) {
14043
14147
  }
14044
14148
 
14045
14149
  // src/commands/rules/info.ts
14046
- import { Command as Command81 } from "commander";
14047
- import { promises as fs26 } from "fs";
14048
- import { join as join18 } from "path";
14150
+ import { Command as Command85 } from "commander";
14151
+ import { promises as fs25 } from "fs";
14152
+ import { join as join17 } from "path";
14049
14153
  function createRulesInfoCommand() {
14050
- return new Command81("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
14154
+ return new Command85("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
14051
14155
  const projectConfigService = new ProjectConfigService();
14052
14156
  const rulesConfig = await projectConfigService.loadRules();
14053
14157
  if (!rulesConfig) {
@@ -14060,14 +14164,14 @@ function createRulesInfoCommand() {
14060
14164
  return;
14061
14165
  }
14062
14166
  console.log("\u{1F4CB} Current Preset Information\n");
14063
- const rulePresetDir = join18(process.cwd(), ".jai1", "rule-preset");
14064
- const presetJsonPath = join18(rulePresetDir, "preset.json");
14167
+ const rulePresetDir = join17(process.cwd(), ".jai1", "rule-preset");
14168
+ const presetJsonPath = join17(rulePresetDir, "preset.json");
14065
14169
  let presetMetadata = null;
14066
14170
  let presetFiles = [];
14067
14171
  try {
14068
- const presetContent = await fs26.readFile(presetJsonPath, "utf-8");
14172
+ const presetContent = await fs25.readFile(presetJsonPath, "utf-8");
14069
14173
  presetMetadata = JSON.parse(presetContent);
14070
- const files = await fs26.readdir(rulePresetDir);
14174
+ const files = await fs25.readdir(rulePresetDir);
14071
14175
  presetFiles = files.filter((f) => f.endsWith(".mdc"));
14072
14176
  } catch {
14073
14177
  }
@@ -14128,7 +14232,7 @@ Available Backups (${rulesConfig.backups.length}):`);
14128
14232
  }
14129
14233
  async function checkPathExists(path13) {
14130
14234
  try {
14131
- await fs26.access(join18(process.cwd(), path13));
14235
+ await fs25.access(join17(process.cwd(), path13));
14132
14236
  return true;
14133
14237
  } catch {
14134
14238
  return false;
@@ -14150,26 +14254,26 @@ async function checkIdeFilesExist(ideId, format) {
14150
14254
 
14151
14255
  // src/commands/rules/index.ts
14152
14256
  function showRulesHelp() {
14153
- console.log(chalk47.bold.cyan("\u{1F4CB} jai1 rules") + chalk47.dim(" - Qu\u1EA3n l\xFD rule presets cho AI agents"));
14257
+ console.log(chalk50.bold.cyan("\u{1F4CB} jai1 rules") + chalk50.dim(" - Qu\u1EA3n l\xFD rule presets cho AI agents"));
14154
14258
  console.log();
14155
- console.log(chalk47.bold("C\xE1c l\u1EC7nh:"));
14156
- console.log(` ${chalk47.cyan("list")} Li\u1EC7t k\xEA c\xE1c presets c\xF3 s\u1EB5n`);
14157
- console.log(` ${chalk47.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t preset`);
14158
- console.log(` ${chalk47.cyan("init")} Kh\u1EDFi t\u1EA1o rules t\u1EEB preset`);
14159
- console.log(` ${chalk47.cyan("apply")} \xC1p d\u1EE5ng preset v\xE0o project`);
14160
- console.log(` ${chalk47.cyan("sync")} \u0110\u1ED3ng b\u1ED9 rules sang c\xE1c \u0111\u1ECBnh d\u1EA1ng IDE`);
14161
- console.log(` ${chalk47.cyan("restore")} Kh\xF4i ph\u1EE5c rules t\u1EEB backup`);
14259
+ console.log(chalk50.bold("C\xE1c l\u1EC7nh:"));
14260
+ console.log(` ${chalk50.cyan("list")} Li\u1EC7t k\xEA c\xE1c presets c\xF3 s\u1EB5n`);
14261
+ console.log(` ${chalk50.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t preset`);
14262
+ console.log(` ${chalk50.cyan("init")} Kh\u1EDFi t\u1EA1o rules t\u1EEB preset`);
14263
+ console.log(` ${chalk50.cyan("apply")} \xC1p d\u1EE5ng preset v\xE0o project`);
14264
+ console.log(` ${chalk50.cyan("sync")} \u0110\u1ED3ng b\u1ED9 rules sang c\xE1c \u0111\u1ECBnh d\u1EA1ng IDE`);
14265
+ console.log(` ${chalk50.cyan("restore")} Kh\xF4i ph\u1EE5c rules t\u1EEB backup`);
14162
14266
  console.log();
14163
- console.log(chalk47.bold("V\xED d\u1EE5:"));
14164
- console.log(chalk47.dim(" $ jai1 rules list"));
14165
- console.log(chalk47.dim(" $ jai1 rules info react-typescript"));
14166
- console.log(chalk47.dim(" $ jai1 rules init --preset=react-typescript"));
14167
- console.log(chalk47.dim(" $ jai1 rules apply react-typescript"));
14267
+ console.log(chalk50.bold("V\xED d\u1EE5:"));
14268
+ console.log(chalk50.dim(" $ jai1 rules list"));
14269
+ console.log(chalk50.dim(" $ jai1 rules info react-typescript"));
14270
+ console.log(chalk50.dim(" $ jai1 rules init --preset=react-typescript"));
14271
+ console.log(chalk50.dim(" $ jai1 rules apply react-typescript"));
14168
14272
  console.log();
14169
- console.log(chalk47.dim('Ch\u1EA1y "jai1 rules <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
14273
+ console.log(chalk50.dim('Ch\u1EA1y "jai1 rules <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
14170
14274
  }
14171
14275
  function createRulesCommand() {
14172
- const rulesCommand = new Command82("rules").description("Manage rule presets for AI agents").action(() => {
14276
+ const rulesCommand = new Command86("rules").description("Manage rule presets for AI agents").action(() => {
14173
14277
  showRulesHelp();
14174
14278
  });
14175
14279
  rulesCommand.addCommand(createRulesListCommand());
@@ -14182,16 +14286,16 @@ function createRulesCommand() {
14182
14286
  }
14183
14287
 
14184
14288
  // src/commands/skills/index.ts
14185
- import { Command as Command88 } from "commander";
14186
- import chalk53 from "chalk";
14289
+ import { Command as Command92 } from "commander";
14290
+ import chalk56 from "chalk";
14187
14291
 
14188
14292
  // src/commands/skills/find.ts
14189
- import { Command as Command83 } from "commander";
14190
- import chalk48 from "chalk";
14293
+ import { Command as Command87 } from "commander";
14294
+ import chalk51 from "chalk";
14191
14295
 
14192
14296
  // src/services/skills.service.ts
14193
- import { promises as fs27 } from "fs";
14194
- import { join as join19 } from "path";
14297
+ import { promises as fs26 } from "fs";
14298
+ import { join as join18 } from "path";
14195
14299
  import { execFile } from "child_process";
14196
14300
  import { promisify } from "util";
14197
14301
  var execFileAsync = promisify(execFile);
@@ -14227,20 +14331,20 @@ var SkillsService = class {
14227
14331
  * List locally installed skills from .jai1/skills/
14228
14332
  */
14229
14333
  async listLocal(projectRoot) {
14230
- const skillsDir = join19(projectRoot, ".jai1", "skills");
14334
+ const skillsDir = join18(projectRoot, ".jai1", "skills");
14231
14335
  const skills = [];
14232
14336
  try {
14233
- const entries = await fs27.readdir(skillsDir, { withFileTypes: true });
14337
+ const entries = await fs26.readdir(skillsDir, { withFileTypes: true });
14234
14338
  for (const entry of entries) {
14235
14339
  if (!entry.isDirectory()) continue;
14236
- const skillPath = join19(skillsDir, entry.name);
14237
- const skillMd = join19(skillPath, "SKILL.md");
14340
+ const skillPath = join18(skillsDir, entry.name);
14341
+ const skillMd = join18(skillPath, "SKILL.md");
14238
14342
  try {
14239
- await fs27.access(skillMd);
14343
+ await fs26.access(skillMd);
14240
14344
  } catch {
14241
14345
  continue;
14242
14346
  }
14243
- const content = await fs27.readFile(skillMd, "utf-8");
14347
+ const content = await fs26.readFile(skillMd, "utf-8");
14244
14348
  const { name, description } = this.parseFrontmatter(content);
14245
14349
  const fileCount = await this.countFiles(skillPath);
14246
14350
  skills.push({
@@ -14259,14 +14363,14 @@ var SkillsService = class {
14259
14363
  * Get detailed info for a single skill
14260
14364
  */
14261
14365
  async getSkillInfo(projectRoot, skillName) {
14262
- const skillPath = join19(projectRoot, ".jai1", "skills", skillName);
14263
- const skillMd = join19(skillPath, "SKILL.md");
14366
+ const skillPath = join18(projectRoot, ".jai1", "skills", skillName);
14367
+ const skillMd = join18(skillPath, "SKILL.md");
14264
14368
  try {
14265
- await fs27.access(skillMd);
14369
+ await fs26.access(skillMd);
14266
14370
  } catch {
14267
14371
  return null;
14268
14372
  }
14269
- const content = await fs27.readFile(skillMd, "utf-8");
14373
+ const content = await fs26.readFile(skillMd, "utf-8");
14270
14374
  const { name, description } = this.parseFrontmatter(content);
14271
14375
  const fileCount = await this.countFiles(skillPath);
14272
14376
  return {
@@ -14335,26 +14439,26 @@ var SkillsService = class {
14335
14439
  * After npx skills add, copy newly installed skills from .agents/skills/ into .jai1/skills/
14336
14440
  */
14337
14441
  async copySkillshResultsToJai1(projectRoot, specificSkill) {
14338
- const jai1SkillsDir = join19(projectRoot, ".jai1", "skills");
14339
- await fs27.mkdir(jai1SkillsDir, { recursive: true });
14340
- const universalDir = join19(projectRoot, ".agents", "skills");
14442
+ const jai1SkillsDir = join18(projectRoot, ".jai1", "skills");
14443
+ await fs26.mkdir(jai1SkillsDir, { recursive: true });
14444
+ const universalDir = join18(projectRoot, ".agents", "skills");
14341
14445
  try {
14342
- const entries = await fs27.readdir(universalDir, { withFileTypes: true });
14446
+ const entries = await fs26.readdir(universalDir, { withFileTypes: true });
14343
14447
  for (const entry of entries) {
14344
14448
  if (!entry.isDirectory()) continue;
14345
14449
  if (specificSkill && entry.name !== specificSkill) continue;
14346
- const srcSkill = join19(universalDir, entry.name);
14347
- const skillMd = join19(srcSkill, "SKILL.md");
14450
+ const srcSkill = join18(universalDir, entry.name);
14451
+ const skillMd = join18(srcSkill, "SKILL.md");
14348
14452
  try {
14349
- await fs27.access(skillMd);
14453
+ await fs26.access(skillMd);
14350
14454
  } catch {
14351
14455
  continue;
14352
14456
  }
14353
- const targetSkill = join19(jai1SkillsDir, entry.name);
14457
+ const targetSkill = join18(jai1SkillsDir, entry.name);
14354
14458
  try {
14355
- await fs27.access(targetSkill);
14459
+ await fs26.access(targetSkill);
14356
14460
  } catch {
14357
- await fs27.mkdir(targetSkill, { recursive: true });
14461
+ await fs26.mkdir(targetSkill, { recursive: true });
14358
14462
  await this.copyDir(srcSkill, targetSkill);
14359
14463
  }
14360
14464
  }
@@ -14389,16 +14493,16 @@ var SkillsService = class {
14389
14493
  const target = this.getIDETarget(ide);
14390
14494
  if (!target) continue;
14391
14495
  for (const skill of skillsToSync) {
14392
- const targetPath = join19(projectRoot, target.skillsPath, skill.slug);
14496
+ const targetPath = join18(projectRoot, target.skillsPath, skill.slug);
14393
14497
  try {
14394
14498
  let status = "created";
14395
14499
  try {
14396
- await fs27.access(targetPath);
14500
+ await fs26.access(targetPath);
14397
14501
  status = "updated";
14398
- await fs27.rm(targetPath, { recursive: true, force: true });
14502
+ await fs26.rm(targetPath, { recursive: true, force: true });
14399
14503
  } catch {
14400
14504
  }
14401
- await fs27.mkdir(targetPath, { recursive: true });
14505
+ await fs26.mkdir(targetPath, { recursive: true });
14402
14506
  await this.copyDir(skill.path, targetPath);
14403
14507
  if (status === "created") created++;
14404
14508
  else updated++;
@@ -14450,10 +14554,10 @@ var SkillsService = class {
14450
14554
  */
14451
14555
  async countFiles(dirPath) {
14452
14556
  let count = 0;
14453
- const entries = await fs27.readdir(dirPath, { withFileTypes: true });
14557
+ const entries = await fs26.readdir(dirPath, { withFileTypes: true });
14454
14558
  for (const entry of entries) {
14455
14559
  if (entry.isDirectory()) {
14456
- count += await this.countFiles(join19(dirPath, entry.name));
14560
+ count += await this.countFiles(join18(dirPath, entry.name));
14457
14561
  } else {
14458
14562
  count++;
14459
14563
  }
@@ -14464,15 +14568,15 @@ var SkillsService = class {
14464
14568
  * Copy directory recursively
14465
14569
  */
14466
14570
  async copyDir(source, target) {
14467
- const entries = await fs27.readdir(source, { withFileTypes: true });
14571
+ const entries = await fs26.readdir(source, { withFileTypes: true });
14468
14572
  for (const entry of entries) {
14469
- const srcPath = join19(source, entry.name);
14470
- const tgtPath = join19(target, entry.name);
14573
+ const srcPath = join18(source, entry.name);
14574
+ const tgtPath = join18(target, entry.name);
14471
14575
  if (entry.isDirectory()) {
14472
- await fs27.mkdir(tgtPath, { recursive: true });
14576
+ await fs26.mkdir(tgtPath, { recursive: true });
14473
14577
  await this.copyDir(srcPath, tgtPath);
14474
14578
  } else {
14475
- await fs27.copyFile(srcPath, tgtPath);
14579
+ await fs26.copyFile(srcPath, tgtPath);
14476
14580
  }
14477
14581
  }
14478
14582
  }
@@ -14480,7 +14584,7 @@ var SkillsService = class {
14480
14584
 
14481
14585
  // src/commands/skills/find.ts
14482
14586
  function createSkillsFindCommand() {
14483
- return new Command83("find").description("Search for skills on server or npm").argument("<query>", "Search query").option("--skillsh", "Search on npm skills registry instead of Jai1 server").option("--all", "Search on both Jai1 server and npm").action(async (query, options) => {
14587
+ return new Command87("find").description("Search for skills on server or npm").argument("<query>", "Search query").option("--skillsh", "Search on npm skills registry instead of Jai1 server").option("--all", "Search on both Jai1 server and npm").action(async (query, options) => {
14484
14588
  const searchNpm = options.skillsh || options.all;
14485
14589
  const searchServer = !options.skillsh || options.all;
14486
14590
  if (searchServer) {
@@ -14489,83 +14593,83 @@ function createSkillsFindCommand() {
14489
14593
  if (!config) {
14490
14594
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
14491
14595
  }
14492
- console.log(chalk48.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn Jai1 server..."));
14596
+ console.log(chalk51.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn Jai1 server..."));
14493
14597
  console.log();
14494
14598
  const skillsService = new SkillsService();
14495
14599
  const results = await skillsService.searchFromServer(config, query);
14496
14600
  if (results.length === 0) {
14497
- console.log(chalk48.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o tr\xEAn server."));
14601
+ console.log(chalk51.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o tr\xEAn server."));
14498
14602
  } else {
14499
- console.log(chalk48.bold(`\u{1F4E6} Jai1 Server (${results.length} k\u1EBFt qu\u1EA3)
14603
+ console.log(chalk51.bold(`\u{1F4E6} Jai1 Server (${results.length} k\u1EBFt qu\u1EA3)
14500
14604
  `));
14501
14605
  for (const skill of results) {
14502
14606
  const name = skill.filepath.replace("skills/", "");
14503
- const version = skill.version ? chalk48.green(`v${skill.version}`) : chalk48.dim("-");
14504
- const downloads = chalk48.dim(`${skill.downloads || 0} downloads`);
14607
+ const version = skill.version ? chalk51.green(`v${skill.version}`) : chalk51.dim("-");
14608
+ const downloads = chalk51.dim(`${skill.downloads || 0} downloads`);
14505
14609
  const desc = skill.description || "";
14506
14610
  const maxDesc = 120;
14507
14611
  const truncatedDesc = desc.length > maxDesc ? desc.slice(0, maxDesc) + "\u2026" : desc;
14508
- console.log(` ${chalk48.bold.white(name)} ${version} \xB7 ${downloads}`);
14612
+ console.log(` ${chalk51.bold.white(name)} ${version} \xB7 ${downloads}`);
14509
14613
  if (truncatedDesc) {
14510
- console.log(` ${chalk48.dim(truncatedDesc)}`);
14614
+ console.log(` ${chalk51.dim(truncatedDesc)}`);
14511
14615
  }
14512
14616
  console.log();
14513
14617
  }
14514
14618
  }
14515
14619
  }
14516
14620
  if (searchNpm) {
14517
- console.log(chalk48.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn npm skills..."));
14621
+ console.log(chalk51.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn npm skills..."));
14518
14622
  console.log();
14519
14623
  const skillsService = new SkillsService();
14520
14624
  try {
14521
14625
  const output = await skillsService.npmSkillsFind(query);
14522
- console.log(chalk48.bold("\u{1F310} npm Skills Registry"));
14626
+ console.log(chalk51.bold("\u{1F310} npm Skills Registry"));
14523
14627
  console.log(output);
14524
14628
  } catch (error) {
14525
- console.log(chalk48.yellow(
14629
+ console.log(chalk51.yellow(
14526
14630
  `Kh\xF4ng th\u1EC3 t\xECm ki\u1EBFm tr\xEAn npm: ${error instanceof Error ? error.message : String(error)}`
14527
14631
  ));
14528
14632
  }
14529
14633
  }
14530
14634
  if (searchServer && !searchNpm) {
14531
- console.log(chalk48.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t t\u1EEB server'));
14635
+ console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t t\u1EEB server'));
14532
14636
  } else if (searchNpm && !searchServer) {
14533
- console.log(chalk48.dim('\u{1F4A1} D\xF9ng "j skills add <owner/repo@skill> --skillsh" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14637
+ console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills add <owner/repo@skill> --skillsh" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14534
14638
  } else {
14535
- console.log(chalk48.dim("\u{1F4A1} C\xE0i \u0111\u1EB7t:"));
14536
- console.log(chalk48.dim(" Server: j skills add <t\xEAn>"));
14537
- console.log(chalk48.dim(" Skills.sh: j skills add <owner/repo@skill> --skillsh"));
14639
+ console.log(chalk51.dim("\u{1F4A1} C\xE0i \u0111\u1EB7t:"));
14640
+ console.log(chalk51.dim(" Server: j skills add <t\xEAn>"));
14641
+ console.log(chalk51.dim(" Skills.sh: j skills add <owner/repo@skill> --skillsh"));
14538
14642
  }
14539
14643
  });
14540
14644
  }
14541
14645
 
14542
14646
  // src/commands/skills/add.ts
14543
- import { Command as Command84 } from "commander";
14544
- import { join as join20 } from "path";
14545
- import chalk49 from "chalk";
14647
+ import { Command as Command88 } from "commander";
14648
+ import { join as join19 } from "path";
14649
+ import chalk52 from "chalk";
14546
14650
  import { checkbox as checkbox7 } from "@inquirer/prompts";
14547
14651
  function createSkillsAddCommand() {
14548
- return new Command84("add").description("Install a skill to .jai1/skills/").argument("<name>", "Skill name or source (npm: GitHub shorthand, URL)").option("--skillsh", "Install from npm skills registry instead of Jai1 server").option("--sync", "Auto-sync to IDE(s) after install").option("--ides <ides...>", "Target IDEs for sync (cursor, windsurf, antigravity, claudecode, opencode)").option("--all", "Sync to all available IDEs").option("-y, --yes", "Headless mode (skip all prompts)").action(async (name, options) => {
14652
+ return new Command88("add").description("Install a skill to .jai1/skills/").argument("<name>", "Skill name or source (npm: GitHub shorthand, URL)").option("--skillsh", "Install from npm skills registry instead of Jai1 server").option("--sync", "Auto-sync to IDE(s) after install").option("--ides <ides...>", "Target IDEs for sync (cursor, windsurf, antigravity, claudecode, opencode)").option("--all", "Sync to all available IDEs").option("-y, --yes", "Headless mode (skip all prompts)").action(async (name, options) => {
14549
14653
  const skillsService = new SkillsService();
14550
14654
  const projectRoot = process.cwd();
14551
14655
  const headless = options.yes === true;
14552
14656
  if (options.skillsh) {
14553
- console.log(chalk49.cyan(`\u{1F310} \u0110ang c\xE0i \u0111\u1EB7t skill t\u1EEB npm: ${name}...`));
14657
+ console.log(chalk52.cyan(`\u{1F310} \u0110ang c\xE0i \u0111\u1EB7t skill t\u1EEB npm: ${name}...`));
14554
14658
  console.log();
14555
14659
  const output = await skillsService.npmSkillsAdd(name, projectRoot);
14556
14660
  console.log(output);
14557
- console.log(chalk49.green("\u2705 C\xE0i \u0111\u1EB7t t\u1EEB npm th\xE0nh c\xF4ng!"));
14661
+ console.log(chalk52.green("\u2705 C\xE0i \u0111\u1EB7t t\u1EEB npm th\xE0nh c\xF4ng!"));
14558
14662
  } else {
14559
14663
  const configService = new ConfigService();
14560
14664
  const config = await configService.load();
14561
14665
  if (!config) {
14562
14666
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
14563
14667
  }
14564
- console.log(chalk49.cyan(`\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t skill: ${name}...`));
14668
+ console.log(chalk52.cyan(`\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t skill: ${name}...`));
14565
14669
  console.log();
14566
- const targetDir = join20(projectRoot, ".jai1");
14670
+ const targetDir = join19(projectRoot, ".jai1");
14567
14671
  await skillsService.installFromServer(config, name, targetDir);
14568
- console.log(chalk49.green(`\u2705 \u0110\xE3 c\xE0i \u0111\u1EB7t skill "${name}" v\xE0o .jai1/skills/${name}/`));
14672
+ console.log(chalk52.green(`\u2705 \u0110\xE3 c\xE0i \u0111\u1EB7t skill "${name}" v\xE0o .jai1/skills/${name}/`));
14569
14673
  }
14570
14674
  console.log();
14571
14675
  if (options.sync) {
@@ -14590,7 +14694,7 @@ function createSkillsAddCommand() {
14590
14694
  });
14591
14695
  }
14592
14696
  if (selectedIdes.length > 0) {
14593
- console.log(chalk49.cyan("\u{1F504} \u0110ang sync sang IDE(s)..."));
14697
+ console.log(chalk52.cyan("\u{1F504} \u0110ang sync sang IDE(s)..."));
14594
14698
  console.log();
14595
14699
  const slug = name.includes("/") ? name.split("/").pop() : name;
14596
14700
  const result = await skillsService.syncToIdes(
@@ -14603,24 +14707,24 @@ function createSkillsAddCommand() {
14603
14707
  }
14604
14708
  );
14605
14709
  console.log();
14606
- console.log(chalk49.green(`\u2705 Sync ho\xE0n t\u1EA5t! Created: ${result.created}, Updated: ${result.updated}`));
14710
+ console.log(chalk52.green(`\u2705 Sync ho\xE0n t\u1EA5t! Created: ${result.created}, Updated: ${result.updated}`));
14607
14711
  if (result.errors > 0) {
14608
- console.log(chalk49.yellow(`\u26A0\uFE0F Errors: ${result.errors}`));
14712
+ console.log(chalk52.yellow(`\u26A0\uFE0F Errors: ${result.errors}`));
14609
14713
  }
14610
14714
  }
14611
14715
  } else {
14612
- console.log(chalk49.dim('\u{1F4A1} Ch\u1EA1y "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14613
- console.log(chalk49.dim(' ho\u1EB7c "j ide sync" \u0111\u1EC3 sync to\xE0n b\u1ED9 .jai1/'));
14716
+ console.log(chalk52.dim('\u{1F4A1} Ch\u1EA1y "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14717
+ console.log(chalk52.dim(' ho\u1EB7c "j ide sync" \u0111\u1EC3 sync to\xE0n b\u1ED9 .jai1/'));
14614
14718
  }
14615
14719
  });
14616
14720
  }
14617
14721
 
14618
14722
  // src/commands/skills/list.ts
14619
- import { Command as Command85 } from "commander";
14620
- import chalk50 from "chalk";
14723
+ import { Command as Command89 } from "commander";
14724
+ import chalk53 from "chalk";
14621
14725
  import Table8 from "cli-table3";
14622
14726
  function createSkillsListCommand() {
14623
- return new Command85("list").description("List installed skills or available skills on server").option("--available", "List all skills available on Jai1 server").option("-s, --search <term>", "Search skills by name or description").action(async (options) => {
14727
+ return new Command89("list").description("List installed skills or available skills on server").option("--available", "List all skills available on Jai1 server").option("-s, --search <term>", "Search skills by name or description").action(async (options) => {
14624
14728
  const skillsService = new SkillsService();
14625
14729
  if (options.available) {
14626
14730
  const configService = new ConfigService();
@@ -14628,19 +14732,19 @@ function createSkillsListCommand() {
14628
14732
  if (!config) {
14629
14733
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
14630
14734
  }
14631
- console.log(chalk50.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch skills t\u1EEB server..."));
14735
+ console.log(chalk53.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch skills t\u1EEB server..."));
14632
14736
  console.log();
14633
14737
  const results = await skillsService.searchFromServer(config, options.search);
14634
14738
  if (results.length === 0) {
14635
- console.log(chalk50.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o."));
14739
+ console.log(chalk53.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o."));
14636
14740
  return;
14637
14741
  }
14638
14742
  const table = new Table8({
14639
14743
  head: [
14640
- chalk50.cyan("T\xEAn"),
14641
- chalk50.cyan("M\xF4 t\u1EA3"),
14642
- chalk50.cyan("Version"),
14643
- chalk50.cyan("Downloads")
14744
+ chalk53.cyan("T\xEAn"),
14745
+ chalk53.cyan("M\xF4 t\u1EA3"),
14746
+ chalk53.cyan("Version"),
14747
+ chalk53.cyan("Downloads")
14644
14748
  ],
14645
14749
  style: { head: [], border: ["gray"] },
14646
14750
  colWidths: [28, 40, 10, 12]
@@ -14648,72 +14752,72 @@ function createSkillsListCommand() {
14648
14752
  for (const skill of results) {
14649
14753
  const name = skill.filepath.replace("skills/", "");
14650
14754
  table.push([
14651
- chalk50.white(name),
14652
- chalk50.dim((skill.description || "").slice(0, 38)),
14653
- chalk50.green(skill.version || "-"),
14654
- chalk50.dim(String(skill.downloads || 0))
14755
+ chalk53.white(name),
14756
+ chalk53.dim((skill.description || "").slice(0, 38)),
14757
+ chalk53.green(skill.version || "-"),
14758
+ chalk53.dim(String(skill.downloads || 0))
14655
14759
  ]);
14656
14760
  }
14657
14761
  console.log(table.toString());
14658
14762
  console.log();
14659
- console.log(chalk50.dim(`T\u1ED5ng c\u1ED9ng: ${results.length} skill(s)`));
14660
- console.log(chalk50.dim('\n\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14763
+ console.log(chalk53.dim(`T\u1ED5ng c\u1ED9ng: ${results.length} skill(s)`));
14764
+ console.log(chalk53.dim('\n\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14661
14765
  } else {
14662
14766
  const projectRoot = process.cwd();
14663
14767
  const skills = await skillsService.listLocal(projectRoot);
14664
14768
  if (skills.length === 0) {
14665
- console.log(chalk50.yellow("Ch\u01B0a c\xF3 skills n\xE0o \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t."));
14769
+ console.log(chalk53.yellow("Ch\u01B0a c\xF3 skills n\xE0o \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t."));
14666
14770
  console.log();
14667
- console.log(chalk50.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14668
- console.log(chalk50.dim(' ho\u1EB7c "j skills list --available" \u0111\u1EC3 xem skills c\xF3 s\u1EB5n'));
14771
+ console.log(chalk53.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14772
+ console.log(chalk53.dim(' ho\u1EB7c "j skills list --available" \u0111\u1EC3 xem skills c\xF3 s\u1EB5n'));
14669
14773
  return;
14670
14774
  }
14671
- console.log(chalk50.bold.cyan("\u{1F6E0} Skills \u0111\xE3 c\xE0i \u0111\u1EB7t"));
14775
+ console.log(chalk53.bold.cyan("\u{1F6E0} Skills \u0111\xE3 c\xE0i \u0111\u1EB7t"));
14672
14776
  console.log();
14673
14777
  const table = new Table8({
14674
14778
  head: [
14675
- chalk50.cyan("T\xEAn"),
14676
- chalk50.cyan("M\xF4 t\u1EA3"),
14677
- chalk50.cyan("Files")
14779
+ chalk53.cyan("T\xEAn"),
14780
+ chalk53.cyan("M\xF4 t\u1EA3"),
14781
+ chalk53.cyan("Files")
14678
14782
  ],
14679
14783
  style: { head: [], border: ["gray"] },
14680
14784
  colWidths: [28, 45, 8]
14681
14785
  });
14682
14786
  for (const skill of skills) {
14683
14787
  table.push([
14684
- chalk50.white(skill.slug),
14685
- chalk50.dim(skill.description.slice(0, 43)),
14686
- chalk50.dim(String(skill.fileCount))
14788
+ chalk53.white(skill.slug),
14789
+ chalk53.dim(skill.description.slice(0, 43)),
14790
+ chalk53.dim(String(skill.fileCount))
14687
14791
  ]);
14688
14792
  }
14689
14793
  console.log(table.toString());
14690
14794
  console.log();
14691
- console.log(chalk50.dim(`T\u1ED5ng c\u1ED9ng: ${skills.length} skill(s)`));
14692
- console.log(chalk50.dim('\n\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14795
+ console.log(chalk53.dim(`T\u1ED5ng c\u1ED9ng: ${skills.length} skill(s)`));
14796
+ console.log(chalk53.dim('\n\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14693
14797
  }
14694
14798
  });
14695
14799
  }
14696
14800
 
14697
14801
  // src/commands/skills/info.ts
14698
- import { Command as Command86 } from "commander";
14699
- import chalk51 from "chalk";
14802
+ import { Command as Command90 } from "commander";
14803
+ import chalk54 from "chalk";
14700
14804
  function createSkillsInfoCommand() {
14701
- return new Command86("info").description("Show detailed information about a skill").argument("<name>", "Skill name").option("--server", "Show info from Jai1 server instead of local").action(async (name, options) => {
14805
+ return new Command90("info").description("Show detailed information about a skill").argument("<name>", "Skill name").option("--server", "Show info from Jai1 server instead of local").action(async (name, options) => {
14702
14806
  const skillsService = new SkillsService();
14703
14807
  if (options.server) {
14704
14808
  const configService = new ConfigService();
14705
14809
  const config = await configService.load();
14706
14810
  if (!config) {
14707
- console.log(chalk51.red('\u274C Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.'));
14811
+ console.log(chalk54.red('\u274C Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.'));
14708
14812
  process.exit(1);
14709
14813
  }
14710
14814
  const filepath = name.startsWith("skills/") ? name : `skills/${name}`;
14711
- const { ComponentsService: ComponentsService2 } = await import("./components.service-NWAWKII3.js");
14815
+ const { ComponentsService: ComponentsService2 } = await import("./components.service-JUUV4CUI.js");
14712
14816
  const componentsService = new ComponentsService2();
14713
14817
  try {
14714
14818
  const component = await componentsService.get(config, filepath);
14715
14819
  console.log(`
14716
- \u{1F6E0} ${chalk51.bold(component.name || name)}
14820
+ \u{1F6E0} ${chalk54.bold(component.name || name)}
14717
14821
  `);
14718
14822
  console.log(`Filepath: ${component.filepath}`);
14719
14823
  console.log(`Version: ${component.version}`);
@@ -14726,47 +14830,47 @@ function createSkillsInfoCommand() {
14726
14830
  }
14727
14831
  console.log(`Type: ${component.contentType}`);
14728
14832
  console.log();
14729
- console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14833
+ console.log(chalk54.dim('\u{1F4A1} D\xF9ng "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14730
14834
  } catch (error) {
14731
- console.log(chalk51.red(`\u274C Kh\xF4ng t\xECm th\u1EA5y skill "${name}" tr\xEAn server.`));
14835
+ console.log(chalk54.red(`\u274C Kh\xF4ng t\xECm th\u1EA5y skill "${name}" tr\xEAn server.`));
14732
14836
  process.exit(1);
14733
14837
  }
14734
14838
  } else {
14735
14839
  const projectRoot = process.cwd();
14736
14840
  const skill = await skillsService.getSkillInfo(projectRoot, name);
14737
14841
  if (!skill) {
14738
- console.log(chalk51.red(`\u274C Skill "${name}" ch\u01B0a \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t.`));
14739
- console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills info ' + name + ' --server" \u0111\u1EC3 xem tr\xEAn server'));
14740
- console.log(chalk51.dim(' ho\u1EB7c "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14842
+ console.log(chalk54.red(`\u274C Skill "${name}" ch\u01B0a \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t.`));
14843
+ console.log(chalk54.dim('\u{1F4A1} D\xF9ng "j skills info ' + name + ' --server" \u0111\u1EC3 xem tr\xEAn server'));
14844
+ console.log(chalk54.dim(' ho\u1EB7c "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14741
14845
  process.exit(1);
14742
14846
  }
14743
14847
  console.log(`
14744
- \u{1F6E0} ${chalk51.bold(skill.name)}
14848
+ \u{1F6E0} ${chalk54.bold(skill.name)}
14745
14849
  `);
14746
14850
  console.log(`Slug: ${skill.slug}`);
14747
- console.log(`Description: ${skill.description || chalk51.dim("(none)")}`);
14851
+ console.log(`Description: ${skill.description || chalk54.dim("(none)")}`);
14748
14852
  console.log(`Path: ${skill.path}`);
14749
14853
  console.log(`Files: ${skill.fileCount}`);
14750
14854
  console.log();
14751
- console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14855
+ console.log(chalk54.dim('\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14752
14856
  }
14753
14857
  });
14754
14858
  }
14755
14859
 
14756
14860
  // src/commands/skills/sync.ts
14757
- import { Command as Command87 } from "commander";
14758
- import chalk52 from "chalk";
14861
+ import { Command as Command91 } from "commander";
14862
+ import chalk55 from "chalk";
14759
14863
  import { confirm as confirm19, checkbox as checkbox8 } from "@inquirer/prompts";
14760
14864
  function createSkillsSyncCommand() {
14761
- return new Command87("sync").description("Sync skills from .jai1/skills/ to IDE directories").option("--ides <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--skills <skills...>", "Specific skill slugs to sync (default: all)").option("--all", "Select all available IDEs").option("--dry-run", "Preview changes without writing files").option("-y, --yes", "Headless mode (skip all prompts)").action(async (options) => {
14865
+ return new Command91("sync").description("Sync skills from .jai1/skills/ to IDE directories").option("--ides <ides...>", "Target IDEs (cursor, windsurf, antigravity, claudecode, opencode)").option("--skills <skills...>", "Specific skill slugs to sync (default: all)").option("--all", "Select all available IDEs").option("--dry-run", "Preview changes without writing files").option("-y, --yes", "Headless mode (skip all prompts)").action(async (options) => {
14762
14866
  const skillsService = new SkillsService();
14763
14867
  const projectRoot = process.cwd();
14764
14868
  const headless = options.yes === true;
14765
- console.log(chalk52.bold.cyan("\n\u{1F504} Sync skills sang IDE(s)\n"));
14869
+ console.log(chalk55.bold.cyan("\n\u{1F504} Sync skills sang IDE(s)\n"));
14766
14870
  const localSkills = await skillsService.listLocal(projectRoot);
14767
14871
  if (localSkills.length === 0) {
14768
- console.log(chalk52.yellow("\u26A0\uFE0F Kh\xF4ng c\xF3 skills n\xE0o trong .jai1/skills/"));
14769
- console.log(chalk52.dim('\u{1F4A1} Ch\u1EA1y "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t skills tr\u01B0\u1EDBc'));
14872
+ console.log(chalk55.yellow("\u26A0\uFE0F Kh\xF4ng c\xF3 skills n\xE0o trong .jai1/skills/"));
14873
+ console.log(chalk55.dim('\u{1F4A1} Ch\u1EA1y "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t skills tr\u01B0\u1EDBc'));
14770
14874
  process.exit(1);
14771
14875
  }
14772
14876
  console.log(`\u{1F4C1} T\xECm th\u1EA5y ${localSkills.length} skill(s) trong .jai1/skills/`);
@@ -14798,7 +14902,7 @@ function createSkillsSyncCommand() {
14798
14902
  theme: checkboxTheme
14799
14903
  });
14800
14904
  if (selectedIdes.length === 0) {
14801
- console.log(chalk52.yellow("\n\u26A0\uFE0F Ch\u01B0a ch\u1ECDn IDE n\xE0o!"));
14905
+ console.log(chalk55.yellow("\n\u26A0\uFE0F Ch\u01B0a ch\u1ECDn IDE n\xE0o!"));
14802
14906
  process.exit(0);
14803
14907
  }
14804
14908
  }
@@ -14813,7 +14917,7 @@ function createSkillsSyncCommand() {
14813
14917
  console.log(` Total: ${totalFiles} skill folder(s) s\u1EBD \u0111\u01B0\u1EE3c sync
14814
14918
  `);
14815
14919
  if (options.dryRun) {
14816
- console.log(chalk52.dim("\u{1F50D} DRY RUN - Kh\xF4ng c\xF3 file n\xE0o \u0111\u01B0\u1EE3c ghi\n"));
14920
+ console.log(chalk55.dim("\u{1F50D} DRY RUN - Kh\xF4ng c\xF3 file n\xE0o \u0111\u01B0\u1EE3c ghi\n"));
14817
14921
  return;
14818
14922
  }
14819
14923
  if (!headless) {
@@ -14822,25 +14926,25 @@ function createSkillsSyncCommand() {
14822
14926
  default: true
14823
14927
  });
14824
14928
  if (!confirmed) {
14825
- console.log(chalk52.yellow("\n\u274C \u0110\xE3 h\u1EE7y sync.\n"));
14929
+ console.log(chalk55.yellow("\n\u274C \u0110\xE3 h\u1EE7y sync.\n"));
14826
14930
  process.exit(0);
14827
14931
  }
14828
14932
  }
14829
- console.log(chalk52.cyan("\n\u{1F504} \u0110ang sync...\n"));
14933
+ console.log(chalk55.cyan("\n\u{1F504} \u0110ang sync...\n"));
14830
14934
  const result = await skillsService.syncToIdes(
14831
14935
  projectRoot,
14832
14936
  selectedIdes,
14833
14937
  selectedSlugs,
14834
14938
  (res) => {
14835
14939
  const icon = res.status === "created" ? "\u2713" : res.status === "updated" ? "\u21BB" : "\u2717";
14836
- const statusColor = res.status === "error" ? chalk52.red : chalk52.green;
14837
- console.log(` ${statusColor(icon)} ${res.ide}: ${res.skill} \u2192 ${chalk52.dim(res.path)}`);
14940
+ const statusColor = res.status === "error" ? chalk55.red : chalk55.green;
14941
+ console.log(` ${statusColor(icon)} ${res.ide}: ${res.skill} \u2192 ${chalk55.dim(res.path)}`);
14838
14942
  if (res.status === "error" && res.error) {
14839
- console.log(` ${chalk52.red("Error:")} ${res.error}`);
14943
+ console.log(` ${chalk55.red("Error:")} ${res.error}`);
14840
14944
  }
14841
14945
  }
14842
14946
  );
14843
- console.log(chalk52.green("\n\u2705 Sync ho\xE0n t\u1EA5t!\n"));
14947
+ console.log(chalk55.green("\n\u2705 Sync ho\xE0n t\u1EA5t!\n"));
14844
14948
  console.log(` Created: ${result.created}`);
14845
14949
  console.log(` Updated: ${result.updated}`);
14846
14950
  if (result.errors > 0) {
@@ -14853,27 +14957,27 @@ function createSkillsSyncCommand() {
14853
14957
  // src/commands/skills/index.ts
14854
14958
  function showSkillsHelp() {
14855
14959
  const cli = getCliName();
14856
- console.log(chalk53.bold.cyan("\u{1F6E0} " + cli + " skills") + chalk53.dim(" - Qu\u1EA3n l\xFD agent skills"));
14960
+ console.log(chalk56.bold.cyan("\u{1F6E0} " + cli + " skills") + chalk56.dim(" - Qu\u1EA3n l\xFD agent skills"));
14857
14961
  console.log();
14858
- console.log(chalk53.bold("C\xE1c l\u1EC7nh:"));
14859
- console.log(` ${chalk53.cyan("find")} T\xECm ki\u1EBFm skills tr\xEAn server ho\u1EB7c npm`);
14860
- console.log(` ${chalk53.cyan("add")} C\xE0i \u0111\u1EB7t skill v\xE0o .jai1/skills/`);
14861
- console.log(` ${chalk53.cyan("list")} Li\u1EC7t k\xEA skills \u0111\xE3 c\xE0i ho\u1EB7c c\xF3 s\u1EB5n`);
14862
- console.log(` ${chalk53.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t skill`);
14863
- console.log(` ${chalk53.cyan("sync")} \u0110\u1ED3ng b\u1ED9 skills sang c\xE1c IDE`);
14962
+ console.log(chalk56.bold("C\xE1c l\u1EC7nh:"));
14963
+ console.log(` ${chalk56.cyan("find")} T\xECm ki\u1EBFm skills tr\xEAn server ho\u1EB7c npm`);
14964
+ console.log(` ${chalk56.cyan("add")} C\xE0i \u0111\u1EB7t skill v\xE0o .jai1/skills/`);
14965
+ console.log(` ${chalk56.cyan("list")} Li\u1EC7t k\xEA skills \u0111\xE3 c\xE0i ho\u1EB7c c\xF3 s\u1EB5n`);
14966
+ console.log(` ${chalk56.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t skill`);
14967
+ console.log(` ${chalk56.cyan("sync")} \u0110\u1ED3ng b\u1ED9 skills sang c\xE1c IDE`);
14864
14968
  console.log();
14865
- console.log(chalk53.bold("V\xED d\u1EE5:"));
14866
- console.log(chalk53.dim(` $ ${cli} skills find audit`));
14867
- console.log(chalk53.dim(` $ ${cli} skills find "react" --skillsh`));
14868
- console.log(chalk53.dim(` $ ${cli} skills add brainstorming`));
14869
- console.log(chalk53.dim(` $ ${cli} skills add vercel/next-skills --skillsh`));
14870
- console.log(chalk53.dim(` $ ${cli} skills list`));
14871
- console.log(chalk53.dim(` $ ${cli} skills sync --all -y`));
14969
+ console.log(chalk56.bold("V\xED d\u1EE5:"));
14970
+ console.log(chalk56.dim(` $ ${cli} skills find audit`));
14971
+ console.log(chalk56.dim(` $ ${cli} skills find "react" --skillsh`));
14972
+ console.log(chalk56.dim(` $ ${cli} skills add brainstorming`));
14973
+ console.log(chalk56.dim(` $ ${cli} skills add vercel/next-skills --skillsh`));
14974
+ console.log(chalk56.dim(` $ ${cli} skills list`));
14975
+ console.log(chalk56.dim(` $ ${cli} skills sync --all -y`));
14872
14976
  console.log();
14873
- console.log(chalk53.dim(`Ch\u1EA1y "${cli} skills <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt`));
14977
+ console.log(chalk56.dim(`Ch\u1EA1y "${cli} skills <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt`));
14874
14978
  }
14875
14979
  function createSkillsCommand() {
14876
- const cmd = new Command88("skills").alias("s").description("Manage agent skills (search, install, sync to IDEs)").action(() => {
14980
+ const cmd = new Command92("skills").alias("s").description("Manage agent skills (search, install, sync to IDEs)").action(() => {
14877
14981
  showSkillsHelp();
14878
14982
  });
14879
14983
  cmd.addCommand(createSkillsFindCommand());
@@ -14885,7 +14989,7 @@ function createSkillsCommand() {
14885
14989
  }
14886
14990
 
14887
14991
  // src/commands/upgrade.ts
14888
- import { Command as Command89 } from "commander";
14992
+ import { Command as Command93 } from "commander";
14889
14993
  import { confirm as confirm20 } from "@inquirer/prompts";
14890
14994
  import { execSync as execSync5 } from "child_process";
14891
14995
  var colors2 = {
@@ -14897,7 +15001,7 @@ var colors2 = {
14897
15001
  bold: "\x1B[1m"
14898
15002
  };
14899
15003
  function createUpgradeCommand() {
14900
- return new Command89("upgrade").description("Upgrade CLI client to the latest version").option("--check", "Only check for updates without installing").option("-y, --force", "Upgrade without confirmation prompt (skip if already latest)").action(async (options) => {
15004
+ return new Command93("upgrade").description("Upgrade CLI client to the latest version").option("--check", "Only check for updates without installing").option("-y, --force", "Upgrade without confirmation prompt (skip if already latest)").action(async (options) => {
14901
15005
  await handleUpgrade(options);
14902
15006
  });
14903
15007
  }
@@ -15050,13 +15154,13 @@ function getInstallCommand(packageManager2) {
15050
15154
  }
15051
15155
 
15052
15156
  // src/commands/clean.ts
15053
- import { Command as Command90 } from "commander";
15157
+ import { Command as Command94 } from "commander";
15054
15158
  import { confirm as confirm21, select as select6 } from "@inquirer/prompts";
15055
- import { promises as fs28 } from "fs";
15056
- import { join as join21 } from "path";
15159
+ import { promises as fs27 } from "fs";
15160
+ import { join as join20 } from "path";
15057
15161
  import { existsSync as existsSync4 } from "fs";
15058
15162
  function createCleanCommand() {
15059
- return new Command90("clean").description("Clean up backups, cache, IDE configs, and .jai1 directory").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--jai1", "Clean only .jai1/ directory").option("--ide", "Clean only IDE directories (.cursor, .windsurf, .agent, .claude, .opencode)").option("--all", "Clean all (backups + .jai1 + IDE dirs)").action(async (options) => {
15163
+ return new Command94("clean").description("Clean up backups, cache, IDE configs, and .jai1 directory").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--jai1", "Clean only .jai1/ directory").option("--ide", "Clean only IDE directories (.cursor, .windsurf, .agent, .claude, .opencode)").option("--all", "Clean all (backups + .jai1 + IDE dirs)").action(async (options) => {
15060
15164
  await handleClean(options);
15061
15165
  });
15062
15166
  }
@@ -15067,7 +15171,7 @@ async function handleClean(options) {
15067
15171
  {
15068
15172
  name: "Backups",
15069
15173
  description: "Component backup files (.jai1_backup/)",
15070
- path: join21(cwd, ".jai1_backup"),
15174
+ path: join20(cwd, ".jai1_backup"),
15071
15175
  check: async () => {
15072
15176
  const backups = await service.listBackups(cwd);
15073
15177
  return { exists: backups.length > 0, count: backups.length };
@@ -15079,13 +15183,13 @@ async function handleClean(options) {
15079
15183
  {
15080
15184
  name: "Jai1 Config",
15081
15185
  description: "Jai1 framework config (.jai1/)",
15082
- path: join21(cwd, ".jai1"),
15186
+ path: join20(cwd, ".jai1"),
15083
15187
  check: async () => {
15084
- const exists = existsSync4(join21(cwd, ".jai1"));
15188
+ const exists = existsSync4(join20(cwd, ".jai1"));
15085
15189
  return { exists };
15086
15190
  },
15087
15191
  clean: async () => {
15088
- await fs28.rm(join21(cwd, ".jai1"), { recursive: true, force: true });
15192
+ await fs27.rm(join20(cwd, ".jai1"), { recursive: true, force: true });
15089
15193
  }
15090
15194
  }
15091
15195
  ];
@@ -15097,7 +15201,7 @@ async function handleClean(options) {
15097
15201
  { name: "OpenCode", dir: ".opencode" }
15098
15202
  ];
15099
15203
  for (const ide of ideDirectories) {
15100
- const idePath = join21(cwd, ide.dir);
15204
+ const idePath = join20(cwd, ide.dir);
15101
15205
  if (existsSync4(idePath)) {
15102
15206
  targets.push({
15103
15207
  name: `IDE: ${ide.name}`,
@@ -15105,7 +15209,7 @@ async function handleClean(options) {
15105
15209
  path: idePath,
15106
15210
  check: async () => ({ exists: true }),
15107
15211
  clean: async () => {
15108
- await fs28.rm(idePath, { recursive: true, force: true });
15212
+ await fs27.rm(idePath, { recursive: true, force: true });
15109
15213
  }
15110
15214
  });
15111
15215
  }
@@ -15216,7 +15320,7 @@ async function cleanTarget(target, skipConfirm) {
15216
15320
  }
15217
15321
 
15218
15322
  // src/commands/redmine/check.ts
15219
- import { Command as Command91 } from "commander";
15323
+ import { Command as Command95 } from "commander";
15220
15324
 
15221
15325
  // src/services/redmine-config.service.ts
15222
15326
  import { readFile as readFile7 } from "fs/promises";
@@ -15523,7 +15627,7 @@ async function checkConnectivity(config) {
15523
15627
 
15524
15628
  // src/commands/redmine/check.ts
15525
15629
  function createRedmineCheckCommand() {
15526
- const cmd = new Command91("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
15630
+ const cmd = new Command95("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
15527
15631
  await handleRedmineCheck(options);
15528
15632
  });
15529
15633
  return cmd;
@@ -15551,7 +15655,7 @@ async function handleRedmineCheck(options) {
15551
15655
  }
15552
15656
 
15553
15657
  // src/commands/redmine/sync-issue.ts
15554
- import { Command as Command92 } from "commander";
15658
+ import { Command as Command96 } from "commander";
15555
15659
 
15556
15660
  // src/sync-issue.ts
15557
15661
  import { resolve as resolve3, relative } from "path";
@@ -15935,7 +16039,7 @@ function extractIssueIdFromUrl(url) {
15935
16039
 
15936
16040
  // src/commands/redmine/sync-issue.ts
15937
16041
  function createSyncIssueCommand() {
15938
- const cmd = new Command92("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) => {
16042
+ const cmd = new Command96("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) => {
15939
16043
  await handleSyncIssue(options);
15940
16044
  });
15941
16045
  return cmd;
@@ -15979,7 +16083,7 @@ async function handleSyncIssue(options) {
15979
16083
  }
15980
16084
 
15981
16085
  // src/commands/redmine/sync-project.ts
15982
- import { Command as Command93 } from "commander";
16086
+ import { Command as Command97 } from "commander";
15983
16087
 
15984
16088
  // src/sync-project.ts
15985
16089
  async function syncProject(config, options = {}) {
@@ -16049,7 +16153,7 @@ async function syncProject(config, options = {}) {
16049
16153
 
16050
16154
  // src/commands/redmine/sync-project.ts
16051
16155
  function createSyncProjectCommand() {
16052
- const cmd = new Command93("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) => {
16156
+ const cmd = new Command97("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) => {
16053
16157
  await handleSyncProject(options);
16054
16158
  });
16055
16159
  return cmd;
@@ -16104,12 +16208,12 @@ async function handleSyncProject(options) {
16104
16208
  }
16105
16209
 
16106
16210
  // src/commands/framework/info.ts
16107
- import { Command as Command94 } from "commander";
16108
- import { promises as fs29 } from "fs";
16109
- import { join as join22 } from "path";
16110
- import { homedir as homedir5 } from "os";
16211
+ import { Command as Command98 } from "commander";
16212
+ import { promises as fs28 } from "fs";
16213
+ import { join as join21 } from "path";
16214
+ import { homedir as homedir4 } from "os";
16111
16215
  function createInfoCommand() {
16112
- const cmd = new Command94("info").description("Show client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
16216
+ const cmd = new Command98("info").description("Show client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
16113
16217
  await handleInfo(options);
16114
16218
  });
16115
16219
  return cmd;
@@ -16120,7 +16224,7 @@ async function handleInfo(options) {
16120
16224
  if (!config) {
16121
16225
  throw new ValidationError(`Not initialized. Run "${getCliName()} auth" first.`);
16122
16226
  }
16123
- const frameworkPath = join22(homedir5(), ".jai1", "framework");
16227
+ const frameworkPath = join21(homedir4(), ".jai1", "framework");
16124
16228
  const projectStatus = await getProjectStatus2();
16125
16229
  const info = {
16126
16230
  configPath: configService.getConfigPath(),
@@ -16155,9 +16259,9 @@ function maskKey4(key) {
16155
16259
  return "****" + key.slice(-4);
16156
16260
  }
16157
16261
  async function getProjectStatus2() {
16158
- const projectJai1 = join22(process.cwd(), ".jai1");
16262
+ const projectJai1 = join21(process.cwd(), ".jai1");
16159
16263
  try {
16160
- await fs29.access(projectJai1);
16264
+ await fs28.access(projectJai1);
16161
16265
  return { exists: true, version: "Synced" };
16162
16266
  } catch {
16163
16267
  return { exists: false };
@@ -16165,7 +16269,7 @@ async function getProjectStatus2() {
16165
16269
  }
16166
16270
 
16167
16271
  // src/commands/self-update.ts
16168
- import { Command as Command95 } from "commander";
16272
+ import { Command as Command99 } from "commander";
16169
16273
  import { confirm as confirm22 } from "@inquirer/prompts";
16170
16274
  import { execSync as execSync6 } from "child_process";
16171
16275
  var colors3 = {
@@ -16177,7 +16281,7 @@ var colors3 = {
16177
16281
  bold: "\x1B[1m"
16178
16282
  };
16179
16283
  function createSelfUpdateCommand() {
16180
- return new Command95("self-update").description("Update CLI client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
16284
+ return new Command99("self-update").description("Update CLI client to the latest version").option("--check", "Only check for updates without installing").option("--force", "Force update without confirmation").action(async (options) => {
16181
16285
  await handleSelfUpdate(options);
16182
16286
  });
16183
16287
  }
@@ -16317,10 +16421,10 @@ function getInstallCommand2(packageManager2) {
16317
16421
  }
16318
16422
 
16319
16423
  // src/commands/clear-backups.ts
16320
- import { Command as Command96 } from "commander";
16424
+ import { Command as Command100 } from "commander";
16321
16425
  import { confirm as confirm23 } from "@inquirer/prompts";
16322
16426
  function createClearBackupsCommand() {
16323
- return new Command96("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
16427
+ return new Command100("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
16324
16428
  const service = new ComponentsService();
16325
16429
  const backups = await service.listBackups(process.cwd());
16326
16430
  if (backups.length === 0) {
@@ -16345,9 +16449,9 @@ function createClearBackupsCommand() {
16345
16449
  }
16346
16450
 
16347
16451
  // src/commands/vscode/index.ts
16348
- import { Command as Command97 } from "commander";
16452
+ import { Command as Command101 } from "commander";
16349
16453
  import { checkbox as checkbox9, confirm as confirm24, select as select7 } from "@inquirer/prompts";
16350
- import fs30 from "fs/promises";
16454
+ import fs29 from "fs/promises";
16351
16455
  import path12 from "path";
16352
16456
  import { existsSync as existsSync5 } from "fs";
16353
16457
  var PERFORMANCE_GROUPS2 = {
@@ -16485,7 +16589,7 @@ var PERFORMANCE_GROUPS2 = {
16485
16589
  }
16486
16590
  };
16487
16591
  function createVSCodeCommand() {
16488
- const vscodeCommand = new Command97("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
16592
+ const vscodeCommand = new Command101("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
16489
16593
  vscodeCommand.action(async () => {
16490
16594
  await interactiveMode2();
16491
16595
  });
@@ -16580,13 +16684,13 @@ async function applyGroups2(groupKeys, action) {
16580
16684
  return;
16581
16685
  }
16582
16686
  if (!existsSync5(vscodeDir)) {
16583
- await fs30.mkdir(vscodeDir, { recursive: true });
16687
+ await fs29.mkdir(vscodeDir, { recursive: true });
16584
16688
  console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
16585
16689
  }
16586
16690
  let currentSettings = {};
16587
16691
  if (existsSync5(settingsPath)) {
16588
16692
  try {
16589
- const content = await fs30.readFile(settingsPath, "utf-8");
16693
+ const content = await fs29.readFile(settingsPath, "utf-8");
16590
16694
  currentSettings = JSON.parse(content);
16591
16695
  console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
16592
16696
  } catch {
@@ -16626,7 +16730,7 @@ async function applyGroups2(groupKeys, action) {
16626
16730
  }
16627
16731
  }
16628
16732
  }
16629
- await fs30.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
16733
+ await fs29.writeFile(settingsPath, JSON.stringify(newSettings, null, 2));
16630
16734
  console.log(`
16631
16735
  \u2705 \u0110\xE3 c\u1EADp nh\u1EADt c\xE0i \u0111\u1EB7t VSCode t\u1EA1i: ${settingsPath}`);
16632
16736
  console.log("\u{1F4A1} M\u1EB9o: Kh\u1EDFi \u0111\u1ED9ng l\u1EA1i VSCode \u0111\u1EC3 \xE1p d\u1EE5ng c\xE1c thay \u0111\u1ED5i.");
@@ -16647,7 +16751,7 @@ async function resetSettings2(groupKeys) {
16647
16751
  return;
16648
16752
  }
16649
16753
  if (groupKeys.length === 0) {
16650
- await fs30.unlink(settingsPath);
16754
+ await fs29.unlink(settingsPath);
16651
16755
  console.log("\n\u2705 \u0110\xE3 x\xF3a file settings.json");
16652
16756
  } else {
16653
16757
  await applyGroups2(groupKeys, "disable");
@@ -16656,10 +16760,10 @@ async function resetSettings2(groupKeys) {
16656
16760
  }
16657
16761
 
16658
16762
  // src/commands/migrate-ide.ts
16659
- import { Command as Command98 } from "commander";
16763
+ import { Command as Command102 } from "commander";
16660
16764
  import { checkbox as checkbox10, confirm as confirm25 } from "@inquirer/prompts";
16661
16765
  function createMigrateIdeCommand() {
16662
- const cmd = new Command98("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) => {
16766
+ const cmd = new Command102("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) => {
16663
16767
  await runMigrateIde(options);
16664
16768
  });
16665
16769
  return cmd;
@@ -16768,20 +16872,20 @@ async function runMigrateIde(options) {
16768
16872
 
16769
16873
  // src/utils/help-formatter.ts
16770
16874
  import boxen4 from "boxen";
16771
- import chalk54 from "chalk";
16875
+ import chalk57 from "chalk";
16772
16876
  import gradient from "gradient-string";
16773
16877
  import figlet from "figlet";
16774
16878
  function showCustomHelp(version) {
16775
16879
  const title = figlet.textSync("JAI1", { font: "Small" });
16776
16880
  console.log(gradient.pastel(title));
16777
16881
  console.log(
16778
- boxen4(chalk54.cyan(`Agentic Coding CLI v${version}`), {
16882
+ boxen4(chalk57.cyan(`Agentic Coding CLI v${version}`), {
16779
16883
  padding: { left: 1, right: 1, top: 0, bottom: 0 },
16780
16884
  borderStyle: "round",
16781
16885
  borderColor: "cyan"
16782
16886
  })
16783
16887
  );
16784
- console.log(chalk54.bold("\n\u{1F527} Thi\u1EBFt l\u1EADp & Th\xF4ng tin"));
16888
+ console.log(chalk57.bold("\n\u{1F527} Thi\u1EBFt l\u1EADp & Th\xF4ng tin"));
16785
16889
  console.log(" auth X\xE1c th\u1EF1c v\xE0 c\u1EA5u h\xECnh client");
16786
16890
  console.log(" status Hi\u1EC3n th\u1ECB tr\u1EA1ng th\xE1i c\u1EA5u h\xECnh");
16787
16891
  console.log(" client-info T\u1EA1o th\xF4ng tin client \u0111\u1EC3 g\u1EEDi \u0111\u1ED9i ph\xE1t tri\u1EC3n");
@@ -16789,43 +16893,43 @@ function showCustomHelp(version) {
16789
16893
  console.log(" guide H\u01B0\u1EDBng d\u1EABn s\u1EED d\u1EE5ng nhanh");
16790
16894
  console.log(" quickstart B\u1EAFt \u0111\u1EA7u t\u1EEB \u0111\xE2u? (theo t\xECnh hu\u1ED1ng)");
16791
16895
  console.log(" doctor Chu\u1EA9n \u0111o\xE1n project hi\u1EC7n t\u1EA1i");
16792
- console.log(chalk54.bold("\n\u{1F4E6} Qu\u1EA3n l\xFD Components"));
16896
+ console.log(chalk57.bold("\n\u{1F4E6} Qu\u1EA3n l\xFD Components"));
16793
16897
  console.log(" apply C\xE0i \u0111\u1EB7t components (interactive)");
16794
16898
  console.log(" update C\u1EADp nh\u1EADt components \u0111\xE3 c\xE0i");
16795
16899
  console.log(" check Ki\u1EC3m tra c\u1EADp nh\u1EADt t\u1EEB server");
16796
- console.log(chalk54.bold("\n\u{1F5A5}\uFE0F IDE & T\xEDch h\u1EE3p"));
16900
+ console.log(chalk57.bold("\n\u{1F5A5}\uFE0F IDE & T\xEDch h\u1EE3p"));
16797
16901
  console.log(" ide L\u1EC7nh c\u1EA5u h\xECnh IDE");
16798
16902
  console.log(" chat Chat AI v\u1EDBi Jai1 LLM Proxy");
16799
16903
  console.log(" openai-keys Th\xF4ng tin API credentials");
16800
- console.log(chalk54.bold("\n\u{1F916} AI Tools"));
16904
+ console.log(chalk57.bold("\n\u{1F916} AI Tools"));
16801
16905
  console.log(" translate D\u1ECBch v\u0103n b\u1EA3n/file b\u1EB1ng AI");
16802
16906
  console.log(" image T\u1EA1o \u1EA3nh (Coming Soon)");
16803
16907
  console.log(" stats Th\u1ED1ng k\xEA s\u1EED d\u1EE5ng LLM");
16804
16908
  console.log(" feedback G\u1EEDi b\xE1o c\xE1o/\u0111\u1EC1 xu\u1EA5t");
16805
- console.log(chalk54.bold("\n\u{1F4C1} Project"));
16909
+ console.log(chalk57.bold("\n\u{1F4C1} Project"));
16806
16910
  console.log(" kit Qu\u1EA3n l\xFD starter kits");
16807
16911
  console.log(" tasks (t) Qu\u1EA3n l\xFD tasks ph\xE1t tri\u1EC3n");
16808
16912
  console.log(" rules Qu\u1EA3n l\xFD rule presets");
16809
16913
  console.log(" deps Qu\u1EA3n l\xFD dependencies");
16810
16914
  console.log(" redmine Redmine context sync");
16811
- console.log(chalk54.bold("\n\u2699\uFE0F B\u1EA3o tr\xEC"));
16915
+ console.log(chalk57.bold("\n\u2699\uFE0F B\u1EA3o tr\xEC"));
16812
16916
  console.log(" upgrade C\u1EADp nh\u1EADt CLI client");
16813
16917
  console.log(" clean D\u1ECDn d\u1EB9p cache/backup");
16814
16918
  console.log(" utils Developer utilities");
16815
16919
  const name = getCliName();
16816
- console.log(chalk54.dim(`
16920
+ console.log(chalk57.dim(`
16817
16921
  S\u1EED d\u1EE5ng: ${name} [l\u1EC7nh] --help \u0111\u1EC3 xem chi ti\u1EBFt`));
16818
16922
  }
16819
16923
  function showUnknownCommand(commandName) {
16820
- console.error(chalk54.red(`\u274C L\u1EC7nh kh\xF4ng t\u1ED3n t\u1EA1i: ${commandName}`));
16924
+ console.error(chalk57.red(`\u274C L\u1EC7nh kh\xF4ng t\u1ED3n t\u1EA1i: ${commandName}`));
16821
16925
  const name = getCliName();
16822
- console.error(chalk54.dim(`
16926
+ console.error(chalk57.dim(`
16823
16927
  G\u1EE3i \xFD: Ch\u1EA1y ${name} --help \u0111\u1EC3 xem danh s\xE1ch l\u1EC7nh`));
16824
16928
  }
16825
16929
 
16826
16930
  // src/cli.ts
16827
16931
  checkNodeVersion();
16828
- var program = new Command99();
16932
+ var program = new Command103();
16829
16933
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
16830
16934
  console.log(package_default.version);
16831
16935
  if (!process.argv.includes("--skip-update-check")) {
@@ -16861,6 +16965,7 @@ program.addCommand(createErrorsCommand());
16861
16965
  program.addCommand(createUtilsCommand());
16862
16966
  program.addCommand(createDepsCommand());
16863
16967
  program.addCommand(createDevCommand());
16968
+ program.addCommand(createSettingsCommand());
16864
16969
  program.addCommand(createTasksCommand());
16865
16970
  program.addCommand(createKitCommand());
16866
16971
  program.addCommand(createRulesCommand());
@@ -16868,9 +16973,9 @@ program.addCommand(createSkillsCommand());
16868
16973
  program.addCommand(createHooksCommand());
16869
16974
  program.addCommand(createUpgradeCommand());
16870
16975
  program.addCommand(createCleanCommand());
16871
- var redmineCommand = new Command99("redmine").description("Redmine context sync commands");
16976
+ var redmineCommand = new Command103("redmine").description("Redmine context sync commands");
16872
16977
  redmineCommand.addCommand(createRedmineCheckCommand());
16873
- var syncCommand = new Command99("sync").description("Sync Redmine issues to markdown files");
16978
+ var syncCommand = new Command103("sync").description("Sync Redmine issues to markdown files");
16874
16979
  syncCommand.addCommand(createSyncIssueCommand());
16875
16980
  syncCommand.addCommand(createSyncProjectCommand());
16876
16981
  redmineCommand.addCommand(syncCommand);