@leejungkiin/awkit 1.7.1 → 1.7.4
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 +576 -84
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +148 -167
- package/core/GEMINI.md.bak +149 -116
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_ponytail_integration.md +146 -0
- package/docs/brainstorm_smart_setup.md +113 -0
- package/docs/deep-research-report (1).md +293 -0
- package/docs/history/GEMINI.v1.md +135 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/package.json +4 -1
- package/scripts/artifact-storage.js +130 -0
- package/scripts/automation-gate.js +35 -2
- package/scripts/claude-plan.js +76 -0
- package/scripts/dependency-manager.js +210 -0
- package/scripts/exec-rtk.js +11 -5
- package/scripts/i18n-helper.js +381 -0
- package/scripts/multi-model-pipeline.js +144 -0
- package/skill-packs/mobile-ios/pack.json +4 -2
- package/skill-packs/reverse-engineering/pack.json +1 -0
- package/skills/CATALOG.md +20 -0
- package/skills/GEMINI.md +9 -1
- package/skills/TRIGGER_INDEX.md +10 -0
- package/skills/ai-music/SKILL.md +275 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/animal-island-ui-style/SKILL.md +1450 -0
- package/skills/app-store-review-agent/SKILL.md +164 -0
- package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
- package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
- package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
- package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
- package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
- package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
- package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
- package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
- package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
- package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
- package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
- package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
- package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
- package/skills/awf-ponytail/SKILL.md +91 -0
- package/skills/awf-ponytail-review/SKILL.md +67 -0
- package/skills/awf-session-restore/SKILL.md +3 -3
- package/skills/brainstorm-agent/SKILL.md +11 -2
- package/skills/brainstorm-agent/templates/brief-template.md +8 -0
- package/skills/claude-planner/SKILL.md +47 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/expo-game-development/SKILL.md +163 -0
- package/skills/flutter/LICENSE.txt +202 -0
- package/skills/flutter/SKILL.md +127 -0
- package/skills/flutter-project-creater/LICENSE.txt +202 -0
- package/skills/flutter-project-creater/SKILL.md +106 -0
- package/skills/game-developer/SKILL.md +163 -0
- package/skills/game-developer/references/ecs-patterns.md +501 -0
- package/skills/game-developer/references/multiplayer-networking.md +475 -0
- package/skills/game-developer/references/performance-optimization.md +422 -0
- package/skills/game-developer/references/unity-patterns.md +271 -0
- package/skills/game-developer/references/unreal-cpp.md +352 -0
- package/skills/generate-gui-assets/SKILL.md +305 -0
- package/skills/generate-gui-assets/agents/openai.yaml +4 -0
- package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
- package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
- package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
- package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
- package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
- package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
- package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
- package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
- package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
- package/skills/godot-game-development/SKILL.md +142 -0
- package/skills/hatch-pet/LICENSE.txt +201 -0
- package/skills/hatch-pet/SKILL.md +420 -0
- package/skills/hatch-pet/agents/openai.yaml +4 -0
- package/skills/hatch-pet/references/animation-rows.md +29 -0
- package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
- package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
- package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
- package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/skills/i18n-orchestrator/SKILL.md +37 -0
- package/skills/ios-simulator-skill/SKILL.md +390 -0
- package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
- package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
- package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
- package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
- package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
- package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
- package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
- package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
- package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
- package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
- package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
- package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
- package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
- package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
- package/skills/ios-simulator-skill/scripts/container.py +668 -0
- package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
- package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
- package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
- package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
- package/skills/ios-simulator-skill/scripts/location.py +467 -0
- package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
- package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
- package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
- package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
- package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
- package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
- package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
- package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
- package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
- package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
- package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
- package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
- package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
- package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
- package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
- package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
- package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
- package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
- package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
- package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
- package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
- package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
- package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
- package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
- package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
- package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
- package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
- package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
- package/skills/orchestrator/SKILL.md +0 -20
- package/skills/persistent-storage/SKILL.md +55 -0
- package/skills/short-maker/SKILL.md +23 -0
- package/skills/short-maker/scripts/effects.js +56 -0
- package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
- package/skills/short-maker/scripts/videomix.js +601 -0
- package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
- package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
- package/skills/smali-to-kotlin/SKILL.md +128 -0
- package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
- package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
- package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/spec-gate/SKILL.md +6 -2
- package/skills/symphony-enforcer/SKILL.md +8 -0
- package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
- package/skills/symphony-enforcer/examples/three-phase.md +16 -0
- package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
- package/skills/unity-game-development/SKILL.md +231 -0
- package/skills/video-edit/SKILL.md +36 -0
- package/skills/video-edit/scripts/video_edit.py +324 -0
- package/templates/project-identity/android.json +2 -2
- package/templates/project-identity/backend-nestjs.json +2 -2
- package/templates/project-identity/expo.json +2 -2
- package/templates/project-identity/ios.json +2 -2
- package/templates/project-identity/web-nextjs.json +2 -2
- package/templates/setup-mapping.json +48 -0
- package/templates/specs/design-template.md +161 -71
- package/templates/specs/requirements-template.md +65 -133
- package/templates/specs/task-spec-template.xml +3 -0
- package/workflows/_uncategorized/critic.md +40 -0
- package/workflows/_uncategorized/git-rebase-flow.md +81 -0
- package/workflows/_uncategorized/image-gen.md +118 -0
- package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
- package/workflows/_uncategorized/pixel-gen.md +86 -0
- package/workflows/_uncategorized/pixel-setup.md +90 -0
- package/workflows/_uncategorized/ponytail-review.md +59 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/_uncategorized/safety-router.md +34 -0
- package/workflows/_uncategorized/teach.md +89 -0
- package/workflows/_uncategorized/verify-ui.md +53 -0
- package/workflows/_uncategorized/visualize-screenshots.md +34 -0
- package/workflows/ads/ads-analyst.md +201 -0
- package/workflows/ads/ads-audit.md +106 -0
- package/workflows/ads/ads-optimize.md +97 -0
- package/workflows/ads/ads-targeting.md +241 -0
- package/workflows/ads/adsExpert.md +160 -0
- package/workflows/ads/smali-ads-config.md +400 -0
- package/workflows/ads/smali-ads-flow.md +331 -0
- package/workflows/ads/smali-ads-interstitial.md +377 -0
- package/workflows/ads/smali-ads-native.md +382 -0
- package/workflows/context/teach.md +89 -0
- package/workflows/gitnexus.md +8 -8
- package/workflows/lifecycle/brainstorm.md +43 -0
- package/workflows/lifecycle/code.md +5 -0
- package/workflows/lifecycle/init.md +23 -5
- package/workflows/lifecycle/multi-model-pipeline.md +60 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- package/workflows/roles/safety-router.md +34 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const C = {
|
|
5
|
+
cyan: '\x1b[36m',
|
|
6
|
+
green: '\x1b[32m',
|
|
7
|
+
yellow: '\x1b[33m',
|
|
8
|
+
red: '\x1b[31m',
|
|
9
|
+
gray: '\x1b[90m',
|
|
10
|
+
bold: '\x1b[1m',
|
|
11
|
+
reset: '\x1b[0m'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function log(msg) { console.log(msg); }
|
|
15
|
+
function ok(msg) { log(`${C.green}✓ ${msg}${C.reset}`); }
|
|
16
|
+
function warn(msg) { log(`${C.yellow}⚠ ${msg}${C.reset}`); }
|
|
17
|
+
function err(msg) { log(`${C.red}✗ ${msg}${C.reset}`); }
|
|
18
|
+
function dim(msg) { log(`${C.gray}${msg}${C.reset}`); }
|
|
19
|
+
|
|
20
|
+
// Helper to set nested property in object (like lodash.set)
|
|
21
|
+
function setNested(obj, pathStr, value) {
|
|
22
|
+
const parts = pathStr.split('.');
|
|
23
|
+
let current = obj;
|
|
24
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
25
|
+
const part = parts[i];
|
|
26
|
+
if (current[part] === undefined || typeof current[part] !== 'object') {
|
|
27
|
+
current[part] = {};
|
|
28
|
+
}
|
|
29
|
+
current = current[part];
|
|
30
|
+
}
|
|
31
|
+
current[parts[parts.length - 1]] = value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Helper to get nested property in object
|
|
35
|
+
function getNested(obj, pathStr) {
|
|
36
|
+
const parts = pathStr.split('.');
|
|
37
|
+
let current = obj;
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
if (current === null || current === undefined) return undefined;
|
|
40
|
+
current = current[part];
|
|
41
|
+
}
|
|
42
|
+
return current;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Recursively find all nested keys and values in an object
|
|
46
|
+
function flattenObject(obj, prefix = '') {
|
|
47
|
+
let results = {};
|
|
48
|
+
for (const k in obj) {
|
|
49
|
+
if (Object.prototype.hasOwnProperty.call(obj, k)) {
|
|
50
|
+
const keyName = prefix ? `${prefix}.${k}` : k;
|
|
51
|
+
if (obj[k] !== null && typeof obj[k] === 'object' && !Array.isArray(obj[k])) {
|
|
52
|
+
Object.assign(results, flattenObject(obj[k], keyName));
|
|
53
|
+
} else {
|
|
54
|
+
results[keyName] = obj[k];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Format Javascript object as clean JS/TS string with sorted keys
|
|
62
|
+
function formatJsObject(obj, indent = 2) {
|
|
63
|
+
const spaces = ' '.repeat(indent);
|
|
64
|
+
if (Array.isArray(obj)) {
|
|
65
|
+
return '[\n' + obj.map(item => spaces + formatJsObject(item, indent + 2)).join(',\n') + '\n' + ' '.repeat(indent - 2) + ']';
|
|
66
|
+
} else if (obj !== null && typeof obj === 'object') {
|
|
67
|
+
const keys = Object.keys(obj).sort();
|
|
68
|
+
const lines = keys.map(k => {
|
|
69
|
+
const keyStr = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(k) ? k : JSON.stringify(k);
|
|
70
|
+
return `${spaces}${keyStr}: ${formatJsObject(obj[k], indent + 2)}`;
|
|
71
|
+
});
|
|
72
|
+
return '{\n' + lines.join(',\n') + '\n' + ' '.repeat(indent - 2) + '}';
|
|
73
|
+
} else {
|
|
74
|
+
return JSON.stringify(obj);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Find translation files in target directories, avoiding heavy system folders
|
|
79
|
+
function findTranslationFiles(dir) {
|
|
80
|
+
const filesList = [];
|
|
81
|
+
const ignoreList = ['node_modules', '.git', '.gitnexus', 'dist', 'build', '.expo', 'ios', 'android', 'web-build'];
|
|
82
|
+
|
|
83
|
+
function traverse(currentDir) {
|
|
84
|
+
let list;
|
|
85
|
+
try {
|
|
86
|
+
list = fs.readdirSync(currentDir);
|
|
87
|
+
} catch (_) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const file of list) {
|
|
92
|
+
const absPath = path.join(currentDir, file);
|
|
93
|
+
let stat;
|
|
94
|
+
try {
|
|
95
|
+
stat = fs.statSync(absPath);
|
|
96
|
+
} catch (_) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (stat.isDirectory()) {
|
|
101
|
+
if (ignoreList.includes(file)) continue;
|
|
102
|
+
traverse(absPath);
|
|
103
|
+
} else if (stat.isFile()) {
|
|
104
|
+
const ext = path.extname(file).toLowerCase();
|
|
105
|
+
const nameLower = file.toLowerCase();
|
|
106
|
+
|
|
107
|
+
// Look for translations.* or locale files like en.json, vi.json
|
|
108
|
+
const isTranslationFile =
|
|
109
|
+
(nameLower.includes('translation') && (ext === '.json' || ext === '.ts' || ext === '.js')) ||
|
|
110
|
+
(ext === '.json' && (nameLower === 'en.json' || nameLower === 'vi.json' || nameLower === 'ja.json'));
|
|
111
|
+
|
|
112
|
+
if (isTranslationFile) {
|
|
113
|
+
filesList.push(absPath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
traverse(dir);
|
|
120
|
+
return filesList;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Read and parse translation file safely
|
|
124
|
+
function readTranslationFile(filePath) {
|
|
125
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
126
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
127
|
+
|
|
128
|
+
if (ext === '.json') {
|
|
129
|
+
try {
|
|
130
|
+
return { type: 'json', data: JSON.parse(content), raw: content };
|
|
131
|
+
} catch (e) {
|
|
132
|
+
throw new Error(`Failed to parse JSON file ${filePath}: ${e.message}`);
|
|
133
|
+
}
|
|
134
|
+
} else if (ext === '.ts' || ext === '.js') {
|
|
135
|
+
// Find the outer curly braces block
|
|
136
|
+
const braceStart = content.indexOf('{');
|
|
137
|
+
const braceEnd = content.lastIndexOf('}');
|
|
138
|
+
if (braceStart === -1 || braceEnd === -1 || braceEnd < braceStart) {
|
|
139
|
+
throw new Error(`Could not locate object braces in JS/TS file: ${filePath}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const objectStr = content.substring(braceStart, braceEnd + 1);
|
|
143
|
+
try {
|
|
144
|
+
// Safe evaluation of object content
|
|
145
|
+
const data = new Function(`return (${objectStr})`)();
|
|
146
|
+
return {
|
|
147
|
+
type: 'js',
|
|
148
|
+
data,
|
|
149
|
+
prefix: content.substring(0, braceStart),
|
|
150
|
+
suffix: content.substring(braceEnd + 1),
|
|
151
|
+
raw: content
|
|
152
|
+
};
|
|
153
|
+
} catch (e) {
|
|
154
|
+
throw new Error(`Failed to parse JS/TS object in ${filePath}: ${e.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
throw new Error(`Unsupported translation file type: ${ext}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Write translation file safely
|
|
162
|
+
function writeTranslationFile(filePath, fileInfo) {
|
|
163
|
+
if (fileInfo.type === 'json') {
|
|
164
|
+
// Sort keys recursively
|
|
165
|
+
const sorted = sortObjectKeys(fileInfo.data);
|
|
166
|
+
fs.writeFileSync(filePath, JSON.stringify(sorted, null, 2) + '\n', 'utf8');
|
|
167
|
+
} else if (fileInfo.type === 'js') {
|
|
168
|
+
const sorted = sortObjectKeys(fileInfo.data);
|
|
169
|
+
const formatted = formatJsObject(sorted);
|
|
170
|
+
fs.writeFileSync(filePath, `${fileInfo.prefix}${formatted}${fileInfo.suffix}`, 'utf8');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Sort object keys recursively
|
|
175
|
+
function sortObjectKeys(obj) {
|
|
176
|
+
if (Array.isArray(obj)) {
|
|
177
|
+
return obj.map(sortObjectKeys);
|
|
178
|
+
} else if (obj !== null && typeof obj === 'object') {
|
|
179
|
+
const sorted = {};
|
|
180
|
+
Object.keys(obj).sort().forEach(key => {
|
|
181
|
+
sorted[key] = sortObjectKeys(obj[key]);
|
|
182
|
+
});
|
|
183
|
+
return sorted;
|
|
184
|
+
}
|
|
185
|
+
return obj;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// CLI implementation
|
|
189
|
+
async function cmdI18n(args) {
|
|
190
|
+
const subCmd = args[0] || 'help';
|
|
191
|
+
|
|
192
|
+
if (subCmd === 'help' || subCmd === '--help' || subCmd === '-h') {
|
|
193
|
+
log('');
|
|
194
|
+
log(`${C.cyan}${C.bold}🌐 awkit i18n — Language & Translation Workflow Helper${C.reset}`);
|
|
195
|
+
log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
|
|
196
|
+
log(`Manage your localization and translation files cleanly.`);
|
|
197
|
+
log('');
|
|
198
|
+
log(`${C.bold}Commands:${C.reset}`);
|
|
199
|
+
log(` ${C.green}add${C.reset} --key <key> [--en <val>] [--vi <val>] ...`);
|
|
200
|
+
log(` Add a translation key with values across files.`);
|
|
201
|
+
log(` ${C.green}search${C.reset} <query> (or find)`);
|
|
202
|
+
log(` Search for translation keys or values containing query.`);
|
|
203
|
+
log(` ${C.green}sync${C.reset}`);
|
|
204
|
+
log(` Alphabetically sort and synchronize keys across all translation files.`);
|
|
205
|
+
log(` ${C.green}list${C.reset}`);
|
|
206
|
+
log(` List all translations mapped in the project.`);
|
|
207
|
+
log('');
|
|
208
|
+
log(`${C.bold}Examples:${C.reset}`);
|
|
209
|
+
log(` awkit i18n add --key "auth.login.title" --en "Log In" --vi "Đăng nhập"`);
|
|
210
|
+
log(` awkit i18n search "Welcome"`);
|
|
211
|
+
log('');
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const cwd = process.cwd();
|
|
216
|
+
|
|
217
|
+
// Read files configured in .project-identity or auto-detect
|
|
218
|
+
let configFiles = [];
|
|
219
|
+
const identityPath = path.join(cwd, '.project-identity');
|
|
220
|
+
if (fs.existsSync(identityPath)) {
|
|
221
|
+
try {
|
|
222
|
+
const identity = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
223
|
+
if (identity.i18n && Array.isArray(identity.i18n.files)) {
|
|
224
|
+
configFiles = identity.i18n.files.map(f => path.resolve(cwd, f));
|
|
225
|
+
}
|
|
226
|
+
} catch (_) {}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const files = configFiles.length > 0 ? configFiles : findTranslationFiles(cwd);
|
|
230
|
+
|
|
231
|
+
if (files.length === 0) {
|
|
232
|
+
err('No translation files found in this repository.');
|
|
233
|
+
dim('Either configure "i18n.files" in .project-identity or place translation files matching *translation*.{json,ts,js} or en.json/vi.json.');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
switch (subCmd) {
|
|
238
|
+
case 'add': {
|
|
239
|
+
// Parse arguments
|
|
240
|
+
let key = '';
|
|
241
|
+
const translations = {};
|
|
242
|
+
|
|
243
|
+
for (let i = 1; i < args.length; i++) {
|
|
244
|
+
if (args[i] === '--key') {
|
|
245
|
+
key = args[++i];
|
|
246
|
+
} else if (args[i].startsWith('--')) {
|
|
247
|
+
const lang = args[i].substring(2);
|
|
248
|
+
translations[lang] = args[++i];
|
|
249
|
+
} else if (args[i].includes(':')) {
|
|
250
|
+
// Alternative syntax: en:Hello
|
|
251
|
+
const parts = args[i].split(':');
|
|
252
|
+
const lang = parts[0];
|
|
253
|
+
const val = parts.slice(1).join(':');
|
|
254
|
+
translations[lang] = val;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (!key) {
|
|
259
|
+
err('Missing translation key. Specify using --key <key_name>');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (Object.keys(translations).length === 0) {
|
|
264
|
+
err('No translations specified. E.g. --en "Hello" --vi "Xin chào"');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
info(`Adding key "${key}" to translation files...`);
|
|
269
|
+
|
|
270
|
+
for (const file of files) {
|
|
271
|
+
const basename = path.basename(file);
|
|
272
|
+
const fileLang = basename.split('.')[0].toLowerCase(); // e.g. en, vi, translations
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
const fileInfo = readTranslationFile(file);
|
|
276
|
+
|
|
277
|
+
// Match translation value. If file name is specific like en.json or vi.json, inject specific lang.
|
|
278
|
+
// If it is translations.ts, inject nested object languages.
|
|
279
|
+
if (fileLang === 'en' || fileLang === 'vi') {
|
|
280
|
+
const val = translations[fileLang] || translations['en'] || Object.values(translations)[0];
|
|
281
|
+
setNested(fileInfo.data, key, val);
|
|
282
|
+
} else {
|
|
283
|
+
// Mixed translation file (e.g. translations.ts), set language key paths
|
|
284
|
+
for (const lang in translations) {
|
|
285
|
+
if (fileInfo.data[lang] !== undefined) {
|
|
286
|
+
setNested(fileInfo.data[lang], key, translations[lang]);
|
|
287
|
+
} else {
|
|
288
|
+
// Fallback directly on root
|
|
289
|
+
setNested(fileInfo.data, `${lang}.${key}`, translations[lang]);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
writeTranslationFile(file, fileInfo);
|
|
295
|
+
ok(`Updated ${basename}`);
|
|
296
|
+
} catch (e) {
|
|
297
|
+
err(`Failed updating ${basename}: ${e.message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
case 'search':
|
|
304
|
+
case 'find': {
|
|
305
|
+
const query = args.slice(1).join(' ').toLowerCase();
|
|
306
|
+
if (!query) {
|
|
307
|
+
err('Please specify a query to search.');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
log(`\n🔍 Searching for "${query}" in translations...`);
|
|
312
|
+
log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
|
|
313
|
+
|
|
314
|
+
let matchesFound = 0;
|
|
315
|
+
for (const file of files) {
|
|
316
|
+
try {
|
|
317
|
+
const fileInfo = readTranslationFile(file);
|
|
318
|
+
const flattened = flattenObject(fileInfo.data);
|
|
319
|
+
|
|
320
|
+
for (const key in flattened) {
|
|
321
|
+
const val = String(flattened[key]);
|
|
322
|
+
if (key.toLowerCase().includes(query) || val.toLowerCase().includes(query)) {
|
|
323
|
+
log(` [${C.cyan}${path.basename(file)}${C.reset}] ${C.green}${key}${C.reset}: "${val}"`);
|
|
324
|
+
matchesFound++;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
} catch (e) {
|
|
328
|
+
err(`Error scanning ${path.basename(file)}: ${e.message}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (matchesFound === 0) {
|
|
332
|
+
warn('No matches found.');
|
|
333
|
+
} else {
|
|
334
|
+
log(`\nFound ${matchesFound} matches.`);
|
|
335
|
+
}
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
case 'sync': {
|
|
340
|
+
info('Synchronizing and formatting all translation files...');
|
|
341
|
+
for (const file of files) {
|
|
342
|
+
try {
|
|
343
|
+
const fileInfo = readTranslationFile(file);
|
|
344
|
+
writeTranslationFile(file, fileInfo);
|
|
345
|
+
ok(`Synced & Sorted ${path.basename(file)}`);
|
|
346
|
+
} catch (e) {
|
|
347
|
+
err(`Failed to sync ${path.basename(file)}: ${e.message}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
case 'list': {
|
|
354
|
+
log(`\n📋 Listing all translation entries:`);
|
|
355
|
+
log(`${C.gray}${'─'.repeat(56)}${C.reset}`);
|
|
356
|
+
for (const file of files) {
|
|
357
|
+
try {
|
|
358
|
+
const fileInfo = readTranslationFile(file);
|
|
359
|
+
const flattened = flattenObject(fileInfo.data);
|
|
360
|
+
log(`\n${C.cyan}${path.basename(file)}${C.reset}:`);
|
|
361
|
+
for (const key in flattened) {
|
|
362
|
+
log(` ${C.green}${key}${C.reset}: "${flattened[key]}"`);
|
|
363
|
+
}
|
|
364
|
+
} catch (e) {
|
|
365
|
+
err(`Error reading ${path.basename(file)}: ${e.message}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
default:
|
|
372
|
+
err(`Unknown command: ${subCmd}`);
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function info(msg) { log(`${C.cyan}ℹ ${msg}${C.reset}`); }
|
|
378
|
+
|
|
379
|
+
module.exports = {
|
|
380
|
+
cmdI18n
|
|
381
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Model Collaborative Pipeline Helper for AWKit
|
|
3
|
+
* Orchestrates tasks across Gemini Flash Medium, agy (Claude Opus), and Codex.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
const AGY_PATH = '/Users/trungkientn/.local/bin/agy';
|
|
11
|
+
|
|
12
|
+
const C = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
red: '\x1b[31m',
|
|
15
|
+
green: '\x1b[32m',
|
|
16
|
+
yellow: '\x1b[33m',
|
|
17
|
+
cyan: '\x1b[36m',
|
|
18
|
+
gray: '\x1b[90m',
|
|
19
|
+
bold: '\x1b[1m',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const log = (msg) => console.log(msg);
|
|
23
|
+
const ok = (msg) => log(`${C.green}✔${C.reset} ${msg}`);
|
|
24
|
+
const warn = (msg) => log(`${C.yellow}⚠${C.reset} ${msg}`);
|
|
25
|
+
const err = (msg) => log(`${C.red}✖${C.reset} ${msg}`);
|
|
26
|
+
const info = (msg) => log(`${C.cyan}ℹ${C.reset} ${msg}`);
|
|
27
|
+
|
|
28
|
+
function findAgy() {
|
|
29
|
+
if (fs.existsSync(AGY_PATH)) {
|
|
30
|
+
return AGY_PATH;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return execSync('which agy', { encoding: 'utf8' }).trim();
|
|
34
|
+
} catch (_) {
|
|
35
|
+
return 'agy';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function runPlanStep(featureName) {
|
|
40
|
+
const agyBin = findAgy();
|
|
41
|
+
info(`Khởi chạy Lập kế hoạch Kiến trúc (Opus 4.6 via agy CLI)...`);
|
|
42
|
+
|
|
43
|
+
// Ensure docs and docs/specs directories exist
|
|
44
|
+
fs.mkdirSync(path.join(process.cwd(), 'docs', 'specs'), { recursive: true });
|
|
45
|
+
|
|
46
|
+
const specFile = `docs/specs/${featureName.toLowerCase().replace(/\s+/g, '_')}_spec.md`;
|
|
47
|
+
const prompt = `Thực hiện lập kế hoạch chi tiết cho tính năng '${featureName}'. Tạo PRD tại docs/PRD.md và Spec chi tiết tại ${specFile}. Hãy vẽ kèm sơ đồ Mermaid thể hiện luồng xử lý. Hãy phản hồi ngắn gọn bằng JSON tóm tắt các files đã tạo và mô tả kế hoạch.`;
|
|
48
|
+
|
|
49
|
+
const cmd = `"${agyBin}" --model claude-opus --print "${prompt.replace(/"/g, '\\"')}" < /dev/null`;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
log(`${C.gray}$ ${cmd}${C.reset}`);
|
|
53
|
+
const output = execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] });
|
|
54
|
+
log(output);
|
|
55
|
+
ok(`Hoàn thành lập kế hoạch kiến trúc.`);
|
|
56
|
+
ok(`PRD đã lưu tại docs/PRD.md`);
|
|
57
|
+
ok(`Spec đã lưu tại ${specFile}`);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
err(`Lỗi lập kế hoạch: ${e.message}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runUiStep(featureName) {
|
|
65
|
+
info(`Khởi chạy Thiết kế Shell & GUI Assets (Codex CLI)...`);
|
|
66
|
+
|
|
67
|
+
// Ensure assets/ui directory exists
|
|
68
|
+
fs.mkdirSync(path.join(process.cwd(), 'assets', 'ui'), { recursive: true });
|
|
69
|
+
|
|
70
|
+
// Step A: Prompt to generate layout demo preview HTML/CSS or mockup code
|
|
71
|
+
const promptPreview = `Tạo UI Demo Preview dưới dạng HTML/CSS tĩnh hoặc SwiftUI shell cho tính năng '${featureName}' dựa trên tài liệu docs/PRD.md và spec hiện có. Lưu tệp demo vào assets/ui/demo_preview.html.`;
|
|
72
|
+
const cmdPreview = `codex exec "${promptPreview.replace(/"/g, '\\"')}" --sandbox read-only < /dev/null`;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
log(`${C.gray}$ ${cmdPreview}${C.reset}`);
|
|
76
|
+
const outPreview = execSync(cmdPreview, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] });
|
|
77
|
+
log(outPreview);
|
|
78
|
+
ok(`Đã sinh UI Demo Preview tại assets/ui/demo_preview.html`);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
err(`Lỗi sinh UI Demo Preview: ${e.message}`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Step B: Prompt to generate spritesheet/image assets
|
|
85
|
+
const promptAssets = `Tạo GUI assets (nút bấm, icons, pet companion, egg) dưới dạng spritesheet hoặc dạng assets lẻ dựa trên thiết kế của UI Demo Preview. Lưu tệp assets vào thư mục assets/ui/.`;
|
|
86
|
+
const cmdAssets = `codex exec "${promptAssets.replace(/"/g, '\\"')}" --sandbox read-only < /dev/null`;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
log(`${C.gray}$ ${cmdAssets}${C.reset}`);
|
|
90
|
+
const outAssets = execSync(cmdAssets, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] });
|
|
91
|
+
log(outAssets);
|
|
92
|
+
ok(`Đã sinh GUI assets thành công vào assets/ui/`);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
err(`Lỗi sinh GUI assets: ${e.message}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function runCodeStep(featureName) {
|
|
100
|
+
const agyBin = findAgy();
|
|
101
|
+
info(`Khởi chạy Thực thi Viết Code (Gemini via agy CLI)...`);
|
|
102
|
+
|
|
103
|
+
const promptCode = `Hãy thực hiện viết code cho tính năng '${featureName}' tuân thủ kế hoạch chi tiết trong implementation_plan.md và các spec giao diện trong docs/specs/. Sau đó tự động gọi critic subagent để review code.`;
|
|
104
|
+
const cmdCode = `"${agyBin}" --model gemini-2.5-flash --print "${promptCode.replace(/"/g, '\\"')}" < /dev/null`;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
log(`${C.gray}$ ${cmdCode}${C.reset}`);
|
|
108
|
+
const output = execSync(cmdCode, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] });
|
|
109
|
+
log(output);
|
|
110
|
+
ok(`Đã viết code và hoàn tất quá trình review từ critic subagent.`);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
err(`Lỗi thực thi viết code: ${e.message}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function cmdPipeline(args) {
|
|
118
|
+
const step = args[0];
|
|
119
|
+
const featureName = args[1] || 'NewFeature';
|
|
120
|
+
|
|
121
|
+
if (!step) {
|
|
122
|
+
console.error('Usage: awkit pipeline <plan|ui|code> [FeatureName]');
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
switch (step.toLowerCase()) {
|
|
127
|
+
case 'plan':
|
|
128
|
+
runPlanStep(featureName);
|
|
129
|
+
break;
|
|
130
|
+
case 'ui':
|
|
131
|
+
runUiStep(featureName);
|
|
132
|
+
break;
|
|
133
|
+
case 'code':
|
|
134
|
+
runCodeStep(featureName);
|
|
135
|
+
break;
|
|
136
|
+
default:
|
|
137
|
+
console.error(`Unknown step: ${step}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = {
|
|
143
|
+
cmdPipeline,
|
|
144
|
+
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mobile-ios",
|
|
3
3
|
"auto_install": false,
|
|
4
|
-
"description": "iOS development skills: Xcode, Swift, SwiftUI, reverse engineering, build optimization, and SPM analysis",
|
|
4
|
+
"description": "iOS development skills: Xcode, Swift, SwiftUI, reverse engineering, build optimization, visual QA, and SPM analysis",
|
|
5
5
|
"skills": [
|
|
6
6
|
"ios-engineer",
|
|
7
|
+
"ios-visual-qa-strategist",
|
|
7
8
|
"smali-to-swift",
|
|
8
9
|
"swiftui-pro",
|
|
9
10
|
"xcode-build-benchmark",
|
|
@@ -11,6 +12,7 @@
|
|
|
11
12
|
"xcode-build-orchestrator",
|
|
12
13
|
"xcode-compilation-analyzer",
|
|
13
14
|
"xcode-project-analyzer",
|
|
14
|
-
"spm-build-analysis"
|
|
15
|
+
"spm-build-analysis",
|
|
16
|
+
"ios-simulator-skill"
|
|
15
17
|
]
|
|
16
18
|
}
|
package/skills/CATALOG.md
CHANGED
|
@@ -36,6 +36,26 @@
|
|
|
36
36
|
| 15 | `spec-gate` | `auto` | Gate 2 check fail | 2 | 1.0.0 | ✅ Active |
|
|
37
37
|
| 16 | `visual-design-gate` | `auto` | Gate 2.5 check fail | 2.5 | 1.0.0 | ✅ Active |
|
|
38
38
|
| 17 | `trello-sync` | `auto` | Always | 2 | 3.0.0 | ✅ Active |
|
|
39
|
+
| 18 | `animal-island-ui-style` | `manual` | keywords (动物森友会, 可爱圆润 UI) | — | 1.0.0 | ✅ Active |
|
|
40
|
+
| 19 | `ios-visual-qa-strategist` | `manual` | iOS visual QA, simulator screenshots, minimal capture testing | — | 1.0.0 | ✅ Active |
|
|
41
|
+
| 20 | `ios-simulator-skill` | `manual` | iOS app building, testing, and simulator control | — | 1.5.0 | ✅ Active |
|
|
42
|
+
| 21 | `unity-game-development` | `manual` | Unity C# coding, ScriptableObjects, and profiling | — | 1.0.0 | ✅ Active |
|
|
43
|
+
| 22 | `godot-game-development` | `manual` | Godot 4 GDScript, composition and signal design | — | 1.0.0 | ✅ Active |
|
|
44
|
+
| 23 | `expo-game-development` | `manual` | Expo/React Native Skia/GL game loop optimization | — | 1.0.0 | ✅ Active |
|
|
45
|
+
| 24 | `ai-music` | `manual` | generate music, make a song, AI music, soundtrack, jingle, compose, inpaint music | — | 1.0.0 | ✅ Active |
|
|
46
|
+
| 25 | `game-developer` | `manual` | Unity, Unreal Engine, ECS architecture, game physics, multiplayer networking, shader programming, game AI | — | 1.1.0 | ✅ Active |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Ponytail (Code Minimalism)
|
|
51
|
+
|
|
52
|
+
> Adapted from [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) (MIT).
|
|
53
|
+
> Enforces lazy senior dev coding: YAGNI, stdlib/native first, no unrequested abstractions.
|
|
54
|
+
|
|
55
|
+
| # | Skill | Type | Trigger | Priority | Version | Status |
|
|
56
|
+
|---|-------|------|---------|----------|---------|--------|
|
|
57
|
+
| 26 | `awf-ponytail` | `auto` | `.project-identity` check (default ON) | 7.6 | 1.0.0 | ✅ Active |
|
|
58
|
+
| 27 | `awf-ponytail-review` | `manual` | `/ponytail-review`, "what can we delete", Gate 5 | — | 1.0.0 | ✅ Active |
|
|
39
59
|
|
|
40
60
|
---
|
|
41
61
|
|
package/skills/GEMINI.md
CHANGED
|
@@ -78,6 +78,14 @@ Mỗi skill tự xử lý gate logic riêng — xem SKILL.md của từng skill.
|
|
|
78
78
|
- Code/Docs/Comments: Tiếng Anh.
|
|
79
79
|
- Kết thúc task: Tóm tắt + Test + Next steps.
|
|
80
80
|
- Không rõ: Hỏi lại, tối đa 2 lần.
|
|
81
|
+
- 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.
|
|
82
|
+
|
|
83
|
+
### Brainstorm & Plan Integrity (BPIP)
|
|
84
|
+
- CẤM ghi đè (overwrite) toàn bộ BRIEF.md hoặc plan.md khi tinh chỉnh ý tưởng.
|
|
85
|
+
- PHẢI sử dụng công cụ sửa code (replace_file_content) để cập nhật từng phần.
|
|
86
|
+
- PHẢI duy trì bảng Revision History ở đầu mỗi file design/planning.
|
|
87
|
+
- PHẢI lưu bản sao dự phòng vào `docs/history/` trước khi sửa đổi lớn (định dạng `[filename].v[N].md`, ví dụ: `implementation_plan.v1.md`).
|
|
88
|
+
- CẤM dồn tất cả các phiên/tính năng vào một file `implementation_plan.md` duy nhất. PHẢI tách thành các kế hoạch phân mảnh (ví dụ: `implementation_plan.v2.md` hoặc `implementation_plan_feature.md`) và duy trì liên kết ngữ cảnh (Chain of Plans) đến phiên trước kèm tóm tắt ngắn ở đầu file mới.
|
|
81
89
|
|
|
82
90
|
### Anti-sycophancy (Trung thực)
|
|
83
91
|
- PHẢI push back khi approach của user có vấn đề — giải thích rõ trade-offs.
|
|
@@ -119,7 +127,7 @@ Khi AI cần tự quyết định mà không hỏi user:
|
|
|
119
127
|
- Risk HIGH/CRITICAL → PHẢI cảnh báo user trước khi sửa.
|
|
120
128
|
- Explore code lạ → ưu tiên `gitnexus_query` thay vì grep thủ công.
|
|
121
129
|
- Rename symbol → PHẢI dùng `gitnexus_rename` (dry_run trước).
|
|
122
|
-
- Index stale → cảnh báo "⚠️ chạy `npx gitnexus analyze`".
|
|
130
|
+
- Index stale → cảnh báo "⚠️ chạy `pnpm dlx gitnexus analyze` (hoặc `npx gitnexus analyze`)".
|
|
123
131
|
- Chi tiết: xem `gitnexus-intelligence/SKILL.md`.
|
|
124
132
|
|
|
125
133
|
### Two-Agent Flow (Conductor)
|
package/skills/TRIGGER_INDEX.md
CHANGED
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
| ship-to-code | Code porting, migration, language translation | ship-to-code/SKILL.md | 🟢 |
|
|
20
20
|
| visual-design-gate | Gate 2.5 UI/UX design sync | visual-design-gate/SKILL.md | 🟢 |
|
|
21
21
|
| module-spec-writer | Gate 1.5 COMPLEX + >3 modules | module-spec-writer/SKILL.md | 🟢 |
|
|
22
|
+
| animal-island-ui-style | Animal Crossing (动物森友会) style, animal-island-ui, 可爱圆润风格 UI | animal-island-ui-style/SKILL.md | 🟢 |
|
|
23
|
+
| i18n-orchestrator | Translation, localization, i18n, translations, file ngôn ngữ | i18n-orchestrator/SKILL.md | 🟢 |
|
|
24
|
+
| ios-visual-qa-strategist | iOS visual QA, SwiftUI/UIKit app testing, simulator screenshots, minimal screenshot capture | ios-visual-qa-strategist/SKILL.md | 🟢 |
|
|
25
|
+
| ios-simulator-skill | iOS app testing, building, simulator control, accessibility mapping, and simulator automation | ios-simulator-skill/SKILL.md | 🟢 |
|
|
26
|
+
| unity-game-development | Unity, C#, MonoBehaviour, ScriptableObject, FixedUpdate, object pool | unity-game-development/SKILL.md | 🟢 |
|
|
27
|
+
| godot-game-development | Godot, GDScript, CharacterBody2D, CharacterBody3D, autoload, signal.connect | godot-game-development/SKILL.md | 🟢 |
|
|
28
|
+
| expo-game-development | Expo game, React Native Skia, expo-gl, requestAnimationFrame, expo-av, GestureHandler | expo-game-development/SKILL.md | 🟢 |
|
|
29
|
+
| ai-music | generate music, make a song, AI music, background music, soundtrack, jingle, theme music, royalty-free music, compose, music with lyrics, extend music, fix this song, inpaint music, runcomfy music | ai-music/SKILL.md | 🟢 |
|
|
30
|
+
| game-developer | Unity, Unreal Engine, game development, ECS architecture, game physics, multiplayer networking, game optimization, shader programming, game AI, object pooling, state machine, LOD | game-developer/SKILL.md | 🟢 |
|
|
31
|
+
|
|
22
32
|
|
|
23
33
|
## File Guards
|
|
24
34
|
|