clavix 5.1.0 → 5.2.1

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 (44) hide show
  1. package/README.md +21 -3
  2. package/dist/cli/commands/config.d.ts +1 -3
  3. package/dist/cli/commands/config.js +4 -13
  4. package/dist/cli/commands/diagnose.d.ts +15 -0
  5. package/dist/cli/commands/diagnose.js +295 -0
  6. package/dist/core/adapters/agents-md-generator.d.ts +0 -10
  7. package/dist/core/adapters/agents-md-generator.js +7 -41
  8. package/dist/core/adapters/copilot-instructions-generator.d.ts +0 -10
  9. package/dist/core/adapters/copilot-instructions-generator.js +7 -41
  10. package/dist/core/adapters/gemini-adapter.d.ts +2 -18
  11. package/dist/core/adapters/gemini-adapter.js +7 -46
  12. package/dist/core/adapters/llxprt-adapter.d.ts +2 -18
  13. package/dist/core/adapters/llxprt-adapter.js +7 -46
  14. package/dist/core/adapters/octo-md-generator.d.ts +0 -10
  15. package/dist/core/adapters/octo-md-generator.js +7 -41
  16. package/dist/core/adapters/qwen-adapter.d.ts +2 -18
  17. package/dist/core/adapters/qwen-adapter.js +7 -46
  18. package/dist/core/adapters/toml-formatting-adapter.d.ts +50 -0
  19. package/dist/core/adapters/toml-formatting-adapter.js +74 -0
  20. package/dist/core/adapters/warp-md-generator.d.ts +3 -4
  21. package/dist/core/adapters/warp-md-generator.js +10 -30
  22. package/dist/core/doc-injector.js +4 -5
  23. package/dist/templates/agents/agents.md +8 -2
  24. package/dist/templates/agents/copilot-instructions.md +6 -2
  25. package/dist/templates/agents/octo.md +6 -2
  26. package/dist/templates/agents/warp.md +6 -2
  27. package/dist/templates/slash-commands/_canonical/archive.md +4 -7
  28. package/dist/templates/slash-commands/_canonical/implement.md +4 -7
  29. package/dist/templates/slash-commands/_canonical/improve.md +4 -7
  30. package/dist/templates/slash-commands/_canonical/plan.md +4 -7
  31. package/dist/templates/slash-commands/_canonical/prd.md +4 -7
  32. package/dist/templates/slash-commands/_canonical/start.md +3 -6
  33. package/dist/templates/slash-commands/_canonical/summarize.md +3 -6
  34. package/dist/templates/slash-commands/_canonical/verify.md +4 -7
  35. package/dist/templates/slash-commands/_components/agent-protocols/AGENT_MANUAL.md +284 -0
  36. package/dist/types/agent.d.ts +0 -4
  37. package/dist/types/config.d.ts +0 -80
  38. package/dist/types/config.js +1 -1
  39. package/dist/utils/agent-error-messages.d.ts +5 -5
  40. package/dist/utils/agent-error-messages.js +5 -5
  41. package/dist/utils/error-utils.d.ts +1 -7
  42. package/dist/utils/error-utils.js +12 -11
  43. package/dist/utils/toml-templates.js +4 -1
  44. package/package.json +3 -8
package/README.md CHANGED
@@ -12,7 +12,8 @@
12
12
 
13
13
  | Version | Highlights | Details |
14
14
  | --- | --- | --- |
15
- | **v5.0.0** (Latest) | Agentic-first architecture - lean template delivery | [Changelog](CHANGELOG.md#500---2025-01-27) |
15
+ | **v5.2.0** (Latest) | Diagnose command, DRY architecture, feature matrix | [Changelog](CHANGELOG.md) |
16
+ | **v5.0.0** | Agentic-first architecture - lean template delivery | [Changelog](CHANGELOG.md#500---2025-01-27) |
16
17
  | **v4.12.0** | Final v4 release with full CLI commands | [Changelog](docs/archive/v4-changelog.md) |
17
18
 
18
19
  **Requirements:** Node.js >= 18.0.0
@@ -49,6 +50,15 @@ Clavix v5 follows an **agentic-first architecture**:
49
50
  | CLI agents | Claude Code, Droid CLI, CodeBuddy CLI, OpenCode, Gemini CLI, Qwen Code, LLXPRT, Amp, Crush CLI, Codex CLI, Augment CLI |
50
51
  | Universal adapters | AGENTS.md, GitHub Copilot, OCTO.md, WARP.md |
51
52
 
53
+ ### Feature Matrix
54
+
55
+ | Feature | Claude Code | Cursor/Windsurf | Gemini/Qwen | Generic Agents |
56
+ |---------|-------------|-----------------|-------------|----------------|
57
+ | Slash commands | ✅ Native | ✅ Native | ✅ TOML | ❌ Read-only |
58
+ | Doc injection | ✅ CLAUDE.md | ✅ .cursor/rules | ✅ N/A | ✅ AGENTS.md |
59
+ | Namespace dirs | ✅ clavix/ | ✅ clavix/ | ✅ clavix/ | N/A |
60
+ | Auto-detection | ✅ Yes | ✅ Yes | ✅ Yes | N/A |
61
+
52
62
  Full list and configuration: [docs/integrations.md](docs/integrations.md)
53
63
 
54
64
  ## Quickstart
@@ -77,6 +87,7 @@ The AI agent reads the improve template and:
77
87
 
78
88
  ### 3. Choose Your Workflow
79
89
 
90
+ **Core Workflows:**
80
91
  | Command | When to Use |
81
92
  |---------|-------------|
82
93
  | `/clavix:improve` | Optimize a single prompt (auto-selects depth) |
@@ -84,7 +95,13 @@ The AI agent reads the improve template and:
84
95
  | `/clavix:start` | Explore ideas conversationally first |
85
96
  | `/clavix:plan` | Generate tasks from a PRD |
86
97
  | `/clavix:implement` | Execute tasks with progress tracking |
87
- | `/clavix:archive` | Archive completed projects |
98
+ | `/clavix:summarize` | Extract requirements from conversation |
99
+
100
+ **Project Management:**
101
+ | Utility | Purpose |
102
+ |---------|---------|
103
+ | `/clavix:verify` | Check implementation against PRD requirements |
104
+ | `/clavix:archive` | Archive completed projects to `.clavix/archive/` |
88
105
 
89
106
  See [Choosing the Right Workflow](docs/guides/choosing-workflow.md) for detailed guidance.
90
107
 
@@ -96,13 +113,14 @@ clavix update # After npm update clavix
96
113
 
97
114
  ## CLI Commands
98
115
 
99
- Clavix v5 has only 4 CLI commands (for setup, not workflows):
116
+ Clavix v5 has 5 CLI commands (for setup and diagnostics, not workflows):
100
117
 
101
118
  | Command | Purpose |
102
119
  |---------|---------|
103
120
  | `clavix init` | Initialize Clavix in a project |
104
121
  | `clavix update` | Update templates after package update |
105
122
  | `clavix config` | Manage configuration |
123
+ | `clavix diagnose` | Check installation and report issues |
106
124
  | `clavix version` | Show version |
107
125
 
108
126
  **All workflows** (`/clavix:improve`, `/clavix:prd`, etc.) are **slash commands** that AI agents execute by reading markdown templates.
@@ -7,9 +7,7 @@ export default class Config extends Command {
7
7
  key: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
8
  value: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
9
9
  };
10
- static flags: {
11
- global: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
- };
10
+ static flags: {};
13
11
  run(): Promise<void>;
14
12
  private showInteractiveMenu;
15
13
  private manageIntegrations;
@@ -1,4 +1,4 @@
1
- import { Command, Args, Flags } from '@oclif/core';
1
+ import { Command, Args } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
3
  import fs from 'fs-extra';
4
4
  import * as path from 'path';
@@ -28,18 +28,9 @@ export default class Config extends Command {
28
28
  required: false,
29
29
  }),
30
30
  };
31
- static flags = {
32
- global: Flags.boolean({
33
- char: 'g',
34
- description: 'Use global configuration (not implemented yet)',
35
- default: false,
36
- }),
37
- };
31
+ static flags = {};
38
32
  async run() {
39
- const { args, flags } = await this.parse(Config);
40
- if (flags.global) {
41
- this.warn('Global configuration is not yet supported. Using project configuration.');
42
- }
33
+ const { args } = await this.parse(Config);
43
34
  const clavixDir = path.join(process.cwd(), '.clavix');
44
35
  const configPath = path.join(clavixDir, 'config.json');
45
36
  if (!fs.existsSync(clavixDir) || !fs.existsSync(configPath)) {
@@ -420,7 +411,7 @@ export default class Config extends Command {
420
411
  }
421
412
  displayConfig(config) {
422
413
  this.log(` ${chalk.gray('Version:')} ${config.version}`);
423
- this.log(` ${chalk.gray('Integrations:')} ${config.integrations.map(p => chalk.cyan(p)).join(', ') || chalk.gray('(none)')}`);
414
+ this.log(` ${chalk.gray('Integrations:')} ${config.integrations.map((p) => chalk.cyan(p)).join(', ') || chalk.gray('(none)')}`);
424
415
  if (config.preferences) {
425
416
  this.log(`\n ${chalk.bold('Preferences:')}`);
426
417
  this.log(` ${chalk.gray('Auto-open outputs:')} ${config.preferences.autoOpenOutputs ? chalk.green('yes') : chalk.gray('no')}`);
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Diagnose extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ private checkVersion;
7
+ private checkClavixDir;
8
+ private checkConfig;
9
+ private static readonly DOC_GENERATORS;
10
+ private getDocGeneratorFile;
11
+ private getDocGeneratorName;
12
+ private checkIntegrations;
13
+ private checkTemplates;
14
+ }
15
+ //# sourceMappingURL=diagnose.d.ts.map
@@ -0,0 +1,295 @@
1
+ import { Command } from '@oclif/core';
2
+ import chalk from 'chalk';
3
+ import * as path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname } from 'path';
6
+ import fs from 'fs-extra';
7
+ import { AgentManager } from '../../core/agent-manager.js';
8
+ import { FileSystem } from '../../utils/file-system.js';
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ export default class Diagnose extends Command {
12
+ static description = 'Diagnose Clavix installation and configuration';
13
+ static examples = [
14
+ '<%= config.bin %> <%= command.id %>',
15
+ '<%= config.bin %> <%= command.id %> # Check setup and report issues',
16
+ ];
17
+ async run() {
18
+ this.log(chalk.bold.cyan('\n🔍 Clavix Diagnostic Report\n'));
19
+ const results = [];
20
+ // 1. Check version
21
+ results.push(await this.checkVersion());
22
+ // 2. Check .clavix directory
23
+ results.push(await this.checkClavixDir());
24
+ // 3. Check config.json
25
+ results.push(await this.checkConfig());
26
+ // 4. Check integrations
27
+ results.push(...(await this.checkIntegrations()));
28
+ // 5. Check templates
29
+ results.push(await this.checkTemplates());
30
+ // Note: Slash commands are checked per-integration in checkIntegrations()
31
+ // No separate checkSlashCommands() - commands are in adapter-specific directories
32
+ // Print results
33
+ this.log(chalk.gray('─'.repeat(50)));
34
+ this.log(chalk.bold('\nResults:\n'));
35
+ let passCount = 0;
36
+ let warnCount = 0;
37
+ let failCount = 0;
38
+ for (const result of results) {
39
+ const icon = result.status === 'pass'
40
+ ? chalk.green('✓')
41
+ : result.status === 'warn'
42
+ ? chalk.yellow('⚠')
43
+ : chalk.red('✗');
44
+ const color = result.status === 'pass'
45
+ ? chalk.green
46
+ : result.status === 'warn'
47
+ ? chalk.yellow
48
+ : chalk.red;
49
+ this.log(` ${icon} ${color(result.message)}`);
50
+ if (result.details) {
51
+ this.log(chalk.gray(` ${result.details}`));
52
+ }
53
+ if (result.status === 'pass')
54
+ passCount++;
55
+ else if (result.status === 'warn')
56
+ warnCount++;
57
+ else
58
+ failCount++;
59
+ }
60
+ // Summary
61
+ this.log('\n' + chalk.gray('─'.repeat(50)));
62
+ this.log(chalk.bold(`\nSummary: ${chalk.green(passCount + ' passed')}, ${chalk.yellow(warnCount + ' warnings')}, ${chalk.red(failCount + ' failed')}\n`));
63
+ // Recommendations
64
+ if (failCount > 0) {
65
+ this.log(chalk.yellow('Recommendations:'));
66
+ this.log(chalk.gray(' • Run `clavix init` to initialize or repair installation'));
67
+ this.log(chalk.gray(' • Run `clavix update` to sync templates\n'));
68
+ }
69
+ else if (warnCount > 0) {
70
+ this.log(chalk.cyan('Tip: Run `clavix update` to resolve warnings\n'));
71
+ }
72
+ else {
73
+ this.log(chalk.green('✨ All checks passed! Clavix is ready to use.\n'));
74
+ }
75
+ }
76
+ async checkVersion() {
77
+ try {
78
+ const packageJsonPath = path.join(__dirname, '../../../package.json');
79
+ const packageJson = await fs.readJson(packageJsonPath);
80
+ return {
81
+ status: 'pass',
82
+ message: `Version: v${packageJson.version}`,
83
+ };
84
+ }
85
+ catch {
86
+ return {
87
+ status: 'fail',
88
+ message: 'Could not determine version',
89
+ details: 'package.json not found',
90
+ };
91
+ }
92
+ }
93
+ async checkClavixDir() {
94
+ const clavixDir = path.join(process.cwd(), '.clavix');
95
+ if (!(await FileSystem.exists(clavixDir))) {
96
+ return {
97
+ status: 'fail',
98
+ message: '.clavix directory not found',
99
+ details: 'Run `clavix init` to initialize',
100
+ };
101
+ }
102
+ // Check for essential subdirectory (outputs is always created)
103
+ // Note: 'instructions' is only created when generic integrations are used
104
+ // Note: 'commands' doesn't exist - commands go to adapter-specific directories
105
+ const outputsDir = path.join(clavixDir, 'outputs');
106
+ if (!(await FileSystem.exists(outputsDir))) {
107
+ return {
108
+ status: 'warn',
109
+ message: '.clavix directory incomplete',
110
+ details: 'Missing: outputs',
111
+ };
112
+ }
113
+ return {
114
+ status: 'pass',
115
+ message: '.clavix directory OK',
116
+ };
117
+ }
118
+ async checkConfig() {
119
+ const configPath = path.join(process.cwd(), '.clavix', 'config.json');
120
+ if (!(await FileSystem.exists(configPath))) {
121
+ return {
122
+ status: 'fail',
123
+ message: 'config.json not found',
124
+ details: 'Run `clavix init` to create configuration',
125
+ };
126
+ }
127
+ try {
128
+ const config = await fs.readJson(configPath);
129
+ if (!config.version) {
130
+ return {
131
+ status: 'warn',
132
+ message: 'config.json missing version field',
133
+ };
134
+ }
135
+ if (!config.integrations || config.integrations.length === 0) {
136
+ return {
137
+ status: 'warn',
138
+ message: 'No integrations configured',
139
+ details: 'Run `clavix config` to add integrations',
140
+ };
141
+ }
142
+ return {
143
+ status: 'pass',
144
+ message: `config.json OK (${config.integrations.length} integration(s))`,
145
+ };
146
+ }
147
+ catch (error) {
148
+ return {
149
+ status: 'fail',
150
+ message: 'config.json is invalid',
151
+ details: `${error}`,
152
+ };
153
+ }
154
+ }
155
+ // Doc generators are integrations that generate documentation files, not adapters
156
+ static DOC_GENERATORS = [
157
+ 'agents-md',
158
+ 'octo-md',
159
+ 'warp-md',
160
+ 'copilot-instructions',
161
+ ];
162
+ getDocGeneratorFile(integration) {
163
+ switch (integration) {
164
+ case 'agents-md':
165
+ return 'AGENTS.md';
166
+ case 'octo-md':
167
+ return 'OCTO.md';
168
+ case 'warp-md':
169
+ return 'WARP.md';
170
+ case 'copilot-instructions':
171
+ return path.join('.github', 'copilot-instructions.md');
172
+ default:
173
+ return '';
174
+ }
175
+ }
176
+ getDocGeneratorName(integration) {
177
+ switch (integration) {
178
+ case 'agents-md':
179
+ return 'AGENTS.md';
180
+ case 'octo-md':
181
+ return 'OCTO.md';
182
+ case 'warp-md':
183
+ return 'WARP.md';
184
+ case 'copilot-instructions':
185
+ return 'GitHub Copilot';
186
+ default:
187
+ return integration;
188
+ }
189
+ }
190
+ async checkIntegrations() {
191
+ const results = [];
192
+ const configPath = path.join(process.cwd(), '.clavix', 'config.json');
193
+ if (!(await FileSystem.exists(configPath))) {
194
+ return results;
195
+ }
196
+ try {
197
+ const config = await fs.readJson(configPath);
198
+ const agentManager = new AgentManager();
199
+ for (const integrationName of config.integrations || []) {
200
+ // Handle doc generators specially (they don't have adapters)
201
+ if (Diagnose.DOC_GENERATORS.includes(integrationName)) {
202
+ const docFile = this.getDocGeneratorFile(integrationName);
203
+ const docPath = path.join(process.cwd(), docFile);
204
+ if (await FileSystem.exists(docPath)) {
205
+ results.push({
206
+ status: 'pass',
207
+ message: `${this.getDocGeneratorName(integrationName)}: Generated`,
208
+ details: docFile,
209
+ });
210
+ }
211
+ else {
212
+ results.push({
213
+ status: 'warn',
214
+ message: `${this.getDocGeneratorName(integrationName)}: Not generated`,
215
+ details: `Run \`clavix update\` to generate`,
216
+ });
217
+ }
218
+ continue;
219
+ }
220
+ // Handle adapters (integrations with command generation)
221
+ const adapter = agentManager.getAdapter(integrationName);
222
+ if (!adapter) {
223
+ results.push({
224
+ status: 'warn',
225
+ message: `Unknown integration: ${integrationName}`,
226
+ details: 'May be removed in a future version',
227
+ });
228
+ continue;
229
+ }
230
+ // Check if adapter's command directory exists
231
+ const commandPath = adapter.getCommandPath();
232
+ const commandDirExists = await FileSystem.exists(commandPath);
233
+ if (commandDirExists) {
234
+ const files = await FileSystem.listFiles(commandPath);
235
+ const commandCount = files.filter((f) => f.endsWith('.md') || f.endsWith('.toml') || f.endsWith('.mdc')).length;
236
+ results.push({
237
+ status: 'pass',
238
+ message: `${adapter.displayName}: ${commandCount} command(s)`,
239
+ details: commandPath,
240
+ });
241
+ }
242
+ else {
243
+ results.push({
244
+ status: 'warn',
245
+ message: `${adapter.displayName}: commands not generated`,
246
+ details: `Run \`clavix update\` to generate`,
247
+ });
248
+ }
249
+ }
250
+ }
251
+ catch {
252
+ // Config read error handled elsewhere
253
+ }
254
+ return results;
255
+ }
256
+ async checkTemplates() {
257
+ const templateDir = path.join(__dirname, '../../templates');
258
+ if (!(await FileSystem.exists(templateDir))) {
259
+ return {
260
+ status: 'fail',
261
+ message: 'Template directory not found',
262
+ details: 'Package may be corrupted',
263
+ };
264
+ }
265
+ // Check for canonical templates
266
+ const canonicalDir = path.join(templateDir, 'slash-commands', '_canonical');
267
+ if (!(await FileSystem.exists(canonicalDir))) {
268
+ return {
269
+ status: 'warn',
270
+ message: 'Canonical templates missing',
271
+ details: 'Try reinstalling clavix',
272
+ };
273
+ }
274
+ const requiredTemplates = ['improve.md', 'prd.md', 'plan.md', 'implement.md'];
275
+ const missing = [];
276
+ for (const template of requiredTemplates) {
277
+ const templatePath = path.join(canonicalDir, template);
278
+ if (!(await FileSystem.exists(templatePath))) {
279
+ missing.push(template);
280
+ }
281
+ }
282
+ if (missing.length > 0) {
283
+ return {
284
+ status: 'warn',
285
+ message: 'Some canonical templates missing',
286
+ details: missing.join(', '),
287
+ };
288
+ }
289
+ return {
290
+ status: 'pass',
291
+ message: 'Package templates OK',
292
+ };
293
+ }
294
+ }
295
+ //# sourceMappingURL=diagnose.js.map
@@ -4,20 +4,10 @@
4
4
  */
5
5
  export declare class AgentsMdGenerator {
6
6
  static readonly TARGET_FILE = "AGENTS.md";
7
- static readonly START_MARKER = "<!-- CLAVIX:START -->";
8
- static readonly END_MARKER = "<!-- CLAVIX:END -->";
9
7
  /**
10
8
  * Generate or update AGENTS.md with Clavix workflows
11
9
  */
12
10
  static generate(): Promise<void>;
13
- /**
14
- * Inject or update managed block in AGENTS.md
15
- */
16
- private static injectManagedBlock;
17
- /**
18
- * Escape special regex characters
19
- */
20
- private static escapeRegex;
21
11
  /**
22
12
  * Check if AGENTS.md has Clavix block
23
13
  */
@@ -1,7 +1,8 @@
1
- import { FileSystem } from '../../utils/file-system.js';
2
1
  import * as path from 'path';
3
2
  import { fileURLToPath } from 'url';
4
3
  import { dirname } from 'path';
4
+ import { FileSystem } from '../../utils/file-system.js';
5
+ import { DocInjector } from '../doc-injector.js';
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = dirname(__filename);
7
8
  /**
@@ -10,60 +11,25 @@ const __dirname = dirname(__filename);
10
11
  */
11
12
  export class AgentsMdGenerator {
12
13
  static TARGET_FILE = 'AGENTS.md';
13
- static START_MARKER = '<!-- CLAVIX:START -->';
14
- static END_MARKER = '<!-- CLAVIX:END -->';
15
14
  /**
16
15
  * Generate or update AGENTS.md with Clavix workflows
17
16
  */
18
17
  static async generate() {
19
18
  const templatePath = path.join(__dirname, '../../templates/agents/agents.md');
20
- // Check if template exists
21
19
  if (!(await FileSystem.exists(templatePath))) {
22
20
  throw new Error(`AGENTS.md template not found at ${templatePath}`);
23
21
  }
24
22
  const template = await FileSystem.readFile(templatePath);
25
- // Inject into AGENTS.md using managed blocks
26
- await this.injectManagedBlock(this.TARGET_FILE, template);
27
- }
28
- /**
29
- * Inject or update managed block in AGENTS.md
30
- */
31
- static async injectManagedBlock(filePath, content) {
32
- let fileContent = '';
33
- // Read existing file or start with empty content
34
- if (await FileSystem.exists(filePath)) {
35
- fileContent = await FileSystem.readFile(filePath);
36
- }
37
- const blockRegex = new RegExp(`${this.escapeRegex(this.START_MARKER)}[\\s\\S]*?${this.escapeRegex(this.END_MARKER)}`, 'g');
38
- const wrappedContent = `${this.START_MARKER}\n${content}\n${this.END_MARKER}`;
39
- if (blockRegex.test(fileContent)) {
40
- // Replace existing block
41
- fileContent = fileContent.replace(blockRegex, wrappedContent);
42
- }
43
- else {
44
- // Append new block
45
- if (fileContent && !fileContent.endsWith('\n\n')) {
46
- fileContent += '\n\n';
47
- }
48
- fileContent += wrappedContent + '\n';
49
- }
50
- await FileSystem.writeFileAtomic(filePath, fileContent);
51
- }
52
- /**
53
- * Escape special regex characters
54
- */
55
- static escapeRegex(str) {
56
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
23
+ await DocInjector.injectBlock(this.TARGET_FILE, template, {
24
+ createIfMissing: true,
25
+ validateMarkdown: false, // Template is pre-validated
26
+ });
57
27
  }
58
28
  /**
59
29
  * Check if AGENTS.md has Clavix block
60
30
  */
61
31
  static async hasClavixBlock() {
62
- if (!(await FileSystem.exists(this.TARGET_FILE))) {
63
- return false;
64
- }
65
- const content = await FileSystem.readFile(this.TARGET_FILE);
66
- return content.includes(this.START_MARKER);
32
+ return DocInjector.hasBlock(this.TARGET_FILE);
67
33
  }
68
34
  }
69
35
  //# sourceMappingURL=agents-md-generator.js.map
@@ -4,20 +4,10 @@
4
4
  */
5
5
  export declare class CopilotInstructionsGenerator {
6
6
  static readonly TARGET_FILE = ".github/copilot-instructions.md";
7
- static readonly START_MARKER = "<!-- CLAVIX:START -->";
8
- static readonly END_MARKER = "<!-- CLAVIX:END -->";
9
7
  /**
10
8
  * Generate or update .github/copilot-instructions.md with Clavix workflows
11
9
  */
12
10
  static generate(): Promise<void>;
13
- /**
14
- * Inject or update managed block in .github/copilot-instructions.md
15
- */
16
- private static injectManagedBlock;
17
- /**
18
- * Escape special regex characters
19
- */
20
- private static escapeRegex;
21
11
  /**
22
12
  * Check if .github/copilot-instructions.md has Clavix block
23
13
  */
@@ -1,7 +1,8 @@
1
- import { FileSystem } from '../../utils/file-system.js';
2
1
  import * as path from 'path';
3
2
  import { fileURLToPath } from 'url';
4
3
  import { dirname } from 'path';
4
+ import { FileSystem } from '../../utils/file-system.js';
5
+ import { DocInjector } from '../doc-injector.js';
5
6
  const __filename = fileURLToPath(import.meta.url);
6
7
  const __dirname = dirname(__filename);
7
8
  /**
@@ -10,62 +11,27 @@ const __dirname = dirname(__filename);
10
11
  */
11
12
  export class CopilotInstructionsGenerator {
12
13
  static TARGET_FILE = '.github/copilot-instructions.md';
13
- static START_MARKER = '<!-- CLAVIX:START -->';
14
- static END_MARKER = '<!-- CLAVIX:END -->';
15
14
  /**
16
15
  * Generate or update .github/copilot-instructions.md with Clavix workflows
17
16
  */
18
17
  static async generate() {
19
18
  const templatePath = path.join(__dirname, '../../templates/agents/copilot-instructions.md');
20
- // Check if template exists
21
19
  if (!(await FileSystem.exists(templatePath))) {
22
20
  throw new Error(`Copilot instructions template not found at ${templatePath}`);
23
21
  }
24
22
  const template = await FileSystem.readFile(templatePath);
25
23
  // Ensure .github directory exists
26
24
  await FileSystem.ensureDir('.github');
27
- // Inject into .github/copilot-instructions.md using managed blocks
28
- await this.injectManagedBlock(this.TARGET_FILE, template);
29
- }
30
- /**
31
- * Inject or update managed block in .github/copilot-instructions.md
32
- */
33
- static async injectManagedBlock(filePath, content) {
34
- let fileContent = '';
35
- // Read existing file or start with empty content
36
- if (await FileSystem.exists(filePath)) {
37
- fileContent = await FileSystem.readFile(filePath);
38
- }
39
- const blockRegex = new RegExp(`${this.escapeRegex(this.START_MARKER)}[\\s\\S]*?${this.escapeRegex(this.END_MARKER)}`, 'g');
40
- const wrappedContent = `${this.START_MARKER}\n${content}\n${this.END_MARKER}`;
41
- if (blockRegex.test(fileContent)) {
42
- // Replace existing block
43
- fileContent = fileContent.replace(blockRegex, wrappedContent);
44
- }
45
- else {
46
- // Append new block
47
- if (fileContent && !fileContent.endsWith('\n\n')) {
48
- fileContent += '\n\n';
49
- }
50
- fileContent += wrappedContent + '\n';
51
- }
52
- await FileSystem.writeFileAtomic(filePath, fileContent);
53
- }
54
- /**
55
- * Escape special regex characters
56
- */
57
- static escapeRegex(str) {
58
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
25
+ await DocInjector.injectBlock(this.TARGET_FILE, template, {
26
+ createIfMissing: true,
27
+ validateMarkdown: false,
28
+ });
59
29
  }
60
30
  /**
61
31
  * Check if .github/copilot-instructions.md has Clavix block
62
32
  */
63
33
  static async hasClavixBlock() {
64
- if (!(await FileSystem.exists(this.TARGET_FILE))) {
65
- return false;
66
- }
67
- const content = await FileSystem.readFile(this.TARGET_FILE);
68
- return content.includes(this.START_MARKER);
34
+ return DocInjector.hasBlock(this.TARGET_FILE);
69
35
  }
70
36
  }
71
37
  //# sourceMappingURL=copilot-instructions-generator.js.map
@@ -1,27 +1,11 @@
1
- import { BaseAdapter } from './base-adapter.js';
2
- import { CommandTemplate } from '../../types/agent.js';
1
+ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
3
2
  /**
4
3
  * Gemini CLI adapter
5
4
  * Commands stored as TOML files under .gemini/commands/clavix by default
6
5
  */
7
- export declare class GeminiAdapter extends BaseAdapter {
8
- private readonly options;
9
- readonly name = "gemini";
10
- readonly displayName = "Gemini CLI";
11
- readonly fileExtension = ".toml";
12
- readonly features: {
13
- supportsSubdirectories: boolean;
14
- supportsFrontmatter: boolean;
15
- argumentPlaceholder: string;
16
- };
6
+ export declare class GeminiAdapter extends TomlFormattingAdapter {
17
7
  constructor(options?: {
18
8
  useNamespace?: boolean;
19
9
  });
20
- get directory(): string;
21
- detectProject(): Promise<boolean>;
22
- getCommandPath(): string;
23
- getTargetFilename(name: string): string;
24
- protected formatCommand(template: CommandTemplate): string;
25
- private getHomeDir;
26
10
  }
27
11
  //# sourceMappingURL=gemini-adapter.d.ts.map