@dtd-dev/agent-kb 0.1.0 → 0.1.1

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/README.md +3 -1
  2. package/bin/cli.js +83 -27
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -36,7 +36,9 @@ Không cài global, không cần clone. Zero-dependency nên `npx` chạy tức
36
36
  | `help` | Trợ giúp |
37
37
 
38
38
  Chạy tương tác sẽ hỏi: **tên dự án, backend, database, frontend, CI/CD, lệnh deploy, tool phụ**
39
- (Enter để giữ gợi ý). agent-kb **tự đọc `package.json`/`go.mod`/… để gợi ý stack & database sẵn**.
39
+ (Enter để giữ gợi ý). agent-kb **tự đọc `package.json`/`go.mod`/… để gợi ý stack & database sẵn**
40
+ — quét cả **thư mục con tới 3 cấp** nên hỗ trợ **monorepo** (vd `apps/web`, `services/api`). Nếu
41
+ không thấy manifest nào, nó **báo rõ** và để bạn nhập tay (hoặc dùng cờ `--backend/--frontend/--database`).
40
42
  Các phần còn lại (cache, state, UI lib, container, URL môi trường, rollback…) là placeholder
41
43
  `<!-- vd: ... -->` trong file để bạn điền tay sau.
42
44
 
package/bin/cli.js CHANGED
@@ -167,38 +167,86 @@ function substituteTokens(values) {
167
167
  }
168
168
  }
169
169
 
170
- // Đọc dự án để gợi ý stack chỉ đọc file, không đổi gì.
171
- function detectStack() {
172
- const out = { backend: null, frontend: null, database: null, cicd: null, stacks: [] };
173
- const addStack = (s) => {
174
- if (!out.stacks.includes(s)) out.stacks.push(s);
170
+ // Thư mục rác/sinh ra không quét để khỏi nhận diện nhầm & cho nhanh.
171
+ const IGNORE_DIRS = new Set([
172
+ "node_modules", ".git", ".ai", ".claude", "dist", "build", "out",
173
+ ".next", ".nuxt", "coverage", "vendor", "target", ".gradle", ".venv", "venv", "__pycache__",
174
+ ]);
175
+ const MANIFEST_NAMES = [
176
+ "package.json", "go.mod", "requirements.txt", "pyproject.toml", "Pipfile",
177
+ "pom.xml", "build.gradle", "build.gradle.kts", "Cargo.toml", "composer.json",
178
+ ];
179
+
180
+ // Tìm các thư mục có manifest, quét tối đa maxDepth cấp từ root (bỏ thư mục rác/dotdir).
181
+ function findProjectRoots(root, maxDepth) {
182
+ const roots = [];
183
+ const walk = (dir, depth) => {
184
+ let entries;
185
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
186
+ if (entries.some((e) => e.isFile() && MANIFEST_NAMES.includes(e.name))) roots.push(dir);
187
+ if (depth >= maxDepth) return;
188
+ for (const e of entries) {
189
+ if (e.isDirectory() && !e.name.startsWith(".") && !IGNORE_DIRS.has(e.name)) {
190
+ walk(path.join(dir, e.name), depth + 1);
191
+ }
192
+ }
175
193
  };
194
+ walk(root, 0);
195
+ return roots;
196
+ }
176
197
 
177
- const pkg = readJSONSafe(path.join(CWD, "package.json"));
198
+ // Nhận diện stack trong MỘT thư mục, gộp vào `out` (chỉ điền chỗ còn trống → root thắng subfolder).
199
+ function detectInDir(dir, out, addStack) {
200
+ const exists = (f) => fs.existsSync(path.join(dir, f));
201
+ const pkg = readJSONSafe(path.join(dir, "package.json"));
178
202
  if (pkg) {
179
203
  const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
180
204
  const has = (n) => Object.prototype.hasOwnProperty.call(deps, n);
181
- if (has("next")) { out.frontend = "Next.js + React"; addStack("react"); }
182
- else if (has("react")) { out.frontend = "React" + (has("vite") ? " + Vite" : ""); addStack("react"); }
183
- else if (has("vue")) out.frontend = "Vue";
184
- else if (has("svelte") || has("@sveltejs/kit")) out.frontend = "Svelte";
185
-
186
- if (has("@nestjs/core")) { out.backend = "Node.js + NestJS"; addStack("node"); }
187
- else if (has("express")) { out.backend = "Node.js + Express"; addStack("node"); }
188
- else if (has("fastify")) { out.backend = "Node.js + Fastify"; addStack("node"); }
189
- else if (!out.frontend) { out.backend = "Node.js"; addStack("node"); }
190
-
191
- if (has("pg") || has("postgres") || has("postgresql")) out.database = "PostgreSQL";
192
- else if (has("mysql") || has("mysql2")) out.database = "MySQL";
193
- else if (has("mongoose") || has("mongodb")) out.database = "MongoDB";
194
- else if (has("firebase") || has("firebase-admin")) out.database = "Firebase/Firestore";
195
- if (has("redis") || has("ioredis")) out.database = out.database ? out.database + " + Redis" : "Redis";
196
- }
197
- if (hasFile("go.mod")) { out.backend = out.backend || "Go"; addStack("go"); }
198
- if (hasFile("requirements.txt") || hasFile("pyproject.toml") || hasFile("Pipfile")) { out.backend = out.backend || "Python"; addStack("python"); }
199
- if (hasFile("pom.xml") || hasFile("build.gradle") || hasFile("build.gradle.kts")) { out.backend = out.backend || "Java"; addStack("java"); }
200
- if (hasFile("Cargo.toml")) { out.backend = out.backend || "Rust"; addStack("rust"); }
201
- if (hasFile("composer.json")) { out.backend = out.backend || "PHP"; addStack("php"); }
205
+ let fe = null, be = null;
206
+ if (has("next")) { fe = "Next.js + React"; addStack("react"); }
207
+ else if (has("react")) { fe = "React" + (has("vite") ? " + Vite" : ""); addStack("react"); }
208
+ else if (has("vue")) fe = "Vue";
209
+ else if (has("svelte") || has("@sveltejs/kit")) fe = "Svelte";
210
+
211
+ if (has("@nestjs/core")) { be = "Node.js + NestJS"; addStack("node"); }
212
+ else if (has("express")) { be = "Node.js + Express"; addStack("node"); }
213
+ else if (has("fastify")) { be = "Node.js + Fastify"; addStack("node"); }
214
+ else if (!fe) { out._node = true; addStack("node"); } // Node "trơn": ưu tiên thấp nhất, quyết ở cuối
215
+
216
+ if (fe && !out.frontend) out.frontend = fe;
217
+ if (be && !out.backend) out.backend = be;
218
+
219
+ if (!out.database) {
220
+ if (has("pg") || has("postgres") || has("postgresql")) out.database = "PostgreSQL";
221
+ else if (has("mysql") || has("mysql2")) out.database = "MySQL";
222
+ else if (has("mongoose") || has("mongodb")) out.database = "MongoDB";
223
+ else if (has("firebase") || has("firebase-admin")) out.database = "Firebase/Firestore";
224
+ }
225
+ if ((has("redis") || has("ioredis")) && !(out.database || "").includes("Redis")) {
226
+ out.database = out.database ? out.database + " + Redis" : "Redis";
227
+ }
228
+ }
229
+ if (exists("go.mod")) { out.backend = out.backend || "Go"; addStack("go"); }
230
+ if (exists("requirements.txt") || exists("pyproject.toml") || exists("Pipfile")) { out.backend = out.backend || "Python"; addStack("python"); }
231
+ if (exists("pom.xml") || exists("build.gradle") || exists("build.gradle.kts")) { out.backend = out.backend || "Java"; addStack("java"); }
232
+ if (exists("Cargo.toml")) { out.backend = out.backend || "Rust"; addStack("rust"); }
233
+ if (exists("composer.json")) { out.backend = out.backend || "PHP"; addStack("php"); }
234
+ }
235
+
236
+ // Đọc dự án để gợi ý stack — chỉ đọc file, không đổi gì. Quét cả thư mục con (monorepo).
237
+ function detectStack() {
238
+ const out = { backend: null, frontend: null, database: null, cicd: null, stacks: [], roots: [], _node: false };
239
+ const addStack = (s) => {
240
+ if (!out.stacks.includes(s)) out.stacks.push(s);
241
+ };
242
+
243
+ // Root (CWD) trước, rồi tới subfolder nông→sâu, để stack của thư mục gốc được ưu tiên.
244
+ const roots = findProjectRoots(CWD, 3).sort((a, b) => a.length - b.length);
245
+ for (const dir of roots) {
246
+ detectInDir(dir, out, addStack);
247
+ out.roots.push(path.relative(CWD, dir) || ".");
248
+ }
249
+ if (!out.backend && out._node) out.backend = "Node.js"; // fallback Node sau khi đã xét hết
202
250
 
203
251
  if (fs.existsSync(path.join(CWD, ".github", "workflows"))) out.cicd = "GitHub Actions";
204
252
  else if (hasFile(".gitlab-ci.yml")) out.cicd = "GitLab CI";
@@ -259,6 +307,14 @@ async function init() {
259
307
 
260
308
  if (det.backend || det.frontend || det.cicd) {
261
309
  console.log(`\nℹ Nhận diện stack: ${[det.backend, det.frontend, det.database, det.cicd].filter(Boolean).join(" · ") || "—"}`);
310
+ if (det.roots.length > 1 || (det.roots.length === 1 && det.roots[0] !== ".")) {
311
+ console.log(` (manifest tại: ${det.roots.join(", ")})`);
312
+ }
313
+ } else {
314
+ console.log("\n⚠ Không tự nhận diện được stack — không thấy manifest");
315
+ console.log(" (package.json / go.mod / requirements.txt / pyproject.toml / pom.xml / Cargo.toml / composer.json)");
316
+ console.log(" trong thư mục này hay các thư mục con (quét tối đa 3 cấp).");
317
+ console.log(" → Chạy ở đúng thư mục gốc dự án, hoặc nhập tay / dùng cờ --backend --frontend --database.");
262
318
  }
263
319
 
264
320
  if (!YES) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtd-dev/agent-kb",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Bộ agent skill chuẩn hoá cho doanh nghiệp: scaffold knowledge base .ai/ tiết kiệm token, tăng độ chính xác khi viết code, và cá nhân hoá theo nghiệp vụ công ty để tái dùng cho nhiều dự án cùng nghiệp vụ (AGENTS.md, CLAUDE.md, GEMINI.md, Copilot).",
5
5
  "bin": {
6
6
  "agent-kb": "bin/cli.js"