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.
- package/README.md +21 -3
- package/dist/cli/commands/config.d.ts +1 -3
- package/dist/cli/commands/config.js +4 -13
- package/dist/cli/commands/diagnose.d.ts +15 -0
- package/dist/cli/commands/diagnose.js +295 -0
- package/dist/core/adapters/agents-md-generator.d.ts +0 -10
- package/dist/core/adapters/agents-md-generator.js +7 -41
- package/dist/core/adapters/copilot-instructions-generator.d.ts +0 -10
- package/dist/core/adapters/copilot-instructions-generator.js +7 -41
- package/dist/core/adapters/gemini-adapter.d.ts +2 -18
- package/dist/core/adapters/gemini-adapter.js +7 -46
- package/dist/core/adapters/llxprt-adapter.d.ts +2 -18
- package/dist/core/adapters/llxprt-adapter.js +7 -46
- package/dist/core/adapters/octo-md-generator.d.ts +0 -10
- package/dist/core/adapters/octo-md-generator.js +7 -41
- package/dist/core/adapters/qwen-adapter.d.ts +2 -18
- package/dist/core/adapters/qwen-adapter.js +7 -46
- package/dist/core/adapters/toml-formatting-adapter.d.ts +50 -0
- package/dist/core/adapters/toml-formatting-adapter.js +74 -0
- package/dist/core/adapters/warp-md-generator.d.ts +3 -4
- package/dist/core/adapters/warp-md-generator.js +10 -30
- package/dist/core/doc-injector.js +4 -5
- package/dist/templates/agents/agents.md +8 -2
- package/dist/templates/agents/copilot-instructions.md +6 -2
- package/dist/templates/agents/octo.md +6 -2
- package/dist/templates/agents/warp.md +6 -2
- package/dist/templates/slash-commands/_canonical/archive.md +4 -7
- package/dist/templates/slash-commands/_canonical/implement.md +4 -7
- package/dist/templates/slash-commands/_canonical/improve.md +4 -7
- package/dist/templates/slash-commands/_canonical/plan.md +4 -7
- package/dist/templates/slash-commands/_canonical/prd.md +4 -7
- package/dist/templates/slash-commands/_canonical/start.md +3 -6
- package/dist/templates/slash-commands/_canonical/summarize.md +3 -6
- package/dist/templates/slash-commands/_canonical/verify.md +4 -7
- package/dist/templates/slash-commands/_components/agent-protocols/AGENT_MANUAL.md +284 -0
- package/dist/types/agent.d.ts +0 -4
- package/dist/types/config.d.ts +0 -80
- package/dist/types/config.js +1 -1
- package/dist/utils/agent-error-messages.d.ts +5 -5
- package/dist/utils/agent-error-messages.js +5 -5
- package/dist/utils/error-utils.d.ts +1 -7
- package/dist/utils/error-utils.js +12 -11
- package/dist/utils/toml-templates.js +4 -1
- package/package.json +3 -8
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
| Version | Highlights | Details |
|
|
14
14
|
| --- | --- | --- |
|
|
15
|
-
| **v5.
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|