@leejungkiin/awkit 1.3.8 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/awk.js +630 -52
- package/bin/claude-generators.js +122 -0
- package/core/AGENTS.md +54 -0
- package/core/CLAUDE.md +155 -0
- package/core/GEMINI.md +44 -9
- package/core/GEMINI.md.bak +126 -199
- package/package.json +1 -1
- package/skills/ai-sprite-maker/SKILL.md +81 -0
- package/skills/ai-sprite-maker/scripts/animate_sprite.py +102 -0
- package/skills/ai-sprite-maker/scripts/process_sprites.py +140 -0
- package/skills/awf-session-restore/SKILL.md +12 -2
- package/skills/brainstorm-agent/SKILL.md +11 -8
- package/skills/code-review/SKILL.md +21 -33
- package/skills/gitnexus/gitnexus-cli/SKILL.md +82 -0
- package/skills/gitnexus/gitnexus-debugging/SKILL.md +89 -0
- package/skills/gitnexus/gitnexus-exploring/SKILL.md +78 -0
- package/skills/gitnexus/gitnexus-guide/SKILL.md +64 -0
- package/skills/gitnexus/gitnexus-impact-analysis/SKILL.md +97 -0
- package/skills/gitnexus/gitnexus-refactoring/SKILL.md +121 -0
- package/skills/lucylab-tts/SKILL.md +64 -0
- package/skills/lucylab-tts/resources/voices_library.json +908 -0
- package/skills/lucylab-tts/scripts/.env +1 -0
- package/skills/lucylab-tts/scripts/lucylab_tts.py +506 -0
- package/skills/nm-memory-sync/SKILL.md +14 -1
- package/skills/orchestrator/SKILL.md +5 -38
- package/skills/ship-to-code/SKILL.md +115 -0
- package/skills/short-maker/SKILL.md +150 -0
- package/skills/short-maker/_backup/storyboard.html +106 -0
- package/skills/short-maker/_backup/video_mixer.py +296 -0
- package/skills/short-maker/outputs/fitbite-promo/background.jpg +0 -0
- package/skills/short-maker/outputs/fitbite-promo/final/promo-final.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/script.md +19 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-01.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-02.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-03.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/segments/scene-04.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-01.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-02.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-03.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard/scene-04.png +0 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard.html +133 -0
- package/skills/short-maker/outputs/fitbite-promo/storyboard.json +38 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/merged_chroma.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/merged_crossfaded.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_00.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_01.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_02.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/temp/ready_03.mp4 +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/manifest.json +31 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-01.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-02.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-03.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts/scene-04.wav +0 -0
- package/skills/short-maker/outputs/fitbite-promo/tts_script.txt +11 -0
- package/skills/short-maker/scripts/google-flow-cli/.project-identity +41 -0
- package/skills/short-maker/scripts/google-flow-cli/.trae/rules/project_rules.md +52 -0
- package/skills/short-maker/scripts/google-flow-cli/CODEBASE.md +67 -0
- package/skills/short-maker/scripts/google-flow-cli/GoogleFlowCli.code-workspace +29 -0
- package/skills/short-maker/scripts/google-flow-cli/README.md +168 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/PROJECT.md +12 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/REQUIREMENTS.md +22 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/ROADMAP.md +16 -0
- package/skills/short-maker/scripts/google-flow-cli/docs/specs/TECH-SPEC.md +13 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/__init__.py +3 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/__init__.py +19 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/client.py +1921 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/models.py +64 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/api/rpc_ids.py +98 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/__init__.py +15 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/browser_auth.py +692 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/humanizer.py +417 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/proxy_ext.py +120 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/auth/recaptcha.py +482 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/__init__.py +5 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/batchexecute/client.py +414 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/cli/__init__.py +1 -0
- package/skills/short-maker/scripts/google-flow-cli/gflow/cli/main.py +1075 -0
- package/skills/short-maker/scripts/google-flow-cli/pyproject.toml +36 -0
- package/skills/short-maker/scripts/google-flow-cli/script.txt +22 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/__init__.py +0 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/test_batchexecute.py +113 -0
- package/skills/short-maker/scripts/google-flow-cli/tests/test_client.py +190 -0
- package/skills/short-maker/templates/aida_script.md +40 -0
- package/skills/short-maker/templates/mimic_analyzer.md +29 -0
- package/skills/single-flow-task-execution/SKILL.md +412 -0
- package/skills/single-flow-task-execution/code-quality-reviewer-prompt.md +20 -0
- package/skills/single-flow-task-execution/implementer-prompt.md +78 -0
- package/skills/single-flow-task-execution/spec-reviewer-prompt.md +61 -0
- package/skills/skill-creator/SKILL.md +44 -0
- package/skills/spm-build-analysis/SKILL.md +92 -0
- package/skills/spm-build-analysis/references/build-optimization-sources.md +155 -0
- package/skills/spm-build-analysis/references/recommendation-format.md +85 -0
- package/skills/spm-build-analysis/references/spm-analysis-checks.md +105 -0
- package/skills/spm-build-analysis/scripts/check_spm_pins.py +118 -0
- package/skills/symphony-enforcer/SKILL.md +83 -97
- package/skills/symphony-orchestrator/SKILL.md +1 -1
- package/skills/trello-sync/SKILL.md +52 -45
- package/skills/verification-gate/SKILL.md +13 -2
- package/skills/xcode-build-benchmark/SKILL.md +88 -0
- package/skills/xcode-build-benchmark/references/benchmark-artifacts.md +94 -0
- package/skills/xcode-build-benchmark/references/benchmarking-workflow.md +67 -0
- package/skills/xcode-build-benchmark/schemas/build-benchmark.schema.json +230 -0
- package/skills/xcode-build-benchmark/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-fixer/SKILL.md +218 -0
- package/skills/xcode-build-fixer/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-build-fixer/references/fix-patterns.md +290 -0
- package/skills/xcode-build-fixer/references/recommendation-format.md +85 -0
- package/skills/xcode-build-fixer/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-orchestrator/SKILL.md +156 -0
- package/skills/xcode-build-orchestrator/references/benchmark-artifacts.md +94 -0
- package/skills/xcode-build-orchestrator/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-build-orchestrator/references/orchestration-report-template.md +143 -0
- package/skills/xcode-build-orchestrator/references/recommendation-format.md +85 -0
- package/skills/xcode-build-orchestrator/scripts/benchmark_builds.py +308 -0
- package/skills/xcode-build-orchestrator/scripts/diagnose_compilation.py +273 -0
- package/skills/xcode-build-orchestrator/scripts/generate_optimization_report.py +533 -0
- package/skills/xcode-compilation-analyzer/SKILL.md +89 -0
- package/skills/xcode-compilation-analyzer/references/build-optimization-sources.md +155 -0
- package/skills/xcode-compilation-analyzer/references/code-compilation-checks.md +106 -0
- package/skills/xcode-compilation-analyzer/references/recommendation-format.md +85 -0
- package/skills/xcode-compilation-analyzer/scripts/diagnose_compilation.py +273 -0
- package/skills/xcode-project-analyzer/SKILL.md +76 -0
- package/skills/xcode-project-analyzer/references/build-optimization-sources.md +155 -0
- package/skills/xcode-project-analyzer/references/build-settings-best-practices.md +216 -0
- package/skills/xcode-project-analyzer/references/project-audit-checks.md +101 -0
- package/skills/xcode-project-analyzer/references/recommendation-format.md +85 -0
- package/templates/CODEBASE.md +26 -42
- package/templates/configs/trello-config.json +2 -2
- package/templates/workflow_dual_mode_template.md +5 -5
- package/workflows/_uncategorized/conductor-codex.md +125 -0
- package/workflows/_uncategorized/conductor.md +97 -0
- package/workflows/_uncategorized/ship-to-code.md +85 -0
- package/workflows/_uncategorized/trello-sync.md +52 -0
- package/workflows/context/codebase-sync.md +10 -87
- package/workflows/quality/visual-debug.md +66 -12
package/bin/awk.js
CHANGED
|
@@ -36,6 +36,7 @@ const HOME = process.env.HOME || process.env.USERPROFILE;
|
|
|
36
36
|
|
|
37
37
|
const { generateClineRules, generateClineWorkflows, generateClineSkills } = require('./cline-generators');
|
|
38
38
|
const { generateCodexAgentsMd, generateCodexSkills, generateCodexAgents } = require('./codex-generators');
|
|
39
|
+
const { generateClaudeRules, generateClaudeSkills } = require('./claude-generators');
|
|
39
40
|
|
|
40
41
|
// ─── Platform Definitions ──────────────────────────────────────────────────
|
|
41
42
|
|
|
@@ -73,6 +74,15 @@ const PLATFORMS = {
|
|
|
73
74
|
agents: 'agents',
|
|
74
75
|
skills: '../.agents/skills',
|
|
75
76
|
},
|
|
77
|
+
},
|
|
78
|
+
claude: {
|
|
79
|
+
name: 'Claude Code',
|
|
80
|
+
globalRoot: process.cwd(), // Local to project
|
|
81
|
+
rulesFile: 'CLAUDE.md',
|
|
82
|
+
versionFile: '.claude/awk_version',
|
|
83
|
+
dirs: {
|
|
84
|
+
skills: '.claude/skills',
|
|
85
|
+
},
|
|
76
86
|
}
|
|
77
87
|
};
|
|
78
88
|
|
|
@@ -290,35 +300,90 @@ function checkSymphony({ silent = false } = {}) {
|
|
|
290
300
|
}
|
|
291
301
|
}
|
|
292
302
|
|
|
293
|
-
function cmdInstall(
|
|
303
|
+
function cmdInstall(args = []) {
|
|
294
304
|
log('');
|
|
295
305
|
log(`${C.cyan}${C.bold}╔══════════════════════════════════════════════════════════╗${C.reset}`);
|
|
296
306
|
log(`${C.cyan}${C.bold}║ 🚀 AWK v${AWK_VERSION} — Antigravity Workflow Kit ║${C.reset}`);
|
|
297
307
|
log(`${C.cyan}${C.bold}╚══════════════════════════════════════════════════════════╝${C.reset}`);
|
|
298
308
|
log('');
|
|
299
309
|
|
|
300
|
-
|
|
301
|
-
let
|
|
310
|
+
const isUpdate = args.includes('--update');
|
|
311
|
+
let selectedPlatforms = [];
|
|
302
312
|
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
|
|
313
|
+
if (args.includes('--all') || args.includes('-a') || args.includes('all')) {
|
|
314
|
+
selectedPlatforms = Object.keys(PLATFORMS);
|
|
315
|
+
} else {
|
|
316
|
+
if (args.includes('--gemini') || args.includes('-g') || args.includes('antigravity')) selectedPlatforms.push('antigravity');
|
|
317
|
+
if (args.includes('--cline') || args.includes('cline')) selectedPlatforms.push('cline');
|
|
318
|
+
if (args.includes('--codex') || args.includes('-x')) selectedPlatforms.push('codex');
|
|
319
|
+
if (args.includes('--claude-code') || args.includes('--claude') || args.includes('-c') || args.includes('claude')) selectedPlatforms.push('claude');
|
|
320
|
+
|
|
321
|
+
const pIdx = args.indexOf('--platform');
|
|
322
|
+
let legacyArg = null;
|
|
323
|
+
if (pIdx !== -1 && args[pIdx + 1]) {
|
|
324
|
+
legacyArg = args[pIdx + 1];
|
|
325
|
+
} else if (args.length > 0 && !args[0].startsWith('-') && args[0] !== 'all' && args[0] !== '--update') {
|
|
326
|
+
legacyArg = args[0];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (legacyArg && PLATFORMS[legacyArg] && !selectedPlatforms.includes(legacyArg)) {
|
|
330
|
+
selectedPlatforms.push(legacyArg);
|
|
331
|
+
}
|
|
306
332
|
}
|
|
307
333
|
|
|
308
|
-
|
|
309
|
-
|
|
334
|
+
if (selectedPlatforms.length === 0) {
|
|
335
|
+
if (isUpdate) {
|
|
336
|
+
selectedPlatforms = [getActivePlatform()];
|
|
337
|
+
} else {
|
|
338
|
+
log(`${C.cyan}Select platforms to install (e.g., type "1,2", "all", or "1,2,3,4"):${C.reset}`);
|
|
339
|
+
log(` 1. Gemini Code Assist (antigravity)`);
|
|
340
|
+
log(` 2. Cline (VS Code)`);
|
|
341
|
+
log(` 3. Codex CLI (codex)`);
|
|
342
|
+
log(` 4. Claude Code (.claude/)`);
|
|
343
|
+
log(` 5. All of the above`);
|
|
344
|
+
const choice = promptChoice('Choice', '5').trim().toLowerCase();
|
|
345
|
+
|
|
346
|
+
if (choice === '5' || choice === 'all' || choice === '') {
|
|
347
|
+
selectedPlatforms = Object.keys(PLATFORMS);
|
|
348
|
+
} else {
|
|
349
|
+
if (choice.includes('1')) selectedPlatforms.push('antigravity');
|
|
350
|
+
if (choice.includes('2')) selectedPlatforms.push('cline');
|
|
351
|
+
if (choice.includes('3')) selectedPlatforms.push('codex');
|
|
352
|
+
if (choice.includes('4')) selectedPlatforms.push('claude');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
310
356
|
|
|
311
|
-
|
|
312
|
-
|
|
357
|
+
if (selectedPlatforms.length === 0) {
|
|
358
|
+
selectedPlatforms = [getActivePlatform()];
|
|
359
|
+
}
|
|
313
360
|
|
|
314
|
-
|
|
315
|
-
|
|
361
|
+
log(`${C.cyan}Installing to: ${selectedPlatforms.map(p => PLATFORMS[p].name).join(', ')}${C.reset}`);
|
|
362
|
+
|
|
363
|
+
// Main installation loop
|
|
364
|
+
for (const platform of selectedPlatforms) {
|
|
365
|
+
if (!PLATFORMS[platform]) {
|
|
366
|
+
err(`Unknown platform: ${platform}.`);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
activePlatform = platform;
|
|
371
|
+
if (platform === selectedPlatforms[0]) {
|
|
372
|
+
savePlatform(platform); // Store primary platform
|
|
373
|
+
}
|
|
316
374
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
checkSymphony();
|
|
375
|
+
const plat = PLATFORMS[platform];
|
|
376
|
+
const target = plat.globalRoot;
|
|
320
377
|
|
|
321
|
-
|
|
378
|
+
log('');
|
|
379
|
+
info(`Installing for ${C.bold}${plat.name}${C.reset}...`);
|
|
380
|
+
log('');
|
|
381
|
+
|
|
382
|
+
// 0. Check Symphony dependency
|
|
383
|
+
info('Checking dependencies...');
|
|
384
|
+
checkSymphony({ silent: platform !== selectedPlatforms[0] });
|
|
385
|
+
|
|
386
|
+
// 1. Ensure target dirs exist
|
|
322
387
|
info('Creating directories...');
|
|
323
388
|
const dirKeys = Object.values(plat.dirs);
|
|
324
389
|
for (const dir of dirKeys) {
|
|
@@ -339,6 +404,11 @@ function cmdInstall(platformArg) {
|
|
|
339
404
|
} else if (platform === 'codex') {
|
|
340
405
|
info('Generating Codex AGENTS.md...');
|
|
341
406
|
generateCodexAgentsMd(path.join(AWK_ROOT, 'core', 'GEMINI.md'), plat.rulesFile);
|
|
407
|
+
} else if (platform === 'claude') {
|
|
408
|
+
info('Generating Claude Code CLAUDE.md...');
|
|
409
|
+
const claudeTemplateSrc = path.join(AWK_ROOT, 'core', 'CLAUDE.md');
|
|
410
|
+
const claudeRulesDest = path.join(target, plat.rulesFile);
|
|
411
|
+
generateClaudeRules(claudeTemplateSrc, claudeRulesDest);
|
|
342
412
|
}
|
|
343
413
|
|
|
344
414
|
// 3. Backup and install workflows
|
|
@@ -392,6 +462,8 @@ function cmdInstall(platformArg) {
|
|
|
392
462
|
generateCodexSkills(skillsSrc, skillsDest);
|
|
393
463
|
const agentsDest = path.join(target, plat.dirs.agents);
|
|
394
464
|
generateCodexAgents(skillsSrc, agentsDest);
|
|
465
|
+
} else if (platform === 'claude') {
|
|
466
|
+
generateClaudeSkills(skillsSrc, skillsDest);
|
|
395
467
|
} else {
|
|
396
468
|
const skillCount = copyDirRecursive(skillsSrc, skillsDest);
|
|
397
469
|
ok(`${skillCount} skill files installed`);
|
|
@@ -462,6 +534,7 @@ function cmdInstall(platformArg) {
|
|
|
462
534
|
}
|
|
463
535
|
log(`${C.cyan}👉 Run 'awkit doctor' to verify installation.${C.reset}`);
|
|
464
536
|
log('');
|
|
537
|
+
} // End of platform loop
|
|
465
538
|
}
|
|
466
539
|
|
|
467
540
|
/**
|
|
@@ -570,7 +643,7 @@ function cmdUpdate() {
|
|
|
570
643
|
}
|
|
571
644
|
log('');
|
|
572
645
|
info('Applying new workflows, skills & schemas...');
|
|
573
|
-
cmdInstall();
|
|
646
|
+
cmdInstall(['--update']);
|
|
574
647
|
return;
|
|
575
648
|
}
|
|
576
649
|
|
|
@@ -579,7 +652,7 @@ function cmdUpdate() {
|
|
|
579
652
|
ok(`Already on latest version (v${AWK_VERSION}) — could not verify with npm`);
|
|
580
653
|
} else {
|
|
581
654
|
info(`Upgrading from v${installedVersion} → v${AWK_VERSION} (local only, npm unreachable)`);
|
|
582
|
-
cmdInstall();
|
|
655
|
+
cmdInstall(['--update']);
|
|
583
656
|
}
|
|
584
657
|
}
|
|
585
658
|
|
|
@@ -663,6 +736,77 @@ function cmdDoctor() {
|
|
|
663
736
|
log('');
|
|
664
737
|
}
|
|
665
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Handle browser-related tasks (e.g., cleaning up recordings).
|
|
741
|
+
*/
|
|
742
|
+
function cmdBrowser(args) {
|
|
743
|
+
if (args[0] !== 'clean') {
|
|
744
|
+
err('Unknown browser command. Use "awkit browser clean".');
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const recordingsDir = path.join(TARGETS.antigravity, 'browser_recordings');
|
|
749
|
+
|
|
750
|
+
log('');
|
|
751
|
+
log(`${C.cyan}${C.bold}🧹 AWK Browser Cleanup${C.reset}`);
|
|
752
|
+
log('');
|
|
753
|
+
|
|
754
|
+
if (!fs.existsSync(recordingsDir)) {
|
|
755
|
+
ok(`No browser_recordings directory found at ${recordingsDir}. Nothing to clean.`);
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
const files = fs.readdirSync(recordingsDir).filter(f => f.endsWith('.webm') || f.endsWith('.webp') || f.endsWith('.mp4'));
|
|
760
|
+
if (files.length === 0) {
|
|
761
|
+
ok('No browser recordings found. Nothing to clean.');
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
let keepDays = 7; // default 7 days
|
|
766
|
+
const daysArgIdx = args.indexOf('--days');
|
|
767
|
+
if (daysArgIdx !== -1 && args[daysArgIdx + 1]) {
|
|
768
|
+
keepDays = parseInt(args[daysArgIdx + 1], 10);
|
|
769
|
+
} else if (args.includes('--all')) {
|
|
770
|
+
keepDays = 0;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (keepDays === 0) {
|
|
774
|
+
log(`Cleaning ${C.yellow}ALL${C.reset} browser recordings...`);
|
|
775
|
+
} else {
|
|
776
|
+
log(`Cleaning browser recordings older than ${C.yellow}${keepDays} days${C.reset}...`);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const now = Date.now();
|
|
780
|
+
const cutoff = now - (keepDays * 24 * 60 * 60 * 1000);
|
|
781
|
+
let deletedCount = 0;
|
|
782
|
+
let totalSizeFreed = 0;
|
|
783
|
+
|
|
784
|
+
for (const file of files) {
|
|
785
|
+
const filePath = path.join(recordingsDir, file);
|
|
786
|
+
try {
|
|
787
|
+
const stats = fs.statSync(filePath);
|
|
788
|
+
if (stats.mtimeMs < cutoff) {
|
|
789
|
+
totalSizeFreed += stats.size;
|
|
790
|
+
fs.unlinkSync(filePath);
|
|
791
|
+
deletedCount++;
|
|
792
|
+
dim(`Deleted: ${file}`);
|
|
793
|
+
}
|
|
794
|
+
} catch (e) {
|
|
795
|
+
warn(`Failed to process ${file}: ${e.message}`);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
log('');
|
|
800
|
+
const sizeMb = (totalSizeFreed / (1024 * 1024)).toFixed(2);
|
|
801
|
+
if (deletedCount > 0) {
|
|
802
|
+
ok(`Cleaned ${C.green}${C.bold}${deletedCount}${C.reset} recording(s).`);
|
|
803
|
+
ok(`Freed ${C.green}${C.bold}${sizeMb} MB${C.reset} of disk space.`);
|
|
804
|
+
} else {
|
|
805
|
+
ok(`No recordings older than ${keepDays} days found. Disk space is already optimized.`);
|
|
806
|
+
}
|
|
807
|
+
log('');
|
|
808
|
+
}
|
|
809
|
+
|
|
666
810
|
/**
|
|
667
811
|
* Find a compatible Python interpreter meeting the minimum version requirement.
|
|
668
812
|
* Tries python3.13, python3.12, python3.11, python3, python in order.
|
|
@@ -1327,6 +1471,95 @@ function cmdSync() {
|
|
|
1327
1471
|
log('');
|
|
1328
1472
|
}
|
|
1329
1473
|
|
|
1474
|
+
async function cmdAdmin() {
|
|
1475
|
+
info('Mở Symphony Dashboard...');
|
|
1476
|
+
try {
|
|
1477
|
+
const http = require('http');
|
|
1478
|
+
const isRunning = await new Promise((resolve) => {
|
|
1479
|
+
const req = http.get('http://localhost:3100', (res) => {
|
|
1480
|
+
resolve(true);
|
|
1481
|
+
}).on('error', () => {
|
|
1482
|
+
resolve(false);
|
|
1483
|
+
});
|
|
1484
|
+
req.setTimeout(1000, () => {
|
|
1485
|
+
req.destroy();
|
|
1486
|
+
resolve(false);
|
|
1487
|
+
});
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
if (!isRunning) {
|
|
1491
|
+
info('Symphony service chưa chạy. Đang khởi động ngầm...');
|
|
1492
|
+
const { spawn } = require('child_process');
|
|
1493
|
+
const child = spawn('symphony', ['start'], {
|
|
1494
|
+
detached: true,
|
|
1495
|
+
stdio: 'ignore'
|
|
1496
|
+
});
|
|
1497
|
+
child.unref();
|
|
1498
|
+
|
|
1499
|
+
info('Vui lòng đợi 3 giây để service khởi động...');
|
|
1500
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
try {
|
|
1504
|
+
execSync('symphony dashboard', { stdio: 'inherit' });
|
|
1505
|
+
} catch (_) {
|
|
1506
|
+
err('Không thể mở Symphony Dashboard.');
|
|
1507
|
+
}
|
|
1508
|
+
} catch (e) {
|
|
1509
|
+
err('Không thể khởi động Symphony Dashboard.');
|
|
1510
|
+
dim('Vui lòng cài đặt: npm install -g @leejungkiin/awkit-symphony');
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
async function cmdRestart() {
|
|
1515
|
+
info('Đang restart service awkit (Symphony)...');
|
|
1516
|
+
try {
|
|
1517
|
+
const { execSync, spawn } = require('child_process');
|
|
1518
|
+
try {
|
|
1519
|
+
// Find and kill process on port 3100
|
|
1520
|
+
const pids = execSync('lsof -t -i:3100').toString().trim().split('\n');
|
|
1521
|
+
for (const pid of pids) {
|
|
1522
|
+
if (pid) {
|
|
1523
|
+
process.kill(parseInt(pid, 10), 'SIGTERM');
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
info('Đã dừng service hiện tại.');
|
|
1527
|
+
} catch (e) {
|
|
1528
|
+
// Probably no process running on port 3100
|
|
1529
|
+
dim('Không tìm thấy service đang chạy.');
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
1533
|
+
|
|
1534
|
+
// Auto-build production bundle so code changes take effect
|
|
1535
|
+
const symphonyDir = path.join(AWK_ROOT, '..', 'symphony');
|
|
1536
|
+
if (fs.existsSync(path.join(symphonyDir, 'package.json'))) {
|
|
1537
|
+
info('Đang build production bundle...');
|
|
1538
|
+
try {
|
|
1539
|
+
execSync('npm run build', { cwd: symphonyDir, stdio: 'pipe' });
|
|
1540
|
+
log(`${C.green}✅ Build thành công!${C.reset}`);
|
|
1541
|
+
} catch (buildErr) {
|
|
1542
|
+
warn('Build thất bại, sử dụng bundle cũ.');
|
|
1543
|
+
dim(buildErr.message?.slice(0, 200));
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
info('Đang khởi động lại service ngầm...');
|
|
1548
|
+
const child = spawn('symphony', ['start'], {
|
|
1549
|
+
detached: true,
|
|
1550
|
+
stdio: 'ignore'
|
|
1551
|
+
});
|
|
1552
|
+
child.unref();
|
|
1553
|
+
|
|
1554
|
+
info('Vui lòng đợi 3 giây để service khởi động...');
|
|
1555
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
1556
|
+
|
|
1557
|
+
log(`${C.green}✅ Restart thành công!${C.reset}`);
|
|
1558
|
+
} catch (e) {
|
|
1559
|
+
err('Lỗi khi restart service: ' + e.message);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1330
1563
|
function cmdHelp() {
|
|
1331
1564
|
const line = `${C.gray}${'─'.repeat(56)}${C.reset}`;
|
|
1332
1565
|
log('');
|
|
@@ -1354,6 +1587,15 @@ function cmdHelp() {
|
|
|
1354
1587
|
log(` ${C.gray} CODEBASE.md, .symphony/ (Symphony task DB)${C.reset}`);
|
|
1355
1588
|
log('');
|
|
1356
1589
|
|
|
1590
|
+
// Maintenance
|
|
1591
|
+
log(`${C.bold}🧹 Maintenance${C.reset}`);
|
|
1592
|
+
log(line);
|
|
1593
|
+
log(` ${C.green}serve${C.reset} [dir] [-p <port>] Start local HTTP server for assets in CWD`);
|
|
1594
|
+
log(` ${C.green}browser clean${C.reset} Clean browser recordings`);
|
|
1595
|
+
log(` ${C.gray} --days <N>${C.reset} Keep recordings from last N days (default: 7)`);
|
|
1596
|
+
log(` ${C.gray} --all${C.reset} Delete all recordings`);
|
|
1597
|
+
log('');
|
|
1598
|
+
|
|
1357
1599
|
// Sync
|
|
1358
1600
|
log(`${C.bold}🔄 Sync${C.reset}`);
|
|
1359
1601
|
log(line);
|
|
@@ -1362,6 +1604,12 @@ function cmdHelp() {
|
|
|
1362
1604
|
log(` ${C.green}sync${C.reset} Full sync: harvest + install (one shot)`);
|
|
1363
1605
|
log('');
|
|
1364
1606
|
|
|
1607
|
+
// Symphony
|
|
1608
|
+
log(`${C.bold}🎶 Symphony${C.reset}`);
|
|
1609
|
+
log(line);
|
|
1610
|
+
log(` ${C.green}admin${C.reset} Khởi động Symphony Dashboard`);
|
|
1611
|
+
log('');
|
|
1612
|
+
|
|
1365
1613
|
// Packs
|
|
1366
1614
|
log(`${C.bold}📦 Skill Packs${C.reset}`);
|
|
1367
1615
|
log(line);
|
|
@@ -1604,7 +1852,12 @@ function buildProjectIdentity(projectName, projectType, cwd, date) {
|
|
|
1604
1852
|
};
|
|
1605
1853
|
|
|
1606
1854
|
return {
|
|
1855
|
+
_comments: {
|
|
1856
|
+
projectId: 'Auto-generated. DO NOT change — used by Symphony for task scoping.',
|
|
1857
|
+
trello: 'Fill in your Trello board/list/card names. Run "awkit trello info" to verify.',
|
|
1858
|
+
},
|
|
1607
1859
|
projectName,
|
|
1860
|
+
projectId: bundleBase,
|
|
1608
1861
|
projectType: cfg.projectType,
|
|
1609
1862
|
...(cfg.bundleIdentifier && { bundleIdentifier: cfg.bundleIdentifier }),
|
|
1610
1863
|
...(cfg.packageName && { packageName: cfg.packageName }),
|
|
@@ -1616,6 +1869,11 @@ function buildProjectIdentity(projectName, projectType, cwd, date) {
|
|
|
1616
1869
|
features: ['analytics', 'crashlytics', 'remote-config', 'auth'],
|
|
1617
1870
|
},
|
|
1618
1871
|
},
|
|
1872
|
+
trello: {
|
|
1873
|
+
board: 'Your Board Name',
|
|
1874
|
+
list: 'Your List Name',
|
|
1875
|
+
card: 'Your Card Name',
|
|
1876
|
+
},
|
|
1619
1877
|
projectStage: 'development',
|
|
1620
1878
|
codingStandards: cfg.codingStandards,
|
|
1621
1879
|
projectGoals: [],
|
|
@@ -1784,25 +2042,38 @@ async function cmdInit(forceFlag = false) {
|
|
|
1784
2042
|
ok(`${workspaceName} created`);
|
|
1785
2043
|
}
|
|
1786
2044
|
|
|
1787
|
-
// ── 3.5. .
|
|
2045
|
+
// ── 3.5. Trello config (embedded in .project-identity) ──────────────────────
|
|
2046
|
+
// Migration: If .trello-config.json exists but identity has no trello key, merge it in
|
|
1788
2047
|
const trelloConfigPath = path.join(cwd, '.trello-config.json');
|
|
1789
|
-
if (fs.existsSync(trelloConfigPath)
|
|
1790
|
-
|
|
2048
|
+
if (fs.existsSync(trelloConfigPath)) {
|
|
2049
|
+
try {
|
|
2050
|
+
const oldCfg = JSON.parse(fs.readFileSync(trelloConfigPath, 'utf8'));
|
|
2051
|
+
const currentIdentity = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
2052
|
+
if (!currentIdentity.trello) {
|
|
2053
|
+
currentIdentity.trello = {
|
|
2054
|
+
board: oldCfg.BOARD_NAME || oldCfg.board || 'Your Board Name',
|
|
2055
|
+
list: oldCfg.LIST_NAME || oldCfg.list || 'Your List',
|
|
2056
|
+
card: oldCfg.CARD_NAME || oldCfg.card || 'Your Card',
|
|
2057
|
+
};
|
|
2058
|
+
fs.writeFileSync(identityPath, JSON.stringify(currentIdentity, null, 2) + '\n');
|
|
2059
|
+
ok('Migrated Trello config from .trello-config.json → .project-identity');
|
|
2060
|
+
dim('You can safely delete .trello-config.json now.');
|
|
2061
|
+
}
|
|
2062
|
+
} catch (_) { /* ignore migration errors */ }
|
|
1791
2063
|
} else {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
}
|
|
2064
|
+
// Ensure identity has trello placeholder if not already present
|
|
2065
|
+
try {
|
|
2066
|
+
const currentIdentity = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
2067
|
+
if (!currentIdentity.trello) {
|
|
2068
|
+
currentIdentity.trello = {
|
|
2069
|
+
board: 'Your Board Name',
|
|
2070
|
+
list: 'Your List',
|
|
2071
|
+
card: 'Your Card',
|
|
2072
|
+
};
|
|
2073
|
+
fs.writeFileSync(identityPath, JSON.stringify(currentIdentity, null, 2) + '\n');
|
|
2074
|
+
ok('Added Trello config placeholder to .project-identity');
|
|
2075
|
+
}
|
|
2076
|
+
} catch (_) { /* ignore */ }
|
|
1806
2077
|
}
|
|
1807
2078
|
|
|
1808
2079
|
const trelloCred = trelloLoadCredentials();
|
|
@@ -1894,7 +2165,7 @@ async function cmdInit(forceFlag = false) {
|
|
|
1894
2165
|
log('');
|
|
1895
2166
|
dim(`Type: ${projectType}`);
|
|
1896
2167
|
dim(`Firebase: analytics, crashlytics, remote-config, auth`);
|
|
1897
|
-
dim(`Files: .project-identity, ${workspaceName}, CODEBASE.md
|
|
2168
|
+
dim(`Files: .project-identity, ${workspaceName}, CODEBASE.md`);
|
|
1898
2169
|
dim(`Symphony: task tracking ready)`);
|
|
1899
2170
|
log('');
|
|
1900
2171
|
log(`${C.cyan}👉 Open ${workspaceName} in VS Code to get started.${C.reset}`);
|
|
@@ -2097,6 +2368,178 @@ function cmdTelegram(args) {
|
|
|
2097
2368
|
}
|
|
2098
2369
|
}
|
|
2099
2370
|
|
|
2371
|
+
// ─── Credentials Management ───────────────────────────────────────────────────
|
|
2372
|
+
|
|
2373
|
+
const CREDENTIALS_CONFIG_PATH = path.join(TARGETS.antigravity, '.credentials.json');
|
|
2374
|
+
|
|
2375
|
+
function credentialsLoad() {
|
|
2376
|
+
if (!fs.existsSync(CREDENTIALS_CONFIG_PATH)) return {};
|
|
2377
|
+
try {
|
|
2378
|
+
return JSON.parse(fs.readFileSync(CREDENTIALS_CONFIG_PATH, 'utf8'));
|
|
2379
|
+
} catch (_) {
|
|
2380
|
+
return {};
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
function credentialsSave(config) {
|
|
2385
|
+
const dir = path.dirname(CREDENTIALS_CONFIG_PATH);
|
|
2386
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
2387
|
+
fs.writeFileSync(CREDENTIALS_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n');
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
function credentialsHelp() {
|
|
2391
|
+
log('');
|
|
2392
|
+
log(`${C.cyan}${C.bold}🔑 Credentials Commands${C.reset}`);
|
|
2393
|
+
log('');
|
|
2394
|
+
log(` ${C.green}awkit credentials list${C.reset} List all stored credentials`);
|
|
2395
|
+
log(` ${C.green}awkit credentials set${C.reset} <key> <value> Set a credential`);
|
|
2396
|
+
log(` ${C.green}awkit credentials get${C.reset} <key> Get a credential value`);
|
|
2397
|
+
log(` ${C.green}awkit credentials remove${C.reset} <key> Remove a credential`);
|
|
2398
|
+
log(` ${C.green}awkit credentials setup${C.reset} Interactive setup wizard`);
|
|
2399
|
+
log('');
|
|
2400
|
+
log(` ${C.gray}Known keys: gemini_api_key, lucylab_bearer${C.reset}`);
|
|
2401
|
+
log(` ${C.gray}Config: ${CREDENTIALS_CONFIG_PATH}${C.reset}`);
|
|
2402
|
+
log('');
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
async function credentialsSetup() {
|
|
2406
|
+
log('');
|
|
2407
|
+
log(`${C.cyan}${C.bold}🔑 API Credentials Setup${C.reset}`);
|
|
2408
|
+
log('');
|
|
2409
|
+
log(`${C.gray} Credentials are stored in: ${CREDENTIALS_CONFIG_PATH}${C.reset}`);
|
|
2410
|
+
log(`${C.gray} Used by Short Maker, Symphony Admin, and other services.${C.reset}`);
|
|
2411
|
+
log('');
|
|
2412
|
+
|
|
2413
|
+
const readline = require('readline');
|
|
2414
|
+
const rl = readline.createInterface({
|
|
2415
|
+
input: process.stdin,
|
|
2416
|
+
output: process.stdout
|
|
2417
|
+
});
|
|
2418
|
+
|
|
2419
|
+
const question = (query) => new Promise(resolve => rl.question(query, resolve));
|
|
2420
|
+
const sanitize = (s) => s.trim().replace(/^bearer\s+/i, '').replace(/\s+/g, '');
|
|
2421
|
+
|
|
2422
|
+
const config = credentialsLoad();
|
|
2423
|
+
|
|
2424
|
+
try {
|
|
2425
|
+
// Gemini API Key
|
|
2426
|
+
log(`${C.gray} Get your key at: https://aistudio.google.com/apikey${C.reset}`);
|
|
2427
|
+
const geminiKey = sanitize(await question(` ${C.yellow}Gemini API Key${config.gemini_api_key ? ` [${config.gemini_api_key.slice(0, 8)}...]` : ''}: ${C.reset}`));
|
|
2428
|
+
if (geminiKey) {
|
|
2429
|
+
config.gemini_api_key = geminiKey;
|
|
2430
|
+
ok('Gemini API Key saved');
|
|
2431
|
+
} else if (config.gemini_api_key) {
|
|
2432
|
+
dim('Kept existing Gemini API Key');
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
log('');
|
|
2436
|
+
|
|
2437
|
+
// LucyLab Bearer
|
|
2438
|
+
log(`${C.gray} LucyLab TTS bearer token for voice generation${C.reset}`);
|
|
2439
|
+
const lucylabToken = sanitize(await question(` ${C.yellow}LucyLab Bearer${config.lucylab_bearer ? ` [${config.lucylab_bearer.slice(0, 8)}...]` : ''}: ${C.reset}`));
|
|
2440
|
+
if (lucylabToken) {
|
|
2441
|
+
config.lucylab_bearer = lucylabToken;
|
|
2442
|
+
ok('LucyLab Bearer saved');
|
|
2443
|
+
} else if (config.lucylab_bearer) {
|
|
2444
|
+
dim('Kept existing LucyLab Bearer');
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
credentialsSave(config);
|
|
2448
|
+
log('');
|
|
2449
|
+
ok(`Credentials saved to ${CREDENTIALS_CONFIG_PATH}`);
|
|
2450
|
+
log('');
|
|
2451
|
+
} catch (e) {
|
|
2452
|
+
warn(`Failed to setup credentials: ${e.message}`);
|
|
2453
|
+
} finally {
|
|
2454
|
+
rl.close();
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
function cmdCredentials(args) {
|
|
2459
|
+
const subCmd = args[0];
|
|
2460
|
+
const key = args[1];
|
|
2461
|
+
const value = args.slice(2).join(' ');
|
|
2462
|
+
|
|
2463
|
+
switch (subCmd) {
|
|
2464
|
+
case 'list': {
|
|
2465
|
+
const config = credentialsLoad();
|
|
2466
|
+
const keys = Object.keys(config);
|
|
2467
|
+
if (keys.length === 0) {
|
|
2468
|
+
warn('No credentials stored. Run "awkit credentials setup" to configure.');
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
log('');
|
|
2472
|
+
log(`${C.cyan}${C.bold}🔑 Stored Credentials${C.reset}`);
|
|
2473
|
+
log('');
|
|
2474
|
+
for (const k of keys) {
|
|
2475
|
+
const val = config[k];
|
|
2476
|
+
const masked = val ? `${val.slice(0, 8)}${'•'.repeat(Math.max(0, val.length - 8))}` : '(empty)';
|
|
2477
|
+
log(` ${C.green}${k}${C.reset} = ${C.gray}${masked}${C.reset}`);
|
|
2478
|
+
}
|
|
2479
|
+
log('');
|
|
2480
|
+
dim(`Config: ${CREDENTIALS_CONFIG_PATH}`);
|
|
2481
|
+
log('');
|
|
2482
|
+
break;
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
case 'set': {
|
|
2486
|
+
let valueToSet = value;
|
|
2487
|
+
if (valueToSet) {
|
|
2488
|
+
valueToSet = valueToSet.trim().replace(/^bearer\s+/i, '').replace(/\s+/g, '');
|
|
2489
|
+
}
|
|
2490
|
+
if (!key || !valueToSet) {
|
|
2491
|
+
err('Usage: awkit credentials set <key> <value>');
|
|
2492
|
+
dim('Example: awkit credentials set gemini_api_key AIzaSy...');
|
|
2493
|
+
return;
|
|
2494
|
+
}
|
|
2495
|
+
const config = credentialsLoad();
|
|
2496
|
+
config[key] = valueToSet;
|
|
2497
|
+
credentialsSave(config);
|
|
2498
|
+
ok(`${key} saved ✅`);
|
|
2499
|
+
break;
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
case 'get': {
|
|
2503
|
+
if (!key) {
|
|
2504
|
+
err('Usage: awkit credentials get <key>');
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
const config = credentialsLoad();
|
|
2508
|
+
if (config[key]) {
|
|
2509
|
+
log(config[key]);
|
|
2510
|
+
} else {
|
|
2511
|
+
warn(`Key "${key}" not found.`);
|
|
2512
|
+
}
|
|
2513
|
+
break;
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
case 'remove':
|
|
2517
|
+
case 'delete': {
|
|
2518
|
+
if (!key) {
|
|
2519
|
+
err('Usage: awkit credentials remove <key>');
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
const config = credentialsLoad();
|
|
2523
|
+
if (config[key]) {
|
|
2524
|
+
delete config[key];
|
|
2525
|
+
credentialsSave(config);
|
|
2526
|
+
ok(`${key} removed`);
|
|
2527
|
+
} else {
|
|
2528
|
+
warn(`Key "${key}" not found.`);
|
|
2529
|
+
}
|
|
2530
|
+
break;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
case 'setup':
|
|
2534
|
+
credentialsSetup();
|
|
2535
|
+
break;
|
|
2536
|
+
|
|
2537
|
+
default:
|
|
2538
|
+
credentialsHelp();
|
|
2539
|
+
break;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2100
2543
|
// ─── Trello Integration ───────────────────────────────────────────────────────
|
|
2101
2544
|
|
|
2102
2545
|
/**
|
|
@@ -2111,10 +2554,28 @@ function trelloLoadCredentials() {
|
|
|
2111
2554
|
}
|
|
2112
2555
|
|
|
2113
2556
|
/**
|
|
2114
|
-
* Load Trello project config from .trello-config.json
|
|
2557
|
+
* Load Trello project config from .project-identity (preferred) or .trello-config.json (fallback).
|
|
2115
2558
|
* Returns { board, list, card } or null.
|
|
2116
2559
|
*/
|
|
2117
2560
|
function trelloLoadProjectConfig() {
|
|
2561
|
+
// 1. Try .project-identity → trello key
|
|
2562
|
+
const identityPath = path.join(process.cwd(), '.project-identity');
|
|
2563
|
+
if (fs.existsSync(identityPath)) {
|
|
2564
|
+
try {
|
|
2565
|
+
const identity = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
2566
|
+
if (identity.trello) {
|
|
2567
|
+
const t = identity.trello;
|
|
2568
|
+
const board = t.board || t.BOARD_NAME;
|
|
2569
|
+
const list = t.list || t.LIST_NAME;
|
|
2570
|
+
const card = t.card || t.CARD_NAME;
|
|
2571
|
+
if (board && list && card) {
|
|
2572
|
+
return { board, list, card };
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
} catch (_) { /* ignore parse error */ }
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
// 2. Fallback: .trello-config.json
|
|
2118
2579
|
const configPath = path.join(process.cwd(), '.trello-config.json');
|
|
2119
2580
|
if (!fs.existsSync(configPath)) return null;
|
|
2120
2581
|
try {
|
|
@@ -2141,8 +2602,8 @@ function trelloExec(cliArgs, retries = 3) {
|
|
|
2141
2602
|
return false;
|
|
2142
2603
|
}
|
|
2143
2604
|
if (!cfg) {
|
|
2144
|
-
err('
|
|
2145
|
-
log(` Run ${C.cyan}awkit init${C.reset} to
|
|
2605
|
+
err('Trello config not found. Add "trello" key to .project-identity or create .trello-config.json.');
|
|
2606
|
+
log(` Run ${C.cyan}awkit init${C.reset} to set up, or add manually to .project-identity.`);
|
|
2146
2607
|
return false;
|
|
2147
2608
|
}
|
|
2148
2609
|
|
|
@@ -2191,9 +2652,12 @@ function trelloHelp() {
|
|
|
2191
2652
|
log(` ${C.green}awkit trello complete${C.reset} <name> Mark checklist item ✅ complete`);
|
|
2192
2653
|
log(` ${C.green}awkit trello block${C.reset} <reason> Label card Blocked + comment`);
|
|
2193
2654
|
log(` ${C.green}awkit trello checklist${C.reset} <name> Create a new checklist on card`);
|
|
2655
|
+
log(` ${C.green}awkit trello info${C.reset} Show card details`);
|
|
2656
|
+
log(` ${C.green}awkit trello checklists${C.reset} List checklists on card`);
|
|
2657
|
+
log(` ${C.green}awkit trello comments${C.reset} List comments on card`);
|
|
2194
2658
|
log('');
|
|
2195
2659
|
log(` ${C.gray}Credentials: env vars TRELLO_KEY and TRELLO_TOKEN${C.reset}`);
|
|
2196
|
-
log(` ${C.gray}Project config: .trello-config.json
|
|
2660
|
+
log(` ${C.gray}Project config: "trello" key in .project-identity (fallback: .trello-config.json)${C.reset}`);
|
|
2197
2661
|
log('');
|
|
2198
2662
|
}
|
|
2199
2663
|
|
|
@@ -2206,12 +2670,28 @@ function cmdTrello(args) {
|
|
|
2206
2670
|
return;
|
|
2207
2671
|
}
|
|
2208
2672
|
|
|
2209
|
-
|
|
2673
|
+
const noTextCmds = ['info', 'checklists', 'comments'];
|
|
2674
|
+
if (!text && !noTextCmds.includes(subCmd)) {
|
|
2210
2675
|
err(`Missing argument for 'trello ${subCmd}'. Usage: awkit trello ${subCmd} <text>`);
|
|
2211
2676
|
return;
|
|
2212
2677
|
}
|
|
2213
2678
|
|
|
2214
2679
|
switch (subCmd) {
|
|
2680
|
+
case 'info':
|
|
2681
|
+
info(`Fetching card details...`);
|
|
2682
|
+
trelloExec(['card:show']);
|
|
2683
|
+
break;
|
|
2684
|
+
|
|
2685
|
+
case 'checklists':
|
|
2686
|
+
info(`Fetching card checklists...`);
|
|
2687
|
+
trelloExec(['card:checklists']);
|
|
2688
|
+
break;
|
|
2689
|
+
|
|
2690
|
+
case 'comments':
|
|
2691
|
+
info(`Fetching card comments...`);
|
|
2692
|
+
trelloExec(['card:comments']);
|
|
2693
|
+
break;
|
|
2694
|
+
|
|
2215
2695
|
case 'desc':
|
|
2216
2696
|
info(`Updating card description...`);
|
|
2217
2697
|
trelloExec(['card:update', '--description', text]);
|
|
@@ -2331,6 +2811,98 @@ function checkAutoUpdate() {
|
|
|
2331
2811
|
}
|
|
2332
2812
|
}
|
|
2333
2813
|
|
|
2814
|
+
// ─── Native HTTP Server ───────────────────────────────────────────────────────
|
|
2815
|
+
|
|
2816
|
+
function cmdServe(args) {
|
|
2817
|
+
const http = require('http');
|
|
2818
|
+
|
|
2819
|
+
let port = 8080;
|
|
2820
|
+
let serveDir = process.cwd();
|
|
2821
|
+
|
|
2822
|
+
for (let i = 0; i < args.length; i++) {
|
|
2823
|
+
if (args[i] === '--port' || args[i] === '-p') {
|
|
2824
|
+
port = parseInt(args[++i], 10) || 8080;
|
|
2825
|
+
} else if (!args[i].startsWith('-')) {
|
|
2826
|
+
serveDir = path.resolve(process.cwd(), args[i]);
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
if (!fs.existsSync(serveDir)) {
|
|
2831
|
+
err(`Directory not found: ${serveDir}`);
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
const mimeTypes = {
|
|
2836
|
+
'.html': 'text/html',
|
|
2837
|
+
'.js': 'text/javascript',
|
|
2838
|
+
'.css': 'text/css',
|
|
2839
|
+
'.json': 'application/json',
|
|
2840
|
+
'.png': 'image/png',
|
|
2841
|
+
'.jpg': 'image/jpeg',
|
|
2842
|
+
'.jpeg': 'image/jpeg',
|
|
2843
|
+
'.gif': 'image/gif',
|
|
2844
|
+
'.svg': 'image/svg+xml',
|
|
2845
|
+
'.wav': 'audio/wav',
|
|
2846
|
+
'.mp4': 'video/mp4',
|
|
2847
|
+
'.woff': 'application/font-woff',
|
|
2848
|
+
'.ttf': 'application/font-ttf',
|
|
2849
|
+
'.eot': 'application/vnd.ms-fontobject',
|
|
2850
|
+
'.otf': 'application/font-otf',
|
|
2851
|
+
'.wasm': 'application/wasm'
|
|
2852
|
+
};
|
|
2853
|
+
|
|
2854
|
+
const server = http.createServer((request, response) => {
|
|
2855
|
+
response.setHeader('Access-Control-Allow-Origin', '*');
|
|
2856
|
+
response.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
|
2857
|
+
response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
2858
|
+
|
|
2859
|
+
if (request.method === 'OPTIONS') {
|
|
2860
|
+
response.writeHead(200);
|
|
2861
|
+
response.end();
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
let filePath = '.' + request.url.split('?')[0];
|
|
2866
|
+
if (filePath === './') {
|
|
2867
|
+
filePath = './index.html';
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
const absPath = path.join(serveDir, filePath);
|
|
2871
|
+
const extname = String(path.extname(absPath)).toLowerCase();
|
|
2872
|
+
const contentType = mimeTypes[extname] || 'application/octet-stream';
|
|
2873
|
+
|
|
2874
|
+
fs.readFile(absPath, (error, content) => {
|
|
2875
|
+
if (error) {
|
|
2876
|
+
if (error.code === 'ENOENT') {
|
|
2877
|
+
response.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
2878
|
+
response.end('404 Not Found', 'utf-8');
|
|
2879
|
+
} else {
|
|
2880
|
+
response.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
2881
|
+
response.end('500 Internal Server Error: ' + error.code, 'utf-8');
|
|
2882
|
+
}
|
|
2883
|
+
} else {
|
|
2884
|
+
response.writeHead(200, { 'Content-Type': contentType });
|
|
2885
|
+
response.end(content, 'utf-8');
|
|
2886
|
+
}
|
|
2887
|
+
});
|
|
2888
|
+
});
|
|
2889
|
+
|
|
2890
|
+
server.listen(port, '0.0.0.0', () => {
|
|
2891
|
+
log('');
|
|
2892
|
+
log(`${C.cyan}${C.bold}🚀 awkit serve running at:${C.reset}`);
|
|
2893
|
+
log(`${C.green} http://localhost:${port}${C.reset}`);
|
|
2894
|
+
dim(`Serving directory: ${serveDir}`);
|
|
2895
|
+
dim(`Press Ctrl+C to stop`);
|
|
2896
|
+
log('');
|
|
2897
|
+
}).on('error', (e) => {
|
|
2898
|
+
if (e.code === 'EADDRINUSE') {
|
|
2899
|
+
err(`Port ${port} is already in use. Try a different port with --port <number>`);
|
|
2900
|
+
} else {
|
|
2901
|
+
err(`Server error: ${e.message}`);
|
|
2902
|
+
}
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2334
2906
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
2335
2907
|
|
|
2336
2908
|
// Check for updates (max once per day) before continuing
|
|
@@ -2344,17 +2916,7 @@ const [, , command, ...args] = process.argv;
|
|
|
2344
2916
|
await cmdInit(args.includes('--force'));
|
|
2345
2917
|
break;
|
|
2346
2918
|
case 'install':
|
|
2347
|
-
|
|
2348
|
-
{
|
|
2349
|
-
const pIdx = args.indexOf('--platform');
|
|
2350
|
-
let platformArg = null;
|
|
2351
|
-
if (pIdx !== -1 && args[pIdx + 1]) {
|
|
2352
|
-
platformArg = args[pIdx + 1];
|
|
2353
|
-
} else if (args[0] && !args[0].startsWith('-')) {
|
|
2354
|
-
platformArg = args[0];
|
|
2355
|
-
}
|
|
2356
|
-
cmdInstall(platformArg);
|
|
2357
|
-
}
|
|
2919
|
+
cmdInstall(args);
|
|
2358
2920
|
break;
|
|
2359
2921
|
case 'uninstall':
|
|
2360
2922
|
cmdUninstall();
|
|
@@ -2374,6 +2936,9 @@ const [, , command, ...args] = process.argv;
|
|
|
2374
2936
|
case 'doctor':
|
|
2375
2937
|
cmdDoctor();
|
|
2376
2938
|
break;
|
|
2939
|
+
case 'browser':
|
|
2940
|
+
cmdBrowser(args);
|
|
2941
|
+
break;
|
|
2377
2942
|
case 'enable-pack':
|
|
2378
2943
|
cmdEnablePack(args[0]);
|
|
2379
2944
|
break;
|
|
@@ -2398,6 +2963,19 @@ const [, , command, ...args] = process.argv;
|
|
|
2398
2963
|
case 'telegram':
|
|
2399
2964
|
cmdTelegram(args);
|
|
2400
2965
|
break;
|
|
2966
|
+
case 'credentials':
|
|
2967
|
+
case 'creds':
|
|
2968
|
+
cmdCredentials(args);
|
|
2969
|
+
break;
|
|
2970
|
+
case 'serve':
|
|
2971
|
+
cmdServe(args);
|
|
2972
|
+
break;
|
|
2973
|
+
case 'admin':
|
|
2974
|
+
cmdAdmin();
|
|
2975
|
+
break;
|
|
2976
|
+
case 'restart':
|
|
2977
|
+
await cmdRestart();
|
|
2978
|
+
break;
|
|
2401
2979
|
case 'help':
|
|
2402
2980
|
case '--help':
|
|
2403
2981
|
case '-h':
|