flight-rules 0.5.9

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.
Files changed (35) hide show
  1. package/README.md +270 -0
  2. package/dist/commands/adapter.d.ts +35 -0
  3. package/dist/commands/adapter.js +308 -0
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.js +197 -0
  6. package/dist/commands/upgrade.d.ts +1 -0
  7. package/dist/commands/upgrade.js +255 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +83 -0
  10. package/dist/utils/files.d.ts +75 -0
  11. package/dist/utils/files.js +245 -0
  12. package/dist/utils/interactive.d.ts +5 -0
  13. package/dist/utils/interactive.js +7 -0
  14. package/package.json +52 -0
  15. package/payload/.editorconfig +15 -0
  16. package/payload/AGENTS.md +247 -0
  17. package/payload/commands/dev-session.end.md +79 -0
  18. package/payload/commands/dev-session.start.md +54 -0
  19. package/payload/commands/impl.create.md +178 -0
  20. package/payload/commands/impl.outline.md +120 -0
  21. package/payload/commands/prd.clarify.md +139 -0
  22. package/payload/commands/prd.create.md +154 -0
  23. package/payload/commands/test.add.md +73 -0
  24. package/payload/commands/test.assess-current.md +75 -0
  25. package/payload/doc-templates/critical-learnings.md +21 -0
  26. package/payload/doc-templates/implementation/overview.md +27 -0
  27. package/payload/doc-templates/prd.md +49 -0
  28. package/payload/doc-templates/progress.md +19 -0
  29. package/payload/doc-templates/session-log.md +62 -0
  30. package/payload/doc-templates/tech-stack.md +101 -0
  31. package/payload/prompts/.gitkeep +0 -0
  32. package/payload/prompts/implementation/README.md +26 -0
  33. package/payload/prompts/implementation/plan-review.md +80 -0
  34. package/payload/prompts/prd/README.md +46 -0
  35. package/payload/prompts/prd/creation-conversational.md +46 -0
@@ -0,0 +1,197 @@
1
+ import * as p from '@clack/prompts';
2
+ import pc from 'picocolors';
3
+ import { isFlightRulesInstalled, fetchPayloadFromGitHub, copyPayloadFrom, getFlightRulesDir, ensureDir, writeManifest, getCliVersion } from '../utils/files.js';
4
+ import { isInteractive } from '../utils/interactive.js';
5
+ import { cpSync, existsSync } from 'fs';
6
+ import { join } from 'path';
7
+ const DOC_FILES = [
8
+ { src: 'prd.md', dest: 'prd.md' },
9
+ { src: 'progress.md', dest: 'progress.md' },
10
+ { src: 'critical-learnings.md', dest: 'critical-learnings.md' },
11
+ { src: 'implementation/overview.md', dest: 'implementation/overview.md' },
12
+ { src: 'tech-stack.md', dest: 'tech-stack.md' },
13
+ ];
14
+ async function copyDocsFromTemplates(templatesDir, docsDir, skipExisting) {
15
+ ensureDir(docsDir);
16
+ ensureDir(join(docsDir, 'implementation'));
17
+ ensureDir(join(docsDir, 'session_logs'));
18
+ for (const file of DOC_FILES) {
19
+ const srcPath = join(templatesDir, file.src);
20
+ const destPath = join(docsDir, file.dest);
21
+ if (!existsSync(srcPath))
22
+ continue;
23
+ if (skipExisting && existsSync(destPath)) {
24
+ continue;
25
+ }
26
+ cpSync(srcPath, destPath);
27
+ }
28
+ }
29
+ export async function init() {
30
+ const cwd = process.cwd();
31
+ const interactive = isInteractive();
32
+ // Check if already installed
33
+ if (isFlightRulesInstalled(cwd)) {
34
+ if (interactive) {
35
+ const shouldContinue = await p.confirm({
36
+ message: 'Flight Rules is already installed. Do you want to reinstall? (This will overwrite existing files)',
37
+ initialValue: false,
38
+ });
39
+ if (p.isCancel(shouldContinue) || !shouldContinue) {
40
+ p.log.info('Installation cancelled.');
41
+ p.outro('Run `flight-rules upgrade` to update framework files while preserving your docs.');
42
+ return;
43
+ }
44
+ }
45
+ else {
46
+ // Non-interactive: skip reinstall (safe default)
47
+ p.log.info('Flight Rules is already installed. Skipping reinstall.');
48
+ p.outro('Run `flight-rules upgrade` to update framework files while preserving your docs.');
49
+ return;
50
+ }
51
+ }
52
+ const spinner = p.spinner();
53
+ // Fetch from GitHub
54
+ spinner.start('Fetching latest Flight Rules from GitHub...');
55
+ let fetched;
56
+ try {
57
+ fetched = await fetchPayloadFromGitHub();
58
+ spinner.stop(`Found Flight Rules version ${pc.cyan(fetched.version)}`);
59
+ }
60
+ catch (error) {
61
+ spinner.stop('Failed to fetch from GitHub');
62
+ if (error instanceof Error) {
63
+ p.log.error(error.message);
64
+ }
65
+ p.outro('Check your network connection and try again.');
66
+ return;
67
+ }
68
+ // Copy payload
69
+ spinner.start('Installing Flight Rules...');
70
+ try {
71
+ copyPayloadFrom(fetched.payloadPath, cwd);
72
+ // Write manifest to track deployed version
73
+ writeManifest(cwd, {
74
+ version: fetched.version,
75
+ deployedAt: new Date().toISOString(),
76
+ deployedBy: {
77
+ cli: getCliVersion(),
78
+ command: 'init',
79
+ },
80
+ });
81
+ spinner.stop('Flight Rules installed!');
82
+ }
83
+ catch (error) {
84
+ spinner.stop('Failed to install Flight Rules');
85
+ fetched.cleanup();
86
+ throw error;
87
+ }
88
+ fetched.cleanup();
89
+ // Ask about initializing docs
90
+ let initDocs;
91
+ if (interactive) {
92
+ const initDocsResult = await p.confirm({
93
+ message: 'Would you like to initialize project docs from templates?',
94
+ initialValue: true,
95
+ });
96
+ if (p.isCancel(initDocsResult)) {
97
+ p.outro('Flight Rules installed. Run `flight-rules adapter` to generate agent adapters.');
98
+ return;
99
+ }
100
+ initDocs = initDocsResult;
101
+ }
102
+ else {
103
+ // Non-interactive: default to yes (create docs)
104
+ initDocs = true;
105
+ }
106
+ if (initDocs) {
107
+ const flightRulesDir = getFlightRulesDir(cwd);
108
+ const templatesDir = join(flightRulesDir, 'doc-templates');
109
+ const docsDir = join(cwd, 'docs');
110
+ // Check if docs directory already exists with content
111
+ const docsExist = existsSync(docsDir);
112
+ let skipExisting = false;
113
+ if (docsExist) {
114
+ if (interactive) {
115
+ const handleExisting = await p.select({
116
+ message: 'A docs/ directory already exists. How would you like to proceed?',
117
+ options: [
118
+ { value: 'skip', label: 'Skip existing files', hint: 'only create missing files' },
119
+ { value: 'overwrite', label: 'Overwrite existing files' },
120
+ { value: 'cancel', label: 'Cancel docs initialization' },
121
+ ],
122
+ });
123
+ if (p.isCancel(handleExisting) || handleExisting === 'cancel') {
124
+ p.log.info('Skipped docs initialization.');
125
+ }
126
+ else {
127
+ skipExisting = handleExisting === 'skip';
128
+ await copyDocsFromTemplates(templatesDir, docsDir, skipExisting);
129
+ p.log.success('Project docs initialized from templates.');
130
+ }
131
+ }
132
+ else {
133
+ // Non-interactive: skip existing files (safe default)
134
+ skipExisting = true;
135
+ await copyDocsFromTemplates(templatesDir, docsDir, skipExisting);
136
+ p.log.success('Project docs initialized from templates (skipped existing files).');
137
+ }
138
+ }
139
+ else {
140
+ await copyDocsFromTemplates(templatesDir, docsDir, false);
141
+ p.log.success('Project docs initialized from templates.');
142
+ }
143
+ }
144
+ // Ask about generating adapters
145
+ if (interactive) {
146
+ const generateAdaptersResult = await p.confirm({
147
+ message: 'Would you like to generate agent adapter files?',
148
+ initialValue: true,
149
+ });
150
+ if (p.isCancel(generateAdaptersResult)) {
151
+ p.outro('Done! Your project now has Flight Rules.');
152
+ return;
153
+ }
154
+ if (generateAdaptersResult) {
155
+ const adapters = await p.multiselect({
156
+ message: 'Which adapters would you like to generate?',
157
+ options: [
158
+ { value: 'cursor', label: 'Cursor (AGENTS.md + .cursor/commands/)', hint: 'recommended' },
159
+ { value: 'claude', label: 'Claude Code (CLAUDE.md + .claude/commands/)' },
160
+ ],
161
+ initialValues: ['cursor'],
162
+ });
163
+ if (p.isCancel(adapters)) {
164
+ p.outro('Done! Your project now has Flight Rules.');
165
+ return;
166
+ }
167
+ // Import and run adapter generation
168
+ const { generateAdapters: genAdapters } = await import('./adapter.js');
169
+ await genAdapters(adapters);
170
+ }
171
+ }
172
+ else {
173
+ // Non-interactive: skip adapter generation (user can run `flight-rules adapter` separately)
174
+ p.log.info('Skipping adapter generation. Run `flight-rules adapter --cursor` or `--claude` to generate adapters.');
175
+ }
176
+ // Ask about installing .editorconfig
177
+ const editorConfigPath = join(cwd, '.editorconfig');
178
+ const editorConfigExists = existsSync(editorConfigPath);
179
+ if (!editorConfigExists) {
180
+ if (interactive) {
181
+ const installEditorConfig = await p.confirm({
182
+ message: 'Would you like to add a standard .editorconfig? (helps prevent formatting diffs)',
183
+ initialValue: true,
184
+ });
185
+ if (!p.isCancel(installEditorConfig) && installEditorConfig) {
186
+ const flightRulesDir = getFlightRulesDir(cwd);
187
+ const srcEditorConfig = join(flightRulesDir, '.editorconfig');
188
+ if (existsSync(srcEditorConfig)) {
189
+ cpSync(srcEditorConfig, editorConfigPath);
190
+ p.log.success('Added .editorconfig to project root.');
191
+ }
192
+ }
193
+ }
194
+ // Non-interactive: skip .editorconfig installation (safe default)
195
+ }
196
+ p.outro(pc.green('Flight Rules is ready! Start with: "start coding session"'));
197
+ }
@@ -0,0 +1 @@
1
+ export declare function upgrade(version?: string): Promise<void>;
@@ -0,0 +1,255 @@
1
+ import * as p from '@clack/prompts';
2
+ import pc from 'picocolors';
3
+ import { existsSync, cpSync } from 'fs';
4
+ import { join } from 'path';
5
+ import { isFlightRulesInstalled, fetchPayloadFromGitHub, copyFrameworkFilesFrom, ensureDir, getInstalledVersion, writeManifest, getCliVersion } from '../utils/files.js';
6
+ import { isInteractive } from '../utils/interactive.js';
7
+ import { isCursorAdapterInstalled, isClaudeAdapterInstalled, setupCursorCommands, setupClaudeCommands, } from './adapter.js';
8
+ const DOC_FILES = [
9
+ { src: 'prd.md', dest: 'prd.md' },
10
+ { src: 'progress.md', dest: 'progress.md' },
11
+ { src: 'critical-learnings.md', dest: 'critical-learnings.md' },
12
+ { src: 'implementation/overview.md', dest: 'implementation/overview.md' },
13
+ { src: 'tech-stack.md', dest: 'tech-stack.md' },
14
+ ];
15
+ /**
16
+ * Copy new doc templates to docs/ without overwriting existing files.
17
+ * Returns the list of files that were copied.
18
+ */
19
+ function copyNewDocsFromTemplates(templatesDir, docsDir) {
20
+ ensureDir(docsDir);
21
+ ensureDir(join(docsDir, 'implementation'));
22
+ ensureDir(join(docsDir, 'session_logs'));
23
+ const copied = [];
24
+ for (const file of DOC_FILES) {
25
+ const srcPath = join(templatesDir, file.src);
26
+ const destPath = join(docsDir, file.dest);
27
+ if (!existsSync(srcPath))
28
+ continue;
29
+ // Only copy if destination doesn't exist
30
+ if (!existsSync(destPath)) {
31
+ cpSync(srcPath, destPath);
32
+ copied.push(file.dest);
33
+ }
34
+ }
35
+ return copied;
36
+ }
37
+ export async function upgrade(version) {
38
+ const cwd = process.cwd();
39
+ // Check if Flight Rules is installed
40
+ if (!isFlightRulesInstalled(cwd)) {
41
+ p.log.error('Flight Rules is not installed in this directory.');
42
+ p.outro('Run `flight-rules init` to install Flight Rules first.');
43
+ return;
44
+ }
45
+ // Get current installed version
46
+ const currentVersion = getInstalledVersion(cwd);
47
+ // Detect installed adapters before upgrade
48
+ const cursorAdapterInstalled = isCursorAdapterInstalled(cwd);
49
+ const claudeAdapterInstalled = isClaudeAdapterInstalled(cwd);
50
+ const agentsMdExists = existsSync(join(cwd, 'AGENTS.md'));
51
+ const claudeMdExists = existsSync(join(cwd, 'CLAUDE.md'));
52
+ // Show what will be upgraded
53
+ p.log.info(`${pc.bold('The .flight-rules/ directory will be upgraded.')}`);
54
+ p.log.message(' Framework files (AGENTS.md, doc-templates/, commands/, prompts/) will be replaced.');
55
+ console.log();
56
+ // Show adapter upgrade info
57
+ const adaptersToUpgrade = [];
58
+ if (cursorAdapterInstalled) {
59
+ adaptersToUpgrade.push('Cursor (.cursor/commands/)');
60
+ }
61
+ if (claudeAdapterInstalled) {
62
+ adaptersToUpgrade.push('Claude Code (.claude/commands/)');
63
+ }
64
+ else if (claudeMdExists) {
65
+ // CLAUDE.md exists but .claude/commands/ doesn't - will be created on upgrade
66
+ adaptersToUpgrade.push('Claude Code (.claude/commands/ will be created)');
67
+ }
68
+ if (agentsMdExists) {
69
+ adaptersToUpgrade.push('AGENTS.md');
70
+ }
71
+ if (claudeMdExists && !adaptersToUpgrade.some(a => a.includes('Claude Code'))) {
72
+ adaptersToUpgrade.push('CLAUDE.md');
73
+ }
74
+ if (adaptersToUpgrade.length > 0) {
75
+ p.log.info(`${pc.bold('Installed adapters will also be upgraded:')}`);
76
+ p.log.message(` ${adaptersToUpgrade.join(', ')}`);
77
+ console.log();
78
+ }
79
+ p.log.info(`${pc.bold('Your project content will be preserved.')}`);
80
+ p.log.message(' New templates may be added to docs/, but existing files are never modified.');
81
+ console.log();
82
+ const spinner = p.spinner();
83
+ // Fetch from GitHub
84
+ spinner.start(version ? `Fetching Flight Rules ${version} from GitHub...` : 'Fetching latest Flight Rules from GitHub...');
85
+ let fetched;
86
+ try {
87
+ fetched = await fetchPayloadFromGitHub(version);
88
+ spinner.stop(`Found Flight Rules version ${pc.cyan(fetched.version)}`);
89
+ }
90
+ catch (error) {
91
+ spinner.stop('Failed to fetch from GitHub');
92
+ if (error instanceof Error) {
93
+ p.log.error(error.message);
94
+ }
95
+ p.outro('Check your network connection and try again.');
96
+ return;
97
+ }
98
+ // Show version comparison
99
+ if (currentVersion) {
100
+ p.log.info(`Current version: ${pc.yellow(currentVersion)} → ${pc.cyan(fetched.version)}`);
101
+ }
102
+ if (isInteractive()) {
103
+ const shouldContinue = await p.confirm({
104
+ message: `Upgrade to version ${fetched.version}?`,
105
+ initialValue: true,
106
+ });
107
+ if (p.isCancel(shouldContinue) || !shouldContinue) {
108
+ fetched.cleanup();
109
+ p.log.info('Upgrade cancelled.');
110
+ return;
111
+ }
112
+ }
113
+ else {
114
+ // Non-interactive: proceed with upgrade
115
+ p.log.info(`Upgrading to version ${fetched.version}...`);
116
+ }
117
+ // Upgrade .flight-rules/
118
+ spinner.start('Upgrading Flight Rules...');
119
+ try {
120
+ copyFrameworkFilesFrom(fetched.payloadPath, cwd);
121
+ // Write manifest to track deployed version
122
+ writeManifest(cwd, {
123
+ version: fetched.version,
124
+ deployedAt: new Date().toISOString(),
125
+ deployedBy: {
126
+ cli: getCliVersion(),
127
+ command: 'upgrade',
128
+ },
129
+ });
130
+ spinner.stop('Flight Rules framework upgraded!');
131
+ }
132
+ catch (error) {
133
+ spinner.stop('Failed to upgrade Flight Rules');
134
+ fetched.cleanup();
135
+ throw error;
136
+ }
137
+ p.log.success('Framework files have been updated.');
138
+ // Add new doc templates to docs/ (without overwriting existing files)
139
+ const templatesDir = join(fetched.payloadPath, 'doc-templates');
140
+ const docsDir = join(cwd, 'docs');
141
+ const newDocs = copyNewDocsFromTemplates(templatesDir, docsDir);
142
+ if (newDocs.length > 0) {
143
+ p.log.success(`Added ${newDocs.length} new template(s) to docs/: ${newDocs.join(', ')}`);
144
+ }
145
+ // Upgrade installed adapters
146
+ if (adaptersToUpgrade.length > 0) {
147
+ spinner.start('Upgrading adapters...');
148
+ try {
149
+ const sourceCommandsDir = join(fetched.payloadPath, 'commands');
150
+ // Upgrade Cursor commands if installed
151
+ if (cursorAdapterInstalled) {
152
+ const result = await setupCursorCommands(cwd, sourceCommandsDir, true); // skipPrompts = true for upgrade
153
+ if (result.copied.length > 0) {
154
+ p.log.success(`Updated ${result.copied.length} command(s) in .cursor/commands/`);
155
+ }
156
+ }
157
+ // Upgrade Claude commands if installed, or create them if CLAUDE.md exists but .claude/commands/ doesn't
158
+ // (handles upgrade from pre-0.5.4 where Claude didn't have native commands)
159
+ if (claudeAdapterInstalled || claudeMdExists) {
160
+ const result = await setupClaudeCommands(cwd, sourceCommandsDir, true); // skipPrompts = true for upgrade
161
+ if (result.copied.length > 0) {
162
+ const action = claudeAdapterInstalled ? 'Updated' : 'Created';
163
+ p.log.success(`${action} ${result.copied.length} command(s) in .claude/commands/`);
164
+ }
165
+ }
166
+ // Regenerate adapter files
167
+ const adaptersToRegenerate = [];
168
+ if (agentsMdExists) {
169
+ adaptersToRegenerate.push('cursor');
170
+ }
171
+ if (claudeMdExists) {
172
+ adaptersToRegenerate.push('claude');
173
+ }
174
+ if (adaptersToRegenerate.length > 0) {
175
+ // For upgrade, we regenerate silently (the files already exist, so we just overwrite)
176
+ for (const adapterName of adaptersToRegenerate) {
177
+ await regenerateAdapterFile(cwd, adapterName, sourceCommandsDir);
178
+ }
179
+ }
180
+ spinner.stop('Adapters upgraded!');
181
+ }
182
+ catch (error) {
183
+ spinner.stop('Failed to upgrade adapters');
184
+ fetched.cleanup();
185
+ throw error;
186
+ }
187
+ }
188
+ fetched.cleanup();
189
+ p.outro(pc.green('Upgrade complete!'));
190
+ }
191
+ /**
192
+ * Regenerate a single adapter file during upgrade (no prompts, just overwrite)
193
+ */
194
+ async function regenerateAdapterFile(cwd, adapterName, _sourceCommandsDir) {
195
+ // Import the adapter config and content generator
196
+ const { writeFileSync } = await import('fs');
197
+ const { join } = await import('path');
198
+ const ADAPTERS = {
199
+ cursor: {
200
+ filename: 'AGENTS.md',
201
+ title: 'Flight Rules – Cursor Adapter',
202
+ description: 'This file is placed at the project root as `AGENTS.md` for Cursor compatibility.',
203
+ hasNativeCommands: true,
204
+ commandsDirectory: '.cursor/commands',
205
+ },
206
+ claude: {
207
+ filename: 'CLAUDE.md',
208
+ title: 'Flight Rules – Claude Code Adapter',
209
+ description: 'This file is placed at the project root as `CLAUDE.md` for Claude Code compatibility.',
210
+ hasNativeCommands: true,
211
+ commandsDirectory: '.claude/commands',
212
+ },
213
+ };
214
+ const config = ADAPTERS[adapterName];
215
+ if (!config)
216
+ return;
217
+ const commandLocation = config.hasNativeCommands && config.commandsDirectory
218
+ ? `\`${config.commandsDirectory}/\` (as slash commands)`
219
+ : `\`.flight-rules/commands/\``;
220
+ const commandInstructions = config.hasNativeCommands
221
+ ? `Use the \`/dev-session.start\` and \`/dev-session.end\` slash commands.`
222
+ : `When the user says "start coding session" or "end coding session", follow the instructions in \`.flight-rules/commands/\`.`;
223
+ const content = `# ${config.title}
224
+
225
+ ${config.description}
226
+
227
+ ---
228
+
229
+ **This project uses Flight Rules.**
230
+
231
+ Agent guidelines and workflows live in \`.flight-rules/\`. Project documentation lives in \`docs/\`.
232
+
233
+ ## Quick Reference
234
+
235
+ | What | Where |
236
+ |------|-------|
237
+ | Agent Guidelines | \`.flight-rules/AGENTS.md\` |
238
+ | PRD | \`docs/prd.md\` |
239
+ | Implementation Specs | \`docs/implementation/\` |
240
+ | Progress Log | \`docs/progress.md\` |
241
+ | Session Commands | ${commandLocation} |
242
+
243
+ ## For Agents
244
+
245
+ Please read \`.flight-rules/AGENTS.md\` for complete guidelines on:
246
+ - Project structure
247
+ - Implementation specs
248
+ - Coding sessions
249
+ - How to work with this system
250
+
251
+ ${commandInstructions}
252
+ `;
253
+ const filePath = join(cwd, config.filename);
254
+ writeFileSync(filePath, content, 'utf-8');
255
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ import * as p from '@clack/prompts';
3
+ import pc from 'picocolors';
4
+ import { init } from './commands/init.js';
5
+ import { upgrade } from './commands/upgrade.js';
6
+ import { adapter } from './commands/adapter.js';
7
+ import { getCliVersion } from './utils/files.js';
8
+ const command = process.argv[2];
9
+ const args = process.argv.slice(3);
10
+ /**
11
+ * Parse --version flag from args, returning the version value if present
12
+ */
13
+ function parseVersionArg(args) {
14
+ const versionIndex = args.findIndex(arg => arg === '--version' || arg === '-V');
15
+ if (versionIndex !== -1 && args[versionIndex + 1]) {
16
+ return args[versionIndex + 1];
17
+ }
18
+ // Also support --version=0.1.4 format
19
+ const versionArg = args.find(arg => arg.startsWith('--version='));
20
+ if (versionArg) {
21
+ return versionArg.split('=')[1];
22
+ }
23
+ return undefined;
24
+ }
25
+ async function main() {
26
+ // Handle --version early, without intro banner
27
+ if (command === '--version' || command === '-v') {
28
+ console.log(getCliVersion());
29
+ return;
30
+ }
31
+ console.log();
32
+ p.intro(pc.bgCyan(pc.black(' flight-rules ')));
33
+ switch (command) {
34
+ case 'init':
35
+ await init();
36
+ break;
37
+ case 'upgrade':
38
+ const version = parseVersionArg(args);
39
+ await upgrade(version);
40
+ break;
41
+ case 'adapter':
42
+ await adapter(args);
43
+ break;
44
+ case undefined:
45
+ case '--help':
46
+ case '-h':
47
+ showHelp();
48
+ break;
49
+ default:
50
+ p.log.error(`Unknown command: ${command}`);
51
+ showHelp();
52
+ process.exit(1);
53
+ }
54
+ }
55
+ function showHelp() {
56
+ console.log(`
57
+ ${pc.bold('Usage:')} flight-rules <command> [options]
58
+
59
+ ${pc.bold('Commands:')}
60
+ init Install Flight Rules into the current project
61
+ upgrade Upgrade Flight Rules (preserves your docs)
62
+ adapter Generate agent-specific adapter files
63
+
64
+ ${pc.bold('Upgrade Options:')}
65
+ --version <version> Upgrade to a specific version (e.g., 0.1.4)
66
+ Defaults to latest from main branch
67
+
68
+ ${pc.bold('Adapter Options:')}
69
+ --cursor Generate AGENTS.md for Cursor
70
+ --claude Generate CLAUDE.md for Claude Code
71
+ --all Generate all adapters
72
+
73
+ ${pc.bold('Examples:')}
74
+ flight-rules init
75
+ flight-rules upgrade
76
+ flight-rules upgrade --version 0.1.4
77
+ flight-rules adapter --cursor --claude
78
+ `);
79
+ }
80
+ main().catch((err) => {
81
+ p.log.error(err.message);
82
+ process.exit(1);
83
+ });
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Get the CLI version from package.json
3
+ */
4
+ export declare function getCliVersion(): string;
5
+ /**
6
+ * Get the path to the payload directory (the Flight Rules content to install)
7
+ */
8
+ export declare function getPayloadPath(): string;
9
+ /**
10
+ * Check if Flight Rules is already installed in the target directory
11
+ */
12
+ export declare function isFlightRulesInstalled(targetDir: string): boolean;
13
+ /**
14
+ * Get the .flight-rules directory path in the target
15
+ */
16
+ export declare function getFlightRulesDir(targetDir: string): string;
17
+ /**
18
+ * Copy the payload to the target directory as .flight-rules
19
+ */
20
+ export declare function copyPayload(targetDir: string): void;
21
+ /**
22
+ * Copy only framework files (not docs/) during upgrade
23
+ */
24
+ export declare function copyFrameworkFiles(targetDir: string): void;
25
+ /**
26
+ * Ensure a directory exists
27
+ */
28
+ export declare function ensureDir(dir: string): void;
29
+ /**
30
+ * Result of fetching payload from GitHub
31
+ */
32
+ export interface FetchedPayload {
33
+ payloadPath: string;
34
+ version: string;
35
+ cleanup: () => void;
36
+ }
37
+ /**
38
+ * Fetch the Flight Rules payload from GitHub
39
+ * @param version - Git ref to fetch (tag like 'v0.1.4', branch like 'main', or 'latest' for main)
40
+ * @returns Object with payloadPath, version string, and cleanup function
41
+ */
42
+ export declare function fetchPayloadFromGitHub(version?: string): Promise<FetchedPayload>;
43
+ /**
44
+ * Copy framework files from a source payload directory (used by both local and remote)
45
+ */
46
+ export declare function copyFrameworkFilesFrom(sourcePayloadPath: string, targetDir: string): void;
47
+ /**
48
+ * Copy entire payload from a source directory (used by both local and remote)
49
+ */
50
+ export declare function copyPayloadFrom(sourcePayloadPath: string, targetDir: string): void;
51
+ /**
52
+ * Manifest file structure for tracking deployed Flight Rules version
53
+ */
54
+ export interface Manifest {
55
+ version: string;
56
+ deployedAt: string;
57
+ deployedBy: {
58
+ cli: string;
59
+ command: 'init' | 'upgrade';
60
+ };
61
+ }
62
+ /**
63
+ * Read the manifest.json from a Flight Rules installation
64
+ * @returns The manifest data, or null if not found
65
+ */
66
+ export declare function readManifest(targetDir: string): Manifest | null;
67
+ /**
68
+ * Write the manifest.json to a Flight Rules installation
69
+ */
70
+ export declare function writeManifest(targetDir: string, data: Manifest): void;
71
+ /**
72
+ * Get the current version from manifest, falling back to AGENTS.md
73
+ * @returns The version string, or null if not found
74
+ */
75
+ export declare function getInstalledVersion(targetDir: string): string | null;