@leejungkiin/awkit 1.6.0 → 1.6.2

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/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # AWKit — Antigravity Workflow Kit v12.5
2
2
 
3
- > **v12.5.0** · Single Source of Truth · Symphony-First · Mindful Execution
3
+ > **v12.5** · Single Source of Truth · Symphony-First · Mindful Execution
4
4
 
5
5
  AWKit là framework điều phối AI agent chuyên nghiệp. Đây là **nơi duy nhất** chứa toàn bộ workflows, skills, GEMINI.md và cấu hình — không còn phân tán giữa nhiều repo.
6
+ AWKit giúp tối ưu context khi làm việc, có khả năng quản lý task, đồng bộ Trello và báo cáo lên Telegram, ngoài ra Awkit còn sử dụng cơ chế checkpoint để dev dừng đúng lúc tránh tâm lý tối ưu hóa quá mức (over-optimization) một vấn đề phổ biến khi làm việc với AI.
6
7
 
7
8
  ---
8
9
 
@@ -224,4 +225,4 @@ awkit enable-pack creator-studio
224
225
 
225
226
  ---
226
227
 
227
- *AWKit v1.5.x — Antigravity Workflow Kit · Created by Kien AI*
228
+ *AWKit Antigravity Workflow Kit · Created by leejungkiin*
package/bin/awk.js CHANGED
@@ -2051,6 +2051,18 @@ function cmdHelp() {
2051
2051
  log(` ${C.gray} --parse-mode <md|html>${C.reset} Formatting mode`);
2052
2052
  log('');
2053
2053
 
2054
+ // GitNexus
2055
+ log(`${C.bold}🔍 GitNexus${C.reset}`);
2056
+ log(line);
2057
+ log(` ${C.green}gitnexus list${C.reset} List all indexed repositories`);
2058
+ log(` ${C.green}gitnexus status${C.reset} Show current project index info`);
2059
+ log(` ${C.green}gitnexus clean${C.reset} Interactive cleanup of old indexes`);
2060
+ log(` ${C.green}gitnexus clean${C.reset} ${C.gray}<name...>${C.reset} Remove specific repo(s) by name`);
2061
+ log(` ${C.gray} --stale${C.reset} Auto-remove repos with missing paths`);
2062
+ log(` ${C.gray} --all${C.reset} Remove all except current project`);
2063
+ log(` ${C.gray} Alias: gn${C.reset}`);
2064
+ log('');
2065
+
2054
2066
  // Available packs
2055
2067
  const packsDir = path.join(AWK_ROOT, 'skill-packs');
2056
2068
  if (fs.existsSync(packsDir)) {
@@ -3383,6 +3395,309 @@ function checkAutoUpdate() {
3383
3395
  }
3384
3396
  }
3385
3397
 
3398
+ // ─── GitNexus Management ──────────────────────────────────────────────────────
3399
+
3400
+ const GITNEXUS_REGISTRY = path.join(HOME, '.gitnexus', 'registry.json');
3401
+
3402
+ function readGitnexusRegistry() {
3403
+ if (!fs.existsSync(GITNEXUS_REGISTRY)) return [];
3404
+ try {
3405
+ return JSON.parse(fs.readFileSync(GITNEXUS_REGISTRY, 'utf8'));
3406
+ } catch (_) {
3407
+ return [];
3408
+ }
3409
+ }
3410
+
3411
+ function writeGitnexusRegistry(registry) {
3412
+ fs.mkdirSync(path.dirname(GITNEXUS_REGISTRY), { recursive: true });
3413
+ fs.writeFileSync(GITNEXUS_REGISTRY, JSON.stringify(registry, null, 2) + '\n');
3414
+ }
3415
+
3416
+ function cmdGitnexus(args) {
3417
+ const sub = args[0] || 'list';
3418
+
3419
+ switch (sub) {
3420
+ case 'list':
3421
+ case 'ls': {
3422
+ const registry = readGitnexusRegistry();
3423
+ if (registry.length === 0) {
3424
+ info('No GitNexus indexed repositories found.');
3425
+ dim('Run `npx gitnexus analyze` in a project to index it.');
3426
+ return;
3427
+ }
3428
+
3429
+ log('');
3430
+ log(`${C.cyan}${C.bold}🔍 GitNexus Indexed Repositories (${registry.length})${C.reset}`);
3431
+ log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
3432
+
3433
+ const cwd = process.cwd();
3434
+ for (const repo of registry) {
3435
+ const isCurrent = repo.path === cwd;
3436
+ const marker = isCurrent ? `${C.green}◉` : `${C.gray}○`;
3437
+ const nameColor = isCurrent ? C.green : C.reset;
3438
+ const stats = repo.stats || {};
3439
+ const indexDate = repo.indexedAt ? new Date(repo.indexedAt).toLocaleDateString() : 'unknown';
3440
+ const pathExists = fs.existsSync(repo.path);
3441
+ const pathStatus = pathExists ? '' : ` ${C.red}(path missing!)${C.reset}`;
3442
+
3443
+ log(` ${marker} ${nameColor}${C.bold}${repo.name}${C.reset}${pathStatus}`);
3444
+ dim(` Path: ${repo.path}`);
3445
+ dim(` Indexed: ${indexDate} | ${stats.nodes || 0} symbols, ${stats.edges || 0} edges, ${stats.processes || 0} flows`);
3446
+ }
3447
+ log('');
3448
+ break;
3449
+ }
3450
+
3451
+ case 'status': {
3452
+ const cwd = process.cwd();
3453
+ const registry = readGitnexusRegistry();
3454
+ const match = registry.find(r => r.path === cwd);
3455
+
3456
+ if (!match) {
3457
+ warn('Current directory is not indexed by GitNexus.');
3458
+ dim('Run `npx gitnexus analyze` to index this project.');
3459
+ return;
3460
+ }
3461
+
3462
+ const stats = match.stats || {};
3463
+ const indexDate = match.indexedAt ? new Date(match.indexedAt) : null;
3464
+ const ageMs = indexDate ? Date.now() - indexDate.getTime() : 0;
3465
+ const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24));
3466
+ const stale = ageDays > 7;
3467
+
3468
+ log('');
3469
+ log(`${C.cyan}${C.bold}🔍 GitNexus: ${match.name}${C.reset}`);
3470
+ log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
3471
+ dim(`Path: ${match.path}`);
3472
+ dim(`Storage: ${match.storagePath}`);
3473
+ dim(`Indexed: ${indexDate ? indexDate.toLocaleString() : 'unknown'} (${ageDays}d ago)`);
3474
+ dim(`Last Commit: ${match.lastCommit || 'n/a'}`);
3475
+ dim(`Symbols: ${stats.nodes || 0}`);
3476
+ dim(`Relations: ${stats.edges || 0}`);
3477
+ dim(`Communities: ${stats.communities || 0}`);
3478
+ dim(`Processes: ${stats.processes || 0}`);
3479
+ dim(`Embeddings: ${stats.embeddings || 0}`);
3480
+
3481
+ if (stale) {
3482
+ log('');
3483
+ warn(`Index is ${ageDays} days old. Consider refreshing:`);
3484
+ dim(' npx gitnexus analyze');
3485
+ }
3486
+
3487
+ // Show projectId from .project-identity if available
3488
+ const identityPath = path.join(cwd, '.project-identity');
3489
+ const identity = readJsonFile(identityPath);
3490
+ if (identity && identity.projectId) {
3491
+ dim(`Project ID: ${identity.projectId}`);
3492
+ }
3493
+ log('');
3494
+ break;
3495
+ }
3496
+
3497
+ case 'clean': {
3498
+ const registry = readGitnexusRegistry();
3499
+ if (registry.length === 0) {
3500
+ info('No GitNexus indexed repositories to clean.');
3501
+ return;
3502
+ }
3503
+
3504
+ const cwd = process.cwd();
3505
+ const isStaleMode = args.includes('--stale');
3506
+ const isAllMode = args.includes('--all');
3507
+
3508
+ // Named repos: awkit gn clean <name1> <name2> ...
3509
+ const namedArgs = args.slice(1).filter(a => !a.startsWith('--'));
3510
+ if (namedArgs.length > 0 && !isStaleMode && !isAllMode) {
3511
+ const nameLookup = new Map(registry.map(r => [r.name.toLowerCase(), r]));
3512
+ const matched = [];
3513
+ const notFound = [];
3514
+
3515
+ for (const name of namedArgs) {
3516
+ const entry = nameLookup.get(name.toLowerCase());
3517
+ if (entry) matched.push(entry);
3518
+ else notFound.push(name);
3519
+ }
3520
+
3521
+ if (notFound.length > 0) {
3522
+ warn(`Not found in registry: ${notFound.join(', ')}`);
3523
+ dim('Available repos:');
3524
+ for (const r of registry) dim(` • ${r.name}`);
3525
+ }
3526
+
3527
+ if (matched.length === 0) {
3528
+ info('No matching repos to clean.');
3529
+ return;
3530
+ }
3531
+
3532
+ log('');
3533
+ log(`${C.yellow}${C.bold}🧹 Will remove ${matched.length} repo(s):${C.reset}`);
3534
+ for (const r of matched) {
3535
+ log(` ${C.red}✗${C.reset} ${r.name} — ${r.path}`);
3536
+ }
3537
+ log('');
3538
+
3539
+ if (!promptYN('Confirm?')) {
3540
+ info('Cancelled.');
3541
+ return;
3542
+ }
3543
+
3544
+ const removeNames = new Set(matched.map(r => r.name));
3545
+ for (const r of matched) {
3546
+ if (r.storagePath && fs.existsSync(r.storagePath)) {
3547
+ try {
3548
+ fs.rmSync(r.storagePath, { recursive: true, force: true });
3549
+ dim(`Deleted: ${r.storagePath}`);
3550
+ } catch (e) {
3551
+ warn(`Failed to delete ${r.storagePath}: ${e.message}`);
3552
+ }
3553
+ }
3554
+ }
3555
+
3556
+ const remaining = registry.filter(r => !removeNames.has(r.name));
3557
+ writeGitnexusRegistry(remaining);
3558
+ ok(`Removed ${matched.length} repos. ${remaining.length} remaining.`);
3559
+ return;
3560
+ }
3561
+
3562
+ if (isStaleMode) {
3563
+ // Auto-clean repos whose paths no longer exist
3564
+ const stale = registry.filter(r => !fs.existsSync(r.path));
3565
+ if (stale.length === 0) {
3566
+ ok('No stale repos found. All paths are valid.');
3567
+ return;
3568
+ }
3569
+
3570
+ log('');
3571
+ log(`${C.yellow}${C.bold}🧹 Found ${stale.length} stale repo(s):${C.reset}`);
3572
+ for (const r of stale) {
3573
+ log(` ${C.red}✗${C.reset} ${r.name} — ${r.path}`);
3574
+ }
3575
+ log('');
3576
+
3577
+ if (!promptYN('Remove these stale entries?')) {
3578
+ info('Cancelled.');
3579
+ return;
3580
+ }
3581
+
3582
+ for (const r of stale) {
3583
+ // Remove .gitnexus storage if it exists
3584
+ if (r.storagePath && fs.existsSync(r.storagePath)) {
3585
+ try {
3586
+ fs.rmSync(r.storagePath, { recursive: true, force: true });
3587
+ dim(`Deleted: ${r.storagePath}`);
3588
+ } catch (e) {
3589
+ warn(`Failed to delete ${r.storagePath}: ${e.message}`);
3590
+ }
3591
+ }
3592
+ }
3593
+
3594
+ const remaining = registry.filter(r => fs.existsSync(r.path));
3595
+ writeGitnexusRegistry(remaining);
3596
+ ok(`Removed ${stale.length} stale entries. ${remaining.length} repos remaining.`);
3597
+ return;
3598
+ }
3599
+
3600
+ if (isAllMode) {
3601
+ const toRemove = registry.filter(r => r.path !== cwd);
3602
+ if (toRemove.length === 0) {
3603
+ info('Only current project is indexed. Nothing to clean.');
3604
+ return;
3605
+ }
3606
+
3607
+ log('');
3608
+ log(`${C.yellow}${C.bold}🧹 Will remove ${toRemove.length} repo(s) (keeping current project):${C.reset}`);
3609
+ for (const r of toRemove) {
3610
+ log(` ${C.red}✗${C.reset} ${r.name} — ${r.path}`);
3611
+ }
3612
+ log('');
3613
+
3614
+ if (!promptYN('Proceed?')) {
3615
+ info('Cancelled.');
3616
+ return;
3617
+ }
3618
+
3619
+ for (const r of toRemove) {
3620
+ if (r.storagePath && fs.existsSync(r.storagePath)) {
3621
+ try {
3622
+ fs.rmSync(r.storagePath, { recursive: true, force: true });
3623
+ dim(`Deleted: ${r.storagePath}`);
3624
+ } catch (e) {
3625
+ warn(`Failed to delete ${r.storagePath}: ${e.message}`);
3626
+ }
3627
+ }
3628
+ }
3629
+
3630
+ const remaining = registry.filter(r => r.path === cwd);
3631
+ writeGitnexusRegistry(remaining);
3632
+ ok(`Removed ${toRemove.length} repos. Current project preserved.`);
3633
+ return;
3634
+ }
3635
+
3636
+ // Interactive mode: show numbered list, user selects
3637
+ log('');
3638
+ log(`${C.cyan}${C.bold}🔍 Select repos to remove:${C.reset}`);
3639
+ log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
3640
+
3641
+ for (let i = 0; i < registry.length; i++) {
3642
+ const r = registry[i];
3643
+ const isCurrent = r.path === cwd;
3644
+ const pathExists = fs.existsSync(r.path);
3645
+ const tag = isCurrent ? ` ${C.green}(current)${C.reset}` : !pathExists ? ` ${C.red}(missing)${C.reset}` : '';
3646
+ log(` ${C.yellow}${i + 1}${C.reset}. ${r.name}${tag}`);
3647
+ dim(` ${r.path}`);
3648
+ }
3649
+ log('');
3650
+
3651
+ const input = promptChoice('Enter numbers to remove (e.g. 2,3,5)', '').trim();
3652
+ if (!input) {
3653
+ info('No selection. Cancelled.');
3654
+ return;
3655
+ }
3656
+
3657
+ const indices = input.split(',').map(s => parseInt(s.trim(), 10) - 1).filter(i => i >= 0 && i < registry.length);
3658
+ if (indices.length === 0) {
3659
+ info('Invalid selection. Cancelled.');
3660
+ return;
3661
+ }
3662
+
3663
+ const selected = indices.map(i => registry[i]);
3664
+ log('');
3665
+ log(`${C.yellow}Will remove:${C.reset}`);
3666
+ for (const r of selected) {
3667
+ log(` ${C.red}✗${C.reset} ${r.name}`);
3668
+ }
3669
+ log('');
3670
+
3671
+ if (!promptYN('Confirm?')) {
3672
+ info('Cancelled.');
3673
+ return;
3674
+ }
3675
+
3676
+ const removeNames = new Set(selected.map(r => r.name));
3677
+ for (const r of selected) {
3678
+ if (r.storagePath && fs.existsSync(r.storagePath)) {
3679
+ try {
3680
+ fs.rmSync(r.storagePath, { recursive: true, force: true });
3681
+ dim(`Deleted: ${r.storagePath}`);
3682
+ } catch (e) {
3683
+ warn(`Failed to delete ${r.storagePath}: ${e.message}`);
3684
+ }
3685
+ }
3686
+ }
3687
+
3688
+ const remaining = registry.filter(r => !removeNames.has(r.name));
3689
+ writeGitnexusRegistry(remaining);
3690
+ ok(`Removed ${selected.length} repos. ${remaining.length} remaining.`);
3691
+ break;
3692
+ }
3693
+
3694
+ default:
3695
+ err(`Unknown gitnexus sub-command: ${sub}`);
3696
+ log(` Available: list, status, clean`);
3697
+ break;
3698
+ }
3699
+ }
3700
+
3386
3701
  // ─── Native HTTP Server ───────────────────────────────────────────────────────
3387
3702
 
3388
3703
  function cmdServe(args) {
@@ -3545,6 +3860,10 @@ const [, , command, ...args] = process.argv;
3545
3860
  case 'serve':
3546
3861
  cmdServe(args);
3547
3862
  break;
3863
+ case 'gitnexus':
3864
+ case 'gn':
3865
+ cmdGitnexus(args);
3866
+ break;
3548
3867
  case 'gate':
3549
3868
  cmdGate(args);
3550
3869
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leejungkiin/awkit",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Antigravity Workflow Kit v12.5. Unified AI agent orchestration system with Mindful Checkpoints.",
5
5
  "main": "bin/awk.js",
6
6
  "bin": {
@@ -41,13 +41,38 @@ INDEX STALE (tool trả warning):
41
41
 
42
42
  ---
43
43
 
44
+ ## 🔑 Auto-Repo Detection Protocol (BẮT BUỘC)
45
+
46
+ ```
47
+ TRƯỚC KHI gọi bất kỳ GitNexus MCP tool nào:
48
+
49
+ 1. Gọi gitnexus_list_repos() → lấy danh sách repos đã index
50
+ 2. Match project directory (từ .project-identity hoặc cwd) với repo paths
51
+ 3. Dùng matched repo name làm `repo` param cho MỌI tool call
52
+
53
+ VÍ DỤ:
54
+ gitnexus_list_repos() trả về repo path "/Users/.../FitWitnessSimple"
55
+ → project đang mở = FitWitnessSimple
56
+ → gitnexus_query({query: "weather", repo: "FitWitnessSimple"})
57
+
58
+ FALLBACK (nếu không match path):
59
+ 1. So sánh projectId (từ .project-identity) với repo names
60
+ 2. Nếu vẫn không match → hỏi user chọn repo
61
+
62
+ ⚠️ KHÔNG BAO GIỜ gọi GitNexus tool mà THIẾU `repo` param khi có >1 repo indexed.
63
+ ```
64
+
65
+ > **Quản lý repos:** `awkit gitnexus list` để xem, `awkit gitnexus clean` để dọn repos cũ.
66
+
67
+ ---
68
+
44
69
  ## 🎯 When to Activate
45
70
 
46
71
  | Trigger | Action |
47
72
  |---------|--------|
48
73
  | Trước khi edit bất kỳ function/class/method | `gitnexus_impact` → check blast radius |
49
74
  | Debug error / trace bug | `gitnexus_query` + `gitnexus_context` |
50
- | Explore unfamiliar code | `gitnexus_query` → execution flows |
75
+ | Explore unfamiliar code | `CODEBASE.md` + `grep_search` Tìm Anchor Class → `gitnexus_context` |
51
76
  | Rename symbol | `gitnexus_rename` (dry_run trước) |
52
77
  | Trước commit | `gitnexus_detect_changes` |
53
78
  | Refactor / extract / split | `gitnexus_context` + `gitnexus_impact` |
@@ -124,14 +149,14 @@ INDEX STALE (tool trả warning):
124
149
 
125
150
  ---
126
151
 
127
- ## 📋 Workflow: Exploring Code
152
+ ## 📋 Workflow: Exploring Code (Zero-Shotgun Protocol)
128
153
 
129
154
  ```
130
- 1. READ gitnexus://repo/{name}/context → Overview + staleness
131
- 2. READ gitnexus://repo/{name}/clusters → Functional areas
132
- 3. gitnexus_query({query: "<concept>"}) → Execution flows
133
- 4. gitnexus_context({name: "<symbol>"}) Deep dive
134
- 5. READ gitnexus://repo/{name}/process/{name} → Full trace
155
+ 1. Đọc CODEBASE.md để xác định cấu trúc module / Clean Architecture layers.
156
+ 2. Dùng list_dir hoặc grep_search vào đúng thư mục dự đoán để tìm 1 "Anchor Class" (VD: ProfileViewModel).
157
+ 3. KHÔNG dùng gitnexus_query rải rác trừ khi các bước 1-2 hoàn toàn thất bại.
158
+ 4. Dùng gitnexus_context({name: "<AnchorClass>"}) để lấy 360° view các luồng dữ liệu xung quanh điểm neo này.
159
+ 5. READ gitnexus://repo/{name}/process/{name} → Full trace luồng thực thi liên quan.
135
160
  ```
136
161
 
137
162
  ---
@@ -176,10 +201,11 @@ always_do:
176
201
  - PHẢI chạy gitnexus_impact TRƯỚC khi edit bất kỳ symbol nào
177
202
  - PHẢI chạy gitnexus_detect_changes TRƯỚC khi commit
178
203
  - PHẢI cảnh báo user khi risk = HIGH hoặc CRITICAL
179
- - Ưu tiên gitnexus_query thay grep khi explore code
204
+ - PHẢI dùng GitNexus context sau khi xác định được "Anchor Class" qua heuristic search
180
205
  - PHẢI dùng gitnexus_rename (dry_run trước) khi rename
181
206
 
182
207
  never_do:
208
+ - KHÔNG gọi gitnexus_query (>1 lần) với các khái niệm bao quát ("appwrite feedback", "push notification") gây lãng phí token.
183
209
  - KHÔNG edit function/class mà chưa check impact
184
210
  - KHÔNG ignore HIGH/CRITICAL risk warnings
185
211
  - KHÔNG rename bằng find-and-replace → dùng gitnexus_rename
@@ -84,7 +84,7 @@ OPTIONAL:
84
84
  ### Phase 2: Per-Module Spec Generation
85
85
  - Gather context (BRIEF, source code, KI, NeuralMemory)
86
86
  - Generate spec theo template → `templates/module-spec-template.md`
87
- - Self-review checklist: screens đủ? flows rõ? edge cases?
87
+ - Self-review checklist: screens đủ? flows rõ? edge cases? **transitions & micro-interactions defined?**
88
88
 
89
89
  ### Phase 3: Cross-Module Consistency Check
90
90
  - Dependency graph (circular? missing cross-refs?)
@@ -85,10 +85,31 @@
85
85
 
86
86
  ---
87
87
 
88
+ ## Transitions & Micro-interactions (Mobile)
89
+
90
+ | Screen/Element | Animation Type | Details |
91
+ |----------------|---------------|---------|
92
+ | [List/Grid screen] | Staggered fade+slide | Items appear sequentially (50ms delay) |
93
+ | [Stats/Dashboard] | Number counter | Values roll/count up from 0 |
94
+ | [Navigation A→B] | Hero / Shared element | [which element animates across] |
95
+ | [Modal/Sheet] | Spring damping | Spring-based open/close |
96
+ | [Buttons/Cards] | Scale on press | Scale 0.95 + haptic impact(light) |
97
+ | [Success state] | Checkmark draw | Animated stroke white→green |
98
+ | [Error state] | Shake | Horizontal oscillation on invalid field |
99
+ | [Toggle/Switch] | Spring bounce | Spring physics + optional haptic |
100
+ | [Like/Favorite] | Pulse/Particle | Scale pulse or burst effect |
101
+
102
+ > Fill only relevant rows. Delete unused ones. Add custom animations as needed.
103
+
104
+ ---
105
+
88
106
  ## Acceptance Criteria
89
107
  - [ ] [measurable criterion 1]
90
108
  - [ ] [measurable criterion 2]
91
109
  - [ ] [measurable criterion 3]
110
+ - [ ] All loading states use skeleton→content morph transitions (no instant pop-in)
111
+ - [ ] All tappable elements have scale-on-press feedback
112
+ - [ ] Haptic feedback integrated for key interactions
92
113
  ```
93
114
 
94
115
  ---
@@ -187,16 +187,6 @@ If `nmem` is not available AND auto-install fails, falls back to flat-file behav
187
187
  - Shows warning once: "⚠️ NeuralMemory not installed. Using flat-file fallback."
188
188
  ```
189
189
 
190
- ## CLI Fallback (MCP Unresponsive)
191
-
192
- If the `neural-memory` MCP server is unresponsive or fails, you MUST fallback to using the `nmem` CLI directly using the `run_command` tool. The CLI offers full parity with the MCP tools:
193
- - `nmem_remember` -> `nmem remember "..."`
194
- - `nmem_recall` -> `nmem recall "..."`
195
- - `nmem_context` -> `nmem recap` or `nmem recall "..."`
196
- - `nmem_auto` -> `nmem auto process --text "..."`
197
-
198
- Always check the `nmem` CLI help (`nmem --help`) if unsure of the syntax.
199
-
200
190
  ---
201
191
 
202
192
  ## Integration
@@ -98,9 +98,13 @@ File patterns:
98
98
  - Đưa hướng dẫn test cụ thể
99
99
  - Gọi notify_user(BlockedOnUser=true) — DỪNG và CHỜ user response
100
100
 
101
- === TRƯỜNG HỢP 2: autoVerification = true (Auto Maestro) ===
102
- - Chạy Auto Build
103
- - Chạy mcp_maestro_launch_app, mcp_maestro_take_screenshot
104
- - NẾU Build/Run Lỗi: BlockedOnUser=true
105
- - NẾU Pass: BlockedOnUser=false. Lập tức đi tiếp!
101
+ === TRƯỜNG HỢP 2: autoVerification = true (Autonomous UI Visual Verification) ===
102
+ AI tự động thực hiện chu trình 5 bước để kiểm tra hiển thị:
103
+ 1. [ISOLATION]: Tạm thời chỉnh sửa Entry File (ContentView/MainActivity/App) để boot trực tiếp vào màn hình mục tiêu. Inject mock-data.
104
+ 2. [BOOT]: Chạy Auto Build và Launch app lên Simulator/Emulator (hoặc dùng mcp_maestro_launch_app).
105
+ 3. [VERIFY]: Call CLI / Maestro take_screenshot. AI gọi `view_file` lên ảnh để đối chiếu vs Thiết kế (Padding, Colors, Text, State).
106
+ 4. [MANDATORY REVERT]: BẤT KỂ kết quả ra sao (hay build lỗi), PHẢI gỡ bỏ code Isolation, trả Entry File về phiên bản gốc (dùng Git stash hoặc revert tay).
107
+ 5. [FEEDBACK LOOP]:
108
+ - Nếu PASS: BlockedOnUser=false. Lập tức đi tiếp!
109
+ - Nếu FAIL: AI tự log ra file kết quả chẩn đoán lỗi hiển thị -> Tự vòng lại sửa Code -> Start Bước 1. (Tối đa 3 vòng lặp mindful_pause).
106
110
  ```