agent-flutter 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/cli.js +115 -11
package/README.md
CHANGED
|
@@ -14,12 +14,15 @@ By default `init` installs adapters for all supported IDEs:
|
|
|
14
14
|
- Cursor
|
|
15
15
|
- Windsurf
|
|
16
16
|
- Cline
|
|
17
|
+
- GitHub (Copilot)
|
|
17
18
|
|
|
18
19
|
## Commands
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
22
|
npx agent-flutter@latest init --ide all --cwd /path/to/project --force
|
|
22
23
|
npx agent-flutter@latest init --ide trae,codex
|
|
24
|
+
npx agent-flutter@latest sync
|
|
25
|
+
npx agent-flutter@latest sync --ide trae,codex,github
|
|
23
26
|
npx agent-flutter@latest list --cwd /path/to/project
|
|
24
27
|
```
|
|
25
28
|
|
|
@@ -55,3 +58,4 @@ npm run release:major
|
|
|
55
58
|
- Cursor: `.cursor/rules/agent-flutter.mdc`
|
|
56
59
|
- Windsurf: `.windsurf/rules/agent-flutter.md`
|
|
57
60
|
- Cline: `.clinerules/agent-flutter.md`
|
|
61
|
+
- GitHub: `.github/copilot-instructions.md`
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -2,17 +2,19 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
4
|
|
|
5
|
-
const SUPPORTED_IDES = ['trae', 'codex', 'cursor', 'windsurf', 'cline'];
|
|
5
|
+
const SUPPORTED_IDES = ['trae', 'codex', 'cursor', 'windsurf', 'cline', 'github'];
|
|
6
6
|
|
|
7
7
|
const USAGE = `
|
|
8
8
|
agent-flutter
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
npx agent-flutter@latest init [--ide all|trae,codex,cursor,windsurf,cline] [--cwd <project_dir>] [--force]
|
|
11
|
+
npx agent-flutter@latest init [--ide all|trae,codex,cursor,windsurf,cline,github] [--cwd <project_dir>] [--force]
|
|
12
|
+
npx agent-flutter@latest sync [--ide all|trae,codex,cursor,windsurf,cline,github] [--cwd <project_dir>]
|
|
12
13
|
npx agent-flutter@latest list [--cwd <project_dir>]
|
|
13
14
|
|
|
14
15
|
Commands:
|
|
15
16
|
init Install shared Flutter skills/rules and IDE adapters.
|
|
17
|
+
sync Update installed shared pack and adapters from latest template.
|
|
16
18
|
list Print available skills/rules from the shared pack.
|
|
17
19
|
`;
|
|
18
20
|
|
|
@@ -29,6 +31,9 @@ export async function runCli(argv) {
|
|
|
29
31
|
case 'init':
|
|
30
32
|
await runInit(options);
|
|
31
33
|
return;
|
|
34
|
+
case 'sync':
|
|
35
|
+
await runSync(options);
|
|
36
|
+
return;
|
|
32
37
|
case 'list':
|
|
33
38
|
await runList(options);
|
|
34
39
|
return;
|
|
@@ -82,6 +87,61 @@ async function runInit(options) {
|
|
|
82
87
|
const ideTargets = resolveIdeTargets(options.get('ide', 'all'));
|
|
83
88
|
const force = options.hasFlag('force');
|
|
84
89
|
|
|
90
|
+
await applyPack({
|
|
91
|
+
templateRoot,
|
|
92
|
+
projectRoot,
|
|
93
|
+
ideTargets,
|
|
94
|
+
force,
|
|
95
|
+
mode: 'install',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log('Done.');
|
|
100
|
+
console.log('Use --force to overwrite existing adapters.');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function runSync(options) {
|
|
104
|
+
const packageRoot = getPackageRoot();
|
|
105
|
+
const templateRoot = path.join(packageRoot, 'templates', 'shared');
|
|
106
|
+
await assertDirExists(templateRoot, `Shared template not found: ${templateRoot}`);
|
|
107
|
+
|
|
108
|
+
const projectRoot = path.resolve(options.get('cwd', process.cwd()));
|
|
109
|
+
await assertDirExists(projectRoot, `Project directory not found: ${projectRoot}`);
|
|
110
|
+
|
|
111
|
+
let ideTargets;
|
|
112
|
+
const ideOption = options.get('ide', null);
|
|
113
|
+
if (ideOption) {
|
|
114
|
+
ideTargets = resolveIdeTargets(ideOption);
|
|
115
|
+
} else {
|
|
116
|
+
ideTargets = await detectInstalledIdeTargets(projectRoot);
|
|
117
|
+
if (ideTargets.size) {
|
|
118
|
+
console.log(`Detected adapters: ${[...ideTargets].join(', ')}`);
|
|
119
|
+
} else {
|
|
120
|
+
ideTargets = new Set(SUPPORTED_IDES);
|
|
121
|
+
console.log('No existing adapters detected. Syncing all adapters.');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await applyPack({
|
|
126
|
+
templateRoot,
|
|
127
|
+
projectRoot,
|
|
128
|
+
ideTargets,
|
|
129
|
+
force: true,
|
|
130
|
+
mode: 'sync',
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
console.log('');
|
|
134
|
+
console.log('Sync completed.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function applyPack({
|
|
138
|
+
templateRoot,
|
|
139
|
+
projectRoot,
|
|
140
|
+
ideTargets,
|
|
141
|
+
force,
|
|
142
|
+
mode,
|
|
143
|
+
}) {
|
|
144
|
+
const verb = mode === 'sync' ? 'Synced' : 'Installed';
|
|
85
145
|
const sharedTarget = path.join(projectRoot, '.agent-flutter');
|
|
86
146
|
if ((await exists(sharedTarget)) && !force) {
|
|
87
147
|
console.log(`Using existing shared pack: ${sharedTarget}`);
|
|
@@ -92,7 +152,7 @@ async function runInit(options) {
|
|
|
92
152
|
projectRoot,
|
|
93
153
|
force: true,
|
|
94
154
|
});
|
|
95
|
-
console.log(
|
|
155
|
+
console.log(`${verb} shared pack: ${sharedTarget}`);
|
|
96
156
|
}
|
|
97
157
|
|
|
98
158
|
if (ideTargets.has('trae')) {
|
|
@@ -106,7 +166,7 @@ async function runInit(options) {
|
|
|
106
166
|
projectRoot,
|
|
107
167
|
force: true,
|
|
108
168
|
});
|
|
109
|
-
console.log(
|
|
169
|
+
console.log(`${verb} Trae adapter: ${traeTarget}`);
|
|
110
170
|
}
|
|
111
171
|
}
|
|
112
172
|
|
|
@@ -127,7 +187,7 @@ async function runInit(options) {
|
|
|
127
187
|
);
|
|
128
188
|
console.log(
|
|
129
189
|
written
|
|
130
|
-
?
|
|
190
|
+
? `${verb} Codex adapter: ${agentsPath}`
|
|
131
191
|
: `Skipped Codex adapter (exists): ${agentsPath}`,
|
|
132
192
|
);
|
|
133
193
|
}
|
|
@@ -141,7 +201,7 @@ async function runInit(options) {
|
|
|
141
201
|
);
|
|
142
202
|
console.log(
|
|
143
203
|
written
|
|
144
|
-
?
|
|
204
|
+
? `${verb} Cursor adapter: ${cursorPath}`
|
|
145
205
|
: `Skipped Cursor adapter (exists): ${cursorPath}`,
|
|
146
206
|
);
|
|
147
207
|
}
|
|
@@ -155,7 +215,7 @@ async function runInit(options) {
|
|
|
155
215
|
);
|
|
156
216
|
console.log(
|
|
157
217
|
written
|
|
158
|
-
?
|
|
218
|
+
? `${verb} Windsurf adapter: ${windsurfPath}`
|
|
159
219
|
: `Skipped Windsurf adapter (exists): ${windsurfPath}`,
|
|
160
220
|
);
|
|
161
221
|
}
|
|
@@ -169,14 +229,45 @@ async function runInit(options) {
|
|
|
169
229
|
);
|
|
170
230
|
console.log(
|
|
171
231
|
written
|
|
172
|
-
?
|
|
232
|
+
? `${verb} Cline adapter: ${clinePath}`
|
|
173
233
|
: `Skipped Cline adapter (exists): ${clinePath}`,
|
|
174
234
|
);
|
|
175
235
|
}
|
|
176
236
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
237
|
+
if (ideTargets.has('github')) {
|
|
238
|
+
const githubPath = path.join(projectRoot, '.github', 'copilot-instructions.md');
|
|
239
|
+
const written = await writeTextFile(
|
|
240
|
+
githubPath,
|
|
241
|
+
buildGithubCopilotInstructions(),
|
|
242
|
+
{ force },
|
|
243
|
+
);
|
|
244
|
+
console.log(
|
|
245
|
+
written
|
|
246
|
+
? `${verb} GitHub adapter: ${githubPath}`
|
|
247
|
+
: `Skipped GitHub adapter (exists): ${githubPath}`,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function detectInstalledIdeTargets(projectRoot) {
|
|
253
|
+
const checks = [
|
|
254
|
+
['trae', path.join(projectRoot, '.trae')],
|
|
255
|
+
['codex', path.join(projectRoot, 'AGENTS.md')],
|
|
256
|
+
['cursor', path.join(projectRoot, '.cursor', 'rules', 'agent-flutter.mdc')],
|
|
257
|
+
['windsurf', path.join(projectRoot, '.windsurf', 'rules', 'agent-flutter.md')],
|
|
258
|
+
['cline', path.join(projectRoot, '.clinerules', 'agent-flutter.md')],
|
|
259
|
+
['github', path.join(projectRoot, '.github', 'copilot-instructions.md')],
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const results = await Promise.all(
|
|
263
|
+
checks.map(async ([ide, targetPath]) => [ide, await exists(targetPath)]),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const detected = new Set();
|
|
267
|
+
for (const [ide, installed] of results) {
|
|
268
|
+
if (installed) detected.add(ide);
|
|
269
|
+
}
|
|
270
|
+
return detected;
|
|
180
271
|
}
|
|
181
272
|
|
|
182
273
|
async function runList(options) {
|
|
@@ -467,6 +558,19 @@ Execution checklist:
|
|
|
467
558
|
`;
|
|
468
559
|
}
|
|
469
560
|
|
|
561
|
+
function buildGithubCopilotInstructions() {
|
|
562
|
+
return `# Agent Flutter Copilot Instructions
|
|
563
|
+
|
|
564
|
+
This repository uses a shared local instruction pack in \`.agent-flutter\`.
|
|
565
|
+
|
|
566
|
+
Follow this order when generating code:
|
|
567
|
+
1. Read applicable files in \`.agent-flutter/rules/\`.
|
|
568
|
+
2. If task matches a skill, read \`.agent-flutter/skills/<skill>/SKILL.md\`.
|
|
569
|
+
3. Keep architecture, localization, and UI conventions aligned with the shared pack.
|
|
570
|
+
4. Update specs/docs when UI/API behavior changes.
|
|
571
|
+
`;
|
|
572
|
+
}
|
|
573
|
+
|
|
470
574
|
async function exists(filePath) {
|
|
471
575
|
try {
|
|
472
576
|
await fs.access(filePath);
|