@noobdemon/noob-cli 1.10.19 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/i18n.js CHANGED
@@ -1,219 +1,242 @@
1
1
  // Vietnamese UI strings for noob CLI. Single language (tiếng Việt).
2
2
  export const t = {
3
- tagline: "trợ lý lập trình trong terminal · sức mạnh từ Noob Demon",
4
- ready: "Nhập yêu cầu của bạn, hoặc gõ /help để xem lệnh.",
5
- promptYou: "bạn ",
6
- thinking: "đang suy nghĩ",
7
- searching: "đang tìm trên web",
8
- merging: "đang tổng hợp đa mô hình",
9
- bye: "tạm biệt 👋",
10
- interrupted: "đã ngắt",
11
- pressAgainToExit: "nhấn Ctrl+C lần nữa để thoát",
12
- running: "đang chạy…",
13
- denied: "đã từ chối",
3
+ tagline: 'trợ lý lập trình trong terminal · sức mạnh từ Noob Demon',
4
+ ready: 'Nhập yêu cầu của bạn, hoặc gõ /help để xem lệnh.',
5
+ promptYou: 'bạn ',
6
+ thinking: 'đang suy nghĩ',
7
+ searching: 'đang tìm trên web',
8
+ merging: 'đang tổng hợp đa mô hình',
9
+ bye: 'tạm biệt 👋',
10
+ interrupted: 'đã ngắt',
11
+ pressAgainToExit: 'nhấn Ctrl+C lần nữa để thoát',
12
+ running: 'đang chạy…',
13
+ denied: 'đã từ chối',
14
14
  queued: (n, txt) => `⏎ đã xếp hàng [${n}] · gửi khi model xong: ${txt}`,
15
15
  queueCleared: (n) => `(đã xoá ${n} tin đang xếp hàng)`,
16
- steerHint: "💬 Gõ + Enter bất cứ lúc nào để chèn ý cho AI giữa chừng (không ngắt task đang chạy).",
16
+ steerHint:
17
+ '💬 Gõ + Enter bất cứ lúc nào để chèn ý cho AI giữa chừng (không ngắt task đang chạy).',
17
18
  steerWillInject: (txt) => `💬 sẽ chèn cho AI ở bước tới: ${txt}`,
18
19
  steerInject: (txt) => `💬 đã chèn cho AI: ${txt}`,
19
- permRetry: "→ gõ y (đồng ý) · n (từ chối) · a (luôn cho phép)",
20
+ permRetry: '→ gõ y (đồng ý) · n (từ chối) · a (luôn cho phép)',
20
21
 
21
22
  // auth
22
23
  notLoggedIn:
23
- "Bạn chưa đăng nhập. Chạy: noob login <api-key>\nChưa có key? Liên hệ admin để lấy key (Pro / Pro+ / Trial).",
24
+ 'Bạn chưa đăng nhập. Chạy: noob login <api-key>\nChưa có key? Liên hệ admin để lấy key (Pro / Pro+ / Trial).',
24
25
  loginOk: (plan) => `Đăng nhập thành công. Gói: ${plan}.`,
25
26
  loginSaved: (p) => `Đã lưu API key vào ${p}`,
26
- loggedOut: "Đã đăng xuất, xoá API key khỏi máy.",
27
- needKeyArg: "Thiếu key. Dùng: noob login <api-key>",
27
+ loggedOut: 'Đã đăng xuất, xoá API key khỏi máy.',
28
+ needKeyArg: 'Thiếu key. Dùng: noob login <api-key>',
28
29
 
29
30
  // usage
30
- usageTitle: "Hạn mức API key",
31
- plan: "Gói",
32
- status: "Trạng thái",
33
- remaining: "Còn lại",
34
- used: "Đã dùng",
35
- unlimited: "không giới hạn",
36
- resetAt: "Đặt lại lúc",
31
+ usageTitle: 'Hạn mức API key',
32
+ plan: 'Gói',
33
+ status: 'Trạng thái',
34
+ remaining: 'Còn lại',
35
+ used: 'Đã dùng',
36
+ unlimited: 'không giới hạn',
37
+ resetAt: 'Đặt lại lúc',
37
38
  trialLeft: (n) => `${n} lượt dùng thử còn lại`,
38
39
  windowInfo: (used, limit) => `${used}/${limit} trong cửa sổ 5 giờ`,
39
40
 
40
41
  // errors (gateway codes → VN)
41
- errMissingKey: "Thiếu API key. Chạy: noob login <key>",
42
- errInvalidKey: "API key không hợp lệ.",
43
- errKeyDead: "API key đã bị vô hiệu hoá (dead).",
44
- errTrialExhausted: "Key dùng thử đã hết 200 lượt — key đã dead. Liên hệ admin để nâng cấp.",
45
- errDisabled: "API key đã bị khoá.",
42
+ errMissingKey: 'Thiếu API key. Chạy: noob login <key>',
43
+ errInvalidKey: 'API key không hợp lệ.',
44
+ errKeyDead: 'API key đã bị vô hiệu hoá (dead).',
45
+ errTrialExhausted: 'Key dùng thử đã hết 200 lượt — key đã dead. Liên hệ admin để nâng cấp.',
46
+ errDisabled: 'API key đã bị khoá.',
46
47
  errRateLimited: (reset) =>
47
- `Đã hết hạn mức trong cửa sổ 5 giờ.${reset ? " Đặt lại lúc " + reset + "." : " Thử lại sau."}`,
48
- errConn: "Lỗi kết nối tới máy chủ.",
48
+ `Đã hết hạn mức trong cửa sổ 5 giờ.${reset ? ' Đặt lại lúc ' + reset + '.' : ' Thử lại sau.'}`,
49
+ errConn: 'Lỗi kết nối tới máy chủ.',
49
50
 
50
51
  // help
51
- helpTitle: "noob · trợ giúp",
52
- helpCommands: "Lệnh",
53
- helpTips: "Mẹo",
54
- cmdModel: "/model [tên] đổi mô hình, hoặc liệt kê tất cả",
55
- cmdModels: "/models liệt kê mọi mô hình",
56
- cmdMerge: "/merge bật/tắt Merge AI (tổng hợp đa mô hình)",
57
- cmdSearch: "/search bật/tắt chế độ tìm web",
58
- cmdChat: "/chat quay lại chế độ chat thường",
59
- cmdYolo: "/yolo bật/tắt tự duyệt (hoặc nhấn Shift+Tab)",
60
- cmdAgent: "/agent on|off bật/tắt agent mode (model đẻ sub-agent song song/tuần tự/phân cấp)",
61
- cmdTokens: "/tokens xem số token đã dùng trong phiên",
62
- cmdAutoYolo: "/auto-yolo lưu/bỏ yolo làm mặc định mỗi lần chạy (cần xác nhận)",
63
- cmdInit: "/init quét dự án & tạo noob.md (tổng quan + quy ước, như Claude Code)",
64
- cmdKarpathy: "/karpathy [path] rà soát code theo 4 nguyên tắc Karpathy (/kc)",
65
- cmdFrontendDesign: "/frontend-design <yêu cầu> thiết kế UI frontend chất lượng cao theo skill (/fd)",
66
- cmdImprove: "/improve [hint] phân tích workspace & đề xuất tính năng cải thiện (/imp)",
67
- cmdUltra: "/ultra <mục tiêu> tự hành: noob tự nghĩ & tự làm nhiệm vụ tới khi xong (/u)",
68
- cmdWorkflow: "/workflow <yêu cầu>|help|patterns|builtins|list|save|load|run|delete|rm dynamic workflow đa sub-agent (/wf, /ultracode)",
69
- cmdGoal: "/goal <text>|clear đặt HARD GOAL cho phiên (chống goal drift; không arg = xem)",
70
- cmdLoop: "/loop <interval> <task> chạy task lặp lại (vd /loop 10m triage); /loop stop để dừng",
71
- cmdLearn: "/learn [ghi chú] chưng cất bài học của phiên vào noob.md",
72
- cmdCompact: "/compact tóm tắt phiên ngay để gọn ngữ cảnh (giữ trí nhớ dài hạn)",
73
- cmdMemory: "/memory xem bộ nhớ noob.md (/mem)",
74
- cmdAddDir: "/add-dir <path> thêm thư mục ngoài cwd vào phạm vi tool (lưu theo workspace, không arg = liệt kê)",
75
- cmdClear: "/clear /new xoá ngữ cảnh (mở phiên mới, phiên cũ vẫn resume được)",
76
- cmdResume: "/resume [id] tiếp tục phiên cũ (không id = chọn từ danh sách)",
77
- cmdSessions: "/sessions liệt các phiên đã lưu",
78
- cmdLogin: "/login <key> đăng nhập bằng API key",
79
- cmdLogout: "/logout đăng xuất",
80
- cmdUsage: "/usage xem hạn mức key còn lại",
81
- cmdStatus: "/status xem hình, version, trạng thái yolo, thư mục",
82
- cmdVersion: "/version /v xem version hiện tại + trạng thái yolo",
83
- cmdExit: "/exit /quit thoát",
84
- tip1: "• tả việc cần làm; noob sẽ đọc/sửa file & chạy lệnh giúp bạn.",
85
- tip2: "• Đang chạy vẫn tiếp được tin sẽ xếp hàng & tự gửi khi model xong.",
86
- tip3: "• Shift+Tab: bật/tắt yolo nhanh. Ctrl+C 1 lần = dừng lượt, 2 lần = thoát.",
87
- tip4: " @ để gắn file (chỉ chỗ cho AI đọc). ←/→ Home/End sửa giữa dòng; ↑/↓ gọi lại lệnh cũ.",
52
+ helpTitle: 'noob · trợ giúp',
53
+ helpCommands: 'Lệnh',
54
+ helpTips: 'Mẹo',
55
+ cmdModel: '/model [tên] đổi mô hình, hoặc liệt kê tất cả',
56
+ cmdModels: '/models liệt kê mọi mô hình',
57
+ cmdMerge: '/merge bật/tắt Merge AI (tổng hợp đa mô hình)',
58
+ cmdSearch: '/search bật/tắt chế độ tìm web',
59
+ cmdChat: '/chat quay lại chế độ chat thường',
60
+ cmdYolo: '/yolo bật/tắt tự duyệt (hoặc nhấn Shift+Tab)',
61
+ cmdAgent: '/agent on|off bật/tắt agent mode (model đẻ sub-agent song song/tuần tự/phân cấp)',
62
+ cmdTokens: '/tokens xem số token đã dùng trong phiên',
63
+ cmdAutoYolo: '/auto-yolo lưu/bỏ yolo làm mặc định mỗi lần chạy (cần xác nhận)',
64
+ cmdInit: '/init quét dự án & tạo noob.md (tổng quan + quy ước, như Claude Code)',
65
+ cmdKarpathy: '/karpathy [path] rà soát code theo 4 nguyên tắc Karpathy (/kc)',
66
+ cmdFrontendDesign:
67
+ '/frontend-design <yêu cầu> thiết kế UI frontend chất lượng cao theo skill (/fd)',
68
+ cmdImprove: '/improve [hint] phân tích workspace & đề xuất tính năng cải thiện (/imp)',
69
+ cmdUltra: '/ultra <mục tiêu> tự hành: noob tự nghĩ & tự làm nhiệm vụ tới khi xong (/u)',
70
+ cmdWorkflow:
71
+ '/workflow <yêu cầu>|help|patterns|builtins|list|save|load|run|delete|rm dynamic workflow đa sub-agent (/wf, /ultracode)',
72
+ cmdGoal: '/goal <text>|clear đặt HARD GOAL cho phiên (chống goal drift; không arg = xem)',
73
+ cmdLoop: '/loop <interval> <task> chạy task lặp lại (vd /loop 10m triage); /loop stop để dừng',
74
+ cmdLearn: '/learn [ghi chú] chưng cất bài học của phiên vào noob.md',
75
+ cmdCompact: '/compact tóm tắt phiên ngay để gọn ngữ cảnh (giữ trí nhớ dài hạn)',
76
+ cmdMemory: '/memory xem bộ nhớ noob.md (/mem)',
77
+ cmdAddDir:
78
+ '/add-dir <path> thêm thư mục ngoài cwd vào phạm vi tool (lưu theo workspace, không arg = liệt kê)',
79
+ cmdClear: '/clear /new xoá ngữ cảnh (mở phiên mới, phiên cũ vẫn resume được)',
80
+ cmdResume: '/resume [id] tiếp tục phiên cũ (không id = chọn từ danh sách)',
81
+ cmdSessions: '/sessions liệt các phiên đã lưu',
82
+ cmdLogin: '/login <key> đăng nhập bằng API key',
83
+ cmdLogout: '/logout đăng xuất',
84
+ cmdUsage: '/usage xem hạn mức key còn lại',
85
+ cmdStatus: '/status xem hình, version, trạng thái yolo, thư mục',
86
+ cmdVersion: '/version /v xem version hiện tại + trạng thái yolo',
87
+ cmdExit: '/exit /quit thoát',
88
+ tip1: ' tả việc cần làm; noob sẽ đọc/sửa file & chạy lệnh giúp bạn.',
89
+ tip2: '• Đang chạy vẫn gõ tiếp được — tin sẽ xếp hàng & tự gửi khi model xong.',
90
+ tip3: '• Shift+Tab: bật/tắt yolo nhanh. Ctrl+C 1 lần = dừng lượt, 2 lần = thoát.',
91
+ tip4: '• Gõ @ để gắn file (chỉ chỗ cho AI đọc). ←/→ Home/End sửa giữa dòng; ↑/↓ gọi lại lệnh cũ.',
88
92
 
89
93
  // misc
90
- yoloOn: "⚠ yolo BẬT — tự động duyệt mọi thao tác sửa file & chạy lệnh",
91
- yoloOff: "✓ yolo TẮT — sẽ hỏi trước khi sửa file & chạy lệnh",
94
+ yoloOn: '⚠ yolo BẬT — tự động duyệt mọi thao tác sửa file & chạy lệnh',
95
+ yoloOff: '✓ yolo TẮT — sẽ hỏi trước khi sửa file & chạy lệnh',
92
96
 
93
97
  // add-dir: auto-prompt khi model tag folder ngoài workspace
94
98
  outOfScopeAdded: (root) => `✓ đã thêm ${root} vào phạm vi (lưu .noob/dirs.json).`,
95
- outOfScopeRejected: (root) => `đã từ chối — ${root} không nằm trong phạm vi. Model có thể dùng /add-dir để thêm sau.`,
96
- addDirRemoveNeedArg: "Thiếu path. Dùng: /add-dir remove <đường-dẫn>",
99
+ outOfScopeRejected: (root) =>
100
+ `đã từ chối — ${root} không nằm trong phạm vi. Model có thể dùng /add-dir để thêm sau.`,
101
+ addDirRemoveNeedArg: 'Thiếu path. Dùng: /add-dir remove <đường-dẫn>',
97
102
  addDirNotInScope: (p) => `${p} không có trong phạm vi (chỉ cwd + các folder đã /add-dir).`,
98
- autoYoloWarn: "⚠ yolo tự duyệt MỌI thao tác (sửa file/chạy lệnh) KHÔNG hỏi. Lưu làm mặc định = mỗi lần mở noob đều bật sẵn yolo.",
103
+ autoYoloWarn:
104
+ '⚠ yolo tự duyệt MỌI thao tác (sửa file/chạy lệnh) KHÔNG hỏi. Lưu làm mặc định = mỗi lần mở noob đều bật sẵn yolo.',
99
105
  autoYoloConfirm: "Chắc chắn lưu yolo làm mặc định? gõ 'y' để xác nhận, phím khác để huỷ › ",
100
- autoYoloOn: "⚡ Đã LƯU yolo làm mặc định — mọi phiên sau tự bật. Gõ /auto-yolo lần nữa để tắt.",
101
- autoYoloOff: "✓ Đã bỏ yolo mặc định — phiên sau sẽ KHÔNG tự bật yolo (phiên này giữ nguyên).",
102
- autoYoloCancel: "Huỷ — không thay đổi gì.",
103
- mergeOn: "Merge AI: BẬT",
104
- mergeOff: "Merge AI: TẮT",
105
- searchOn: "Tìm web: BẬT",
106
- searchOff: "Tìm web: TẮT",
107
- backToChat: "quay lại chế độ chat",
108
- ctxCleared: "đã xoá ngữ cảnh",
106
+ autoYoloOn: '⚡ Đã LƯU yolo làm mặc định — mọi phiên sau tự bật. Gõ /auto-yolo lần nữa để tắt.',
107
+ autoYoloOff: '✓ Đã bỏ yolo mặc định — phiên sau sẽ KHÔNG tự bật yolo (phiên này giữ nguyên).',
108
+ autoYoloCancel: 'Huỷ — không thay đổi gì.',
109
+ mergeOn: 'Merge AI: BẬT',
110
+ mergeOff: 'Merge AI: TẮT',
111
+ searchOn: 'Tìm web: BẬT',
112
+ searchOff: 'Tìm web: TẮT',
113
+ backToChat: 'quay lại chế độ chat',
114
+ ctxCleared: 'đã xoá ngữ cảnh',
109
115
  unknownCmd: (c) => `không rõ lệnh: /${c}`,
110
- tryHelp: "(gõ /help)",
116
+ tryHelp: '(gõ /help)',
111
117
  noModelMatch: (q) => `không có mô hình khớp "${q}"`,
112
- modelListHint: "/model <tên> để chuyển",
113
- switchTo: "→ đã chuyển",
118
+ modelListHint: '/model <tên> để chuyển',
119
+ switchTo: '→ đã chuyển',
114
120
  providerRefuses: (p) =>
115
121
  `lưu ý: mô hình ${p} trên gateway này hay từ chối giao thức tool; nên dùng Anthropic/DeepSeek cho tác vụ sửa code.`,
116
- maxSteps: "_(đã dừng: chạm giới hạn số bước tool)_",
117
- toolDenied: "Người dùng từ chối thao tác này. Hãy đổi cách làm hoặc hỏi lại.",
122
+ maxSteps: '_(đã dừng: chạm giới hạn số bước tool)_',
123
+ toolDenied: 'Người dùng từ chối thao tác này. Hãy đổi cách làm hoặc hỏi lại.',
118
124
 
119
125
  // ultra (tự hành / self-quest) + bộ nhớ noob.md
120
- ultraOn: "Ultra: BẬT — noob tự lập kế hoạch & tự làm tới khi xong (Ctrl+C để dừng).",
121
- ultraDone: "Ultra: đã hoàn thành mục tiêu.",
122
- ultraStopped: "Ultra: đã dừng.",
123
- ultraMax: "Ultra: chạm giới hạn số vòng — dừng để bạn kiểm tra & ra lệnh tiếp.",
124
- ultraNeedGoal: "Cần mục tiêu. Dùng: /ultra <mô tả mục tiêu>",
126
+ ultraOn: 'Ultra: BẬT — noob tự lập kế hoạch & tự làm tới khi xong (Ctrl+C để dừng).',
127
+ ultraDone: 'Ultra: đã hoàn thành mục tiêu.',
128
+ ultraStopped: 'Ultra: đã dừng.',
129
+ ultraMax: 'Ultra: chạm giới hạn số vòng — dừng để bạn kiểm tra & ra lệnh tiếp.',
130
+ ultraNeedGoal: 'Cần mục tiêu. Dùng: /ultra <mô tả mục tiêu>',
125
131
  ultraQuest: (n) => `tự nghĩ nhiệm vụ kế tiếp (vòng ${n})…`,
126
- loopNeedArgs: "Cần task. Dùng: /loop <interval> <task> (vd: /loop 5m kiểm tra log lỗi mới) · /loop stop để dừng · /loop để xem trạng thái",
132
+ loopNeedArgs:
133
+ 'Cần task. Dùng: /loop <interval> <task> (vd: /loop 5m kiểm tra log lỗi mới) · /loop stop để dừng · /loop để xem trạng thái',
127
134
  loopBadInterval: (s) => `interval không hợp lệ: "${s}". Dùng dạng 30s / 5m / 1h / 2h30m.`,
128
- loopStarted: (interval, task) => `🔁 Loop BẬT — chạy mỗi ${interval} (không giới hạn token): ${task}`,
135
+ loopStarted: (interval, task) =>
136
+ `🔁 Loop BẬT — chạy mỗi ${interval} (không giới hạn token): ${task}`,
129
137
  // [GỠ BUDGET 2026-06-06] loopBadBudget + loopBudgetExceeded giữ lại để tương thích ngược nếu có code cũ gọi, không dùng nữa.
130
138
  loopBadBudget: (s) => `(deprecated) ngân sách không còn được hỗ trợ: "${s}".`,
131
139
  loopBudgetExceeded: (used, budget, ticks) => `(deprecated) loop không còn cap token.`,
132
- loopStopped: "🔁 Loop đã dừng.",
133
- loopNotRunning: "Không có loop nào đang chạy.",
134
- loopStatus: (interval, task, ticks, nextIn) => `🔁 Loop: chạy mỗi ${interval} · đã ${ticks} lần · lần kế trong ~${nextIn}\n task: ${task}`,
140
+ loopStopped: '🔁 Loop đã dừng.',
141
+ loopNotRunning: 'Không có loop nào đang chạy.',
142
+ loopStatus: (interval, task, ticks, nextIn) =>
143
+ `🔁 Loop: chạy mỗi ${interval} · đã ${ticks} lần · lần kế trong ~${nextIn}\n task: ${task}`,
135
144
  loopTick: (n) => `🔁 loop tick #${n}…`,
136
145
  loopAutoStop: (n) => `Loop tự dừng sau tick #${n} — model phát <<LOOP_DONE>> (task hoàn tất).`,
137
- loopAlreadyRunning: "Đã có loop đang chạy. /loop stop trước khi đặt loop mới.",
138
- learning: "đang chưng cất bài học vào noob.md…",
139
- learnSuggest: (n) => `💡 Phiên này có ${n} lượt. Gõ /learn trước để chưng cất bài học vào noob.md (sau khi /new thì history sẽ mất).`,
140
- memoryStatus: (lines, rules, notes, ago) => `📝 noob.md: ${lines} dòng (${rules} rules, ${notes} notes) · cập nhật ${ago}`,
141
- memoryMissing: "📝 noob.md: chưa — gõ /init để tạo từ dự án.",
142
- compactRunning: "đang tóm tắt phiên để gọn ngữ cảnh…",
143
- compactEmpty: "Phiên còn trốngkhông để tóm tắt.",
144
- compactSkipped: "Phiên còn ngắn hoặc tóm tắt thất bại bỏ qua.",
145
- compactDone: (bMsgs, aMsgs, bK, aK, pct) => `Đã tóm tắt: ${bMsgs} → ${aMsgs} tin · ${bK}k → ${aK}k chars (giảm ${pct}%).`,
146
- longSession: (k) => `Phiên dài (${k}k chars). Cân nhắc /compact để gọn ngữ cảnh (giữ trí nhớ) hoặc /clear để phiên mới hoàn toàn.`,
147
- veryLongSession: (k) => `⚠ Phiên RẤT dài (${k}k chars) — model có thể chậm/lú. Khuyến nghị /compact ngay, hoặc /clear nếu task đã xong.`,
146
+ loopAlreadyRunning: 'Đã có loop đang chạy. /loop stop trước khi đặt loop mới.',
147
+ learning: 'đang chưng cất bài học vào noob.md…',
148
+ learnSuggest: (n) =>
149
+ `💡 Phiên này ${n} lượt. /learn trước để chưng cất bài học vào noob.md (sau khi /new thì history sẽ mất).`,
150
+ memoryStatus: (lines, rules, notes, ago) =>
151
+ `📝 noob.md: ${lines} dòng (${rules} rules, ${notes} notes) · cập nhật ${ago}`,
152
+ memoryMissing: '📝 noob.md: chưa /init để tạo từ dự án.',
153
+ compactRunning: 'đang tóm tắt phiên để gọn ngữ cảnh…',
154
+ compactEmpty: 'Phiên còn trống không để tóm tắt.',
155
+ compactSkipped: 'Phiên còn ngắn hoặc tóm tắt thất bại bỏ qua.',
156
+ compactDone: (bMsgs, aMsgs, bK, aK, pct) =>
157
+ `Đã tóm tắt: ${bMsgs} → ${aMsgs} tin · ${bK}k → ${aK}k chars (giảm ${pct}%).`,
158
+ longSession: (k) =>
159
+ `Phiên dài (${k}k chars). Cân nhắc /compact để gọn ngữ cảnh (giữ trí nhớ) hoặc /clear để phiên mới hoàn toàn.`,
160
+ veryLongSession: (k) =>
161
+ `⚠ Phiên RẤT dài (${k}k chars) — model có thể chậm/lú. Khuyến nghị /compact ngay, hoặc /clear nếu task đã xong.`,
148
162
  autoCompactTrigger: (k) => `Phiên đã đạt ${k}k chars — tự động tóm tắt để giữ model chạy mượt…`,
149
- autoCompactDone: (bK, aK, pct) => `✓ Auto-compact: ${bK}k → ${aK}k chars (giảm ${pct}%). Trí nhớ dài hạn đã giữ lại trong session_summary.`,
150
- autoCompactFail: "Auto-compact thất bại bạn nên /clear hoặc /compact thủ công.",
151
- initRunning: "đang quét dự án & soạn noob.md…",
152
- frontendDesignRunning: "đang vận dụng skill frontend-design",
153
- improveRunning: "đang khảo sát workspace & soạn đề xuất cải thiện",
154
- frontendDesignNoSkill: "không tìm thấy skills/frontend-design/SKILL.md skill chưa được cài.",
155
- frontendDesignNeedReq: "cần tả yêu cầu. Ví dụ: /frontend-design landing page cho app nghe nhạc lo-fi",
156
- workflowRunning: "đang chạy dynamic workflow đa sub-agent…",
157
- workflowNoSkill: "không tìm thấy skills/dynamic-workflows/SKILL.md skill chưa được cài.",
158
- workflowNeedArg: "cần tả task. Ví dụ: /workflow audit toàn bộ src/ tìm lỗ hổng SQL injection",
159
- workflowAgentAutoOn: "agent mode tự bật cho /workflow (cần spawn_agent)",
160
- workflowAgentAskHint: "🎼 /workflow cần spawn sub-agent (spawn_agent) agent mode hiện đang TẮT.",
161
- workflowAgentAskPrompt: " bật agent mode chạy workflow? [y] có, bật & chạy / [n] huỷ ( /agent rồi chạy lại nếu muốn) › ",
162
- workflowAgentEnabled: "đã bật agent mode cho workflow này.",
163
- workflowAgentDenied: "đã huỷ /workflow agent mode vẫn TẮT. Gõ /agent rồi chạy lại lệnh nếu muốn.",
163
+ autoCompactDone: (bK, aK, pct) =>
164
+ `✓ Auto-compact: ${bK}k ${aK}k chars (giảm ${pct}%). Trí nhớ dài hạn đã giữ lại trong session_summary.`,
165
+ autoCompactFail: 'Auto-compact thất bại bạn nên /clear hoặc /compact thủ công.',
166
+ initRunning: 'đang quét dự án & soạn noob.md',
167
+ frontendDesignRunning: 'đang vận dụng skill frontend-design',
168
+ improveRunning: 'đang khảo sát workspace & soạn đề xuất cải thiện…',
169
+ frontendDesignNoSkill: 'không tìm thấy skills/frontend-design/SKILL.md skill chưa được cài.',
170
+ frontendDesignNeedReq:
171
+ 'cần tả yêu cầu. Ví dụ: /frontend-design landing page cho app nghe nhạc lo-fi',
172
+ workflowRunning: 'đang chạy dynamic workflow đa sub-agent…',
173
+ workflowNoSkill: 'không tìm thấy skills/dynamic-workflows/SKILL.md skill chưa được cài.',
174
+ workflowNeedArg: 'cần mô tả task. Ví dụ: /workflow audit toàn bộ src/ tìm lỗ hổng SQL injection',
175
+ workflowAgentAutoOn: 'agent mode tự bật cho /workflow (cần spawn_agent)',
176
+ workflowAgentAskHint:
177
+ '🎼 /workflow cần spawn sub-agent (spawn_agent) agent mode hiện đang TẮT.',
178
+ workflowAgentAskPrompt:
179
+ ' bật agent mode và chạy workflow? [y] có, bật & chạy / [n] huỷ (gõ /agent rồi chạy lại nếu muốn) › ',
180
+ workflowAgentEnabled: 'đã bật agent mode cho workflow này.',
181
+ workflowAgentDenied:
182
+ 'đã huỷ /workflow — agent mode vẫn TẮT. Gõ /agent rồi chạy lại lệnh nếu muốn.',
164
183
  // saved workflows (CRUD)
165
- workflowListEmpty: (dir) => `Chưa có workflow đã lưu. Tạo bằng /workflow save <name> <yêu cầu>. Thư mục: ${dir}`,
184
+ workflowListEmpty: (dir) =>
185
+ `Chưa có workflow đã lưu. Tạo bằng /workflow save <name> <yêu cầu>. Thư mục: ${dir}`,
166
186
  workflowListHeader: (dir) => `Workflow đã lưu (${dir}):`,
167
- workflowSaveNeedArgs: "Cách dùng: /workflow save <name> <yêu cầu workflow>",
168
- workflowSaveEmptyPrompt: "Thiếu yêu cầu workflow. VD: /workflow save code-audit-security \"audit src/ tìm SQL injection\"",
169
- workflowSaveBadName: (n) => `Tên workflow không hợp lệ: '${n}'. Chỉ chấp nhận [a-z0-9_-], bắt đầu bằng chữ/số, tối đa 64 ký tự.`,
187
+ workflowSaveNeedArgs: 'Cách dùng: /workflow save <name> <yêu cầu workflow>',
188
+ workflowSaveEmptyPrompt:
189
+ 'Thiếu yêu cầu workflow. VD: /workflow save code-audit-security "audit src/ tìm SQL injection"',
190
+ workflowSaveBadName: (n) =>
191
+ `Tên workflow không hợp lệ: '${n}'. Chỉ chấp nhận [a-z0-9_-], bắt đầu bằng chữ/số, tối đa 64 ký tự.`,
170
192
  workflowSaveError: (n, e) => `Không lưu được workflow '${n}': ${e}`,
171
193
  workflowSaveOk: (n, p) => `Đã lưu workflow '${n}' → ${p}`,
172
- workflowSaveAskDesc: "thêm mô tả ngắn để dễ tìm sau này? [y/n] › ",
173
- workflowSaveDescPrompt: "mô tả (1 dòng): ",
174
- workflowSaveDescSkipped: "(bỏ qua description — có thể thêm sau bằng cách save lại)",
194
+ workflowSaveAskDesc: 'thêm mô tả ngắn để dễ tìm sau này? [y/n] › ',
195
+ workflowSaveDescPrompt: 'mô tả (1 dòng): ',
196
+ workflowSaveDescSkipped: '(bỏ qua description — có thể thêm sau bằng cách save lại)',
175
197
  workflowSaveDescOk: (n, d) => `Đã thêm mô tả cho '${n}': ${d}`,
176
- workflowRunNeedName: "Cách dùng: /workflow run <name> [thêm ngữ cảnh]",
198
+ workflowRunNeedName: 'Cách dùng: /workflow run <name> [thêm ngữ cảnh]',
177
199
  workflowRunError: (n, e) => `Không nạp được workflow '${n}': ${e}`,
178
200
  workflowRunOk: (n) => `Chạy workflow đã lưu '${n}'…`,
179
201
  workflowRunPreviewBuiltin: (n, title) => `Built-in workflow '${n}' (${title})`,
180
202
  workflowRunPreviewSaved: (n) => `Workflow đã lưu '${n}'`,
181
- workflowLoadNeedName: "Cách dùng: /workflow load <name>",
203
+ workflowLoadNeedName: 'Cách dùng: /workflow load <name>',
182
204
  workflowLoadError: (n, e) => `Không nạp được workflow '${n}': ${e}`,
183
205
  workflowLoadOk: (n, p) => `Workflow '${n}' (${p}):`,
184
- workflowDeleteNeedName: "Cách dùng: /workflow delete <name>",
206
+ workflowDeleteNeedName: 'Cách dùng: /workflow delete <name>',
185
207
  workflowDeleteError: (n, e) => `Không xoá được workflow '${n}': ${e}`,
186
208
  workflowDeleteOk: (n) => `Đã xoá workflow '${n}'.`,
187
209
  workflowDeleteBuiltIn: (n) => `'${n}' là built-in workflow, không xoá được.`,
188
210
  // discoverability (v1.9.1)
189
- workflowHelpTitle: "🎼 /workflow — orchestrate multi-agent workflow",
190
- workflowHelpSub: "Workflow chia task lớn thành sub-agent chạy song song/độc lập → chống 3 failure mode của single-context: agentic laziness, self-preferential bias, goal drift.",
191
- workflowPatternsTitle: "🎼 6 pattern workflow (theo article Thariq)",
211
+ workflowHelpTitle: '🎼 /workflow — orchestrate multi-agent workflow',
212
+ workflowHelpSub:
213
+ 'Workflow chia task lớn thành sub-agent chạy song song/độc lập → chống 3 failure mode của single-context: agentic laziness, self-preferential bias, goal drift.',
214
+ workflowPatternsTitle: '🎼 6 pattern workflow (theo article Thariq)',
192
215
  workflowBuiltinsTitle: (n) => `🎼 Workflow built-in (${n} mẫu ship sẵn):`,
193
216
  initOverwriteWarn: (p) => `⚠ Đã có noob.md tại ${p}. /init sẽ ghi đè nội dung hiện tại.`,
194
217
  initOverwriteConfirm: "Ghi đè? gõ 'y' để xác nhận, phím khác để huỷ › ",
195
- initCancel: "Huỷ /init — giữ nguyên noob.md.",
218
+ initCancel: 'Huỷ /init — giữ nguyên noob.md.',
196
219
  memoryEmpty: (p) => `Chưa có noob.md. noob sẽ tự tạo ở: ${p}`,
197
220
  memoryStat: (n) => ` · ${n} dòng / ~200`,
198
221
 
199
222
  // sessions (lưu lịch sử + resume)
200
223
  sessionResumed: (id) => `Đã khôi phục phiên ${id}`,
201
- sessionNonePrev: "Chưa có phiên nào trước đó — bắt đầu phiên mới.",
224
+ sessionNonePrev: 'Chưa có phiên nào trước đó — bắt đầu phiên mới.',
202
225
  sessionNotFound: (id) => `Không tìm thấy phiên "${id}".`,
203
- sessionEmpty: "Chưa có phiên đã lưu nào.",
204
- sessionPickTitle: "Chọn phiên để tiếp tục:",
205
- sessionListTitle: "Các phiên đã lưu:",
226
+ sessionEmpty: 'Chưa có phiên đã lưu nào.',
227
+ sessionPickTitle: 'Chọn phiên để tiếp tục:',
228
+ sessionListTitle: 'Các phiên đã lưu:',
206
229
  sessionPickPrompt: (n) => `chọn phiên [1-${n}], Enter để bỏ qua › `,
207
- sessionPickBad: "lựa chọn không hợp lệ.",
208
- sessionResumeHint: "/resume <id> để tiếp tục một phiên · hoặc chạy: noob -c (phiên gần nhất)",
230
+ sessionPickBad: 'lựa chọn không hợp lệ.',
231
+ sessionResumeHint: '/resume <id> để tiếp tục một phiên · hoặc chạy: noob -c (phiên gần nhất)',
209
232
 
210
233
  // update
211
- cmdUpdate: "/update cập nhật noob lên bản mới nhất",
234
+ cmdUpdate: '/update cập nhật noob lên bản mới nhất',
212
235
  updateFound: (cur, lat) => `🆕 Có bản mới ${lat} (đang dùng ${cur}) — đang tự cập nhật nền…`,
213
- updateBgDone: "Đang cập nhật nền. Mở lại noob để dùng bản mới.",
214
- updateChecking: "Đang kiểm tra cập nhật…",
236
+ updateBgDone: 'Đang cập nhật nền. Mở lại noob để dùng bản mới.',
237
+ updateChecking: 'Đang kiểm tra cập nhật…',
215
238
  updateLatest: (cur) => `Đã ở bản mới nhất (${cur}).`,
216
- updating: "Đang cập nhật…",
217
- updateOk: "✓ Cập nhật xong. Mở lại noob để dùng bản mới.",
218
- updateFail: "✗ Cập nhật thất bại. Thử thủ công: npm i -g @noobdemon/noob-cli@latest",
239
+ updating: 'Đang cập nhật…',
240
+ updateOk: '✓ Cập nhật xong. Mở lại noob để dùng bản mới.',
241
+ updateFail: '✗ Cập nhật thất bại. Thử thủ công: npm i -g @noobdemon/noob-cli@latest',
219
242
  };
package/src/memory.js CHANGED
@@ -1,10 +1,10 @@
1
1
  // Bộ nhớ lâu dài của noob: file `noob.md` ở thư mục gốc dự án (giống CLAUDE.md /
2
2
  // AGENTS.md). noob TỰ tạo & TỰ cập nhật nó qua write_file/edit_file để học và
3
3
  // nhớ giữa các phiên. Runtime chỉ ĐỌC để chèn vào prompt — không tự ghi đè.
4
- import fs from "node:fs";
5
- import path from "node:path";
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
6
 
7
- const FILE = "noob.md";
7
+ const FILE = 'noob.md';
8
8
 
9
9
  export function memoryPath() {
10
10
  return path.resolve(process.cwd(), FILE);
@@ -13,7 +13,7 @@ export function memoryPath() {
13
13
  /** Nội dung noob.md hiện tại, hoặc null nếu chưa có / rỗng. */
14
14
  export function loadMemory() {
15
15
  try {
16
- const txt = fs.readFileSync(memoryPath(), "utf8").trim();
16
+ const txt = fs.readFileSync(memoryPath(), 'utf8').trim();
17
17
  return txt || null;
18
18
  } catch {
19
19
  return null;
@@ -26,25 +26,36 @@ export function loadMemory() {
26
26
  export function memoryStats() {
27
27
  let txt;
28
28
  try {
29
- txt = fs.readFileSync(memoryPath(), "utf8");
29
+ txt = fs.readFileSync(memoryPath(), 'utf8');
30
30
  } catch {
31
31
  return null;
32
32
  }
33
33
  if (!txt.trim()) return null;
34
- const lines = txt.split("\n");
34
+ const lines = txt.split('\n');
35
35
  let rules = 0;
36
36
  let notes = 0;
37
- let inSection = "";
37
+ let inSection = '';
38
38
  for (const l of lines) {
39
- if (/^##\s+Rules\b/i.test(l)) { inSection = "rules"; continue; }
40
- if (/^##\s+Notes\b/i.test(l)) { inSection = "notes"; continue; }
41
- if (/^##\s/.test(l)) { inSection = ""; continue; } // mục khác → reset
39
+ if (/^##\s+Rules\b/i.test(l)) {
40
+ inSection = 'rules';
41
+ continue;
42
+ }
43
+ if (/^##\s+Notes\b/i.test(l)) {
44
+ inSection = 'notes';
45
+ continue;
46
+ }
47
+ if (/^##\s/.test(l)) {
48
+ inSection = '';
49
+ continue;
50
+ } // mục khác → reset
42
51
  if (/^\s*[-*]\s+/.test(l)) {
43
- if (inSection === "rules") rules++;
44
- else if (inSection === "notes") notes++;
52
+ if (inSection === 'rules') rules++;
53
+ else if (inSection === 'notes') notes++;
45
54
  }
46
55
  }
47
56
  let mtime = 0;
48
- try { mtime = fs.statSync(memoryPath()).mtimeMs; } catch {}
57
+ try {
58
+ mtime = fs.statSync(memoryPath()).mtimeMs;
59
+ } catch {}
49
60
  return { lines: lines.length, rules, notes, mtime, path: memoryPath() };
50
61
  }