@theunwalked/cardigantime 0.0.21 → 0.0.23

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 (61) hide show
  1. package/README.md +197 -4
  2. package/dist/cardigantime.cjs +107 -19
  3. package/dist/cardigantime.cjs.map +1 -1
  4. package/dist/cardigantime.d.ts +24 -0
  5. package/dist/cardigantime.js +28 -3
  6. package/dist/cardigantime.js.map +1 -1
  7. package/dist/config/executable-security.d.ts +32 -0
  8. package/dist/config/format-detector.d.ts +59 -0
  9. package/dist/configure.js +14 -0
  10. package/dist/configure.js.map +1 -1
  11. package/dist/constants.js +3 -1
  12. package/dist/constants.js.map +1 -1
  13. package/dist/discovery/discoverer.d.ts +62 -0
  14. package/dist/discovery/hierarchical-modes.d.ts +64 -0
  15. package/dist/discovery/index.d.ts +15 -0
  16. package/dist/discovery/patterns.d.ts +77 -0
  17. package/dist/discovery/root-detection.d.ts +100 -0
  18. package/dist/discovery/traversal-security.d.ts +106 -0
  19. package/dist/error/ConfigParseError.d.ts +26 -0
  20. package/dist/error/index.d.ts +1 -0
  21. package/dist/mcp/discovery.d.ts +105 -0
  22. package/dist/mcp/errors.d.ts +75 -0
  23. package/dist/mcp/index.d.ts +22 -0
  24. package/dist/mcp/integration.d.ts +184 -0
  25. package/dist/mcp/parser.d.ts +141 -0
  26. package/dist/mcp/resolver.d.ts +127 -0
  27. package/dist/mcp/tools/check-config-types.d.ts +208 -0
  28. package/dist/mcp/tools/check-config.d.ts +85 -0
  29. package/dist/mcp/tools/index.d.ts +12 -0
  30. package/dist/mcp/types.d.ts +171 -0
  31. package/dist/parsers/index.d.ts +25 -0
  32. package/dist/parsers/javascript-parser.d.ts +12 -0
  33. package/dist/parsers/json-parser.d.ts +6 -0
  34. package/dist/parsers/typescript-parser.d.ts +15 -0
  35. package/dist/parsers/yaml-parser.d.ts +6 -0
  36. package/dist/read.js +1 -1
  37. package/dist/read.js.map +1 -1
  38. package/dist/security/audit-logger.d.ts +135 -0
  39. package/dist/security/cli-validator.d.ts +73 -0
  40. package/dist/security/config-validator.d.ts +95 -0
  41. package/dist/security/defaults.d.ts +17 -0
  42. package/dist/security/index.d.ts +14 -0
  43. package/dist/security/numeric-guard.d.ts +111 -0
  44. package/dist/security/path-guard.d.ts +53 -0
  45. package/dist/security/profiles.d.ts +127 -0
  46. package/dist/security/security-validator.d.ts +109 -0
  47. package/dist/security/string-guard.d.ts +92 -0
  48. package/dist/security/types.d.ts +126 -0
  49. package/dist/security/zod-secure-enum.d.ts +20 -0
  50. package/dist/security/zod-secure-number.d.ts +39 -0
  51. package/dist/security/zod-secure-path.d.ts +24 -0
  52. package/dist/security/zod-secure-string.d.ts +38 -0
  53. package/dist/types.d.ts +431 -0
  54. package/dist/types.js +44 -1
  55. package/dist/types.js.map +1 -1
  56. package/dist/util/hierarchical.js +14 -14
  57. package/dist/util/hierarchical.js.map +1 -1
  58. package/dist/util/storage.d.ts +1 -1
  59. package/dist/util/storage.js +4 -5
  60. package/dist/util/storage.js.map +1 -1
  61. package/package.json +2 -2
package/README.md CHANGED
@@ -6,7 +6,7 @@ A robust TypeScript library for configuration management in command-line applica
6
6
 
7
7
  Cardigantime is a configuration management library designed to solve the common problem of handling configuration in CLI applications. It provides a unified way to:
8
8
 
9
- - **Read configuration from YAML files** with intelligent file discovery
9
+ - **Read configuration from multiple formats** (YAML, JSON, JavaScript, TypeScript) with intelligent file discovery
10
10
  - **Validate configuration** using Zod schemas for type safety
11
11
  - **Integrate with CLI frameworks** like Commander.js seamlessly
12
12
  - **Merge configuration sources** (files, CLI args, defaults) with proper precedence
@@ -24,6 +24,35 @@ Without Cardigantime, you need to manually handle:
24
24
 
25
25
  Cardigantime provides a complete, battle-tested solution for all of this complexity.
26
26
 
27
+ ### One Schema, Multiple Formats
28
+
29
+ Define your configuration schema once with Zod, and Cardigantime automatically supports:
30
+ - **YAML** (`.yaml`, `.yml`) - Human-readable, great for hand-edited configs
31
+ - **JSON** (`.json`) - Strict syntax, ideal for programmatic generation
32
+ - **JavaScript** (`.js`, `.mjs`, `.cjs`) - Dynamic configs with environment logic
33
+ - **TypeScript** (`.ts`, `.mts`, `.cts`) - Type-safe configs with IDE support
34
+
35
+ No additional code or schema definitions needed per format. Your users choose their preferred format, and Cardigantime handles parsing, validation, and merging automatically.
36
+
37
+ ## Who Uses Cardigantime?
38
+
39
+ Cardigantime serves two distinct audiences:
40
+
41
+ ### Tool Developers
42
+ Developers building CLI applications who want robust configuration management without the boilerplate. You integrate Cardigantime once, define your Zod schema, and get:
43
+ - Multi-format config file support out of the box
44
+ - Automatic CLI option generation
45
+ - Deep merging with proper precedence
46
+ - Hierarchical config discovery (like `.eslintrc` or `.gitignore`)
47
+ - Type safety throughout your codebase
48
+
49
+ ### End Users
50
+ Users of tools built with Cardigantime benefit from a consistent, powerful configuration experience without needing to know Cardigantime exists. They get:
51
+ - Freedom to use their preferred config format (YAML, JSON, JS, or TS)
52
+ - Consistent CLI options across tools
53
+ - Clear, actionable error messages
54
+ - Built-in config generation (`--init-config`) and analysis (`--check-config`)
55
+
27
56
  ## Installation
28
57
 
29
58
  ```bash
@@ -102,8 +131,84 @@ async function main() {
102
131
  main().catch(console.error);
103
132
  ```
104
133
 
105
- ### Example Configuration File (`config/myapp.yaml`)
134
+ ### Version Information with Git Details
135
+
136
+ Cardigantime exports its own version information including git commit details. You can also set up the same pattern in your own project.
137
+
138
+ #### Using Cardigantime's Version
139
+
140
+ ```typescript
141
+ import { VERSION, PROGRAM_NAME } from '@theunwalked/cardigantime';
142
+
143
+ console.log(`Using ${PROGRAM_NAME}: ${VERSION}`);
144
+ // Output: Using cardigantime: 0.0.22-dev.0 (working/a1b2c3d 2026-01-27 11:11:46 -0800) darwin arm64 v24.8.0
145
+ ```
146
+
147
+ #### Setting Up Version Info in Your Own Project
148
+
149
+ To add the same detailed version format to your own CLI application, add this to your `vite.config.ts`:
150
+
151
+ ```typescript
152
+ import { defineConfig } from 'vite';
153
+ import replace from '@rollup/plugin-replace';
154
+ import { execSync } from 'node:child_process';
155
+
156
+ // Extract git information at build time
157
+ let gitInfo = {
158
+ branch: '',
159
+ commit: '',
160
+ tags: '',
161
+ commitDate: '',
162
+ };
163
+
164
+ try {
165
+ gitInfo = {
166
+ branch: execSync('git rev-parse --abbrev-ref HEAD').toString().trim(),
167
+ commit: execSync('git rev-parse --short HEAD').toString().trim(),
168
+ tags: '',
169
+ commitDate: execSync('git log -1 --format=%cd --date=iso').toString().trim(),
170
+ };
171
+
172
+ try {
173
+ gitInfo.tags = execSync('git tag --points-at HEAD | paste -sd "," -').toString().trim();
174
+ } catch {
175
+ gitInfo.tags = '';
176
+ }
177
+ } catch {
178
+ console.log('Directory does not have a Git repository, skipping git info');
179
+ }
180
+
181
+ export default defineConfig({
182
+ plugins: [
183
+ replace({
184
+ '__VERSION__': process.env.npm_package_version,
185
+ '__GIT_BRANCH__': gitInfo.branch,
186
+ '__GIT_COMMIT__': gitInfo.commit,
187
+ '__GIT_TAGS__': gitInfo.tags === '' ? '' : `T:${gitInfo.tags}`,
188
+ '__GIT_COMMIT_DATE__': gitInfo.commitDate,
189
+ '__SYSTEM_INFO__': `${process.platform} ${process.arch} ${process.version}`,
190
+ preventAssignment: true,
191
+ }),
192
+ // ... your other plugins
193
+ ],
194
+ // ... rest of your config
195
+ });
196
+ ```
197
+
198
+ Then in your constants file:
199
+
200
+ ```typescript
201
+ export const VERSION = '__VERSION__ (__GIT_BRANCH__/__GIT_COMMIT__ __GIT_TAGS__ __GIT_COMMIT_DATE__) __SYSTEM_INFO__';
202
+ export const PROGRAM_NAME = 'myapp';
203
+ ```
204
+
205
+ The placeholders will be replaced at build time with actual values. This is particularly useful for CLI applications where you need visibility into exactly which build is running.
206
+
207
+ ### Configuration File Examples
106
208
 
209
+ Cardigantime supports multiple configuration formats. Choose the one that best fits your workflow:
210
+
211
+ #### YAML (`config/myapp.yaml`)
107
212
  ```yaml
108
213
  apiKey: "your-secret-api-key"
109
214
  timeout: 10000
@@ -111,6 +216,47 @@ retries: 5
111
216
  debug: true
112
217
  ```
113
218
 
219
+ #### JSON (`config/myapp.json`)
220
+ ```json
221
+ {
222
+ "apiKey": "your-secret-api-key",
223
+ "timeout": 10000,
224
+ "retries": 5,
225
+ "debug": true
226
+ }
227
+ ```
228
+
229
+ #### JavaScript (`config/myapp.js`)
230
+ ```javascript
231
+ module.exports = {
232
+ apiKey: process.env.API_KEY || "your-secret-api-key",
233
+ timeout: 10000,
234
+ retries: 5,
235
+ debug: process.env.NODE_ENV === 'development'
236
+ };
237
+ ```
238
+
239
+ #### TypeScript (`config/myapp.ts`)
240
+ ```typescript
241
+ export default {
242
+ apiKey: process.env.API_KEY || "your-secret-api-key",
243
+ timeout: 10000,
244
+ retries: 5,
245
+ debug: process.env.NODE_ENV === 'development'
246
+ } as const;
247
+ ```
248
+
249
+ **Format Priority:** When multiple config files exist, Cardigantime uses this priority order:
250
+ 1. TypeScript (`.ts`, `.mts`, `.cts`) - Highest priority
251
+ 2. JavaScript (`.js`, `.mjs`, `.cjs`)
252
+ 3. JSON (`.json`)
253
+ 4. YAML (`.yaml`, `.yml`) - Lowest priority
254
+
255
+ You can override automatic detection with `--config-format`:
256
+ ```bash
257
+ ./myapp --config-format yaml # Force YAML even if JSON exists
258
+ ```
259
+
114
260
  ### Example Usage
115
261
 
116
262
  ```bash
@@ -138,12 +284,57 @@ Merges configuration from multiple sources in order of precedence:
138
284
  2. **Configuration file(s)** (medium priority)
139
285
  3. **Default values** (lowest priority)
140
286
 
141
- ### Flexible YAML Support
142
- Supports both `.yaml` and `.yml` file extensions with automatic fallback - if `config.yaml` isn't found, Cardigantime automatically tries `config.yml` (and vice versa).
287
+ ### Multi-Format Configuration
288
+ Supports YAML (`.yaml`, `.yml`), JSON (`.json`), JavaScript (`.js`, `.mjs`, `.cjs`), and TypeScript (`.ts`, `.mts`, `.cts`) configuration files. When multiple formats exist, Cardigantime uses automatic format detection with configurable priority.
289
+
290
+ ### Configuration Discovery
291
+
292
+ Cardigantime automatically searches for configuration files using multiple naming conventions, similar to how tools like Vite, ESLint, and TypeScript work:
293
+
294
+ | Priority | Pattern | Example |
295
+ |----------|---------|---------|
296
+ | 1 | `{app}.config.{ext}` | `myapp.config.yaml` |
297
+ | 2 | `{app}.conf.{ext}` | `myapp.conf.yaml` |
298
+ | 3 | `.{app}/config.{ext}` | `.myapp/config.yaml` |
299
+ | 4 | `.{app}rc.{ext}` | `.myapprc.yaml` |
300
+ | 5 | `.{app}rc` | `.myapprc` |
301
+
302
+ Modern visible config files (like `myapp.config.yaml`) are checked first for better discoverability.
143
303
 
144
304
  ### Hierarchical Configuration Discovery
145
305
  Supports hierarchical configuration discovery, similar to how `.gitignore`, `.eslintrc`, or `package.json` work - searching up the directory tree for configuration directories.
146
306
 
307
+ **Hierarchical Modes:**
308
+ - `enabled` (default) - Merge configs from parent directories
309
+ - `disabled` - Use only the config in the starting directory
310
+ - `root-only` - Find first config, no merging
311
+ - `explicit` - Only merge explicitly referenced configs
312
+
313
+ ```yaml
314
+ # Disable hierarchical for isolated projects
315
+ hierarchical:
316
+ mode: disabled
317
+ ```
318
+
319
+ ### MCP Integration
320
+ First-class support for Model Context Protocol (MCP), enabling AI assistants to configure tools directly through MCP invocations. Includes:
321
+ - **MCP Configuration Priority** - MCP config takes exclusive precedence when provided
322
+ - **File-Based Fallback** - Automatic discovery from target file or working directory
323
+ - **CheckConfig Tool** - Built-in diagnostic tool for all MCP tools
324
+ - **Integration Helpers** - Simple APIs for adding MCP support to your tools
325
+
326
+ ```typescript
327
+ import { createMCPIntegration } from '@theunwalked/cardigantime/mcp';
328
+
329
+ const integration = createMCPIntegration({
330
+ appName: 'myapp',
331
+ configSchema: myConfigSchema,
332
+ });
333
+
334
+ // CheckConfig tool is automatically available
335
+ // Config resolution handles MCP and file-based sources
336
+ ```
337
+
147
338
  ### Type Safety & Validation
148
339
  Full TypeScript support with Zod schema validation for robust, type-safe configuration management.
149
340
 
@@ -157,6 +348,8 @@ Comprehensive error handling with detailed, actionable error messages to help us
157
348
  **Quick Links:**
158
349
  - [Getting Started Guide](https://utilarium.github.io/cardigantime/#getting-started) - Detailed setup and basic concepts
159
350
  - [Core Concepts](https://utilarium.github.io/cardigantime/#core-concepts) - Configuration sources, hierarchical discovery
351
+ - [MCP Integration](https://utilarium.github.io/cardigantime/#mcp-integration) - Model Context Protocol support for AI assistants
352
+ - [CheckConfig Tool](https://utilarium.github.io/cardigantime/#check-config-tool) - Built-in diagnostic tool
160
353
  - [API Reference](https://utilarium.github.io/cardigantime/#api-reference) - Complete API documentation
161
354
  - [Configuration Options](https://utilarium.github.io/cardigantime/#configuration-options) - All available options
162
355
  - [Debugging & Analysis](https://utilarium.github.io/cardigantime/#debugging-analysis) - Tools for analyzing config
@@ -3,10 +3,10 @@
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const yaml = require('js-yaml');
6
- const path = require('path');
7
- const fs = require('fs');
6
+ const path = require('node:path');
7
+ const fs = require('node:fs');
8
8
  const glob = require('glob');
9
- const crypto = require('crypto');
9
+ const crypto = require('node:crypto');
10
10
  const zod = require('zod');
11
11
 
12
12
  function _interopNamespaceDefault(e) {
@@ -29,6 +29,7 @@ function _interopNamespaceDefault(e) {
29
29
  const yaml__namespace = /*#__PURE__*/_interopNamespaceDefault(yaml);
30
30
  const path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
31
31
  const fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
32
+ const crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
32
33
 
33
34
  function _define_property$2(obj, key, value) {
34
35
  if (key in obj) {
@@ -180,9 +181,25 @@ function _define_property$2(obj, key, value) {
180
181
  retCommand = retCommand.option('--init-config', 'Generate initial configuration file and exit');
181
182
  // Add the check config option
182
183
  retCommand = retCommand.option('--check-config', 'Display resolved configuration with source tracking and exit');
184
+ // Add the config format option
185
+ retCommand = retCommand.option('--config-format <format>', 'Force a specific configuration file format (yaml, json, javascript, typescript)', (value)=>{
186
+ const validFormats = [
187
+ 'yaml',
188
+ 'json',
189
+ 'javascript',
190
+ 'typescript'
191
+ ];
192
+ const normalized = value.toLowerCase();
193
+ if (!validFormats.includes(normalized)) {
194
+ throw new ArgumentError('config-format', `Invalid --config-format: must be one of ${validFormats.join(', ')}`);
195
+ }
196
+ return normalized;
197
+ });
183
198
  return retCommand;
184
199
  };
185
200
 
201
+ /** Version string populated at build time with git and system information */ const VERSION = '0.0.23 (HEAD/b3ed796 T:v0.0.23 2026-01-27 14:30:06 -0800) linux x64 v24.13.0';
202
+ /** The program name used in CLI help and error messages */ const PROGRAM_NAME = 'cardigantime';
186
203
  /** Default file encoding for reading configuration files */ const DEFAULT_ENCODING = 'utf8';
187
204
  /** Default configuration file name to look for in the config directory */ const DEFAULT_CONFIG_FILE = 'config.yaml';
188
205
  /**
@@ -273,7 +290,6 @@ function _define_property$1(obj, key, value) {
273
290
  }
274
291
  }
275
292
 
276
- // eslint-disable-next-line no-restricted-imports
277
293
  const create$1 = (params)=>{
278
294
  // eslint-disable-next-line no-console
279
295
  const log = params.log || console.log;
@@ -385,7 +401,7 @@ const create$1 = (params)=>{
385
401
  nodir: true
386
402
  });
387
403
  for (const file of files){
388
- await callback(path.join(directory, file));
404
+ await callback(path__namespace.join(directory, file));
389
405
  }
390
406
  } catch (err) {
391
407
  throw FileSystemError.operationFailed(`glob pattern ${options.pattern}`, directory, err);
@@ -396,7 +412,7 @@ const create$1 = (params)=>{
396
412
  };
397
413
  const hashFile = async (path, length)=>{
398
414
  const file = await readFile(path, 'utf8');
399
- return crypto.createHash('sha256').update(file).digest('hex').slice(0, length);
415
+ return crypto__namespace.createHash('sha256').update(file).digest('hex').slice(0, length);
400
416
  };
401
417
  const listFiles = async (directory)=>{
402
418
  return await fs__namespace.promises.readdir(directory);
@@ -482,10 +498,10 @@ function setNestedValue$1(obj, path, value) {
482
498
  /**
483
499
  * Resolves a single path string relative to the config directory if it's a relative path.
484
500
  */ function resolveSinglePath$1(pathStr, configDir) {
485
- if (!pathStr || path.isAbsolute(pathStr)) {
501
+ if (!pathStr || path__namespace.isAbsolute(pathStr)) {
486
502
  return pathStr;
487
503
  }
488
- return path.resolve(configDir, pathStr);
504
+ return path__namespace.resolve(configDir, pathStr);
489
505
  }
490
506
  /**
491
507
  * Discovers configuration directories by traversing up the directory tree.
@@ -516,19 +532,19 @@ function setNestedValue$1(obj, path, value) {
516
532
  log: (logger === null || logger === void 0 ? void 0 : logger.debug) || (()=>{})
517
533
  });
518
534
  const discoveredDirs = [];
519
- let currentDir = path.resolve(startingDir);
535
+ let currentDir = path__namespace.resolve(startingDir);
520
536
  let level = 0;
521
537
  const visited = new Set(); // Prevent infinite loops with symlinks
522
538
  logger === null || logger === void 0 ? void 0 : logger.debug(`Starting hierarchical discovery from: ${currentDir}`);
523
539
  while(level < maxLevels){
524
540
  // Prevent infinite loops with symlinks
525
- const realPath = path.resolve(currentDir);
541
+ const realPath = path__namespace.resolve(currentDir);
526
542
  if (visited.has(realPath)) {
527
543
  logger === null || logger === void 0 ? void 0 : logger.debug(`Already visited ${realPath}, stopping discovery`);
528
544
  break;
529
545
  }
530
546
  visited.add(realPath);
531
- const configDirPath = path.join(currentDir, configDirName);
547
+ const configDirPath = path__namespace.join(currentDir, configDirName);
532
548
  logger === null || logger === void 0 ? void 0 : logger.debug(`Checking for config directory: ${configDirPath}`);
533
549
  try {
534
550
  const exists = await storage.exists(configDirPath);
@@ -546,7 +562,7 @@ function setNestedValue$1(obj, path, value) {
546
562
  logger === null || logger === void 0 ? void 0 : logger.debug(`Error checking config directory ${configDirPath}: ${error.message}`);
547
563
  }
548
564
  // Move up one directory level
549
- const parentDir = path.dirname(currentDir);
565
+ const parentDir = path__namespace.dirname(currentDir);
550
566
  // Check if we've reached the root directory
551
567
  if (parentDir === currentDir) {
552
568
  logger === null || logger === void 0 ? void 0 : logger.debug('Reached filesystem root, stopping discovery');
@@ -567,7 +583,7 @@ function setNestedValue$1(obj, path, value) {
567
583
  * @param logger Optional logger for debugging
568
584
  * @returns Promise resolving to the found config file path or null if not found
569
585
  */ async function findConfigFileWithExtension$1(storage, configDir, configFileName, logger) {
570
- const configFilePath = path.join(configDir, configFileName);
586
+ const configFilePath = path__namespace.join(configDir, configFileName);
571
587
  // First try the exact filename as specified
572
588
  const exists = await storage.exists(configFilePath);
573
589
  if (exists) {
@@ -578,11 +594,11 @@ function setNestedValue$1(obj, path, value) {
578
594
  }
579
595
  // If the exact filename doesn't exist or isn't readable, try alternative extensions
580
596
  // Only do this if the filename has a .yaml or .yml extension
581
- const ext = path.extname(configFileName);
597
+ const ext = path__namespace.extname(configFileName);
582
598
  if (ext === '.yaml' || ext === '.yml') {
583
- const baseName = path.basename(configFileName, ext);
599
+ const baseName = path__namespace.basename(configFileName, ext);
584
600
  const alternativeExt = ext === '.yaml' ? '.yml' : '.yaml';
585
- const alternativePath = path.join(configDir, baseName + alternativeExt);
601
+ const alternativePath = path__namespace.join(configDir, baseName + alternativeExt);
586
602
  logger === null || logger === void 0 ? void 0 : logger.debug(`Config file not found at ${configFilePath}, trying alternative: ${alternativePath}`);
587
603
  const altExists = await storage.exists(alternativePath);
588
604
  if (altExists) {
@@ -610,11 +626,11 @@ function setNestedValue$1(obj, path, value) {
610
626
  log: (logger === null || logger === void 0 ? void 0 : logger.debug) || (()=>{})
611
627
  });
612
628
  try {
613
- logger === null || logger === void 0 ? void 0 : logger.verbose(`Attempting to load config file: ${path.join(configDir, configFileName)}`);
629
+ logger === null || logger === void 0 ? void 0 : logger.verbose(`Attempting to load config file: ${path__namespace.join(configDir, configFileName)}`);
614
630
  // Try to find the config file with alternative extensions
615
631
  const configFilePath = await findConfigFileWithExtension$1(storage, configDir, configFileName, logger);
616
632
  if (!configFilePath) {
617
- logger === null || logger === void 0 ? void 0 : logger.debug(`Config file does not exist: ${path.join(configDir, configFileName)}`);
633
+ logger === null || logger === void 0 ? void 0 : logger.debug(`Config file does not exist: ${path__namespace.join(configDir, configFileName)}`);
618
634
  return null;
619
635
  }
620
636
  const yamlContent = await storage.readFile(configFilePath, encoding);
@@ -632,7 +648,7 @@ function setNestedValue$1(obj, path, value) {
632
648
  return null;
633
649
  }
634
650
  } catch (error) {
635
- logger === null || logger === void 0 ? void 0 : logger.debug(`Error loading config from ${path.join(configDir, configFileName)}: ${error.message}`);
651
+ logger === null || logger === void 0 ? void 0 : logger.debug(`Error loading config from ${path__namespace.join(configDir, configFileName)}: ${error.message}`);
636
652
  return null;
637
653
  }
638
654
  }
@@ -1540,6 +1556,20 @@ function _define_property(obj, key, value) {
1540
1556
  }
1541
1557
  }
1542
1558
 
1559
+ /**
1560
+ * Supported configuration file formats.
1561
+ *
1562
+ * - 'yaml': YAML format (.yaml, .yml)
1563
+ * - 'json': JSON format (.json)
1564
+ * - 'javascript': JavaScript module (.js, .mjs, .cjs)
1565
+ * - 'typescript': TypeScript module (.ts, .mts, .cts)
1566
+ */ var ConfigFormat = /*#__PURE__*/ function(ConfigFormat) {
1567
+ ConfigFormat["YAML"] = "yaml";
1568
+ ConfigFormat["JSON"] = "json";
1569
+ ConfigFormat["JavaScript"] = "javascript";
1570
+ ConfigFormat["TypeScript"] = "typescript";
1571
+ return ConfigFormat;
1572
+ }({});
1543
1573
  /**
1544
1574
  * Base Zod schema for core Cardigantime configuration.
1545
1575
  * Contains the minimum required configuration fields.
@@ -1548,6 +1578,35 @@ function _define_property(obj, key, value) {
1548
1578
  /** Array of all directory paths that were discovered during hierarchical search */ discoveredConfigDirs: zod.z.array(zod.z.string()),
1549
1579
  /** Array of directory paths that actually contained valid configuration files */ resolvedConfigDirs: zod.z.array(zod.z.string())
1550
1580
  });
1581
+ /**
1582
+ * Default root markers used when none are specified.
1583
+ * These indicate common project root boundaries.
1584
+ */ const DEFAULT_ROOT_MARKERS = [
1585
+ {
1586
+ type: 'file',
1587
+ name: 'package.json'
1588
+ },
1589
+ {
1590
+ type: 'directory',
1591
+ name: '.git'
1592
+ },
1593
+ {
1594
+ type: 'file',
1595
+ name: 'pnpm-workspace.yaml'
1596
+ },
1597
+ {
1598
+ type: 'file',
1599
+ name: 'lerna.json'
1600
+ },
1601
+ {
1602
+ type: 'file',
1603
+ name: 'nx.json'
1604
+ },
1605
+ {
1606
+ type: 'file',
1607
+ name: 'rush.json'
1608
+ }
1609
+ ];
1551
1610
 
1552
1611
  /**
1553
1612
  * Recursively extracts all keys from a Zod schema in dot notation.
@@ -2072,10 +2131,39 @@ function _define_property(obj, key, value) {
2072
2131
  checkConfig: (args)=>checkConfig(args, options)
2073
2132
  };
2074
2133
  };
2134
+ /**
2135
+ * Type-safe helper for defining configuration in TypeScript/JavaScript files.
2136
+ *
2137
+ * This is a simple identity function that provides type checking and
2138
+ * autocomplete for configuration objects when using TypeScript config files.
2139
+ *
2140
+ * @template T - The configuration type
2141
+ * @param config - The configuration object
2142
+ * @returns The same configuration object (identity function)
2143
+ *
2144
+ * @example
2145
+ * ```typescript
2146
+ * // config.ts
2147
+ * import { defineConfig } from '@theunwalked/cardigantime';
2148
+ *
2149
+ * export default defineConfig({
2150
+ * apiKey: process.env.API_KEY || 'default-key',
2151
+ * timeout: 5000,
2152
+ * debug: process.env.NODE_ENV === 'development'
2153
+ * });
2154
+ * ```
2155
+ */ function defineConfig(config) {
2156
+ return config;
2157
+ }
2075
2158
 
2076
2159
  exports.ArgumentError = ArgumentError;
2160
+ exports.ConfigFormat = ConfigFormat;
2077
2161
  exports.ConfigSchema = ConfigSchema;
2078
2162
  exports.ConfigurationError = ConfigurationError;
2163
+ exports.DEFAULT_ROOT_MARKERS = DEFAULT_ROOT_MARKERS;
2079
2164
  exports.FileSystemError = FileSystemError;
2165
+ exports.PROGRAM_NAME = PROGRAM_NAME;
2166
+ exports.VERSION = VERSION;
2080
2167
  exports.create = create;
2168
+ exports.defineConfig = defineConfig;
2081
2169
  //# sourceMappingURL=cardigantime.cjs.map