@jvittechs/j 1.0.61 → 1.0.62

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
@@ -10,14 +10,17 @@ import {
10
10
  createSettingsShowCommand
11
11
  } from "./chunk-5RDBJYO2.js";
12
12
  import {
13
- BLOCKED_ICON,
14
13
  CloudTaskProvider,
14
+ TaskService,
15
+ createTaskSummaryCommand
16
+ } from "./chunk-TEVFTK65.js";
17
+ import {
18
+ BLOCKED_ICON,
15
19
  PRIORITY_ICONS,
16
20
  PRIORITY_LABELS,
17
21
  STATUS_ICONS,
18
- TaskService,
19
- createTaskSummaryCommand
20
- } from "./chunk-F6GY6L6O.js";
22
+ TaskSchema
23
+ } from "./chunk-WOAXYUZ6.js";
21
24
  import {
22
25
  ConfigService,
23
26
  SettingsService
@@ -157,7 +160,7 @@ import { basename as basename5 } from "path";
157
160
  // package.json
158
161
  var package_default = {
159
162
  name: "@jvittechs/j",
160
- version: "1.0.61",
163
+ version: "1.0.62",
161
164
  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.",
162
165
  type: "module",
163
166
  bin: {
@@ -11391,6 +11394,30 @@ async function registerProject(config, projectId, repoUrl, silent) {
11391
11394
  return null;
11392
11395
  }
11393
11396
  }
11397
+ async function syncLocalTasksToCloud(config, projectId, tasksPath, silent) {
11398
+ try {
11399
+ const { existsSync: existsSync7, readFileSync: readFileSync4 } = await import("fs");
11400
+ if (!existsSync7(tasksPath)) return;
11401
+ const content = readFileSync4(tasksPath, "utf-8").trim();
11402
+ if (!content) return;
11403
+ const { TaskSchema: TaskSchema2 } = await import("./task.types-M4GWGDMH.js");
11404
+ const lines = content.split("\n").filter(Boolean);
11405
+ const tasks = lines.map((line) => TaskSchema2.parse(JSON.parse(line)));
11406
+ if (tasks.length === 0) return;
11407
+ if (!silent) {
11408
+ console.log(chalk31.dim(` \u2191 Syncing ${tasks.length} local tasks to cloud...`));
11409
+ }
11410
+ const provider = new CloudTaskProvider(config, projectId);
11411
+ await provider.push(tasks);
11412
+ if (!silent) {
11413
+ console.log(chalk31.green(` \u2713 ${tasks.length} tasks synced to cloud`));
11414
+ }
11415
+ } catch {
11416
+ if (!silent) {
11417
+ console.log(chalk31.dim(" \u26A0\uFE0F Could not sync local tasks. Use j t sync --push later."));
11418
+ }
11419
+ }
11420
+ }
11394
11421
  function createSettingsInitCommand() {
11395
11422
  return new Command58("init").description("Kh\u1EDFi t\u1EA1o .jai1/settings.yaml").option("-f, --force", "Ghi \u0111\xE8 file c\u0169 n\u1EBFu \u0111\xE3 t\u1ED3n t\u1EA1i").option("--cloud", "Enable cloud task sync (non-interactive)").option("--no-interactive", "Kh\xF4ng h\u1ECFi, d\xF9ng flags/defaults").option("-j, --json", "Output JSON").action(async (options) => {
11396
11423
  try {
@@ -11449,9 +11476,18 @@ function createSettingsInitCommand() {
11449
11476
  repoUrl,
11450
11477
  !!options.json
11451
11478
  );
11479
+ const finalProjectId = registeredProjectId && registeredProjectId !== projectId ? registeredProjectId : projectId;
11452
11480
  if (registeredProjectId && registeredProjectId !== projectId) {
11453
11481
  await service.set("tasks.projectId", registeredProjectId);
11454
11482
  }
11483
+ if (registeredProjectId) {
11484
+ await syncLocalTasksToCloud(
11485
+ authResult.config,
11486
+ finalProjectId,
11487
+ service.getSettingsPath().replace(/settings\.yaml$/, "tasks.jsonl"),
11488
+ !!options.json
11489
+ );
11490
+ }
11455
11491
  }
11456
11492
  }
11457
11493
  const finalSettings = service.load();
@@ -11488,6 +11524,8 @@ function createSettingsInitCommand() {
11488
11524
  // src/commands/settings/set.ts
11489
11525
  import { Command as Command59 } from "commander";
11490
11526
  import chalk32 from "chalk";
11527
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
11528
+ import { join as join9 } from "path";
11491
11529
  function createSettingsSetCommand() {
11492
11530
  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) => {
11493
11531
  try {
@@ -11513,15 +11551,29 @@ function createSettingsSetCommand() {
11513
11551
  const repoUrl = service.resolveGitRepoUrl();
11514
11552
  const projectId = service.getProjectId();
11515
11553
  if (repoUrl && projectId) {
11554
+ let finalProjectId = projectId;
11516
11555
  try {
11517
11556
  const provider = new CloudTaskProvider(config, projectId);
11518
11557
  const registeredId = await provider.ensureProjectRegistered(repoUrl);
11519
11558
  console.log(chalk32.green(" \u2713 Project registered on server"));
11520
11559
  if (registeredId && registeredId !== projectId) {
11521
11560
  await service.set("tasks.projectId", registeredId);
11522
- console.log(chalk32.dim(` Project ID: ${registeredId}`));
11523
- } else {
11524
- console.log(chalk32.dim(` Project: ${projectId}`));
11561
+ finalProjectId = registeredId;
11562
+ }
11563
+ console.log(chalk32.dim(` Project: ${finalProjectId}`));
11564
+ const tasksPath = join9(process.cwd(), ".jai1", "tasks.jsonl");
11565
+ if (existsSync4(tasksPath)) {
11566
+ const content = readFileSync3(tasksPath, "utf-8").trim();
11567
+ if (content) {
11568
+ const lines = content.split("\n").filter(Boolean);
11569
+ const tasks = lines.map((l) => TaskSchema.parse(JSON.parse(l)));
11570
+ if (tasks.length > 0) {
11571
+ console.log(chalk32.dim(` \u2191 Syncing ${tasks.length} local tasks to cloud...`));
11572
+ const p = new CloudTaskProvider(config, finalProjectId);
11573
+ await p.push(tasks);
11574
+ console.log(chalk32.green(` \u2713 ${tasks.length} tasks synced to cloud`));
11575
+ }
11576
+ }
11525
11577
  }
11526
11578
  } catch (error) {
11527
11579
  const msg = error instanceof Error ? error.message : String(error);
@@ -11673,6 +11725,9 @@ function printTaskLine(task, resolvedIds) {
11673
11725
  const blockedBy = task.depends_on.filter((id) => !resolvedIds.has(id));
11674
11726
  line += chalk35.red(` (blocked: ${blockedBy.join(", ")})`);
11675
11727
  }
11728
+ if (task.type && task.type !== "task") {
11729
+ line += chalk35.magenta(` {${task.type}}`);
11730
+ }
11676
11731
  if (task.parent) {
11677
11732
  line += chalk35.dim(` [${task.parent}]`);
11678
11733
  }
@@ -12396,7 +12451,7 @@ function createTasksCommand() {
12396
12451
  cmd.addCommand(createTaskDeleteCommand());
12397
12452
  cmd.addCommand(createTaskGuideCommand());
12398
12453
  cmd.action(async () => {
12399
- const { handleTaskSummary } = await import("./summary-KFXQDFG6.js");
12454
+ const { handleTaskSummary } = await import("./summary-7EHQYYJU.js");
12400
12455
  await handleTaskSummary({ json: false });
12401
12456
  });
12402
12457
  return cmd;
@@ -12413,7 +12468,7 @@ import Table6 from "cli-table3";
12413
12468
 
12414
12469
  // src/services/starter-kit.service.ts
12415
12470
  import { promises as fs18 } from "fs";
12416
- import { join as join9 } from "path";
12471
+ import { join as join10 } from "path";
12417
12472
  import AdmZip from "adm-zip";
12418
12473
  var StarterKitService = class {
12419
12474
  /**
@@ -12460,9 +12515,9 @@ var StarterKitService = class {
12460
12515
  throw new NetworkError(`Failed to download kit: HTTP ${response.status}`);
12461
12516
  }
12462
12517
  if (onProgress) onProgress(30);
12463
- const tmpDir = join9(process.env.TMPDIR || "/tmp", "jai1-kits");
12518
+ const tmpDir = join10(process.env.TMPDIR || "/tmp", "jai1-kits");
12464
12519
  await fs18.mkdir(tmpDir, { recursive: true });
12465
- const tmpFile = join9(tmpDir, `${slug}.zip`);
12520
+ const tmpFile = join10(tmpDir, `${slug}.zip`);
12466
12521
  const buffer = await response.arrayBuffer();
12467
12522
  await fs18.writeFile(tmpFile, Buffer.from(buffer));
12468
12523
  if (onProgress) onProgress(60);
@@ -12595,7 +12650,7 @@ Post-Init Commands:`);
12595
12650
  // src/commands/kit/create.ts
12596
12651
  import { Command as Command78 } from "commander";
12597
12652
  import { promises as fs19 } from "fs";
12598
- import { join as join10 } from "path";
12653
+ import { join as join11 } from "path";
12599
12654
  import { select as select3, input as input2, checkbox as checkbox4 } from "@inquirer/prompts";
12600
12655
  import { execa as execa2 } from "execa";
12601
12656
 
@@ -12658,7 +12713,7 @@ function createKitCreateCommand() {
12658
12713
  }
12659
12714
  }
12660
12715
  }
12661
- const targetDir = directory || join10(process.cwd(), options.name || slug);
12716
+ const targetDir = directory || join11(process.cwd(), options.name || slug);
12662
12717
  try {
12663
12718
  await fs19.access(targetDir);
12664
12719
  throw new Error(`Directory already exists: ${targetDir}`);
@@ -12723,7 +12778,7 @@ function createKitCreateCommand() {
12723
12778
  );
12724
12779
  for (const filepath of expandedPaths) {
12725
12780
  console.log(` \u{1F4E5} Installing ${filepath}...`);
12726
- await componentsService.install(config, filepath, join10(targetDir, ".jai1"));
12781
+ await componentsService.install(config, filepath, join11(targetDir, ".jai1"));
12727
12782
  }
12728
12783
  console.log(" \u2713 Framework components applied");
12729
12784
  }
@@ -12803,7 +12858,7 @@ async function getAllFiles(dir) {
12803
12858
  const files = [];
12804
12859
  const entries = await fs19.readdir(dir, { withFileTypes: true });
12805
12860
  for (const entry of entries) {
12806
- const fullPath = join10(dir, entry.name);
12861
+ const fullPath = join11(dir, entry.name);
12807
12862
  if (entry.isDirectory()) {
12808
12863
  if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
12809
12864
  files.push(...await getAllFiles(fullPath));
@@ -12919,20 +12974,20 @@ function createRulesListCommand() {
12919
12974
  // src/commands/rules/init.ts
12920
12975
  import { Command as Command81 } from "commander";
12921
12976
  import { promises as fs21 } from "fs";
12922
- import { join as join12 } from "path";
12977
+ import { join as join13 } from "path";
12923
12978
  import { select as select4, confirm as confirm15 } from "@inquirer/prompts";
12924
12979
 
12925
12980
  // src/services/project-config.service.ts
12926
12981
  import { promises as fs20 } from "fs";
12927
- import { join as join11 } from "path";
12982
+ import { join as join12 } from "path";
12928
12983
  var ProjectConfigService = class {
12929
12984
  projectRoot;
12930
12985
  configDir;
12931
12986
  configPath;
12932
12987
  constructor(projectRoot = process.cwd()) {
12933
12988
  this.projectRoot = projectRoot;
12934
- this.configDir = join11(this.projectRoot, ".jai1");
12935
- this.configPath = join11(this.configDir, "project.json");
12989
+ this.configDir = join12(this.projectRoot, ".jai1");
12990
+ this.configPath = join12(this.configDir, "project.json");
12936
12991
  }
12937
12992
  /**
12938
12993
  * Check if config file exists
@@ -13138,10 +13193,10 @@ function createRulesInitCommand() {
13138
13193
  });
13139
13194
  }
13140
13195
  async function applyCursorFormat(bundle) {
13141
- const rulesDir = join12(process.cwd(), ".cursor", "rules");
13196
+ const rulesDir = join13(process.cwd(), ".cursor", "rules");
13142
13197
  await fs21.mkdir(rulesDir, { recursive: true });
13143
13198
  for (const [filename, content] of Object.entries(bundle.files)) {
13144
- const filePath = join12(rulesDir, filename);
13199
+ const filePath = join13(rulesDir, filename);
13145
13200
  await fs21.writeFile(filePath, content, "utf-8");
13146
13201
  console.log(`\u2713 Created .cursor/rules/${filename}`);
13147
13202
  }
@@ -13176,7 +13231,7 @@ async function applyAgentsMdFormat(bundle) {
13176
13231
  // src/commands/rules/apply.ts
13177
13232
  import { Command as Command82 } from "commander";
13178
13233
  import { promises as fs23 } from "fs";
13179
- import { join as join14 } from "path";
13234
+ import { join as join15 } from "path";
13180
13235
  import { search, confirm as confirm16, checkbox as checkbox5 } from "@inquirer/prompts";
13181
13236
 
13182
13237
  // src/services/rules-generator.service.ts
@@ -13468,7 +13523,7 @@ Follow all instructions and patterns defined in AGENTS.md above.
13468
13523
 
13469
13524
  // src/services/backup.service.ts
13470
13525
  import { promises as fs22 } from "fs";
13471
- import { join as join13, dirname } from "path";
13526
+ import { join as join14, dirname } from "path";
13472
13527
  var BackupService = class {
13473
13528
  backupDir = ".jai1/backups";
13474
13529
  /**
@@ -13476,7 +13531,7 @@ var BackupService = class {
13476
13531
  */
13477
13532
  async createBackup(ides, presetSlug) {
13478
13533
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13479
- const backupPath = join13(this.backupDir, timestamp);
13534
+ const backupPath = join14(this.backupDir, timestamp);
13480
13535
  const backedUpFiles = [];
13481
13536
  let hasContent = false;
13482
13537
  for (const ideId of ides) {
@@ -13485,7 +13540,7 @@ var BackupService = class {
13485
13540
  console.warn(`Unknown IDE format: ${ideId}, skipping backup`);
13486
13541
  continue;
13487
13542
  }
13488
- const rulesPath = format.rulesPath === "." ? process.cwd() : join13(process.cwd(), format.rulesPath);
13543
+ const rulesPath = format.rulesPath === "." ? process.cwd() : join14(process.cwd(), format.rulesPath);
13489
13544
  try {
13490
13545
  const exists = await this.pathExists(rulesPath);
13491
13546
  if (!exists) {
@@ -13503,14 +13558,14 @@ var BackupService = class {
13503
13558
  const files = await fs22.readdir(rulesPath);
13504
13559
  for (const file of files) {
13505
13560
  if (file.endsWith(format.fileExtension)) {
13506
- const originalPath = join13(rulesPath, file);
13507
- const relativePath = join13(format.rulesPath, file);
13508
- const destPath = join13(backupPath, ideId, file);
13561
+ const originalPath = join14(rulesPath, file);
13562
+ const relativePath = join14(format.rulesPath, file);
13563
+ const destPath = join14(backupPath, ideId, file);
13509
13564
  await fs22.mkdir(dirname(destPath), { recursive: true });
13510
13565
  await fs22.copyFile(originalPath, destPath);
13511
13566
  backedUpFiles.push({
13512
13567
  originalPath: relativePath,
13513
- backupPath: join13(ideId, file),
13568
+ backupPath: join14(ideId, file),
13514
13569
  ide: ideId
13515
13570
  });
13516
13571
  hasContent = true;
@@ -13533,7 +13588,7 @@ var BackupService = class {
13533
13588
  };
13534
13589
  await fs22.mkdir(backupPath, { recursive: true });
13535
13590
  await fs22.writeFile(
13536
- join13(backupPath, "metadata.json"),
13591
+ join14(backupPath, "metadata.json"),
13537
13592
  JSON.stringify(metadata, null, 2),
13538
13593
  "utf-8"
13539
13594
  );
@@ -13543,18 +13598,18 @@ var BackupService = class {
13543
13598
  * Backup a single file (for AGENTS.md, GEMINI.md)
13544
13599
  */
13545
13600
  async backupSingleFile(filename, backupPath, ideId, backedUpFiles) {
13546
- const originalPath = join13(process.cwd(), filename);
13601
+ const originalPath = join14(process.cwd(), filename);
13547
13602
  try {
13548
13603
  const exists = await this.pathExists(originalPath);
13549
13604
  if (!exists) {
13550
13605
  return;
13551
13606
  }
13552
- const destPath = join13(backupPath, ideId, filename);
13607
+ const destPath = join14(backupPath, ideId, filename);
13553
13608
  await fs22.mkdir(dirname(destPath), { recursive: true });
13554
13609
  await fs22.copyFile(originalPath, destPath);
13555
13610
  backedUpFiles.push({
13556
13611
  originalPath: filename,
13557
- backupPath: join13(ideId, filename),
13612
+ backupPath: join14(ideId, filename),
13558
13613
  ide: ideId
13559
13614
  });
13560
13615
  } catch (error) {
@@ -13564,14 +13619,14 @@ var BackupService = class {
13564
13619
  * Restore files from a backup
13565
13620
  */
13566
13621
  async restoreBackup(backupPath) {
13567
- const metadataPath = join13(backupPath, "metadata.json");
13622
+ const metadataPath = join14(backupPath, "metadata.json");
13568
13623
  const metadataContent = await fs22.readFile(metadataPath, "utf-8");
13569
13624
  const metadata = JSON.parse(metadataContent);
13570
13625
  console.log(`
13571
13626
  Restoring backup from ${metadata.timestamp}...`);
13572
13627
  for (const file of metadata.files) {
13573
- const sourcePath = join13(backupPath, file.backupPath);
13574
- const destPath = join13(process.cwd(), file.originalPath);
13628
+ const sourcePath = join14(backupPath, file.backupPath);
13629
+ const destPath = join14(process.cwd(), file.originalPath);
13575
13630
  await fs22.mkdir(dirname(destPath), { recursive: true });
13576
13631
  await fs22.copyFile(sourcePath, destPath);
13577
13632
  console.log(`\u2713 Restored ${file.originalPath}`);
@@ -13583,7 +13638,7 @@ Restoring backup from ${metadata.timestamp}...`);
13583
13638
  */
13584
13639
  async listBackups() {
13585
13640
  try {
13586
- const backupDirPath = join13(process.cwd(), this.backupDir);
13641
+ const backupDirPath = join14(process.cwd(), this.backupDir);
13587
13642
  const exists = await this.pathExists(backupDirPath);
13588
13643
  if (!exists) {
13589
13644
  return [];
@@ -13592,7 +13647,7 @@ Restoring backup from ${metadata.timestamp}...`);
13592
13647
  const backups = [];
13593
13648
  for (const entry of entries) {
13594
13649
  if (entry.isDirectory()) {
13595
- const metadataPath = join13(backupDirPath, entry.name, "metadata.json");
13650
+ const metadataPath = join14(backupDirPath, entry.name, "metadata.json");
13596
13651
  try {
13597
13652
  const metadataContent = await fs22.readFile(metadataPath, "utf-8");
13598
13653
  const metadata = JSON.parse(metadataContent);
@@ -13611,7 +13666,7 @@ Restoring backup from ${metadata.timestamp}...`);
13611
13666
  * Delete a specific backup
13612
13667
  */
13613
13668
  async deleteBackup(timestamp) {
13614
- const backupPath = join13(process.cwd(), this.backupDir, timestamp);
13669
+ const backupPath = join14(process.cwd(), this.backupDir, timestamp);
13615
13670
  await this.deleteDirectory(backupPath);
13616
13671
  }
13617
13672
  /**
@@ -13660,7 +13715,7 @@ Restoring backup from ${metadata.timestamp}...`);
13660
13715
  }
13661
13716
  const entries = await fs22.readdir(path13, { withFileTypes: true });
13662
13717
  for (const entry of entries) {
13663
- const fullPath = join13(path13, entry.name);
13718
+ const fullPath = join14(path13, entry.name);
13664
13719
  if (entry.isDirectory()) {
13665
13720
  await this.deleteDirectory(fullPath);
13666
13721
  } else {
@@ -13675,13 +13730,13 @@ Restoring backup from ${metadata.timestamp}...`);
13675
13730
  * Get backup directory path
13676
13731
  */
13677
13732
  getBackupDir() {
13678
- return join13(process.cwd(), this.backupDir);
13733
+ return join14(process.cwd(), this.backupDir);
13679
13734
  }
13680
13735
  /**
13681
13736
  * Ensure backup directory exists
13682
13737
  */
13683
13738
  async ensureBackupDir() {
13684
- const backupDirPath = join13(process.cwd(), this.backupDir);
13739
+ const backupDirPath = join14(process.cwd(), this.backupDir);
13685
13740
  await fs22.mkdir(backupDirPath, { recursive: true });
13686
13741
  }
13687
13742
  };
@@ -13854,20 +13909,20 @@ function createRulesApplyCommand() {
13854
13909
  }
13855
13910
  }
13856
13911
  console.log("\n\u{1F4DD} Applying preset...\n");
13857
- const rulePresetDir = join14(process.cwd(), ".jai1", "rule-preset");
13912
+ const rulePresetDir = join15(process.cwd(), ".jai1", "rule-preset");
13858
13913
  try {
13859
13914
  await fs23.rm(rulePresetDir, { recursive: true, force: true });
13860
13915
  } catch {
13861
13916
  }
13862
13917
  await fs23.mkdir(rulePresetDir, { recursive: true });
13863
13918
  await fs23.writeFile(
13864
- join14(rulePresetDir, "preset.json"),
13919
+ join15(rulePresetDir, "preset.json"),
13865
13920
  JSON.stringify(bundle.preset, null, 2),
13866
13921
  "utf-8"
13867
13922
  );
13868
13923
  for (const [filename, content] of Object.entries(bundle.files)) {
13869
- const filePath = join14(rulePresetDir, filename);
13870
- await fs23.mkdir(join14(filePath, ".."), { recursive: true });
13924
+ const filePath = join15(rulePresetDir, filename);
13925
+ await fs23.mkdir(join15(filePath, ".."), { recursive: true });
13871
13926
  await fs23.writeFile(filePath, content, "utf-8");
13872
13927
  }
13873
13928
  console.log(`\u2713 Saved preset to .jai1/rule-preset/`);
@@ -13876,8 +13931,8 @@ function createRulesApplyCommand() {
13876
13931
  try {
13877
13932
  const files = generatorService.generateForIde(bundle, ideId);
13878
13933
  for (const file of files) {
13879
- const fullPath = join14(process.cwd(), file.path);
13880
- await fs23.mkdir(join14(fullPath, ".."), { recursive: true });
13934
+ const fullPath = join15(process.cwd(), file.path);
13935
+ await fs23.mkdir(join15(fullPath, ".."), { recursive: true });
13881
13936
  await fs23.writeFile(fullPath, file.content, "utf-8");
13882
13937
  console.log(`\u2713 [${ideId}] ${file.path}`);
13883
13938
  allGeneratedFiles.push({
@@ -13984,7 +14039,7 @@ function createRulesApplyCommand() {
13984
14039
 
13985
14040
  // src/commands/rules/restore.ts
13986
14041
  import { Command as Command83 } from "commander";
13987
- import { join as join15 } from "path";
14042
+ import { join as join16 } from "path";
13988
14043
  import { select as select5, confirm as confirm17 } from "@inquirer/prompts";
13989
14044
  function createRulesRestoreCommand() {
13990
14045
  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) => {
@@ -14031,7 +14086,7 @@ function createRulesRestoreCommand() {
14031
14086
  }
14032
14087
  console.log("\n\u{1F504} Restoring backup...\n");
14033
14088
  try {
14034
- const backupPath = join15(backupService.getBackupDir(), selectedBackup.timestamp);
14089
+ const backupPath = join16(backupService.getBackupDir(), selectedBackup.timestamp);
14035
14090
  await backupService.restoreBackup(backupPath);
14036
14091
  console.log("\n\u2705 Backup restored successfully!\n");
14037
14092
  console.log("\u{1F4A1} Tip: Your IDE may need to be restarted to pick up the changes.");
@@ -14058,12 +14113,12 @@ function formatTimestamp(timestamp) {
14058
14113
  // src/commands/rules/sync.ts
14059
14114
  import { Command as Command84 } from "commander";
14060
14115
  import { promises as fs24 } from "fs";
14061
- import { join as join16 } from "path";
14116
+ import { join as join17 } from "path";
14062
14117
  import { checkbox as checkbox6, confirm as confirm18, Separator } from "@inquirer/prompts";
14063
14118
  function createRulesSyncCommand() {
14064
14119
  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) => {
14065
- const rulePresetDir = join16(process.cwd(), ".jai1", "rule-preset");
14066
- const presetJsonPath = join16(rulePresetDir, "preset.json");
14120
+ const rulePresetDir = join17(process.cwd(), ".jai1", "rule-preset");
14121
+ const presetJsonPath = join17(rulePresetDir, "preset.json");
14067
14122
  let presetExists = false;
14068
14123
  let presetData = null;
14069
14124
  try {
@@ -14200,7 +14255,7 @@ Current IDE(s): ${currentIdes.join(", ") || "none"}`);
14200
14255
  const files = await fs24.readdir(rulePresetDir);
14201
14256
  for (const file of files) {
14202
14257
  if (file.endsWith(".mdc") || file.endsWith(".md")) {
14203
- const filePath = join16(rulePresetDir, file);
14258
+ const filePath = join17(rulePresetDir, file);
14204
14259
  const content = await fs24.readFile(filePath, "utf-8");
14205
14260
  bundle.files[file] = content;
14206
14261
  }
@@ -14215,8 +14270,8 @@ Current IDE(s): ${currentIdes.join(", ") || "none"}`);
14215
14270
  }
14216
14271
  const files2 = generatorService.generateForIde(bundle, ideId);
14217
14272
  for (const file of files2) {
14218
- const fullPath = join16(process.cwd(), file.path);
14219
- await fs24.mkdir(join16(fullPath, ".."), { recursive: true });
14273
+ const fullPath = join17(process.cwd(), file.path);
14274
+ await fs24.mkdir(join17(fullPath, ".."), { recursive: true });
14220
14275
  await fs24.writeFile(fullPath, file.content, "utf-8");
14221
14276
  }
14222
14277
  console.log(`\u2713 ${format.name} - ${files2.length} files regenerated`);
@@ -14281,7 +14336,7 @@ function buildIdeChoices(currentIdes, detected, suggestions) {
14281
14336
  // src/commands/rules/info.ts
14282
14337
  import { Command as Command85 } from "commander";
14283
14338
  import { promises as fs25 } from "fs";
14284
- import { join as join17 } from "path";
14339
+ import { join as join18 } from "path";
14285
14340
  function createRulesInfoCommand() {
14286
14341
  return new Command85("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
14287
14342
  const projectConfigService = new ProjectConfigService();
@@ -14296,8 +14351,8 @@ function createRulesInfoCommand() {
14296
14351
  return;
14297
14352
  }
14298
14353
  console.log("\u{1F4CB} Current Preset Information\n");
14299
- const rulePresetDir = join17(process.cwd(), ".jai1", "rule-preset");
14300
- const presetJsonPath = join17(rulePresetDir, "preset.json");
14354
+ const rulePresetDir = join18(process.cwd(), ".jai1", "rule-preset");
14355
+ const presetJsonPath = join18(rulePresetDir, "preset.json");
14301
14356
  let presetMetadata = null;
14302
14357
  let presetFiles = [];
14303
14358
  try {
@@ -14364,7 +14419,7 @@ Available Backups (${rulesConfig.backups.length}):`);
14364
14419
  }
14365
14420
  async function checkPathExists(path13) {
14366
14421
  try {
14367
- await fs25.access(join17(process.cwd(), path13));
14422
+ await fs25.access(join18(process.cwd(), path13));
14368
14423
  return true;
14369
14424
  } catch {
14370
14425
  return false;
@@ -14427,7 +14482,7 @@ import chalk51 from "chalk";
14427
14482
 
14428
14483
  // src/services/skills.service.ts
14429
14484
  import { promises as fs26 } from "fs";
14430
- import { join as join18 } from "path";
14485
+ import { join as join19 } from "path";
14431
14486
  import { execFile } from "child_process";
14432
14487
  import { promisify } from "util";
14433
14488
  var execFileAsync = promisify(execFile);
@@ -14463,14 +14518,14 @@ var SkillsService = class {
14463
14518
  * List locally installed skills from .jai1/skills/
14464
14519
  */
14465
14520
  async listLocal(projectRoot) {
14466
- const skillsDir = join18(projectRoot, ".jai1", "skills");
14521
+ const skillsDir = join19(projectRoot, ".jai1", "skills");
14467
14522
  const skills = [];
14468
14523
  try {
14469
14524
  const entries = await fs26.readdir(skillsDir, { withFileTypes: true });
14470
14525
  for (const entry of entries) {
14471
14526
  if (!entry.isDirectory()) continue;
14472
- const skillPath = join18(skillsDir, entry.name);
14473
- const skillMd = join18(skillPath, "SKILL.md");
14527
+ const skillPath = join19(skillsDir, entry.name);
14528
+ const skillMd = join19(skillPath, "SKILL.md");
14474
14529
  try {
14475
14530
  await fs26.access(skillMd);
14476
14531
  } catch {
@@ -14495,8 +14550,8 @@ var SkillsService = class {
14495
14550
  * Get detailed info for a single skill
14496
14551
  */
14497
14552
  async getSkillInfo(projectRoot, skillName) {
14498
- const skillPath = join18(projectRoot, ".jai1", "skills", skillName);
14499
- const skillMd = join18(skillPath, "SKILL.md");
14553
+ const skillPath = join19(projectRoot, ".jai1", "skills", skillName);
14554
+ const skillMd = join19(skillPath, "SKILL.md");
14500
14555
  try {
14501
14556
  await fs26.access(skillMd);
14502
14557
  } catch {
@@ -14571,22 +14626,22 @@ var SkillsService = class {
14571
14626
  * After npx skills add, copy newly installed skills from .agents/skills/ into .jai1/skills/
14572
14627
  */
14573
14628
  async copySkillshResultsToJai1(projectRoot, specificSkill) {
14574
- const jai1SkillsDir = join18(projectRoot, ".jai1", "skills");
14629
+ const jai1SkillsDir = join19(projectRoot, ".jai1", "skills");
14575
14630
  await fs26.mkdir(jai1SkillsDir, { recursive: true });
14576
- const universalDir = join18(projectRoot, ".agents", "skills");
14631
+ const universalDir = join19(projectRoot, ".agents", "skills");
14577
14632
  try {
14578
14633
  const entries = await fs26.readdir(universalDir, { withFileTypes: true });
14579
14634
  for (const entry of entries) {
14580
14635
  if (!entry.isDirectory()) continue;
14581
14636
  if (specificSkill && entry.name !== specificSkill) continue;
14582
- const srcSkill = join18(universalDir, entry.name);
14583
- const skillMd = join18(srcSkill, "SKILL.md");
14637
+ const srcSkill = join19(universalDir, entry.name);
14638
+ const skillMd = join19(srcSkill, "SKILL.md");
14584
14639
  try {
14585
14640
  await fs26.access(skillMd);
14586
14641
  } catch {
14587
14642
  continue;
14588
14643
  }
14589
- const targetSkill = join18(jai1SkillsDir, entry.name);
14644
+ const targetSkill = join19(jai1SkillsDir, entry.name);
14590
14645
  try {
14591
14646
  await fs26.access(targetSkill);
14592
14647
  } catch {
@@ -14625,7 +14680,7 @@ var SkillsService = class {
14625
14680
  const target = this.getIDETarget(ide);
14626
14681
  if (!target) continue;
14627
14682
  for (const skill of skillsToSync) {
14628
- const targetPath = join18(projectRoot, target.skillsPath, skill.slug);
14683
+ const targetPath = join19(projectRoot, target.skillsPath, skill.slug);
14629
14684
  try {
14630
14685
  let status = "created";
14631
14686
  try {
@@ -14689,7 +14744,7 @@ var SkillsService = class {
14689
14744
  const entries = await fs26.readdir(dirPath, { withFileTypes: true });
14690
14745
  for (const entry of entries) {
14691
14746
  if (entry.isDirectory()) {
14692
- count += await this.countFiles(join18(dirPath, entry.name));
14747
+ count += await this.countFiles(join19(dirPath, entry.name));
14693
14748
  } else {
14694
14749
  count++;
14695
14750
  }
@@ -14702,8 +14757,8 @@ var SkillsService = class {
14702
14757
  async copyDir(source, target) {
14703
14758
  const entries = await fs26.readdir(source, { withFileTypes: true });
14704
14759
  for (const entry of entries) {
14705
- const srcPath = join18(source, entry.name);
14706
- const tgtPath = join18(target, entry.name);
14760
+ const srcPath = join19(source, entry.name);
14761
+ const tgtPath = join19(target, entry.name);
14707
14762
  if (entry.isDirectory()) {
14708
14763
  await fs26.mkdir(tgtPath, { recursive: true });
14709
14764
  await this.copyDir(srcPath, tgtPath);
@@ -14777,7 +14832,7 @@ function createSkillsFindCommand() {
14777
14832
 
14778
14833
  // src/commands/skills/add.ts
14779
14834
  import { Command as Command88 } from "commander";
14780
- import { join as join19 } from "path";
14835
+ import { join as join20 } from "path";
14781
14836
  import chalk52 from "chalk";
14782
14837
  import { checkbox as checkbox7 } from "@inquirer/prompts";
14783
14838
  function createSkillsAddCommand() {
@@ -14799,7 +14854,7 @@ function createSkillsAddCommand() {
14799
14854
  }
14800
14855
  console.log(chalk52.cyan(`\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t skill: ${name}...`));
14801
14856
  console.log();
14802
- const targetDir = join19(projectRoot, ".jai1");
14857
+ const targetDir = join20(projectRoot, ".jai1");
14803
14858
  await skillsService.installFromServer(config, name, targetDir);
14804
14859
  console.log(chalk52.green(`\u2705 \u0110\xE3 c\xE0i \u0111\u1EB7t skill "${name}" v\xE0o .jai1/skills/${name}/`));
14805
14860
  }
@@ -15289,8 +15344,8 @@ function getInstallCommand(packageManager2) {
15289
15344
  import { Command as Command94 } from "commander";
15290
15345
  import { confirm as confirm22, select as select6 } from "@inquirer/prompts";
15291
15346
  import { promises as fs27 } from "fs";
15292
- import { join as join20 } from "path";
15293
- import { existsSync as existsSync4 } from "fs";
15347
+ import { join as join21 } from "path";
15348
+ import { existsSync as existsSync5 } from "fs";
15294
15349
  function createCleanCommand() {
15295
15350
  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) => {
15296
15351
  await handleClean(options);
@@ -15303,7 +15358,7 @@ async function handleClean(options) {
15303
15358
  {
15304
15359
  name: "Backups",
15305
15360
  description: "Component backup files (.jai1_backup/)",
15306
- path: join20(cwd, ".jai1_backup"),
15361
+ path: join21(cwd, ".jai1_backup"),
15307
15362
  check: async () => {
15308
15363
  const backups = await service.listBackups(cwd);
15309
15364
  return { exists: backups.length > 0, count: backups.length };
@@ -15315,13 +15370,13 @@ async function handleClean(options) {
15315
15370
  {
15316
15371
  name: "Jai1 Config",
15317
15372
  description: "Jai1 framework config (.jai1/)",
15318
- path: join20(cwd, ".jai1"),
15373
+ path: join21(cwd, ".jai1"),
15319
15374
  check: async () => {
15320
- const exists = existsSync4(join20(cwd, ".jai1"));
15375
+ const exists = existsSync5(join21(cwd, ".jai1"));
15321
15376
  return { exists };
15322
15377
  },
15323
15378
  clean: async () => {
15324
- await fs27.rm(join20(cwd, ".jai1"), { recursive: true, force: true });
15379
+ await fs27.rm(join21(cwd, ".jai1"), { recursive: true, force: true });
15325
15380
  }
15326
15381
  }
15327
15382
  ];
@@ -15333,8 +15388,8 @@ async function handleClean(options) {
15333
15388
  { name: "OpenCode", dir: ".opencode" }
15334
15389
  ];
15335
15390
  for (const ide of ideDirectories) {
15336
- const idePath = join20(cwd, ide.dir);
15337
- if (existsSync4(idePath)) {
15391
+ const idePath = join21(cwd, ide.dir);
15392
+ if (existsSync5(idePath)) {
15338
15393
  targets.push({
15339
15394
  name: `IDE: ${ide.name}`,
15340
15395
  description: `${ide.name} IDE config (${ide.dir}/)`,
@@ -16342,7 +16397,7 @@ async function handleSyncProject(options) {
16342
16397
  // src/commands/framework/info.ts
16343
16398
  import { Command as Command98 } from "commander";
16344
16399
  import { promises as fs28 } from "fs";
16345
- import { join as join21 } from "path";
16400
+ import { join as join22 } from "path";
16346
16401
  import { homedir as homedir4 } from "os";
16347
16402
  function createInfoCommand() {
16348
16403
  const cmd = new Command98("info").description("Show client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
@@ -16356,7 +16411,7 @@ async function handleInfo(options) {
16356
16411
  if (!config) {
16357
16412
  throw new ValidationError(`Not initialized. Run "${getCliName()} auth" first.`);
16358
16413
  }
16359
- const frameworkPath = join21(homedir4(), ".jai1", "framework");
16414
+ const frameworkPath = join22(homedir4(), ".jai1", "framework");
16360
16415
  const projectStatus = await getProjectStatus2();
16361
16416
  const info = {
16362
16417
  configPath: configService.getConfigPath(),
@@ -16391,7 +16446,7 @@ function maskKey4(key) {
16391
16446
  return "****" + key.slice(-4);
16392
16447
  }
16393
16448
  async function getProjectStatus2() {
16394
- const projectJai1 = join21(process.cwd(), ".jai1");
16449
+ const projectJai1 = join22(process.cwd(), ".jai1");
16395
16450
  try {
16396
16451
  await fs28.access(projectJai1);
16397
16452
  return { exists: true, version: "Synced" };
@@ -16585,7 +16640,7 @@ import { Command as Command101 } from "commander";
16585
16640
  import { checkbox as checkbox9, confirm as confirm25, select as select7 } from "@inquirer/prompts";
16586
16641
  import fs29 from "fs/promises";
16587
16642
  import path12 from "path";
16588
- import { existsSync as existsSync5 } from "fs";
16643
+ import { existsSync as existsSync6 } from "fs";
16589
16644
  var PERFORMANCE_GROUPS2 = {
16590
16645
  telemetry: {
16591
16646
  name: "Telemetry",
@@ -16815,12 +16870,12 @@ async function applyGroups2(groupKeys, action) {
16815
16870
  console.log(' \u{1F4A1} Ch\u1EA1y "jai1 vscode list" \u0111\u1EC3 xem danh s\xE1ch nh\xF3m c\xF3 s\u1EB5n.');
16816
16871
  return;
16817
16872
  }
16818
- if (!existsSync5(vscodeDir)) {
16873
+ if (!existsSync6(vscodeDir)) {
16819
16874
  await fs29.mkdir(vscodeDir, { recursive: true });
16820
16875
  console.log("\u{1F4C1} \u0110\xE3 t\u1EA1o th\u01B0 m\u1EE5c .vscode/");
16821
16876
  }
16822
16877
  let currentSettings = {};
16823
- if (existsSync5(settingsPath)) {
16878
+ if (existsSync6(settingsPath)) {
16824
16879
  try {
16825
16880
  const content = await fs29.readFile(settingsPath, "utf-8");
16826
16881
  currentSettings = JSON.parse(content);
@@ -16870,7 +16925,7 @@ async function applyGroups2(groupKeys, action) {
16870
16925
  async function resetSettings2(groupKeys) {
16871
16926
  const vscodeDir = path12.join(process.cwd(), ".vscode");
16872
16927
  const settingsPath = path12.join(vscodeDir, "settings.json");
16873
- if (!existsSync5(settingsPath)) {
16928
+ if (!existsSync6(settingsPath)) {
16874
16929
  console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
16875
16930
  return;
16876
16931
  }