@leejungkiin/awkit 1.6.4 → 1.6.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/bin/awk.js +70 -5
- package/bin/claude-generators.js +2 -2
- package/bin/cursor-generators.js +256 -0
- package/core/CURSOR.md +47 -0
- package/core/CURSOR_DETAILED.md +102 -0
- package/package.json +2 -2
- package/scripts/automation-gate.js +18 -0
- package/scripts/obsidian-sync.js +494 -0
- package/skills/app-store-screenshots/SKILL.md +86 -0
- package/skills/app-store-screenshots/resources/mockup.png +0 -0
- package/skills/aseprite-artist/SKILL.md +346 -0
- package/skills/aseprite-artist/resources/examples.md +188 -0
- package/skills/aseprite-artist/resources/palettes.md +133 -0
- package/skills/pixel-art-creator/SKILL.md +89 -0
- package/skills/semantic-qa-agent/SKILL.md +68 -0
- package/skills/symphony-enforcer/examples/three-phase.md +19 -11
- package/templates/project-identity/android.json +2 -0
- package/templates/project-identity/backend-nestjs.json +2 -0
- package/templates/project-identity/expo.json +2 -0
- package/templates/project-identity/ios.json +2 -0
- package/templates/project-identity/web-nextjs.json +2 -0
package/bin/awk.js
CHANGED
|
@@ -38,7 +38,9 @@ const HOME = process.env.HOME || process.env.USERPROFILE;
|
|
|
38
38
|
const { generateClineRules, generateClineWorkflows, generateClineSkills } = require('./cline-generators');
|
|
39
39
|
const { generateCodexAgentsMd, generateCodexSkills, generateCodexAgents } = require('./codex-generators');
|
|
40
40
|
const { generateClaudeRules, generateClaudeSkills } = require('./claude-generators');
|
|
41
|
+
const { generateCursorRules, generateCursorSkills } = require('./cursor-generators');
|
|
41
42
|
const { cmdGate } = require('../scripts/automation-gate');
|
|
43
|
+
const { cmdObsidian } = require('../scripts/obsidian-sync');
|
|
42
44
|
|
|
43
45
|
// ─── Platform Definitions ──────────────────────────────────────────────────
|
|
44
46
|
|
|
@@ -85,6 +87,24 @@ const PLATFORMS = {
|
|
|
85
87
|
dirs: {
|
|
86
88
|
skills: '.claude/skills',
|
|
87
89
|
},
|
|
90
|
+
},
|
|
91
|
+
qwen: {
|
|
92
|
+
name: 'Qwen Code',
|
|
93
|
+
globalRoot: path.join(HOME, '.qwen'),
|
|
94
|
+
rulesFile: null,
|
|
95
|
+
versionFile: path.join(HOME, '.qwen', 'awk_version'),
|
|
96
|
+
dirs: {
|
|
97
|
+
skills: 'skills',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
cursor: {
|
|
101
|
+
name: 'Cursor AI',
|
|
102
|
+
globalRoot: process.cwd(), // Local to project
|
|
103
|
+
rulesFile: '.cursor/rules/antigravity-rules.mdc',
|
|
104
|
+
versionFile: '.cursor/awk_version',
|
|
105
|
+
dirs: {
|
|
106
|
+
skills: '.cursor/rules',
|
|
107
|
+
},
|
|
88
108
|
}
|
|
89
109
|
};
|
|
90
110
|
|
|
@@ -516,6 +536,8 @@ function cmdInstall(args = []) {
|
|
|
516
536
|
if (args.includes('--cline') || args.includes('cline')) selectedPlatforms.push('cline');
|
|
517
537
|
if (args.includes('--codex') || args.includes('-x')) selectedPlatforms.push('codex');
|
|
518
538
|
if (args.includes('--claude-code') || args.includes('--claude') || args.includes('-c') || args.includes('claude')) selectedPlatforms.push('claude');
|
|
539
|
+
if (args.includes('--qwen') || args.includes('--qwen-code') || args.includes('-q') || args.includes('qwen')) selectedPlatforms.push('qwen');
|
|
540
|
+
if (args.includes('--cursor') || args.includes('cursor')) selectedPlatforms.push('cursor');
|
|
519
541
|
|
|
520
542
|
const pIdx = args.indexOf('--platform');
|
|
521
543
|
let legacyArg = null;
|
|
@@ -534,25 +556,29 @@ function cmdInstall(args = []) {
|
|
|
534
556
|
if (isUpdate) {
|
|
535
557
|
selectedPlatforms = [getActivePlatform()];
|
|
536
558
|
} else {
|
|
537
|
-
const platformOrder = ['antigravity', 'cline', 'codex', 'claude'];
|
|
559
|
+
const platformOrder = ['antigravity', 'cline', 'codex', 'claude', 'qwen', 'cursor'];
|
|
538
560
|
const defaultPlatform = getActivePlatform();
|
|
539
561
|
const defaultChoice = String(Math.max(platformOrder.indexOf(defaultPlatform), 0) + 1);
|
|
540
|
-
log(`${C.cyan}Select platforms to install (e.g., type "1,2", "all", or "1
|
|
562
|
+
log(`${C.cyan}Select platforms to install (e.g., type "1,2", "all", or "1-6"):${C.reset}`);
|
|
541
563
|
log(` 1. Gemini Code Assist (antigravity)`);
|
|
542
564
|
log(` 2. Cline (VS Code)`);
|
|
543
565
|
log(` 3. Codex CLI (codex)`);
|
|
544
566
|
log(` 4. Claude Code (.claude/)`);
|
|
545
|
-
log(` 5.
|
|
567
|
+
log(` 5. Qwen Code (~/.qwen/)`);
|
|
568
|
+
log(` 6. Cursor AI (.cursor/rules/)`);
|
|
569
|
+
log(` 7. All of the above`);
|
|
546
570
|
log(`${C.gray}Press Enter to install only the active platform: ${PLATFORMS[defaultPlatform].name}.${C.reset}`);
|
|
547
571
|
const choice = promptChoice('Choice', defaultChoice).trim().toLowerCase();
|
|
548
572
|
|
|
549
|
-
if (choice === '
|
|
573
|
+
if (choice === '7' || choice === 'all') {
|
|
550
574
|
selectedPlatforms = Object.keys(PLATFORMS);
|
|
551
575
|
} else {
|
|
552
576
|
if (choice.includes('1')) selectedPlatforms.push('antigravity');
|
|
553
577
|
if (choice.includes('2')) selectedPlatforms.push('cline');
|
|
554
578
|
if (choice.includes('3')) selectedPlatforms.push('codex');
|
|
555
579
|
if (choice.includes('4')) selectedPlatforms.push('claude');
|
|
580
|
+
if (choice.includes('5')) selectedPlatforms.push('qwen');
|
|
581
|
+
if (choice.includes('6')) selectedPlatforms.push('cursor');
|
|
556
582
|
}
|
|
557
583
|
}
|
|
558
584
|
}
|
|
@@ -614,6 +640,10 @@ function cmdInstall(args = []) {
|
|
|
614
640
|
const claudeTemplateSrc = path.join(AWK_ROOT, 'core', 'CLAUDE.md');
|
|
615
641
|
const claudeRulesDest = path.join(target, plat.rulesFile);
|
|
616
642
|
generateClaudeRules(claudeTemplateSrc, claudeRulesDest);
|
|
643
|
+
} else if (platform === 'cursor') {
|
|
644
|
+
info('Generating Cursor AI .mdc rules...');
|
|
645
|
+
const cursorRulesDest = path.join(target, plat.rulesFile);
|
|
646
|
+
generateCursorRules(path.join(AWK_ROOT, 'core', 'GEMINI.md'), cursorRulesDest);
|
|
617
647
|
}
|
|
618
648
|
|
|
619
649
|
// 3. Backup and install workflows
|
|
@@ -668,7 +698,11 @@ function cmdInstall(args = []) {
|
|
|
668
698
|
const agentsDest = path.join(target, plat.dirs.agents);
|
|
669
699
|
generateCodexAgents(skillsSrc, agentsDest, coreSkills);
|
|
670
700
|
} else if (platform === 'claude') {
|
|
671
|
-
generateClaudeSkills(skillsSrc, skillsDest, coreSkills);
|
|
701
|
+
generateClaudeSkills(skillsSrc, skillsDest, coreSkills, 'Claude Code');
|
|
702
|
+
} else if (platform === 'qwen') {
|
|
703
|
+
generateClaudeSkills(skillsSrc, skillsDest, coreSkills, 'Qwen Code'); // Shares the same format with Claude
|
|
704
|
+
} else if (platform === 'cursor') {
|
|
705
|
+
generateCursorSkills(skillsSrc, skillsDest, coreSkills);
|
|
672
706
|
} else {
|
|
673
707
|
const skillCount = copySelectedSkillDirs(skillsSrc, skillsDest, coreSkills);
|
|
674
708
|
ok(`${skillCount} core skill files installed`);
|
|
@@ -2298,6 +2332,25 @@ function buildProjectIdentity(projectName, projectType, cwd, date) {
|
|
|
2298
2332
|
list: 'Your List Name',
|
|
2299
2333
|
card: 'Your Card Name',
|
|
2300
2334
|
},
|
|
2335
|
+
automation: {
|
|
2336
|
+
autoQA: true,
|
|
2337
|
+
maxSelfCorrectionLoops: 3,
|
|
2338
|
+
telegram: {
|
|
2339
|
+
enabled: true,
|
|
2340
|
+
chatId: "",
|
|
2341
|
+
topicId: "",
|
|
2342
|
+
triggers: { git_push: true, task_complete: false, deploy: true }
|
|
2343
|
+
},
|
|
2344
|
+
trello: {
|
|
2345
|
+
enabled: true,
|
|
2346
|
+
autoSync: true,
|
|
2347
|
+
triggers: { task_complete: true, milestone: true, blocked: true }
|
|
2348
|
+
},
|
|
2349
|
+
git: {
|
|
2350
|
+
autoCommit: true,
|
|
2351
|
+
autoPush: true
|
|
2352
|
+
}
|
|
2353
|
+
},
|
|
2301
2354
|
projectStage: 'development',
|
|
2302
2355
|
codingStandards: cfg.codingStandards,
|
|
2303
2356
|
projectGoals: [],
|
|
@@ -2505,6 +2558,8 @@ async function cmdInit(forceFlag = false) {
|
|
|
2505
2558
|
const currentIdentity = JSON.parse(fs.readFileSync(identityPath, 'utf8'));
|
|
2506
2559
|
if (!currentIdentity.automation) {
|
|
2507
2560
|
currentIdentity.automation = {
|
|
2561
|
+
autoQA: true,
|
|
2562
|
+
maxSelfCorrectionLoops: 3,
|
|
2508
2563
|
telegram: {
|
|
2509
2564
|
enabled: true,
|
|
2510
2565
|
chatId: "",
|
|
@@ -2523,6 +2578,12 @@ async function cmdInit(forceFlag = false) {
|
|
|
2523
2578
|
};
|
|
2524
2579
|
fs.writeFileSync(identityPath, JSON.stringify(currentIdentity, null, 2) + '\n');
|
|
2525
2580
|
ok('Added Automation config placeholder to .project-identity');
|
|
2581
|
+
} else if (currentIdentity.automation.autoQA === undefined) {
|
|
2582
|
+
// Update existing automation block with new QA fields
|
|
2583
|
+
currentIdentity.automation.autoQA = true;
|
|
2584
|
+
currentIdentity.automation.maxSelfCorrectionLoops = 3;
|
|
2585
|
+
fs.writeFileSync(identityPath, JSON.stringify(currentIdentity, null, 2) + '\n');
|
|
2586
|
+
ok('Updated Automation config with autoQA defaults in .project-identity');
|
|
2526
2587
|
}
|
|
2527
2588
|
} catch (_) { /* ignore */ }
|
|
2528
2589
|
|
|
@@ -3867,6 +3928,10 @@ const [, , command, ...args] = process.argv;
|
|
|
3867
3928
|
case 'gate':
|
|
3868
3929
|
cmdGate(args);
|
|
3869
3930
|
break;
|
|
3931
|
+
case 'obsidian':
|
|
3932
|
+
case 'obs':
|
|
3933
|
+
cmdObsidian(args);
|
|
3934
|
+
break;
|
|
3870
3935
|
case 'admin':
|
|
3871
3936
|
cmdAdmin();
|
|
3872
3937
|
break;
|
package/bin/claude-generators.js
CHANGED
|
@@ -25,7 +25,7 @@ function generateClaudeRules(sourcePath, destPath) {
|
|
|
25
25
|
* Preserves full directory structure: <skill-name>/SKILL.md + scripts/ + templates/
|
|
26
26
|
* Injects YAML frontmatter if missing.
|
|
27
27
|
*/
|
|
28
|
-
function generateClaudeSkills(srcDir, destDir, selectedSkills = null) {
|
|
28
|
+
function generateClaudeSkills(srcDir, destDir, selectedSkills = null, platformName = 'Claude Code') {
|
|
29
29
|
if (!fs.existsSync(srcDir)) return;
|
|
30
30
|
|
|
31
31
|
fs.mkdirSync(destDir, { recursive: true });
|
|
@@ -51,7 +51,7 @@ function generateClaudeSkills(srcDir, destDir, selectedSkills = null) {
|
|
|
51
51
|
|
|
52
52
|
count++;
|
|
53
53
|
}
|
|
54
|
-
console.log(`✅ Generated ${count}
|
|
54
|
+
console.log(`✅ Generated ${count} ${platformName} skills in ${destDir}`);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cursor Rules Generator for AWKit
|
|
6
|
+
*
|
|
7
|
+
* Follows Cursor's official rule design:
|
|
8
|
+
* - 4 activation modes: Always Apply, Auto Attached (Globs), Agent Requested, Manual
|
|
9
|
+
* - Token efficiency: alwaysApply rules must be concise
|
|
10
|
+
* - Skills → Agent Requested mode (description only, no globs)
|
|
11
|
+
* - Global rules → Always Apply mode (concise, essential only)
|
|
12
|
+
*
|
|
13
|
+
* @see https://docs.cursor.com/docs/rules
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate Cursor rule files from core templates.
|
|
18
|
+
* Creates TWO files following Cursor's best practices:
|
|
19
|
+
* 1. antigravity-rules.mdc (Always Apply) — concise identity + protocol (~30 lines)
|
|
20
|
+
* 2. antigravity-detailed.mdc (Agent Requested) — full rules loaded when relevant
|
|
21
|
+
*
|
|
22
|
+
* @param {string} sourcePath Path to core/GEMINI.md (used to auto-detect core dir)
|
|
23
|
+
* @param {string} destPath Destination .cursor/rules/antigravity-rules.mdc
|
|
24
|
+
*/
|
|
25
|
+
function generateCursorRules(sourcePath, destPath) {
|
|
26
|
+
const coreDir = path.dirname(sourcePath);
|
|
27
|
+
const destDir = path.dirname(destPath);
|
|
28
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
// --- File 1: Always Apply (concise identity + protocol) ---
|
|
31
|
+
const cursorTemplate = path.join(coreDir, 'CURSOR.md');
|
|
32
|
+
const actualSource = fs.existsSync(cursorTemplate) ? cursorTemplate : sourcePath;
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(actualSource)) {
|
|
35
|
+
console.log(`⚠️ Template not found: ${actualSource}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const content = fs.readFileSync(actualSource, 'utf8');
|
|
40
|
+
const alwaysFrontmatter = [
|
|
41
|
+
'---',
|
|
42
|
+
'description: "MANDATORY Antigravity Orchestrator identity and session protocol. You MUST follow these rules in EVERY conversation."',
|
|
43
|
+
'alwaysApply: true',
|
|
44
|
+
'---',
|
|
45
|
+
'', '',
|
|
46
|
+
].join('\n');
|
|
47
|
+
|
|
48
|
+
fs.writeFileSync(destPath, alwaysFrontmatter + content.trim() + '\n');
|
|
49
|
+
console.log(`✅ Cursor Rules (Always Apply) → ${path.basename(destPath)}`);
|
|
50
|
+
|
|
51
|
+
// --- File 2: Agent Requested (detailed operational rules) ---
|
|
52
|
+
const detailedSource = path.join(coreDir, 'CURSOR_DETAILED.md');
|
|
53
|
+
if (fs.existsSync(detailedSource)) {
|
|
54
|
+
const detailedContent = fs.readFileSync(detailedSource, 'utf8');
|
|
55
|
+
const detailedFrontmatter = [
|
|
56
|
+
'---',
|
|
57
|
+
'description: "Antigravity detailed rules: 7-Gate system, code standards, safety guardrails, NeuralMemory protocol, GitNexus integration, and decision principles. Load when planning, coding, debugging, or reviewing."',
|
|
58
|
+
'---',
|
|
59
|
+
'', '',
|
|
60
|
+
].join('\n');
|
|
61
|
+
|
|
62
|
+
const detailedDest = path.join(destDir, 'antigravity-detailed.mdc');
|
|
63
|
+
fs.writeFileSync(detailedDest, detailedFrontmatter + detailedContent.trim() + '\n');
|
|
64
|
+
console.log(`✅ Cursor Rules (Agent Requested) → antigravity-detailed.mdc`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Convert AWKit skills to Cursor .mdc rules using proper activation modes.
|
|
70
|
+
*
|
|
71
|
+
* Activation mode strategy:
|
|
72
|
+
* - Skills with clear triggers → Agent Requested (description only)
|
|
73
|
+
* - Skills that are always needed → alwaysApply: true (rare)
|
|
74
|
+
* - All skills: NO globs (skills are concept-based, not file-based)
|
|
75
|
+
*
|
|
76
|
+
* @param {string} srcDir Source skills directory
|
|
77
|
+
* @param {string} destDir Destination .cursor/rules directory
|
|
78
|
+
* @param {string[]} selectedSkills Optional list of skill names to include
|
|
79
|
+
*/
|
|
80
|
+
function generateCursorSkills(srcDir, destDir, selectedSkills = null) {
|
|
81
|
+
if (!fs.existsSync(srcDir)) return;
|
|
82
|
+
|
|
83
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
84
|
+
const skills = fs.readdirSync(srcDir);
|
|
85
|
+
const allowed = selectedSkills ? new Set(selectedSkills) : null;
|
|
86
|
+
|
|
87
|
+
let count = 0;
|
|
88
|
+
for (const skill of skills) {
|
|
89
|
+
if (allowed && !allowed.has(skill)) continue;
|
|
90
|
+
const skillSrcDir = path.join(srcDir, skill);
|
|
91
|
+
if (!fs.statSync(skillSrcDir).isDirectory()) continue;
|
|
92
|
+
if (skill === '.DS_Store') continue;
|
|
93
|
+
|
|
94
|
+
const skillFile = path.join(skillSrcDir, 'SKILL.md');
|
|
95
|
+
if (!fs.existsSync(skillFile)) continue;
|
|
96
|
+
|
|
97
|
+
const destFile = path.join(destDir, `${skill}.mdc`);
|
|
98
|
+
let content = fs.readFileSync(skillFile, 'utf8');
|
|
99
|
+
|
|
100
|
+
// Extract description from existing frontmatter or content
|
|
101
|
+
let description = extractDescription(content, skill);
|
|
102
|
+
|
|
103
|
+
// Strip existing frontmatter (we'll generate Cursor-specific one)
|
|
104
|
+
content = stripFrontmatter(content);
|
|
105
|
+
|
|
106
|
+
// Determine activation mode based on skill nature
|
|
107
|
+
const mode = getSkillActivationMode(skill);
|
|
108
|
+
|
|
109
|
+
// Build Cursor-compatible frontmatter
|
|
110
|
+
const frontmatter = buildFrontmatter(description, mode);
|
|
111
|
+
|
|
112
|
+
fs.writeFileSync(destFile, frontmatter + content.trim() + '\n');
|
|
113
|
+
|
|
114
|
+
// Copy scripts subdirectory if exists (reference for AI)
|
|
115
|
+
const scriptsSrc = path.join(skillSrcDir, 'scripts');
|
|
116
|
+
if (fs.existsSync(scriptsSrc)) {
|
|
117
|
+
const scriptsDest = path.join(destDir, 'scripts', skill);
|
|
118
|
+
copyRecursive(scriptsSrc, scriptsDest);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
count++;
|
|
122
|
+
}
|
|
123
|
+
console.log(`✅ Generated ${count} Cursor rules (.mdc) in ${destDir}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Extract a clean description from skill content.
|
|
128
|
+
* Handles both single-line and YAML folded block scalar (>-) descriptions.
|
|
129
|
+
*/
|
|
130
|
+
function extractDescription(content, skillName) {
|
|
131
|
+
// Try YAML frontmatter description
|
|
132
|
+
if (content.startsWith('---\n')) {
|
|
133
|
+
const endIdx = content.indexOf('\n---\n', 4);
|
|
134
|
+
if (endIdx !== -1) {
|
|
135
|
+
const frontmatter = content.slice(4, endIdx);
|
|
136
|
+
|
|
137
|
+
// Handle folded (>-) or literal (|) block scalar: description: >- or description: |
|
|
138
|
+
const foldedMatch = frontmatter.match(/^description:\s*[>|]-?\s*\n((?:\s{2,}.+\n?)+)/m);
|
|
139
|
+
if (foldedMatch) {
|
|
140
|
+
// Join indented continuation lines, strip leading whitespace
|
|
141
|
+
const lines = foldedMatch[1].split('\n')
|
|
142
|
+
.map(l => l.trim())
|
|
143
|
+
.filter(l => l.length > 0);
|
|
144
|
+
return lines.join(' ');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Handle single-line: description: "value" or description: value
|
|
148
|
+
const singleMatch = frontmatter.match(/^description:\s*"?([^"\n]+)"?\s*$/m);
|
|
149
|
+
if (singleMatch) return singleMatch[1].trim();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Fallback: try first markdown heading
|
|
154
|
+
const headingMatch = content.match(/^#\s+(.+)/m);
|
|
155
|
+
if (headingMatch) {
|
|
156
|
+
return headingMatch[1].replace(/[`*_]/g, '').trim();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return `Antigravity skill: ${skillName}`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Strip existing YAML frontmatter from content.
|
|
164
|
+
*/
|
|
165
|
+
function stripFrontmatter(content) {
|
|
166
|
+
if (content.startsWith('---\n')) {
|
|
167
|
+
const endIdx = content.indexOf('\n---\n', 4);
|
|
168
|
+
if (endIdx !== -1) {
|
|
169
|
+
return content.slice(endIdx + 5).trimStart();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return content;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Determine the Cursor activation mode for a skill.
|
|
177
|
+
*
|
|
178
|
+
* Modes:
|
|
179
|
+
* - "always" → alwaysApply: true (very few skills)
|
|
180
|
+
* - "agent" → Agent Requested: description only (most skills)
|
|
181
|
+
* - "globs" → Auto Attached: for file-type-specific skills
|
|
182
|
+
*
|
|
183
|
+
* @returns {{mode: string, globs?: string[]}}
|
|
184
|
+
*/
|
|
185
|
+
function getSkillActivationMode(skillName) {
|
|
186
|
+
// Skills that should always be available (critical orchestration)
|
|
187
|
+
const alwaysApplySkills = [
|
|
188
|
+
'orchestrator',
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
// Skills with file-type affinity
|
|
192
|
+
const globSkills = {
|
|
193
|
+
'gitnexus-intelligence': ['**/*.js', '**/*.ts', '**/*.py', '**/*.swift', '**/*.kt'],
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
if (alwaysApplySkills.includes(skillName)) {
|
|
197
|
+
return { mode: 'always' };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (globSkills[skillName]) {
|
|
201
|
+
return { mode: 'globs', globs: globSkills[skillName] };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Default: Agent Requested (description-based, most token-efficient)
|
|
205
|
+
return { mode: 'agent' };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Build Cursor-compatible YAML frontmatter.
|
|
210
|
+
*/
|
|
211
|
+
function buildFrontmatter(description, modeConfig) {
|
|
212
|
+
const lines = ['---'];
|
|
213
|
+
|
|
214
|
+
lines.push(`description: "${description.replace(/"/g, '\\"')}"`);
|
|
215
|
+
|
|
216
|
+
if (modeConfig.mode === 'always') {
|
|
217
|
+
lines.push('alwaysApply: true');
|
|
218
|
+
} else if (modeConfig.mode === 'globs') {
|
|
219
|
+
const globStr = modeConfig.globs.map(g => `"${g}"`).join(', ');
|
|
220
|
+
lines.push(`globs: [${globStr}]`);
|
|
221
|
+
lines.push('alwaysApply: false');
|
|
222
|
+
} else {
|
|
223
|
+
// Agent Requested: just description, no globs, no alwaysApply
|
|
224
|
+
// Cursor docs: when only description is set, AI decides relevance
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
lines.push('---');
|
|
228
|
+
lines.push('');
|
|
229
|
+
lines.push('');
|
|
230
|
+
return lines.join('\n');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Recursively copy directories.
|
|
235
|
+
*/
|
|
236
|
+
function copyRecursive(src, dest) {
|
|
237
|
+
if (!fs.existsSync(src)) return;
|
|
238
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
239
|
+
|
|
240
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
if (entry.name === '.DS_Store' || entry.name === '__pycache__') continue;
|
|
243
|
+
const srcPath = path.join(src, entry.name);
|
|
244
|
+
const destPath = path.join(dest, entry.name);
|
|
245
|
+
if (entry.isDirectory()) {
|
|
246
|
+
copyRecursive(srcPath, destPath);
|
|
247
|
+
} else {
|
|
248
|
+
fs.copyFileSync(srcPath, destPath);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
module.exports = {
|
|
254
|
+
generateCursorRules,
|
|
255
|
+
generateCursorSkills,
|
|
256
|
+
};
|
package/core/CURSOR.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# IDENTITY
|
|
2
|
+
|
|
3
|
+
You are **Antigravity Orchestrator**. Not "Cursor assistant", not "AI assistant". You are Antigravity.
|
|
4
|
+
When asked "who are you?", answer: "Tôi là Antigravity Orchestrator."
|
|
5
|
+
|
|
6
|
+
# SESSION PROTOCOL (HARD-ENFORCED)
|
|
7
|
+
|
|
8
|
+
> [!CAUTION]
|
|
9
|
+
> This is NOT optional. Skipping this = DISCIPLINARY VIOLATION.
|
|
10
|
+
> You MUST execute terminal commands BEFORE any analysis, planning, or code generation.
|
|
11
|
+
|
|
12
|
+
**MANDATORY FIRST ACTIONS** — Run these in terminal (RunTerminalCommand) sequentially:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Step 1: Read project identity (ALWAYS)
|
|
16
|
+
cat .project-identity
|
|
17
|
+
|
|
18
|
+
# Step 2: Check Symphony status via CLI (NEVER read symphony/ files directly)
|
|
19
|
+
command -v symphony >/dev/null && symphony next || echo "Symphony CLI not installed"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Then use NeuralMemory MCP (if available): `nmem_recall` with project context.
|
|
23
|
+
|
|
24
|
+
**ZERO-TOLERANCE RULES:**
|
|
25
|
+
- ⛔ **BANNED**: Using read_file/grep/search tools on `symphony/` directory or `~/.gemini/brain/` to infer task state. You MUST use `symphony status` or `symphony next` CLI commands instead.
|
|
26
|
+
- ⛔ **BANNED**: Responding with a markdown plan or "Trạng thái hiện tại" summary BEFORE terminal init commands have executed successfully.
|
|
27
|
+
- ⛔ **BANNED**: Saying "Symphony đang trỏ project khác" as an observation without IMMEDIATELY running `symphony project switch <correct-id>` to fix it.
|
|
28
|
+
|
|
29
|
+
**Exception**: Pure Q&A (no code changes planned) may skip init chain.
|
|
30
|
+
**When in doubt**: Run init chain. Default to compliance.
|
|
31
|
+
|
|
32
|
+
# ABSOLUTE RULES
|
|
33
|
+
|
|
34
|
+
1. Chat in **Vietnamese**. Code/docs/comments in **English**.
|
|
35
|
+
2. End every response with **"Next steps"** section.
|
|
36
|
+
3. Never run `git reset --hard`, `git push --force`, `rm -rf` without user confirmation.
|
|
37
|
+
4. Never say "Great idea!" if the idea has problems. State risks first.
|
|
38
|
+
5. When you don't follow a rule, say "Tôi đã không tuân thủ rule X" — never rationalize.
|
|
39
|
+
6. **Git commits**: Use `awkit gate git auto "message"` — NEVER use raw `git commit` in terminal.
|
|
40
|
+
|
|
41
|
+
# ANTI-EVASION
|
|
42
|
+
|
|
43
|
+
- Do NOT reinterpret rules to avoid compliance.
|
|
44
|
+
- Do NOT blame "environment limitations" to skip rules. If a tool is missing, say so once, then do what you CAN.
|
|
45
|
+
- Do NOT separate "I am Cursor" from "Antigravity Orchestrator". You are one entity.
|
|
46
|
+
- Do NOT write paragraphs explaining why a rule doesn't apply. Follow it or state the violation.
|
|
47
|
+
- Do NOT read static files to "understand context" as a substitute for running CLI commands. The CLI commands exist to ensure correct state synchronization.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Antigravity Detailed Rules
|
|
2
|
+
|
|
3
|
+
> This file contains detailed operational rules. Loaded by Cursor when relevant to the task.
|
|
4
|
+
|
|
5
|
+
## 7-Gate Autonomous System
|
|
6
|
+
|
|
7
|
+
Triage complexity before every task:
|
|
8
|
+
|
|
9
|
+
| Complexity | Gates Required |
|
|
10
|
+
|---|---|
|
|
11
|
+
| TRIVIAL | Skip to Gate 4 (code directly) |
|
|
12
|
+
| MODERATE | Gate 3 → 4 → 5 |
|
|
13
|
+
| COMPLEX | All 7 Gates sequentially |
|
|
14
|
+
|
|
15
|
+
### Gates
|
|
16
|
+
1. **Gate 1 (Spec)**: Brainstorm → BRIEF.md
|
|
17
|
+
2. **Gate 1.5 (Module Spec)**: Per-module product specs (COMPLEX + >3 modules only)
|
|
18
|
+
3. **Gate 2 (Architecture)**: Design doc + user approve
|
|
19
|
+
4. **Gate 2.5 (Visual Design)**: UI agreement (skip for backend-only tasks)
|
|
20
|
+
5. **Gate 3 (Tasks)**: Create task tickets via Symphony
|
|
21
|
+
6. **Gate 4 (Execution)**: Code to ticket, verify against design doc
|
|
22
|
+
7. **Gate 5 (Verification)**: Test + code review
|
|
23
|
+
|
|
24
|
+
### Gate 4 Three-Phase (COMPLEX + UI only)
|
|
25
|
+
- **Phase A** 🏗️ Infrastructure: dependencies, navigation skeleton → build check
|
|
26
|
+
- **Phase B** 🎨 UI Shell: all screens with mock data → USER TEST CHECKPOINT
|
|
27
|
+
- **Phase C** ⚡ Logic: replace mock with real data → USER TEST per feature
|
|
28
|
+
- ⛔ NEVER code logic before user confirms UI is OK.
|
|
29
|
+
|
|
30
|
+
## Symphony Interaction Protocol (MANDATORY)
|
|
31
|
+
|
|
32
|
+
> [!WARNING]
|
|
33
|
+
> These rules prevent the #1 compliance failure: agents bypassing Symphony by reading raw files.
|
|
34
|
+
|
|
35
|
+
### BANNED Actions
|
|
36
|
+
| Action | Why Banned | Correct Alternative |
|
|
37
|
+
|--------|-----------|-------------------|
|
|
38
|
+
| `read_file("symphony/tasks/*.json")` | Bypasses state sync, gets stale data | `symphony task list` in terminal |
|
|
39
|
+
| `read_file("symphony/agents/*.json")` | Reads unfiltered cross-project data | `symphony status` in terminal |
|
|
40
|
+
| `grep_search("symphony/")` | Static sniffing ≠ live state | `symphony next` in terminal |
|
|
41
|
+
| Writing markdown plan before init | Gives illusion of progress, skips context | Run terminal init first, then plan |
|
|
42
|
+
|
|
43
|
+
### REQUIRED Actions
|
|
44
|
+
| Situation | Terminal Command |
|
|
45
|
+
|-----------|-----------------|
|
|
46
|
+
| Start of session | `cat .project-identity && symphony next` |
|
|
47
|
+
| User asks "what's next?" | `symphony next` |
|
|
48
|
+
| Need task list | `symphony task list` |
|
|
49
|
+
| Project mismatch detected | `symphony project switch <projectId>` |
|
|
50
|
+
| Task completed | `awkit gate git auto "feat: description"` |
|
|
51
|
+
| Check current state | `symphony status` |
|
|
52
|
+
|
|
53
|
+
### Project ID Mismatch Hard-Stop
|
|
54
|
+
If you detect that Symphony's active project differs from `.project-identity`'s `projectId`:
|
|
55
|
+
1. **STOP ALL ANALYSIS IMMEDIATELY** — do not brainstorm, plan, or summarize.
|
|
56
|
+
2. Run: `symphony project switch <correct-projectId>` in terminal.
|
|
57
|
+
3. Run: `symphony next` to get correct context.
|
|
58
|
+
4. ONLY THEN proceed with the user's request.
|
|
59
|
+
|
|
60
|
+
## Code Standards
|
|
61
|
+
- Production quality. Files < 500 lines.
|
|
62
|
+
- Don't modify code outside scope.
|
|
63
|
+
- Don't hardcode secrets → use `.env`.
|
|
64
|
+
- AI models: Gemini 2.5+ only.
|
|
65
|
+
- Firebase: Firebase AI Logic SDK.
|
|
66
|
+
|
|
67
|
+
## Auto-Commit Protocol
|
|
68
|
+
- Build success (0 errors) → use `awkit gate git auto "type: message"`.
|
|
69
|
+
- ⛔ **NEVER** use raw `git commit` or `git push` in terminal. Always use `awkit gate git auto`.
|
|
70
|
+
- Commit message: conventional format (`fix:`, `feat:`, `refactor:`, `chore:`).
|
|
71
|
+
- Push fail → gate handles retry automatically. Never force push.
|
|
72
|
+
|
|
73
|
+
## NeuralMemory Protocol
|
|
74
|
+
- Brain = projectId (from `.project-identity`). Switch brain before any nmem call.
|
|
75
|
+
- Tag every `nmem_remember()` with projectId.
|
|
76
|
+
- Cross-brain queries: `nmem_recall(query, brains=["default", projectId])`.
|
|
77
|
+
|
|
78
|
+
## Safety Guardrails
|
|
79
|
+
Never auto-run these without user confirmation:
|
|
80
|
+
- `rm -rf`, `rm -r` (recursive delete)
|
|
81
|
+
- `git push --force`, `git reset --hard`, `git clean -fd`
|
|
82
|
+
- `DROP TABLE`, `DROP DATABASE`, `DELETE FROM` (without WHERE)
|
|
83
|
+
- `npm publish`, `pod trunk push`
|
|
84
|
+
- Any production deploy command
|
|
85
|
+
|
|
86
|
+
## 6 Decision Principles (when deciding without user)
|
|
87
|
+
1. Complete > Shortcuts
|
|
88
|
+
2. Evidence > Assumptions
|
|
89
|
+
3. Standard > Custom
|
|
90
|
+
4. Explicit > Implicit
|
|
91
|
+
5. Test > Trust
|
|
92
|
+
6. Small > Big
|
|
93
|
+
|
|
94
|
+
## Project Context
|
|
95
|
+
- `.project-identity` exists → READ IT FIRST for projectId, techStack, goals.
|
|
96
|
+
- `CODEBASE.md` exists → don't scan raw directory.
|
|
97
|
+
|
|
98
|
+
## GitNexus (Code Intelligence)
|
|
99
|
+
- `.gitnexus/` exists → MUST use GitNexus tools.
|
|
100
|
+
- Before editing a symbol → `gitnexus_impact` check blast radius.
|
|
101
|
+
- Before committing → `gitnexus_detect_changes()` verify scope.
|
|
102
|
+
- HIGH/CRITICAL risk → WARN user before editing.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leejungkiin/awkit",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "Antigravity Workflow Kit
|
|
3
|
+
"version": "1.6.5",
|
|
4
|
+
"description": "Antigravity Workflow Kit v1.6 Unified AI agent orchestration system with Mindful Checkpoints.",
|
|
5
5
|
"main": "bin/awk.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"awkit": "bin/awk.js",
|
|
@@ -19,6 +19,19 @@ const fs = require('fs');
|
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const { execSync } = require('child_process');
|
|
21
21
|
|
|
22
|
+
// Lazy-load obsidian-sync to avoid circular dependencies
|
|
23
|
+
let _autoSyncObsidian = null;
|
|
24
|
+
function getAutoSyncObsidian() {
|
|
25
|
+
if (!_autoSyncObsidian) {
|
|
26
|
+
try {
|
|
27
|
+
_autoSyncObsidian = require('./obsidian-sync').autoSyncObsidian;
|
|
28
|
+
} catch (_) {
|
|
29
|
+
_autoSyncObsidian = () => {}; // Graceful fallback
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return _autoSyncObsidian;
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
// ─── Color helpers (borrowed from main CLI) ──────────────────────────────────
|
|
23
36
|
|
|
24
37
|
const C = {
|
|
@@ -224,6 +237,9 @@ function execGitAuto(message) {
|
|
|
224
237
|
}
|
|
225
238
|
}
|
|
226
239
|
|
|
240
|
+
// Trigger Obsidian sync after successful git auto
|
|
241
|
+
getAutoSyncObsidian()();
|
|
242
|
+
|
|
227
243
|
return true;
|
|
228
244
|
}
|
|
229
245
|
|
|
@@ -240,6 +256,8 @@ function execTrelloAction(action, args) {
|
|
|
240
256
|
try {
|
|
241
257
|
const cmd = `awkit trello ${action} ${args.map(a => `"${a}"`).join(' ')}`;
|
|
242
258
|
execSync(cmd, { stdio: 'inherit' });
|
|
259
|
+
// Trigger Obsidian sync after successful trello action
|
|
260
|
+
getAutoSyncObsidian()();
|
|
243
261
|
return true;
|
|
244
262
|
} catch (e) {
|
|
245
263
|
err(`Trello ${action} failed: ${e.message}`);
|