@agentfile/cli 0.1.0

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/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ /// <reference types="node" />
3
+ import { Command } from 'commander';
4
+ import { initCommand } from './commands/init.js';
5
+ import { syncCommand } from './commands/sync.js';
6
+ import { validateCommand } from './commands/validate.js';
7
+ const program = new Command();
8
+ program
9
+ .name('agentfile')
10
+ .description('Unified AI agent contract manager')
11
+ .version('0.1.0');
12
+ program
13
+ .command('init')
14
+ .description('Scaffold a new agentfile setup in the current project')
15
+ .action(initCommand);
16
+ program
17
+ .command('sync')
18
+ .description('Generate agent instruction files from ai/contract.yaml')
19
+ .option('--dry-run', 'Render templates without writing files')
20
+ .action((options) => syncCommand({ dryRun: options.dryRun }));
21
+ program
22
+ .command('validate')
23
+ .description('Validate ai/contract.yaml schema (used in CI)')
24
+ .action(validateCommand);
25
+ program.parse();
26
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,8BAA8B;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,WAAW,EAAE,MAAU,oBAAoB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAU,oBAAoB,CAAA;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,mCAAmC,CAAC;KAChD,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,WAAW,CAAC,CAAA;AAEtB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,WAAW,EAAE,wCAAwC,CAAC;KAC7D,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAE/D,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,eAAe,CAAC,CAAA;AAE1B,OAAO,CAAC,KAAK,EAAE,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA4NA,wBAAsB,WAAW,kBA4FhC"}
@@ -0,0 +1,275 @@
1
+ /// <reference types="node" />
2
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { logger } from '../logger.js';
5
+ // ─── Scaffolding Templates ─────────────────────────────────────────────────
6
+ function contractYaml(name, stack) {
7
+ const stackList = stack.map(s => ` - ${s}`).join('\n');
8
+ return `version: 1
9
+
10
+ project:
11
+ name: ${name}
12
+ stack:
13
+ ${stackList}
14
+
15
+ rules:
16
+
17
+ coding:
18
+ - Prefer small composable functions
19
+ - Avoid unnecessary abstractions
20
+ - Write readable code before optimizing
21
+
22
+ architecture:
23
+ - Follow feature-based folder structure
24
+ - Avoid cross-feature imports
25
+
26
+ testing:
27
+ - Critical business logic must have unit tests
28
+ - Prefer integration tests over mocks
29
+
30
+ naming:
31
+ - Use descriptive variable names
32
+ - Avoid abbreviations
33
+
34
+ skills:
35
+
36
+ - name: example-skill
37
+ description: Replace this with your first shared workflow
38
+ context:
39
+ - Add any relevant file paths or conventions here
40
+ steps:
41
+ - Describe the first step
42
+ - Describe the second step
43
+ expected_output: Describe what a correct result looks like
44
+ examples:
45
+ - input: "example input"
46
+ output: "example output"
47
+ `;
48
+ }
49
+ const claudeTemplate = `# Project Instructions
50
+
51
+ **Project:** \${project.name}
52
+ **Stack:** \${project.stack.join(', ')}
53
+
54
+ ---
55
+
56
+ ## Coding Rules
57
+
58
+ \${rules.coding}
59
+
60
+ ## Architecture
61
+
62
+ \${rules.architecture}
63
+
64
+ ## Testing
65
+
66
+ \${rules.testing}
67
+
68
+ ## Naming
69
+
70
+ \${rules.naming}
71
+ \${skills}
72
+ \${override}
73
+ `;
74
+ const copilotTemplate = `# Copilot Instructions
75
+
76
+ This file configures GitHub Copilot for the **\${project.name}** project.
77
+ Stack: \${project.stack.join(', ')}
78
+
79
+ ## Coding
80
+
81
+ \${rules.coding}
82
+
83
+ ## Architecture
84
+
85
+ \${rules.architecture}
86
+
87
+ ## Testing
88
+
89
+ \${rules.testing}
90
+
91
+ ## Naming Conventions
92
+
93
+ \${rules.naming}
94
+ \${skills}
95
+ \${override}
96
+ `;
97
+ const cursorTemplate = `---
98
+ description: \${project.name} — global coding rules
99
+ globs: ["**/*"]
100
+ alwaysApply: true
101
+ ---
102
+
103
+ # \${project.name} Rules
104
+
105
+ Stack: \${project.stack.join(', ')}
106
+
107
+ ## Coding
108
+
109
+ \${rules.coding}
110
+
111
+ ## Architecture
112
+
113
+ \${rules.architecture}
114
+
115
+ ## Testing
116
+
117
+ \${rules.testing}
118
+
119
+ ## Naming
120
+
121
+ \${rules.naming}
122
+ \${override}
123
+ `;
124
+ const agentsMdTemplate = `# AGENTS.md
125
+
126
+ > This file is auto-generated by [agentfile](https://github.com/dennishavermans/agentfile).
127
+ > Edit \`ai/contract.yaml\` — do not edit this file directly.
128
+
129
+ **Project:** \${project.name}
130
+ **Stack:** \${project.stack.join(', ')}
131
+
132
+ ---
133
+
134
+ ## Coding Rules
135
+
136
+ \${rules.coding}
137
+
138
+ ## Architecture
139
+
140
+ \${rules.architecture}
141
+
142
+ ## Testing
143
+
144
+ \${rules.testing}
145
+
146
+ ## Naming
147
+
148
+ \${rules.naming}
149
+ \${skills}
150
+ \${override}
151
+ `;
152
+ const agentsExample = `# Copy this file to .ai-agents (no extension) and list the agents you use.
153
+ # This file is gitignored — it is yours, not the team's.
154
+ #
155
+ # Available agents (one per line):
156
+ # claude
157
+ # copilot
158
+ # cursor
159
+ # agents-md
160
+ `;
161
+ const gitignoreAdditions = `
162
+ # agentfile — AI agent personal config and generated files
163
+ .ai-agents
164
+ CLAUDE.md
165
+ .github/copilot-instructions.md
166
+ .cursor/
167
+ .windsurfrules
168
+ ai.override.yaml
169
+ `;
170
+ const ciWorkflow = `name: Validate AI Contract
171
+
172
+ on:
173
+ push:
174
+ paths:
175
+ - 'ai/contract.yaml'
176
+ - 'ai/agents/**'
177
+ pull_request:
178
+ paths:
179
+ - 'ai/contract.yaml'
180
+ - 'ai/agents/**'
181
+
182
+ jobs:
183
+ validate:
184
+ name: Validate AI contract
185
+ runs-on: ubuntu-latest
186
+ steps:
187
+ - uses: actions/checkout@v4
188
+ - uses: actions/setup-node@v4
189
+ with:
190
+ node-version: '20'
191
+ cache: 'npm'
192
+ - run: npm ci
193
+ - name: Validate contract schema
194
+ run: npx agentfile validate
195
+ - name: Dry-run generation
196
+ run: npx agentfile sync --dry-run
197
+ `;
198
+ // ─── File Writer ───────────────────────────────────────────────────────────
199
+ function writeIfMissing(path, content, label) {
200
+ if (existsSync(path)) {
201
+ logger.warn(`${label} already exists — skipped`);
202
+ return;
203
+ }
204
+ writeFileSync(path, content, 'utf-8');
205
+ logger.success(`Created ${label}`);
206
+ }
207
+ // ─── Init Command ──────────────────────────────────────────────────────────
208
+ export async function initCommand() {
209
+ logger.title('agentfile init');
210
+ // Dynamic import — enquirer is CJS-compat but we import at runtime only
211
+ const { default: Enquirer } = await import('enquirer');
212
+ const enquirer = new Enquirer();
213
+ const answers = await enquirer.prompt([
214
+ {
215
+ type: 'input',
216
+ name: 'name',
217
+ message: 'Project name?',
218
+ initial: 'My Project'
219
+ },
220
+ {
221
+ type: 'list',
222
+ name: 'stack',
223
+ message: 'Tech stack? (comma-separated)',
224
+ initial: 'typescript, node'
225
+ },
226
+ {
227
+ type: 'multiselect',
228
+ name: 'agents',
229
+ message: 'Which agents does your team use?',
230
+ choices: ['claude', 'copilot', 'cursor', 'agents-md']
231
+ }
232
+ ]);
233
+ const root = process.cwd();
234
+ console.log();
235
+ // ai/ directory and contract
236
+ mkdirSync(join(root, 'ai', 'agents', 'claude'), { recursive: true });
237
+ mkdirSync(join(root, 'ai', 'agents', 'copilot'), { recursive: true });
238
+ mkdirSync(join(root, 'ai', 'agents', 'cursor'), { recursive: true });
239
+ mkdirSync(join(root, 'ai', 'agents', 'agents-md'), { recursive: true });
240
+ mkdirSync(join(root, '.github', 'workflows'), { recursive: true });
241
+ writeIfMissing(join(root, 'ai', 'contract.yaml'), contractYaml(answers.name, answers.stack), 'ai/contract.yaml');
242
+ // Agent configs
243
+ const agentConfigs = {
244
+ claude: { name: 'Claude', output: 'CLAUDE.md', description: 'Anthropic Claude instruction file' },
245
+ copilot: { name: 'GitHub Copilot', output: '.github/copilot-instructions.md', description: 'GitHub Copilot workspace instruction file' },
246
+ cursor: { name: 'Cursor', output: '.cursor/rules/main.mdc', description: 'Cursor AI rules file' },
247
+ 'agents-md': { name: 'AGENTS.md', output: 'AGENTS.md', description: 'Universal agent instruction file' }
248
+ };
249
+ const templates = {
250
+ claude: claudeTemplate,
251
+ copilot: copilotTemplate,
252
+ cursor: cursorTemplate,
253
+ 'agents-md': agentsMdTemplate
254
+ };
255
+ for (const [agent, config] of Object.entries(agentConfigs)) {
256
+ const dir = join(root, 'ai', 'agents', agent);
257
+ const configYaml = `name: ${config.name}\noutput: ${config.output}\ndescription: ${config.description}\n`;
258
+ writeIfMissing(join(dir, 'config.yaml'), configYaml, `ai/agents/${agent}/config.yaml`);
259
+ writeIfMissing(join(dir, 'template.md'), templates[agent], `ai/agents/${agent}/template.md`);
260
+ }
261
+ // .ai-agents.example
262
+ writeIfMissing(join(root, '.ai-agents.example'), agentsExample, '.ai-agents.example');
263
+ // .ai-agents for this developer
264
+ if (answers.agents.length) {
265
+ writeIfMissing(join(root, '.ai-agents'), answers.agents.join('\n') + '\n', '.ai-agents (your personal agent selection)');
266
+ }
267
+ // CI workflow
268
+ writeIfMissing(join(root, '.github', 'workflows', 'ai-contract.yml'), ciWorkflow, '.github/workflows/ai-contract.yml');
269
+ // .gitignore hint
270
+ console.log();
271
+ logger.info('Add the following to your .gitignore:');
272
+ console.log(gitignoreAdditions);
273
+ logger.success('Done! Run `npx agentfile sync` to generate your agent files.\n');
274
+ }
275
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function syncCommand(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AA0BA,wBAAsB,WAAW,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,iBAsDnE"}
@@ -0,0 +1,68 @@
1
+ /// <reference types="node" />
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { generate } from '@agentfile/core';
5
+ import { logger } from '../logger.js';
6
+ const AI_AGENTS_FILE = '.ai-agents';
7
+ const AI_AGENTS_EXAMPLE = '.ai-agents.example';
8
+ function readAgents(root) {
9
+ const agentsPath = join(root, AI_AGENTS_FILE);
10
+ if (!existsSync(agentsPath)) {
11
+ logger.warn(`No ${AI_AGENTS_FILE} file found.`);
12
+ if (existsSync(join(root, AI_AGENTS_EXAMPLE))) {
13
+ logger.info(`Copy ${AI_AGENTS_EXAMPLE} to ${AI_AGENTS_FILE} and list the agents you use.`);
14
+ }
15
+ return null;
16
+ }
17
+ return readFileSync(agentsPath, 'utf-8')
18
+ .split('\n')
19
+ .map(l => l.trim())
20
+ .filter(l => l && !l.startsWith('#'));
21
+ }
22
+ export async function syncCommand(options = {}) {
23
+ const root = process.cwd();
24
+ const dryRun = options.dryRun ?? false;
25
+ logger.title(dryRun ? 'agentfile — dry run' : 'agentfile sync');
26
+ // Read agent selection
27
+ const agents = readAgents(root);
28
+ if (!agents) {
29
+ process.exit(1);
30
+ }
31
+ if (!agents.length) {
32
+ logger.error(`${AI_AGENTS_FILE} is empty. Add at least one agent name.`);
33
+ process.exit(1);
34
+ }
35
+ logger.info(`Agents: ${agents.join(', ')}\n`);
36
+ // Run generation
37
+ let result;
38
+ try {
39
+ result = generate({ root, agents, dryRun });
40
+ }
41
+ catch (err) {
42
+ logger.error(err.message);
43
+ process.exit(1);
44
+ }
45
+ // Report results
46
+ for (const r of result.results) {
47
+ if (r.status === 'ok') {
48
+ const label = dryRun ? `(dry-run) ${r.agent}` : r.agent;
49
+ logger.success(`${label} → ${r.output}`);
50
+ }
51
+ else if (r.status === 'skipped') {
52
+ logger.warn(`${r.agent} skipped — ${r.reason}`);
53
+ }
54
+ else {
55
+ logger.error(`${r.agent} — ${r.error.message}`);
56
+ }
57
+ }
58
+ console.log();
59
+ if (!result.success) {
60
+ logger.error('Sync failed. See errors above.');
61
+ process.exit(1);
62
+ }
63
+ logger.success(dryRun
64
+ ? 'Dry run passed. All templates render without errors.'
65
+ : 'All agent files generated successfully.');
66
+ console.log();
67
+ }
68
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function validateCommand(): Promise<void>;
2
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAKA,wBAAsB,eAAe,kBAsBpC"}
@@ -0,0 +1,25 @@
1
+ /// <reference types="node" />
2
+ import { join } from 'path';
3
+ import { validateContract } from '@agentfile/core';
4
+ import { logger } from '../logger.js';
5
+ export async function validateCommand() {
6
+ const root = process.cwd();
7
+ const contractPath = join(root, 'ai', 'contract.yaml');
8
+ logger.title('agentfile validate');
9
+ try {
10
+ const contract = validateContract({ contractPath });
11
+ logger.success(`contract.yaml is valid (version ${contract.version})`);
12
+ logger.success(`Project: ${contract.project.name}`);
13
+ logger.success(`Stack: ${contract.project.stack.join(', ')}`);
14
+ const ruleCount = Object.values(contract.rules)
15
+ .reduce((sum, rules) => sum + rules.length, 0);
16
+ logger.success(`Rules: ${ruleCount} total across ${Object.keys(contract.rules).length} categories`);
17
+ console.log();
18
+ }
19
+ catch (err) {
20
+ logger.error(err.message);
21
+ console.log();
22
+ process.exit(1);
23
+ }
24
+ }
25
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,IAAI,GAAW,OAAO,CAAC,GAAG,EAAE,CAAA;IAClC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAA;IAEtD,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAA;IAElC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;QACnD,MAAM,CAAC,OAAO,CAAC,mCAAmC,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAA;QACtE,MAAM,CAAC,OAAO,CAAC,YAAY,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;QACnD,MAAM,CAAC,OAAO,CAAC,YAAY,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE/D,MAAM,SAAS,GAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAgB;aAC5D,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QAEhD,MAAM,CAAC,OAAO,CAAC,YAAY,SAAS,iBAAiB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,aAAa,CAAC,CAAA;QACrG,OAAO,CAAC,GAAG,EAAE,CAAA;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAE,GAAa,CAAC,OAAO,CAAC,CAAA;QACpC,OAAO,CAAC,GAAG,EAAE,CAAA;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const logger: {
2
+ info: (msg: string) => void;
3
+ success: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ title: (msg: string) => void;
7
+ divider: () => void;
8
+ };
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM;gBACF,MAAM;mBACN,MAAM;gBACN,MAAM;iBACN,MAAM;iBACN,MAAM;;CAEtB,CAAA"}
package/dist/logger.js ADDED
@@ -0,0 +1,11 @@
1
+ /// <reference types="node" />
2
+ import chalk from 'chalk';
3
+ export const logger = {
4
+ info: (msg) => console.log(` ${msg}`),
5
+ success: (msg) => console.log(`${chalk.green('✔')} ${msg}`),
6
+ warn: (msg) => console.log(`${chalk.yellow('⚠')} ${msg}`),
7
+ error: (msg) => console.log(`${chalk.red('✘')} ${msg}`),
8
+ title: (msg) => console.log(`\n${chalk.bold.cyan(msg)}\n`),
9
+ divider: () => console.log(chalk.gray('─'.repeat(40)))
10
+ };
11
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAK,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,CAAC;IACjD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACnE,IAAI,EAAK,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACpE,KAAK,EAAI,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACjE,KAAK,EAAI,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACpE,OAAO,EAAE,GAAc,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;CAClE,CAAA"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@agentfile/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for agentfile — init, sync, and validate AI agent contracts",
5
+ "type": "module",
6
+ "bin": {
7
+ "agentfile": "./dist/bin.js"
8
+ },
9
+ "files": ["dist"],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "typecheck": "tsc --noEmit",
13
+ "test": "vitest run",
14
+ "dev": "tsx src/bin.ts"
15
+ },
16
+ "keywords": ["ai", "agents", "cli", "rules", "claude", "copilot", "cursor", "agentfile"],
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/dennishavermans/agentfile"
21
+ },
22
+ "homepage": "https://github.com/dennishavermans/agentfile#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/dennishavermans/agentfile/issues"
25
+ },
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "dependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@agentfile/core": "^0.1.0",
35
+ "chalk": "^5.3.0",
36
+ "commander": "^12.0.0",
37
+ "enquirer": "^2.4.1"
38
+ },
39
+ "devDependencies": {
40
+ "tsx": "^4.7.0",
41
+ "typescript": "^5.3.0",
42
+ "vitest": "^4.1.0"
43
+ }
44
+ }