@noobdemon/noob-cli 1.9.0 → 1.9.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.
- package/package.json +1 -1
- package/src/i18n.js +14 -1
- package/src/repl.js +212 -37
- package/src/workflows-builtin.js +127 -0
package/package.json
CHANGED
package/src/i18n.js
CHANGED
|
@@ -65,7 +65,7 @@ export const t = {
|
|
|
65
65
|
cmdFrontendDesign: "/frontend-design <yêu cầu> thiết kế UI frontend chất lượng cao theo skill (/fd)",
|
|
66
66
|
cmdImprove: "/improve [hint] phân tích workspace & đề xuất tính năng cải thiện (/imp)",
|
|
67
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>|
|
|
68
|
+
cmdWorkflow: "/workflow <yêu cầu>|help|patterns|builtins|list|save|load|run|delete|rm dynamic workflow đa sub-agent (/wf, /ultracode)",
|
|
69
69
|
cmdGoal: "/goal <text>|clear đặt HARD GOAL cho phiên (chống goal drift; không arg = xem)",
|
|
70
70
|
cmdLoop: "/loop <interval> <task> chạy task lặp lại (vd /loop 10m triage); /loop stop để dừng",
|
|
71
71
|
cmdLearn: "/learn [ghi chú] chưng cất bài học của phiên vào noob.md",
|
|
@@ -165,18 +165,31 @@ export const t = {
|
|
|
165
165
|
workflowListEmpty: (dir) => `Chưa có workflow đã lưu. Tạo bằng /workflow save <name> <yêu cầu>. Thư mục: ${dir}`,
|
|
166
166
|
workflowListHeader: (dir) => `Workflow đã lưu (${dir}):`,
|
|
167
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\"",
|
|
168
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ự.`,
|
|
169
170
|
workflowSaveError: (n, e) => `Không lưu được workflow '${n}': ${e}`,
|
|
170
171
|
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)",
|
|
175
|
+
workflowSaveDescOk: (n, d) => `Đã thêm mô tả cho '${n}': ${d}`,
|
|
171
176
|
workflowRunNeedName: "Cách dùng: /workflow run <name> [thêm ngữ cảnh]",
|
|
172
177
|
workflowRunError: (n, e) => `Không nạp được workflow '${n}': ${e}`,
|
|
173
178
|
workflowRunOk: (n) => `Chạy workflow đã lưu '${n}'…`,
|
|
179
|
+
workflowRunPreviewBuiltin: (n, title) => `Built-in workflow '${n}' (${title})`,
|
|
180
|
+
workflowRunPreviewSaved: (n) => `Workflow đã lưu '${n}'`,
|
|
174
181
|
workflowLoadNeedName: "Cách dùng: /workflow load <name>",
|
|
175
182
|
workflowLoadError: (n, e) => `Không nạp được workflow '${n}': ${e}`,
|
|
176
183
|
workflowLoadOk: (n, p) => `Workflow '${n}' (${p}):`,
|
|
177
184
|
workflowDeleteNeedName: "Cách dùng: /workflow delete <name>",
|
|
178
185
|
workflowDeleteError: (n, e) => `Không xoá được workflow '${n}': ${e}`,
|
|
179
186
|
workflowDeleteOk: (n) => `Đã xoá workflow '${n}'.`,
|
|
187
|
+
workflowDeleteBuiltIn: (n) => `'${n}' là built-in workflow, không xoá được.`,
|
|
188
|
+
// 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)",
|
|
192
|
+
workflowBuiltinsTitle: (n) => `🎼 Workflow built-in (${n} mẫu ship sẵn):`,
|
|
180
193
|
initOverwriteWarn: (p) => `⚠ Đã có noob.md tại ${p}. /init sẽ ghi đè nội dung hiện tại.`,
|
|
181
194
|
initOverwriteConfirm: "Ghi đè? gõ 'y' để xác nhận, phím khác để huỷ › ",
|
|
182
195
|
initCancel: "Huỷ /init — giữ nguyên noob.md.",
|
package/src/repl.js
CHANGED
|
@@ -17,6 +17,7 @@ import { checkLatest, runUpdate, CURRENT } from "./update.js";
|
|
|
17
17
|
import * as sessions from "./sessions.js";
|
|
18
18
|
import { loadSkill, listSkills } from "./skills.js";
|
|
19
19
|
import { saveWorkflow, loadWorkflow, listWorkflows, deleteWorkflow, workflowsDir } from "./workflows.js";
|
|
20
|
+
import { getBuiltinWorkflow, listBuiltinWorkflows, loadBuiltinPrompt } from "./workflows-builtin.js";
|
|
20
21
|
|
|
21
22
|
// Lệnh dùng cho autocomplete. Gõ "/l" → lọc các lệnh có "l" (login, logout,
|
|
22
23
|
// clear, models, yolo…); ↑/↓ chọn, Tab điền, Enter chạy mục đang sáng.
|
|
@@ -389,28 +390,45 @@ Thực thi: đọc/tạo file cần thiết bằng tool, viết code production-
|
|
|
389
390
|
}
|
|
390
391
|
|
|
391
392
|
// /workflow <yêu cầu> — chạy ad-hoc dynamic workflow
|
|
393
|
+
// /workflow help | ? — show syntax + patterns + builtins
|
|
394
|
+
// /workflow patterns — liệt kê 6 pattern workflow (theo article Thariq)
|
|
395
|
+
// /workflow builtins — liệt kê workflow built-in có sẵn
|
|
392
396
|
// /workflow save <name> <req> — lưu prompt template ra ~/.noob/workflows/<name>.md
|
|
393
|
-
// /workflow run <name> [extra] — chạy workflow đã lưu (extra context optional)
|
|
394
|
-
// /workflow load <name> — xem nội dung workflow
|
|
395
|
-
// /workflow list — liệt kê workflow đã lưu
|
|
396
|
-
// /workflow delete <name>
|
|
397
|
-
// Cảm hứng tweet_dump.txt
|
|
397
|
+
// /workflow run <name> [extra] — chạy workflow đã lưu HOẶC built-in (extra context optional)
|
|
398
|
+
// /workflow load <name> — xem nội dung workflow (saved hoặc built-in)
|
|
399
|
+
// /workflow list — liệt kê workflow đã lưu (cộng builtins)
|
|
400
|
+
// /workflow delete|rm <name> — xoá workflow đã lưu
|
|
401
|
+
// Cảm hứng tweet_dump.txt — article Thariq "A harness for every task: dynamic
|
|
402
|
+
// workflows in Claude Code" (2026-06): L83-109 (6 pattern), L121 (deep-research
|
|
403
|
+
// built-in), L147-153 (triage + quarantine + pair-with-/loop), L177
|
|
404
|
+
// (repeatable workflow + /goal + /loop integration).
|
|
398
405
|
async function runWorkflow(arg) {
|
|
399
406
|
if (!config.apiKey) return console.log(c.tool(" " + t.notLoggedIn));
|
|
400
|
-
|
|
401
|
-
//
|
|
402
|
-
|
|
407
|
+
// Empty arg → KHÔNG báo lỗi "need arg" nữa, mà show menu trợ giúp — user
|
|
408
|
+
// mới gõ /workflow có thể chưa biết phải gì. Thay vì đuổi đi, show help +
|
|
409
|
+
// builtins + saved → user thấy luôn có gì để chạy.
|
|
410
|
+
if (!arg || !arg.trim()) {
|
|
411
|
+
return workflowHelp();
|
|
412
|
+
}
|
|
413
|
+
const trimmed = arg.trim();
|
|
414
|
+
// Detect sub-command. Sub-command tách bằng khoảng trắng đầu tiên. Thứ tự
|
|
415
|
+
// match quan trọng: `help` / `?` / `patterns` / `builtins` / `list|ls` /
|
|
416
|
+
// `load` / `delete|rm` / `save` / `run`. Ad-hoc default = phần còn lại.
|
|
417
|
+
const m = trimmed.match(/^(help|\?|patterns|builtins|list|ls|load|delete|rm|save|run)\b\s*([\s\S]*)$/i);
|
|
403
418
|
if (m) {
|
|
404
419
|
const sub = m[1].toLowerCase();
|
|
405
420
|
const rest = m[2].trim();
|
|
421
|
+
if (sub === "help" || sub === "?") return workflowHelp();
|
|
422
|
+
if (sub === "patterns") return workflowPatterns();
|
|
423
|
+
if (sub === "builtins") return workflowBuiltins();
|
|
406
424
|
if (sub === "list" || sub === "ls") return workflowList();
|
|
407
425
|
if (sub === "load") return workflowLoad(rest);
|
|
408
426
|
if (sub === "delete" || sub === "rm") return workflowDelete(rest);
|
|
409
427
|
if (sub === "save") return workflowSave(rest);
|
|
410
428
|
if (sub === "run") return workflowRun(rest);
|
|
411
429
|
}
|
|
412
|
-
// Default: ad-hoc workflow (giữ behavior cũ).
|
|
413
|
-
await workflowExecute(
|
|
430
|
+
// Default: ad-hoc workflow (giữ behavior cũ — model design workflow từ request).
|
|
431
|
+
await workflowExecute(trimmed);
|
|
414
432
|
}
|
|
415
433
|
|
|
416
434
|
// Hỏi quyền bật agent mode để chạy workflow. CHỈ chấp nhận y/n (Enter = yes).
|
|
@@ -438,9 +456,38 @@ Thực thi: đọc/tạo file cần thiết bằng tool, viết code production-
|
|
|
438
456
|
}
|
|
439
457
|
|
|
440
458
|
// Chạy thật workflow prompt — chia sẻ giữa ad-hoc và `run <name>`.
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
459
|
+
// `builtInName` (optional): nếu có thì SKIP loadSkill dynamic-workflows (prompt
|
|
460
|
+
// built-in đã hardcode pattern + step cụ thể rồi, không cần model design lại).
|
|
461
|
+
async function workflowExecute(userRequest, { builtInName = null } = {}) {
|
|
462
|
+
let prompt;
|
|
463
|
+
if (builtInName) {
|
|
464
|
+
// Built-in prompt đã đầy đủ PLAN + 4 bước thực thi — KHÔNG wrap thêm skill.
|
|
465
|
+
prompt = userRequest;
|
|
466
|
+
} else {
|
|
467
|
+
const skill = loadSkill("dynamic-workflows");
|
|
468
|
+
if (!skill) return console.log(c.err(" " + (t.workflowNoSkill || "Không tìm thấy skill dynamic-workflows")));
|
|
469
|
+
// Enforce PLAN xuất hiện TRƯỚC khi spawn bằng cách gộp vào bước 1 và yêu cầu
|
|
470
|
+
// output. Model hay skip bước này → user mất visibility vào plan.
|
|
471
|
+
prompt = `Bạn đang thực thi SKILL "dynamic-workflows". Đọc kỹ playbook dưới đây và TUÂN THỦ khi orchestrate multi-agent workflow.
|
|
472
|
+
|
|
473
|
+
=== SKILL: dynamic-workflows ===
|
|
474
|
+
${skill}
|
|
475
|
+
=== HẾT SKILL ===
|
|
476
|
+
|
|
477
|
+
YÊU CẦU NGƯỜI DÙNG:
|
|
478
|
+
${userRequest}
|
|
479
|
+
|
|
480
|
+
Thực thi THEO ĐÚNG THỨ TỰ (BẮT BUỘC):
|
|
481
|
+
1. **PLAN (xuất ra TRƯỚC khi spawn bất kỳ sub-agent nào)** — bullet list ≤ 7 gạch:
|
|
482
|
+
- Sub-tasks cần làm
|
|
483
|
+
- Nhánh nào SONG SONG (spawn_agents) vs TUẦN TỰ (spawn_agent)
|
|
484
|
+
- Pattern chính (1 trong 6: classify-and-act / fan-out-synthesize / adversarial-verification / generate-and-filter / tournament / loop-until-done) + vì sao
|
|
485
|
+
- Nếu dùng fan-out-synthesize: nhắc rõ "synthesize step LÀ BARRIER" — đợi tất cả fan-out xong mới merge
|
|
486
|
+
- Synthesis step + stop condition
|
|
487
|
+
Viết plan RA trước, user cần thấy.
|
|
488
|
+
2. Spawn sub-agent theo plan — mỗi prompt sub-agent có 5 mục GOAL/INPUTS/METHOD/OUTPUT SHAPE/STOP CONDITION.
|
|
489
|
+
3. Gom kết quả, dedupe, reconcile mâu thuẫn, viết báo cáo cuối tiếng Việt. Sub-agent KHÔNG nói trực tiếp với user.`;
|
|
490
|
+
}
|
|
444
491
|
if (!state.agent) {
|
|
445
492
|
// Đừng tự bật — workflow cần spawn_agent, đây là quyền nặng (sub-agent chạy
|
|
446
493
|
// tool độc lập). Hỏi 1 lần, user chọn y thì bật & chạy, n thì huỷ sạch +
|
|
@@ -452,41 +499,117 @@ Thực thi: đọc/tạo file cần thiết bằng tool, viết code production-
|
|
|
452
499
|
state.agent = true;
|
|
453
500
|
console.log(c.tool(" ✓ " + (t.workflowAgentEnabled || "đã bật agent mode cho workflow này.")));
|
|
454
501
|
}
|
|
455
|
-
const prompt = `Bạn đang thực thi SKILL "dynamic-workflows". Đọc kỹ playbook dưới đây và TUÂN THỦ khi orchestrate multi-agent workflow.
|
|
456
|
-
|
|
457
|
-
=== SKILL: dynamic-workflows ===
|
|
458
|
-
${skill}
|
|
459
|
-
=== HẾT SKILL ===
|
|
460
|
-
|
|
461
|
-
YÊU CẦU NGƯỜI DÙNG:
|
|
462
|
-
${userRequest}
|
|
463
|
-
|
|
464
|
-
Thực thi:
|
|
465
|
-
1. Viết PLAN ngắn (sub-tasks, sequential vs parallel, synthesis step, stop condition).
|
|
466
|
-
2. Spawn sub-agent theo plan — dùng spawn_agents cho công việc song song độc lập, spawn_agent tuần tự khi có phụ thuộc.
|
|
467
|
-
3. Mỗi prompt sub-agent đều có GOAL / INPUTS / METHOD / OUTPUT SHAPE / STOP CONDITION (theo skill).
|
|
468
|
-
4. Gom kết quả, dedupe, reconcile xung đột, viết báo cáo cuối tiếng Việt cho người dùng. Sub-agent KHÔNG nói trực tiếp với user.`;
|
|
469
502
|
console.log(c.tool(" 🎼 " + (t.workflowRunning || "Dynamic workflow running…")));
|
|
470
503
|
await handle(prompt);
|
|
471
504
|
persist();
|
|
472
505
|
}
|
|
473
506
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
507
|
+
// ── Help / patterns / builtins — khối discoverability (v1.9.1+) ─────────
|
|
508
|
+
// Trước đó /workflow không có gì để khám phá: user phải biết syntax sẵn. Giờ
|
|
509
|
+
// empty /workflow hoặc `/workflow help` show menu đầy đủ.
|
|
510
|
+
function workflowHelp() {
|
|
511
|
+
console.log(c.tool(" " + (t.workflowHelpTitle || "🎼 /workflow — orchestrate multi-agent workflow")));
|
|
512
|
+
console.log(c.dim(" " + (t.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.")));
|
|
513
|
+
console.log("");
|
|
514
|
+
console.log(c.accent(" Cú pháp:"));
|
|
515
|
+
console.log(" /workflow <yêu cầu> chạy ad-hoc (model tự design workflow)");
|
|
516
|
+
console.log(" /workflow help | ? menu này");
|
|
517
|
+
console.log(" /workflow patterns 6 pattern workflow (theo article Thariq)");
|
|
518
|
+
console.log(" /workflow builtins 3 workflow built-in có sẵn");
|
|
519
|
+
console.log(" /workflow list workflow đã lưu");
|
|
520
|
+
console.log(" /workflow save <name> <req> lưu prompt template → ~/.noob/workflows/");
|
|
521
|
+
console.log(" /workflow load <name> xem nội dung (saved hoặc built-in)");
|
|
522
|
+
console.log(" /workflow run <name> [extra] chạy (built-in HOẶC saved, có thể thêm ngữ cảnh)");
|
|
523
|
+
console.log(" /workflow delete|rm <name> xoá workflow đã lưu");
|
|
524
|
+
console.log("");
|
|
525
|
+
console.log(c.accent(" Nhanh nhất để thử:"));
|
|
526
|
+
console.log(" " + c.dim("/workflow builtins ") + "xem có sẵn cái nào");
|
|
527
|
+
console.log(" " + c.dim("/workflow run deep-research \"async-await trong Python\"") + " chạy ngay");
|
|
528
|
+
console.log(" " + c.dim("/workflow run verify-claims README.md ") + "verify claim trong tài liệu");
|
|
529
|
+
console.log("");
|
|
530
|
+
console.log(c.dim(" 💡 Repeatable workflow (triage, research, verify) — pair với /loop <interval> + /goal <text>"));
|
|
531
|
+
console.log("");
|
|
532
|
+
workflowBuiltins({ compact: true });
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Liệt kê 6 pattern từ article Thariq (L83-109). Mỗi pattern 1 dòng — user
|
|
536
|
+
// scan nhanh chọn pattern phù hợp task. Trước đó tôi liệt kê 7 (thêm
|
|
537
|
+
// "Diverse-Hypothesis Debug" tự bịa) → fix về 6 theo article.
|
|
538
|
+
function workflowPatterns() {
|
|
539
|
+
const PATTERNS = [
|
|
540
|
+
["Classify-and-act", "classifier phân loại task → route tới sub-agent chuyên dụng. HOẶC classifier ở cuối để check output. Khi: input không đồng nhất, mỗi loại cần chiến lược khác."],
|
|
541
|
+
["Fan-out-and-synthesize", "task lớn chia N nhánh độc lập song song → gom kết quả. SYNTHESIZE STEP LÀ BARRIER (article L93): đợi tất cả fan-out xong mới merge. Khi: partition rõ theo file/module/khía cạnh."],
|
|
542
|
+
["Adversarial verification", "1 agent LÀM, 1 agent KHÁC verify output chống rubric/criteria. Khi: claim cần verify, code rủi ro, quyết định khó đảo."],
|
|
543
|
+
["Generate-and-filter", "sinh nhiều phương án song song → 1 agent lọc theo rubric/verify → dedupe → trả về top. Khi: bài toán mở, cần đa dạng giải pháp đã verify."],
|
|
544
|
+
["Tournament", "N agents CÙNG LÀM 1 task với approach khác nhau → judge pairwise cho tới khi có winner. Pairwise comparison reliable hơn absolute scoring. Khi: cần ranking/rubric, hoặc bài toán 'taste' (naming, design)."],
|
|
545
|
+
["Loop-until-done", "sub-agent làm 1 vòng, parent check stop condition (no new findings / no more errors), chưa đạt → spawn lại. Khi: lượng work không biết trước, có metric đo được."],
|
|
546
|
+
];
|
|
547
|
+
console.log(c.tool(" " + (t.workflowPatternsTitle || "🎼 6 pattern workflow (theo article Thariq — A harness for every task)")));
|
|
548
|
+
PATTERNS.forEach(([name, desc], i) => {
|
|
549
|
+
console.log(" " + c.accent(`${i + 1}. ${name}`));
|
|
550
|
+
console.log(" " + c.dim(desc));
|
|
551
|
+
});
|
|
552
|
+
console.log("");
|
|
553
|
+
console.log(c.dim(" Tổ hợp: 1 workflow có thể compose nhiều pattern (vd triage = classify-and-act + loop-until-done + quarantine)."));
|
|
554
|
+
console.log(c.dim(" Lưu ý (article L165-167): workflow KHÔNG cần cho mọi task — tốn nhiều token. Việc < vài file → tự làm."));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Liệt kê built-in workflow có sẵn trong source. Built-in là 3 mẫu ship sẵn
|
|
558
|
+
// để user `run` ngay, không phải tự viết. `compact=true` dùng trong help để
|
|
559
|
+
// khỏi tốn dòng; default = list đầy đủ pattern + description.
|
|
560
|
+
function workflowBuiltins({ compact = false } = {}) {
|
|
561
|
+
const items = listBuiltinWorkflows();
|
|
562
|
+
if (!compact) {
|
|
563
|
+
console.log(c.tool(" " + (t.workflowBuiltinsTitle || `🎼 Workflow built-in (${items.length} mẫu ship sẵn):`)));
|
|
564
|
+
} else {
|
|
565
|
+
console.log(c.accent(" Built-in workflow:"));
|
|
479
566
|
}
|
|
567
|
+
for (const w of items) {
|
|
568
|
+
console.log(" " + c.accent("/workflow run " + w.name) + c.dim(" · " + w.pattern));
|
|
569
|
+
if (!compact) console.log(" " + c.dim(w.description));
|
|
570
|
+
}
|
|
571
|
+
if (!compact) {
|
|
572
|
+
console.log("");
|
|
573
|
+
console.log(c.dim(" Chạy: /workflow run <name> [input]. VD: /workflow run verify-claims README.md"));
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function workflowList() {
|
|
578
|
+
const saved = listWorkflows();
|
|
579
|
+
const builtins = listBuiltinWorkflows();
|
|
580
|
+
// Luôn show cả 2 nhóm — built-in quan trọng vì user quên chúng có sẵn.
|
|
480
581
|
console.log(c.tool(" " + (t.workflowListHeader ? t.workflowListHeader(workflowsDir()) : `Workflow đã lưu (${workflowsDir()}):`)));
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
582
|
+
if (saved.length) {
|
|
583
|
+
for (const it of saved) {
|
|
584
|
+
const desc = it.description ? c.dim(" — " + it.description) : "";
|
|
585
|
+
const date = it.updated ? c.dim(" [" + it.updated.slice(0, 10) + "]") : "";
|
|
586
|
+
console.log(" " + c.accent(it.name) + desc + date);
|
|
587
|
+
}
|
|
588
|
+
} else {
|
|
589
|
+
console.log(c.dim(" (chưa có — /workflow save <name> <yêu cầu> để tạo)"));
|
|
485
590
|
}
|
|
591
|
+
console.log("");
|
|
592
|
+
console.log(c.accent(" Built-in workflow (chạy ngay, không cần save):"));
|
|
593
|
+
for (const w of builtins) {
|
|
594
|
+
console.log(" " + c.accent("/workflow run " + w.name) + c.dim(" · " + w.title));
|
|
595
|
+
}
|
|
596
|
+
console.log("");
|
|
597
|
+
console.log(c.dim(" Dùng: /workflow <yêu cầu> hoặc /workflow run <name> [input] hoặc /workflow help"));
|
|
486
598
|
}
|
|
487
599
|
|
|
488
600
|
function workflowLoad(name) {
|
|
489
601
|
if (!name) return console.log(c.err(" " + (t.workflowLoadNeedName || "Cách dùng: /workflow load <name>")));
|
|
602
|
+
// Check built-in trước — user có thể quên chúng có sẵn.
|
|
603
|
+
const builtin = getBuiltinWorkflow(name);
|
|
604
|
+
if (builtin) {
|
|
605
|
+
console.log(c.tool(" " + `🎼 Built-in workflow '${builtin.name}' — ${builtin.title}`));
|
|
606
|
+
console.log(c.dim(" pattern: " + builtin.pattern));
|
|
607
|
+
console.log(c.dim(" " + builtin.description));
|
|
608
|
+
console.log("");
|
|
609
|
+
console.log(c.dim(" ── prompt template (chạy bằng /workflow run " + builtin.name + " <input>) ──"));
|
|
610
|
+
console.log(builtin.buildPrompt("<input>"));
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
490
613
|
const r = loadWorkflow(name);
|
|
491
614
|
if (!r.ok) return console.log(c.err(" " + (t.workflowLoadError ? t.workflowLoadError(name, r.error) : `Không nạp được workflow '${name}': ${r.error}`)));
|
|
492
615
|
console.log(c.tool(" " + (t.workflowLoadOk ? t.workflowLoadOk(r.name, r.path) : `Workflow '${r.name}' (${r.path}):`)));
|
|
@@ -498,6 +621,9 @@ Thực thi:
|
|
|
498
621
|
|
|
499
622
|
function workflowDelete(name) {
|
|
500
623
|
if (!name) return console.log(c.err(" " + (t.workflowDeleteNeedName || "Cách dùng: /workflow delete <name>")));
|
|
624
|
+
// Chỉ xoá saved — built-in không xoá được.
|
|
625
|
+
const builtin = getBuiltinWorkflow(name);
|
|
626
|
+
if (builtin) return console.log(c.err(" " + (t.workflowDeleteBuiltIn ? t.workflowDeleteBuiltIn(name) : `'${name}' là built-in workflow, không xoá được.`)));
|
|
501
627
|
const r = deleteWorkflow(name);
|
|
502
628
|
if (!r.ok) return console.log(c.err(" " + (t.workflowDeleteError ? t.workflowDeleteError(name, r.error) : `Không xoá được workflow '${name}': ${r.error}`)));
|
|
503
629
|
console.log(c.tool(" " + (t.workflowDeleteOk ? t.workflowDeleteOk(name) : `Đã xoá workflow '${name}'.`)));
|
|
@@ -509,6 +635,7 @@ Thực thi:
|
|
|
509
635
|
if (!m) return console.log(c.err(" " + (t.workflowSaveNeedArgs || "Cách dùng: /workflow save <name> <yêu cầu workflow>")));
|
|
510
636
|
const name = m[1];
|
|
511
637
|
const prompt = m[2].trim();
|
|
638
|
+
if (!prompt) return console.log(c.err(" " + (t.workflowSaveEmptyPrompt || "Thiếu yêu cầu workflow. VD: /workflow save code-audit-security \"audit src/ tìm SQL injection\"")));
|
|
512
639
|
const r = saveWorkflow(name, prompt);
|
|
513
640
|
if (!r.ok) {
|
|
514
641
|
const msg = r.error === "invalid_name"
|
|
@@ -517,17 +644,65 @@ Thực thi:
|
|
|
517
644
|
return console.log(c.err(" " + msg));
|
|
518
645
|
}
|
|
519
646
|
console.log(c.tool(" 💾 " + (t.workflowSaveOk ? t.workflowSaveOk(name, r.path) : `Đã lưu workflow '${name}' → ${r.path}`)));
|
|
647
|
+
// Hỏi thêm description (1 dòng) — list/load sau này có ích, user nhìn 1 dòng
|
|
648
|
+
// là biết workflow này làm gì. Không bắt buộc: n / Enter = skip.
|
|
649
|
+
return maybeAskWorkflowDescription(name, prompt);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Hỏi user có muốn thêm description cho workflow vừa lưu không. Nếu y → ask
|
|
653
|
+
// 1 dòng rồi saveWorkflow lại (ghi đè file, description vào front-matter).
|
|
654
|
+
// Tái sử dụng pattern ask() + pending.push (paste-spam protection).
|
|
655
|
+
async function maybeAskWorkflowDescription(name, currentPrompt) {
|
|
656
|
+
tui.setBusy(false);
|
|
657
|
+
try {
|
|
658
|
+
const raw = await ask(c.tool(" " + (t.workflowSaveAskDesc || "thêm mô tả ngắn để dễ tìm sau này? [y/n] › ")) + c.dim("(y = hỏi 1 dòng, phím khác = bỏ qua) "));
|
|
659
|
+
if (raw == null) return; // stdin đóng
|
|
660
|
+
const a = raw.trim().toLowerCase();
|
|
661
|
+
if (a !== "y" && a !== "yes" && a !== "có") {
|
|
662
|
+
console.log(c.dim(" " + (t.workflowSaveDescSkipped || "(bỏ qua description — có thể thêm sau bằng cách save lại)")));
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const descRaw = await ask(c.tool(" " + (t.workflowSaveDescPrompt || "mô tả (1 dòng): ")));
|
|
666
|
+
if (descRaw == null) return;
|
|
667
|
+
const desc = descRaw.trim();
|
|
668
|
+
if (!desc) {
|
|
669
|
+
console.log(c.dim(" (description trống — bỏ qua)"));
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
const r2 = saveWorkflow(name, currentPrompt, { description: desc });
|
|
673
|
+
if (r2.ok) console.log(c.ok(" ✓ " + (t.workflowSaveDescOk ? t.workflowSaveDescOk(name, desc) : `Đã thêm mô tả cho '${name}': ${desc}`)));
|
|
674
|
+
} catch (e) {
|
|
675
|
+
console.log(c.dim(" (lỗi thêm description, workflow vẫn được lưu)"));
|
|
676
|
+
} finally {
|
|
677
|
+
tui.setBusy(true, t.thinking);
|
|
678
|
+
}
|
|
520
679
|
}
|
|
521
680
|
|
|
522
681
|
async function workflowRun(rest) {
|
|
523
682
|
if (!rest) return console.log(c.err(" " + (t.workflowRunNeedName || "Cách dùng: /workflow run <name> [thêm ngữ cảnh]")));
|
|
683
|
+
// Tách name (1 từ, kebab-case theo sanitize) + extra context phần còn lại.
|
|
524
684
|
const m = rest.match(/^(\S+)(?:\s+([\s\S]+))?$/);
|
|
525
685
|
const name = m[1];
|
|
526
686
|
const extra = (m[2] || "").trim();
|
|
687
|
+
// Built-in trước — user có thể gõ `run deep-research ...` mà quên đó là built-in.
|
|
688
|
+
const builtin = getBuiltinWorkflow(name);
|
|
689
|
+
if (builtin) {
|
|
690
|
+
const userInput = extra || c.dim("(không có input — workflow sẽ chạy với placeholder)");
|
|
691
|
+
const prompt = builtin.buildPrompt(userInput);
|
|
692
|
+
console.log(c.tool(" ▶️ " + (t.workflowRunPreviewBuiltin ? t.workflowRunPreviewBuiltin(name, builtin.title) : `Built-in workflow '${name}' (${builtin.title}) — pattern: ${builtin.pattern}`)));
|
|
693
|
+
console.log(c.dim(" input: " + truncate(userInput, 80)));
|
|
694
|
+
console.log(c.dim(" prompt: " + prompt.length + " chars"));
|
|
695
|
+
return await workflowExecute(prompt, { builtInName: name });
|
|
696
|
+
}
|
|
527
697
|
const r = loadWorkflow(name);
|
|
528
698
|
if (!r.ok) return console.log(c.err(" " + (t.workflowRunError ? t.workflowRunError(name, r.error) : `Không nạp được workflow '${name}': ${r.error}`)));
|
|
529
699
|
const userRequest = extra ? `${r.prompt}\n\nNgữ cảnh bổ sung cho lần chạy này:\n${extra}` : r.prompt;
|
|
530
|
-
|
|
700
|
+
// Preview banner trước khi execute — user verify "đúng cái mình muốn" trước
|
|
701
|
+
// khi bỏ 30s+ chờ. Tránh case user gõ nhầm `run my-workflow` thành
|
|
702
|
+
// `run my-workflw` (saved khác) và mất 1 phút mới biết.
|
|
703
|
+
console.log(c.tool(" ▶️ " + (t.workflowRunPreviewSaved ? t.workflowRunPreviewSaved(name) : `Workflow đã lưu '${name}'`)));
|
|
704
|
+
console.log(c.dim(" prompt: " + r.prompt.length + " chars · " + (r.meta.description || "(chưa có description)")));
|
|
705
|
+
if (extra) console.log(c.dim(" extra context: " + truncate(extra, 80)));
|
|
531
706
|
await workflowExecute(userRequest);
|
|
532
707
|
}
|
|
533
708
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Built-in workflow templates — ship sẵn để user `run` ngay mà không phải tự
|
|
2
|
+
// viết. 3 mẫu khớp VỚI 3 example prompts Thariq nêu trong bài "A harness for
|
|
3
|
+
// every task: dynamic workflows in Claude Code":
|
|
4
|
+
// • deep-research — `/deep-research` skill nội bộ Claude Code (article L121).
|
|
5
|
+
// Fan-out web/code search + adversarial verify + synthesize cited report.
|
|
6
|
+
// • verify-claims — example L45/L127: "Go through my blog post draft and
|
|
7
|
+
// using a workflow verify every technical claim against the codebase."
|
|
8
|
+
// Adversarial verification pattern: 1 agent list claims, N agent verify.
|
|
9
|
+
// • triage — article L147-153: "Pair triage workflows with /loop". Classify
|
|
10
|
+
// + dedupe + route, với QUARANTINE (article L151): agent đọc untrusted
|
|
11
|
+
// content KHÔNG được gọi tool destructive — chỉ route đề xuất, parent mới
|
|
12
|
+
// thực thi.
|
|
13
|
+
//
|
|
14
|
+
// Mỗi built-in trả về string prompt hoàn chỉnh (KHÔNG load lại skill
|
|
15
|
+
// dynamic-workflows — built-in đã hardcode pattern + step cụ thể rồi).
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} BuiltinWorkflow
|
|
19
|
+
* @property {string} name — id (kebab-case, dùng cho `run <name>`)
|
|
20
|
+
* @property {string} title — tiêu đề hiển thị trong `/workflow builtins`
|
|
21
|
+
* @property {string} pattern — pattern chính theo article
|
|
22
|
+
* @property {string} description — 1-2 dòng tóm tắt
|
|
23
|
+
* @property {string} buildPrompt — (userInput: string) => string prompt hoàn chỉnh
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** @type {BuiltinWorkflow[]} */
|
|
27
|
+
export const BUILTIN_WORKFLOWS = [
|
|
28
|
+
{
|
|
29
|
+
name: "deep-research",
|
|
30
|
+
title: "Deep Research",
|
|
31
|
+
pattern: "Fan-out-and-Synthesize + Adversarial Verification",
|
|
32
|
+
description:
|
|
33
|
+
"Đào sâu 1 chủ đề: fan-out N search song song, mỗi search có adversarial verify, parent synthesize báo cáo có trích dẫn.",
|
|
34
|
+
buildPrompt: (topic) => `Bạn đang chạy workflow DEEP-RESEARCH (built-in) cho chủ đề: ${topic}
|
|
35
|
+
|
|
36
|
+
Mục tiêu: báo cáo TIẾNG VIỆT có trích dẫn, mỗi claim đã được verify chống nguồn gốc, parent tổng hợp từ ≥3 sub-agent độc lập.
|
|
37
|
+
|
|
38
|
+
Thực thi ĐÚNG thứ tự (4 bước):
|
|
39
|
+
1. **PLAN** (xuất ra TRƯỚC khi spawn sub-agent nào, ≤ 5 gạch đầu dòng): chia chủ đề thành N=3–5 nhánh độc lập (vd "lịch sử", "hiện trạng", "ưu nhược", "use case", "rủi ro"). Mỗi nhánh = 1 sub-agent.
|
|
40
|
+
2. **FAN-OUT** (spawn_agents SONG SONG): mỗi sub-agent có GOAL / INPUTS / METHOD / OUTPUT SHAPE / STOP CONDITION đầy đủ (xem SKILL dynamic-workflows). OUTPUT SHAPE BẮT BUỘC: "≤ 800 token bullet list, mỗi fact kèm [source: <url hoặc tên file>], tuyệt đối KHÔNG bịa URL".
|
|
41
|
+
3. **ADVERSARIAL VERIFY**: 1 sub-agent phản biện đọc output của TẤT CẢ sub-agent trên, đánh dấu [✓ verified] / [⚠ chưa verify được] / [✗ nghi ngờ sai] cho từng fact. Source nào không truy cập được → đánh dấu ngay, KHÔNG tự suy.
|
|
42
|
+
4. **SYNTHESIZE** — BƯỚC NÀY LÀ BARRIER: phải ĐỢI TẤT CẢ fan-out + verify xong mới gom. Gom output + verify marker → báo cáo cuối tiếng Việt có cấu trúc:
|
|
43
|
+
- Tóm tắt 1 đoạn
|
|
44
|
+
- Findings chính (có trích dẫn [n])
|
|
45
|
+
- Điểm còn tranh cãi / chưa verify
|
|
46
|
+
- Nguồn tham khảo (list URL)
|
|
47
|
+
Báo cáo cuối PHẢI nêu rõ fact nào đã verify, fact nào chưa — user quyết định có tin hay không.
|
|
48
|
+
|
|
49
|
+
Không spawn reader agent đọc nguồn untrusted nếu không cần — chỉ spawn search/verify agent. KHÔNG tự đoán URL.
|
|
50
|
+
|
|
51
|
+
💡 Repeatable? Thêm \`/loop <interval>\` để chạy lặp, \`/goal <text>\` để set hard completion requirement.`,
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
name: "verify-claims",
|
|
56
|
+
title: "Verify Claims",
|
|
57
|
+
pattern: "Adversarial Verification",
|
|
58
|
+
description:
|
|
59
|
+
"Verify mọi technical claim trong 1 tài liệu (blog/code/README) chống codebase thật: 1 agent list claims, N agent verify từng claim.",
|
|
60
|
+
buildPrompt: (target) => `Bạn đang chạy workflow VERIFY-CLAIMS (built-in) cho tài liệu: ${target || "(user chưa chỉ rõ — dùng context gần nhất)"}
|
|
61
|
+
|
|
62
|
+
Mục tiêu: với MỖI technical claim trong tài liệu, xác minh chống codebase THẬT (bằng read_file/grep/run_command), đánh dấu [✓ đúng] / [✗ sai] / [⚠ cần verify thêm]. Báo cáo cuối: claim nào sai → user phải sửa trước khi ship.
|
|
63
|
+
|
|
64
|
+
Thực thi ĐÚNG thứ tự (4 bước):
|
|
65
|
+
1. **PLAN**: đọc tài liệu (read_file). Liệt kê tất cả technical claim (vd "function X trả về Y", "class Z có method W", "API endpoint A chấp nhận B"). Nếu < 5 claim → chạy tuần tự. Nếu ≥ 5 → fan-out theo claim.
|
|
66
|
+
2. **LIST CLAIMS** (1 sub-agent, KHÔNG cần verify): output bảng [claim_id] [claim_text] [relevant file/module hint].
|
|
67
|
+
3. **ADVERSARIAL VERIFY** (N sub-agent SONG SONG, mỗi cái verify 1 nhóm claim): với MỖI claim, tìm trong codebase bằng read_file/grep. Output [claim_id] [verdict: ✓ đúng / ✗ sai / ⚠ cần verify thêm] [evidence: <file:line trích dẫn>] [1-câu giải thích].
|
|
68
|
+
4. **SYNTHESIZE** — báo cáo cuối tiếng Việt:
|
|
69
|
+
- Tóm tắt (tổng claim, bao nhiêu đúng/sai/cần verify)
|
|
70
|
+
- ✗ Claims SAI (kèm evidence — user ưu tiên sửa)
|
|
71
|
+
- ⚠ Claims cần verify thêm
|
|
72
|
+
- ✓ Claims đúng
|
|
73
|
+
Mỗi verdict có "file:line" cụ thể. KHÔNG bịa evidence — nếu không tìm thấy, nói "không tìm thấy trong codebase".
|
|
74
|
+
|
|
75
|
+
KHÔNG tự sửa tài liệu — chỉ report. User quyết định sửa.`,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
{
|
|
79
|
+
name: "triage",
|
|
80
|
+
title: "Triage Queue",
|
|
81
|
+
pattern: "Classify-and-Route + Quarantine",
|
|
82
|
+
description:
|
|
83
|
+
"Phân loại 1 danh sách item (ticket/bug/idea): classify + dedupe + route. Pair với /loop. QUARANTINE: agent đọc untrusted content KHÔNG gọi tool destructive.",
|
|
84
|
+
buildPrompt: (input) => `Bạn đang chạy workflow TRIAGE (built-in) cho input: ${input}
|
|
85
|
+
|
|
86
|
+
Mục tiêu: phân loại MỖI item trong input, dedupe với nhau + với context đã biết, route hành động (auto-fix/escalate-to-human/defer/drop). Áp dụng QUARANTINE pattern (article L151): agent đọc untrusted content KHÔNG ĐƯỢC gọi tool có high-privilege — chỉ route đề xuất, parent mới thực thi.
|
|
87
|
+
|
|
88
|
+
Thực thi ĐÚNG thứ tự (4 bước):
|
|
89
|
+
1. **PLAN**: xác định input là gì (1 danh sách item? file CSV? raw text?). Nếu input > 20 item → cân nhắc Loop-Until-Done, mỗi vòng 5–10 item.
|
|
90
|
+
2. **CLASSIFY** (1 sub-agent, READER ROLE — KHÔNG ĐƯỢC gọi write_file/edit_file/run_command có side-effect. Đây là QUARANTINE.): đọc input, phân loại mỗi item theo:
|
|
91
|
+
- **Category**: bug / feature-request / question / duplicate / spam / out-of-scope.
|
|
92
|
+
- **Severity** (chỉ bug): 🔴 P0 / 🟡 P1 / 🔵 P2.
|
|
93
|
+
- **Suggested action**: auto-fix / escalate-to-human / defer / drop.
|
|
94
|
+
OUTPUT SHAPE: bảng markdown, cột: [item_id] [category] [severity] [action] [1-câu lý do].
|
|
95
|
+
3. **DEDUPE** (1 sub-agent khác): đọc output classify + context đã biết (noob.md, git log gần đây), tìm item trùng → gộp, giữ lại id gốc + reference id trùng.
|
|
96
|
+
4. **ROUTE — PARENT MỚI THỰC THI** (article L151: high-privilege action do parent — agent chịu trách nhiệm về thông tin — làm, KHÔNG phải reader agent):
|
|
97
|
+
- Tóm tắt (tổng item, phân bổ category/severity)
|
|
98
|
+
- 🔴 P0 cần fix ngay (nếu có)
|
|
99
|
+
- 🟡 P1 + 🟢 P2 (gom nhóm nếu nhiều)
|
|
100
|
+
- Dropped (spam/duplicate/out-of-scope) + lý do
|
|
101
|
+
- Action items cho user (manual)
|
|
102
|
+
Nếu action = auto-fix → parent TỰ gọi write_file/edit_file (KHÔNG phải classify agent). Nếu escalate → in note cho user.
|
|
103
|
+
|
|
104
|
+
QUARANTINE REMINDER: classify/dedupe agent chỉ ĐỌC. Mọi tool có side-effect (write_file/edit_file/run_command thay đổi hệ thống) đều do parent gọi.
|
|
105
|
+
|
|
106
|
+
💡 Repeatable? Thêm \`/loop <interval>\` để chạy queue liên tục (article L153). \`/goal <text>\` để set completion requirement.`,
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
export function listBuiltinWorkflows() {
|
|
111
|
+
return BUILTIN_WORKFLOWS.map((w) => ({
|
|
112
|
+
name: w.name,
|
|
113
|
+
title: w.title,
|
|
114
|
+
pattern: w.pattern,
|
|
115
|
+
description: w.description,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getBuiltinWorkflow(name) {
|
|
120
|
+
return BUILTIN_WORKFLOWS.find((w) => w.name === name) || null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function loadBuiltinPrompt(name, userInput) {
|
|
124
|
+
const wf = getBuiltinWorkflow(name);
|
|
125
|
+
if (!wf) return null;
|
|
126
|
+
return wf.buildPrompt(userInput || "");
|
|
127
|
+
}
|