@leejungkiin/awkit 1.7.7 → 1.7.8

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/bin/awk.js CHANGED
@@ -48,6 +48,7 @@ const { cmdI18n } = require('../scripts/i18n-helper');
48
48
  const { cmdStorage } = require('../scripts/artifact-storage');
49
49
  const { cmdPipeline } = require('../scripts/multi-model-pipeline');
50
50
  const depManager = require('../scripts/dependency-manager');
51
+ const rtkRuntime = require('../scripts/exec-rtk');
51
52
 
52
53
 
53
54
  // ─── Platform Definitions ──────────────────────────────────────────────────
@@ -488,32 +489,31 @@ function flattenWorkflows(srcBase, destDir) {
488
489
  }
489
490
 
490
491
  /**
491
- * Install or update GEMINI.md into ~/.gemini/
492
+ * Install or update GEMINI.md into Antigravity rule locations.
492
493
  */
493
494
  function syncGeminiMd() {
494
495
  const srcGemini = path.join(AWK_ROOT, 'core', 'GEMINI.md');
495
- const destGemini = TARGETS.geminiMd;
496
+ const primaryDest = TARGETS.geminiMd;
497
+ const legacyDest = path.join(PLATFORMS.antigravity.globalRoot, 'GEMINI.md');
498
+ const destinations = [...new Set([primaryDest, legacyDest])];
496
499
 
497
- const destDir = path.dirname(destGemini);
498
- if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
500
+ for (const destGemini of destinations) {
501
+ const destDir = path.dirname(destGemini);
502
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
499
503
 
500
- // Read existing GEMINI.md if present
501
- let existingContent = '';
502
- if (fs.existsSync(destGemini)) {
503
- existingContent = fs.readFileSync(destGemini, 'utf8');
504
+ if (fs.existsSync(destGemini)) {
505
+ const backupDir = path.join(PLATFORMS.antigravity.globalRoot, 'backup');
506
+ if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
504
507
 
505
- // Backup existing
506
- const backupDir = path.join(destDir, 'antigravity', 'backup');
507
- if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
508
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
509
+ const label = destGemini === legacyDest ? 'GEMINI_legacy' : 'GEMINI';
510
+ const backupPath = path.join(backupDir, `${label}_${timestamp}.md.bak`);
511
+ fs.copyFileSync(destGemini, backupPath);
512
+ dim(`Backup: ${backupPath}`);
513
+ }
508
514
 
509
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
510
- const backupPath = path.join(backupDir, `GEMINI_${timestamp}.md.bak`);
511
- fs.copyFileSync(destGemini, backupPath);
512
- dim(`Backup: ${backupPath}`);
515
+ fs.copyFileSync(srcGemini, destGemini);
513
516
  }
514
-
515
- // Copy new GEMINI.md
516
- fs.copyFileSync(srcGemini, destGemini);
517
517
  ok('GEMINI.md updated');
518
518
  }
519
519
 
@@ -1030,16 +1030,12 @@ async function cmdDoctor() {
1030
1030
  warn('schemas/ directory missing'); issues++;
1031
1031
  }
1032
1032
 
1033
- // 4.5. Check RTK & GitNexus Integration
1033
+ // 4.5. Check optional RTK & GitNexus Integration
1034
1034
  if (depManager.checkRtk()) {
1035
- ok(`RTK (Rust Token Killer) is installed (v${depManager.getRtkVersion() || 'unknown'})`);
1035
+ const rtkMode = rtkRuntime.getRtkMode();
1036
+ ok(`RTK (Rust Token Killer) is installed (v${depManager.getRtkVersion() || 'unknown'}, mode: ${rtkMode.mode})`);
1036
1037
  } else {
1037
- warn('RTK (Rust Token Killer) not found.');
1038
- if (promptYN('Would you like to install RTK automatically now?')) {
1039
- depManager.installRtk();
1040
- } else {
1041
- issues++;
1042
- }
1038
+ warn('RTK (Rust Token Killer) not found. Optional: run `awkit rtk setup`.');
1043
1039
  }
1044
1040
 
1045
1041
  if (depManager.checkGitnexus()) {
@@ -1073,7 +1069,8 @@ async function cmdDoctor() {
1073
1069
  ok('AWKit is up-to-date');
1074
1070
  }
1075
1071
 
1076
- const currentRtk = depManager.getRtkVersion();
1072
+ const currentRtkMode = rtkRuntime.getRtkMode();
1073
+ const currentRtk = currentRtkMode.mode === 'off' ? null : depManager.getRtkVersion();
1077
1074
  if (updates.latestRtk && currentRtk && isNewerVersion(updates.latestRtk, currentRtk)) {
1078
1075
  warn(`RTK update available: v${updates.latestRtk} (current: v${currentRtk})`);
1079
1076
  } else if (currentRtk) {
@@ -2339,7 +2336,7 @@ function cmdHelp() {
2339
2336
  log(` ${C.green}update${C.reset} Pull latest + reinstall`);
2340
2337
  log(` ${C.green}lint${C.reset} Run skill & workflow guards (check length, frontmatter)`);
2341
2338
  log(` ${C.green}doctor${C.reset} Check installation health`);
2342
- log(` ${C.green}rtk setup${C.reset} Auto-install and configure RTK wrapper`);
2339
+ log(` ${C.green}rtk status|setup|off${C.reset} Manage RTK output compression`);
2343
2340
  log(` ${C.green}credentials list${C.reset} List stored API keys`);
2344
2341
  log(` ${C.green}credentials set${C.reset} <k> <v> Set API key (e.g., gemini_api_key, openrouter_api_key)`);
2345
2342
  log(` ${C.green}set-openrouter${C.reset} <key> Shorthand for setting OpenRouter API Key`);
@@ -4133,7 +4130,8 @@ async function checkAutoUpdate() {
4133
4130
  log('');
4134
4131
  }
4135
4132
 
4136
- const currentRtk = depManager.getRtkVersion();
4133
+ const currentRtkMode = rtkRuntime.getRtkMode();
4134
+ const currentRtk = currentRtkMode.mode === 'off' ? null : depManager.getRtkVersion();
4137
4135
  if (updates.latestRtk && currentRtk && isNewerVersion(updates.latestRtk, currentRtk)) {
4138
4136
  log('');
4139
4137
  log(`${C.yellow}${C.bold}🌟 [Thông báo] Có phiên bản mới cho RTK! (v${updates.latestRtk})${C.reset}`);
@@ -4477,35 +4475,12 @@ function cmdGitnexus(args) {
4477
4475
 
4478
4476
  // ─── RTK Integration ──────────────────────────────────────────────────────────
4479
4477
 
4480
- async function cmdRtkSetup() {
4481
- log(`${C.cyan}${C.bold}╔═══════════════════════════════════════════════════════╗${C.reset}`);
4482
- log(`${C.cyan}${C.bold}║ ⚙️ RTK Auto-Setup & Configuration ║${C.reset}`);
4483
- log(`${C.cyan}${C.bold}╚═══════════════════════════════════════════════════════╝${C.reset}`);
4478
+ const RTK_SHELL_MARKER = '# RTK Integration for AI Agents (AWKit)';
4479
+ const RTK_SHELL_END_MARKER = '# End RTK Integration for AI Agents (AWKit)';
4484
4480
 
4485
- const installed = depManager.installRtk();
4486
- if (!installed) return;
4487
-
4488
- const zshrcPath = path.join(HOME, '.zshrc');
4489
- log(`\nConfiguring Shell Aliases in ~/.zshrc...`);
4490
- if (fs.existsSync(zshrcPath)) {
4491
- let zshrc = fs.readFileSync(zshrcPath, 'utf8');
4492
-
4493
- // Clean up old aliases to avoid collision
4494
- const oldAliases = [
4495
- 'alias git="rtk git"',
4496
- 'alias npm="rtk npm"',
4497
- 'alias pnpm="rtk pnpm"',
4498
- 'alias yarn="rtk yarn"',
4499
- 'alias cargo="rtk cargo"'
4500
- ];
4501
- for (const oldAlias of oldAliases) {
4502
- if (zshrc.includes(oldAlias)) {
4503
- zshrc = zshrc.replace(new RegExp(`\\n?${oldAlias}\\n?`, 'g'), '\n');
4504
- }
4505
- }
4506
-
4507
- const functionBlock = `
4508
- # RTK Integration for AI Agents (AWKit)
4481
+ function getRtkShellBlock() {
4482
+ return `
4483
+ ${RTK_SHELL_MARKER}
4509
4484
  unalias npm pnpm yarn cargo git 2>/dev/null
4510
4485
  npm() {
4511
4486
  if [[ "$1" == "login" || "$1" == "adduser" || "$1" == "publish" ]]; then
@@ -4542,19 +4517,130 @@ git() {
4542
4517
  rtk git "$@"
4543
4518
  fi
4544
4519
  }
4520
+ ${RTK_SHELL_END_MARKER}
4545
4521
  `;
4546
- // Clean up old RTK integration block if exists to allow updating
4547
- if (zshrc.includes('# RTK Integration for AI Agents (AWKit)')) {
4548
- const startIdx = zshrc.indexOf('# RTK Integration for AI Agents (AWKit)');
4549
- zshrc = zshrc.substring(0, startIdx);
4522
+ }
4523
+
4524
+ function escapeRegExp(value) {
4525
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4526
+ }
4527
+
4528
+ function stripRtkShellBlock(content) {
4529
+ const oldAliases = [
4530
+ 'alias git="rtk git"',
4531
+ 'alias npm="rtk npm"',
4532
+ 'alias pnpm="rtk pnpm"',
4533
+ 'alias yarn="rtk yarn"',
4534
+ 'alias cargo="rtk cargo"'
4535
+ ];
4536
+ let updated = content;
4537
+ for (const oldAlias of oldAliases) {
4538
+ updated = updated.replace(new RegExp(`^\\s*${escapeRegExp(oldAlias)}\\s*\\n?`, 'gm'), '');
4539
+ }
4540
+
4541
+ const lines = updated.split('\n');
4542
+ const start = lines.findIndex(line => line.trim() === RTK_SHELL_MARKER);
4543
+ if (start === -1) return { content: updated, removed: updated !== content };
4544
+
4545
+ let end = lines.findIndex((line, index) => index >= start && line.trim() === RTK_SHELL_END_MARKER);
4546
+ if (end === -1) {
4547
+ const gitStart = lines.findIndex((line, index) => index >= start && line.trim() === 'git() {');
4548
+ if (gitStart !== -1) {
4549
+ end = lines.findIndex((line, index) => index > gitStart && line.trim() === '}');
4550
4550
  }
4551
-
4552
- zshrc += functionBlock;
4553
- fs.writeFileSync(zshrcPath, zshrc, 'utf8');
4554
- ok('Shell wrappers successfully added/updated in ~/.zshrc.');
4555
- log(`\n${C.cyan}Please reload your shell (source ~/.zshrc) to apply shifts.${C.reset}`);
4556
- } else {
4557
- warn('~/.zshrc not found. Skipping alias setup.');
4551
+ }
4552
+ if (end === -1) return { content: updated, removed: updated !== content };
4553
+
4554
+ lines.splice(start, end - start + 1);
4555
+ return { content: lines.join('\n').replace(/\n{3,}/g, '\n\n'), removed: true };
4556
+ }
4557
+
4558
+ function hasRtkShellBlock() {
4559
+ const zshrcPath = path.join(HOME, '.zshrc');
4560
+ return fs.existsSync(zshrcPath) && fs.readFileSync(zshrcPath, 'utf8').includes(RTK_SHELL_MARKER);
4561
+ }
4562
+
4563
+ function removeRtkShellBlock({ quiet = false } = {}) {
4564
+ const zshrcPath = path.join(HOME, '.zshrc');
4565
+ if (!fs.existsSync(zshrcPath)) {
4566
+ if (!quiet) warn('~/.zshrc not found. Shell wrappers already absent.');
4567
+ return false;
4568
+ }
4569
+
4570
+ const zshrc = fs.readFileSync(zshrcPath, 'utf8');
4571
+ const stripped = stripRtkShellBlock(zshrc);
4572
+ if (!stripped.removed) {
4573
+ if (!quiet) ok('No AWKit RTK shell wrappers found.');
4574
+ return false;
4575
+ }
4576
+
4577
+ fs.writeFileSync(zshrcPath, stripped.content, 'utf8');
4578
+ if (!quiet) ok('AWKit RTK shell wrappers removed from ~/.zshrc.');
4579
+ return true;
4580
+ }
4581
+
4582
+ function installRtkShellBlock() {
4583
+ if (!depManager.checkRtk()) {
4584
+ err('RTK binary not found. Run `awkit rtk setup` first.');
4585
+ return;
4586
+ }
4587
+
4588
+ const zshrcPath = path.join(HOME, '.zshrc');
4589
+ const zshrc = fs.existsSync(zshrcPath) ? fs.readFileSync(zshrcPath, 'utf8') : '';
4590
+ const stripped = stripRtkShellBlock(zshrc).content.trimEnd();
4591
+ fs.writeFileSync(zshrcPath, `${stripped}\n${getRtkShellBlock()}`, 'utf8');
4592
+ ok('Shell wrappers added to ~/.zshrc.');
4593
+ warn('Reload shell with `source ~/.zshrc` to apply.');
4594
+ }
4595
+
4596
+ function cmdRtkStatus() {
4597
+ const mode = rtkRuntime.getRtkMode();
4598
+ const installed = depManager.checkRtk();
4599
+ const separator = `${C.gray}${'─'.repeat(56)}${C.reset}`;
4600
+
4601
+ log(`${C.cyan}${C.bold}RTK Status${C.reset}`);
4602
+ log(separator);
4603
+ log(` Binary: ${installed ? C.green + 'installed' + C.reset : C.yellow + 'not installed' + C.reset}`);
4604
+ if (installed) log(` Version: ${depManager.getRtkVersion() || 'unknown'}`);
4605
+ log(` Mode: ${C.bold}${mode.mode}${C.reset}`);
4606
+ log(` Mode source: ${mode.source}`);
4607
+ log(` Global config:${rtkRuntime.getRtkConfigPath()}`);
4608
+ log(` Shell wrap: ${hasRtkShellBlock() ? C.yellow + 'enabled in ~/.zshrc' + C.reset : C.green + 'off' + C.reset}`);
4609
+ log('');
4610
+ log(` Modes: off = raw AWKit, safe = low-risk compression, proxy = track raw, aggressive = old broad wrappers`);
4611
+ }
4612
+
4613
+ async function cmdRtkSetup() {
4614
+ log(`${C.cyan}${C.bold}╔═══════════════════════════════════════════════════════╗${C.reset}`);
4615
+ log(`${C.cyan}${C.bold}║ RTK Setup & Safe Configuration ║${C.reset}`);
4616
+ log(`${C.cyan}${C.bold}╚═══════════════════════════════════════════════════════╝${C.reset}`);
4617
+
4618
+ const installed = depManager.checkRtk() || depManager.installRtk();
4619
+ if (!installed) return;
4620
+
4621
+ rtkRuntime.setGlobalRtkMode('safe');
4622
+ ok('RTK mode set to safe.');
4623
+ warn('Shell wrappers are opt-in now. Run `awkit rtk shell-on` only if you want git/npm aliases.');
4624
+ cmdRtkStatus();
4625
+ }
4626
+
4627
+ function cmdRtkOff() {
4628
+ rtkRuntime.setGlobalRtkMode('off');
4629
+ removeRtkShellBlock({ quiet: true });
4630
+ ok('RTK disabled globally for AWKit.');
4631
+ warn('Reload shell with `source ~/.zshrc` if wrappers were active.');
4632
+ }
4633
+
4634
+ function cmdRtkMode(mode) {
4635
+ if (!mode) {
4636
+ err(`Usage: awkit rtk mode <${rtkRuntime.VALID_RTK_MODES.join('|')}>`);
4637
+ return;
4638
+ }
4639
+ try {
4640
+ rtkRuntime.setGlobalRtkMode(mode);
4641
+ ok(`RTK mode set to ${mode}.`);
4642
+ } catch (e) {
4643
+ err(e.message);
4558
4644
  }
4559
4645
  }
4560
4646
 
@@ -4562,9 +4648,23 @@ async function cmdRtk(args) {
4562
4648
  const action = args[0];
4563
4649
  if (action === 'setup') {
4564
4650
  await cmdRtkSetup();
4651
+ } else if (!action || action === 'status') {
4652
+ cmdRtkStatus();
4653
+ } else if (action === 'off') {
4654
+ cmdRtkOff();
4655
+ } else if (action === 'on') {
4656
+ cmdRtkMode('safe');
4657
+ } else if (action === 'mode') {
4658
+ cmdRtkMode(args[1]);
4659
+ } else if (rtkRuntime.VALID_RTK_MODES.includes(action)) {
4660
+ cmdRtkMode(action);
4661
+ } else if (action === 'shell-on') {
4662
+ installRtkShellBlock();
4663
+ } else if (action === 'shell-off') {
4664
+ removeRtkShellBlock();
4565
4665
  } else {
4566
4666
  err(`Unknown rtk command: ${action || ''}`);
4567
- log(` Available: setup`);
4667
+ log(` Available: status, setup, off, on, mode, shell-on, shell-off`);
4568
4668
  }
4569
4669
  }
4570
4670
 
package/core/GEMINI.md CHANGED
@@ -123,6 +123,8 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
123
123
  ### Communication (CAVEMAN ULTRA)
124
124
  - Chat: Tiếng Việt, tối đa 1-2 câu ngắn. Code/Docs: Tiếng Anh.
125
125
  - CẤM giải thích dài, chào hỏi. Chỉ xuất KẾT QUẢ.
126
+ - Caveman chỉ nén prose chat. KHÔNG cắt/mất thông tin kỹ thuật: command output, error, stack trace, diff, JSON/API response, file path, line ref, test evidence.
127
+ - Khi relay output, giữ nguyên dòng quan trọng; chỉ tóm tắt phần nhiễu xung quanh.
126
128
  - Planning artifacts (implementation_plan.md, walkthrough.md) VẪN chi tiết theo format chuẩn.
127
129
  - Tài liệu thảo luận & brainstorm (Brief, Requirements, Brainstorm) PHẢI dùng tiếng Việt (hoặc ngôn ngữ giao tiếp của User), chỉ Code/Architecture mới bắt buộc dùng tiếng Anh.
128
130
 
@@ -150,6 +152,12 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
150
152
  - Commit: CHỈ qua `awkit gate git auto`. CẤM `git commit` trực tiếp qua bash.
151
153
  - Destructive command → double-confirm user. Không chắc → hỏi trước.
152
154
 
155
+ ### GStack Planning & Code Safety
156
+ - **Office Hours & CEO Review**: Chạy `/office-hours` để thử nghiệm ý tưởng dưới góc nhìn startup/YC. Dùng `/plan-ceo-review` để đạt "trải nghiệm sản phẩm 10 sao" và quản lý phạm vi (scope).
157
+ - **Eng Review & Data Safety**: Chốt kiến trúc và thiết kế dữ liệu. Quét an toàn SQL, concurrency/races, và enum completeness trước khi code.
158
+ - **Pass 1 & Pass 2 Review**: Đánh giá code hai lượt (Pass 1: Critical - SQL/data safety, races, LLM boundary, shell injection, enum; Pass 2: Informational - logic/syntax).
159
+ - **Fix-First Heuristic**: Tự động sửa lỗi cơ học (dead code, N+1 queries, stale comments) và hỏi ý kiến user đối với các quyết định rủi ro/kiến trúc.
160
+
153
161
  ### Subagent Orchestration & Protocol
154
162
  - **Định tuyến trước, Tìm kiếm sau:** Tuyệt đối không dùng `grep_search` hoặc `list_dir` diện rộng để định vị subagents (như `critic`). Bắt buộc tra cứu chỉ mục tại `skills/CATALOG.md`, `skills/TRIGGER_INDEX.md` hoặc `skills/review/SKILL.md` trước.
155
163
  - **Tận dụng Subagents Cô lập:** Sử dụng built-in subagents (`research` cho tìm kiếm codebase/log thô, `browser` cho các tác vụ UI) để tránh ô nhiễm context trên luồng chat chính.
@@ -1,6 +1,6 @@
1
1
  # GEMINI.md — Antigravity v12.6
2
2
 
3
- > Rules only. Updated: 2026-06-15
3
+ > Rules only. Updated: 2026-06-23
4
4
 
5
5
  ---
6
6
 
@@ -62,11 +62,12 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
62
62
  - Build: CHỈ dùng `awkit build`. CẤM gọi native (`xcodebuild`, `./gradlew`, `npm run build`).
63
63
  - `automation.build.enabled: false` → DỪNG, báo user. KHÔNG fallback native.
64
64
  - Thêm params qua `--`: `awkit build -- -destination '...'`. Bypass wrapper = VI PHẠM.
65
+ - **Chạy tác vụ nền (Background Tasks)**: Khi chạy các tác vụ nền hoặc tác vụ dài (>30 giây) như Codex CLI, PHẢI chạy qua wrapper `node scripts/exec-progress.js "<command>"` để hiển thị checklist tiến trình trực quan cho người dùng thay vì để trống màn hình.
65
66
 
66
67
  ### 7-Gate System
67
68
  - Triage: TRIVIAL (→ Gate 4 thẳng) | MODERATE (→ G3+4+5) | COMPLEX (→ all gates).
68
69
  - Gates: G1 brainstorm → G1.5 module-spec (COMPLEX+>3mod) → G2 spec-gate → G2.5 visual (skip nếu backend) → G3 symphony-enforcer → G4 execution → G5 verification.
69
- - **Goal Mode Override:** Khi đang ở goal mode (`/goal`, active Codex goal, hoặc user nói rõ "goal mode") → gates là checklist nội bộ, KHÔNG dừng chờ user approval ở G2/G2.5/G4 checkpoints. AI tự chọn best-effort, tự verify, ghi assumption, rồi tiếp tục tới khi goal complete/bị block thật sự. Safety/destructive/security vẫn phải hỏi.
70
+ - **Goal Mode Override (NO-CONFIRM):** Khi đang ở goal mode (`/goal`, active Codex goal, hoặc user nói rõ "goal mode") → gates là checklist nội bộ, KHÔNG dừng chờ user approval ở bất kỳ bước nào (G2/G2.5/G4 checkpoints, prompt audit, style preview, grid configuration, specs approval, v.v.). AI tự động chọn phương án tối ưu (best-effort/recommended default), tự verify, ghi nhận giả định (assumptions) vào logs/walkthrough, rồi tiếp tục cho đến khi goal hoàn thành hoặc bị block thực sự bởi lỗi kỹ thuật/permission. Chỉ dừng lại hỏi ý kiến khi gặp lệnh thực sự nguy hại (destructive) hoặc nhạy cảm bảo mật quy định tại Safety Guardrails.
70
71
  - **Gate 4 Three-Phase:**
71
72
  - Phase A 🏗️ Infrastructure → B 🎨 UI Shell (mock) → C ⚡ Logic (real data).
72
73
  - COMPLEX+UI: 3 phases bắt buộc. MODERATE+UI: A+C gộp, B optional. TRIVIAL: bypass.
@@ -102,8 +103,11 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
102
103
  - Sau khi dùng tool sửa code → KHÔNG in lại code trong chat. Tóm tắt bằng bullets.
103
104
  - Code block trong chat: tối đa 10 dòng. Show diff → dùng `render_diffs()`.
104
105
 
105
- ### Image Generation Efficiency
106
- - Image gen: grid/spritesheet cho batch variants, không gen từng ảnh rời.
106
+ ### Image Generation & Asset Mandates (BẮT BUỘC)
107
+ - **Cấm tự tạo SVG:** CẤM tự sinh, tự tạo hoặc thiết kế mã SVG cho các UI assets, biểu tượng trang trí, hoặc spritesheet (do chất lượng SVG tự tạo không đảm bảo và không bám sát thiết kế). BẮT BUỘC sử dụng Codex CLI để tạo hình ảnh và spritesheet UI.
108
+ - **Sử dụng Skill bắt buộc:** Tuyệt đối sử dụng các skill `generate-gui-assets` và `hatch-pet` theo tài liệu tương ứng tại `/Users/trungkientn/.agents/skills/generate-gui-assets/SKILL.md` và `/Users/trungkientn/.codex/skills/hatch-pet/SKILL.md`.
109
+ - **Thiết kế dùng Grid để tiết kiệm:** Bắt buộc thiết kế các assets (ngoại trừ background) bằng dạng Grid (spritesheet/atlas) để tối ưu chi phí và tài nguyên.
110
+ - **Quy trình Grid & Tự Động Phê Duyệt:** Luôn ưu tiên tạo và kiểm chứng (verify) theo hướng lưới `8x6` trước. Nếu chất lượng quá xấu, tự động giảm dần số lượng item/kích thước grid xuống các cấu hình nhỏ hơn (ví dụ: 8x5, 6x6, 6x5, v.v.) mà KHÔNG cần hỏi ý kiến hoặc bắt user xác nhận lại (kể cả trong Normal hay Goal Mode).
107
111
 
108
112
  ### Proactive UI Asset Generation (MANDATORY)
109
113
  - **Asset Audit:** Trong Gate 2.5 (Visual Design) và Gate 4 Phase B (UI Shell), BẮT BUỘC rà soát mã nguồn/thiết kế để phát hiện các UI assets bị thiếu (nút bấm, panel, icon, pet, egg...).
@@ -112,12 +116,15 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
112
116
  - **Cấu trúc Lệnh:**
113
117
  - Đối với UI assets: `codex exec "Generate GUI asset: [Prompt/Style/Theme] and save it to [path] using the generate-gui-assets skill rules."`
114
118
  - Đối với Pet/Egg assets: `codex exec "Generate pet companion asset: [Pet Type/State] and save it to [path] using the hatch-pet skill rules and grid configuration [grid]."`
115
- - **Chi tiết & Approval:** Tự động thiết lập prompt chi tiết dựa trên Theme của App, tuân thủ tiêu chuẩn Solid Background và hỏi ý kiến user trước khi thực thi lệnh.
119
+ - **Chi tiết & Approval:** Tự động thiết lập prompt chi tiết dựa trên Theme của App, tuân thủ tiêu chuẩn Solid Background và hỏi ý kiến user trước khi thực thi lệnh (Trừ Goal Mode hoặc trường hợp tự động giảm cấu hình lưới grid: Tự động phê duyệt prompt/cấu hình và thực thi lệnh không cần hỏi).
120
+
116
121
 
117
122
 
118
123
  ### Communication (CAVEMAN ULTRA)
119
124
  - Chat: Tiếng Việt, tối đa 1-2 câu ngắn. Code/Docs: Tiếng Anh.
120
125
  - CẤM giải thích dài, chào hỏi. Chỉ xuất KẾT QUẢ.
126
+ - Caveman chỉ nén prose chat. KHÔNG cắt/mất thông tin kỹ thuật: command output, error, stack trace, diff, JSON/API response, file path, line ref, test evidence.
127
+ - Khi relay output, giữ nguyên dòng quan trọng; chỉ tóm tắt phần nhiễu xung quanh.
121
128
  - Planning artifacts (implementation_plan.md, walkthrough.md) VẪN chi tiết theo format chuẩn.
122
129
  - Tài liệu thảo luận & brainstorm (Brief, Requirements, Brainstorm) PHẢI dùng tiếng Việt (hoặc ngôn ngữ giao tiếp của User), chỉ Code/Architecture mới bắt buộc dùng tiếng Anh.
123
130
 
@@ -145,6 +152,12 @@ symphony-orchestrator → awf-session-restore (gitnexus state) → nm-memory-syn
145
152
  - Commit: CHỈ qua `awkit gate git auto`. CẤM `git commit` trực tiếp qua bash.
146
153
  - Destructive command → double-confirm user. Không chắc → hỏi trước.
147
154
 
155
+ ### GStack Planning & Code Safety
156
+ - **Office Hours & CEO Review**: Chạy `/office-hours` để thử nghiệm ý tưởng dưới góc nhìn startup/YC. Dùng `/plan-ceo-review` để đạt "trải nghiệm sản phẩm 10 sao" và quản lý phạm vi (scope).
157
+ - **Eng Review & Data Safety**: Chốt kiến trúc và thiết kế dữ liệu. Quét an toàn SQL, concurrency/races, và enum completeness trước khi code.
158
+ - **Pass 1 & Pass 2 Review**: Đánh giá code hai lượt (Pass 1: Critical - SQL/data safety, races, LLM boundary, shell injection, enum; Pass 2: Informational - logic/syntax).
159
+ - **Fix-First Heuristic**: Tự động sửa lỗi cơ học (dead code, N+1 queries, stale comments) và hỏi ý kiến user đối với các quyết định rủi ro/kiến trúc.
160
+
148
161
  ### Subagent Orchestration & Protocol
149
162
  - **Định tuyến trước, Tìm kiếm sau:** Tuyệt đối không dùng `grep_search` hoặc `list_dir` diện rộng để định vị subagents (như `critic`). Bắt buộc tra cứu chỉ mục tại `skills/CATALOG.md`, `skills/TRIGGER_INDEX.md` hoặc `skills/review/SKILL.md` trước.
150
163
  - **Tận dụng Subagents Cô lập:** Sử dụng built-in subagents (`research` cho tìm kiếm codebase/log thô, `browser` cho các tác vụ UI) để tránh ô nhiễm context trên luồng chat chính.
@@ -14,6 +14,7 @@
14
14
  "awf-version-tracker",
15
15
  "brainstorm-agent",
16
16
  "code-review",
17
+ "review",
17
18
  "codex-conductor",
18
19
  "codex-goal",
19
20
  "gemini-conductor",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leejungkiin/awkit",
3
- "version": "1.7.7",
3
+ "version": "1.7.8",
4
4
  "description": "Antigravity Workflow Kit v1.6 Unified AI agent orchestration system with Mindful Checkpoints.",
5
5
  "main": "bin/awk.js",
6
6
  "private": false,
@@ -1,6 +1,83 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
1
4
  const { execSync } = require('child_process');
2
5
 
3
6
  let hasRtkCache = null;
7
+ const HOME = os.homedir();
8
+ const CONFIG_DIR = path.join(HOME, '.gemini', 'antigravity');
9
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'rtk.json');
10
+ const VALID_MODES = new Set(['off', 'proxy', 'safe', 'aggressive']);
11
+ const DEFAULT_MODE = 'safe';
12
+
13
+ function readJsonFile(file) {
14
+ try {
15
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
16
+ } catch (_) {
17
+ return null;
18
+ }
19
+ }
20
+
21
+ function findProjectIdentity(startDir = process.cwd()) {
22
+ let dir = path.resolve(startDir);
23
+ const root = path.parse(dir).root;
24
+
25
+ while (dir !== root) {
26
+ const candidate = path.join(dir, '.project-identity');
27
+ if (fs.existsSync(candidate)) return readJsonFile(candidate);
28
+ dir = path.dirname(dir);
29
+ }
30
+ return null;
31
+ }
32
+
33
+ function normalizeMode(mode) {
34
+ const normalized = String(mode || '').trim().toLowerCase();
35
+ return VALID_MODES.has(normalized) ? normalized : null;
36
+ }
37
+
38
+ function getGlobalRtkConfig() {
39
+ return readJsonFile(CONFIG_FILE) || {};
40
+ }
41
+
42
+ function getProjectRtkMode(startDir = process.cwd()) {
43
+ const identity = findProjectIdentity(startDir);
44
+ const rtkConfig = identity && identity.automation && identity.automation.rtk;
45
+ if (!rtkConfig) return null;
46
+ if (rtkConfig.enabled === false) return 'off';
47
+ return normalizeMode(rtkConfig.mode);
48
+ }
49
+
50
+ function getRtkMode(startDir = process.cwd()) {
51
+ const envMode = normalizeMode(process.env.AWKIT_RTK_MODE || process.env.RTK_MODE);
52
+ if (envMode) return { mode: envMode, source: 'env' };
53
+
54
+ const globalConfig = getGlobalRtkConfig();
55
+ const globalMode = normalizeMode(globalConfig.mode);
56
+ if (globalMode) return { mode: globalMode, source: CONFIG_FILE };
57
+
58
+ const projectMode = getProjectRtkMode(startDir);
59
+ if (projectMode) return { mode: projectMode, source: '.project-identity' };
60
+
61
+ return { mode: DEFAULT_MODE, source: 'default' };
62
+ }
63
+
64
+ function setGlobalRtkMode(mode) {
65
+ const normalized = normalizeMode(mode);
66
+ if (!normalized) {
67
+ throw new Error(`Invalid RTK mode: ${mode}. Expected: ${Array.from(VALID_MODES).join(', ')}`);
68
+ }
69
+
70
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
71
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify({
72
+ mode: normalized,
73
+ updatedAt: new Date().toISOString()
74
+ }, null, 2) + '\n');
75
+ return CONFIG_FILE;
76
+ }
77
+
78
+ function startsWithAny(command, prefixes) {
79
+ return prefixes.some(prefix => command === prefix || command.startsWith(`${prefix} `));
80
+ }
4
81
 
5
82
  /**
6
83
  * Check if rtk binary is available in the current environment PATH.
@@ -26,12 +103,21 @@ function checkRtk() {
26
103
  function execRtkSync(command, options = {}) {
27
104
  const opts = { timeout: 30000, ...options };
28
105
  const trimmed = command.trim();
29
-
30
- // Only compress developer commands known to be verbose
31
- const eligiblePrefixes = ['git ', 'npm ', 'cargo ', 'yarn ', 'pnpm ', 'grep ', 'find ', 'awkit trello '];
32
- const extendedPrefixes = ['cat ', 'curl ', 'xcodebuild ', './gradlew ', 'swift ', 'flutter ', 'dart ', 'pod ', 'brew '];
33
- const allEligible = [...eligiblePrefixes, ...extendedPrefixes];
34
- const isEligible = allEligible.some(prefix => trimmed.startsWith(prefix));
106
+ const { mode } = getRtkMode();
107
+
108
+ const safeCommands = ['git status', 'git branch', 'git remote', 'git rev-parse', 'git log'];
109
+ const safePrefixes = ['git add', 'git commit', 'git push'];
110
+ const aggressivePrefixes = [
111
+ 'git ', 'npm ', 'cargo ', 'yarn ', 'pnpm ', 'grep ', 'find ', 'awkit trello ',
112
+ 'cat ', 'curl ', 'xcodebuild ', './gradlew ', 'swift ', 'flutter ', 'dart ', 'pod ', 'brew '
113
+ ];
114
+ const safeEligible = startsWithAny(trimmed, safeCommands) || startsWithAny(trimmed, safePrefixes);
115
+ const aggressiveEligible = aggressivePrefixes.some(prefix => trimmed.startsWith(prefix));
116
+ const isEligible = mode === 'aggressive' ? aggressiveEligible : safeEligible;
117
+
118
+ if (mode === 'off') {
119
+ return execSync(command, opts);
120
+ }
35
121
 
36
122
  if (!checkRtk()) {
37
123
  if (isEligible && !opts.stdio) {
@@ -41,17 +127,26 @@ function execRtkSync(command, options = {}) {
41
127
  }
42
128
 
43
129
  if (trimmed.startsWith('rtk ')) {
44
- return execSync(command, options);
130
+ return execSync(command, opts);
131
+ }
132
+
133
+ if (mode === 'proxy' && aggressiveEligible) {
134
+ return execSync(`rtk proxy ${command}`, opts);
45
135
  }
46
136
 
47
137
  if (isEligible) {
48
- return execSync(`rtk ${command}`, options);
138
+ return execSync(`rtk ${command}`, opts);
49
139
  }
50
140
 
51
- return execSync(command, options);
141
+ return execSync(command, opts);
52
142
  }
53
143
 
54
144
  module.exports = {
55
145
  execRtkSync,
56
- checkRtk
146
+ checkRtk,
147
+ getRtkMode,
148
+ getGlobalRtkConfig,
149
+ getRtkConfigPath: () => CONFIG_FILE,
150
+ setGlobalRtkMode,
151
+ VALID_RTK_MODES: Array.from(VALID_MODES)
57
152
  };
package/skills/CATALOG.md CHANGED
@@ -25,7 +25,7 @@
25
25
  | 5 | `brainstorm-agent` | `manual` | `/brainstorm`, keywords | 5 | 1.0.0 | ✅ Active |
26
26
  | 6 | `awf-error-translator` | `auto` | Error detected | 6 | — | ✅ Active |
27
27
  | 7 | `awf-adaptive-language` | `auto` | Always | 7 | — | ✅ Active |
28
- | 8 | `awf-caveman` | `auto` | `.project-identity` check | 7.5 | 1.0.0 | ✅ Active |
28
+ | 8 | `awf-caveman` | `auto` | `.project-identity` check | 7.5 | 1.0.1 | ✅ Active |
29
29
  | 9 | `ios-engineer` | `manual` | iOS tasks | — | — | ✅ Active |
30
30
  | 9 | `smali-to-kotlin` | `manual` | `/reverse-android` | 8 | — | ✅ Active |
31
31
  | 10 | `smali-to-swift` | `manual` | `/reverse-ios` | 9 | — | ✅ Active |
@@ -4,7 +4,7 @@ description: >-
4
4
  Ultra-compressed communication mode. Cuts token usage ~75% by speaking like caveman.
5
5
  Checks `.project-identity` for `communication.cavemanMode.enabled`.
6
6
  Supports both Vietnamese and English.
7
- version: 1.0.0
7
+ version: 1.0.1
8
8
  ---
9
9
 
10
10
  # AWF Caveman Mode
@@ -28,6 +28,17 @@ if config?.communication?.cavemanMode?.enabled == true:
28
28
 
29
29
  Áp dụng cho mọi phản hồi của AI (cả Tiếng Việt và Tiếng Anh). Mọi hàm lượng kỹ thuật phải giữ nguyên, CHỈ lược bỏ từ thừa.
30
30
 
31
+ ### Scope Guard
32
+
33
+ Caveman chỉ được nén phần prose/chat. KHÔNG được cắt, viết tắt, tái diễn giải, hoặc gom nhóm các bằng chứng kỹ thuật cần độ chính xác cao:
34
+ - Command output quan trọng.
35
+ - Error message, stack trace, warning.
36
+ - Diff, patch, JSON/API response.
37
+ - File path, symbol name, line number.
38
+ - Test/build evidence.
39
+
40
+ Khi cần tiết kiệm token: tóm tắt phần nhiễu xung quanh, nhưng giữ nguyên các dòng kỹ thuật quyết định.
41
+
31
42
  1. **BỎ TỪ ĐỆM**: Bỏ mọi từ thừa, từ lịch sự ("Vâng", "Dạ", "Chắc chắn rồi", "Theo tôi thấy thì...", "Tôi hiểu ý anh...").
32
43
  2. **NÓI CỤT LỦN**: Đi thẳng vào vấn đề. Bắt đầu ngay bằng nguyên nhân lỗi hoặc hành động. Dùng câu mảnh (fragments).
33
44
  3. **KHÔNG GIẢI THÍCH DÀI DÒNG**: Dùng mũi tên `->` để chỉ nguyên nhân/kết quả.
@@ -55,6 +66,7 @@ if config?.communication?.cavemanMode?.enabled == true:
55
66
  Tạm thời ngưng Caveman (trở lại bình thường) khi:
56
67
  - Cảnh báo bảo mật quan trọng (Security warnings).
57
68
  - Hành động không thể hoàn tác (Xóa DB, git reset --hard).
69
+ - Command output/error/diff là bằng chứng chính của task.
58
70
  - Các bước hướng dẫn quá phức tạp dễ gây hiểu nhầm nếu nói tắt.
59
71
  - Chữa cháy / Giải thích lỗi quá lắt léo cần rõ nghĩa.
60
72