@leejungkiin/awkit 1.7.1 → 1.7.5
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 +42 -5
- package/bin/awk.js +1148 -92
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +152 -167
- package/core/GEMINI.md.bak +153 -116
- package/core/GreetingEngine/index.js +225 -0
- package/core/GreetingEngine/locales/en.json +6 -0
- package/core/GreetingEngine/locales/ja.json +6 -0
- package/core/GreetingEngine/locales/vi.json +6 -0
- package/core/GreetingEngine/test.js +37 -0
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/PRD.md +57 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_multi_agent_cli.md +211 -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/PRD.v1.md +55 -0
- package/docs/history/PRD.v2.md +57 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/docs/history/memoizedfibonacci_spec.v1.md +127 -0
- package/docs/specs/greetingapp_spec.md +97 -0
- package/docs/specs/memoizedfibonacci_spec.md +211 -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 +386 -0
- package/scripts/qwen-exec.js +147 -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 +71 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/codex-conductor/SKILL.md +25 -1
- 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/qwen-conductor/SKILL.md +100 -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/multi-agent-pipeline.md +52 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- package/workflows/roles/safety-router.md +34 -0
package/bin/awk.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* awkit list-packs List available skill packs
|
|
20
20
|
* awkit tg setup Setup Telegram Bot API credentials
|
|
21
21
|
* awkit tg send Send a message via Telegram Bot API
|
|
22
|
+
* awkit build Run project build command securely based on configuration
|
|
22
23
|
* awkit version Show current version
|
|
23
24
|
*
|
|
24
25
|
* Created by Kien AI
|
|
@@ -43,6 +44,11 @@ const { cmdGate } = require('../scripts/automation-gate');
|
|
|
43
44
|
const { cmdObsidian } = require('../scripts/obsidian-sync');
|
|
44
45
|
const { cmdQuota } = require('../scripts/cockpit-quota');
|
|
45
46
|
const { cmdVideo } = require('../scripts/video-analyzer');
|
|
47
|
+
const { cmdI18n } = require('../scripts/i18n-helper');
|
|
48
|
+
const { cmdStorage } = require('../scripts/artifact-storage');
|
|
49
|
+
const { cmdPipeline } = require('../scripts/multi-model-pipeline');
|
|
50
|
+
const depManager = require('../scripts/dependency-manager');
|
|
51
|
+
|
|
46
52
|
|
|
47
53
|
// ─── Platform Definitions ──────────────────────────────────────────────────
|
|
48
54
|
|
|
@@ -368,7 +374,7 @@ function copyDirRecursive(src, dest, options = {}) {
|
|
|
368
374
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
369
375
|
|
|
370
376
|
for (const entry of entries) {
|
|
371
|
-
if (entry.name === '.DS_Store' || entry.name === '.git') continue;
|
|
377
|
+
if (entry.name === '.DS_Store' || entry.name === '.git' || entry.name === '.venv' || entry.name === 'node_modules') continue;
|
|
372
378
|
|
|
373
379
|
const srcPath = path.join(src, entry.name);
|
|
374
380
|
|
|
@@ -898,14 +904,19 @@ function cmdUpdate() {
|
|
|
898
904
|
log(`${C.gray} local repo: v${AWK_VERSION}${C.reset}`);
|
|
899
905
|
log('');
|
|
900
906
|
|
|
901
|
-
// 3. Already up-to-date?
|
|
902
|
-
if (npmLatest
|
|
903
|
-
|
|
904
|
-
|
|
907
|
+
// 3. Already up-to-date or newer?
|
|
908
|
+
if (npmLatest) {
|
|
909
|
+
if (npmLatest === installedVersion) {
|
|
910
|
+
ok(`Already on the latest version (v${installedVersion}) 🎉`);
|
|
911
|
+
return;
|
|
912
|
+
} else if (isNewerVersion(installedVersion, npmLatest)) {
|
|
913
|
+
ok(`Your installed version (v${installedVersion}) is newer than the npm registry version (v${npmLatest}) 🎉`);
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
905
916
|
}
|
|
906
917
|
|
|
907
918
|
// 4. New version available on npm → install from registry
|
|
908
|
-
if (npmLatest && npmLatest
|
|
919
|
+
if (npmLatest && isNewerVersion(npmLatest, installedVersion)) {
|
|
909
920
|
info(`Upgrading: v${installedVersion} → v${npmLatest}`);
|
|
910
921
|
info('Running: npm install -g @leejungkiin/awkit');
|
|
911
922
|
try {
|
|
@@ -924,13 +935,15 @@ function cmdUpdate() {
|
|
|
924
935
|
// 5. Offline fallback: compare AWK_VERSION (local repo) vs installed
|
|
925
936
|
if (installedVersion === AWK_VERSION) {
|
|
926
937
|
ok(`Already on latest version (v${AWK_VERSION}) — could not verify with npm`);
|
|
927
|
-
} else {
|
|
938
|
+
} else if (isNewerVersion(AWK_VERSION, installedVersion)) {
|
|
928
939
|
info(`Upgrading from v${installedVersion} → v${AWK_VERSION} (local only, npm unreachable)`);
|
|
929
940
|
cmdInstall(['--update']);
|
|
941
|
+
} else {
|
|
942
|
+
ok(`Your installed version (v${installedVersion}) is newer than or equal to local repo version (v${AWK_VERSION})`);
|
|
930
943
|
}
|
|
931
944
|
}
|
|
932
945
|
|
|
933
|
-
function cmdDoctor() {
|
|
946
|
+
async function cmdDoctor() {
|
|
934
947
|
log('');
|
|
935
948
|
log(`${C.cyan}${C.bold}🏥 AWK Health Check${C.reset}`);
|
|
936
949
|
log('');
|
|
@@ -998,16 +1011,27 @@ function cmdDoctor() {
|
|
|
998
1011
|
warn('schemas/ directory missing'); issues++;
|
|
999
1012
|
}
|
|
1000
1013
|
|
|
1001
|
-
// 4.5. Check RTK Integration
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1014
|
+
// 4.5. Check RTK & GitNexus Integration
|
|
1015
|
+
if (depManager.checkRtk()) {
|
|
1016
|
+
ok(`RTK (Rust Token Killer) is installed (v${depManager.getRtkVersion() || 'unknown'})`);
|
|
1017
|
+
} else {
|
|
1018
|
+
warn('RTK (Rust Token Killer) not found.');
|
|
1019
|
+
if (promptYN('Would you like to install RTK automatically now?')) {
|
|
1020
|
+
depManager.installRtk();
|
|
1006
1021
|
} else {
|
|
1007
|
-
|
|
1022
|
+
issues++;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
if (depManager.checkGitnexus()) {
|
|
1027
|
+
ok('GitNexus (Code Intelligence Indexer) is installed and active');
|
|
1028
|
+
} else {
|
|
1029
|
+
warn('GitNexus (Code Intelligence Indexer) not found.');
|
|
1030
|
+
if (promptYN('Would you like to install GitNexus globally now?')) {
|
|
1031
|
+
depManager.installGitnexus();
|
|
1032
|
+
} else {
|
|
1033
|
+
issues++;
|
|
1008
1034
|
}
|
|
1009
|
-
} catch (e) {
|
|
1010
|
-
warn(`RTK check failed: ${e.message}`);
|
|
1011
1035
|
}
|
|
1012
1036
|
|
|
1013
1037
|
// 5. Check version
|
|
@@ -1021,6 +1045,25 @@ function cmdDoctor() {
|
|
|
1021
1045
|
warn('Version file missing. Run "awkit install" first.'); issues++;
|
|
1022
1046
|
}
|
|
1023
1047
|
|
|
1048
|
+
// 5.5. Check Updates
|
|
1049
|
+
try {
|
|
1050
|
+
const updates = await depManager.checkUpdates(AWK_VERSION);
|
|
1051
|
+
if (updates.latestAwkit && isNewerVersion(updates.latestAwkit, AWK_VERSION)) {
|
|
1052
|
+
warn(`AWKit update available: v${updates.latestAwkit} (current: v${AWK_VERSION})`);
|
|
1053
|
+
} else {
|
|
1054
|
+
ok('AWKit is up-to-date');
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const currentRtk = depManager.getRtkVersion();
|
|
1058
|
+
if (updates.latestRtk && currentRtk && isNewerVersion(updates.latestRtk, currentRtk)) {
|
|
1059
|
+
warn(`RTK update available: v${updates.latestRtk} (current: v${currentRtk})`);
|
|
1060
|
+
} else if (currentRtk) {
|
|
1061
|
+
ok('RTK is up-to-date');
|
|
1062
|
+
}
|
|
1063
|
+
} catch (e) {
|
|
1064
|
+
warn(`Update check failed: ${e.message}`);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1024
1067
|
log('');
|
|
1025
1068
|
log(`${C.bold}Runtime Profile:${C.reset}`);
|
|
1026
1069
|
log(` Profile: ${C.cyan}${installState.profile}${C.reset}`);
|
|
@@ -1710,15 +1753,19 @@ function cmdListPacks() {
|
|
|
1710
1753
|
}
|
|
1711
1754
|
|
|
1712
1755
|
for (const pack of packs) {
|
|
1713
|
-
const readmePath = path.join(packsDir, pack.name, 'README.md');
|
|
1714
1756
|
const configPath = path.join(packsDir, pack.name, 'pack.json');
|
|
1757
|
+
const config = fs.existsSync(configPath) ? readJsonFile(configPath, {}) : {};
|
|
1758
|
+
if (config.hidden === true) {
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
const readmePath = path.join(packsDir, pack.name, 'README.md');
|
|
1715
1763
|
let desc = '';
|
|
1716
1764
|
if (fs.existsSync(readmePath)) {
|
|
1717
1765
|
const content = fs.readFileSync(readmePath, 'utf8');
|
|
1718
1766
|
desc = content.split('\n').find(l => l.trim() && !l.startsWith('#')) || '';
|
|
1719
1767
|
}
|
|
1720
|
-
if (!desc
|
|
1721
|
-
const config = readJsonFile(configPath, {});
|
|
1768
|
+
if (!desc) {
|
|
1722
1769
|
desc = config.description || '';
|
|
1723
1770
|
}
|
|
1724
1771
|
log(` ${C.green}${pack.name}${C.reset} ${C.gray}${desc}${C.reset}`);
|
|
@@ -1898,6 +1945,22 @@ function cmdStatus() {
|
|
|
1898
1945
|
}
|
|
1899
1946
|
|
|
1900
1947
|
log('');
|
|
1948
|
+
|
|
1949
|
+
// ── GitNexus Info ──────────────────────────────────────────────────────
|
|
1950
|
+
const cwd = process.cwd();
|
|
1951
|
+
const gitnexusDir = path.join(cwd, '.gitnexus');
|
|
1952
|
+
if (fs.existsSync(gitnexusDir)) {
|
|
1953
|
+
const registry = readGitnexusRegistry();
|
|
1954
|
+
const match = registry.find(r => r.path === cwd);
|
|
1955
|
+
if (match) {
|
|
1956
|
+
const stats = match.stats || {};
|
|
1957
|
+
log(`${C.bold}GitNexus Info:${C.reset}`);
|
|
1958
|
+
log(` Active repo: ${C.green}${match.name}${C.reset} (${stats.nodes || 0} nodes, ${stats.edges || 0} relations)`);
|
|
1959
|
+
log(` Tip: Run 'awkit index' to refresh index or 'awkit status gn' for details.`);
|
|
1960
|
+
log('');
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1901
1964
|
log(`${C.gray}Tip: 'awkit sync' = harvest (pull live→repo) + install (push repo→live)${C.reset}`);
|
|
1902
1965
|
log('');
|
|
1903
1966
|
}
|
|
@@ -1938,6 +2001,104 @@ function cmdSync() {
|
|
|
1938
2001
|
log('');
|
|
1939
2002
|
}
|
|
1940
2003
|
|
|
2004
|
+
// ─── Build: Safe project-specific compilation ────────────────────────────────
|
|
2005
|
+
|
|
2006
|
+
function cmdBuild() {
|
|
2007
|
+
log('');
|
|
2008
|
+
log(`${C.cyan}${C.bold}🔨 AWK Build Control${C.reset}`);
|
|
2009
|
+
log('');
|
|
2010
|
+
|
|
2011
|
+
const pjPath = path.join(process.cwd(), '.project-identity');
|
|
2012
|
+
const pj = readJsonFile(pjPath, {});
|
|
2013
|
+
|
|
2014
|
+
if (!pj.automation || !pj.automation.build) {
|
|
2015
|
+
warn('No build configuration found in .project-identity under "automation.build".');
|
|
2016
|
+
log('Skipping build...');
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
const { enabled, command } = pj.automation.build;
|
|
2021
|
+
|
|
2022
|
+
if (!enabled) {
|
|
2023
|
+
warn('Build is disabled for this project (automation.build.enabled is false).');
|
|
2024
|
+
log('Skipping build...');
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
if (!command) {
|
|
2029
|
+
err('Build command is not configured in .project-identity (automation.build.command is empty).');
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
info(`Running build command: ${C.bold}${command}${C.reset}`);
|
|
2034
|
+
try {
|
|
2035
|
+
execSync(command, { stdio: 'inherit' });
|
|
2036
|
+
log('');
|
|
2037
|
+
ok('Build successful!');
|
|
2038
|
+
} catch (e) {
|
|
2039
|
+
log('');
|
|
2040
|
+
err(`Build failed: ${e.message}`);
|
|
2041
|
+
process.exit(1);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// ─── Run: Safe project-specific run/start script execution ──────────────────
|
|
2046
|
+
|
|
2047
|
+
function cmdRun(runArgs = []) {
|
|
2048
|
+
log('');
|
|
2049
|
+
log(`${C.cyan}${C.bold}🚀 AWK Run Control${C.reset}`);
|
|
2050
|
+
log('');
|
|
2051
|
+
|
|
2052
|
+
const pjPath = path.join(process.cwd(), '.project-identity');
|
|
2053
|
+
const pj = readJsonFile(pjPath, {});
|
|
2054
|
+
|
|
2055
|
+
if (!pj.automation || !pj.automation.run) {
|
|
2056
|
+
warn('No run configuration found in .project-identity under "automation.run".');
|
|
2057
|
+
log('Skipping run...');
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
const { enabled, command } = pj.automation.run;
|
|
2062
|
+
|
|
2063
|
+
if (!enabled) {
|
|
2064
|
+
warn('Run is disabled for this project (automation.run.enabled is false).');
|
|
2065
|
+
log('Skipping run...');
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (!command) {
|
|
2070
|
+
err('Run command is not configured in .project-identity (automation.run.command is empty).');
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
const fullCommand = runArgs.length > 0 ? `${command} ${runArgs.join(' ')}` : command;
|
|
2075
|
+
|
|
2076
|
+
info(`Running command: ${C.bold}${fullCommand}${C.reset}`);
|
|
2077
|
+
try {
|
|
2078
|
+
execSync(fullCommand, { stdio: 'inherit' });
|
|
2079
|
+
} catch (e) {
|
|
2080
|
+
log('');
|
|
2081
|
+
err(`Run failed: ${e.message}`);
|
|
2082
|
+
process.exit(e.status || 1);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
function cmdTask(taskArgs = []) {
|
|
2087
|
+
try {
|
|
2088
|
+
execSync(`symphony task ${taskArgs.join(' ')}`, { stdio: 'inherit' });
|
|
2089
|
+
} catch (e) {
|
|
2090
|
+
process.exit(e.status || 1);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
function cmdProject(projectArgs = []) {
|
|
2095
|
+
try {
|
|
2096
|
+
execSync(`symphony project ${projectArgs.join(' ')}`, { stdio: 'inherit' });
|
|
2097
|
+
} catch (e) {
|
|
2098
|
+
process.exit(e.status || 1);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
1941
2102
|
async function cmdAdmin() {
|
|
1942
2103
|
info('Mở Symphony Dashboard...');
|
|
1943
2104
|
try {
|
|
@@ -2027,6 +2188,59 @@ async function cmdRestart() {
|
|
|
2027
2188
|
}
|
|
2028
2189
|
}
|
|
2029
2190
|
|
|
2191
|
+
function cmdGreet(args) {
|
|
2192
|
+
let name = 'Guest';
|
|
2193
|
+
let lang = 'en';
|
|
2194
|
+
let timezone = undefined;
|
|
2195
|
+
|
|
2196
|
+
for (let i = 0; i < args.length; i++) {
|
|
2197
|
+
const arg = args[i];
|
|
2198
|
+
if (arg === '--help' || arg === '-h') {
|
|
2199
|
+
log('');
|
|
2200
|
+
log(`${C.cyan}${C.bold}👋 awkit greet — Personalized greetings${C.reset}`);
|
|
2201
|
+
log('');
|
|
2202
|
+
log('Usage:');
|
|
2203
|
+
log(' awkit greet [options]');
|
|
2204
|
+
log('');
|
|
2205
|
+
log('Options:');
|
|
2206
|
+
log(' -n, --name <name> Name of the person to greet (default: "Guest")');
|
|
2207
|
+
log(' -l, --lang <lang> Language code (en, vi, ja) (default: "en")');
|
|
2208
|
+
log(' -t, --timezone <tz> Timezone string (default: system timezone)');
|
|
2209
|
+
log(' -h, --help Show this help message');
|
|
2210
|
+
log('');
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
if ((arg === '--name' || arg === '-n') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2214
|
+
name = args[i + 1];
|
|
2215
|
+
i++;
|
|
2216
|
+
} else if (arg.startsWith('--name=')) {
|
|
2217
|
+
name = arg.split('=')[1];
|
|
2218
|
+
} else if ((arg === '--lang' || arg === '-l') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2219
|
+
lang = args[i + 1];
|
|
2220
|
+
i++;
|
|
2221
|
+
} else if (arg.startsWith('--lang=')) {
|
|
2222
|
+
lang = arg.split('=')[1];
|
|
2223
|
+
} else if ((arg === '--timezone' || arg === '-t') && args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
2224
|
+
timezone = args[i + 1];
|
|
2225
|
+
i++;
|
|
2226
|
+
} else if (arg.startsWith('--timezone=')) {
|
|
2227
|
+
timezone = arg.split('=')[1];
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
try {
|
|
2232
|
+
const GreetingEngine = require('../core/GreetingEngine');
|
|
2233
|
+
const result = GreetingEngine.generateGreeting({ name, lang, timezone });
|
|
2234
|
+
if (result.status === 'success') {
|
|
2235
|
+
log(result.data.message);
|
|
2236
|
+
} else {
|
|
2237
|
+
err('Failed to generate greeting');
|
|
2238
|
+
}
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
err('Failed to execute Greeting Engine: ' + e.message);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2030
2244
|
function cmdHelp() {
|
|
2031
2245
|
const line = `${C.gray}${'─'.repeat(56)}${C.reset}`;
|
|
2032
2246
|
log('');
|
|
@@ -2035,6 +2249,33 @@ function cmdHelp() {
|
|
|
2035
2249
|
log(`${C.cyan}${C.bold}╚═══════════════════════════════════════════════════════╝${C.reset}`);
|
|
2036
2250
|
log('');
|
|
2037
2251
|
|
|
2252
|
+
// Project Context Detector
|
|
2253
|
+
const cwd = process.cwd();
|
|
2254
|
+
const identityPath = path.join(cwd, '.project-identity');
|
|
2255
|
+
if (fs.existsSync(identityPath)) {
|
|
2256
|
+
try {
|
|
2257
|
+
const raw = fs.readFileSync(identityPath, 'utf8');
|
|
2258
|
+
const identity = JSON.parse(raw);
|
|
2259
|
+
const icon = identity.icon || '⚡';
|
|
2260
|
+
const name = identity.projectName || 'Unnamed Project';
|
|
2261
|
+
const pType = identity.projectType ? `Type: ${identity.projectType}` : 'Type: Generic';
|
|
2262
|
+
|
|
2263
|
+
let bCmd = 'Disabled';
|
|
2264
|
+
if (identity.automation && identity.automation.build && identity.automation.build.enabled) {
|
|
2265
|
+
bCmd = identity.automation.build.command || 'Enabled';
|
|
2266
|
+
}
|
|
2267
|
+
let rCmd = 'Disabled';
|
|
2268
|
+
if (identity.automation && identity.automation.run && identity.automation.run.enabled) {
|
|
2269
|
+
rCmd = identity.automation.run.command || 'Enabled';
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
log(`${C.cyan}👉 Active Project: ${icon} ${C.bold}${name}${C.reset}`);
|
|
2273
|
+
log(` [${pType} | Build Control: ${bCmd === 'Disabled' ? C.yellow + 'Manual' : C.green + bCmd} | Run Control: ${rCmd === 'Disabled' ? C.yellow + 'Manual' : C.green + rCmd}${C.reset}]`);
|
|
2274
|
+
log(` Run ${C.green}awkit identity${C.reset} for full configuration details.`);
|
|
2275
|
+
log('');
|
|
2276
|
+
} catch (_) {}
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2038
2279
|
// Install
|
|
2039
2280
|
log(`${C.bold}⚙️ Setup${C.reset}`);
|
|
2040
2281
|
log(line);
|
|
@@ -2047,6 +2288,10 @@ function cmdHelp() {
|
|
|
2047
2288
|
log(` ${C.green}credentials list${C.reset} List stored API keys`);
|
|
2048
2289
|
log(` ${C.green}credentials set${C.reset} <k> <v> Set API key (e.g., gemini_api_key, openrouter_api_key)`);
|
|
2049
2290
|
log(` ${C.green}set-openrouter${C.reset} <key> Shorthand for setting OpenRouter API Key`);
|
|
2291
|
+
log(` ${C.green}config-global list${C.reset} List all global configurations`);
|
|
2292
|
+
log(` ${C.green}config-global set${C.reset} <k> <v> Set global configuration`);
|
|
2293
|
+
log(` ${C.green}config-global audio${C.reset} <on|off> Turn audio alerts on/off globally`);
|
|
2294
|
+
log(` ${C.green}config audio${C.reset} <on|off> Shorthand to turn audio alerts on/off globally`);
|
|
2050
2295
|
log('');
|
|
2051
2296
|
|
|
2052
2297
|
// Project Init
|
|
@@ -2056,6 +2301,9 @@ function cmdHelp() {
|
|
|
2056
2301
|
log(` ${C.gray} --force${C.reset} Overwrite existing files`);
|
|
2057
2302
|
log(` ${C.gray} Generates: .project-identity, <Name>.code-workspace,${C.reset}`);
|
|
2058
2303
|
log(` ${C.gray} CODEBASE.md, thiết lập router (AGENTS.md, CLAUDE.md)${C.reset}`);
|
|
2304
|
+
log(` ${C.green}identity${C.reset} Show project identity & active configurations (alias: config)`);
|
|
2305
|
+
log(` ${C.green}build${C.reset} Run project build based on .project-identity config`);
|
|
2306
|
+
log(` ${C.green}run${C.reset} [args] Run project-specific start/dev commands based on config`);
|
|
2059
2307
|
log('');
|
|
2060
2308
|
|
|
2061
2309
|
// Maintenance
|
|
@@ -2082,10 +2330,21 @@ function cmdHelp() {
|
|
|
2082
2330
|
log(` ${C.green}sync${C.reset} Full sync: harvest + install (one shot)`);
|
|
2083
2331
|
log('');
|
|
2084
2332
|
|
|
2333
|
+
// GreetingApp
|
|
2334
|
+
log(`${C.bold}👋 GreetingApp${C.reset}`);
|
|
2335
|
+
log(line);
|
|
2336
|
+
log(` ${C.green}greet${C.reset} [options] Generate personalized dynamic greeting`);
|
|
2337
|
+
log(` ${C.gray} -n, --name <name>${C.reset} User name to greet (default: Guest)`);
|
|
2338
|
+
log(` ${C.gray} -l, --lang <lang>${C.reset} Language code: en, vi, ja (default: en)`);
|
|
2339
|
+
log(` ${C.gray} -t, --timezone <tz>${C.reset} Timezone parameter`);
|
|
2340
|
+
log('');
|
|
2341
|
+
|
|
2085
2342
|
// Symphony
|
|
2086
2343
|
log(`${C.bold}🎶 Symphony${C.reset}`);
|
|
2087
2344
|
log(line);
|
|
2088
2345
|
log(` ${C.green}admin${C.reset} Khởi động Symphony Dashboard`);
|
|
2346
|
+
log(` ${C.green}task${C.reset} [args] Manage Symphony tasks directly`);
|
|
2347
|
+
log(` ${C.green}project${C.reset} [args] Manage Symphony projects directly`);
|
|
2089
2348
|
log('');
|
|
2090
2349
|
|
|
2091
2350
|
// Packs
|
|
@@ -2098,6 +2357,36 @@ function cmdHelp() {
|
|
|
2098
2357
|
log(` ${C.green}disable-pack${C.reset} <name> Uninstall a skill pack (backed up)`);
|
|
2099
2358
|
log('');
|
|
2100
2359
|
|
|
2360
|
+
// Storage
|
|
2361
|
+
log(`${C.bold}🗄️ Storage${C.reset}`);
|
|
2362
|
+
log(line);
|
|
2363
|
+
log(` ${C.green}storage set${C.reset} <key> <val> Save key-value pair`);
|
|
2364
|
+
log(` ${C.green}storage get${C.reset} <key> Retrieve value by key`);
|
|
2365
|
+
log(` ${C.green}storage delete${C.reset} <key> Delete key`);
|
|
2366
|
+
log(` ${C.green}storage list${C.reset} [prefix] List keys with optional prefix`);
|
|
2367
|
+
log(` ${C.gray} --shared Access shared storage space${C.reset}`);
|
|
2368
|
+
log('');
|
|
2369
|
+
|
|
2370
|
+
// Pipeline
|
|
2371
|
+
log(`${C.bold}🔗 Pipeline & Sub-Agents${C.reset}`);
|
|
2372
|
+
log(line);
|
|
2373
|
+
log(` ${C.green}pipeline plan${C.reset} <Feature> Lập kế hoạch kiến trúc (Claude / Gemini fallback)`);
|
|
2374
|
+
log(` ${C.green}pipeline ui${C.reset} <Feature> Thiết kế shell & GUI assets (Codex / Gemini fallback)`);
|
|
2375
|
+
log(` ${C.green}pipeline code${C.reset} <Feature> Thực thi viết code & review (Qwen / Gemini fallback)`);
|
|
2376
|
+
log('');
|
|
2377
|
+
log(` ${C.bold}🤖 Multi-Agent Collaborative System${C.reset}`);
|
|
2378
|
+
log(` AWKit integrates third-party CLI agents to optimize reasoning quality & costs:`);
|
|
2379
|
+
log(` • ${C.cyan}Claude Code${C.reset} ➜ Architect planning & complex reasoning (Gate 2/4)`);
|
|
2380
|
+
log(` • ${C.cyan}Codex CLI${C.reset} ➜ UI shell design, asset generation & reviews (Gate 2.5/5)`);
|
|
2381
|
+
log(` • ${C.cyan}Qwen Coder${C.reset} ➜ Fast local boilerplate code execution (Gate 4)`);
|
|
2382
|
+
log(` • ${C.cyan}Gemini Flash${C.reset} ➜ Central coordination, active context & fallback router`);
|
|
2383
|
+
log('');
|
|
2384
|
+
log(` To query or configure active runners and alerts:`);
|
|
2385
|
+
log(` - Run ${C.green}awkit config list${C.reset} to show current settings`);
|
|
2386
|
+
log(` - Run ${C.green}awkit config runners${C.reset} to check paths & binary availability`);
|
|
2387
|
+
log(` - Run ${C.green}awkit config <runner> <on|off>${C.reset} to toggle specific runner`);
|
|
2388
|
+
log('');
|
|
2389
|
+
|
|
2101
2390
|
// Trello
|
|
2102
2391
|
log(`${C.bold}📋 Trello${C.reset}`);
|
|
2103
2392
|
log(line);
|
|
@@ -2121,15 +2410,16 @@ function cmdHelp() {
|
|
|
2121
2410
|
log('');
|
|
2122
2411
|
|
|
2123
2412
|
// GitNexus
|
|
2124
|
-
log(`${C.bold}🔍 GitNexus${C.reset}`);
|
|
2413
|
+
log(`${C.bold}🔍 GitNexus (Shortcuts: index, clean, list)${C.reset}`);
|
|
2125
2414
|
log(line);
|
|
2126
|
-
log(` ${C.green}
|
|
2127
|
-
log(` ${C.green}
|
|
2128
|
-
log(` ${C.green}
|
|
2129
|
-
log(` ${C.green}
|
|
2415
|
+
log(` ${C.green}index${C.reset} Index/refresh current codebase (alias: analyze)`);
|
|
2416
|
+
log(` ${C.green}list${C.reset} List all indexed repositories`);
|
|
2417
|
+
log(` ${C.green}status gn${C.reset} Show current project index info (or 'gn status')`);
|
|
2418
|
+
log(` ${C.green}clean${C.reset} Interactive cleanup of old indexes`);
|
|
2419
|
+
log(` ${C.green}clean${C.reset} ${C.gray}<name...>${C.reset} Remove specific repo(s) by name`);
|
|
2130
2420
|
log(` ${C.gray} --stale${C.reset} Auto-remove repos with missing paths`);
|
|
2131
2421
|
log(` ${C.gray} --all${C.reset} Remove all except current project`);
|
|
2132
|
-
log(` ${C.gray} Alias: gn${C.reset}`);
|
|
2422
|
+
log(` ${C.gray} Alias: gn / gitnexus${C.reset}`);
|
|
2133
2423
|
log('');
|
|
2134
2424
|
|
|
2135
2425
|
// Available packs
|
|
@@ -2139,6 +2429,11 @@ function cmdHelp() {
|
|
|
2139
2429
|
if (packs.length) {
|
|
2140
2430
|
log(` Available packs:`);
|
|
2141
2431
|
for (const p of packs) {
|
|
2432
|
+
const configPath = path.join(packsDir, p.name, 'pack.json');
|
|
2433
|
+
const config = fs.existsSync(configPath) ? readJsonFile(configPath, {}) : {};
|
|
2434
|
+
if (config.hidden === true) {
|
|
2435
|
+
continue;
|
|
2436
|
+
}
|
|
2142
2437
|
const readmePath = path.join(packsDir, p.name, 'README.md');
|
|
2143
2438
|
let tagline = '';
|
|
2144
2439
|
if (fs.existsSync(readmePath)) {
|
|
@@ -2212,10 +2507,55 @@ function detectProjectType(cwd) {
|
|
|
2212
2507
|
if (entries.includes('pubspec.yaml')) {
|
|
2213
2508
|
return 'flutter';
|
|
2214
2509
|
}
|
|
2510
|
+
|
|
2511
|
+
// JS/Node project check
|
|
2512
|
+
if (entries.includes('package.json')) {
|
|
2513
|
+
try {
|
|
2514
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
2515
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2516
|
+
if (pkg.bin) {
|
|
2517
|
+
return 'cli';
|
|
2518
|
+
}
|
|
2519
|
+
if (deps['next']) {
|
|
2520
|
+
return 'web-nextjs';
|
|
2521
|
+
}
|
|
2522
|
+
if (deps['@nestjs/core']) {
|
|
2523
|
+
return 'backend-nestjs';
|
|
2524
|
+
}
|
|
2525
|
+
return 'node';
|
|
2526
|
+
} catch (_) { /* continue */ }
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2215
2529
|
// Default: generic mobile-firebase
|
|
2216
2530
|
return 'mobile-firebase';
|
|
2217
2531
|
}
|
|
2218
2532
|
|
|
2533
|
+
/**
|
|
2534
|
+
* Get the default safe build command based on projectType.
|
|
2535
|
+
*/
|
|
2536
|
+
function getDefaultBuildCommand(projectType) {
|
|
2537
|
+
switch (projectType) {
|
|
2538
|
+
case 'ios':
|
|
2539
|
+
return 'xcodebuild -scheme YourScheme -sdk iphonesimulator -configuration Debug';
|
|
2540
|
+
case 'android':
|
|
2541
|
+
return './gradlew assembleDebug';
|
|
2542
|
+
case 'expo':
|
|
2543
|
+
return 'npx expo prebuild';
|
|
2544
|
+
case 'flutter':
|
|
2545
|
+
return 'flutter build apk --debug';
|
|
2546
|
+
case 'web-nextjs':
|
|
2547
|
+
return 'npm run build';
|
|
2548
|
+
case 'backend-nestjs':
|
|
2549
|
+
return 'npm run build';
|
|
2550
|
+
case 'cli':
|
|
2551
|
+
case 'node':
|
|
2552
|
+
return 'npm test';
|
|
2553
|
+
case 'mobile-firebase':
|
|
2554
|
+
default:
|
|
2555
|
+
return 'npm run build';
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2219
2559
|
/**
|
|
2220
2560
|
* Build .project-identity object from detected type + project name.
|
|
2221
2561
|
*/
|
|
@@ -2326,6 +2666,70 @@ function buildProjectIdentity(projectName, projectType, cwd, date) {
|
|
|
2326
2666
|
servicesDir: 'lib/shared/services',
|
|
2327
2667
|
modelsDir: 'lib/shared/models',
|
|
2328
2668
|
},
|
|
2669
|
+
cli: {
|
|
2670
|
+
projectType: 'cli',
|
|
2671
|
+
techStack: {
|
|
2672
|
+
platform: 'CLI',
|
|
2673
|
+
language: 'JavaScript / TypeScript',
|
|
2674
|
+
runtime: 'Node.js',
|
|
2675
|
+
framework: 'Vanilla NodeJS',
|
|
2676
|
+
testing: 'Jest / doctor',
|
|
2677
|
+
},
|
|
2678
|
+
codingStandards: { language: 'en', namingConvention: 'camelCase', indentation: 'spaces-4', lineLength: 120 },
|
|
2679
|
+
architecture: 'Modular',
|
|
2680
|
+
featuresDir: 'src/commands',
|
|
2681
|
+
sharedUIDir: 'src/ui',
|
|
2682
|
+
servicesDir: 'src/services',
|
|
2683
|
+
modelsDir: 'src/models',
|
|
2684
|
+
},
|
|
2685
|
+
node: {
|
|
2686
|
+
projectType: 'node',
|
|
2687
|
+
techStack: {
|
|
2688
|
+
platform: 'NodeJS Backend/App',
|
|
2689
|
+
language: 'JavaScript / TypeScript',
|
|
2690
|
+
runtime: 'Node.js',
|
|
2691
|
+
testing: 'Jest',
|
|
2692
|
+
},
|
|
2693
|
+
codingStandards: { language: 'en', namingConvention: 'camelCase', indentation: 'spaces-4', lineLength: 120 },
|
|
2694
|
+
architecture: 'Modular',
|
|
2695
|
+
featuresDir: 'src/features',
|
|
2696
|
+
sharedUIDir: 'src/views',
|
|
2697
|
+
servicesDir: 'src/services',
|
|
2698
|
+
modelsDir: 'src/models',
|
|
2699
|
+
},
|
|
2700
|
+
'web-nextjs': {
|
|
2701
|
+
projectType: 'web-nextjs',
|
|
2702
|
+
techStack: {
|
|
2703
|
+
platform: 'Web',
|
|
2704
|
+
language: 'TypeScript / JavaScript',
|
|
2705
|
+
framework: 'Next.js',
|
|
2706
|
+
styling: 'Tailwind CSS / CSS Modules',
|
|
2707
|
+
stateManagement: 'Zustand / Redux Toolkit / React Context',
|
|
2708
|
+
networking: 'Axios / Fetch',
|
|
2709
|
+
},
|
|
2710
|
+
codingStandards: { language: 'en', namingConvention: 'camelCase', indentation: 'spaces-2', lineLength: 100 },
|
|
2711
|
+
architecture: 'App Router / Pages Router',
|
|
2712
|
+
featuresDir: 'src/app',
|
|
2713
|
+
sharedUIDir: 'src/components',
|
|
2714
|
+
servicesDir: 'src/services',
|
|
2715
|
+
modelsDir: 'src/models',
|
|
2716
|
+
},
|
|
2717
|
+
'backend-nestjs': {
|
|
2718
|
+
projectType: 'backend-nestjs',
|
|
2719
|
+
techStack: {
|
|
2720
|
+
platform: 'Backend',
|
|
2721
|
+
language: 'TypeScript',
|
|
2722
|
+
framework: 'NestJS',
|
|
2723
|
+
database: 'PostgreSQL / MySQL / MongoDB',
|
|
2724
|
+
orm: 'Prisma / TypeORM / Mongoose',
|
|
2725
|
+
},
|
|
2726
|
+
codingStandards: { language: 'en', namingConvention: 'camelCase', indentation: 'spaces-2', lineLength: 100 },
|
|
2727
|
+
architecture: 'Controller-Service-Repository',
|
|
2728
|
+
featuresDir: 'src/modules',
|
|
2729
|
+
sharedUIDir: 'src/common',
|
|
2730
|
+
servicesDir: 'src/services',
|
|
2731
|
+
modelsDir: 'src/models',
|
|
2732
|
+
},
|
|
2329
2733
|
};
|
|
2330
2734
|
|
|
2331
2735
|
// Fallback: generic mobile-firebase
|
|
@@ -2394,6 +2798,10 @@ function buildProjectIdentity(projectName, projectType, cwd, date) {
|
|
|
2394
2798
|
"pixel-mcp": {
|
|
2395
2799
|
enabled: false
|
|
2396
2800
|
}
|
|
2801
|
+
},
|
|
2802
|
+
build: {
|
|
2803
|
+
enabled: false,
|
|
2804
|
+
command: getDefaultBuildCommand(projectType)
|
|
2397
2805
|
}
|
|
2398
2806
|
},
|
|
2399
2807
|
modelPolicy: {
|
|
@@ -2637,6 +3045,10 @@ async function cmdInit(forceFlag = false) {
|
|
|
2637
3045
|
"pixel-mcp": {
|
|
2638
3046
|
enabled: false
|
|
2639
3047
|
}
|
|
3048
|
+
},
|
|
3049
|
+
build: {
|
|
3050
|
+
enabled: false,
|
|
3051
|
+
command: getDefaultBuildCommand(projectType)
|
|
2640
3052
|
}
|
|
2641
3053
|
};
|
|
2642
3054
|
fs.writeFileSync(identityPath, JSON.stringify(currentIdentity, null, 2) + '\n');
|
|
@@ -2657,6 +3069,18 @@ async function cmdInit(forceFlag = false) {
|
|
|
2657
3069
|
currentIdentity.automation.mcp = { "pixel-mcp": { enabled: false } };
|
|
2658
3070
|
changed = true;
|
|
2659
3071
|
}
|
|
3072
|
+
if (!currentIdentity.projectType) {
|
|
3073
|
+
currentIdentity.projectType = projectType;
|
|
3074
|
+
changed = true;
|
|
3075
|
+
}
|
|
3076
|
+
if (!currentIdentity.automation.build) {
|
|
3077
|
+
const detectedType = currentIdentity.projectType || projectType || 'mobile-firebase';
|
|
3078
|
+
currentIdentity.automation.build = {
|
|
3079
|
+
enabled: false,
|
|
3080
|
+
command: getDefaultBuildCommand(detectedType)
|
|
3081
|
+
};
|
|
3082
|
+
changed = true;
|
|
3083
|
+
}
|
|
2660
3084
|
if (!currentIdentity.modelPolicy) {
|
|
2661
3085
|
currentIdentity.modelPolicy = {
|
|
2662
3086
|
mode: "auto",
|
|
@@ -2841,17 +3265,20 @@ Additional project context can be found in:
|
|
|
2841
3265
|
).trim();
|
|
2842
3266
|
|
|
2843
3267
|
if (hasSource) {
|
|
2844
|
-
|
|
3268
|
+
const usePnpm = fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'));
|
|
3269
|
+
const indexCmd = usePnpm ? 'pnpm dlx gitnexus analyze' : 'npx -y gitnexus analyze';
|
|
3270
|
+
info(`Running index with: ${indexCmd}...`);
|
|
3271
|
+
execSync(indexCmd, {
|
|
2845
3272
|
cwd,
|
|
2846
3273
|
stdio: 'ignore',
|
|
2847
3274
|
});
|
|
2848
3275
|
ok('GitNexus index created (.gitnexus/)');
|
|
2849
3276
|
} else {
|
|
2850
|
-
dim('No source files found — skipping GitNexus index (run later: npx gitnexus analyze)');
|
|
3277
|
+
dim('No source files found — skipping GitNexus index (run later: pnpm dlx gitnexus analyze or npx gitnexus analyze)');
|
|
2851
3278
|
}
|
|
2852
3279
|
} catch (e) {
|
|
2853
3280
|
warn(`GitNexus indexing failed: ${e.message}`);
|
|
2854
|
-
dim('Run manually later: npx gitnexus analyze');
|
|
3281
|
+
dim('Run manually later: pnpm dlx gitnexus analyze or npx gitnexus analyze');
|
|
2855
3282
|
}
|
|
2856
3283
|
|
|
2857
3284
|
// ── 6. Summary ─────────────────────────────────────────────────────────────
|
|
@@ -2866,9 +3293,10 @@ Additional project context can be found in:
|
|
|
2866
3293
|
dim(`GitNexus: code intelligence index`);
|
|
2867
3294
|
log('');
|
|
2868
3295
|
log(`${C.cyan}👉 Open ${workspaceName} in VS Code to get started.${C.reset}`);
|
|
3296
|
+
log(`${C.cyan}👉 Run '/init' in AI chat to activate Smart Ecosystem Setup (SAEE) & recommendations.${C.reset}`);
|
|
2869
3297
|
log(`${C.cyan}👉 Run '/codebase-sync' in AI chat to keep CODEBASE.md updated.${C.reset}`);
|
|
2870
3298
|
log(`${C.cyan}👉 Run 'symphony task list' to manage tasks.${C.reset}`);
|
|
2871
|
-
log(`${C.cyan}👉 Run 'npx gitnexus analyze' after major changes to refresh index.${C.reset}`);
|
|
3299
|
+
log(`${C.cyan}👉 Run 'pnpm dlx gitnexus analyze' (or 'npx gitnexus analyze') after major changes to refresh index.${C.reset}`);
|
|
2872
3300
|
log('');
|
|
2873
3301
|
|
|
2874
3302
|
// ── 7. Open Documentation ───────────────────────────────────────────────────
|
|
@@ -3520,41 +3948,90 @@ function cmdTrello(args) {
|
|
|
3520
3948
|
}
|
|
3521
3949
|
}
|
|
3522
3950
|
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
const
|
|
3951
|
+
/**
|
|
3952
|
+
* Helper to check if semantic version `latest` is newer than `current`.
|
|
3953
|
+
*/
|
|
3954
|
+
function isNewerVersion(latest, current) {
|
|
3955
|
+
if (!latest || !current) return false;
|
|
3956
|
+
const clean = v => v.replace(/^v/, '');
|
|
3957
|
+
const lClean = clean(latest);
|
|
3958
|
+
const cClean = clean(current);
|
|
3959
|
+
if (lClean === cClean) return false;
|
|
3960
|
+
|
|
3961
|
+
const parse = v => {
|
|
3962
|
+
const parts = v.split('-');
|
|
3963
|
+
const numbers = parts[0].split('.').map(Number);
|
|
3964
|
+
const prerelease = parts[1] ? parts[1].split('.') : [];
|
|
3965
|
+
return { numbers, prerelease };
|
|
3966
|
+
};
|
|
3529
3967
|
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3968
|
+
const l = parse(lClean);
|
|
3969
|
+
const c = parse(cClean);
|
|
3970
|
+
|
|
3971
|
+
// Compare main version numbers
|
|
3972
|
+
for (let i = 0; i < 3; i++) {
|
|
3973
|
+
const ln = l.numbers[i] || 0;
|
|
3974
|
+
const cn = c.numbers[i] || 0;
|
|
3975
|
+
if (ln > cn) return true;
|
|
3976
|
+
if (ln < cn) return false;
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
const lIsPrerelease = l.prerelease.length > 0;
|
|
3980
|
+
const cIsPrerelease = c.prerelease.length > 0;
|
|
3981
|
+
|
|
3982
|
+
if (lIsPrerelease && !cIsPrerelease) return false;
|
|
3983
|
+
if (!lIsPrerelease && cIsPrerelease) return true;
|
|
3984
|
+
|
|
3985
|
+
const maxLength = Math.max(l.prerelease.length, c.prerelease.length);
|
|
3986
|
+
for (let i = 0; i < maxLength; i++) {
|
|
3987
|
+
const lp = l.prerelease[i];
|
|
3988
|
+
const cp = c.prerelease[i];
|
|
3989
|
+
if (lp === undefined) return false;
|
|
3990
|
+
if (cp === undefined) return true;
|
|
3991
|
+
const lpNum = parseInt(lp, 10);
|
|
3992
|
+
const cpNum = parseInt(cp, 10);
|
|
3993
|
+
const lpIsNum = !isNaN(lpNum);
|
|
3994
|
+
const cpIsNum = !isNaN(cpNum);
|
|
3995
|
+
if (lpIsNum && cpIsNum) {
|
|
3996
|
+
if (lpNum > cpNum) return true;
|
|
3997
|
+
if (lpNum < cpNum) return false;
|
|
3998
|
+
} else if (lpIsNum) {
|
|
3999
|
+
return false;
|
|
4000
|
+
} else if (cpIsNum) {
|
|
4001
|
+
return true;
|
|
4002
|
+
} else {
|
|
4003
|
+
if (lp > cp) return true;
|
|
4004
|
+
if (lp < cp) return false;
|
|
4005
|
+
}
|
|
3537
4006
|
}
|
|
4007
|
+
return false;
|
|
4008
|
+
}
|
|
3538
4009
|
|
|
3539
|
-
|
|
3540
|
-
try { fs.writeFileSync(checkFile, now.toString()); } catch (_) { }
|
|
4010
|
+
// ─── Auto-Update Checker ──────────────────────────────────────────────────────
|
|
3541
4011
|
|
|
3542
|
-
|
|
4012
|
+
async function checkAutoUpdate() {
|
|
3543
4013
|
try {
|
|
3544
|
-
const
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
// Simple string comparison for versions like "1.0.0" (Assumes SemVer)
|
|
3548
|
-
if (npmVersion && npmVersion !== AWK_VERSION) {
|
|
4014
|
+
const updates = await depManager.checkUpdates(AWK_VERSION);
|
|
4015
|
+
if (updates.latestAwkit && isNewerVersion(updates.latestAwkit, AWK_VERSION)) {
|
|
3549
4016
|
log('');
|
|
3550
|
-
log(`${C.yellow}${C.bold}🌟 [Thông báo] Có phiên bản mới cho AWKit! (v${
|
|
4017
|
+
log(`${C.yellow}${C.bold}🌟 [Thông báo] Có phiên bản mới cho AWKit! (v${updates.latestAwkit})${C.reset}`);
|
|
3551
4018
|
log(`${C.gray} Phiên bản hiện tại: v${AWK_VERSION}${C.reset}`);
|
|
3552
4019
|
log(`${C.gray} Chạy lệnh sau để nâng cấp:${C.reset}`);
|
|
3553
4020
|
log(`${C.cyan} npm i -g @leejungkiin/awkit && awkit install${C.reset}`);
|
|
3554
4021
|
log('');
|
|
3555
4022
|
}
|
|
4023
|
+
|
|
4024
|
+
const currentRtk = depManager.getRtkVersion();
|
|
4025
|
+
if (updates.latestRtk && currentRtk && isNewerVersion(updates.latestRtk, currentRtk)) {
|
|
4026
|
+
log('');
|
|
4027
|
+
log(`${C.yellow}${C.bold}🌟 [Thông báo] Có phiên bản mới cho RTK! (v${updates.latestRtk})${C.reset}`);
|
|
4028
|
+
log(`${C.gray} Phiên bản hiện tại: v${currentRtk}${C.reset}`);
|
|
4029
|
+
log(`${C.gray} Chạy lệnh sau để nâng cấp:${C.reset}`);
|
|
4030
|
+
log(`${C.cyan} awkit rtk setup${C.reset}`);
|
|
4031
|
+
log('');
|
|
4032
|
+
}
|
|
3556
4033
|
} catch (_) {
|
|
3557
|
-
// Fail silently
|
|
4034
|
+
// Fail silently in auto check
|
|
3558
4035
|
}
|
|
3559
4036
|
}
|
|
3560
4037
|
|
|
@@ -3585,7 +4062,7 @@ function cmdGitnexus(args) {
|
|
|
3585
4062
|
const registry = readGitnexusRegistry();
|
|
3586
4063
|
if (registry.length === 0) {
|
|
3587
4064
|
info('No GitNexus indexed repositories found.');
|
|
3588
|
-
dim('Run `npx gitnexus analyze` in a project to index it.');
|
|
4065
|
+
dim('Run `pnpm dlx gitnexus analyze` or `npx gitnexus analyze` in a project to index it.');
|
|
3589
4066
|
return;
|
|
3590
4067
|
}
|
|
3591
4068
|
|
|
@@ -3618,7 +4095,7 @@ function cmdGitnexus(args) {
|
|
|
3618
4095
|
|
|
3619
4096
|
if (!match) {
|
|
3620
4097
|
warn('Current directory is not indexed by GitNexus.');
|
|
3621
|
-
dim('Run `npx gitnexus analyze` to index this project.');
|
|
4098
|
+
dim('Run `pnpm dlx gitnexus analyze` or `npx gitnexus analyze` to index this project.');
|
|
3622
4099
|
return;
|
|
3623
4100
|
}
|
|
3624
4101
|
|
|
@@ -3644,7 +4121,7 @@ function cmdGitnexus(args) {
|
|
|
3644
4121
|
if (stale) {
|
|
3645
4122
|
log('');
|
|
3646
4123
|
warn(`Index is ${ageDays} days old. Consider refreshing:`);
|
|
3647
|
-
dim(' npx gitnexus analyze');
|
|
4124
|
+
dim(' pnpm dlx gitnexus analyze (or npx gitnexus analyze)');
|
|
3648
4125
|
}
|
|
3649
4126
|
|
|
3650
4127
|
// Show projectId from .project-identity if available
|
|
@@ -3854,9 +4331,34 @@ function cmdGitnexus(args) {
|
|
|
3854
4331
|
break;
|
|
3855
4332
|
}
|
|
3856
4333
|
|
|
4334
|
+
case 'index':
|
|
4335
|
+
case 'analyze':
|
|
4336
|
+
case 'build': {
|
|
4337
|
+
const cwd = process.cwd();
|
|
4338
|
+
const usePnpm = fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'));
|
|
4339
|
+
const indexCmd = usePnpm ? 'pnpm' : 'npx';
|
|
4340
|
+
const indexArgs = usePnpm ? ['dlx', 'gitnexus', 'analyze'] : ['-y', 'gitnexus', 'analyze'];
|
|
4341
|
+
|
|
4342
|
+
info(`Indexing codebase with GitNexus (${usePnpm ? 'pnpm' : 'npx'})...`);
|
|
4343
|
+
dim(`Running: ${indexCmd} ${indexArgs.join(' ')}`);
|
|
4344
|
+
|
|
4345
|
+
const result = spawnSync(indexCmd, indexArgs, {
|
|
4346
|
+
cwd,
|
|
4347
|
+
stdio: 'inherit',
|
|
4348
|
+
shell: true
|
|
4349
|
+
});
|
|
4350
|
+
|
|
4351
|
+
if (result.status === 0) {
|
|
4352
|
+
ok('GitNexus index successfully refreshed! ✨');
|
|
4353
|
+
} else {
|
|
4354
|
+
err(`GitNexus indexing failed with exit code ${result.status}`);
|
|
4355
|
+
}
|
|
4356
|
+
break;
|
|
4357
|
+
}
|
|
4358
|
+
|
|
3857
4359
|
default:
|
|
3858
4360
|
err(`Unknown gitnexus sub-command: ${sub}`);
|
|
3859
|
-
log(` Available: list, status, clean`);
|
|
4361
|
+
log(` Available: index, list, status, clean`);
|
|
3860
4362
|
break;
|
|
3861
4363
|
}
|
|
3862
4364
|
}
|
|
@@ -3868,43 +4370,77 @@ async function cmdRtkSetup() {
|
|
|
3868
4370
|
log(`${C.cyan}${C.bold}║ ⚙️ RTK Auto-Setup & Configuration ║${C.reset}`);
|
|
3869
4371
|
log(`${C.cyan}${C.bold}╚═══════════════════════════════════════════════════════╝${C.reset}`);
|
|
3870
4372
|
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
execSync('which cargo', { stdio: 'ignore' });
|
|
3874
|
-
ok('Cargo is installed.');
|
|
3875
|
-
} catch (_) {
|
|
3876
|
-
err('Cargo/Rust not found. Please install Rust (https://rustup.rs/) and retry.');
|
|
3877
|
-
return;
|
|
3878
|
-
}
|
|
3879
|
-
|
|
3880
|
-
log(`\nInstalling RTK (Rust Token Killer) via Cargo...`);
|
|
3881
|
-
try {
|
|
3882
|
-
execSync('cargo install --git https://github.com/rtk-ai/rtk', { stdio: 'inherit' });
|
|
3883
|
-
ok('RTK successfully installed/updated via Cargo.');
|
|
3884
|
-
} catch (e) {
|
|
3885
|
-
err(`Failed to install RTK: ${e.message}`);
|
|
3886
|
-
return;
|
|
3887
|
-
}
|
|
4373
|
+
const installed = depManager.installRtk();
|
|
4374
|
+
if (!installed) return;
|
|
3888
4375
|
|
|
3889
4376
|
const zshrcPath = path.join(HOME, '.zshrc');
|
|
3890
4377
|
log(`\nConfiguring Shell Aliases in ~/.zshrc...`);
|
|
3891
4378
|
if (fs.existsSync(zshrcPath)) {
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
alias
|
|
3897
|
-
alias
|
|
3898
|
-
alias
|
|
3899
|
-
alias
|
|
4379
|
+
let zshrc = fs.readFileSync(zshrcPath, 'utf8');
|
|
4380
|
+
|
|
4381
|
+
// Clean up old aliases to avoid collision
|
|
4382
|
+
const oldAliases = [
|
|
4383
|
+
'alias git="rtk git"',
|
|
4384
|
+
'alias npm="rtk npm"',
|
|
4385
|
+
'alias pnpm="rtk pnpm"',
|
|
4386
|
+
'alias yarn="rtk yarn"',
|
|
4387
|
+
'alias cargo="rtk cargo"'
|
|
4388
|
+
];
|
|
4389
|
+
for (const oldAlias of oldAliases) {
|
|
4390
|
+
if (zshrc.includes(oldAlias)) {
|
|
4391
|
+
zshrc = zshrc.replace(new RegExp(`\\n?${oldAlias}\\n?`, 'g'), '\n');
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
const functionBlock = `
|
|
4396
|
+
# RTK Integration for AI Agents (AWKit)
|
|
4397
|
+
unalias npm pnpm yarn cargo git 2>/dev/null
|
|
4398
|
+
npm() {
|
|
4399
|
+
if [[ "$1" == "login" || "$1" == "adduser" || "$1" == "publish" ]]; then
|
|
4400
|
+
command npm "$@"
|
|
4401
|
+
else
|
|
4402
|
+
rtk npm "$@"
|
|
4403
|
+
fi
|
|
4404
|
+
}
|
|
4405
|
+
pnpm() {
|
|
4406
|
+
if [[ "$1" == "login" || "$1" == "publish" ]]; then
|
|
4407
|
+
command pnpm "$@"
|
|
4408
|
+
else
|
|
4409
|
+
rtk pnpm "$@"
|
|
4410
|
+
fi
|
|
4411
|
+
}
|
|
4412
|
+
yarn() {
|
|
4413
|
+
if [[ "$1" == "login" || "$1" == "publish" ]]; then
|
|
4414
|
+
command yarn "$@"
|
|
4415
|
+
else
|
|
4416
|
+
rtk yarn "$@"
|
|
4417
|
+
fi
|
|
4418
|
+
}
|
|
4419
|
+
cargo() {
|
|
4420
|
+
if [[ "$1" == "login" || "$1" == "publish" ]]; then
|
|
4421
|
+
command cargo "$@"
|
|
4422
|
+
else
|
|
4423
|
+
rtk cargo "$@"
|
|
4424
|
+
fi
|
|
4425
|
+
}
|
|
4426
|
+
git() {
|
|
4427
|
+
if [[ "$1" == "rebase" ]]; then
|
|
4428
|
+
command git "$@"
|
|
4429
|
+
else
|
|
4430
|
+
rtk git "$@"
|
|
4431
|
+
fi
|
|
4432
|
+
}
|
|
3900
4433
|
`;
|
|
3901
|
-
if
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
ok('Shell aliases successfully added to ~/.zshrc.');
|
|
3906
|
-
log(`\n${C.cyan}Please reload your shell (source ~/.zshrc) to apply shifts.${C.reset}`);
|
|
4434
|
+
// Clean up old RTK integration block if exists to allow updating
|
|
4435
|
+
if (zshrc.includes('# RTK Integration for AI Agents (AWKit)')) {
|
|
4436
|
+
const startIdx = zshrc.indexOf('# RTK Integration for AI Agents (AWKit)');
|
|
4437
|
+
zshrc = zshrc.substring(0, startIdx);
|
|
3907
4438
|
}
|
|
4439
|
+
|
|
4440
|
+
zshrc += functionBlock;
|
|
4441
|
+
fs.writeFileSync(zshrcPath, zshrc, 'utf8');
|
|
4442
|
+
ok('Shell wrappers successfully added/updated in ~/.zshrc.');
|
|
4443
|
+
log(`\n${C.cyan}Please reload your shell (source ~/.zshrc) to apply shifts.${C.reset}`);
|
|
3908
4444
|
} else {
|
|
3909
4445
|
warn('~/.zshrc not found. Skipping alias setup.');
|
|
3910
4446
|
}
|
|
@@ -3920,6 +4456,138 @@ async function cmdRtk(args) {
|
|
|
3920
4456
|
}
|
|
3921
4457
|
}
|
|
3922
4458
|
|
|
4459
|
+
// ─── Project Identity CLI View ───────────────────────────────────────────────
|
|
4460
|
+
|
|
4461
|
+
function cmdIdentity(args = []) {
|
|
4462
|
+
const cwd = process.cwd();
|
|
4463
|
+
const identityPath = path.join(cwd, '.project-identity');
|
|
4464
|
+
|
|
4465
|
+
if (!fs.existsSync(identityPath)) {
|
|
4466
|
+
err('No .project-identity found in the current directory.');
|
|
4467
|
+
log(` Run ${C.cyan}awkit init${C.reset} to create one for this project.`);
|
|
4468
|
+
return;
|
|
4469
|
+
}
|
|
4470
|
+
|
|
4471
|
+
try {
|
|
4472
|
+
const raw = fs.readFileSync(identityPath, 'utf8');
|
|
4473
|
+
const identity = JSON.parse(raw);
|
|
4474
|
+
|
|
4475
|
+
// Handle specific field querying
|
|
4476
|
+
if (args.length > 0) {
|
|
4477
|
+
const query = args[0];
|
|
4478
|
+
|
|
4479
|
+
if (query === '--keys') {
|
|
4480
|
+
console.log(Object.keys(identity).join('\n'));
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
if (query === '--json') {
|
|
4485
|
+
console.log(JSON.stringify(identity, null, 2));
|
|
4486
|
+
return;
|
|
4487
|
+
}
|
|
4488
|
+
|
|
4489
|
+
// Helper to get nested value by dot notation (e.g., automation.build.enabled)
|
|
4490
|
+
const getNested = (obj, path) => {
|
|
4491
|
+
return path.split('.').reduce((acc, part) => acc && acc[part], obj);
|
|
4492
|
+
};
|
|
4493
|
+
|
|
4494
|
+
const val = getNested(identity, query);
|
|
4495
|
+
if (val !== undefined) {
|
|
4496
|
+
if (typeof val === 'object') {
|
|
4497
|
+
console.log(JSON.stringify(val));
|
|
4498
|
+
} else {
|
|
4499
|
+
console.log(val);
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
return; // Exit silently if undefined, ideal for bash scripts
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
const border = `${C.cyan}${C.bold}╔═══════════════════════════════════════════════════════╗${C.reset}`;
|
|
4506
|
+
const bottom = `${C.cyan}${C.bold}╚═══════════════════════════════════════════════════════╝${C.reset}`;
|
|
4507
|
+
const line = `${C.gray}${'─'.repeat(56)}${C.reset}`;
|
|
4508
|
+
|
|
4509
|
+
log('');
|
|
4510
|
+
log(border);
|
|
4511
|
+
log(`${C.cyan}${C.bold}║ 🆔 PROJECT IDENTITY: ${C.green}${C.bold}${String(identity.projectName || 'Unnamed Project').padEnd(30)}${C.cyan}${C.bold} ║${C.reset}`);
|
|
4512
|
+
log(bottom);
|
|
4513
|
+
log('');
|
|
4514
|
+
|
|
4515
|
+
// Basic Info
|
|
4516
|
+
log(`${C.bold}ℹ️ Basic Information${C.reset}`);
|
|
4517
|
+
log(line);
|
|
4518
|
+
log(` ${C.bold}Project Stage:${C.reset} ${identity.projectStage || 'development'}`);
|
|
4519
|
+
log(` ${C.bold}Project Type:${C.reset} ${identity.projectType ? C.green + identity.projectType + C.reset : C.yellow + 'Not configured' + C.reset}`);
|
|
4520
|
+
log(` ${C.bold}Primary Lang:${C.reset} ${identity.primaryLanguage || 'en'}`);
|
|
4521
|
+
if (identity.techStack) {
|
|
4522
|
+
const rt = Array.isArray(identity.techStack.runtime) ? identity.techStack.runtime.join(', ') : 'N/A';
|
|
4523
|
+
const lang = Array.isArray(identity.techStack.languages) ? identity.techStack.languages.join(', ') : 'N/A';
|
|
4524
|
+
log(` ${C.bold}Runtime/Lang:${C.reset} ${rt} / ${lang}`);
|
|
4525
|
+
}
|
|
4526
|
+
log('');
|
|
4527
|
+
|
|
4528
|
+
// Build Configuration
|
|
4529
|
+
log(`${C.bold}🛠️ Build & Run Control${C.reset}`);
|
|
4530
|
+
log(line);
|
|
4531
|
+
if (identity.automation && identity.automation.build) {
|
|
4532
|
+
const b = identity.automation.build;
|
|
4533
|
+
const statusStr = b.enabled ? `${C.green}Enabled (Safe Auto-Run via awkit build)${C.reset}` : `${C.yellow}Disabled / Manual Only${C.reset}`;
|
|
4534
|
+
log(` ${C.bold}Build Control:${C.reset} ${statusStr}`);
|
|
4535
|
+
log(` ${C.bold}Build Command:${C.reset} ${C.cyan}${b.command || 'N/A'}${C.reset}`);
|
|
4536
|
+
} else {
|
|
4537
|
+
log(` ${C.bold}Build Control:${C.reset} ${C.yellow}Not Configured (Manual Mode)${C.reset}`);
|
|
4538
|
+
}
|
|
4539
|
+
if (identity.automation && identity.automation.run) {
|
|
4540
|
+
const r = identity.automation.run;
|
|
4541
|
+
const statusStr = r.enabled ? `${C.green}Enabled (Safe Auto-Run via awkit run)${C.reset}` : `${C.yellow}Disabled / Manual Only${C.reset}`;
|
|
4542
|
+
log(` ${C.bold}Run Control:${C.reset} ${statusStr}`);
|
|
4543
|
+
log(` ${C.bold}Run Command:${C.reset} ${C.cyan}${r.command || 'N/A'}${C.reset}`);
|
|
4544
|
+
} else {
|
|
4545
|
+
log(` ${C.bold}Run Control:${C.reset} ${C.yellow}Not Configured (Manual Mode)${C.reset}`);
|
|
4546
|
+
}
|
|
4547
|
+
log('');
|
|
4548
|
+
|
|
4549
|
+
// Automation Gates
|
|
4550
|
+
log(`${C.bold}🔒 Automation & Sync Gates${C.reset}`);
|
|
4551
|
+
log(line);
|
|
4552
|
+
if (identity.automation) {
|
|
4553
|
+
const git = identity.automation.git || {};
|
|
4554
|
+
log(` ${C.bold}Git AutoCommit:${C.reset} ${git.autoCommit ? C.green + 'true' : C.red + 'false'}${C.reset}`);
|
|
4555
|
+
log(` ${C.bold}Git AutoPush:${C.reset} ${git.autoPush ? C.green + 'true' : C.red + 'false'}${C.reset}`);
|
|
4556
|
+
|
|
4557
|
+
const trello = identity.automation.trello || {};
|
|
4558
|
+
const syncStr = trello.enabled
|
|
4559
|
+
? `${C.green}Enabled${C.reset} (AutoSync: ${trello.autoSync ? C.green + 'true' : C.red + 'false'}${C.reset})`
|
|
4560
|
+
: `${C.red}Disabled${C.reset}`;
|
|
4561
|
+
log(` ${C.bold}Trello Sync:${C.reset} ${syncStr}`);
|
|
4562
|
+
if (identity.trello) {
|
|
4563
|
+
log(` ${C.bold}Trello Board:${C.reset} ${identity.trello.board || 'N/A'}`);
|
|
4564
|
+
log(` ${C.bold}Trello Card:${C.reset} ${identity.trello.card || 'N/A'}`);
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4567
|
+
const tg = identity.automation.telegram || {};
|
|
4568
|
+
const tgStr = tg.enabled ? `${C.green}Enabled${C.reset}` : `${C.red}Disabled${C.reset}`;
|
|
4569
|
+
log(` ${C.bold}Telegram Alerts:${C.reset} ${tgStr}`);
|
|
4570
|
+
if (tg.triggers) {
|
|
4571
|
+
const trigs = Object.keys(tg.triggers).filter(k => tg.triggers[k]).join(', ');
|
|
4572
|
+
log(` ${C.bold}Alert Triggers:${C.reset} ${C.gray}${trigs || 'None'}${C.reset}`);
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
log('');
|
|
4576
|
+
|
|
4577
|
+
// Caveman Mode
|
|
4578
|
+
if (identity.communication && identity.communication.cavemanMode) {
|
|
4579
|
+
const cm = identity.communication.cavemanMode;
|
|
4580
|
+
log(`${C.bold}💬 Communication Mode${C.reset}`);
|
|
4581
|
+
log(line);
|
|
4582
|
+
log(` ${C.bold}Caveman Mode:${C.reset} ${cm.enabled ? C.green + 'Enabled (' + cm.level + ')' : C.red + 'Disabled'}${C.reset}`);
|
|
4583
|
+
log('');
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
} catch (e) {
|
|
4587
|
+
err(`Failed to parse .project-identity: ${e.message}`);
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
|
|
3923
4591
|
// ─── Native HTTP Server ───────────────────────────────────────────────────────
|
|
3924
4592
|
|
|
3925
4593
|
function cmdServe(args) {
|
|
@@ -4012,15 +4680,354 @@ function cmdServe(args) {
|
|
|
4012
4680
|
});
|
|
4013
4681
|
}
|
|
4014
4682
|
|
|
4015
|
-
|
|
4683
|
+
const GLOBAL_CONFIG_PATH = path.join(HOME, '.awkit_config.json');
|
|
4684
|
+
|
|
4685
|
+
function readGlobalConfig() {
|
|
4686
|
+
const defaultConf = {
|
|
4687
|
+
audioAlerts: true,
|
|
4688
|
+
runners: {
|
|
4689
|
+
claude: true,
|
|
4690
|
+
codex: true,
|
|
4691
|
+
qwen: true
|
|
4692
|
+
}
|
|
4693
|
+
};
|
|
4694
|
+
if (!fs.existsSync(GLOBAL_CONFIG_PATH)) return defaultConf;
|
|
4695
|
+
try {
|
|
4696
|
+
const parsed = JSON.parse(fs.readFileSync(GLOBAL_CONFIG_PATH, 'utf8'));
|
|
4697
|
+
return {
|
|
4698
|
+
...defaultConf,
|
|
4699
|
+
...parsed,
|
|
4700
|
+
runners: {
|
|
4701
|
+
...defaultConf.runners,
|
|
4702
|
+
...(parsed.runners || {})
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
} catch (_) {
|
|
4706
|
+
return defaultConf;
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4016
4709
|
|
|
4017
|
-
|
|
4018
|
-
|
|
4710
|
+
function writeGlobalConfig(config) {
|
|
4711
|
+
try {
|
|
4712
|
+
fs.writeFileSync(GLOBAL_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
4713
|
+
return true;
|
|
4714
|
+
} catch (e) {
|
|
4715
|
+
err(`Failed to write global config: ${e.message}`);
|
|
4716
|
+
return false;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
function findClaudePath() {
|
|
4721
|
+
let localConfig = {};
|
|
4722
|
+
try {
|
|
4723
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4724
|
+
if (fs.existsSync(p)) {
|
|
4725
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4726
|
+
}
|
|
4727
|
+
} catch (_) {}
|
|
4728
|
+
|
|
4729
|
+
if (localConfig.automation?.multiAgent?.runners?.claude) {
|
|
4730
|
+
const p = localConfig.automation.multiAgent.runners.claude;
|
|
4731
|
+
if (fs.existsSync(p)) return p;
|
|
4732
|
+
}
|
|
4733
|
+
const homeClaude = path.join(os.homedir(), '.claude', 'local', 'claude');
|
|
4734
|
+
if (fs.existsSync(homeClaude)) return homeClaude;
|
|
4735
|
+
|
|
4736
|
+
try {
|
|
4737
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4738
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which claude"' : 'bash -lc "which claude"';
|
|
4739
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4740
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4741
|
+
} catch (_) {}
|
|
4742
|
+
|
|
4743
|
+
return 'claude';
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
function findCodexPath() {
|
|
4747
|
+
let localConfig = {};
|
|
4748
|
+
try {
|
|
4749
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4750
|
+
if (fs.existsSync(p)) {
|
|
4751
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4752
|
+
}
|
|
4753
|
+
} catch (_) {}
|
|
4754
|
+
|
|
4755
|
+
if (localConfig.automation?.multiAgent?.runners?.codex) {
|
|
4756
|
+
const p = localConfig.automation.multiAgent.runners.codex;
|
|
4757
|
+
if (fs.existsSync(p)) return p;
|
|
4758
|
+
}
|
|
4759
|
+
try {
|
|
4760
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4761
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which codex"' : 'bash -lc "which codex"';
|
|
4762
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4763
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4764
|
+
} catch (_) {}
|
|
4765
|
+
return 'codex';
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
function findQwenPath() {
|
|
4769
|
+
let localConfig = {};
|
|
4770
|
+
try {
|
|
4771
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4772
|
+
if (fs.existsSync(p)) {
|
|
4773
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4774
|
+
}
|
|
4775
|
+
} catch (_) {}
|
|
4776
|
+
|
|
4777
|
+
if (localConfig.automation?.multiAgent?.runners?.qwen) {
|
|
4778
|
+
const p = localConfig.automation.multiAgent.runners.qwen;
|
|
4779
|
+
if (fs.existsSync(p)) return p;
|
|
4780
|
+
}
|
|
4781
|
+
try {
|
|
4782
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
4783
|
+
const shellCmd = shell.endsWith('zsh') ? 'zsh -lc "which qwen"' : 'bash -lc "which qwen"';
|
|
4784
|
+
const detected = execSync(shellCmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
4785
|
+
if (detected && fs.existsSync(detected)) return detected;
|
|
4786
|
+
} catch (_) {}
|
|
4787
|
+
return 'qwen';
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
function isRunnerEnabled(runnerName) {
|
|
4791
|
+
let localConfig = {};
|
|
4792
|
+
try {
|
|
4793
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4794
|
+
if (fs.existsSync(p)) {
|
|
4795
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4796
|
+
}
|
|
4797
|
+
} catch (_) {}
|
|
4798
|
+
|
|
4799
|
+
const localVal = localConfig.automation?.multiAgent?.runnersEnabled?.[runnerName];
|
|
4800
|
+
if (localVal !== undefined) return localVal;
|
|
4801
|
+
|
|
4802
|
+
const globalConfig = readGlobalConfig();
|
|
4803
|
+
const globalVal = globalConfig.runners?.[runnerName];
|
|
4804
|
+
if (globalVal !== undefined) return globalVal;
|
|
4805
|
+
|
|
4806
|
+
return true;
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
function isRunnerAvailable(runnerName) {
|
|
4810
|
+
if (!isRunnerEnabled(runnerName)) return false;
|
|
4811
|
+
let p;
|
|
4812
|
+
if (runnerName === 'claude') p = findClaudePath();
|
|
4813
|
+
else if (runnerName === 'codex') p = findCodexPath();
|
|
4814
|
+
else if (runnerName === 'qwen') p = findQwenPath();
|
|
4815
|
+
else return false;
|
|
4816
|
+
|
|
4817
|
+
if (fs.existsSync(p)) return true;
|
|
4818
|
+
try {
|
|
4819
|
+
execSync(`which ${p} || command -v ${p}`, { stdio: 'ignore' });
|
|
4820
|
+
return true;
|
|
4821
|
+
} catch (_) {
|
|
4822
|
+
return false;
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
function cmdGlobalConfig(args = []) {
|
|
4827
|
+
const sub = args[0];
|
|
4828
|
+
if (sub === 'audio') {
|
|
4829
|
+
const config = readGlobalConfig();
|
|
4830
|
+
const action = args[1];
|
|
4831
|
+
if (!action) {
|
|
4832
|
+
info(`Audio Alerts: ${config.audioAlerts ? 'ON' : 'OFF'}`);
|
|
4833
|
+
return;
|
|
4834
|
+
}
|
|
4835
|
+
if (action === 'on' || action === 'true' || action === '1') {
|
|
4836
|
+
config.audioAlerts = true;
|
|
4837
|
+
if (writeGlobalConfig(config)) {
|
|
4838
|
+
ok('Audio alerts turned ON globally.');
|
|
4839
|
+
}
|
|
4840
|
+
} else if (action === 'off' || action === 'false' || action === '0') {
|
|
4841
|
+
config.audioAlerts = false;
|
|
4842
|
+
if (writeGlobalConfig(config)) {
|
|
4843
|
+
ok('Audio alerts turned OFF globally.');
|
|
4844
|
+
}
|
|
4845
|
+
} else {
|
|
4846
|
+
err(`Invalid audio option: ${action}. Use 'on' or 'off'.`);
|
|
4847
|
+
}
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
if (sub === 'claude' || sub === 'codex' || sub === 'qwen') {
|
|
4852
|
+
const config = readGlobalConfig();
|
|
4853
|
+
const action = args[1];
|
|
4854
|
+
if (!action) {
|
|
4855
|
+
info(`${sub.toUpperCase()} Runner: ${config.runners?.[sub] !== false ? 'ON' : 'OFF'}`);
|
|
4856
|
+
return;
|
|
4857
|
+
}
|
|
4858
|
+
if (action === 'on' || action === 'true' || action === '1') {
|
|
4859
|
+
config.runners = config.runners || {};
|
|
4860
|
+
config.runners[sub] = true;
|
|
4861
|
+
if (writeGlobalConfig(config)) {
|
|
4862
|
+
ok(`${sub.toUpperCase()} runner turned ON globally.`);
|
|
4863
|
+
}
|
|
4864
|
+
} else if (action === 'off' || action === 'false' || action === '0') {
|
|
4865
|
+
config.runners = config.runners || {};
|
|
4866
|
+
config.runners[sub] = false;
|
|
4867
|
+
if (writeGlobalConfig(config)) {
|
|
4868
|
+
ok(`${sub.toUpperCase()} runner turned OFF globally.`);
|
|
4869
|
+
}
|
|
4870
|
+
} else {
|
|
4871
|
+
err(`Invalid runner option: ${action}. Use 'on' or 'off'.`);
|
|
4872
|
+
}
|
|
4873
|
+
return;
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
if (sub === 'runners' || sub === 'runner') {
|
|
4877
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4878
|
+
log('');
|
|
4879
|
+
log(`${C.cyan}${C.bold}🏃 RUNNER AGENTS STATUS${C.reset}`);
|
|
4880
|
+
log(line);
|
|
4881
|
+
|
|
4882
|
+
const runners = ['claude', 'codex', 'qwen'];
|
|
4883
|
+
for (const r of runners) {
|
|
4884
|
+
const enabled = isRunnerEnabled(r);
|
|
4885
|
+
const path = r === 'claude' ? findClaudePath() : (r === 'codex' ? findCodexPath() : findQwenPath());
|
|
4886
|
+
const available = isRunnerAvailable(r);
|
|
4887
|
+
|
|
4888
|
+
const statusStr = enabled ? `${C.green}ON${C.reset}` : `${C.red}OFF${C.reset}`;
|
|
4889
|
+
const availStr = available ? `${C.green}✅ Available${C.reset}` : `${C.red}❌ Unavailable${C.reset}`;
|
|
4890
|
+
|
|
4891
|
+
log(` ● ${C.bold}${r.padEnd(8)}${C.reset} Status: [${statusStr}] Path: ${path.padEnd(30)} [${availStr}]`);
|
|
4892
|
+
}
|
|
4893
|
+
log('');
|
|
4894
|
+
return;
|
|
4895
|
+
}
|
|
4896
|
+
|
|
4897
|
+
if (sub === 'models' || sub === 'model') {
|
|
4898
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4899
|
+
log('');
|
|
4900
|
+
log(`${C.cyan}${C.bold}🤖 MODEL ROUTING POLICY${C.reset}`);
|
|
4901
|
+
log(line);
|
|
4902
|
+
|
|
4903
|
+
let localConfig = {};
|
|
4904
|
+
let projectLoaded = false;
|
|
4905
|
+
try {
|
|
4906
|
+
const p = path.join(process.cwd(), '.project-identity');
|
|
4907
|
+
if (fs.existsSync(p)) {
|
|
4908
|
+
localConfig = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
4909
|
+
projectLoaded = true;
|
|
4910
|
+
}
|
|
4911
|
+
} catch (_) {}
|
|
4912
|
+
|
|
4913
|
+
if (projectLoaded) {
|
|
4914
|
+
log(` Project: ${C.green}${C.bold}${localConfig.projectName || 'Active Project'}${C.reset}`);
|
|
4915
|
+
const policy = localConfig.modelPolicy || {};
|
|
4916
|
+
log(` Routing Mode: ${C.cyan}${policy.mode || 'auto'}${C.reset}`);
|
|
4917
|
+
log(` Default Tier: ${C.cyan}${policy.defaultTier || 'STANDARD'}${C.reset}`);
|
|
4918
|
+
|
|
4919
|
+
if (policy.tierOverrides && Object.keys(policy.tierOverrides).length > 0) {
|
|
4920
|
+
log(` Tier Overrides:`);
|
|
4921
|
+
for (const [pattern, tier] of Object.entries(policy.tierOverrides)) {
|
|
4922
|
+
log(` * ${pattern.padEnd(20)} ➜ ${C.yellow}${tier}${C.reset}`);
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
} else {
|
|
4926
|
+
log(` No project loaded in current directory.`);
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
log(line);
|
|
4930
|
+
log(` ${C.bold}Default Models:${C.reset}`);
|
|
4931
|
+
log(` * Standard execution: ${C.green}gemini-3.5-flash${C.reset} (Fast & cost-efficient)`);
|
|
4932
|
+
log(` * Heavy / Spec tasks: ${C.green}gemini-3.1-pro${C.reset} (High reasoning quality)`);
|
|
4933
|
+
log(` * Light tasks: ${C.green}gemini-3.1-flash-lite${C.reset} (Ultra-low latency)`);
|
|
4934
|
+
log('');
|
|
4935
|
+
return;
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
if (!sub || sub === 'list') {
|
|
4939
|
+
const config = readGlobalConfig();
|
|
4940
|
+
const line = `${C.gray}${'─'.repeat(60)}${C.reset}`;
|
|
4941
|
+
log('');
|
|
4942
|
+
log(`${C.cyan}${C.bold}⚙️ AWK CLI CONFIGURATION${C.reset}`);
|
|
4943
|
+
log(line);
|
|
4944
|
+
|
|
4945
|
+
const formatBool = (val) => val !== false ? `${C.green}ON${C.reset}` : `${C.red}OFF${C.reset}`;
|
|
4946
|
+
|
|
4947
|
+
log(` ${C.bold}audioAlerts${C.reset.padEnd(20)} ${formatBool(config.audioAlerts).padEnd(15)} Play speech and chimes on complete`);
|
|
4948
|
+
log(` ${C.bold}runners.claude${C.reset.padEnd(20)} ${formatBool(config.runners?.claude).padEnd(15)} Use Claude Code CLI for planning`);
|
|
4949
|
+
log(` ${C.bold}runners.codex${C.reset.padEnd(20)} ${formatBool(config.runners?.codex).padEnd(15)} Use Codex CLI for UI and assets`);
|
|
4950
|
+
log(` ${C.bold}runners.qwen${C.reset.padEnd(20)} ${formatBool(config.runners?.qwen).padEnd(15)} Use Qwen Coder CLI for execution`);
|
|
4951
|
+
log(line);
|
|
4952
|
+
log(`💡 To toggle, run: ${C.cyan}awkit config <param> <on|off>${C.reset}`);
|
|
4953
|
+
log(` Example: ${C.cyan}awkit config claude off${C.reset}`);
|
|
4954
|
+
log('');
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
if (sub === 'get' && args[1]) {
|
|
4959
|
+
const config = readGlobalConfig();
|
|
4960
|
+
const key = args[1];
|
|
4961
|
+
let val;
|
|
4962
|
+
if (key.includes('.')) {
|
|
4963
|
+
val = key.split('.').reduce((acc, part) => acc && acc[part], config);
|
|
4964
|
+
} else {
|
|
4965
|
+
val = config[key];
|
|
4966
|
+
}
|
|
4967
|
+
if (val !== undefined) {
|
|
4968
|
+
console.log(val);
|
|
4969
|
+
} else {
|
|
4970
|
+
err(`Key "${key}" not found in global config.`);
|
|
4971
|
+
}
|
|
4972
|
+
return;
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
if (sub === 'set' && args[1] && args[2] !== undefined) {
|
|
4976
|
+
const config = readGlobalConfig();
|
|
4977
|
+
const key = args[1];
|
|
4978
|
+
let val = args[2];
|
|
4979
|
+
if (val === 'true') val = true;
|
|
4980
|
+
if (val === 'false') val = false;
|
|
4981
|
+
|
|
4982
|
+
if (key.includes('.')) {
|
|
4983
|
+
const parts = key.split('.');
|
|
4984
|
+
let current = config;
|
|
4985
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
4986
|
+
current[parts[i]] = current[parts[i]] || {};
|
|
4987
|
+
current = current[parts[i]];
|
|
4988
|
+
}
|
|
4989
|
+
current[parts[parts.length - 1]] = val;
|
|
4990
|
+
} else {
|
|
4991
|
+
config[key] = val;
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4994
|
+
if (writeGlobalConfig(config)) {
|
|
4995
|
+
ok(`Global config updated: "${key}" = ${val}`);
|
|
4996
|
+
}
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
|
|
5000
|
+
err('Usage:');
|
|
5001
|
+
log(' awkit config list');
|
|
5002
|
+
log(' awkit config get <key>');
|
|
5003
|
+
log(' awkit config set <key> <value>');
|
|
5004
|
+
log(' awkit config audio <on|off>');
|
|
5005
|
+
log(' awkit config claude <on|off>');
|
|
5006
|
+
log(' awkit config codex <on|off>');
|
|
5007
|
+
log(' awkit config qwen <on|off>');
|
|
5008
|
+
log(' awkit config runners');
|
|
5009
|
+
log(' awkit config models');
|
|
5010
|
+
}
|
|
5011
|
+
|
|
5012
|
+
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
4019
5013
|
|
|
4020
5014
|
const [, , command, ...args] = process.argv;
|
|
4021
5015
|
|
|
4022
5016
|
(async () => {
|
|
5017
|
+
await checkAutoUpdate();
|
|
4023
5018
|
switch (command) {
|
|
5019
|
+
case 'build':
|
|
5020
|
+
cmdBuild();
|
|
5021
|
+
break;
|
|
5022
|
+
case 'run':
|
|
5023
|
+
cmdRun(args);
|
|
5024
|
+
break;
|
|
5025
|
+
case 'task':
|
|
5026
|
+
cmdTask(args);
|
|
5027
|
+
break;
|
|
5028
|
+
case 'project':
|
|
5029
|
+
cmdProject(args);
|
|
5030
|
+
break;
|
|
4024
5031
|
case 'init':
|
|
4025
5032
|
await cmdInit(args.includes('--force'));
|
|
4026
5033
|
break;
|
|
@@ -4037,13 +5044,23 @@ const [, , command, ...args] = process.argv;
|
|
|
4037
5044
|
cmdSync();
|
|
4038
5045
|
break;
|
|
4039
5046
|
case 'status':
|
|
4040
|
-
|
|
5047
|
+
if (args[0] === 'gn' || args[0] === 'gitnexus') {
|
|
5048
|
+
cmdGitnexus(['status']);
|
|
5049
|
+
} else {
|
|
5050
|
+
cmdStatus();
|
|
5051
|
+
}
|
|
4041
5052
|
break;
|
|
4042
5053
|
case 'harvest':
|
|
4043
5054
|
cmdHarvest(args.includes('--dry-run'));
|
|
4044
5055
|
break;
|
|
4045
5056
|
case 'doctor':
|
|
4046
|
-
cmdDoctor();
|
|
5057
|
+
await cmdDoctor();
|
|
5058
|
+
break;
|
|
5059
|
+
case 'storage':
|
|
5060
|
+
cmdStorage(args);
|
|
5061
|
+
break;
|
|
5062
|
+
case 'pipeline':
|
|
5063
|
+
cmdPipeline(args);
|
|
4047
5064
|
break;
|
|
4048
5065
|
case 'browser':
|
|
4049
5066
|
cmdBrowser(args);
|
|
@@ -4079,6 +5096,16 @@ const [, , command, ...args] = process.argv;
|
|
|
4079
5096
|
case 'creds':
|
|
4080
5097
|
cmdCredentials(args);
|
|
4081
5098
|
break;
|
|
5099
|
+
case 'index':
|
|
5100
|
+
case 'analyze':
|
|
5101
|
+
cmdGitnexus(['index', ...args]);
|
|
5102
|
+
break;
|
|
5103
|
+
case 'clean':
|
|
5104
|
+
cmdGitnexus(['clean', ...args]);
|
|
5105
|
+
break;
|
|
5106
|
+
case 'list':
|
|
5107
|
+
cmdGitnexus(['list', ...args]);
|
|
5108
|
+
break;
|
|
4082
5109
|
case 'set-openrouter': {
|
|
4083
5110
|
const key = args[0];
|
|
4084
5111
|
if (!key) {
|
|
@@ -4094,6 +5121,10 @@ const [, , command, ...args] = process.argv;
|
|
|
4094
5121
|
case 'rtk':
|
|
4095
5122
|
await cmdRtk(args);
|
|
4096
5123
|
break;
|
|
5124
|
+
case 'i18n':
|
|
5125
|
+
await cmdI18n(args);
|
|
5126
|
+
break;
|
|
5127
|
+
|
|
4097
5128
|
case 'gitnexus':
|
|
4098
5129
|
case 'gn':
|
|
4099
5130
|
cmdGitnexus(args);
|
|
@@ -4116,6 +5147,31 @@ const [, , command, ...args] = process.argv;
|
|
|
4116
5147
|
case 'restart':
|
|
4117
5148
|
await cmdRestart();
|
|
4118
5149
|
break;
|
|
5150
|
+
case 'greet':
|
|
5151
|
+
cmdGreet(args);
|
|
5152
|
+
break;
|
|
5153
|
+
case 'config-global':
|
|
5154
|
+
cmdGlobalConfig(args);
|
|
5155
|
+
break;
|
|
5156
|
+
case 'identity':
|
|
5157
|
+
case 'config':
|
|
5158
|
+
case 'project': {
|
|
5159
|
+
const isGlobalSub = command === 'config' && (
|
|
5160
|
+
args.length === 0 ||
|
|
5161
|
+
['audio', 'claude', 'codex', 'qwen', 'runners', 'runner', 'models', 'model', 'list', 'get', 'set'].includes(args[0])
|
|
5162
|
+
);
|
|
5163
|
+
if (isGlobalSub) {
|
|
5164
|
+
// If there are no arguments but a project identity exists, show project identity as default
|
|
5165
|
+
if (args.length === 0 && fs.existsSync(path.join(process.cwd(), '.project-identity'))) {
|
|
5166
|
+
cmdIdentity(args);
|
|
5167
|
+
} else {
|
|
5168
|
+
cmdGlobalConfig(args);
|
|
5169
|
+
}
|
|
5170
|
+
} else {
|
|
5171
|
+
cmdIdentity(args);
|
|
5172
|
+
}
|
|
5173
|
+
break;
|
|
5174
|
+
}
|
|
4119
5175
|
case 'help':
|
|
4120
5176
|
case '--help':
|
|
4121
5177
|
case '-h':
|