@noobdemon/noob-cli 1.7.3 → 1.7.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noobdemon/noob-cli",
3
- "version": "1.7.3",
3
+ "version": "1.7.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/agent.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import os from "node:os";
2
2
  import { stream } from "./api.js";
3
3
  import { loadMemory } from "./memory.js";
4
+ import { listRoots } from "./tools.js";
4
5
  import { t } from "./i18n.js";
5
6
  import { countTokens } from "./tokens.js";
6
7
 
@@ -92,6 +93,19 @@ function runtimeContext() {
92
93
  `- Shell for run_command: ${isWin ? "Windows PowerShell (powershell.exe)" : "bash"}`,
93
94
  `- Current working directory: ${process.cwd()}`,
94
95
  ];
96
+ // Extra roots cấp qua /add-dir: model PHẢI biết để chủ động dùng (đọc/list/grep).
97
+ // Không liệt kê ở đây → model không 'thấy' thư mục đó tồn tại dù tools layer
98
+ // đã accept path.
99
+ try {
100
+ const roots = listRoots();
101
+ const extras = roots.slice(1); // [0] là cwd
102
+ if (extras.length) {
103
+ lines.push(
104
+ `- Extra roots cấp quyền qua /add-dir (tool path nằm trong các thư mục này cũng hợp lệ — dùng path tuyệt đối khi gọi tool):`,
105
+ );
106
+ for (const r of extras) lines.push(` • ${r}`);
107
+ }
108
+ } catch {}
95
109
  if (isWin) {
96
110
  lines.push(
97
111
  "- IMPORTANT: run_command runs in PowerShell on Windows — do NOT use Unix tools.",
package/src/i18n.js CHANGED
@@ -62,6 +62,8 @@ export const t = {
62
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
63
  cmdInit: "/init quét dự án & tạo noob.md (tổng quan + quy ước, như Claude Code)",
64
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)",
65
67
  cmdUltra: "/ultra <mục tiêu> tự hành: noob tự nghĩ & tự làm nhiệm vụ tới khi xong (/u)",
66
68
  cmdLearn: "/learn [ghi chú] chưng cất bài học của phiên vào noob.md",
67
69
  cmdCompact: "/compact tóm tắt phiên ngay để gọn ngữ cảnh (giữ trí nhớ dài hạn)",
@@ -123,6 +125,10 @@ export const t = {
123
125
  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.`,
124
126
  autoCompactFail: "Auto-compact thất bại — bạn nên /clear hoặc /compact thủ công.",
125
127
  initRunning: "đang quét dự án & soạn noob.md…",
128
+ frontendDesignRunning: "đang vận dụng skill frontend-design…",
129
+ improveRunning: "đang khảo sát workspace & soạn đề xuất cải thiện…",
130
+ frontendDesignNoSkill: "không tìm thấy skills/frontend-design/SKILL.md — skill chưa được cài.",
131
+ frontendDesignNeedReq: "cần mô tả yêu cầu. Ví dụ: /frontend-design landing page cho app nghe nhạc lo-fi",
126
132
  initOverwriteWarn: (p) => `⚠ Đã có noob.md tại ${p}. /init sẽ ghi đè nội dung hiện tại.`,
127
133
  initOverwriteConfirm: "Ghi đè? gõ 'y' để xác nhận, phím khác để huỷ › ",
128
134
  initCancel: "Huỷ /init — giữ nguyên noob.md.",
package/src/repl.js CHANGED
@@ -15,6 +15,7 @@ import { loadMemory, memoryPath } from "./memory.js";
15
15
  import { t } from "./i18n.js";
16
16
  import { checkLatest, runUpdate, CURRENT } from "./update.js";
17
17
  import * as sessions from "./sessions.js";
18
+ import { loadSkill, listSkills } from "./skills.js";
18
19
 
19
20
  // Lệnh dùng cho autocomplete. Gõ "/l" → lọc các lệnh có "l" (login, logout,
20
21
  // clear, models, yolo…); ↑/↓ chọn, Tab điền, Enter chạy mục đang sáng.
@@ -29,6 +30,8 @@ const SLASH = [
29
30
  { name: "/auto-yolo", desc: "lưu yolo làm mặc định (cần xác nhận)" },
30
31
  { name: "/init", desc: "quét dự án & tạo noob.md" },
31
32
  { name: "/karpathy", desc: "rà soát code (Karpathy)" },
33
+ { name: "/frontend-design", desc: "thiết kế UI frontend chất lượng cao (skill)" },
34
+ { name: "/improve", desc: "phân tích workspace & gợi ý tính năng cải thiện" },
32
35
  { name: "/ultra", desc: "tự hành: tự nghĩ & làm nhiệm vụ" },
33
36
  { name: "/agent", desc: "bật/tắt agent mode (spawn sub-agent)" },
34
37
  { name: "/tokens", desc: "xem số token đã dùng phiên này" },
@@ -332,6 +335,39 @@ export async function startRepl(opts = {}) {
332
335
  }
333
336
  const startFresh = () => (session = sessions.newSession({ cwd: process.cwd(), model: state.model.id }));
334
337
 
338
+ // /frontend-design <yêu cầu> — vận dụng skill frontend-design (skills/frontend-design/SKILL.md)
339
+ // để model tạo UI frontend chất lượng cao, tránh "AI slop" aesthetic.
340
+ async function runFrontendDesign(arg) {
341
+ if (!config.apiKey) return console.log(c.tool(" " + t.notLoggedIn));
342
+ if (!arg) return console.log(c.err(" " + t.frontendDesignNeedReq));
343
+ const skill = loadSkill("frontend-design");
344
+ if (!skill) return console.log(c.err(" " + t.frontendDesignNoSkill));
345
+ const prompt = `Bạn đang thực thi SKILL "frontend-design". Đọc kỹ hướng dẫn skill dưới đây và TUÂN THỦ khi xây dựng UI.
346
+
347
+ === SKILL: frontend-design ===
348
+ ${skill}
349
+ === HẾT SKILL ===
350
+
351
+ YÊU CẦU NGƯỜI DÙNG:
352
+ ${arg}
353
+
354
+ Thực thi: đọc/tạo file cần thiết bằng tool, viết code production-grade theo đúng tinh thần skill (typography đặc sắc, color/theme có cam kết, motion có chủ đích, layout bất ngờ, tránh AI slop). Báo cáo ngắn gọn các file đã tạo và lựa chọn thẩm mỹ chính.`;
355
+ console.log(c.tool(" 🎨 " + t.frontendDesignRunning));
356
+ await handle(prompt);
357
+ persist();
358
+ }
359
+
360
+ // /improve [hint] — model rà soát workspace & đề xuất tính năng/cải tiến.
361
+ // KHÔNG sửa code, chỉ phân tích & đề xuất.
362
+ async function runImprove(arg) {
363
+ if (!config.apiKey) return console.log(c.tool(" " + t.notLoggedIn));
364
+ const focus = arg ? `\nNgười dùng nhấn mạnh: "${arg}". Ưu tiên theo hướng đó nhưng vẫn nêu gợi ý quan trọng khác.` : "";
365
+ const prompt = `Đóng vai senior engineer & product reviewer. KHẢO SÁT workspace hiện tại và đề xuất TÍNH NĂNG / CẢI TIẾN cho dự án.${focus}\n\nQUY TRÌNH (dùng tool, không nói suông):\n1. list_dir thư mục gốc để nắm cấu trúc.\n2. Đọc README.md, package.json, noob.md, CHANGELOG.md (nếu có) để hiểu mục đích & trạng thái.\n3. list_dir/glob các thư mục mã chính. KHÔNG đọc hết file — chỉ đủ để nắm kiến trúc.\n4. grep TODO/FIXME/HACK/XXX để biết chỗ tác giả đã ghi nhận.\n5. Ghi nhận thiếu test/lint/CI nếu có.\n\nSAU KHẢO SÁT, viết báo cáo Markdown TIẾNG VIỆT theo cấu trúc:\n\n## Tóm tắt dự án\n2–4 dòng: làm gì, tech gì, trạng thái.\n\n## Điểm mạnh hiện tại\n3–6 gạch đầu dòng.\n\n## Gợi ý cải thiện\n5–10 đề xuất, MỖI cái:\n### N. <Tên>\n- **Vấn đề/cơ hội:** quan sát cụ thể (kèm tên_file:dòng nếu được).\n- **Đề xuất:** mô tả tính năng/cải tiến.\n- **Lợi ích:** UX/hiệu năng/độ tin cậy/mở rộng.\n- **Công sức:** S (vài giờ) / M (1–2 ngày) / L (>2 ngày).\n- **Ưu tiên:** P0 / P1 / P2.\n\n## Đề xuất ưu tiên hàng đầu\n1–3 mục P0 nên làm trước, kèm lý do.\n\nQUY TẮC: bám observation từ code thật, KHÔNG gợi ý chung chung, thẳng thắn không nịnh, KHÔNG sửa code, KHÔNG ghi noob.md.`;
366
+ console.log(c.tool(" ✨ " + t.improveRunning));
367
+ await handle(prompt);
368
+ persist();
369
+ }
370
+
335
371
  // /karpathy [path] — bắt noob tự rà soát code theo 4 nguyên tắc Karpathy.
336
372
  // Không có path → soát các file đã đổi trong phiên (model thấy qua FILES CHANGED).
337
373
  async function runKarpathy(arg) {
@@ -941,6 +977,15 @@ NGUYÊN TẮC:
941
977
  case "kc":
942
978
  await runKarpathy(arg);
943
979
  break;
980
+ case "frontend-design":
981
+ case "frontend":
982
+ case "fd":
983
+ await runFrontendDesign(arg);
984
+ break;
985
+ case "improve":
986
+ case "imp":
987
+ await runImprove(arg);
988
+ break;
944
989
  case "ultra":
945
990
  case "u":
946
991
  await runUltra(arg);
@@ -1216,6 +1261,8 @@ function printHelp() {
1216
1261
  " " + t.cmdAutoYolo,
1217
1262
  " " + t.cmdInit,
1218
1263
  " " + t.cmdKarpathy,
1264
+ " " + t.cmdFrontendDesign,
1265
+ " " + t.cmdImprove,
1219
1266
  " " + t.cmdUltra,
1220
1267
  " " + t.cmdLearn,
1221
1268
  " " + t.cmdCompact,
package/src/skills.js ADDED
@@ -0,0 +1,43 @@
1
+ // Quản lý skills của project: mỗi skill là một thư mục `skills/<name>/` chứa
2
+ // `SKILL.md` (theo quy ước Anthropic). Khi user gõ `/<skill-name>`, repl sẽ nạp
3
+ // nội dung SKILL.md đó như context bổ sung rồi giao việc cho agent.
4
+ //
5
+ // API tối giản — không over-engineer:
6
+ // loadSkill(name) -> string | null (nội dung SKILL.md, null nếu không có)
7
+ // listSkills() -> string[] (tên skill có sẵn ở cwd)
8
+ // skillPath(name) -> string (đường dẫn tuyệt đối SKILL.md)
9
+
10
+ import fs from "node:fs";
11
+ import path from "node:path";
12
+
13
+ function skillsDir() {
14
+ return path.join(process.cwd(), "skills");
15
+ }
16
+
17
+ export function skillPath(name) {
18
+ return path.join(skillsDir(), name, "SKILL.md");
19
+ }
20
+
21
+ export function loadSkill(name) {
22
+ try {
23
+ const p = skillPath(name);
24
+ if (!fs.existsSync(p)) return null;
25
+ return fs.readFileSync(p, "utf8");
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+
31
+ export function listSkills() {
32
+ try {
33
+ const dir = skillsDir();
34
+ if (!fs.existsSync(dir)) return [];
35
+ return fs
36
+ .readdirSync(dir, { withFileTypes: true })
37
+ .filter((e) => e.isDirectory() && fs.existsSync(path.join(dir, e.name, "SKILL.md")))
38
+ .map((e) => e.name)
39
+ .sort();
40
+ } catch {
41
+ return [];
42
+ }
43
+ }