@jvittechs/j 1.0.45 → 1.0.46

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.
Files changed (3) hide show
  1. package/dist/cli.js +1053 -490
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -49,7 +49,7 @@ function checkNodeVersion() {
49
49
  }
50
50
 
51
51
  // src/cli.ts
52
- import { Command as Command89 } from "commander";
52
+ import { Command as Command99 } from "commander";
53
53
 
54
54
  // src/services/error-log.service.ts
55
55
  import { promises as fs } from "fs";
@@ -149,7 +149,7 @@ import { basename as basename5 } from "path";
149
149
  // package.json
150
150
  var package_default = {
151
151
  name: "@jvittechs/j",
152
- version: "1.0.45",
152
+ version: "1.0.46",
153
153
  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
154
  type: "module",
155
155
  bin: {
@@ -10616,12 +10616,574 @@ function createDepsCommand() {
10616
10616
  return depsCommand;
10617
10617
  }
10618
10618
 
10619
- // src/commands/hooks/index.ts
10619
+ // src/commands/dev/index.ts
10620
+ import { Command as Command56 } from "commander";
10621
+ import chalk29 from "chalk";
10622
+
10623
+ // src/commands/dev/mail/index.ts
10624
+ import { Command as Command55 } from "commander";
10625
+ import chalk28 from "chalk";
10626
+
10627
+ // src/commands/dev/mail/create.ts
10620
10628
  import { Command as Command47 } from "commander";
10629
+ import chalk20 from "chalk";
10630
+
10631
+ // src/services/temp-mail.service.ts
10632
+ var TempMailApiService = class {
10633
+ baseUrl;
10634
+ accessKey;
10635
+ constructor(config) {
10636
+ this.baseUrl = config.apiUrl.replace(/\/$/, "");
10637
+ this.accessKey = config.accessKey;
10638
+ }
10639
+ async request(path13, options = {}) {
10640
+ const url = `${this.baseUrl}/api/temp-mail${path13}`;
10641
+ const res = await fetch(url, {
10642
+ ...options,
10643
+ headers: {
10644
+ "Content-Type": "application/json",
10645
+ "JAI1-Access-Key": this.accessKey,
10646
+ ...options.headers
10647
+ }
10648
+ });
10649
+ const body = await res.json();
10650
+ return body;
10651
+ }
10652
+ async createAccount(name) {
10653
+ return this.request("/accounts", {
10654
+ method: "POST",
10655
+ body: JSON.stringify({ name })
10656
+ });
10657
+ }
10658
+ async listAccounts() {
10659
+ return this.request("/accounts");
10660
+ }
10661
+ async getRandomAccount() {
10662
+ return this.request("/accounts/random");
10663
+ }
10664
+ async getInbox(address, limit = 1) {
10665
+ const enc = encodeURIComponent(address);
10666
+ return this.request(`/accounts/${enc}/inbox?limit=${limit}`);
10667
+ }
10668
+ async getMessage(address, messageId) {
10669
+ const enc = encodeURIComponent(address);
10670
+ return this.request(`/accounts/${enc}/messages/${messageId}`);
10671
+ }
10672
+ async purgeMessages(address) {
10673
+ const enc = encodeURIComponent(address);
10674
+ return this.request(`/accounts/${enc}/messages`, {
10675
+ method: "DELETE"
10676
+ });
10677
+ }
10678
+ async deleteAccount(address) {
10679
+ const enc = encodeURIComponent(address);
10680
+ return this.request(`/accounts/${enc}`, { method: "DELETE" });
10681
+ }
10682
+ };
10683
+
10684
+ // src/commands/dev/mail/create.ts
10685
+ async function handleCreate(options) {
10686
+ const config = await new ConfigService().load();
10687
+ if (!config) {
10688
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10689
+ process.exit(1);
10690
+ }
10691
+ const api = new TempMailApiService(config);
10692
+ if (!options.json) {
10693
+ console.log(chalk20.dim("\u23F3 Creating temp email account..."));
10694
+ }
10695
+ const result = await api.createAccount(options.name);
10696
+ if (!result.success) {
10697
+ if (options.json) {
10698
+ console.log(JSON.stringify({ success: false, error: result.error }));
10699
+ } else {
10700
+ console.error(`\u274C ${result.error}`);
10701
+ }
10702
+ process.exit(1);
10703
+ }
10704
+ if (options.json) {
10705
+ console.log(JSON.stringify({ success: true, data: result.data }));
10706
+ return;
10707
+ }
10708
+ console.log();
10709
+ console.log(`\u2705 Temp email created!`);
10710
+ console.log(` ${chalk20.bold.cyan(result.data.address)}`);
10711
+ console.log(chalk20.dim(` Created: ${new Date(result.data.created_at).toLocaleString()}`));
10712
+ console.log();
10713
+ console.log(chalk20.dim(" Run `j dev mail watch <address>` to listen for new emails"));
10714
+ }
10715
+ function createMailCreateCommand() {
10716
+ return new Command47("create").description("T\u1EA1o temp email account m\u1EDBi").option("--name <prefix>", "Custom prefix cho \u0111\u1ECBa ch\u1EC9 email").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
10717
+ Examples:
10718
+ $ j dev mail create
10719
+ $ j dev mail create --name test
10720
+ $ j dev mail create -j
10721
+ `).action(async (options) => {
10722
+ await handleCreate(options);
10723
+ });
10724
+ }
10725
+
10726
+ // src/commands/dev/mail/list.ts
10727
+ import { Command as Command48 } from "commander";
10728
+ import chalk21 from "chalk";
10729
+ async function handleList(options) {
10730
+ const config = await new ConfigService().load();
10731
+ if (!config) {
10732
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10733
+ process.exit(1);
10734
+ }
10735
+ const api = new TempMailApiService(config);
10736
+ const result = await api.listAccounts();
10737
+ if (!result.success) {
10738
+ if (options.json) {
10739
+ console.log(JSON.stringify({ success: false, error: result.error }));
10740
+ } else {
10741
+ console.error(`\u274C ${result.error}`);
10742
+ }
10743
+ process.exit(1);
10744
+ }
10745
+ const accounts = result.data ?? [];
10746
+ if (options.json) {
10747
+ console.log(JSON.stringify({ success: true, data: accounts }));
10748
+ return;
10749
+ }
10750
+ if (!accounts.length) {
10751
+ console.log(chalk21.dim("Ch\u01B0a c\xF3 temp email n\xE0o. T\u1EA1o m\u1EDBi b\u1EB1ng: j dev mail create"));
10752
+ return;
10753
+ }
10754
+ console.log(chalk21.bold.cyan(`\u{1F4EC} Temp Email Accounts (${accounts.length}/20)
10755
+ `));
10756
+ console.log(
10757
+ chalk21.bold(` ${"#".padEnd(4)} ${"Address".padEnd(40)} Created`)
10758
+ );
10759
+ console.log(" " + "\u2500".repeat(70));
10760
+ accounts.forEach((acc, i) => {
10761
+ const idx = chalk21.dim(String(i + 1).padEnd(4));
10762
+ const addr = chalk21.cyan(acc.address.padEnd(40));
10763
+ const date = chalk21.dim(new Date(acc.created_at).toLocaleDateString("vi-VN"));
10764
+ console.log(` ${idx} ${addr} ${date}`);
10765
+ });
10766
+ console.log();
10767
+ }
10768
+ function createMailListCommand() {
10769
+ return new Command48("list").description("Li\u1EC7t k\xEA t\u1EA5t c\u1EA3 temp email accounts").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
10770
+ Examples:
10771
+ $ j dev mail list
10772
+ $ j dev mail list -j
10773
+ `).action(async (options) => {
10774
+ await handleList(options);
10775
+ });
10776
+ }
10777
+
10778
+ // src/commands/dev/mail/random.ts
10779
+ import { Command as Command49 } from "commander";
10780
+ import chalk22 from "chalk";
10781
+ async function handleRandom(options) {
10782
+ const config = await new ConfigService().load();
10783
+ if (!config) {
10784
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10785
+ process.exit(1);
10786
+ }
10787
+ const api = new TempMailApiService(config);
10788
+ const result = await api.getRandomAccount();
10789
+ if (!result.success) {
10790
+ if (options.json) {
10791
+ console.log(JSON.stringify({ success: false, error: result.error }));
10792
+ } else {
10793
+ console.error(`\u274C ${result.error}`);
10794
+ }
10795
+ process.exit(1);
10796
+ }
10797
+ if (options.json) {
10798
+ console.log(JSON.stringify({ success: true, data: result.data }));
10799
+ return;
10800
+ }
10801
+ console.log(chalk22.cyan(result.data.address));
10802
+ }
10803
+ function createMailRandomCommand() {
10804
+ return new Command49("random").description("L\u1EA5y ng\u1EABu nhi\xEAn 1 \u0111\u1ECBa ch\u1EC9 email t\u1EEB danh s\xE1ch").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
10805
+ Examples:
10806
+ $ j dev mail random
10807
+ $ j dev mail random -j
10808
+ $ ADDRESS=$(j dev mail random) && echo "Using: $ADDRESS"
10809
+ `).action(async (options) => {
10810
+ await handleRandom(options);
10811
+ });
10812
+ }
10813
+
10814
+ // src/commands/dev/mail/inbox.ts
10815
+ import { Command as Command50 } from "commander";
10816
+ import chalk23 from "chalk";
10817
+ async function handleInbox(address, options) {
10818
+ const config = await new ConfigService().load();
10819
+ if (!config) {
10820
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10821
+ process.exit(1);
10822
+ }
10823
+ const limit = Math.max(1, Math.min(30, parseInt(options.number, 10) || 1));
10824
+ const api = new TempMailApiService(config);
10825
+ const result = await api.getInbox(address, limit);
10826
+ if (!result.success) {
10827
+ if (options.json) {
10828
+ console.log(JSON.stringify({ success: false, error: result.error }));
10829
+ } else {
10830
+ console.error(`\u274C ${result.error}`);
10831
+ }
10832
+ process.exit(1);
10833
+ }
10834
+ const messages = result.data ?? [];
10835
+ if (options.json) {
10836
+ console.log(JSON.stringify({ success: true, data: messages }));
10837
+ return;
10838
+ }
10839
+ if (!messages.length) {
10840
+ console.log(chalk23.dim(`Inbox tr\u1ED1ng: ${address}`));
10841
+ return;
10842
+ }
10843
+ console.log(chalk23.bold.cyan(`\u{1F4E5} Inbox: ${address}
10844
+ `));
10845
+ console.log(
10846
+ chalk23.bold(` ${"From".padEnd(30)} ${"Subject".padEnd(35)} Date`)
10847
+ );
10848
+ console.log(" " + "\u2500".repeat(85));
10849
+ messages.forEach((msg) => {
10850
+ const from = (msg.from.name || msg.from.address).slice(0, 28).padEnd(30);
10851
+ const subject = (msg.subject || "(no subject)").slice(0, 33).padEnd(35);
10852
+ const date = new Date(msg.createdAt).toLocaleString("vi-VN");
10853
+ const seenDot = msg.seen ? " " : chalk23.blue("\u25CF");
10854
+ console.log(` ${seenDot} ${chalk23.cyan(from)} ${subject} ${chalk23.dim(date)}`);
10855
+ console.log(chalk23.dim(` ID: ${msg.id}`));
10856
+ });
10857
+ console.log();
10858
+ console.log(chalk23.dim(` Run \`j dev mail read ${address} <id>\` to read full email`));
10859
+ }
10860
+ function createMailInboxCommand() {
10861
+ return new Command50("inbox").description("Xem inbox c\u1EE7a m\u1ED9t email address").argument("<address>", "\u0110\u1ECBa ch\u1EC9 email").option("-n, --number <count>", "S\u1ED1 l\u01B0\u1EE3ng email c\u1EA7n l\u1EA5y (m\u1EB7c \u0111\u1ECBnh: 1)", "1").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
10862
+ Examples:
10863
+ $ j dev mail inbox user@dollicons.com
10864
+ $ j dev mail inbox user@dollicons.com -n 5
10865
+ $ j dev mail inbox user@dollicons.com -j
10866
+ `).action(async (address, options) => {
10867
+ await handleInbox(address, options);
10868
+ });
10869
+ }
10870
+
10871
+ // src/commands/dev/mail/read.ts
10872
+ import { Command as Command51 } from "commander";
10873
+ import chalk24 from "chalk";
10874
+ function htmlToText(html) {
10875
+ return html.join("\n").replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/\n{3,}/g, "\n\n").trim();
10876
+ }
10877
+ async function handleRead(address, messageId, options) {
10878
+ const config = await new ConfigService().load();
10879
+ if (!config) {
10880
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10881
+ process.exit(1);
10882
+ }
10883
+ const api = new TempMailApiService(config);
10884
+ const result = await api.getMessage(address, messageId);
10885
+ if (!result.success) {
10886
+ if (options.json) {
10887
+ console.log(JSON.stringify({ success: false, error: result.error }));
10888
+ } else {
10889
+ console.error(`\u274C ${result.error}`);
10890
+ }
10891
+ process.exit(1);
10892
+ }
10893
+ const msg = result.data;
10894
+ if (options.json) {
10895
+ console.log(JSON.stringify({ success: true, data: msg }));
10896
+ return;
10897
+ }
10898
+ const body = msg.text || (msg.html?.length ? htmlToText(msg.html) : "(no content)");
10899
+ console.log(chalk24.bold.cyan("\u{1F4E7} Email Detail\n"));
10900
+ console.log(` ${chalk24.bold("From:")} ${msg.from.name} <${msg.from.address}>`);
10901
+ console.log(` ${chalk24.bold("To:")} ${msg.to.map((t) => t.address).join(", ")}`);
10902
+ if (msg.cc?.length) console.log(` ${chalk24.bold("CC:")} ${msg.cc.join(", ")}`);
10903
+ console.log(` ${chalk24.bold("Subject:")} ${msg.subject || "(no subject)"}`);
10904
+ console.log(` ${chalk24.bold("Date:")} ${new Date(msg.createdAt).toLocaleString("vi-VN")}`);
10905
+ if (msg.hasAttachments) console.log(` ${chalk24.yellow("\u{1F4CE} Has attachments")}`);
10906
+ console.log("\n" + "\u2500".repeat(80) + "\n");
10907
+ console.log(body);
10908
+ console.log("\n" + "\u2500".repeat(80));
10909
+ }
10910
+ function createMailReadCommand() {
10911
+ return new Command51("read").description("\u0110\u1ECDc n\u1ED9i dung \u0111\u1EA7y \u0111\u1EE7 c\u1EE7a m\u1ED9t email").argument("<address>", "\u0110\u1ECBa ch\u1EC9 email").argument("<message-id>", "ID c\u1EE7a email (t\u1EEB l\u1EC7nh inbox)").option("-j, --json", "Output d\u1EA1ng JSON (raw)").addHelpText("after", `
10912
+ Examples:
10913
+ $ j dev mail read user@dollicons.com abc123
10914
+ $ j dev mail read user@dollicons.com abc123 -j
10915
+ `).action(async (address, messageId, options) => {
10916
+ await handleRead(address, messageId, options);
10917
+ });
10918
+ }
10919
+
10920
+ // src/commands/dev/mail/watch.ts
10921
+ import { Command as Command52 } from "commander";
10922
+ import chalk25 from "chalk";
10923
+ function htmlToText2(html) {
10924
+ return html.join("\n").replace(/<br\s*\/?>/gi, "\n").replace(/<\/p>/gi, "\n\n").replace(/<[^>]+>/g, "").replace(/&[a-z]+;/g, " ").replace(/\n{3,}/g, "\n\n").trim();
10925
+ }
10926
+ async function handleWatch(address, options) {
10927
+ const config = await new ConfigService().load();
10928
+ if (!config) {
10929
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
10930
+ process.exit(1);
10931
+ }
10932
+ const intervalSec = Math.max(5, parseInt(options.interval, 10) || 15);
10933
+ const timeoutSec = options.timeout ? parseInt(options.timeout, 10) : void 0;
10934
+ const api = new TempMailApiService(config);
10935
+ const seenIds = /* @__PURE__ */ new Set();
10936
+ let pollCount = 0;
10937
+ const startTime = Date.now();
10938
+ if (!options.json) {
10939
+ console.log(chalk25.bold.cyan(`\u{1F440} Watching inbox: ${address}`));
10940
+ console.log(chalk25.dim(` Polling every ${intervalSec}s${timeoutSec ? ` \xB7 timeout ${timeoutSec}s` : ""} \xB7 Ctrl+C to stop
10941
+ `));
10942
+ }
10943
+ const init = await api.getInbox(address, 30);
10944
+ if (init.success && init.data) {
10945
+ init.data.forEach((m) => seenIds.add(m.id));
10946
+ }
10947
+ const poll = async () => {
10948
+ if (timeoutSec && (Date.now() - startTime) / 1e3 >= timeoutSec) {
10949
+ if (!options.json) console.log(chalk25.dim("\n\u23F1 Timeout reached. Stopped."));
10950
+ process.exit(0);
10951
+ }
10952
+ pollCount++;
10953
+ if (!options.json) {
10954
+ process.stdout.write(chalk25.dim(`\r \u{1F504} Poll #${pollCount} \u2014 ${(/* @__PURE__ */ new Date()).toLocaleTimeString("vi-VN")} `));
10955
+ }
10956
+ const result = await api.getInbox(address, 30);
10957
+ if (!result.success) {
10958
+ if (!options.json) {
10959
+ process.stdout.write(chalk25.red(`\r \u274C Error: ${result.error}
10960
+ `));
10961
+ }
10962
+ return;
10963
+ }
10964
+ const newMessages = (result.data ?? []).filter((m) => !seenIds.has(m.id));
10965
+ if (newMessages.length > 0) {
10966
+ for (const msg of newMessages) {
10967
+ seenIds.add(msg.id);
10968
+ if (options.json) {
10969
+ console.log(JSON.stringify({ event: "new_message", data: msg }));
10970
+ continue;
10971
+ }
10972
+ const detail = await api.getMessage(address, msg.id);
10973
+ process.stdout.write("\r" + " ".repeat(50) + "\r");
10974
+ console.log("\n" + chalk25.bold.green("\u{1F4E8} New Email!\n"));
10975
+ console.log(` ${chalk25.bold("From:")} ${msg.from.name || msg.from.address}`);
10976
+ console.log(` ${chalk25.bold("Subject:")} ${msg.subject || "(no subject)"}`);
10977
+ console.log(` ${chalk25.bold("Date:")} ${new Date(msg.createdAt).toLocaleString("vi-VN")}`);
10978
+ console.log(` ${chalk25.dim("ID:")} ${msg.id}`);
10979
+ if (detail.success && detail.data) {
10980
+ const body = detail.data.text || (detail.data.html?.length ? htmlToText2(detail.data.html) : "");
10981
+ if (body) {
10982
+ const preview = body.slice(0, 600) + (body.length > 600 ? "\n\u2026" : "");
10983
+ console.log("\n" + "\u2500".repeat(60) + "\n");
10984
+ console.log(preview);
10985
+ console.log("\u2500".repeat(60));
10986
+ }
10987
+ }
10988
+ console.log();
10989
+ }
10990
+ }
10991
+ };
10992
+ await poll();
10993
+ const timer = setInterval(poll, intervalSec * 1e3);
10994
+ process.on("SIGINT", () => {
10995
+ clearInterval(timer);
10996
+ if (!options.json) {
10997
+ console.log(chalk25.dim("\n\n Stopped watching. Goodbye!"));
10998
+ }
10999
+ process.exit(0);
11000
+ });
11001
+ }
11002
+ function createMailWatchCommand() {
11003
+ return new Command52("watch").description("L\u1EAFng nghe email m\u1EDBi (polling)").argument("<address>", "\u0110\u1ECBa ch\u1EC9 email c\u1EA7n theo d\xF5i").option("-i, --interval <seconds>", "Kho\u1EA3ng th\u1EDDi gian poll (gi\xE2y, m\u1EB7c \u0111\u1ECBnh: 15)", "15").option("-t, --timeout <seconds>", "D\u1EEBng sau N gi\xE2y (m\u1EB7c \u0111\u1ECBnh: ch\u1EA1y m\xE3i)").option("-j, --json", "Output s\u1EF1 ki\u1EC7n email m\u1EDBi d\u1EA1ng JSON (m\u1ED7i d\xF2ng 1 event)").addHelpText("after", `
11004
+ Examples:
11005
+ $ j dev mail watch user@dollicons.com
11006
+ $ j dev mail watch user@dollicons.com -i 30
11007
+ $ j dev mail watch user@dollicons.com -t 300
11008
+ $ j dev mail watch user@dollicons.com -j | jq .
11009
+ `).action(async (address, options) => {
11010
+ await handleWatch(address, options);
11011
+ });
11012
+ }
11013
+
11014
+ // src/commands/dev/mail/purge.ts
11015
+ import { Command as Command53 } from "commander";
11016
+ import chalk26 from "chalk";
11017
+ import { confirm as confirm9 } from "@inquirer/prompts";
11018
+ async function handlePurge(address, options) {
11019
+ const config = await new ConfigService().load();
11020
+ if (!config) {
11021
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
11022
+ process.exit(1);
11023
+ }
11024
+ if (!options.yes && !options.json) {
11025
+ const confirmed = await confirm9({
11026
+ message: `X\xF3a to\xE0n b\u1ED9 emails c\u1EE7a ${chalk26.cyan(address)}?`,
11027
+ default: false
11028
+ });
11029
+ if (!confirmed) {
11030
+ console.log(chalk26.dim("\u274C \u0110\xE3 h\u1EE7y."));
11031
+ return;
11032
+ }
11033
+ }
11034
+ const api = new TempMailApiService(config);
11035
+ if (!options.json) {
11036
+ console.log(chalk26.dim("\u23F3 \u0110ang x\xF3a t\u1EA5t c\u1EA3 emails..."));
11037
+ }
11038
+ const result = await api.purgeMessages(address);
11039
+ if (!result.success) {
11040
+ if (options.json) {
11041
+ console.log(JSON.stringify({ success: false, error: result.error }));
11042
+ } else {
11043
+ console.error(`\u274C ${result.error}`);
11044
+ }
11045
+ process.exit(1);
11046
+ }
11047
+ if (options.json) {
11048
+ console.log(JSON.stringify({ success: true, data: result.data }));
11049
+ return;
11050
+ }
11051
+ const deleted = result.data?.deleted ?? 0;
11052
+ if (deleted === 0) {
11053
+ console.log(chalk26.dim("Inbox \u0111\xE3 tr\u1ED1ng, kh\xF4ng c\xF3 g\xEC \u0111\u1EC3 x\xF3a."));
11054
+ } else {
11055
+ console.log(`\u2705 \u0110\xE3 x\xF3a ${chalk26.bold(deleted)} email.`);
11056
+ }
11057
+ }
11058
+ function createMailPurgeCommand() {
11059
+ return new Command53("purge").description("X\xF3a to\xE0n b\u1ED9 emails c\u1EE7a m\u1ED9t account").argument("<address>", "\u0110\u1ECBa ch\u1EC9 email").option("-y, --yes", "B\u1ECF qua x\xE1c nh\u1EADn").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
11060
+ Examples:
11061
+ $ j dev mail purge user@dollicons.com
11062
+ $ j dev mail purge user@dollicons.com -y
11063
+ $ j dev mail purge user@dollicons.com -j
11064
+ `).action(async (address, options) => {
11065
+ await handlePurge(address, options);
11066
+ });
11067
+ }
11068
+
11069
+ // src/commands/dev/mail/delete.ts
11070
+ import { Command as Command54 } from "commander";
11071
+ import chalk27 from "chalk";
11072
+ import { confirm as confirm10 } from "@inquirer/prompts";
11073
+ async function handleDelete(address, options) {
11074
+ const config = await new ConfigService().load();
11075
+ if (!config) {
11076
+ console.error('\u274C Not initialized. Run "jai1 auth" first.');
11077
+ process.exit(1);
11078
+ }
11079
+ if (!options.yes && !options.json) {
11080
+ const confirmed = await confirm10({
11081
+ message: `X\xF3a account ${chalk27.cyan(address)}? H\xE0nh \u0111\u1ED9ng kh\xF4ng th\u1EC3 ho\xE0n t\xE1c.`,
11082
+ default: false
11083
+ });
11084
+ if (!confirmed) {
11085
+ console.log(chalk27.dim("\u274C \u0110\xE3 h\u1EE7y."));
11086
+ return;
11087
+ }
11088
+ }
11089
+ const api = new TempMailApiService(config);
11090
+ if (!options.json) {
11091
+ console.log(chalk27.dim("\u23F3 \u0110ang x\xF3a account..."));
11092
+ }
11093
+ const result = await api.deleteAccount(address);
11094
+ if (!result.success) {
11095
+ if (options.json) {
11096
+ console.log(JSON.stringify({ success: false, error: result.error }));
11097
+ } else {
11098
+ console.error(`\u274C ${result.error}`);
11099
+ }
11100
+ process.exit(1);
11101
+ }
11102
+ if (options.json) {
11103
+ console.log(JSON.stringify({ success: true }));
11104
+ return;
11105
+ }
11106
+ console.log(`\u2705 \u0110\xE3 x\xF3a account: ${chalk27.cyan(address)}`);
11107
+ }
11108
+ function createMailDeleteCommand() {
11109
+ return new Command54("delete").description("X\xF3a m\u1ED9t temp email account").argument("<address>", "\u0110\u1ECBa ch\u1EC9 email c\u1EA7n x\xF3a").option("-y, --yes", "B\u1ECF qua x\xE1c nh\u1EADn").option("-j, --json", "Output d\u1EA1ng JSON").addHelpText("after", `
11110
+ Examples:
11111
+ $ j dev mail delete user@dollicons.com
11112
+ $ j dev mail delete user@dollicons.com -y
11113
+ $ j dev mail delete user@dollicons.com -j
11114
+ `).action(async (address, options) => {
11115
+ await handleDelete(address, options);
11116
+ });
11117
+ }
11118
+
11119
+ // src/commands/dev/mail/index.ts
11120
+ function showMailHelp() {
11121
+ console.log(chalk28.bold.cyan("\u{1F4EC} j dev mail") + chalk28.dim(" - Temp email cho m\xF4i tr\u01B0\u1EDDng dev"));
11122
+ console.log();
11123
+ console.log(chalk28.bold("Qu\u1EA3n l\xFD accounts:"));
11124
+ console.log(` ${chalk28.cyan("create")} T\u1EA1o temp email account m\u1EDBi`);
11125
+ console.log(` ${chalk28.cyan("list")} Li\u1EC7t k\xEA t\u1EA5t c\u1EA3 accounts`);
11126
+ console.log(` ${chalk28.cyan("random")} L\u1EA5y ng\u1EABu nhi\xEAn 1 \u0111\u1ECBa ch\u1EC9`);
11127
+ console.log(` ${chalk28.cyan("delete")} X\xF3a 1 account`);
11128
+ console.log();
11129
+ console.log(chalk28.bold("Email:"));
11130
+ console.log(` ${chalk28.cyan("inbox")} Xem inbox (emails g\u1EA7n nh\u1EA5t)`);
11131
+ console.log(` ${chalk28.cyan("read")} \u0110\u1ECDc n\u1ED9i dung email`);
11132
+ console.log(` ${chalk28.cyan("watch")} L\u1EAFng nghe email m\u1EDBi (polling)`);
11133
+ console.log(` ${chalk28.cyan("purge")} X\xF3a to\xE0n b\u1ED9 emails c\u1EE7a 1 account`);
11134
+ console.log();
11135
+ console.log(chalk28.bold("V\xED d\u1EE5:"));
11136
+ console.log(chalk28.dim(" $ j dev mail create"));
11137
+ console.log(chalk28.dim(" $ j dev mail create --name test"));
11138
+ console.log(chalk28.dim(" $ j dev mail list"));
11139
+ console.log(chalk28.dim(" $ j dev mail watch user@dollicons.com"));
11140
+ console.log();
11141
+ console.log(chalk28.dim(" T\u1EA5t c\u1EA3 l\u1EC7nh \u0111\u1EC1u h\u1ED7 tr\u1EE3 -j / --json"));
11142
+ console.log(chalk28.dim(' Ch\u1EA1y "j dev mail <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
11143
+ }
11144
+ function createMailCommand() {
11145
+ const cmd = new Command55("mail").description("Temp email management cho dev environment").action(() => {
11146
+ showMailHelp();
11147
+ });
11148
+ cmd.addCommand(createMailCreateCommand());
11149
+ cmd.addCommand(createMailListCommand());
11150
+ cmd.addCommand(createMailRandomCommand());
11151
+ cmd.addCommand(createMailInboxCommand());
11152
+ cmd.addCommand(createMailReadCommand());
11153
+ cmd.addCommand(createMailWatchCommand());
11154
+ cmd.addCommand(createMailPurgeCommand());
11155
+ cmd.addCommand(createMailDeleteCommand());
11156
+ return cmd;
11157
+ }
11158
+
11159
+ // src/commands/dev/index.ts
11160
+ function showDevHelp() {
11161
+ console.log(chalk29.bold.cyan("\u{1F9EA} j dev") + chalk29.dim(" - Dev tools cho m\xF4i tr\u01B0\u1EDDng local"));
11162
+ console.log();
11163
+ console.log(chalk29.bold("Tools:"));
11164
+ console.log(` ${chalk29.cyan("mail")} Qu\u1EA3n l\xFD temp email accounts (via mail.tm)`);
11165
+ console.log();
11166
+ console.log(chalk29.bold("V\xED d\u1EE5:"));
11167
+ console.log(chalk29.dim(" $ j dev mail create"));
11168
+ console.log(chalk29.dim(" $ j dev mail list"));
11169
+ console.log(chalk29.dim(" $ j dev mail watch <address>"));
11170
+ console.log();
11171
+ console.log(chalk29.dim('Ch\u1EA1y "j dev <tool> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
11172
+ }
11173
+ function createDevCommand() {
11174
+ const cmd = new Command56("dev").alias("d").description("Developer tools for local development environments").action(() => {
11175
+ showDevHelp();
11176
+ });
11177
+ cmd.addCommand(createMailCommand());
11178
+ return cmd;
11179
+ }
11180
+
11181
+ // src/commands/hooks/index.ts
11182
+ import { Command as Command57 } from "commander";
10621
11183
  import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, unlinkSync, chmodSync, mkdirSync } from "fs";
10622
11184
  import { join as join9 } from "path";
10623
11185
  import { execSync as execSync4 } from "child_process";
10624
- import chalk20 from "chalk";
11186
+ import chalk30 from "chalk";
10625
11187
  var MARKER_START = "# >>> jai1-hooks";
10626
11188
  var MARKER_END = "# <<< jai1-hooks";
10627
11189
  var SHEBANG = "#!/bin/sh";
@@ -10714,7 +11276,7 @@ function setupHooks() {
10714
11276
  if (existsSync3(hookPath)) {
10715
11277
  const existing = readFileSync2(hookPath, "utf-8");
10716
11278
  if (hasJai1Section(existing)) {
10717
- console.log(chalk20.dim(` \u23ED ${def.hookName} \u2014 \u0111\xE3 c\xF3, skip`));
11279
+ console.log(chalk30.dim(` \u23ED ${def.hookName} \u2014 \u0111\xE3 c\xF3, skip`));
10718
11280
  skipped++;
10719
11281
  continue;
10720
11282
  }
@@ -10727,23 +11289,23 @@ ${section}
10727
11289
  `);
10728
11290
  }
10729
11291
  chmodSync(hookPath, 493);
10730
- console.log(chalk20.green(` \u2705 ${def.hookName} \u2014 ${def.description}`));
11292
+ console.log(chalk30.green(` \u2705 ${def.hookName} \u2014 ${def.description}`));
10731
11293
  installed++;
10732
11294
  } catch (err) {
10733
11295
  const msg = err instanceof Error ? err.message : String(err);
10734
11296
  if (msg.includes("EACCES") || msg.includes("permission")) {
10735
- console.log(chalk20.red(` \u274C ${def.hookName} \u2014 kh\xF4ng c\xF3 quy\u1EC1n ghi. Th\u1EED ch\u1EA1y v\u1EDBi sudo.`));
11297
+ console.log(chalk30.red(` \u274C ${def.hookName} \u2014 kh\xF4ng c\xF3 quy\u1EC1n ghi. Th\u1EED ch\u1EA1y v\u1EDBi sudo.`));
10736
11298
  } else {
10737
- console.log(chalk20.red(` \u274C ${def.hookName} \u2014 l\u1ED7i: ${msg}`));
11299
+ console.log(chalk30.red(` \u274C ${def.hookName} \u2014 l\u1ED7i: ${msg}`));
10738
11300
  }
10739
11301
  }
10740
11302
  }
10741
11303
  console.log("");
10742
11304
  if (installed > 0) {
10743
- console.log(chalk20.green(`\u{1F389} \u0110\xE3 c\xE0i ${installed} hook(s).`));
10744
- console.log(chalk20.dim(" Tasks s\u1EBD t\u1EF1 \u0111\u1ED9ng sync khi b\u1EA1n push/pull."));
11305
+ console.log(chalk30.green(`\u{1F389} \u0110\xE3 c\xE0i ${installed} hook(s).`));
11306
+ console.log(chalk30.dim(" Tasks s\u1EBD t\u1EF1 \u0111\u1ED9ng sync khi b\u1EA1n push/pull."));
10745
11307
  } else {
10746
- console.log(chalk20.dim("\u2139\uFE0F T\u1EA5t c\u1EA3 hooks \u0111\xE3 \u0111\u01B0\u1EE3c c\xE0i s\u1EB5n."));
11308
+ console.log(chalk30.dim("\u2139\uFE0F T\u1EA5t c\u1EA3 hooks \u0111\xE3 \u0111\u01B0\u1EE3c c\xE0i s\u1EB5n."));
10747
11309
  }
10748
11310
  }
10749
11311
  function removeHooks() {
@@ -10762,37 +11324,37 @@ function removeHooks() {
10762
11324
  const cleaned = removeJai1Section(content);
10763
11325
  if (isEffectivelyEmpty(cleaned)) {
10764
11326
  unlinkSync(hookPath);
10765
- console.log(chalk20.yellow(` \u{1F5D1} ${def.hookName} \u2014 xo\xE1 file (ch\u1EC9 c\xF3 jai1 hooks)`));
11327
+ console.log(chalk30.yellow(` \u{1F5D1} ${def.hookName} \u2014 xo\xE1 file (ch\u1EC9 c\xF3 jai1 hooks)`));
10766
11328
  } else {
10767
11329
  writeFileSync(hookPath, cleaned);
10768
- console.log(chalk20.yellow(` \u2702\uFE0F ${def.hookName} \u2014 g\u1EE1 ph\u1EA7n jai1`));
11330
+ console.log(chalk30.yellow(` \u2702\uFE0F ${def.hookName} \u2014 g\u1EE1 ph\u1EA7n jai1`));
10769
11331
  }
10770
11332
  removed++;
10771
11333
  } catch (err) {
10772
11334
  const msg = err instanceof Error ? err.message : String(err);
10773
11335
  if (msg.includes("EACCES") || msg.includes("permission")) {
10774
- console.log(chalk20.red(` \u274C ${def.hookName} \u2014 kh\xF4ng c\xF3 quy\u1EC1n ghi/xo\xE1. Th\u1EED ch\u1EA1y v\u1EDBi sudo.`));
11336
+ console.log(chalk30.red(` \u274C ${def.hookName} \u2014 kh\xF4ng c\xF3 quy\u1EC1n ghi/xo\xE1. Th\u1EED ch\u1EA1y v\u1EDBi sudo.`));
10775
11337
  } else {
10776
- console.log(chalk20.red(` \u274C ${def.hookName} \u2014 l\u1ED7i: ${msg}`));
11338
+ console.log(chalk30.red(` \u274C ${def.hookName} \u2014 l\u1ED7i: ${msg}`));
10777
11339
  }
10778
11340
  }
10779
11341
  }
10780
11342
  console.log("");
10781
11343
  if (removed > 0) {
10782
- console.log(chalk20.green(`\u2705 \u0110\xE3 g\u1EE1 ${removed} hook(s).`));
11344
+ console.log(chalk30.green(`\u2705 \u0110\xE3 g\u1EE1 ${removed} hook(s).`));
10783
11345
  } else {
10784
- console.log(chalk20.dim("\u2139\uFE0F Kh\xF4ng c\xF3 jai1 hooks n\xE0o \u0111\u1EC3 g\u1EE1."));
11346
+ console.log(chalk30.dim("\u2139\uFE0F Kh\xF4ng c\xF3 jai1 hooks n\xE0o \u0111\u1EC3 g\u1EE1."));
10785
11347
  }
10786
11348
  }
10787
11349
  function createHooksCommand() {
10788
- const cmd = new Command47("hooks").description("Qu\u1EA3n l\xFD Git hooks t\xEDch h\u1EE3p cho jai1");
11350
+ const cmd = new Command57("hooks").description("Qu\u1EA3n l\xFD Git hooks t\xEDch h\u1EE3p cho jai1");
10789
11351
  cmd.command("setup").description("C\xE0i \u0111\u1EB7t Git hooks (auto task sync on push/pull)").action(() => {
10790
- console.log(chalk20.bold("\n\u{1F517} C\xE0i \u0111\u1EB7t jai1 Git hooks...\n"));
11352
+ console.log(chalk30.bold("\n\u{1F517} C\xE0i \u0111\u1EB7t jai1 Git hooks...\n"));
10791
11353
  setupHooks();
10792
11354
  console.log("");
10793
11355
  });
10794
11356
  cmd.command("remove").description("G\u1EE1 b\u1ECF jai1 Git hooks").action(() => {
10795
- console.log(chalk20.bold("\n\u{1F517} G\u1EE1 b\u1ECF jai1 Git hooks...\n"));
11357
+ console.log(chalk30.bold("\n\u{1F517} G\u1EE1 b\u1ECF jai1 Git hooks...\n"));
10796
11358
  removeHooks();
10797
11359
  console.log("");
10798
11360
  });
@@ -10803,17 +11365,17 @@ function createHooksCommand() {
10803
11365
  }
10804
11366
 
10805
11367
  // src/commands/tasks/index.ts
10806
- import { Command as Command61 } from "commander";
11368
+ import { Command as Command71 } from "commander";
10807
11369
 
10808
11370
  // src/commands/tasks/add.ts
10809
- import { Command as Command48 } from "commander";
10810
- import chalk21 from "chalk";
11371
+ import { Command as Command58 } from "commander";
11372
+ import chalk31 from "chalk";
10811
11373
  function createTaskAddCommand() {
10812
- return new Command48("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, plan/xxx, bug/xxx").option("-t, --tags <tags>", "Comma-separated tags").option("-j, --json", "Output JSON").action(async (title, options) => {
11374
+ 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, plan/xxx, bug/xxx").option("-t, --tags <tags>", "Comma-separated tags").option("-j, --json", "Output JSON").action(async (title, options) => {
10813
11375
  const service = new TaskService();
10814
11376
  const priority = Number(options.priority ?? 2);
10815
11377
  if (priority < 0 || priority > 3) {
10816
- console.error(chalk21.red("\u274C Priority must be 0-3"));
11378
+ console.error(chalk31.red("\u274C Priority must be 0-3"));
10817
11379
  process.exit(1);
10818
11380
  }
10819
11381
  const tags = options.tags ? options.tags.split(",").map((t) => t.trim()) : [];
@@ -10829,23 +11391,23 @@ function createTaskAddCommand() {
10829
11391
  }
10830
11392
  const icon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
10831
11393
  const label = PRIORITY_LABELS[task.priority] || "Medium";
10832
- console.log(chalk21.green(`\u2705 Task added: ${chalk21.bold(task.id)}`));
10833
- console.log(` ${chalk21.dim("Title:")} ${task.title}`);
10834
- console.log(` ${chalk21.dim("Priority:")} ${icon} ${label}`);
11394
+ console.log(chalk31.green(`\u2705 Task added: ${chalk31.bold(task.id)}`));
11395
+ console.log(` ${chalk31.dim("Title:")} ${task.title}`);
11396
+ console.log(` ${chalk31.dim("Priority:")} ${icon} ${label}`);
10835
11397
  if (task.parent) {
10836
- console.log(` ${chalk21.dim("Parent:")} ${task.parent}`);
11398
+ console.log(` ${chalk31.dim("Parent:")} ${task.parent}`);
10837
11399
  }
10838
11400
  if (task.tags.length > 0) {
10839
- console.log(` ${chalk21.dim("Tags:")} ${task.tags.join(", ")}`);
11401
+ console.log(` ${chalk31.dim("Tags:")} ${task.tags.join(", ")}`);
10840
11402
  }
10841
11403
  });
10842
11404
  }
10843
11405
 
10844
11406
  // src/commands/tasks/list.ts
10845
- import { Command as Command49 } from "commander";
10846
- import chalk22 from "chalk";
11407
+ import { Command as Command59 } from "commander";
11408
+ import chalk32 from "chalk";
10847
11409
  function createTaskListCommand() {
10848
- return new Command49("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) => {
11410
+ 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) => {
10849
11411
  await handleTaskList(options);
10850
11412
  });
10851
11413
  }
@@ -10864,12 +11426,12 @@ async function handleTaskList(options) {
10864
11426
  return;
10865
11427
  }
10866
11428
  if (tasks.length === 0) {
10867
- console.log(chalk22.dim("No tasks found."));
11429
+ console.log(chalk32.dim("No tasks found."));
10868
11430
  return;
10869
11431
  }
10870
11432
  const resolvedIds = new Set(allTasks.filter((t) => t.status === "done" || t.status === "cancelled").map((t) => t.id));
10871
11433
  const header = options.parent ? `\u{1F4CB} ${options.parent} (${tasks.length} tasks)` : `\u{1F4CB} All tasks (${tasks.length})`;
10872
- console.log(chalk22.bold(header));
11434
+ console.log(chalk32.bold(header));
10873
11435
  console.log();
10874
11436
  for (const task of tasks) {
10875
11437
  printTaskLine(task, resolvedIds);
@@ -10879,25 +11441,25 @@ function printTaskLine(task, resolvedIds) {
10879
11441
  const isBlocked = task.status === "todo" && task.depends_on.length > 0 && !task.depends_on.every((id) => resolvedIds.has(id));
10880
11442
  const statusIcon = isBlocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
10881
11443
  const priorityIcon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
10882
- let line = ` ${statusIcon} ${chalk22.dim(task.id)} P${task.priority}${priorityIcon} ${task.title}`;
11444
+ let line = ` ${statusIcon} ${chalk32.dim(task.id)} P${task.priority}${priorityIcon} ${task.title}`;
10883
11445
  if (task.status === "in_progress" && task.assigned_to) {
10884
- line += chalk22.cyan(` @${task.assigned_to}`);
11446
+ line += chalk32.cyan(` @${task.assigned_to}`);
10885
11447
  }
10886
11448
  if (isBlocked) {
10887
11449
  const blockedBy = task.depends_on.filter((id) => !resolvedIds.has(id));
10888
- line += chalk22.red(` (blocked: ${blockedBy.join(", ")})`);
11450
+ line += chalk32.red(` (blocked: ${blockedBy.join(", ")})`);
10889
11451
  }
10890
11452
  if (task.parent) {
10891
- line += chalk22.dim(` [${task.parent}]`);
11453
+ line += chalk32.dim(` [${task.parent}]`);
10892
11454
  }
10893
11455
  console.log(line);
10894
11456
  }
10895
11457
 
10896
11458
  // src/commands/tasks/ready.ts
10897
- import { Command as Command50 } from "commander";
10898
- import chalk23 from "chalk";
11459
+ import { Command as Command60 } from "commander";
11460
+ import chalk33 from "chalk";
10899
11461
  function createTaskReadyCommand() {
10900
- return new Command50("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) => {
11462
+ 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) => {
10901
11463
  const service = new TaskService();
10902
11464
  const tasks = await service.getReady(options.parent);
10903
11465
  if (options.json) {
@@ -10905,37 +11467,37 @@ function createTaskReadyCommand() {
10905
11467
  return;
10906
11468
  }
10907
11469
  if (tasks.length === 0) {
10908
- console.log(chalk23.dim("No tasks ready to pick."));
10909
- console.log(chalk23.dim("\u{1F4A1} Check blocked tasks: jai1 t list -s todo"));
11470
+ console.log(chalk33.dim("No tasks ready to pick."));
11471
+ console.log(chalk33.dim("\u{1F4A1} Check blocked tasks: jai1 t list -s todo"));
10910
11472
  return;
10911
11473
  }
10912
- console.log(chalk23.bold(`\u{1F4CB} Ready to pick (${tasks.length} tasks):`));
11474
+ console.log(chalk33.bold(`\u{1F4CB} Ready to pick (${tasks.length} tasks):`));
10913
11475
  console.log();
10914
11476
  for (const task of tasks) {
10915
11477
  const icon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
10916
- let line = ` P${task.priority}${icon} ${chalk23.dim(task.id)} ${task.title}`;
11478
+ let line = ` P${task.priority}${icon} ${chalk33.dim(task.id)} ${task.title}`;
10917
11479
  if (task.parent) {
10918
- line += chalk23.dim(` [${task.parent}]`);
11480
+ line += chalk33.dim(` [${task.parent}]`);
10919
11481
  }
10920
11482
  console.log(line);
10921
11483
  }
10922
11484
  console.log();
10923
- console.log(chalk23.dim("\u{1F4A1} Run: jai1 t pick"));
11485
+ console.log(chalk33.dim("\u{1F4A1} Run: jai1 t pick"));
10924
11486
  });
10925
11487
  }
10926
11488
 
10927
11489
  // src/commands/tasks/update.ts
10928
- import { Command as Command51 } from "commander";
10929
- import chalk24 from "chalk";
11490
+ import { Command as Command61 } from "commander";
11491
+ import chalk34 from "chalk";
10930
11492
  var VALID_STATUSES = ["todo", "in_progress", "done", "cancelled"];
10931
11493
  function createTaskUpdateCommand() {
10932
- return new Command51("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) => {
11494
+ 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) => {
10933
11495
  if (!options.status && !options.notes) {
10934
- console.error(chalk24.red("\u274C At least one of --status or --notes is required"));
11496
+ console.error(chalk34.red("\u274C At least one of --status or --notes is required"));
10935
11497
  process.exit(1);
10936
11498
  }
10937
11499
  if (options.status && !VALID_STATUSES.includes(options.status)) {
10938
- console.error(chalk24.red(`\u274C Invalid status. Must be: ${VALID_STATUSES.join(", ")}`));
11500
+ console.error(chalk34.red(`\u274C Invalid status. Must be: ${VALID_STATUSES.join(", ")}`));
10939
11501
  process.exit(1);
10940
11502
  }
10941
11503
  const service = new TaskService();
@@ -10945,8 +11507,8 @@ function createTaskUpdateCommand() {
10945
11507
  if (existingTask) {
10946
11508
  const { blocked, blockedBy } = await service.isBlocked(existingTask);
10947
11509
  if (blocked) {
10948
- console.log(chalk24.yellow(`\u26A0\uFE0F Task ${id} is blocked by: ${blockedBy.join(", ")}`));
10949
- console.log(chalk24.yellow(` Dependencies ch\u01B0a done. Ti\u1EBFp t\u1EE5c update...`));
11510
+ console.log(chalk34.yellow(`\u26A0\uFE0F Task ${id} is blocked by: ${blockedBy.join(", ")}`));
11511
+ console.log(chalk34.yellow(` Dependencies ch\u01B0a done. Ti\u1EBFp t\u1EE5c update...`));
10950
11512
  }
10951
11513
  }
10952
11514
  }
@@ -10966,24 +11528,24 @@ function createTaskUpdateCommand() {
10966
11528
  if (options.notes) {
10967
11529
  parts.push(`\u{1F4DD} notes updated`);
10968
11530
  }
10969
- console.log(chalk24.green(`\u2705 ${task.id} \u2192 ${parts.join(" | ")}`));
11531
+ console.log(chalk34.green(`\u2705 ${task.id} \u2192 ${parts.join(" | ")}`));
10970
11532
  } catch (error) {
10971
- console.error(chalk24.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11533
+ console.error(chalk34.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
10972
11534
  process.exit(1);
10973
11535
  }
10974
11536
  });
10975
11537
  }
10976
11538
 
10977
11539
  // src/commands/tasks/show.ts
10978
- import { Command as Command52 } from "commander";
10979
- import chalk25 from "chalk";
11540
+ import { Command as Command62 } from "commander";
11541
+ import chalk35 from "chalk";
10980
11542
  function createTaskShowCommand() {
10981
- return new Command52("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) => {
11543
+ 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) => {
10982
11544
  const service = new TaskService();
10983
11545
  if (query.startsWith("T-")) {
10984
11546
  const task = await service.findById(query);
10985
11547
  if (!task) {
10986
- console.error(chalk25.red(`\u274C Task ${query} not found`));
11548
+ console.error(chalk35.red(`\u274C Task ${query} not found`));
10987
11549
  process.exit(1);
10988
11550
  }
10989
11551
  if (options.json) {
@@ -10994,34 +11556,34 @@ function createTaskShowCommand() {
10994
11556
  const statusIcon = blocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
10995
11557
  const priIcon = PRIORITY_ICONS[task.priority] || "\u{1F7E1}";
10996
11558
  const priLabel = PRIORITY_LABELS[task.priority] || "Medium";
10997
- console.log(chalk25.bold(`
11559
+ console.log(chalk35.bold(`
10998
11560
  \u{1F4CC} ${task.id}: ${task.title}
10999
11561
  `));
11000
- console.log(` ${chalk25.dim("Status:")} ${statusIcon} ${task.status}${blocked ? chalk25.red(" (BLOCKED)") : ""}`);
11001
- console.log(` ${chalk25.dim("Priority:")} ${priIcon} P${task.priority} ${priLabel}`);
11562
+ console.log(` ${chalk35.dim("Status:")} ${statusIcon} ${task.status}${blocked ? chalk35.red(" (BLOCKED)") : ""}`);
11563
+ console.log(` ${chalk35.dim("Priority:")} ${priIcon} P${task.priority} ${priLabel}`);
11002
11564
  if (task.parent) {
11003
- console.log(` ${chalk25.dim("Parent:")} ${task.parent}`);
11565
+ console.log(` ${chalk35.dim("Parent:")} ${task.parent}`);
11004
11566
  }
11005
11567
  if (task.assigned_to) {
11006
- console.log(` ${chalk25.dim("Assigned:")} @${task.assigned_to} (${task.claimed_at})`);
11568
+ console.log(` ${chalk35.dim("Assigned:")} @${task.assigned_to} (${task.claimed_at})`);
11007
11569
  }
11008
11570
  if (task.depends_on.length > 0) {
11009
- console.log(` ${chalk25.dim("Depends on:")} ${task.depends_on.join(", ")}`);
11571
+ console.log(` ${chalk35.dim("Depends on:")} ${task.depends_on.join(", ")}`);
11010
11572
  if (blocked) {
11011
- console.log(` ${chalk25.dim("Blocked by:")} ${chalk25.red(blockedBy.join(", "))}`);
11573
+ console.log(` ${chalk35.dim("Blocked by:")} ${chalk35.red(blockedBy.join(", "))}`);
11012
11574
  }
11013
11575
  }
11014
11576
  if (task.tags.length > 0) {
11015
- console.log(` ${chalk25.dim("Tags:")} ${task.tags.join(", ")}`);
11577
+ console.log(` ${chalk35.dim("Tags:")} ${task.tags.join(", ")}`);
11016
11578
  }
11017
11579
  if (task.branch) {
11018
- console.log(` ${chalk25.dim("Branch:")} ${task.branch}`);
11580
+ console.log(` ${chalk35.dim("Branch:")} ${task.branch}`);
11019
11581
  }
11020
11582
  if (task.notes) {
11021
- console.log(` ${chalk25.dim("Notes:")} ${task.notes}`);
11583
+ console.log(` ${chalk35.dim("Notes:")} ${task.notes}`);
11022
11584
  }
11023
- console.log(` ${chalk25.dim("Created:")} ${task.created}`);
11024
- console.log(` ${chalk25.dim("Updated:")} ${task.updated}`);
11585
+ console.log(` ${chalk35.dim("Created:")} ${task.created}`);
11586
+ console.log(` ${chalk35.dim("Updated:")} ${task.updated}`);
11025
11587
  console.log();
11026
11588
  } else {
11027
11589
  const tasks = await service.filter({ parent: query });
@@ -11030,10 +11592,10 @@ function createTaskShowCommand() {
11030
11592
  return;
11031
11593
  }
11032
11594
  if (tasks.length === 0) {
11033
- console.log(chalk25.dim(`No tasks for parent: ${query}`));
11595
+ console.log(chalk35.dim(`No tasks for parent: ${query}`));
11034
11596
  return;
11035
11597
  }
11036
- console.log(chalk25.bold(`
11598
+ console.log(chalk35.bold(`
11037
11599
  \u{1F4CB} ${query} (${tasks.length} tasks)
11038
11600
  `));
11039
11601
  const allTasks = await service.readAll();
@@ -11041,11 +11603,11 @@ function createTaskShowCommand() {
11041
11603
  for (const task of tasks) {
11042
11604
  const isBlocked = task.status === "todo" && task.depends_on.length > 0 && !task.depends_on.every((id) => doneIds.has(id));
11043
11605
  const icon = isBlocked ? BLOCKED_ICON : STATUS_ICONS[task.status] || "\u{1F4CB}";
11044
- let line = ` ${icon} ${chalk25.dim(task.id)} P${task.priority} ${task.title}`;
11045
- if (task.assigned_to) line += chalk25.cyan(` @${task.assigned_to}`);
11606
+ let line = ` ${icon} ${chalk35.dim(task.id)} P${task.priority} ${task.title}`;
11607
+ if (task.assigned_to) line += chalk35.cyan(` @${task.assigned_to}`);
11046
11608
  if (isBlocked) {
11047
11609
  const bb = task.depends_on.filter((id) => !doneIds.has(id));
11048
- line += chalk25.red(` (blocked: ${bb.join(", ")})`);
11610
+ line += chalk35.red(` (blocked: ${bb.join(", ")})`);
11049
11611
  }
11050
11612
  console.log(line);
11051
11613
  }
@@ -11055,11 +11617,11 @@ function createTaskShowCommand() {
11055
11617
  }
11056
11618
 
11057
11619
  // src/commands/tasks/pick.ts
11058
- import { Command as Command53 } from "commander";
11059
- import chalk26 from "chalk";
11060
- import { confirm as confirm9 } from "@inquirer/prompts";
11620
+ import { Command as Command63 } from "commander";
11621
+ import chalk36 from "chalk";
11622
+ import { confirm as confirm11 } from "@inquirer/prompts";
11061
11623
  function createTaskPickCommand() {
11062
- return new Command53("pick").description("Claim the next available task").option("-j, --json", "Output JSON").action(async (options) => {
11624
+ return new Command63("pick").description("Claim the next available task").option("-j, --json", "Output JSON").action(async (options) => {
11063
11625
  const service = new TaskService();
11064
11626
  const ready = await service.getReady();
11065
11627
  if (ready.length === 0) {
@@ -11067,8 +11629,8 @@ function createTaskPickCommand() {
11067
11629
  console.log(JSON.stringify({ picked: null, message: "No tasks ready" }));
11068
11630
  return;
11069
11631
  }
11070
- console.log(chalk26.dim("No tasks ready to pick."));
11071
- console.log(chalk26.dim('\u{1F4A1} Add tasks first: jai1 t add "..."'));
11632
+ console.log(chalk36.dim("No tasks ready to pick."));
11633
+ console.log(chalk36.dim('\u{1F4A1} Add tasks first: jai1 t add "..."'));
11072
11634
  return;
11073
11635
  }
11074
11636
  const top = ready[0];
@@ -11078,34 +11640,34 @@ function createTaskPickCommand() {
11078
11640
  console.log(JSON.stringify(picked2, null, 2));
11079
11641
  return;
11080
11642
  }
11081
- console.log(chalk26.bold("\n\u{1F4CC} Next available task:"));
11082
- console.log(` ${chalk26.bold(top.id)} P${top.priority}${icon} ${top.title}`);
11643
+ console.log(chalk36.bold("\n\u{1F4CC} Next available task:"));
11644
+ console.log(` ${chalk36.bold(top.id)} P${top.priority}${icon} ${top.title}`);
11083
11645
  if (top.parent) {
11084
- console.log(` ${chalk26.dim("Parent:")} ${top.parent}`);
11646
+ console.log(` ${chalk36.dim("Parent:")} ${top.parent}`);
11085
11647
  }
11086
11648
  if (ready.length > 1) {
11087
- console.log(chalk26.dim(`
11649
+ console.log(chalk36.dim(`
11088
11650
  +${ready.length - 1} more tasks ready`));
11089
11651
  }
11090
- const proceed = await confirm9({
11652
+ const proceed = await confirm11({
11091
11653
  message: "Claim this task?",
11092
11654
  default: true
11093
11655
  });
11094
11656
  if (!proceed) {
11095
- console.log(chalk26.dim("\nCancelled."));
11657
+ console.log(chalk36.dim("\nCancelled."));
11096
11658
  return;
11097
11659
  }
11098
11660
  const picked = await service.pick(top.id);
11099
- console.log(chalk26.green(`
11661
+ console.log(chalk36.green(`
11100
11662
  \u2705 ${picked.id} assigned to @${picked.assigned_to}, status \u2192 in_progress`));
11101
11663
  });
11102
11664
  }
11103
11665
 
11104
11666
  // src/commands/tasks/done.ts
11105
- import { Command as Command54 } from "commander";
11106
- import chalk27 from "chalk";
11667
+ import { Command as Command64 } from "commander";
11668
+ import chalk37 from "chalk";
11107
11669
  function createTaskDoneCommand() {
11108
- return new Command54("done").description("Mark task as done").argument("<id>", "Task ID (e.g. T-001)").option("-j, --json", "Output JSON").action(async (id, options) => {
11670
+ 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) => {
11109
11671
  const service = new TaskService();
11110
11672
  try {
11111
11673
  const task = await service.markDone(id);
@@ -11113,19 +11675,19 @@ function createTaskDoneCommand() {
11113
11675
  console.log(JSON.stringify(task, null, 2));
11114
11676
  return;
11115
11677
  }
11116
- console.log(chalk27.green(`\u2705 ${task.id}: ${task.title} \u2192 done`));
11678
+ console.log(chalk37.green(`\u2705 ${task.id}: ${task.title} \u2192 done`));
11117
11679
  } catch (error) {
11118
- console.error(chalk27.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11680
+ console.error(chalk37.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11119
11681
  process.exit(1);
11120
11682
  }
11121
11683
  });
11122
11684
  }
11123
11685
 
11124
11686
  // src/commands/tasks/dep.ts
11125
- import { Command as Command55 } from "commander";
11126
- import chalk28 from "chalk";
11687
+ import { Command as Command65 } from "commander";
11688
+ import chalk38 from "chalk";
11127
11689
  function createTaskDepCommand() {
11128
- return new Command55("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) => {
11690
+ 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) => {
11129
11691
  const service = new TaskService();
11130
11692
  try {
11131
11693
  const task = await service.addDependency(childId, parentId);
@@ -11133,166 +11695,166 @@ function createTaskDepCommand() {
11133
11695
  console.log(JSON.stringify(task, null, 2));
11134
11696
  return;
11135
11697
  }
11136
- console.log(chalk28.green(`\u2705 ${childId} now depends on ${parentId}`));
11137
- console.log(chalk28.dim(` ${task.title} \u2192 waits for ${parentId}`));
11698
+ console.log(chalk38.green(`\u2705 ${childId} now depends on ${parentId}`));
11699
+ console.log(chalk38.dim(` ${task.title} \u2192 waits for ${parentId}`));
11138
11700
  } catch (error) {
11139
- console.error(chalk28.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11701
+ console.error(chalk38.red(`\u274C ${error instanceof Error ? error.message : String(error)}`));
11140
11702
  process.exit(1);
11141
11703
  }
11142
11704
  });
11143
11705
  }
11144
11706
 
11145
11707
  // src/commands/tasks/sync.ts
11146
- import { Command as Command56 } from "commander";
11147
- import chalk29 from "chalk";
11708
+ import { Command as Command66 } from "commander";
11709
+ import chalk39 from "chalk";
11148
11710
  function createTaskSyncCommand() {
11149
- return new Command56("sync").description("Sync tasks via git (default: pull \u2192 push)").option("--pull", "Pull only: merge tasks from origin/jai1").option("--push", "Push only: commit and push tasks to origin/jai1").action(async (options) => {
11711
+ return new Command66("sync").description("Sync tasks via git (default: pull \u2192 push)").option("--pull", "Pull only: merge tasks from origin/jai1").option("--push", "Push only: commit and push tasks to origin/jai1").action(async (options) => {
11150
11712
  const service = new TaskService();
11151
11713
  const branch = service.getSyncBranch();
11152
11714
  const doPull = options.pull || !options.pull && !options.push;
11153
11715
  const doPush = options.push || !options.pull && !options.push;
11154
11716
  if (doPull) {
11155
- console.log(chalk29.dim(`\u23F3 Pulling tasks from origin/${branch}...`));
11717
+ console.log(chalk39.dim(`\u23F3 Pulling tasks from origin/${branch}...`));
11156
11718
  try {
11157
11719
  const result = await service.syncPull();
11158
11720
  if (result.merged > 0) {
11159
- console.log(chalk29.green(` \u2193 ${result.merged} tasks merged`));
11721
+ console.log(chalk39.green(` \u2193 ${result.merged} tasks merged`));
11160
11722
  } else {
11161
- console.log(chalk29.dim(` \u2193 Already up to date`));
11723
+ console.log(chalk39.dim(` \u2193 Already up to date`));
11162
11724
  }
11163
11725
  } catch (error) {
11164
- console.error(chalk29.red(`\u274C Pull failed: ${error instanceof Error ? error.message : String(error)}`));
11726
+ console.error(chalk39.red(`\u274C Pull failed: ${error instanceof Error ? error.message : String(error)}`));
11165
11727
  process.exit(1);
11166
11728
  }
11167
11729
  }
11168
11730
  if (doPush) {
11169
- console.log(chalk29.dim(`\u23F3 Pushing tasks to origin/${branch}...`));
11731
+ console.log(chalk39.dim(`\u23F3 Pushing tasks to origin/${branch}...`));
11170
11732
  try {
11171
11733
  await service.syncPush();
11172
- console.log(chalk29.green(` \u2191 Tasks pushed to origin/${branch}`));
11734
+ console.log(chalk39.green(` \u2191 Tasks pushed to origin/${branch}`));
11173
11735
  } catch (error) {
11174
- console.error(chalk29.red(`\u274C Push failed: ${error instanceof Error ? error.message : String(error)}`));
11736
+ console.error(chalk39.red(`\u274C Push failed: ${error instanceof Error ? error.message : String(error)}`));
11175
11737
  process.exit(1);
11176
11738
  }
11177
11739
  }
11178
- console.log(chalk29.green("\u2705 Sync complete"));
11740
+ console.log(chalk39.green("\u2705 Sync complete"));
11179
11741
  });
11180
11742
  }
11181
11743
 
11182
11744
  // src/commands/tasks/guide.ts
11183
- import { Command as Command57 } from "commander";
11184
- import chalk30 from "chalk";
11745
+ import { Command as Command67 } from "commander";
11746
+ import chalk40 from "chalk";
11185
11747
  var GUIDE_TEXT = `
11186
- ${chalk30.cyan.bold("\u{1F4D6} Jai1 Task Management Guide")}
11187
-
11188
- ${chalk30.bold("\u2501\u2501\u2501 STATUSES \u2501\u2501\u2501")}
11189
- ${chalk30.dim("todo")} \u{1F4CB} Ch\u01B0a b\u1EAFt \u0111\u1EA7u
11190
- ${chalk30.dim("in_progress")} \u{1F535} \u0110ang l\xE0m (bao g\u1ED3m review)
11191
- ${chalk30.dim("done")} \u2705 Ho\xE0n th\xE0nh
11192
- ${chalk30.dim("cancelled")} \u26AB Hu\u1EF7
11193
- ${chalk30.dim("(blocked)")} \u{1F534} Computed: depends_on ch\u01B0a done
11194
-
11195
- ${chalk30.bold("\u2501\u2501\u2501 PRIORITY \u2501\u2501\u2501")}
11196
- ${chalk30.dim("0")} = \u{1F525} Critical \u2014 Prod down, security, block c\u1EA3 team
11197
- ${chalk30.dim("1")} = \u{1F534} High \u2014 Feature ch\xEDnh, deadline g\u1EA7n
11198
- ${chalk30.dim("2")} = \u{1F7E1} Medium \u2014 B\xECnh th\u01B0\u1EDDng (default)
11199
- ${chalk30.dim("3")} = \u{1F7E2} Low \u2014 Nice-to-have, docs, refactor
11200
-
11201
- ${chalk30.bold("\u2501\u2501\u2501 QUICK START \u2501\u2501\u2501")}
11202
- ${chalk30.cyan("jai1 t add")} "Fix login bug" -p 1 -P bug/login
11203
- ${chalk30.cyan("jai1 t ready")} Show tasks s\u1EB5n s\xE0ng
11204
- ${chalk30.cyan("jai1 t pick")} Claim & start working
11205
- ${chalk30.cyan("jai1 t done")} T-003 Mark complete
11206
-
11207
- ${chalk30.bold("\u2501\u2501\u2501 DAILY WORKFLOW \u2501\u2501\u2501")}
11208
- ${chalk30.cyan("jai1 t sync --pull")} Pull latest tasks
11209
- ${chalk30.cyan("jai1 t summary")} Dashboard t\u1ED5ng quan
11210
- ${chalk30.cyan("jai1 t ready")} Xem tasks s\u1EB5n s\xE0ng
11211
- ${chalk30.cyan("jai1 t pick")} Claim task m\u1EDBi
11212
- ${chalk30.cyan("jai1 t done")} T-xxx Ho\xE0n th\xE0nh task
11213
- ${chalk30.cyan("jai1 t sync --push")} Push l\xEAn git
11214
-
11215
- ${chalk30.bold("\u2501\u2501\u2501 ADDING TASKS \u2501\u2501\u2501")}
11216
- ${chalk30.yellow("\u26A0 Lu\xF4n ki\u1EC3m tra duplicate tr\u01B0\u1EDBc khi add:")}
11217
- ${chalk30.cyan("jai1 t list -P")} feature/xxx
11218
-
11219
- ${chalk30.dim("Add cho feature:")}
11220
- ${chalk30.cyan("jai1 t add")} "Setup DB schema" -p 1 -P feature/xxx
11221
- ${chalk30.cyan("jai1 t add")} "Create API" -p 1 -P feature/xxx
11222
- ${chalk30.cyan("jai1 t add")} "Build UI" -p 2 -P feature/xxx
11223
-
11224
- ${chalk30.dim("Add cho plan:")}
11225
- ${chalk30.cyan("jai1 t add")} "Refactor middleware" -p 2 -P plan/xxx
11226
-
11227
- ${chalk30.dim("Add standalone:")}
11228
- ${chalk30.cyan("jai1 t add")} "Fix README typo" -p 3
11229
-
11230
- ${chalk30.dim("Add bug fix:")}
11231
- ${chalk30.cyan("jai1 t add")} "Fix login redirect" -p 1 -P bug/xxx
11232
-
11233
- ${chalk30.bold("\u2501\u2501\u2501 DEPENDENCY \u2501\u2501\u2501")}
11234
- ${chalk30.dim("Task dependency:")}
11235
- ${chalk30.cyan("jai1 t dep")} T-002 T-001 T-002 ch\u1EDD T-001 done
11236
- ${chalk30.cyan("jai1 t dep")} T-003 T-002 T-003 ch\u1EDD T-002 done
11237
-
11238
- ${chalk30.dim("Feature-level dependency:")}
11239
- ${chalk30.dim("# N\u1EBFu feature/auth ph\u1EE5 thu\u1ED9c feature/user-model:")}
11240
- ${chalk30.cyan("jai1 t add")} "[DEP] Wait for feature/user-model" -p 1 -P feature/auth
11241
- ${chalk30.dim("# R\u1ED3i dep n\xF3 v\u1EDBi tasks cu\u1ED1i c\u1EE7a user-model")}
11242
-
11243
- ${chalk30.dim("View deps:")}
11244
- ${chalk30.cyan("jai1 t show")} T-002 Hi\u1EC7n depends_on
11245
-
11246
- ${chalk30.bold("\u2501\u2501\u2501 TEAM COLLABORATION \u2501\u2501\u2501")}
11247
- ${chalk30.yellow("\u26A0 Assignment ch\u1EC9 qua pick \u2014 kh\xF4ng set th\u1EE7 c\xF4ng.")}
11248
- ${chalk30.dim("Khi b\u1EA1n pick \u2192 team th\u1EA5y task \u0111\xE3 c\xF3 ng\u01B0\u1EDDi nh\u1EADn.")}
11249
-
11250
- ${chalk30.dim("Sync morning:")} ${chalk30.cyan("jai1 t sync --pull")}
11251
- ${chalk30.dim("Sync evening:")} ${chalk30.cyan("jai1 t sync --push")}
11252
-
11253
- ${chalk30.bold("\u2501\u2501\u2501 FOR AI AGENTS (Workflow Integration) \u2501\u2501\u2501")}
11254
- ${chalk30.dim("Khi t\u1EA1o tasks t\u1EEB feature/plan:")}
11255
- 1. ${chalk30.cyan("jai1 t list -P")} <parent> Check existing (tr\xE1nh duplicate)
11256
- 2. ${chalk30.cyan("jai1 t add")} "..." -p <0-3> -P <parent> Add t\u1EEBng task
11257
- 3. ${chalk30.cyan("jai1 t dep")} <child> <parent> Set dependencies
11258
- 4. ${chalk30.cyan("jai1 t done")} <id> Mark complete
11259
-
11260
- ${chalk30.dim("Khi implement task ti\u1EBFp theo:")}
11261
- 1. ${chalk30.cyan("jai1 t pick")} (ho\u1EB7c ${chalk30.cyan("jai1 t ready -P")} <parent>)
11748
+ ${chalk40.cyan.bold("\u{1F4D6} Jai1 Task Management Guide")}
11749
+
11750
+ ${chalk40.bold("\u2501\u2501\u2501 STATUSES \u2501\u2501\u2501")}
11751
+ ${chalk40.dim("todo")} \u{1F4CB} Ch\u01B0a b\u1EAFt \u0111\u1EA7u
11752
+ ${chalk40.dim("in_progress")} \u{1F535} \u0110ang l\xE0m (bao g\u1ED3m review)
11753
+ ${chalk40.dim("done")} \u2705 Ho\xE0n th\xE0nh
11754
+ ${chalk40.dim("cancelled")} \u26AB Hu\u1EF7
11755
+ ${chalk40.dim("(blocked)")} \u{1F534} Computed: depends_on ch\u01B0a done
11756
+
11757
+ ${chalk40.bold("\u2501\u2501\u2501 PRIORITY \u2501\u2501\u2501")}
11758
+ ${chalk40.dim("0")} = \u{1F525} Critical \u2014 Prod down, security, block c\u1EA3 team
11759
+ ${chalk40.dim("1")} = \u{1F534} High \u2014 Feature ch\xEDnh, deadline g\u1EA7n
11760
+ ${chalk40.dim("2")} = \u{1F7E1} Medium \u2014 B\xECnh th\u01B0\u1EDDng (default)
11761
+ ${chalk40.dim("3")} = \u{1F7E2} Low \u2014 Nice-to-have, docs, refactor
11762
+
11763
+ ${chalk40.bold("\u2501\u2501\u2501 QUICK START \u2501\u2501\u2501")}
11764
+ ${chalk40.cyan("jai1 t add")} "Fix login bug" -p 1 -P bug/login
11765
+ ${chalk40.cyan("jai1 t ready")} Show tasks s\u1EB5n s\xE0ng
11766
+ ${chalk40.cyan("jai1 t pick")} Claim & start working
11767
+ ${chalk40.cyan("jai1 t done")} T-003 Mark complete
11768
+
11769
+ ${chalk40.bold("\u2501\u2501\u2501 DAILY WORKFLOW \u2501\u2501\u2501")}
11770
+ ${chalk40.cyan("jai1 t sync --pull")} Pull latest tasks
11771
+ ${chalk40.cyan("jai1 t summary")} Dashboard t\u1ED5ng quan
11772
+ ${chalk40.cyan("jai1 t ready")} Xem tasks s\u1EB5n s\xE0ng
11773
+ ${chalk40.cyan("jai1 t pick")} Claim task m\u1EDBi
11774
+ ${chalk40.cyan("jai1 t done")} T-xxx Ho\xE0n th\xE0nh task
11775
+ ${chalk40.cyan("jai1 t sync --push")} Push l\xEAn git
11776
+
11777
+ ${chalk40.bold("\u2501\u2501\u2501 ADDING TASKS \u2501\u2501\u2501")}
11778
+ ${chalk40.yellow("\u26A0 Lu\xF4n ki\u1EC3m tra duplicate tr\u01B0\u1EDBc khi add:")}
11779
+ ${chalk40.cyan("jai1 t list -P")} feature/xxx
11780
+
11781
+ ${chalk40.dim("Add cho feature:")}
11782
+ ${chalk40.cyan("jai1 t add")} "Setup DB schema" -p 1 -P feature/xxx
11783
+ ${chalk40.cyan("jai1 t add")} "Create API" -p 1 -P feature/xxx
11784
+ ${chalk40.cyan("jai1 t add")} "Build UI" -p 2 -P feature/xxx
11785
+
11786
+ ${chalk40.dim("Add cho plan:")}
11787
+ ${chalk40.cyan("jai1 t add")} "Refactor middleware" -p 2 -P plan/xxx
11788
+
11789
+ ${chalk40.dim("Add standalone:")}
11790
+ ${chalk40.cyan("jai1 t add")} "Fix README typo" -p 3
11791
+
11792
+ ${chalk40.dim("Add bug fix:")}
11793
+ ${chalk40.cyan("jai1 t add")} "Fix login redirect" -p 1 -P bug/xxx
11794
+
11795
+ ${chalk40.bold("\u2501\u2501\u2501 DEPENDENCY \u2501\u2501\u2501")}
11796
+ ${chalk40.dim("Task dependency:")}
11797
+ ${chalk40.cyan("jai1 t dep")} T-002 T-001 T-002 ch\u1EDD T-001 done
11798
+ ${chalk40.cyan("jai1 t dep")} T-003 T-002 T-003 ch\u1EDD T-002 done
11799
+
11800
+ ${chalk40.dim("Feature-level dependency:")}
11801
+ ${chalk40.dim("# N\u1EBFu feature/auth ph\u1EE5 thu\u1ED9c feature/user-model:")}
11802
+ ${chalk40.cyan("jai1 t add")} "[DEP] Wait for feature/user-model" -p 1 -P feature/auth
11803
+ ${chalk40.dim("# R\u1ED3i dep n\xF3 v\u1EDBi tasks cu\u1ED1i c\u1EE7a user-model")}
11804
+
11805
+ ${chalk40.dim("View deps:")}
11806
+ ${chalk40.cyan("jai1 t show")} T-002 Hi\u1EC7n depends_on
11807
+
11808
+ ${chalk40.bold("\u2501\u2501\u2501 TEAM COLLABORATION \u2501\u2501\u2501")}
11809
+ ${chalk40.yellow("\u26A0 Assignment ch\u1EC9 qua pick \u2014 kh\xF4ng set th\u1EE7 c\xF4ng.")}
11810
+ ${chalk40.dim("Khi b\u1EA1n pick \u2192 team th\u1EA5y task \u0111\xE3 c\xF3 ng\u01B0\u1EDDi nh\u1EADn.")}
11811
+
11812
+ ${chalk40.dim("Sync morning:")} ${chalk40.cyan("jai1 t sync --pull")}
11813
+ ${chalk40.dim("Sync evening:")} ${chalk40.cyan("jai1 t sync --push")}
11814
+
11815
+ ${chalk40.bold("\u2501\u2501\u2501 FOR AI AGENTS (Workflow Integration) \u2501\u2501\u2501")}
11816
+ ${chalk40.dim("Khi t\u1EA1o tasks t\u1EEB feature/plan:")}
11817
+ 1. ${chalk40.cyan("jai1 t list -P")} <parent> Check existing (tr\xE1nh duplicate)
11818
+ 2. ${chalk40.cyan("jai1 t add")} "..." -p <0-3> -P <parent> Add t\u1EEBng task
11819
+ 3. ${chalk40.cyan("jai1 t dep")} <child> <parent> Set dependencies
11820
+ 4. ${chalk40.cyan("jai1 t done")} <id> Mark complete
11821
+
11822
+ ${chalk40.dim("Khi implement task ti\u1EBFp theo:")}
11823
+ 1. ${chalk40.cyan("jai1 t pick")} (ho\u1EB7c ${chalk40.cyan("jai1 t ready -P")} <parent>)
11262
11824
  2. Implement task
11263
- 3. ${chalk30.cyan("jai1 t done")} <id>
11825
+ 3. ${chalk40.cyan("jai1 t done")} <id>
11264
11826
 
11265
- ${chalk30.dim("Status transitions:")}
11827
+ ${chalk40.dim("Status transitions:")}
11266
11828
  add \u2192 todo (default)
11267
11829
  pick \u2192 in_progress (auto assign)
11268
11830
  done \u2192 done
11269
11831
  update -s \u2192 any valid status
11270
11832
 
11271
- ${chalk30.bold("\u2501\u2501\u2501 ALL COMMANDS \u2501\u2501\u2501")}
11272
- ${chalk30.cyan("jai1 t list")} [-s status] [-P parent] [-j]
11273
- ${chalk30.cyan("jai1 t ready")} [-P parent] [-j]
11274
- ${chalk30.cyan("jai1 t add")} <title> [-p 0-3] [-P parent] [-t tags] [-j]
11275
- ${chalk30.cyan("jai1 t update")} <id> [-s <status>] [-n <notes>] [-j]
11276
- ${chalk30.cyan("jai1 t show")} <id|parent> [-j]
11277
- ${chalk30.cyan("jai1 t pick")} [-j]
11278
- ${chalk30.cyan("jai1 t done")} <id> [-j]
11279
- ${chalk30.cyan("jai1 t dep")} <childId> <parentId> [-j]
11280
- ${chalk30.cyan("jai1 t sync")} [--pull] [--push]
11281
- ${chalk30.cyan("jai1 t summary")} [-j]
11282
- ${chalk30.cyan("jai1 t groups")} [-s status] [-j] ${chalk30.dim("(alias: parents)")}
11283
- ${chalk30.cyan("jai1 t guide")}
11284
-
11285
- ${chalk30.dim("-j / --json available on all commands (except guide, sync)")}
11833
+ ${chalk40.bold("\u2501\u2501\u2501 ALL COMMANDS \u2501\u2501\u2501")}
11834
+ ${chalk40.cyan("jai1 t list")} [-s status] [-P parent] [-j]
11835
+ ${chalk40.cyan("jai1 t ready")} [-P parent] [-j]
11836
+ ${chalk40.cyan("jai1 t add")} <title> [-p 0-3] [-P parent] [-t tags] [-j]
11837
+ ${chalk40.cyan("jai1 t update")} <id> [-s <status>] [-n <notes>] [-j]
11838
+ ${chalk40.cyan("jai1 t show")} <id|parent> [-j]
11839
+ ${chalk40.cyan("jai1 t pick")} [-j]
11840
+ ${chalk40.cyan("jai1 t done")} <id> [-j]
11841
+ ${chalk40.cyan("jai1 t dep")} <childId> <parentId> [-j]
11842
+ ${chalk40.cyan("jai1 t sync")} [--pull] [--push]
11843
+ ${chalk40.cyan("jai1 t summary")} [-j]
11844
+ ${chalk40.cyan("jai1 t groups")} [-s status] [-j] ${chalk40.dim("(alias: parents)")}
11845
+ ${chalk40.cyan("jai1 t guide")}
11846
+
11847
+ ${chalk40.dim("-j / --json available on all commands (except guide, sync)")}
11286
11848
  `;
11287
11849
  function createTaskGuideCommand() {
11288
- return new Command57("guide").description("Show full task management guide").action(() => {
11850
+ return new Command67("guide").description("Show full task management guide").action(() => {
11289
11851
  console.log(GUIDE_TEXT);
11290
11852
  });
11291
11853
  }
11292
11854
 
11293
11855
  // src/commands/tasks/parents.ts
11294
- import { Command as Command58 } from "commander";
11295
- import chalk31 from "chalk";
11856
+ import { Command as Command68 } from "commander";
11857
+ import chalk41 from "chalk";
11296
11858
  var PARENT_STATUS_ICONS = {
11297
11859
  done: "\u2705",
11298
11860
  in_progress: "\u{1F535}",
@@ -11302,17 +11864,17 @@ var PARENT_STATUS_ICONS = {
11302
11864
  function formatProgress(p) {
11303
11865
  const completed = p.done + p.cancelled;
11304
11866
  if (p.status === "done") {
11305
- return chalk31.green(`${completed}/${p.total} done`);
11867
+ return chalk41.green(`${completed}/${p.total} done`);
11306
11868
  }
11307
11869
  const parts = [];
11308
11870
  if (p.in_progress > 0) parts.push(`${p.in_progress} in_progress`);
11309
11871
  if (p.ready > 0) parts.push(`${p.ready} ready`);
11310
- if (p.blocked > 0) parts.push(chalk31.red(`${p.blocked} blocked`));
11872
+ if (p.blocked > 0) parts.push(chalk41.red(`${p.blocked} blocked`));
11311
11873
  if (p.done > 0) parts.push(`${p.done} done`);
11312
11874
  return `${completed}/${p.total} tasks` + (parts.length > 0 ? ` (${parts.join(", ")})` : "");
11313
11875
  }
11314
11876
  function createTaskParentsCommand() {
11315
- return new Command58("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) => {
11877
+ 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) => {
11316
11878
  const service = new TaskService();
11317
11879
  const parents = await service.getParents(options.status);
11318
11880
  if (options.json) {
@@ -11321,44 +11883,44 @@ function createTaskParentsCommand() {
11321
11883
  }
11322
11884
  if (parents.length === 0) {
11323
11885
  if (options.status) {
11324
- console.log(chalk31.dim(`No groups with status: ${options.status}`));
11886
+ console.log(chalk41.dim(`No groups with status: ${options.status}`));
11325
11887
  } else {
11326
- console.log(chalk31.dim("No task groups found."));
11327
- console.log(chalk31.dim('\u{1F4A1} Add tasks with parent: jai1 t add "..." -P feature/xxx'));
11888
+ console.log(chalk41.dim("No task groups found."));
11889
+ console.log(chalk41.dim('\u{1F4A1} Add tasks with parent: jai1 t add "..." -P feature/xxx'));
11328
11890
  }
11329
11891
  return;
11330
11892
  }
11331
11893
  const header = options.status ? `\u{1F4E6} Task Groups \u2014 ${options.status} (${parents.length})` : `\u{1F4E6} Task Groups (${parents.length})`;
11332
- console.log(chalk31.bold(header));
11894
+ console.log(chalk41.bold(header));
11333
11895
  console.log();
11334
11896
  for (const p of parents) {
11335
11897
  const icon = PARENT_STATUS_ICONS[p.status] || "\u{1F4CB}";
11336
11898
  const progress = formatProgress(p);
11337
- console.log(` ${icon} ${chalk31.bold(p.name)} ${chalk31.dim("\u2014")} ${progress}`);
11899
+ console.log(` ${icon} ${chalk41.bold(p.name)} ${chalk41.dim("\u2014")} ${progress}`);
11338
11900
  }
11339
11901
  console.log();
11340
11902
  });
11341
11903
  }
11342
11904
 
11343
11905
  // src/commands/tasks/cancel.ts
11344
- import { Command as Command59 } from "commander";
11345
- import chalk32 from "chalk";
11346
- import { confirm as confirm10 } from "@inquirer/prompts";
11906
+ import { Command as Command69 } from "commander";
11907
+ import chalk42 from "chalk";
11908
+ import { confirm as confirm12 } from "@inquirer/prompts";
11347
11909
  function createTaskCancelCommand() {
11348
- return new Command59("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) => {
11910
+ 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) => {
11349
11911
  const service = new TaskService();
11350
11912
  try {
11351
11913
  const task = await service.findById(id);
11352
11914
  if (!task) {
11353
- console.error(chalk32.red(`\u274C Task ${id} not found`));
11915
+ console.error(chalk42.red(`\u274C Task ${id} not found`));
11354
11916
  process.exit(1);
11355
11917
  }
11356
11918
  if (task.status === "cancelled") {
11357
- console.error(chalk32.yellow(`\u26A0\uFE0F Task ${id} is already cancelled`));
11919
+ console.error(chalk42.yellow(`\u26A0\uFE0F Task ${id} is already cancelled`));
11358
11920
  process.exit(0);
11359
11921
  }
11360
11922
  if (task.status === "done") {
11361
- console.error(chalk32.red(`\u274C Task ${id} is already done \u2014 cannot cancel`));
11923
+ console.error(chalk42.red(`\u274C Task ${id} is already done \u2014 cannot cancel`));
11362
11924
  process.exit(1);
11363
11925
  }
11364
11926
  const dependents = await service.getDependents(id);
@@ -11366,17 +11928,17 @@ function createTaskCancelCommand() {
11366
11928
  (t) => t.status !== "done" && t.status !== "cancelled"
11367
11929
  );
11368
11930
  const icon = STATUS_ICONS[task.status] || "\u{1F4CB}";
11369
- console.log(chalk32.bold(`
11931
+ console.log(chalk42.bold(`
11370
11932
  \u26AB Cancel: ${icon} ${task.id} \u2014 ${task.title}
11371
11933
  `));
11372
11934
  if (activeDependents.length > 0) {
11373
- console.log(chalk32.yellow(`\u26A0\uFE0F ${activeDependents.length} task(s) ph\u1EE5 thu\u1ED9c v\xE0o ${id}:`));
11935
+ console.log(chalk42.yellow(`\u26A0\uFE0F ${activeDependents.length} task(s) ph\u1EE5 thu\u1ED9c v\xE0o ${id}:`));
11374
11936
  for (const dep of activeDependents) {
11375
11937
  const depIcon = STATUS_ICONS[dep.status] || "\u{1F4CB}";
11376
- console.log(` ${depIcon} ${chalk32.dim(dep.id)} ${dep.title}`);
11938
+ console.log(` ${depIcon} ${chalk42.dim(dep.id)} ${dep.title}`);
11377
11939
  }
11378
11940
  console.log(
11379
- chalk32.dim(
11941
+ chalk42.dim(
11380
11942
  `
11381
11943
  \u2192 Cancel s\u1EBD resolve dependency, c\xE1c task tr\xEAn c\xF3 th\u1EC3 \u0111\u01B0\u1EE3c unblock.`
11382
11944
  )
@@ -11384,12 +11946,12 @@ function createTaskCancelCommand() {
11384
11946
  console.log();
11385
11947
  }
11386
11948
  if (!options.yes) {
11387
- const proceed = await confirm10({
11949
+ const proceed = await confirm12({
11388
11950
  message: `Cancel task ${id}?`,
11389
11951
  default: false
11390
11952
  });
11391
11953
  if (!proceed) {
11392
- console.log(chalk32.dim("\u0110\xE3 hu\u1EF7."));
11954
+ console.log(chalk42.dim("\u0110\xE3 hu\u1EF7."));
11393
11955
  return;
11394
11956
  }
11395
11957
  }
@@ -11398,10 +11960,10 @@ function createTaskCancelCommand() {
11398
11960
  console.log(JSON.stringify(updated, null, 2));
11399
11961
  return;
11400
11962
  }
11401
- console.log(chalk32.green(`\u2705 ${updated.id}: ${updated.title} \u2192 cancelled`));
11963
+ console.log(chalk42.green(`\u2705 ${updated.id}: ${updated.title} \u2192 cancelled`));
11402
11964
  } catch (error) {
11403
11965
  console.error(
11404
- chalk32.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
11966
+ chalk42.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
11405
11967
  );
11406
11968
  process.exit(1);
11407
11969
  }
@@ -11409,27 +11971,27 @@ function createTaskCancelCommand() {
11409
11971
  }
11410
11972
 
11411
11973
  // src/commands/tasks/delete.ts
11412
- import { Command as Command60 } from "commander";
11413
- import chalk33 from "chalk";
11414
- import { confirm as confirm11 } from "@inquirer/prompts";
11974
+ import { Command as Command70 } from "commander";
11975
+ import chalk43 from "chalk";
11976
+ import { confirm as confirm13 } from "@inquirer/prompts";
11415
11977
  function createTaskDeleteCommand() {
11416
- return new Command60("delete").description("Delete a task permanently (with dependency impact check)").argument("<id>", "Task ID (e.g. T-001)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON before deletion").action(async (id, options) => {
11978
+ return new Command70("delete").description("Delete a task permanently (with dependency impact check)").argument("<id>", "Task ID (e.g. T-001)").option("-y, --yes", "Skip confirmation").option("-j, --json", "Output JSON before deletion").action(async (id, options) => {
11417
11979
  const service = new TaskService();
11418
11980
  try {
11419
11981
  const task = await service.findById(id);
11420
11982
  if (!task) {
11421
- console.error(chalk33.red(`\u274C Task ${id} not found`));
11983
+ console.error(chalk43.red(`\u274C Task ${id} not found`));
11422
11984
  process.exit(1);
11423
11985
  }
11424
11986
  const dependents = await service.getDependents(id);
11425
11987
  const icon = STATUS_ICONS[task.status] || "\u{1F4CB}";
11426
- console.log(chalk33.bold(`
11988
+ console.log(chalk43.bold(`
11427
11989
  \u{1F5D1}\uFE0F Delete: ${icon} ${task.id} \u2014 ${task.title}
11428
11990
  `));
11429
- console.log(` ${chalk33.dim("Status:")} ${task.status}`);
11430
- console.log(` ${chalk33.dim("Parent:")} ${task.parent || "(none)"}`);
11991
+ console.log(` ${chalk43.dim("Status:")} ${task.status}`);
11992
+ console.log(` ${chalk43.dim("Parent:")} ${task.parent || "(none)"}`);
11431
11993
  if (task.depends_on.length > 0) {
11432
- console.log(` ${chalk33.dim("Depends:")} ${task.depends_on.join(", ")}`);
11994
+ console.log(` ${chalk43.dim("Depends:")} ${task.depends_on.join(", ")}`);
11433
11995
  }
11434
11996
  console.log();
11435
11997
  if (dependents.length > 0) {
@@ -11440,23 +12002,23 @@ function createTaskDeleteCommand() {
11440
12002
  (t) => t.status === "done" || t.status === "cancelled"
11441
12003
  );
11442
12004
  console.log(
11443
- chalk33.yellow(
12005
+ chalk43.yellow(
11444
12006
  `\u26A0\uFE0F ${dependents.length} task(s) c\xF3 depends_on \u2192 ${id}:`
11445
12007
  )
11446
12008
  );
11447
12009
  for (const dep of dependents) {
11448
12010
  const depIcon = STATUS_ICONS[dep.status] || "\u{1F4CB}";
11449
- console.log(` ${depIcon} ${chalk33.dim(dep.id)} ${dep.title}`);
12011
+ console.log(` ${depIcon} ${chalk43.dim(dep.id)} ${dep.title}`);
11450
12012
  }
11451
12013
  console.log(
11452
- chalk33.dim(
12014
+ chalk43.dim(
11453
12015
  `
11454
12016
  \u2192 Xo\xE1 s\u1EBD remove ${id} kh\u1ECFi depends_on c\u1EE7a c\xE1c task tr\xEAn.`
11455
12017
  )
11456
12018
  );
11457
12019
  if (activeDependents.length > 0) {
11458
12020
  console.log(
11459
- chalk33.dim(
12021
+ chalk43.dim(
11460
12022
  ` \u2192 ${activeDependents.length} task(s) ch\u01B0a done c\xF3 th\u1EC3 b\u1ECB \u1EA3nh h\u01B0\u1EDFng (unblock).`
11461
12023
  )
11462
12024
  );
@@ -11464,12 +12026,12 @@ function createTaskDeleteCommand() {
11464
12026
  console.log();
11465
12027
  }
11466
12028
  if (!options.yes) {
11467
- const proceed = await confirm11({
12029
+ const proceed = await confirm13({
11468
12030
  message: `Xo\xE1 v\u0129nh vi\u1EC5n task ${id}?`,
11469
12031
  default: false
11470
12032
  });
11471
12033
  if (!proceed) {
11472
- console.log(chalk33.dim("\u0110\xE3 hu\u1EF7."));
12034
+ console.log(chalk43.dim("\u0110\xE3 hu\u1EF7."));
11473
12035
  return;
11474
12036
  }
11475
12037
  }
@@ -11478,10 +12040,10 @@ function createTaskDeleteCommand() {
11478
12040
  }
11479
12041
  await service.deleteTask(id);
11480
12042
  if (!options.json) {
11481
- console.log(chalk33.green(`\u2705 \u0110\xE3 xo\xE1 ${task.id}: ${task.title}`));
12043
+ console.log(chalk43.green(`\u2705 \u0110\xE3 xo\xE1 ${task.id}: ${task.title}`));
11482
12044
  if (dependents.length > 0) {
11483
12045
  console.log(
11484
- chalk33.dim(
12046
+ chalk43.dim(
11485
12047
  ` \u0110\xE3 c\u1EADp nh\u1EADt depends_on cho: ${dependents.map((d) => d.id).join(", ")}`
11486
12048
  )
11487
12049
  );
@@ -11489,7 +12051,7 @@ function createTaskDeleteCommand() {
11489
12051
  }
11490
12052
  } catch (error) {
11491
12053
  console.error(
11492
- chalk33.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
12054
+ chalk43.red(`\u274C ${error instanceof Error ? error.message : String(error)}`)
11493
12055
  );
11494
12056
  process.exit(1);
11495
12057
  }
@@ -11498,7 +12060,7 @@ function createTaskDeleteCommand() {
11498
12060
 
11499
12061
  // src/commands/tasks/index.ts
11500
12062
  function createTasksCommand() {
11501
- const cmd = new Command61("tasks").alias("t").description("Task management \u2014 track, assign, and manage development tasks").hook("preAction", (thisCommand, actionCommand) => {
12063
+ const cmd = new Command71("tasks").alias("t").description("Task management \u2014 track, assign, and manage development tasks").hook("preAction", (thisCommand, actionCommand) => {
11502
12064
  if (actionCommand.name() !== "guide") {
11503
12065
  TaskService.ensureJai1Dir();
11504
12066
  }
@@ -11525,12 +12087,12 @@ function createTasksCommand() {
11525
12087
  }
11526
12088
 
11527
12089
  // src/commands/kit/index.ts
11528
- import { Command as Command65 } from "commander";
11529
- import chalk35 from "chalk";
12090
+ import { Command as Command75 } from "commander";
12091
+ import chalk45 from "chalk";
11530
12092
 
11531
12093
  // src/commands/kit/list.ts
11532
- import { Command as Command62 } from "commander";
11533
- import chalk34 from "chalk";
12094
+ import { Command as Command72 } from "commander";
12095
+ import chalk44 from "chalk";
11534
12096
  import Table6 from "cli-table3";
11535
12097
 
11536
12098
  // src/services/starter-kit.service.ts
@@ -11598,13 +12160,13 @@ var StarterKitService = class {
11598
12160
 
11599
12161
  // src/commands/kit/list.ts
11600
12162
  function createKitListCommand() {
11601
- return new Command62("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) => {
12163
+ 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) => {
11602
12164
  const configService = new ConfigService();
11603
12165
  const config = await configService.load();
11604
12166
  if (!config) {
11605
12167
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
11606
12168
  }
11607
- console.log(chalk34.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch starter kits..."));
12169
+ console.log(chalk44.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch starter kits..."));
11608
12170
  console.log();
11609
12171
  const kitService = new StarterKitService();
11610
12172
  const kits = await kitService.list(config, {
@@ -11612,9 +12174,9 @@ function createKitListCommand() {
11612
12174
  search: options.search
11613
12175
  });
11614
12176
  if (kits.length === 0) {
11615
- console.log(chalk34.yellow("Kh\xF4ng t\xECm th\u1EA5y starter kits n\xE0o."));
12177
+ console.log(chalk44.yellow("Kh\xF4ng t\xECm th\u1EA5y starter kits n\xE0o."));
11616
12178
  if (options.category || options.search) {
11617
- console.log(chalk34.dim("Th\u1EED b\u1ECF filter \u0111\u1EC3 xem t\u1EA5t c\u1EA3."));
12179
+ console.log(chalk44.dim("Th\u1EED b\u1ECF filter \u0111\u1EC3 xem t\u1EA5t c\u1EA3."));
11618
12180
  }
11619
12181
  return;
11620
12182
  }
@@ -11638,35 +12200,35 @@ function createKitListCommand() {
11638
12200
  const categoryKits = byCategory[category];
11639
12201
  const categoryIcon = category === "frontend" ? "\u{1F3A8}" : category === "backend" ? "\u2699\uFE0F" : category === "fullstack" ? "\u{1F680}" : "\u{1F4E6}";
11640
12202
  console.log(
11641
- chalk34.bold(`${categoryIcon} ${category.charAt(0).toUpperCase() + category.slice(1)}`)
12203
+ chalk44.bold(`${categoryIcon} ${category.charAt(0).toUpperCase() + category.slice(1)}`)
11642
12204
  );
11643
12205
  const table = new Table6({
11644
12206
  head: [
11645
- chalk34.cyan("Slug"),
11646
- chalk34.cyan("M\xF4 t\u1EA3"),
11647
- chalk34.cyan("Version")
12207
+ chalk44.cyan("Slug"),
12208
+ chalk44.cyan("M\xF4 t\u1EA3"),
12209
+ chalk44.cyan("Version")
11648
12210
  ],
11649
12211
  style: { head: [], border: ["gray"] }
11650
12212
  });
11651
12213
  for (const kit of categoryKits) {
11652
12214
  table.push([
11653
- chalk34.white(kit.slug),
11654
- chalk34.dim(kit.description.slice(0, 50)),
11655
- chalk34.green(`v${kit.version}`)
12215
+ chalk44.white(kit.slug),
12216
+ chalk44.dim(kit.description.slice(0, 50)),
12217
+ chalk44.green(`v${kit.version}`)
11656
12218
  ]);
11657
12219
  }
11658
12220
  console.log(table.toString());
11659
12221
  console.log();
11660
12222
  }
11661
- console.log(chalk34.dim(`T\u1ED5ng c\u1ED9ng: ${kits.length} starter kit(s)`));
11662
- console.log(chalk34.dim('\n\u{1F4A1} Ch\u1EA1y "jai1 kit create <slug>" \u0111\u1EC3 t\u1EA1o project m\u1EDBi'));
12223
+ console.log(chalk44.dim(`T\u1ED5ng c\u1ED9ng: ${kits.length} starter kit(s)`));
12224
+ console.log(chalk44.dim('\n\u{1F4A1} Ch\u1EA1y "jai1 kit create <slug>" \u0111\u1EC3 t\u1EA1o project m\u1EDBi'));
11663
12225
  });
11664
12226
  }
11665
12227
 
11666
12228
  // src/commands/kit/info.ts
11667
- import { Command as Command63 } from "commander";
12229
+ import { Command as Command73 } from "commander";
11668
12230
  function createKitInfoCommand() {
11669
- return new Command63("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
12231
+ return new Command73("info").description("Show detailed information about a starter kit").argument("<slug>", "Starter kit slug").action(async (slug) => {
11670
12232
  const configService = new ConfigService();
11671
12233
  const config = await configService.load();
11672
12234
  if (!config) {
@@ -11715,7 +12277,7 @@ Post-Init Commands:`);
11715
12277
  }
11716
12278
 
11717
12279
  // src/commands/kit/create.ts
11718
- import { Command as Command64 } from "commander";
12280
+ import { Command as Command74 } from "commander";
11719
12281
  import { promises as fs20 } from "fs";
11720
12282
  import { join as join11 } from "path";
11721
12283
  import { select as select3, input as input2, checkbox as checkbox4 } from "@inquirer/prompts";
@@ -11760,7 +12322,7 @@ var HookExecutor = class {
11760
12322
 
11761
12323
  // src/commands/kit/create.ts
11762
12324
  function createKitCreateCommand() {
11763
- return new Command64("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) => {
12325
+ 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) => {
11764
12326
  const configService = new ConfigService();
11765
12327
  const config = await configService.load();
11766
12328
  if (!config) {
@@ -11939,23 +12501,23 @@ async function getAllFiles(dir) {
11939
12501
 
11940
12502
  // src/commands/kit/index.ts
11941
12503
  function showKitHelp() {
11942
- console.log(chalk35.bold.cyan("\u{1F4E6} jai1 kit") + chalk35.dim(" - Qu\u1EA3n l\xFD starter kits"));
12504
+ console.log(chalk45.bold.cyan("\u{1F4E6} jai1 kit") + chalk45.dim(" - Qu\u1EA3n l\xFD starter kits"));
11943
12505
  console.log();
11944
- console.log(chalk35.bold("C\xE1c l\u1EC7nh:"));
11945
- console.log(` ${chalk35.cyan("list")} Li\u1EC7t k\xEA c\xE1c starter kits c\xF3 s\u1EB5n`);
11946
- console.log(` ${chalk35.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t starter kit`);
11947
- console.log(` ${chalk35.cyan("create")} T\u1EA1o project m\u1EDBi t\u1EEB starter kit`);
12506
+ console.log(chalk45.bold("C\xE1c l\u1EC7nh:"));
12507
+ console.log(` ${chalk45.cyan("list")} Li\u1EC7t k\xEA c\xE1c starter kits c\xF3 s\u1EB5n`);
12508
+ console.log(` ${chalk45.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t starter kit`);
12509
+ console.log(` ${chalk45.cyan("create")} T\u1EA1o project m\u1EDBi t\u1EEB starter kit`);
11948
12510
  console.log();
11949
- console.log(chalk35.bold("V\xED d\u1EE5:"));
11950
- console.log(chalk35.dim(" $ jai1 kit list"));
11951
- console.log(chalk35.dim(" $ jai1 kit list --category frontend"));
11952
- console.log(chalk35.dim(" $ jai1 kit info next-tw4-shadcn"));
11953
- console.log(chalk35.dim(" $ jai1 kit create next-tw4-shadcn my-project"));
12511
+ console.log(chalk45.bold("V\xED d\u1EE5:"));
12512
+ console.log(chalk45.dim(" $ jai1 kit list"));
12513
+ console.log(chalk45.dim(" $ jai1 kit list --category frontend"));
12514
+ console.log(chalk45.dim(" $ jai1 kit info next-tw4-shadcn"));
12515
+ console.log(chalk45.dim(" $ jai1 kit create next-tw4-shadcn my-project"));
11954
12516
  console.log();
11955
- console.log(chalk35.dim('Ch\u1EA1y "jai1 kit <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
12517
+ console.log(chalk45.dim('Ch\u1EA1y "jai1 kit <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
11956
12518
  }
11957
12519
  function createKitCommand() {
11958
- const cmd = new Command65("kit").description("Manage starter kits for new projects").action(() => {
12520
+ const cmd = new Command75("kit").description("Manage starter kits for new projects").action(() => {
11959
12521
  showKitHelp();
11960
12522
  });
11961
12523
  cmd.addCommand(createKitListCommand());
@@ -11965,21 +12527,21 @@ function createKitCommand() {
11965
12527
  }
11966
12528
 
11967
12529
  // src/commands/rules/index.ts
11968
- import { Command as Command72 } from "commander";
11969
- import chalk37 from "chalk";
12530
+ import { Command as Command82 } from "commander";
12531
+ import chalk47 from "chalk";
11970
12532
 
11971
12533
  // src/commands/rules/list.ts
11972
- import { Command as Command66 } from "commander";
11973
- import chalk36 from "chalk";
12534
+ import { Command as Command76 } from "commander";
12535
+ import chalk46 from "chalk";
11974
12536
  import Table7 from "cli-table3";
11975
12537
  function createRulesListCommand() {
11976
- return new Command66("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
12538
+ return new Command76("list").description("List available rule presets").option("--json", "Output as JSON").action(async (options) => {
11977
12539
  const configService = new ConfigService();
11978
12540
  const config = await configService.load();
11979
12541
  if (!config) {
11980
12542
  throw new ValidationError('Not initialized. Run "jai1 auth" first.');
11981
12543
  }
11982
- console.log(chalk36.cyan("\u{1F4CB} \u0110ang t\u1EA3i danh s\xE1ch rule presets..."));
12544
+ console.log(chalk46.cyan("\u{1F4CB} \u0110ang t\u1EA3i danh s\xE1ch rule presets..."));
11983
12545
  console.log();
11984
12546
  try {
11985
12547
  const response = await fetch(`${config.apiUrl}/api/rules/presets`, {
@@ -11996,23 +12558,23 @@ function createRulesListCommand() {
11996
12558
  return;
11997
12559
  }
11998
12560
  if (data.total === 0) {
11999
- console.log(chalk36.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
12561
+ console.log(chalk46.yellow("Kh\xF4ng c\xF3 presets n\xE0o."));
12000
12562
  return;
12001
12563
  }
12002
12564
  console.log(
12003
- chalk36.green(`\u2713 T\xECm th\u1EA5y ${chalk36.bold(data.total)} preset${data.total > 1 ? "s" : ""}`)
12565
+ chalk46.green(`\u2713 T\xECm th\u1EA5y ${chalk46.bold(data.total)} preset${data.total > 1 ? "s" : ""}`)
12004
12566
  );
12005
12567
  console.log();
12006
12568
  for (const preset of data.presets) {
12007
- console.log(chalk36.bold.cyan(`\u{1F4E6} ${preset.slug}`));
12569
+ console.log(chalk46.bold.cyan(`\u{1F4E6} ${preset.slug}`));
12008
12570
  const table = new Table7({
12009
12571
  style: { head: [], border: ["gray"], compact: true },
12010
12572
  colWidths: [15, 55]
12011
12573
  });
12012
12574
  table.push(
12013
- [chalk36.dim("T\xEAn"), chalk36.white(preset.name)],
12014
- [chalk36.dim("M\xF4 t\u1EA3"), chalk36.white(preset.description)],
12015
- [chalk36.dim("Version"), chalk36.green(`v${preset.version}`)]
12575
+ [chalk46.dim("T\xEAn"), chalk46.white(preset.name)],
12576
+ [chalk46.dim("M\xF4 t\u1EA3"), chalk46.white(preset.description)],
12577
+ [chalk46.dim("Version"), chalk46.green(`v${preset.version}`)]
12016
12578
  );
12017
12579
  const stackParts = [];
12018
12580
  if (preset.stack.frontend) stackParts.push(preset.stack.frontend);
@@ -12020,16 +12582,16 @@ function createRulesListCommand() {
12020
12582
  if (preset.stack.css) stackParts.push(preset.stack.css);
12021
12583
  if (preset.stack.database) stackParts.push(preset.stack.database);
12022
12584
  if (stackParts.length > 0) {
12023
- table.push([chalk36.dim("Stack"), chalk36.yellow(stackParts.join(" + "))]);
12585
+ table.push([chalk46.dim("Stack"), chalk46.yellow(stackParts.join(" + "))]);
12024
12586
  }
12025
12587
  table.push(
12026
- [chalk36.dim("Tags"), chalk36.dim(preset.tags.join(", ") || "-")],
12027
- [chalk36.dim("Downloads"), chalk36.white(preset.downloads.toString())]
12588
+ [chalk46.dim("Tags"), chalk46.dim(preset.tags.join(", ") || "-")],
12589
+ [chalk46.dim("Downloads"), chalk46.white(preset.downloads.toString())]
12028
12590
  );
12029
12591
  console.log(table.toString());
12030
12592
  console.log();
12031
12593
  }
12032
- console.log(chalk36.dim('\u{1F4A1} Ch\u1EA1y "jai1 rules apply <name>" \u0111\u1EC3 \xE1p d\u1EE5ng preset'));
12594
+ console.log(chalk46.dim('\u{1F4A1} Ch\u1EA1y "jai1 rules apply <name>" \u0111\u1EC3 \xE1p d\u1EE5ng preset'));
12033
12595
  } catch (error) {
12034
12596
  throw new Error(
12035
12597
  `L\u1ED7i khi t\u1EA3i presets: ${error instanceof Error ? error.message : String(error)}`
@@ -12039,10 +12601,10 @@ function createRulesListCommand() {
12039
12601
  }
12040
12602
 
12041
12603
  // src/commands/rules/init.ts
12042
- import { Command as Command67 } from "commander";
12604
+ import { Command as Command77 } from "commander";
12043
12605
  import { promises as fs22 } from "fs";
12044
12606
  import { join as join13 } from "path";
12045
- import { select as select4, confirm as confirm12 } from "@inquirer/prompts";
12607
+ import { select as select4, confirm as confirm14 } from "@inquirer/prompts";
12046
12608
 
12047
12609
  // src/services/project-config.service.ts
12048
12610
  import { promises as fs21 } from "fs";
@@ -12164,7 +12726,7 @@ var ProjectConfigService = class {
12164
12726
 
12165
12727
  // src/commands/rules/init.ts
12166
12728
  function createRulesInitCommand() {
12167
- return new Command67("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) => {
12729
+ 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) => {
12168
12730
  const configService = new ConfigService();
12169
12731
  const config = await configService.load();
12170
12732
  if (!config) {
@@ -12226,7 +12788,7 @@ function createRulesInitCommand() {
12226
12788
  });
12227
12789
  }
12228
12790
  if (!options.yes) {
12229
- const proceed = await confirm12({
12791
+ const proceed = await confirm14({
12230
12792
  message: `Apply preset '${bundle.preset.name}' to current directory?`,
12231
12793
  default: true
12232
12794
  });
@@ -12296,10 +12858,10 @@ async function applyAgentsMdFormat(bundle) {
12296
12858
  }
12297
12859
 
12298
12860
  // src/commands/rules/apply.ts
12299
- import { Command as Command68 } from "commander";
12861
+ import { Command as Command78 } from "commander";
12300
12862
  import { promises as fs24 } from "fs";
12301
12863
  import { join as join15 } from "path";
12302
- import { search, confirm as confirm13, checkbox as checkbox5 } from "@inquirer/prompts";
12864
+ import { search, confirm as confirm15, checkbox as checkbox5 } from "@inquirer/prompts";
12303
12865
 
12304
12866
  // src/services/rules-generator.service.ts
12305
12867
  var RulesGeneratorService = class {
@@ -12810,7 +13372,7 @@ Restoring backup from ${metadata.timestamp}...`);
12810
13372
 
12811
13373
  // src/commands/rules/apply.ts
12812
13374
  function createRulesApplyCommand() {
12813
- return new Command68("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) => {
13375
+ 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) => {
12814
13376
  const configService = new ConfigService();
12815
13377
  const config = await configService.load();
12816
13378
  if (!config) {
@@ -12966,7 +13528,7 @@ function createRulesApplyCommand() {
12966
13528
  if (backupPath) {
12967
13529
  console.log(` Backup: ${backupPath}`);
12968
13530
  }
12969
- const proceed = await confirm13({
13531
+ const proceed = await confirm15({
12970
13532
  message: "Apply these rules to the current directory?",
12971
13533
  default: true
12972
13534
  });
@@ -13105,11 +13667,11 @@ function createRulesApplyCommand() {
13105
13667
  }
13106
13668
 
13107
13669
  // src/commands/rules/restore.ts
13108
- import { Command as Command69 } from "commander";
13670
+ import { Command as Command79 } from "commander";
13109
13671
  import { join as join16 } from "path";
13110
- import { select as select5, confirm as confirm14 } from "@inquirer/prompts";
13672
+ import { select as select5, confirm as confirm16 } from "@inquirer/prompts";
13111
13673
  function createRulesRestoreCommand() {
13112
- return new Command69("restore").description("Restore rules from a backup").option("--latest", "Restore the most recent backup").option("-y, --yes", "Skip confirmation").action(async (options) => {
13674
+ 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) => {
13113
13675
  const backupService = new BackupService();
13114
13676
  const backups = await backupService.listBackups();
13115
13677
  if (backups.length === 0) {
@@ -13142,7 +13704,7 @@ function createRulesRestoreCommand() {
13142
13704
  console.log(` IDEs: ${selectedBackup.ides.join(", ")}`);
13143
13705
  console.log(` Files: ${selectedBackup.files.length}`);
13144
13706
  if (!options.yes) {
13145
- const proceed = await confirm14({
13707
+ const proceed = await confirm16({
13146
13708
  message: "This will overwrite current rules. Continue?",
13147
13709
  default: false
13148
13710
  });
@@ -13178,12 +13740,12 @@ function formatTimestamp(timestamp) {
13178
13740
  }
13179
13741
 
13180
13742
  // src/commands/rules/sync.ts
13181
- import { Command as Command70 } from "commander";
13743
+ import { Command as Command80 } from "commander";
13182
13744
  import { promises as fs25 } from "fs";
13183
13745
  import { join as join17 } from "path";
13184
- import { checkbox as checkbox6, confirm as confirm15, Separator } from "@inquirer/prompts";
13746
+ import { checkbox as checkbox6, confirm as confirm17, Separator } from "@inquirer/prompts";
13185
13747
  function createRulesSyncCommand() {
13186
- return new Command70("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) => {
13748
+ 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) => {
13187
13749
  const rulePresetDir = join17(process.cwd(), ".jai1", "rule-preset");
13188
13750
  const presetJsonPath = join17(rulePresetDir, "preset.json");
13189
13751
  let presetExists = false;
@@ -13232,7 +13794,7 @@ Detected ${detected.length} active IDE(s):
13232
13794
  console.log(` ${confidence} ${d.name} - ${d.ruleCount} rules`);
13233
13795
  });
13234
13796
  if (!options.yes) {
13235
- const proceed = await confirm15({
13797
+ const proceed = await confirm17({
13236
13798
  message: "\nSync these detected IDEs?",
13237
13799
  default: true
13238
13800
  });
@@ -13401,11 +13963,11 @@ function buildIdeChoices(currentIdes, detected, suggestions) {
13401
13963
  }
13402
13964
 
13403
13965
  // src/commands/rules/info.ts
13404
- import { Command as Command71 } from "commander";
13966
+ import { Command as Command81 } from "commander";
13405
13967
  import { promises as fs26 } from "fs";
13406
13968
  import { join as join18 } from "path";
13407
13969
  function createRulesInfoCommand() {
13408
- return new Command71("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
13970
+ return new Command81("info").description("Show current preset information").option("--json", "Output as JSON").action(async (options) => {
13409
13971
  const projectConfigService = new ProjectConfigService();
13410
13972
  const rulesConfig = await projectConfigService.loadRules();
13411
13973
  if (!rulesConfig) {
@@ -13508,26 +14070,26 @@ async function checkIdeFilesExist(ideId, format) {
13508
14070
 
13509
14071
  // src/commands/rules/index.ts
13510
14072
  function showRulesHelp() {
13511
- console.log(chalk37.bold.cyan("\u{1F4CB} jai1 rules") + chalk37.dim(" - Qu\u1EA3n l\xFD rule presets cho AI agents"));
14073
+ console.log(chalk47.bold.cyan("\u{1F4CB} jai1 rules") + chalk47.dim(" - Qu\u1EA3n l\xFD rule presets cho AI agents"));
13512
14074
  console.log();
13513
- console.log(chalk37.bold("C\xE1c l\u1EC7nh:"));
13514
- console.log(` ${chalk37.cyan("list")} Li\u1EC7t k\xEA c\xE1c presets c\xF3 s\u1EB5n`);
13515
- console.log(` ${chalk37.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t preset`);
13516
- console.log(` ${chalk37.cyan("init")} Kh\u1EDFi t\u1EA1o rules t\u1EEB preset`);
13517
- console.log(` ${chalk37.cyan("apply")} \xC1p d\u1EE5ng preset v\xE0o project`);
13518
- console.log(` ${chalk37.cyan("sync")} \u0110\u1ED3ng b\u1ED9 rules sang c\xE1c \u0111\u1ECBnh d\u1EA1ng IDE`);
13519
- console.log(` ${chalk37.cyan("restore")} Kh\xF4i ph\u1EE5c rules t\u1EEB backup`);
14075
+ console.log(chalk47.bold("C\xE1c l\u1EC7nh:"));
14076
+ console.log(` ${chalk47.cyan("list")} Li\u1EC7t k\xEA c\xE1c presets c\xF3 s\u1EB5n`);
14077
+ console.log(` ${chalk47.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t preset`);
14078
+ console.log(` ${chalk47.cyan("init")} Kh\u1EDFi t\u1EA1o rules t\u1EEB preset`);
14079
+ console.log(` ${chalk47.cyan("apply")} \xC1p d\u1EE5ng preset v\xE0o project`);
14080
+ console.log(` ${chalk47.cyan("sync")} \u0110\u1ED3ng b\u1ED9 rules sang c\xE1c \u0111\u1ECBnh d\u1EA1ng IDE`);
14081
+ console.log(` ${chalk47.cyan("restore")} Kh\xF4i ph\u1EE5c rules t\u1EEB backup`);
13520
14082
  console.log();
13521
- console.log(chalk37.bold("V\xED d\u1EE5:"));
13522
- console.log(chalk37.dim(" $ jai1 rules list"));
13523
- console.log(chalk37.dim(" $ jai1 rules info react-typescript"));
13524
- console.log(chalk37.dim(" $ jai1 rules init --preset=react-typescript"));
13525
- console.log(chalk37.dim(" $ jai1 rules apply react-typescript"));
14083
+ console.log(chalk47.bold("V\xED d\u1EE5:"));
14084
+ console.log(chalk47.dim(" $ jai1 rules list"));
14085
+ console.log(chalk47.dim(" $ jai1 rules info react-typescript"));
14086
+ console.log(chalk47.dim(" $ jai1 rules init --preset=react-typescript"));
14087
+ console.log(chalk47.dim(" $ jai1 rules apply react-typescript"));
13526
14088
  console.log();
13527
- console.log(chalk37.dim('Ch\u1EA1y "jai1 rules <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
14089
+ console.log(chalk47.dim('Ch\u1EA1y "jai1 rules <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt'));
13528
14090
  }
13529
14091
  function createRulesCommand() {
13530
- const rulesCommand = new Command72("rules").description("Manage rule presets for AI agents").action(() => {
14092
+ const rulesCommand = new Command82("rules").description("Manage rule presets for AI agents").action(() => {
13531
14093
  showRulesHelp();
13532
14094
  });
13533
14095
  rulesCommand.addCommand(createRulesListCommand());
@@ -13540,12 +14102,12 @@ function createRulesCommand() {
13540
14102
  }
13541
14103
 
13542
14104
  // src/commands/skills/index.ts
13543
- import { Command as Command78 } from "commander";
13544
- import chalk43 from "chalk";
14105
+ import { Command as Command88 } from "commander";
14106
+ import chalk53 from "chalk";
13545
14107
 
13546
14108
  // src/commands/skills/find.ts
13547
- import { Command as Command73 } from "commander";
13548
- import chalk38 from "chalk";
14109
+ import { Command as Command83 } from "commander";
14110
+ import chalk48 from "chalk";
13549
14111
  import Table8 from "cli-table3";
13550
14112
 
13551
14113
  // src/services/skills.service.ts
@@ -13839,7 +14401,7 @@ var SkillsService = class {
13839
14401
 
13840
14402
  // src/commands/skills/find.ts
13841
14403
  function createSkillsFindCommand() {
13842
- return new Command73("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) => {
14404
+ 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) => {
13843
14405
  const searchNpm = options.skillsh || options.all;
13844
14406
  const searchServer = !options.skillsh || options.all;
13845
14407
  if (searchServer) {
@@ -13848,19 +14410,19 @@ function createSkillsFindCommand() {
13848
14410
  if (!config) {
13849
14411
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
13850
14412
  }
13851
- console.log(chalk38.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn Jai1 server..."));
14413
+ console.log(chalk48.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn Jai1 server..."));
13852
14414
  console.log();
13853
14415
  const skillsService = new SkillsService();
13854
14416
  const results = await skillsService.searchFromServer(config, query);
13855
14417
  if (results.length === 0) {
13856
- console.log(chalk38.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o tr\xEAn server."));
14418
+ console.log(chalk48.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o tr\xEAn server."));
13857
14419
  } else {
13858
14420
  const table = new Table8({
13859
14421
  head: [
13860
- chalk38.cyan("T\xEAn"),
13861
- chalk38.cyan("M\xF4 t\u1EA3"),
13862
- chalk38.cyan("Version"),
13863
- chalk38.cyan("Downloads")
14422
+ chalk48.cyan("T\xEAn"),
14423
+ chalk48.cyan("M\xF4 t\u1EA3"),
14424
+ chalk48.cyan("Version"),
14425
+ chalk48.cyan("Downloads")
13864
14426
  ],
13865
14427
  style: { head: [], border: ["gray"] },
13866
14428
  colWidths: [25, 40, 10, 12]
@@ -13868,70 +14430,70 @@ function createSkillsFindCommand() {
13868
14430
  for (const skill of results) {
13869
14431
  const name = skill.filepath.replace("skills/", "");
13870
14432
  table.push([
13871
- chalk38.white(name),
13872
- chalk38.dim((skill.description || "").slice(0, 38)),
13873
- chalk38.green(skill.version || "-"),
13874
- chalk38.dim(String(skill.downloads || 0))
14433
+ chalk48.white(name),
14434
+ chalk48.dim((skill.description || "").slice(0, 38)),
14435
+ chalk48.green(skill.version || "-"),
14436
+ chalk48.dim(String(skill.downloads || 0))
13875
14437
  ]);
13876
14438
  }
13877
- console.log(chalk38.bold(`\u{1F4E6} Jai1 Server (${results.length} k\u1EBFt qu\u1EA3)`));
14439
+ console.log(chalk48.bold(`\u{1F4E6} Jai1 Server (${results.length} k\u1EBFt qu\u1EA3)`));
13878
14440
  console.log(table.toString());
13879
14441
  console.log();
13880
14442
  }
13881
14443
  }
13882
14444
  if (searchNpm) {
13883
- console.log(chalk38.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn npm skills..."));
14445
+ console.log(chalk48.cyan("\u{1F50D} \u0110ang t\xECm ki\u1EBFm tr\xEAn npm skills..."));
13884
14446
  console.log();
13885
14447
  const skillsService = new SkillsService();
13886
14448
  try {
13887
14449
  const output = await skillsService.npmSkillsFind(query);
13888
- console.log(chalk38.bold("\u{1F310} npm Skills Registry"));
14450
+ console.log(chalk48.bold("\u{1F310} npm Skills Registry"));
13889
14451
  console.log(output);
13890
14452
  } catch (error) {
13891
- console.log(chalk38.yellow(
14453
+ console.log(chalk48.yellow(
13892
14454
  `Kh\xF4ng th\u1EC3 t\xECm ki\u1EBFm tr\xEAn npm: ${error instanceof Error ? error.message : String(error)}`
13893
14455
  ));
13894
14456
  }
13895
14457
  }
13896
14458
  if (searchServer && !searchNpm) {
13897
- console.log(chalk38.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t t\u1EEB server'));
14459
+ console.log(chalk48.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t t\u1EEB server'));
13898
14460
  } else if (searchNpm && !searchServer) {
13899
- console.log(chalk38.dim('\u{1F4A1} D\xF9ng "j skills add <owner/repo@skill> --skillsh" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14461
+ console.log(chalk48.dim('\u{1F4A1} D\xF9ng "j skills add <owner/repo@skill> --skillsh" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
13900
14462
  } else {
13901
- console.log(chalk38.dim("\u{1F4A1} C\xE0i \u0111\u1EB7t:"));
13902
- console.log(chalk38.dim(" Server: j skills add <t\xEAn>"));
13903
- console.log(chalk38.dim(" Skills.sh: j skills add <owner/repo@skill> --skillsh"));
14463
+ console.log(chalk48.dim("\u{1F4A1} C\xE0i \u0111\u1EB7t:"));
14464
+ console.log(chalk48.dim(" Server: j skills add <t\xEAn>"));
14465
+ console.log(chalk48.dim(" Skills.sh: j skills add <owner/repo@skill> --skillsh"));
13904
14466
  }
13905
14467
  });
13906
14468
  }
13907
14469
 
13908
14470
  // src/commands/skills/add.ts
13909
- import { Command as Command74 } from "commander";
14471
+ import { Command as Command84 } from "commander";
13910
14472
  import { join as join20 } from "path";
13911
- import chalk39 from "chalk";
14473
+ import chalk49 from "chalk";
13912
14474
  import { checkbox as checkbox7 } from "@inquirer/prompts";
13913
14475
  function createSkillsAddCommand() {
13914
- return new Command74("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) => {
14476
+ 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) => {
13915
14477
  const skillsService = new SkillsService();
13916
14478
  const projectRoot = process.cwd();
13917
14479
  const headless = options.yes === true;
13918
14480
  if (options.skillsh) {
13919
- console.log(chalk39.cyan(`\u{1F310} \u0110ang c\xE0i \u0111\u1EB7t skill t\u1EEB npm: ${name}...`));
14481
+ console.log(chalk49.cyan(`\u{1F310} \u0110ang c\xE0i \u0111\u1EB7t skill t\u1EEB npm: ${name}...`));
13920
14482
  console.log();
13921
14483
  const output = await skillsService.npmSkillsAdd(name, projectRoot);
13922
14484
  console.log(output);
13923
- console.log(chalk39.green("\u2705 C\xE0i \u0111\u1EB7t t\u1EEB npm th\xE0nh c\xF4ng!"));
14485
+ console.log(chalk49.green("\u2705 C\xE0i \u0111\u1EB7t t\u1EEB npm th\xE0nh c\xF4ng!"));
13924
14486
  } else {
13925
14487
  const configService = new ConfigService();
13926
14488
  const config = await configService.load();
13927
14489
  if (!config) {
13928
14490
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
13929
14491
  }
13930
- console.log(chalk39.cyan(`\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t skill: ${name}...`));
14492
+ console.log(chalk49.cyan(`\u{1F4E6} \u0110ang c\xE0i \u0111\u1EB7t skill: ${name}...`));
13931
14493
  console.log();
13932
14494
  const targetDir = join20(projectRoot, ".jai1");
13933
14495
  await skillsService.installFromServer(config, name, targetDir);
13934
- console.log(chalk39.green(`\u2705 \u0110\xE3 c\xE0i \u0111\u1EB7t skill "${name}" v\xE0o .jai1/skills/${name}/`));
14496
+ console.log(chalk49.green(`\u2705 \u0110\xE3 c\xE0i \u0111\u1EB7t skill "${name}" v\xE0o .jai1/skills/${name}/`));
13935
14497
  }
13936
14498
  console.log();
13937
14499
  if (options.sync) {
@@ -13956,7 +14518,7 @@ function createSkillsAddCommand() {
13956
14518
  });
13957
14519
  }
13958
14520
  if (selectedIdes.length > 0) {
13959
- console.log(chalk39.cyan("\u{1F504} \u0110ang sync sang IDE(s)..."));
14521
+ console.log(chalk49.cyan("\u{1F504} \u0110ang sync sang IDE(s)..."));
13960
14522
  console.log();
13961
14523
  const slug = name.includes("/") ? name.split("/").pop() : name;
13962
14524
  const result = await skillsService.syncToIdes(
@@ -13969,24 +14531,24 @@ function createSkillsAddCommand() {
13969
14531
  }
13970
14532
  );
13971
14533
  console.log();
13972
- console.log(chalk39.green(`\u2705 Sync ho\xE0n t\u1EA5t! Created: ${result.created}, Updated: ${result.updated}`));
14534
+ console.log(chalk49.green(`\u2705 Sync ho\xE0n t\u1EA5t! Created: ${result.created}, Updated: ${result.updated}`));
13973
14535
  if (result.errors > 0) {
13974
- console.log(chalk39.yellow(`\u26A0\uFE0F Errors: ${result.errors}`));
14536
+ console.log(chalk49.yellow(`\u26A0\uFE0F Errors: ${result.errors}`));
13975
14537
  }
13976
14538
  }
13977
14539
  } else {
13978
- console.log(chalk39.dim('\u{1F4A1} Ch\u1EA1y "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
13979
- console.log(chalk39.dim(' ho\u1EB7c "j ide sync" \u0111\u1EC3 sync to\xE0n b\u1ED9 .jai1/'));
14540
+ console.log(chalk49.dim('\u{1F4A1} Ch\u1EA1y "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14541
+ console.log(chalk49.dim(' ho\u1EB7c "j ide sync" \u0111\u1EC3 sync to\xE0n b\u1ED9 .jai1/'));
13980
14542
  }
13981
14543
  });
13982
14544
  }
13983
14545
 
13984
14546
  // src/commands/skills/list.ts
13985
- import { Command as Command75 } from "commander";
13986
- import chalk40 from "chalk";
14547
+ import { Command as Command85 } from "commander";
14548
+ import chalk50 from "chalk";
13987
14549
  import Table9 from "cli-table3";
13988
14550
  function createSkillsListCommand() {
13989
- return new Command75("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) => {
14551
+ 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) => {
13990
14552
  const skillsService = new SkillsService();
13991
14553
  if (options.available) {
13992
14554
  const configService = new ConfigService();
@@ -13994,19 +14556,19 @@ function createSkillsListCommand() {
13994
14556
  if (!config) {
13995
14557
  throw new ValidationError('Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.');
13996
14558
  }
13997
- console.log(chalk40.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch skills t\u1EEB server..."));
14559
+ console.log(chalk50.cyan("\u{1F4E6} \u0110ang t\u1EA3i danh s\xE1ch skills t\u1EEB server..."));
13998
14560
  console.log();
13999
14561
  const results = await skillsService.searchFromServer(config, options.search);
14000
14562
  if (results.length === 0) {
14001
- console.log(chalk40.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o."));
14563
+ console.log(chalk50.yellow("Kh\xF4ng t\xECm th\u1EA5y skills n\xE0o."));
14002
14564
  return;
14003
14565
  }
14004
14566
  const table = new Table9({
14005
14567
  head: [
14006
- chalk40.cyan("T\xEAn"),
14007
- chalk40.cyan("M\xF4 t\u1EA3"),
14008
- chalk40.cyan("Version"),
14009
- chalk40.cyan("Downloads")
14568
+ chalk50.cyan("T\xEAn"),
14569
+ chalk50.cyan("M\xF4 t\u1EA3"),
14570
+ chalk50.cyan("Version"),
14571
+ chalk50.cyan("Downloads")
14010
14572
  ],
14011
14573
  style: { head: [], border: ["gray"] },
14012
14574
  colWidths: [28, 40, 10, 12]
@@ -14014,63 +14576,63 @@ function createSkillsListCommand() {
14014
14576
  for (const skill of results) {
14015
14577
  const name = skill.filepath.replace("skills/", "");
14016
14578
  table.push([
14017
- chalk40.white(name),
14018
- chalk40.dim((skill.description || "").slice(0, 38)),
14019
- chalk40.green(skill.version || "-"),
14020
- chalk40.dim(String(skill.downloads || 0))
14579
+ chalk50.white(name),
14580
+ chalk50.dim((skill.description || "").slice(0, 38)),
14581
+ chalk50.green(skill.version || "-"),
14582
+ chalk50.dim(String(skill.downloads || 0))
14021
14583
  ]);
14022
14584
  }
14023
14585
  console.log(table.toString());
14024
14586
  console.log();
14025
- console.log(chalk40.dim(`T\u1ED5ng c\u1ED9ng: ${results.length} skill(s)`));
14026
- console.log(chalk40.dim('\n\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14587
+ console.log(chalk50.dim(`T\u1ED5ng c\u1ED9ng: ${results.length} skill(s)`));
14588
+ console.log(chalk50.dim('\n\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14027
14589
  } else {
14028
14590
  const projectRoot = process.cwd();
14029
14591
  const skills = await skillsService.listLocal(projectRoot);
14030
14592
  if (skills.length === 0) {
14031
- console.log(chalk40.yellow("Ch\u01B0a c\xF3 skills n\xE0o \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t."));
14593
+ console.log(chalk50.yellow("Ch\u01B0a c\xF3 skills n\xE0o \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t."));
14032
14594
  console.log();
14033
- console.log(chalk40.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14034
- console.log(chalk40.dim(' ho\u1EB7c "j skills list --available" \u0111\u1EC3 xem skills c\xF3 s\u1EB5n'));
14595
+ console.log(chalk50.dim('\u{1F4A1} D\xF9ng "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14596
+ console.log(chalk50.dim(' ho\u1EB7c "j skills list --available" \u0111\u1EC3 xem skills c\xF3 s\u1EB5n'));
14035
14597
  return;
14036
14598
  }
14037
- console.log(chalk40.bold.cyan("\u{1F6E0} Skills \u0111\xE3 c\xE0i \u0111\u1EB7t"));
14599
+ console.log(chalk50.bold.cyan("\u{1F6E0} Skills \u0111\xE3 c\xE0i \u0111\u1EB7t"));
14038
14600
  console.log();
14039
14601
  const table = new Table9({
14040
14602
  head: [
14041
- chalk40.cyan("T\xEAn"),
14042
- chalk40.cyan("M\xF4 t\u1EA3"),
14043
- chalk40.cyan("Files")
14603
+ chalk50.cyan("T\xEAn"),
14604
+ chalk50.cyan("M\xF4 t\u1EA3"),
14605
+ chalk50.cyan("Files")
14044
14606
  ],
14045
14607
  style: { head: [], border: ["gray"] },
14046
14608
  colWidths: [28, 45, 8]
14047
14609
  });
14048
14610
  for (const skill of skills) {
14049
14611
  table.push([
14050
- chalk40.white(skill.slug),
14051
- chalk40.dim(skill.description.slice(0, 43)),
14052
- chalk40.dim(String(skill.fileCount))
14612
+ chalk50.white(skill.slug),
14613
+ chalk50.dim(skill.description.slice(0, 43)),
14614
+ chalk50.dim(String(skill.fileCount))
14053
14615
  ]);
14054
14616
  }
14055
14617
  console.log(table.toString());
14056
14618
  console.log();
14057
- console.log(chalk40.dim(`T\u1ED5ng c\u1ED9ng: ${skills.length} skill(s)`));
14058
- console.log(chalk40.dim('\n\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14619
+ console.log(chalk50.dim(`T\u1ED5ng c\u1ED9ng: ${skills.length} skill(s)`));
14620
+ console.log(chalk50.dim('\n\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14059
14621
  }
14060
14622
  });
14061
14623
  }
14062
14624
 
14063
14625
  // src/commands/skills/info.ts
14064
- import { Command as Command76 } from "commander";
14065
- import chalk41 from "chalk";
14626
+ import { Command as Command86 } from "commander";
14627
+ import chalk51 from "chalk";
14066
14628
  function createSkillsInfoCommand() {
14067
- return new Command76("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) => {
14629
+ 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) => {
14068
14630
  const skillsService = new SkillsService();
14069
14631
  if (options.server) {
14070
14632
  const configService = new ConfigService();
14071
14633
  const config = await configService.load();
14072
14634
  if (!config) {
14073
- console.log(chalk41.red('\u274C Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.'));
14635
+ console.log(chalk51.red('\u274C Ch\u01B0a x\xE1c th\u1EF1c. Ch\u1EA1y "jai1 auth" tr\u01B0\u1EDBc.'));
14074
14636
  process.exit(1);
14075
14637
  }
14076
14638
  const filepath = name.startsWith("skills/") ? name : `skills/${name}`;
@@ -14079,7 +14641,7 @@ function createSkillsInfoCommand() {
14079
14641
  try {
14080
14642
  const component = await componentsService.get(config, filepath);
14081
14643
  console.log(`
14082
- \u{1F6E0} ${chalk41.bold(component.name || name)}
14644
+ \u{1F6E0} ${chalk51.bold(component.name || name)}
14083
14645
  `);
14084
14646
  console.log(`Filepath: ${component.filepath}`);
14085
14647
  console.log(`Version: ${component.version}`);
@@ -14092,47 +14654,47 @@ function createSkillsInfoCommand() {
14092
14654
  }
14093
14655
  console.log(`Type: ${component.contentType}`);
14094
14656
  console.log();
14095
- console.log(chalk41.dim('\u{1F4A1} D\xF9ng "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14657
+ console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14096
14658
  } catch (error) {
14097
- console.log(chalk41.red(`\u274C Kh\xF4ng t\xECm th\u1EA5y skill "${name}" tr\xEAn server.`));
14659
+ console.log(chalk51.red(`\u274C Kh\xF4ng t\xECm th\u1EA5y skill "${name}" tr\xEAn server.`));
14098
14660
  process.exit(1);
14099
14661
  }
14100
14662
  } else {
14101
14663
  const projectRoot = process.cwd();
14102
14664
  const skill = await skillsService.getSkillInfo(projectRoot, name);
14103
14665
  if (!skill) {
14104
- console.log(chalk41.red(`\u274C Skill "${name}" ch\u01B0a \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t.`));
14105
- console.log(chalk41.dim('\u{1F4A1} D\xF9ng "j skills info ' + name + ' --server" \u0111\u1EC3 xem tr\xEAn server'));
14106
- console.log(chalk41.dim(' ho\u1EB7c "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14666
+ console.log(chalk51.red(`\u274C Skill "${name}" ch\u01B0a \u0111\u01B0\u1EE3c c\xE0i \u0111\u1EB7t.`));
14667
+ console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills info ' + name + ' --server" \u0111\u1EC3 xem tr\xEAn server'));
14668
+ console.log(chalk51.dim(' ho\u1EB7c "j skills add ' + name + '" \u0111\u1EC3 c\xE0i \u0111\u1EB7t'));
14107
14669
  process.exit(1);
14108
14670
  }
14109
14671
  console.log(`
14110
- \u{1F6E0} ${chalk41.bold(skill.name)}
14672
+ \u{1F6E0} ${chalk51.bold(skill.name)}
14111
14673
  `);
14112
14674
  console.log(`Slug: ${skill.slug}`);
14113
- console.log(`Description: ${skill.description || chalk41.dim("(none)")}`);
14675
+ console.log(`Description: ${skill.description || chalk51.dim("(none)")}`);
14114
14676
  console.log(`Path: ${skill.path}`);
14115
14677
  console.log(`Files: ${skill.fileCount}`);
14116
14678
  console.log();
14117
- console.log(chalk41.dim('\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14679
+ console.log(chalk51.dim('\u{1F4A1} D\xF9ng "j skills sync" \u0111\u1EC3 \u0111\u1ED3ng b\u1ED9 sang IDE(s)'));
14118
14680
  }
14119
14681
  });
14120
14682
  }
14121
14683
 
14122
14684
  // src/commands/skills/sync.ts
14123
- import { Command as Command77 } from "commander";
14124
- import chalk42 from "chalk";
14125
- import { confirm as confirm17, checkbox as checkbox8 } from "@inquirer/prompts";
14685
+ import { Command as Command87 } from "commander";
14686
+ import chalk52 from "chalk";
14687
+ import { confirm as confirm19, checkbox as checkbox8 } from "@inquirer/prompts";
14126
14688
  function createSkillsSyncCommand() {
14127
- return new Command77("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) => {
14689
+ 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) => {
14128
14690
  const skillsService = new SkillsService();
14129
14691
  const projectRoot = process.cwd();
14130
14692
  const headless = options.yes === true;
14131
- console.log(chalk42.bold.cyan("\n\u{1F504} Sync skills sang IDE(s)\n"));
14693
+ console.log(chalk52.bold.cyan("\n\u{1F504} Sync skills sang IDE(s)\n"));
14132
14694
  const localSkills = await skillsService.listLocal(projectRoot);
14133
14695
  if (localSkills.length === 0) {
14134
- console.log(chalk42.yellow("\u26A0\uFE0F Kh\xF4ng c\xF3 skills n\xE0o trong .jai1/skills/"));
14135
- console.log(chalk42.dim('\u{1F4A1} Ch\u1EA1y "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t skills tr\u01B0\u1EDBc'));
14696
+ console.log(chalk52.yellow("\u26A0\uFE0F Kh\xF4ng c\xF3 skills n\xE0o trong .jai1/skills/"));
14697
+ console.log(chalk52.dim('\u{1F4A1} Ch\u1EA1y "j skills add <t\xEAn>" \u0111\u1EC3 c\xE0i \u0111\u1EB7t skills tr\u01B0\u1EDBc'));
14136
14698
  process.exit(1);
14137
14699
  }
14138
14700
  console.log(`\u{1F4C1} T\xECm th\u1EA5y ${localSkills.length} skill(s) trong .jai1/skills/`);
@@ -14164,7 +14726,7 @@ function createSkillsSyncCommand() {
14164
14726
  theme: checkboxTheme
14165
14727
  });
14166
14728
  if (selectedIdes.length === 0) {
14167
- console.log(chalk42.yellow("\n\u26A0\uFE0F Ch\u01B0a ch\u1ECDn IDE n\xE0o!"));
14729
+ console.log(chalk52.yellow("\n\u26A0\uFE0F Ch\u01B0a ch\u1ECDn IDE n\xE0o!"));
14168
14730
  process.exit(0);
14169
14731
  }
14170
14732
  }
@@ -14179,34 +14741,34 @@ function createSkillsSyncCommand() {
14179
14741
  console.log(` Total: ${totalFiles} skill folder(s) s\u1EBD \u0111\u01B0\u1EE3c sync
14180
14742
  `);
14181
14743
  if (options.dryRun) {
14182
- console.log(chalk42.dim("\u{1F50D} DRY RUN - Kh\xF4ng c\xF3 file n\xE0o \u0111\u01B0\u1EE3c ghi\n"));
14744
+ console.log(chalk52.dim("\u{1F50D} DRY RUN - Kh\xF4ng c\xF3 file n\xE0o \u0111\u01B0\u1EE3c ghi\n"));
14183
14745
  return;
14184
14746
  }
14185
14747
  if (!headless) {
14186
- const confirmed = await confirm17({
14748
+ const confirmed = await confirm19({
14187
14749
  message: "Ti\u1EBFp t\u1EE5c sync?",
14188
14750
  default: true
14189
14751
  });
14190
14752
  if (!confirmed) {
14191
- console.log(chalk42.yellow("\n\u274C \u0110\xE3 h\u1EE7y sync.\n"));
14753
+ console.log(chalk52.yellow("\n\u274C \u0110\xE3 h\u1EE7y sync.\n"));
14192
14754
  process.exit(0);
14193
14755
  }
14194
14756
  }
14195
- console.log(chalk42.cyan("\n\u{1F504} \u0110ang sync...\n"));
14757
+ console.log(chalk52.cyan("\n\u{1F504} \u0110ang sync...\n"));
14196
14758
  const result = await skillsService.syncToIdes(
14197
14759
  projectRoot,
14198
14760
  selectedIdes,
14199
14761
  selectedSlugs,
14200
14762
  (res) => {
14201
14763
  const icon = res.status === "created" ? "\u2713" : res.status === "updated" ? "\u21BB" : "\u2717";
14202
- const statusColor = res.status === "error" ? chalk42.red : chalk42.green;
14203
- console.log(` ${statusColor(icon)} ${res.ide}: ${res.skill} \u2192 ${chalk42.dim(res.path)}`);
14764
+ const statusColor = res.status === "error" ? chalk52.red : chalk52.green;
14765
+ console.log(` ${statusColor(icon)} ${res.ide}: ${res.skill} \u2192 ${chalk52.dim(res.path)}`);
14204
14766
  if (res.status === "error" && res.error) {
14205
- console.log(` ${chalk42.red("Error:")} ${res.error}`);
14767
+ console.log(` ${chalk52.red("Error:")} ${res.error}`);
14206
14768
  }
14207
14769
  }
14208
14770
  );
14209
- console.log(chalk42.green("\n\u2705 Sync ho\xE0n t\u1EA5t!\n"));
14771
+ console.log(chalk52.green("\n\u2705 Sync ho\xE0n t\u1EA5t!\n"));
14210
14772
  console.log(` Created: ${result.created}`);
14211
14773
  console.log(` Updated: ${result.updated}`);
14212
14774
  if (result.errors > 0) {
@@ -14219,27 +14781,27 @@ function createSkillsSyncCommand() {
14219
14781
  // src/commands/skills/index.ts
14220
14782
  function showSkillsHelp() {
14221
14783
  const cli = getCliName();
14222
- console.log(chalk43.bold.cyan("\u{1F6E0} " + cli + " skills") + chalk43.dim(" - Qu\u1EA3n l\xFD agent skills"));
14784
+ console.log(chalk53.bold.cyan("\u{1F6E0} " + cli + " skills") + chalk53.dim(" - Qu\u1EA3n l\xFD agent skills"));
14223
14785
  console.log();
14224
- console.log(chalk43.bold("C\xE1c l\u1EC7nh:"));
14225
- console.log(` ${chalk43.cyan("find")} T\xECm ki\u1EBFm skills tr\xEAn server ho\u1EB7c npm`);
14226
- console.log(` ${chalk43.cyan("add")} C\xE0i \u0111\u1EB7t skill v\xE0o .jai1/skills/`);
14227
- console.log(` ${chalk43.cyan("list")} Li\u1EC7t k\xEA skills \u0111\xE3 c\xE0i ho\u1EB7c c\xF3 s\u1EB5n`);
14228
- console.log(` ${chalk43.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t skill`);
14229
- console.log(` ${chalk43.cyan("sync")} \u0110\u1ED3ng b\u1ED9 skills sang c\xE1c IDE`);
14786
+ console.log(chalk53.bold("C\xE1c l\u1EC7nh:"));
14787
+ console.log(` ${chalk53.cyan("find")} T\xECm ki\u1EBFm skills tr\xEAn server ho\u1EB7c npm`);
14788
+ console.log(` ${chalk53.cyan("add")} C\xE0i \u0111\u1EB7t skill v\xE0o .jai1/skills/`);
14789
+ console.log(` ${chalk53.cyan("list")} Li\u1EC7t k\xEA skills \u0111\xE3 c\xE0i ho\u1EB7c c\xF3 s\u1EB5n`);
14790
+ console.log(` ${chalk53.cyan("info")} Xem chi ti\u1EBFt m\u1ED9t skill`);
14791
+ console.log(` ${chalk53.cyan("sync")} \u0110\u1ED3ng b\u1ED9 skills sang c\xE1c IDE`);
14230
14792
  console.log();
14231
- console.log(chalk43.bold("V\xED d\u1EE5:"));
14232
- console.log(chalk43.dim(` $ ${cli} skills find audit`));
14233
- console.log(chalk43.dim(` $ ${cli} skills find "react" --skillsh`));
14234
- console.log(chalk43.dim(` $ ${cli} skills add brainstorming`));
14235
- console.log(chalk43.dim(` $ ${cli} skills add vercel/next-skills --skillsh`));
14236
- console.log(chalk43.dim(` $ ${cli} skills list`));
14237
- console.log(chalk43.dim(` $ ${cli} skills sync --all -y`));
14793
+ console.log(chalk53.bold("V\xED d\u1EE5:"));
14794
+ console.log(chalk53.dim(` $ ${cli} skills find audit`));
14795
+ console.log(chalk53.dim(` $ ${cli} skills find "react" --skillsh`));
14796
+ console.log(chalk53.dim(` $ ${cli} skills add brainstorming`));
14797
+ console.log(chalk53.dim(` $ ${cli} skills add vercel/next-skills --skillsh`));
14798
+ console.log(chalk53.dim(` $ ${cli} skills list`));
14799
+ console.log(chalk53.dim(` $ ${cli} skills sync --all -y`));
14238
14800
  console.log();
14239
- console.log(chalk43.dim(`Ch\u1EA1y "${cli} skills <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt`));
14801
+ console.log(chalk53.dim(`Ch\u1EA1y "${cli} skills <l\u1EC7nh> --help" \u0111\u1EC3 xem chi ti\u1EBFt`));
14240
14802
  }
14241
14803
  function createSkillsCommand() {
14242
- const cmd = new Command78("skills").alias("s").description("Manage agent skills (search, install, sync to IDEs)").action(() => {
14804
+ const cmd = new Command88("skills").alias("s").description("Manage agent skills (search, install, sync to IDEs)").action(() => {
14243
14805
  showSkillsHelp();
14244
14806
  });
14245
14807
  cmd.addCommand(createSkillsFindCommand());
@@ -14251,8 +14813,8 @@ function createSkillsCommand() {
14251
14813
  }
14252
14814
 
14253
14815
  // src/commands/upgrade.ts
14254
- import { Command as Command79 } from "commander";
14255
- import { confirm as confirm18 } from "@inquirer/prompts";
14816
+ import { Command as Command89 } from "commander";
14817
+ import { confirm as confirm20 } from "@inquirer/prompts";
14256
14818
  import { execSync as execSync5 } from "child_process";
14257
14819
  var colors2 = {
14258
14820
  yellow: "\x1B[33m",
@@ -14263,7 +14825,7 @@ var colors2 = {
14263
14825
  bold: "\x1B[1m"
14264
14826
  };
14265
14827
  function createUpgradeCommand() {
14266
- return new Command79("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) => {
14828
+ 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) => {
14267
14829
  await handleUpgrade(options);
14268
14830
  });
14269
14831
  }
@@ -14312,7 +14874,7 @@ ${colors2.bold}Current version:${colors2.reset} ${currentVersion}`);
14312
14874
  return;
14313
14875
  }
14314
14876
  if (!options.force) {
14315
- const shouldUpdate = await confirm18({
14877
+ const shouldUpdate = await confirm20({
14316
14878
  message: "Update to the latest version now?",
14317
14879
  default: true
14318
14880
  });
@@ -14416,11 +14978,11 @@ function getInstallCommand(packageManager2) {
14416
14978
  }
14417
14979
 
14418
14980
  // src/commands/clean.ts
14419
- import { Command as Command80 } from "commander";
14420
- import { confirm as confirm19, select as select6 } from "@inquirer/prompts";
14981
+ import { Command as Command90 } from "commander";
14982
+ import { confirm as confirm21, select as select6 } from "@inquirer/prompts";
14421
14983
  import { join as join21 } from "path";
14422
14984
  function createCleanCommand() {
14423
- return new Command80("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
14985
+ return new Command90("clean").description("Clean up backups, cache, and temporary files").option("-y, --yes", "Skip confirmation").option("--backups", "Clean only backup files").option("--all", "Clean all (backups + cache)").action(async (options) => {
14424
14986
  await handleClean(options);
14425
14987
  });
14426
14988
  }
@@ -14516,7 +15078,7 @@ async function cleanTarget(target, skipConfirm) {
14516
15078
  }
14517
15079
  const countStr = info.count ? ` (${info.count} items)` : "";
14518
15080
  if (!skipConfirm) {
14519
- const confirmed = await confirm19({
15081
+ const confirmed = await confirm21({
14520
15082
  message: `Delete ${target.name}${countStr}?`,
14521
15083
  default: false
14522
15084
  });
@@ -14534,7 +15096,7 @@ async function cleanTarget(target, skipConfirm) {
14534
15096
  }
14535
15097
 
14536
15098
  // src/commands/redmine/check.ts
14537
- import { Command as Command81 } from "commander";
15099
+ import { Command as Command91 } from "commander";
14538
15100
 
14539
15101
  // src/services/redmine-config.service.ts
14540
15102
  import { readFile as readFile7 } from "fs/promises";
@@ -14841,7 +15403,7 @@ async function checkConnectivity(config) {
14841
15403
 
14842
15404
  // src/commands/redmine/check.ts
14843
15405
  function createRedmineCheckCommand() {
14844
- const cmd = new Command81("check").description("Check Redmine connectivity").option("-c, --config <path>", "Config file path", "redmine.config.yaml").option("--json", "Output as JSON").action(async (options) => {
15406
+ 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) => {
14845
15407
  await handleRedmineCheck(options);
14846
15408
  });
14847
15409
  return cmd;
@@ -14869,7 +15431,7 @@ async function handleRedmineCheck(options) {
14869
15431
  }
14870
15432
 
14871
15433
  // src/commands/redmine/sync-issue.ts
14872
- import { Command as Command82 } from "commander";
15434
+ import { Command as Command92 } from "commander";
14873
15435
 
14874
15436
  // src/sync-issue.ts
14875
15437
  import { resolve as resolve3, relative } from "path";
@@ -15253,7 +15815,7 @@ function extractIssueIdFromUrl(url) {
15253
15815
 
15254
15816
  // src/commands/redmine/sync-issue.ts
15255
15817
  function createSyncIssueCommand() {
15256
- const cmd = new Command82("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) => {
15818
+ 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) => {
15257
15819
  await handleSyncIssue(options);
15258
15820
  });
15259
15821
  return cmd;
@@ -15297,7 +15859,7 @@ async function handleSyncIssue(options) {
15297
15859
  }
15298
15860
 
15299
15861
  // src/commands/redmine/sync-project.ts
15300
- import { Command as Command83 } from "commander";
15862
+ import { Command as Command93 } from "commander";
15301
15863
 
15302
15864
  // src/sync-project.ts
15303
15865
  async function syncProject(config, options = {}) {
@@ -15367,7 +15929,7 @@ async function syncProject(config, options = {}) {
15367
15929
 
15368
15930
  // src/commands/redmine/sync-project.ts
15369
15931
  function createSyncProjectCommand() {
15370
- const cmd = new Command83("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) => {
15932
+ 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) => {
15371
15933
  await handleSyncProject(options);
15372
15934
  });
15373
15935
  return cmd;
@@ -15422,12 +15984,12 @@ async function handleSyncProject(options) {
15422
15984
  }
15423
15985
 
15424
15986
  // src/commands/framework/info.ts
15425
- import { Command as Command84 } from "commander";
15987
+ import { Command as Command94 } from "commander";
15426
15988
  import { promises as fs28 } from "fs";
15427
15989
  import { join as join22 } from "path";
15428
15990
  import { homedir as homedir5 } from "os";
15429
15991
  function createInfoCommand() {
15430
- const cmd = new Command84("info").description("Show client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
15992
+ const cmd = new Command94("info").description("Show client configuration and status").option("--json", "Output as JSON").option("--verbose", "Show detailed information").action(async (options) => {
15431
15993
  await handleInfo(options);
15432
15994
  });
15433
15995
  return cmd;
@@ -15483,8 +16045,8 @@ async function getProjectStatus2() {
15483
16045
  }
15484
16046
 
15485
16047
  // src/commands/self-update.ts
15486
- import { Command as Command85 } from "commander";
15487
- import { confirm as confirm20 } from "@inquirer/prompts";
16048
+ import { Command as Command95 } from "commander";
16049
+ import { confirm as confirm22 } from "@inquirer/prompts";
15488
16050
  import { execSync as execSync6 } from "child_process";
15489
16051
  var colors3 = {
15490
16052
  yellow: "\x1B[33m",
@@ -15495,7 +16057,7 @@ var colors3 = {
15495
16057
  bold: "\x1B[1m"
15496
16058
  };
15497
16059
  function createSelfUpdateCommand() {
15498
- return new Command85("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) => {
16060
+ 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) => {
15499
16061
  await handleSelfUpdate(options);
15500
16062
  });
15501
16063
  }
@@ -15539,7 +16101,7 @@ ${colors3.bold}Current version:${colors3.reset} ${currentVersion}`);
15539
16101
  return;
15540
16102
  }
15541
16103
  if (!options.force) {
15542
- const shouldUpdate = await confirm20({
16104
+ const shouldUpdate = await confirm22({
15543
16105
  message: "Update to the latest version now?",
15544
16106
  default: true
15545
16107
  });
@@ -15635,10 +16197,10 @@ function getInstallCommand2(packageManager2) {
15635
16197
  }
15636
16198
 
15637
16199
  // src/commands/clear-backups.ts
15638
- import { Command as Command86 } from "commander";
15639
- import { confirm as confirm21 } from "@inquirer/prompts";
16200
+ import { Command as Command96 } from "commander";
16201
+ import { confirm as confirm23 } from "@inquirer/prompts";
15640
16202
  function createClearBackupsCommand() {
15641
- return new Command86("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
16203
+ return new Command96("clear-backups").description("Clear backup files").option("-y, --yes", "Skip confirmation").action(async (options) => {
15642
16204
  const service = new ComponentsService();
15643
16205
  const backups = await service.listBackups(process.cwd());
15644
16206
  if (backups.length === 0) {
@@ -15654,7 +16216,7 @@ function createClearBackupsCommand() {
15654
16216
  }
15655
16217
  console.log();
15656
16218
  if (!options.yes) {
15657
- const ok = await confirm21({ message: "Delete all backups?", default: false });
16219
+ const ok = await confirm23({ message: "Delete all backups?", default: false });
15658
16220
  if (!ok) return;
15659
16221
  }
15660
16222
  await service.clearBackups(process.cwd());
@@ -15663,8 +16225,8 @@ function createClearBackupsCommand() {
15663
16225
  }
15664
16226
 
15665
16227
  // src/commands/vscode/index.ts
15666
- import { Command as Command87 } from "commander";
15667
- import { checkbox as checkbox9, confirm as confirm22, select as select7 } from "@inquirer/prompts";
16228
+ import { Command as Command97 } from "commander";
16229
+ import { checkbox as checkbox9, confirm as confirm24, select as select7 } from "@inquirer/prompts";
15668
16230
  import fs29 from "fs/promises";
15669
16231
  import path12 from "path";
15670
16232
  import { existsSync as existsSync4 } from "fs";
@@ -15803,7 +16365,7 @@ var PERFORMANCE_GROUPS2 = {
15803
16365
  }
15804
16366
  };
15805
16367
  function createVSCodeCommand() {
15806
- const vscodeCommand = new Command87("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
16368
+ const vscodeCommand = new Command97("vscode").description("Qu\u1EA3n l\xFD c\xE0i \u0111\u1EB7t VSCode cho d\u1EF1 \xE1n hi\u1EC7n t\u1EA1i");
15807
16369
  vscodeCommand.action(async () => {
15808
16370
  await interactiveMode2();
15809
16371
  });
@@ -15909,7 +16471,7 @@ async function applyGroups2(groupKeys, action) {
15909
16471
  console.log("\u{1F4C4} \u0110\xE3 \u0111\u1ECDc c\xE0i \u0111\u1EB7t hi\u1EC7n t\u1EA1i t\u1EEB settings.json");
15910
16472
  } catch {
15911
16473
  console.warn("\u26A0\uFE0F Kh\xF4ng th\u1EC3 \u0111\u1ECDc settings.json (c\xF3 th\u1EC3 ch\u1EE9a comments).");
15912
- const confirmOverwrite = await confirm22({
16474
+ const confirmOverwrite = await confirm24({
15913
16475
  message: "Ghi \u0111\xE8 file settings.json hi\u1EC7n t\u1EA1i?",
15914
16476
  default: false
15915
16477
  });
@@ -15956,7 +16518,7 @@ async function resetSettings2(groupKeys) {
15956
16518
  console.log("\n\u26A0\uFE0F Kh\xF4ng t\xECm th\u1EA5y file settings.json");
15957
16519
  return;
15958
16520
  }
15959
- const confirmReset = await confirm22({
16521
+ const confirmReset = await confirm24({
15960
16522
  message: groupKeys.length === 0 ? "Reset T\u1EA4T C\u1EA2 settings v\u1EC1 m\u1EB7c \u0111\u1ECBnh (x\xF3a to\xE0n b\u1ED9 file)?" : `Reset c\xE1c nh\xF3m: ${groupKeys.join(", ")}?`,
15961
16523
  default: false
15962
16524
  });
@@ -15974,10 +16536,10 @@ async function resetSettings2(groupKeys) {
15974
16536
  }
15975
16537
 
15976
16538
  // src/commands/migrate-ide.ts
15977
- import { Command as Command88 } from "commander";
15978
- import { checkbox as checkbox10, confirm as confirm23 } from "@inquirer/prompts";
16539
+ import { Command as Command98 } from "commander";
16540
+ import { checkbox as checkbox10, confirm as confirm25 } from "@inquirer/prompts";
15979
16541
  function createMigrateIdeCommand() {
15980
- const cmd = new Command88("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) => {
16542
+ 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) => {
15981
16543
  await runMigrateIde(options);
15982
16544
  });
15983
16545
  return cmd;
@@ -16048,7 +16610,7 @@ async function runMigrateIde(options) {
16048
16610
  if (options.dryRun) {
16049
16611
  console.log("\u{1F50D} DRY RUN - No files will be written\n");
16050
16612
  }
16051
- const confirmed = await confirm23({
16613
+ const confirmed = await confirm25({
16052
16614
  message: "Proceed with migration?",
16053
16615
  default: true
16054
16616
  });
@@ -16086,20 +16648,20 @@ async function runMigrateIde(options) {
16086
16648
 
16087
16649
  // src/utils/help-formatter.ts
16088
16650
  import boxen4 from "boxen";
16089
- import chalk44 from "chalk";
16651
+ import chalk54 from "chalk";
16090
16652
  import gradient from "gradient-string";
16091
16653
  import figlet from "figlet";
16092
16654
  function showCustomHelp(version) {
16093
16655
  const title = figlet.textSync("JAI1", { font: "Small" });
16094
16656
  console.log(gradient.pastel(title));
16095
16657
  console.log(
16096
- boxen4(chalk44.cyan(`Agentic Coding CLI v${version}`), {
16658
+ boxen4(chalk54.cyan(`Agentic Coding CLI v${version}`), {
16097
16659
  padding: { left: 1, right: 1, top: 0, bottom: 0 },
16098
16660
  borderStyle: "round",
16099
16661
  borderColor: "cyan"
16100
16662
  })
16101
16663
  );
16102
- console.log(chalk44.bold("\n\u{1F527} Thi\u1EBFt l\u1EADp & Th\xF4ng tin"));
16664
+ console.log(chalk54.bold("\n\u{1F527} Thi\u1EBFt l\u1EADp & Th\xF4ng tin"));
16103
16665
  console.log(" auth X\xE1c th\u1EF1c v\xE0 c\u1EA5u h\xECnh client");
16104
16666
  console.log(" status Hi\u1EC3n th\u1ECB tr\u1EA1ng th\xE1i c\u1EA5u h\xECnh");
16105
16667
  console.log(" client-info T\u1EA1o th\xF4ng tin client \u0111\u1EC3 g\u1EEDi \u0111\u1ED9i ph\xE1t tri\u1EC3n");
@@ -16107,43 +16669,43 @@ function showCustomHelp(version) {
16107
16669
  console.log(" guide H\u01B0\u1EDBng d\u1EABn s\u1EED d\u1EE5ng nhanh");
16108
16670
  console.log(" quickstart B\u1EAFt \u0111\u1EA7u t\u1EEB \u0111\xE2u? (theo t\xECnh hu\u1ED1ng)");
16109
16671
  console.log(" doctor Chu\u1EA9n \u0111o\xE1n project hi\u1EC7n t\u1EA1i");
16110
- console.log(chalk44.bold("\n\u{1F4E6} Qu\u1EA3n l\xFD Components"));
16672
+ console.log(chalk54.bold("\n\u{1F4E6} Qu\u1EA3n l\xFD Components"));
16111
16673
  console.log(" apply C\xE0i \u0111\u1EB7t components (interactive)");
16112
16674
  console.log(" update C\u1EADp nh\u1EADt components \u0111\xE3 c\xE0i");
16113
16675
  console.log(" check Ki\u1EC3m tra c\u1EADp nh\u1EADt t\u1EEB server");
16114
- console.log(chalk44.bold("\n\u{1F5A5}\uFE0F IDE & T\xEDch h\u1EE3p"));
16676
+ console.log(chalk54.bold("\n\u{1F5A5}\uFE0F IDE & T\xEDch h\u1EE3p"));
16115
16677
  console.log(" ide L\u1EC7nh c\u1EA5u h\xECnh IDE");
16116
16678
  console.log(" chat Chat AI v\u1EDBi Jai1 LLM Proxy");
16117
16679
  console.log(" openai-keys Th\xF4ng tin API credentials");
16118
- console.log(chalk44.bold("\n\u{1F916} AI Tools"));
16680
+ console.log(chalk54.bold("\n\u{1F916} AI Tools"));
16119
16681
  console.log(" translate D\u1ECBch v\u0103n b\u1EA3n/file b\u1EB1ng AI");
16120
16682
  console.log(" image T\u1EA1o \u1EA3nh (Coming Soon)");
16121
16683
  console.log(" stats Th\u1ED1ng k\xEA s\u1EED d\u1EE5ng LLM");
16122
16684
  console.log(" feedback G\u1EEDi b\xE1o c\xE1o/\u0111\u1EC1 xu\u1EA5t");
16123
- console.log(chalk44.bold("\n\u{1F4C1} Project"));
16685
+ console.log(chalk54.bold("\n\u{1F4C1} Project"));
16124
16686
  console.log(" kit Qu\u1EA3n l\xFD starter kits");
16125
16687
  console.log(" tasks (t) Qu\u1EA3n l\xFD tasks ph\xE1t tri\u1EC3n");
16126
16688
  console.log(" rules Qu\u1EA3n l\xFD rule presets");
16127
16689
  console.log(" deps Qu\u1EA3n l\xFD dependencies");
16128
16690
  console.log(" redmine Redmine context sync");
16129
- console.log(chalk44.bold("\n\u2699\uFE0F B\u1EA3o tr\xEC"));
16691
+ console.log(chalk54.bold("\n\u2699\uFE0F B\u1EA3o tr\xEC"));
16130
16692
  console.log(" upgrade C\u1EADp nh\u1EADt CLI client");
16131
16693
  console.log(" clean D\u1ECDn d\u1EB9p cache/backup");
16132
16694
  console.log(" utils Developer utilities");
16133
16695
  const name = getCliName();
16134
- console.log(chalk44.dim(`
16696
+ console.log(chalk54.dim(`
16135
16697
  S\u1EED d\u1EE5ng: ${name} [l\u1EC7nh] --help \u0111\u1EC3 xem chi ti\u1EBFt`));
16136
16698
  }
16137
16699
  function showUnknownCommand(commandName) {
16138
- console.error(chalk44.red(`\u274C L\u1EC7nh kh\xF4ng t\u1ED3n t\u1EA1i: ${commandName}`));
16700
+ console.error(chalk54.red(`\u274C L\u1EC7nh kh\xF4ng t\u1ED3n t\u1EA1i: ${commandName}`));
16139
16701
  const name = getCliName();
16140
- console.error(chalk44.dim(`
16702
+ console.error(chalk54.dim(`
16141
16703
  G\u1EE3i \xFD: Ch\u1EA1y ${name} --help \u0111\u1EC3 xem danh s\xE1ch l\u1EC7nh`));
16142
16704
  }
16143
16705
 
16144
16706
  // src/cli.ts
16145
16707
  checkNodeVersion();
16146
- var program = new Command89();
16708
+ var program = new Command99();
16147
16709
  if (process.argv.includes("-v") || process.argv.includes("--version")) {
16148
16710
  console.log(package_default.version);
16149
16711
  if (!process.argv.includes("--skip-update-check")) {
@@ -16178,6 +16740,7 @@ program.addCommand(createClientInfoCommand());
16178
16740
  program.addCommand(createErrorsCommand());
16179
16741
  program.addCommand(createUtilsCommand());
16180
16742
  program.addCommand(createDepsCommand());
16743
+ program.addCommand(createDevCommand());
16181
16744
  program.addCommand(createTasksCommand());
16182
16745
  program.addCommand(createKitCommand());
16183
16746
  program.addCommand(createRulesCommand());
@@ -16185,9 +16748,9 @@ program.addCommand(createSkillsCommand());
16185
16748
  program.addCommand(createHooksCommand());
16186
16749
  program.addCommand(createUpgradeCommand());
16187
16750
  program.addCommand(createCleanCommand());
16188
- var redmineCommand = new Command89("redmine").description("Redmine context sync commands");
16751
+ var redmineCommand = new Command99("redmine").description("Redmine context sync commands");
16189
16752
  redmineCommand.addCommand(createRedmineCheckCommand());
16190
- var syncCommand = new Command89("sync").description("Sync Redmine issues to markdown files");
16753
+ var syncCommand = new Command99("sync").description("Sync Redmine issues to markdown files");
16191
16754
  syncCommand.addCommand(createSyncIssueCommand());
16192
16755
  syncCommand.addCommand(createSyncProjectCommand());
16193
16756
  redmineCommand.addCommand(syncCommand);