clavix 5.9.0 → 5.9.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 (33) hide show
  1. package/dist/cli/commands/init.js +93 -3
  2. package/dist/cli/commands/update.js +5 -1
  3. package/dist/cli/helpers/init/config.d.ts +1 -1
  4. package/dist/cli/helpers/init/config.js +7 -1
  5. package/dist/core/adapters/claude-code-adapter.d.ts +3 -0
  6. package/dist/core/adapters/claude-code-adapter.js +5 -0
  7. package/dist/core/adapters/gemini-adapter.d.ts +3 -1
  8. package/dist/core/adapters/gemini-adapter.js +25 -6
  9. package/dist/core/adapters/llxprt-adapter.d.ts +3 -1
  10. package/dist/core/adapters/llxprt-adapter.js +25 -6
  11. package/dist/core/adapters/qwen-adapter.d.ts +3 -1
  12. package/dist/core/adapters/qwen-adapter.js +25 -6
  13. package/dist/core/adapters/toml-formatting-adapter.d.ts +3 -0
  14. package/dist/core/adapters/toml-formatting-adapter.js +2 -0
  15. package/dist/core/adapters/universal-adapter.d.ts +3 -1
  16. package/dist/core/adapters/universal-adapter.js +6 -7
  17. package/dist/core/agent-manager.d.ts +3 -1
  18. package/dist/core/agent-manager.js +8 -6
  19. package/dist/templates/slash-commands/_canonical/archive.md +1 -1
  20. package/dist/templates/slash-commands/_canonical/implement.md +1 -1
  21. package/dist/templates/slash-commands/_canonical/improve.md +1 -1
  22. package/dist/templates/slash-commands/_canonical/plan.md +1 -1
  23. package/dist/templates/slash-commands/_canonical/prd.md +1 -1
  24. package/dist/templates/slash-commands/_canonical/refine.md +1 -1
  25. package/dist/templates/slash-commands/_canonical/start.md +1 -1
  26. package/dist/templates/slash-commands/_canonical/summarize.md +1 -1
  27. package/dist/templates/slash-commands/_canonical/verify.md +1 -1
  28. package/dist/types/config.d.ts +10 -1
  29. package/dist/utils/path-resolver.d.ts +28 -0
  30. package/dist/utils/path-resolver.js +57 -0
  31. package/dist/utils/schemas.d.ts +24 -9
  32. package/dist/utils/schemas.js +16 -1
  33. package/package.json +2 -1
@@ -25,8 +25,8 @@ export default class Init extends Command {
25
25
  async run() {
26
26
  this.log(chalk.bold.cyan('\nšŸš€ Clavix Initialization\n'));
27
27
  try {
28
- const agentManager = new AgentManager();
29
28
  let existingIntegrations = [];
29
+ let existingConfig;
30
30
  // Load existing config if present
31
31
  if (await FileSystem.exists('.clavix/config.json')) {
32
32
  try {
@@ -37,6 +37,7 @@ export default class Init extends Command {
37
37
  if (validationResult.success && validationResult.data) {
38
38
  existingIntegrations =
39
39
  validationResult.data.integrations || validationResult.data.providers || [];
40
+ existingConfig = validationResult.data;
40
41
  // Log warnings (non-blocking)
41
42
  if (validationResult.warnings) {
42
43
  for (const warning of validationResult.warnings) {
@@ -60,6 +61,8 @@ export default class Init extends Command {
60
61
  // Continue with empty array - will prompt for new configuration
61
62
  }
62
63
  }
64
+ // Initialize agent manager with existing config (for custom integration paths)
65
+ const agentManager = new AgentManager(existingConfig);
63
66
  // Check if already initialized
64
67
  if (await FileSystem.exists('.clavix')) {
65
68
  // Show current state
@@ -176,12 +179,93 @@ export default class Init extends Command {
176
179
  }
177
180
  // If 'skip': do nothing
178
181
  }
182
+ // Collect custom integration paths (e.g., for Codex with $CODEX_HOME)
183
+ const integrationPaths = {};
184
+ // Prompt about Codex path if Codex is selected
185
+ if (selectedIntegrations.includes('codex')) {
186
+ this.log(chalk.cyan('\nšŸ”§ Codex Configuration'));
187
+ const hasEnvVar = process.env.CODEX_HOME;
188
+ const defaultPath = '~/.codex/prompts';
189
+ if (hasEnvVar) {
190
+ // $CODEX_HOME is detected - ask for confirmation
191
+ const { useEnvPath } = await inquirer.prompt([
192
+ {
193
+ type: 'confirm',
194
+ name: 'useEnvPath',
195
+ message: `Detected $CODEX_HOME=${hasEnvVar}. Use this path instead of ${defaultPath}?`,
196
+ default: true,
197
+ },
198
+ ]);
199
+ if (useEnvPath) {
200
+ integrationPaths.codex = hasEnvVar;
201
+ this.log(chalk.gray(` āœ“ Using $CODEX_HOME: ${hasEnvVar}`));
202
+ }
203
+ else {
204
+ // Ask if they want to use a custom path
205
+ const { useCustomPath } = await inquirer.prompt([
206
+ {
207
+ type: 'confirm',
208
+ name: 'useCustomPath',
209
+ message: 'Use a custom Codex prompts directory?',
210
+ default: false,
211
+ },
212
+ ]);
213
+ if (useCustomPath) {
214
+ const { customPath } = await inquirer.prompt([
215
+ {
216
+ type: 'input',
217
+ name: 'customPath',
218
+ message: 'Enter path to Codex prompts directory:',
219
+ default: defaultPath,
220
+ validate: (input) => {
221
+ if (!input || input.trim().length === 0) {
222
+ return 'Path cannot be empty';
223
+ }
224
+ return true;
225
+ },
226
+ },
227
+ ]);
228
+ integrationPaths.codex = customPath;
229
+ this.log(chalk.gray(` āœ“ Using custom path: ${customPath}`));
230
+ }
231
+ }
232
+ }
233
+ else {
234
+ // No $CODEX_HOME - ask if they want a custom path
235
+ const { useCustomPath } = await inquirer.prompt([
236
+ {
237
+ type: 'confirm',
238
+ name: 'useCustomPath',
239
+ message: 'Use a custom Codex prompts directory?',
240
+ default: false,
241
+ },
242
+ ]);
243
+ if (useCustomPath) {
244
+ const { customPath } = await inquirer.prompt([
245
+ {
246
+ type: 'input',
247
+ name: 'customPath',
248
+ message: 'Enter path to Codex prompts directory:',
249
+ default: defaultPath,
250
+ validate: (input) => {
251
+ if (!input || input.trim().length === 0) {
252
+ return 'Path cannot be empty';
253
+ }
254
+ return true;
255
+ },
256
+ },
257
+ ]);
258
+ integrationPaths.codex = customPath;
259
+ this.log(chalk.gray(` āœ“ Using custom path: ${customPath}`));
260
+ }
261
+ }
262
+ }
179
263
  // Create .clavix directory structure
180
264
  this.log(chalk.cyan('\nšŸ“ Creating directory structure...'));
181
265
  await this.createDirectoryStructure();
182
266
  // Generate config
183
267
  this.log(chalk.cyan('āš™ļø Generating configuration...'));
184
- await this.generateConfig(selectedIntegrations);
268
+ await this.generateConfig(selectedIntegrations, integrationPaths);
185
269
  // Generate INSTRUCTIONS.md and QUICKSTART.md
186
270
  await this.generateInstructions();
187
271
  await this.generateQuickstart();
@@ -396,11 +480,17 @@ export default class Init extends Command {
396
480
  await FileSystem.ensureDir(dir);
397
481
  }
398
482
  }
399
- async generateConfig(integrations) {
483
+ async generateConfig(integrations, integrationPaths = {}) {
400
484
  const config = {
401
485
  ...DEFAULT_CONFIG,
402
486
  integrations,
403
487
  };
488
+ // Add integration paths to experimental if any
489
+ if (Object.keys(integrationPaths).length > 0) {
490
+ config.experimental = {
491
+ integrationPaths,
492
+ };
493
+ }
404
494
  const configPath = '.clavix/config.json';
405
495
  const configContent = JSON.stringify(config, null, 2);
406
496
  await FileSystem.writeFileAtomic(configPath, configContent);
@@ -72,6 +72,8 @@ export default class Update extends Command {
72
72
  this.log(chalk.yellow(` ⚠ ${warning}`));
73
73
  }
74
74
  }
75
+ // Type assertion: validationResult.data is User type which has optional version
76
+ // We know version exists in valid configs, so we can assert
75
77
  config = validationResult.data;
76
78
  }
77
79
  catch (error) {
@@ -84,8 +86,10 @@ export default class Update extends Command {
84
86
  chalk.cyan('clavix init') +
85
87
  chalk.yellow(' to regenerate.'));
86
88
  }
89
+ // Handle legacy 'providers' field for backward compatibility
87
90
  const integrations = config.integrations || config.providers || ['claude-code'];
88
- const agentManager = new AgentManager();
91
+ // Initialize agent manager with config (for custom integration paths)
92
+ const agentManager = new AgentManager(config);
89
93
  const updateDocs = flags['docs-only'] || (!flags['docs-only'] && !flags['commands-only']);
90
94
  const updateCommands = flags['commands-only'] || (!flags['docs-only'] && !flags['commands-only']);
91
95
  let updatedCount = 0;
@@ -12,7 +12,7 @@ export declare function loadExistingConfig(): Promise<{
12
12
  /**
13
13
  * Generate and save the Clavix config file
14
14
  */
15
- export declare function generateConfig(integrations: string[]): Promise<void>;
15
+ export declare function generateConfig(integrations: string[], integrationPaths?: Record<string, string>): Promise<void>;
16
16
  /**
17
17
  * Check if Clavix is already initialized in the current directory
18
18
  */
@@ -31,11 +31,17 @@ export async function loadExistingConfig() {
31
31
  /**
32
32
  * Generate and save the Clavix config file
33
33
  */
34
- export async function generateConfig(integrations) {
34
+ export async function generateConfig(integrations, integrationPaths = {}) {
35
35
  const config = {
36
36
  ...DEFAULT_CONFIG,
37
37
  integrations,
38
38
  };
39
+ // Add integration paths to experimental if any
40
+ if (Object.keys(integrationPaths).length > 0) {
41
+ config.experimental = {
42
+ integrationPaths,
43
+ };
44
+ }
39
45
  const configPath = '.clavix/config.json';
40
46
  const configContent = JSON.stringify(config, null, 2);
41
47
  await FileSystem.writeFileAtomic(configPath, configContent);
@@ -1,5 +1,6 @@
1
1
  import { BaseAdapter } from './base-adapter.js';
2
2
  import { ManagedBlock } from '../../types/agent.js';
3
+ import { ClavixConfig } from '../../types/config.js';
3
4
  /**
4
5
  * Claude Code agent adapter
5
6
  */
@@ -11,6 +12,8 @@ export declare class ClaudeCodeAdapter extends BaseAdapter {
11
12
  readonly features: {
12
13
  supportsSubdirectories: boolean;
13
14
  };
15
+ protected readonly userConfig?: ClavixConfig;
16
+ constructor(userConfig?: ClavixConfig);
14
17
  /**
15
18
  * Detect if Claude Code is available in the project
16
19
  */
@@ -14,6 +14,11 @@ export class ClaudeCodeAdapter extends BaseAdapter {
14
14
  features = {
15
15
  supportsSubdirectories: true,
16
16
  };
17
+ userConfig;
18
+ constructor(userConfig) {
19
+ super();
20
+ this.userConfig = userConfig;
21
+ }
17
22
  /**
18
23
  * Detect if Claude Code is available in the project
19
24
  */
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * Gemini CLI adapter
4
5
  * Commands stored as TOML files under .gemini/commands/clavix by default
5
6
  */
6
7
  export declare class GeminiAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=gemini-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .gemini/commands/clavix by default
5
5
  */
6
6
  export class GeminiAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'gemini',
10
- displayName: 'Gemini CLI',
11
- rootDir: '.gemini',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'gemini',
12
+ displayName: 'Gemini CLI',
13
+ rootDir: '.gemini',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'gemini',
20
+ displayName: 'Gemini CLI',
21
+ rootDir: '.gemini',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'gemini',
28
+ displayName: 'Gemini CLI',
29
+ rootDir: '.gemini',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=gemini-adapter.js.map
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * LLXPRT adapter
4
5
  * Commands stored as TOML files under .llxprt/commands/clavix by default
5
6
  */
6
7
  export declare class LlxprtAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=llxprt-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .llxprt/commands/clavix by default
5
5
  */
6
6
  export class LlxprtAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'llxprt',
10
- displayName: 'LLXPRT',
11
- rootDir: '.llxprt',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'llxprt',
12
+ displayName: 'LLXPRT',
13
+ rootDir: '.llxprt',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'llxprt',
20
+ displayName: 'LLXPRT',
21
+ rootDir: '.llxprt',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'llxprt',
28
+ displayName: 'LLXPRT',
29
+ rootDir: '.llxprt',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=llxprt-adapter.js.map
@@ -1,11 +1,13 @@
1
1
  import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
2
+ import { ClavixConfig } from '../../types/config.js';
2
3
  /**
3
4
  * Qwen Code CLI adapter
4
5
  * Commands stored as TOML files under .qwen/commands/clavix by default
5
6
  */
6
7
  export declare class QwenAdapter extends TomlFormattingAdapter {
7
- constructor(options?: {
8
+ constructor(userConfigOrOptions?: ClavixConfig | {
8
9
  useNamespace?: boolean;
10
+ userConfig?: ClavixConfig;
9
11
  });
10
12
  }
11
13
  //# sourceMappingURL=qwen-adapter.d.ts.map
@@ -4,12 +4,31 @@ import { TomlFormattingAdapter } from './toml-formatting-adapter.js';
4
4
  * Commands stored as TOML files under .qwen/commands/clavix by default
5
5
  */
6
6
  export class QwenAdapter extends TomlFormattingAdapter {
7
- constructor(options = {}) {
8
- super({
9
- name: 'qwen',
10
- displayName: 'Qwen Code',
11
- rootDir: '.qwen',
12
- }, options);
7
+ constructor(userConfigOrOptions) {
8
+ // Support both old API (options object) and new API (userConfig directly)
9
+ if (!userConfigOrOptions) {
10
+ super({
11
+ name: 'qwen',
12
+ displayName: 'Qwen Code',
13
+ rootDir: '.qwen',
14
+ });
15
+ }
16
+ else if ('useNamespace' in userConfigOrOptions) {
17
+ // It's the options object
18
+ super({
19
+ name: 'qwen',
20
+ displayName: 'Qwen Code',
21
+ rootDir: '.qwen',
22
+ }, userConfigOrOptions);
23
+ }
24
+ else {
25
+ // It's the userConfig directly - pass as options
26
+ super({
27
+ name: 'qwen',
28
+ displayName: 'Qwen Code',
29
+ rootDir: '.qwen',
30
+ }, { userConfig: userConfigOrOptions });
31
+ }
13
32
  }
14
33
  }
15
34
  //# sourceMappingURL=qwen-adapter.js.map
@@ -1,5 +1,6 @@
1
1
  import { BaseAdapter } from './base-adapter.js';
2
2
  import { CommandTemplate } from '../../types/agent.js';
3
+ import { ClavixConfig } from '../../types/config.js';
3
4
  /**
4
5
  * Configuration for TOML-based adapters
5
6
  */
@@ -30,8 +31,10 @@ export declare abstract class TomlFormattingAdapter extends BaseAdapter {
30
31
  argumentPlaceholder: string;
31
32
  };
32
33
  protected readonly config: TomlAdapterConfig;
34
+ protected readonly userConfig?: ClavixConfig;
33
35
  constructor(config: TomlAdapterConfig, options?: {
34
36
  useNamespace?: boolean;
37
+ userConfig?: ClavixConfig;
35
38
  });
36
39
  get name(): string;
37
40
  get displayName(): string;
@@ -19,12 +19,14 @@ export class TomlFormattingAdapter extends BaseAdapter {
19
19
  argumentPlaceholder: '{{args}}',
20
20
  };
21
21
  config;
22
+ userConfig;
22
23
  constructor(config, options = {}) {
23
24
  super();
24
25
  this.config = {
25
26
  ...config,
26
27
  useNamespace: options.useNamespace ?? config.useNamespace ?? true,
27
28
  };
29
+ this.userConfig = options.userConfig;
28
30
  }
29
31
  get name() {
30
32
  return this.config.name;
@@ -13,10 +13,12 @@
13
13
  import { BaseAdapter } from './base-adapter.js';
14
14
  import { AdapterConfig } from '../../types/adapter-config.js';
15
15
  import { IntegrationFeatures } from '../../types/agent.js';
16
+ import { ClavixConfig } from '../../types/config.js';
16
17
  export declare class UniversalAdapter extends BaseAdapter {
17
18
  private config;
18
19
  readonly features: IntegrationFeatures;
19
- constructor(config: AdapterConfig);
20
+ private userConfig?;
21
+ constructor(config: AdapterConfig, userConfig?: ClavixConfig);
20
22
  get name(): string;
21
23
  get displayName(): string;
22
24
  get directory(): string;
@@ -11,14 +11,16 @@
11
11
  * @since v5.3.0
12
12
  */
13
13
  import { BaseAdapter } from './base-adapter.js';
14
+ import { resolveIntegrationPath } from '../../utils/path-resolver.js';
14
15
  import * as path from 'path';
15
- import * as os from 'os';
16
16
  export class UniversalAdapter extends BaseAdapter {
17
17
  config;
18
18
  features;
19
- constructor(config) {
19
+ userConfig;
20
+ constructor(config, userConfig) {
20
21
  super();
21
22
  this.config = config;
23
+ this.userConfig = userConfig;
22
24
  // Set features from config for interface compatibility
23
25
  this.features = {
24
26
  supportsSubdirectories: config.features.supportsSubdirectories,
@@ -34,11 +36,8 @@ export class UniversalAdapter extends BaseAdapter {
34
36
  return this.config.displayName;
35
37
  }
36
38
  get directory() {
37
- // Expand ~ to home directory for global adapters
38
- if (this.config.directory.startsWith('~/')) {
39
- return this.config.directory.replace('~', os.homedir());
40
- }
41
- return this.config.directory;
39
+ // Use path resolver for proper environment variable and config override support
40
+ return resolveIntegrationPath(this.config, this.userConfig);
42
41
  }
43
42
  /**
44
43
  * Check if this adapter uses global (home directory) installation
@@ -1,4 +1,5 @@
1
1
  import { AgentAdapter, ValidationResult } from '../types/agent.js';
2
+ import { ClavixConfig } from '../types/config.js';
2
3
  /**
3
4
  * Agent Manager - handles agent detection and registration
4
5
  *
@@ -9,7 +10,8 @@ import { AgentAdapter, ValidationResult } from '../types/agent.js';
9
10
  */
10
11
  export declare class AgentManager {
11
12
  private adapters;
12
- constructor();
13
+ private userConfig?;
14
+ constructor(userConfig?: ClavixConfig);
13
15
  /**
14
16
  * Register a new agent adapter
15
17
  */
@@ -15,18 +15,20 @@ import { IntegrationError } from '../types/errors.js';
15
15
  */
16
16
  export class AgentManager {
17
17
  adapters = new Map();
18
- constructor() {
18
+ userConfig;
19
+ constructor(userConfig) {
20
+ this.userConfig = userConfig;
19
21
  // Register special adapters (require custom logic)
20
- this.registerAdapter(new ClaudeCodeAdapter()); // Doc injection
21
- this.registerAdapter(new GeminiAdapter()); // TOML format
22
- this.registerAdapter(new QwenAdapter()); // TOML format
23
- this.registerAdapter(new LlxprtAdapter()); // TOML format
22
+ this.registerAdapter(new ClaudeCodeAdapter(userConfig)); // Doc injection
23
+ this.registerAdapter(new GeminiAdapter(userConfig)); // TOML format
24
+ this.registerAdapter(new QwenAdapter(userConfig)); // TOML format
25
+ this.registerAdapter(new LlxprtAdapter(userConfig)); // TOML format
24
26
  // Register simple adapters from config (using UniversalAdapter factory)
25
27
  for (const config of getSimpleAdapters()) {
26
28
  // Skip adapters that have special handlers registered above
27
29
  if (this.adapters.has(config.name))
28
30
  continue;
29
- this.registerAdapter(new UniversalAdapter(config));
31
+ this.registerAdapter(new UniversalAdapter(config, userConfig));
30
32
  }
31
33
  }
32
34
  /**
@@ -274,7 +274,7 @@ Result: Project permanently deleted
274
274
 
275
275
  ---
276
276
 
277
- ## Agent Transparency (v5.9.0)
277
+ ## Agent Transparency (v5.9.1)
278
278
 
279
279
  ### Agent Manual (Universal Protocols)
280
280
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -524,7 +524,7 @@ I'll explain what's wrong and what you might need to do:
524
524
 
525
525
  ---
526
526
 
527
- ## Agent Transparency (v5.9.0)
527
+ ## Agent Transparency (v5.9.1)
528
528
 
529
529
  ### Agent Manual (Universal Protocols)
530
530
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -524,7 +524,7 @@ Wait for the user to decide what to do next.
524
524
 
525
525
  ---
526
526
 
527
- ## Agent Transparency (v5.9.0)
527
+ ## Agent Transparency (v5.9.1)
528
528
 
529
529
  ### Agent Manual (Universal Protocols)
530
530
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -229,7 +229,7 @@ Present the plan and ask:
229
229
 
230
230
  ---
231
231
 
232
- ## Agent Transparency (v5.9.0)
232
+ ## Agent Transparency (v5.9.1)
233
233
 
234
234
  ### Agent Manual (Universal Protocols)
235
235
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -354,7 +354,7 @@ The validation ensures generated PRDs are immediately usable for AI consumption
354
354
 
355
355
  ---
356
356
 
357
- ## Agent Transparency (v5.9.0)
357
+ ## Agent Transparency (v5.9.1)
358
358
 
359
359
  ### Agent Manual (Universal Protocols)
360
360
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -415,7 +415,7 @@ I'll update the PRD and add this to the refinement history. Confirm?
415
415
 
416
416
  ---
417
417
 
418
- ## Agent Transparency (v5.9.0)
418
+ ## Agent Transparency (v5.9.1)
419
419
 
420
420
  ### Agent Manual (Universal Protocols)
421
421
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -230,7 +230,7 @@ The goal is natural exploration of requirements, not a rigid questionnaire. Foll
230
230
 
231
231
  ---
232
232
 
233
- ## Agent Transparency (v5.9.0)
233
+ ## Agent Transparency (v5.9.1)
234
234
 
235
235
  ### Agent Manual (Universal Protocols)
236
236
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -409,7 +409,7 @@ The `/clavix:summarize` command extracts requirements from exploratory conversat
409
409
 
410
410
  ---
411
411
 
412
- ## Agent Transparency (v5.9.0)
412
+ ## Agent Transparency (v5.9.1)
413
413
 
414
414
  ### Agent Manual (Universal Protocols)
415
415
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -123,7 +123,7 @@ Implementation: BLOCKED - I'll analyze and report, not modify or fix
123
123
 
124
124
  ----
125
125
 
126
- ## Agent Transparency (v5.9.0)
126
+ ## Agent Transparency (v5.9.1)
127
127
 
128
128
  ### Agent Manual (Universal Protocols)
129
129
  {{INCLUDE:agent-protocols/AGENT_MANUAL.md}}
@@ -7,7 +7,9 @@ export interface ClavixConfig {
7
7
  templates: TemplateConfig;
8
8
  outputs: OutputConfig;
9
9
  preferences: PreferencesConfig;
10
- experimental?: Record<string, unknown>;
10
+ experimental?: Record<string, unknown> & {
11
+ integrationPaths?: IntegrationPathsConfig;
12
+ };
11
13
  }
12
14
  /**
13
15
  * Legacy config format (pre-v3.5.0)
@@ -37,6 +39,13 @@ export interface PreferencesConfig {
37
39
  autoOpenOutputs: boolean;
38
40
  verboseLogging: boolean;
39
41
  }
42
+ /**
43
+ * Custom directory paths for integrations
44
+ * Maps integration name (e.g., 'codex') to custom directory path
45
+ */
46
+ export interface IntegrationPathsConfig {
47
+ [integrationName: string]: string;
48
+ }
40
49
  export declare const DEFAULT_CONFIG: ClavixConfig;
41
50
  /**
42
51
  * Migrate legacy config to current format (v3.5.0+)
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Path resolution utility for integration directories
3
+ *
4
+ * Supports environment variable overrides with proper priority:
5
+ * 1. Environment variable (e.g., $CODEX_HOME)
6
+ * 2. User config override (experimental.integrationPaths)
7
+ * 3. Built-in default from integrations.json
8
+ */
9
+ import type { ClavixConfig } from '../types/config.js';
10
+ import type { AdapterConfig } from '../types/adapter-config.js';
11
+ /**
12
+ * Mapping of integration names to their environment variable names
13
+ *
14
+ * Future extensibility: Add more integrations here as needed
15
+ */
16
+ export declare const ENV_VAR_MAP: Record<string, string>;
17
+ /**
18
+ * Resolves the directory path for an integration based on priority:
19
+ * 1. Environment variable (highest priority)
20
+ * 2. User config override
21
+ * 3. Built-in default (fallback)
22
+ *
23
+ * @param config - The adapter configuration from integrations.json
24
+ * @param userConfig - The user's Clavix config (optional)
25
+ * @returns The resolved directory path with tilde expansion
26
+ */
27
+ export declare function resolveIntegrationPath(config: AdapterConfig, userConfig?: ClavixConfig): string;
28
+ //# sourceMappingURL=path-resolver.d.ts.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Path resolution utility for integration directories
3
+ *
4
+ * Supports environment variable overrides with proper priority:
5
+ * 1. Environment variable (e.g., $CODEX_HOME)
6
+ * 2. User config override (experimental.integrationPaths)
7
+ * 3. Built-in default from integrations.json
8
+ */
9
+ import * as os from 'os';
10
+ /**
11
+ * Mapping of integration names to their environment variable names
12
+ *
13
+ * Future extensibility: Add more integrations here as needed
14
+ */
15
+ export const ENV_VAR_MAP = {
16
+ codex: 'CODEX_HOME',
17
+ // Future: cursor: 'CURSOR_HOME',
18
+ // Future: gemini: 'GEMINI_HOME',
19
+ };
20
+ /**
21
+ * Resolves the directory path for an integration based on priority:
22
+ * 1. Environment variable (highest priority)
23
+ * 2. User config override
24
+ * 3. Built-in default (fallback)
25
+ *
26
+ * @param config - The adapter configuration from integrations.json
27
+ * @param userConfig - The user's Clavix config (optional)
28
+ * @returns The resolved directory path with tilde expansion
29
+ */
30
+ export function resolveIntegrationPath(config, userConfig) {
31
+ const integrationName = config.name;
32
+ // Priority 1: Environment variable
33
+ const envVar = ENV_VAR_MAP[integrationName];
34
+ if (envVar && process.env[envVar]) {
35
+ return process.env[envVar];
36
+ }
37
+ // Priority 2: User config override
38
+ const customPath = userConfig?.experimental?.integrationPaths?.[integrationName];
39
+ if (customPath && typeof customPath === 'string') {
40
+ return expandTilde(customPath);
41
+ }
42
+ // Priority 3: Built-in default from config
43
+ return expandTilde(config.directory);
44
+ }
45
+ /**
46
+ * Expands tilde (~) to the user's home directory
47
+ *
48
+ * @param dir - Directory path that may start with ~/
49
+ * @returns Directory path with ~ expanded to home directory
50
+ */
51
+ function expandTilde(dir) {
52
+ if (dir.startsWith('~/')) {
53
+ return dir.replace('~', os.homedir());
54
+ }
55
+ return dir;
56
+ }
57
+ //# sourceMappingURL=path-resolver.js.map
@@ -119,7 +119,6 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
119
119
  placeholder?: string | undefined;
120
120
  }[]>;
121
121
  }, "strip", z.ZodTypeAny, {
122
- version: string;
123
122
  integrations: {
124
123
  name: string;
125
124
  directory: string;
@@ -134,9 +133,9 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
134
133
  global?: boolean | undefined;
135
134
  placeholder?: string | undefined;
136
135
  }[];
136
+ version: string;
137
137
  $schema?: string | undefined;
138
138
  }, {
139
- version: string;
140
139
  integrations: {
141
140
  name: string;
142
141
  directory: string;
@@ -151,8 +150,14 @@ export declare const IntegrationsConfigSchema: z.ZodObject<{
151
150
  global?: boolean | undefined;
152
151
  placeholder?: string | undefined;
153
152
  }[];
153
+ version: string;
154
154
  $schema?: string | undefined;
155
155
  }>;
156
+ /**
157
+ * Schema for integration paths in experimental config
158
+ * Maps integration name to custom directory path
159
+ */
160
+ export declare const IntegrationPathsSchema: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
156
161
  /**
157
162
  * Schema for user's .clavix/config.json
158
163
  * Matches ClavixConfig interface in src/types/config.ts
@@ -194,11 +199,17 @@ export declare const UserConfigSchema: z.ZodObject<{
194
199
  autoOpenOutputs: boolean;
195
200
  verboseLogging: boolean;
196
201
  }>>;
197
- experimental: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
202
+ experimental: z.ZodOptional<z.ZodObject<{
203
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
204
+ }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
205
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
206
+ }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
207
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
208
+ }, z.ZodTypeAny, "passthrough">>>;
198
209
  }, "strip", z.ZodTypeAny, {
199
- version?: string | undefined;
200
- integrations?: string[] | undefined;
201
210
  providers?: string[] | undefined;
211
+ integrations?: string[] | undefined;
212
+ version?: string | undefined;
202
213
  templates?: {
203
214
  prdQuestions: string;
204
215
  fullPrd: string;
@@ -212,11 +223,13 @@ export declare const UserConfigSchema: z.ZodObject<{
212
223
  autoOpenOutputs: boolean;
213
224
  verboseLogging: boolean;
214
225
  } | undefined;
215
- experimental?: Record<string, unknown> | undefined;
226
+ experimental?: z.objectOutputType<{
227
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
228
+ }, z.ZodTypeAny, "passthrough"> | undefined;
216
229
  }, {
217
- version?: string | undefined;
218
- integrations?: string[] | undefined;
219
230
  providers?: string[] | undefined;
231
+ integrations?: string[] | undefined;
232
+ version?: string | undefined;
220
233
  templates?: {
221
234
  prdQuestions: string;
222
235
  fullPrd: string;
@@ -230,7 +243,9 @@ export declare const UserConfigSchema: z.ZodObject<{
230
243
  autoOpenOutputs: boolean;
231
244
  verboseLogging: boolean;
232
245
  } | undefined;
233
- experimental?: Record<string, unknown> | undefined;
246
+ experimental?: z.objectInputType<{
247
+ integrationPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
248
+ }, z.ZodTypeAny, "passthrough"> | undefined;
234
249
  }>;
235
250
  /**
236
251
  * Inferred TypeScript types from schemas
@@ -63,6 +63,21 @@ const PreferencesConfigSchema = z.object({
63
63
  autoOpenOutputs: z.boolean(),
64
64
  verboseLogging: z.boolean(),
65
65
  });
66
+ /**
67
+ * Schema for integration paths in experimental config
68
+ * Maps integration name to custom directory path
69
+ */
70
+ export const IntegrationPathsSchema = z
71
+ .record(z.string().min(1, 'Integration name is required'), z.string().min(1, 'Path cannot be empty'))
72
+ .optional();
73
+ /**
74
+ * Schema for experimental configuration
75
+ */
76
+ const ExperimentalConfigSchema = z
77
+ .object({
78
+ integrationPaths: IntegrationPathsSchema,
79
+ })
80
+ .passthrough(); // Allow other experimental fields
66
81
  /**
67
82
  * Schema for user's .clavix/config.json
68
83
  * Matches ClavixConfig interface in src/types/config.ts
@@ -78,7 +93,7 @@ export const UserConfigSchema = z.object({
78
93
  templates: TemplateConfigSchema.optional(),
79
94
  outputs: OutputConfigSchema.optional(),
80
95
  preferences: PreferencesConfigSchema.optional(),
81
- experimental: z.record(z.unknown()).optional(),
96
+ experimental: ExperimentalConfigSchema.optional(),
82
97
  });
83
98
  /**
84
99
  * Validate integrations.json content (build-time, strict)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clavix",
3
- "version": "5.9.0",
3
+ "version": "5.9.1",
4
4
  "description": "Agentic-first prompt workflows. Markdown templates that teach AI agents how to optimize prompts, create PRDs, and manage implementation.\n\nSLASH COMMANDS (in your AI assistant):\n /clavix:improve Optimize prompts with auto-depth\n /clavix:prd Generate PRD through questions\n /clavix:plan Create task breakdown from PRD\n /clavix:implement Execute tasks with progress tracking\n /clavix:start Begin conversational session\n /clavix:summarize Extract requirements from conversation\n /clavix:refine Refine existing PRD or prompt\n /clavix:verify Verify implementation against requirements\n /clavix:archive Archive completed projects\n\nWorks with Claude Code, Cursor, Windsurf, and 20 AI coding tools.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -70,6 +70,7 @@
70
70
  "@oclif/core": "^4.8.0",
71
71
  "@oclif/plugin-help": "^6.2.35",
72
72
  "chalk": "^5.6.2",
73
+ "clavix": "^5.9.0",
73
74
  "fs-extra": "^11.3.2",
74
75
  "inquirer": "^12.11.1",
75
76
  "zod": "^3.24.4"