micro-contracts 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +351 -0
  3. package/dist/cli/templates.d.ts +16 -0
  4. package/dist/cli/templates.d.ts.map +1 -0
  5. package/dist/cli/templates.js +377 -0
  6. package/dist/cli/templates.js.map +1 -0
  7. package/dist/cli.d.ts +9 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +978 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/generator/dependencyGenerator.d.ts +43 -0
  12. package/dist/generator/dependencyGenerator.d.ts.map +1 -0
  13. package/dist/generator/dependencyGenerator.js +159 -0
  14. package/dist/generator/dependencyGenerator.js.map +1 -0
  15. package/dist/generator/domainGenerator.d.ts +16 -0
  16. package/dist/generator/domainGenerator.d.ts.map +1 -0
  17. package/dist/generator/domainGenerator.js +212 -0
  18. package/dist/generator/domainGenerator.js.map +1 -0
  19. package/dist/generator/index.d.ts +37 -0
  20. package/dist/generator/index.d.ts.map +1 -0
  21. package/dist/generator/index.js +747 -0
  22. package/dist/generator/index.js.map +1 -0
  23. package/dist/generator/linter.d.ts +24 -0
  24. package/dist/generator/linter.d.ts.map +1 -0
  25. package/dist/generator/linter.js +202 -0
  26. package/dist/generator/linter.js.map +1 -0
  27. package/dist/generator/overlayProcessor.d.ts +90 -0
  28. package/dist/generator/overlayProcessor.d.ts.map +1 -0
  29. package/dist/generator/overlayProcessor.js +532 -0
  30. package/dist/generator/overlayProcessor.js.map +1 -0
  31. package/dist/generator/schemaGenerator.d.ts +10 -0
  32. package/dist/generator/schemaGenerator.d.ts.map +1 -0
  33. package/dist/generator/schemaGenerator.js +299 -0
  34. package/dist/generator/schemaGenerator.js.map +1 -0
  35. package/dist/generator/templateProcessor.d.ts +178 -0
  36. package/dist/generator/templateProcessor.d.ts.map +1 -0
  37. package/dist/generator/templateProcessor.js +607 -0
  38. package/dist/generator/templateProcessor.js.map +1 -0
  39. package/dist/generator/typeGenerator.d.ts +9 -0
  40. package/dist/generator/typeGenerator.d.ts.map +1 -0
  41. package/dist/generator/typeGenerator.js +395 -0
  42. package/dist/generator/typeGenerator.js.map +1 -0
  43. package/dist/guardrails/allowlist.d.ts +45 -0
  44. package/dist/guardrails/allowlist.d.ts.map +1 -0
  45. package/dist/guardrails/allowlist.js +261 -0
  46. package/dist/guardrails/allowlist.js.map +1 -0
  47. package/dist/guardrails/config.d.ts +40 -0
  48. package/dist/guardrails/config.d.ts.map +1 -0
  49. package/dist/guardrails/config.js +174 -0
  50. package/dist/guardrails/config.js.map +1 -0
  51. package/dist/guardrails/docs.d.ts +24 -0
  52. package/dist/guardrails/docs.d.ts.map +1 -0
  53. package/dist/guardrails/docs.js +138 -0
  54. package/dist/guardrails/docs.js.map +1 -0
  55. package/dist/guardrails/drift.d.ts +23 -0
  56. package/dist/guardrails/drift.d.ts.map +1 -0
  57. package/dist/guardrails/drift.js +127 -0
  58. package/dist/guardrails/drift.js.map +1 -0
  59. package/dist/guardrails/index.d.ts +19 -0
  60. package/dist/guardrails/index.d.ts.map +1 -0
  61. package/dist/guardrails/index.js +25 -0
  62. package/dist/guardrails/index.js.map +1 -0
  63. package/dist/guardrails/lint.d.ts +20 -0
  64. package/dist/guardrails/lint.d.ts.map +1 -0
  65. package/dist/guardrails/lint.js +274 -0
  66. package/dist/guardrails/lint.js.map +1 -0
  67. package/dist/guardrails/manifest.d.ts +43 -0
  68. package/dist/guardrails/manifest.d.ts.map +1 -0
  69. package/dist/guardrails/manifest.js +231 -0
  70. package/dist/guardrails/manifest.js.map +1 -0
  71. package/dist/guardrails/runner.d.ts +31 -0
  72. package/dist/guardrails/runner.d.ts.map +1 -0
  73. package/dist/guardrails/runner.js +268 -0
  74. package/dist/guardrails/runner.js.map +1 -0
  75. package/dist/guardrails/security.d.ts +31 -0
  76. package/dist/guardrails/security.d.ts.map +1 -0
  77. package/dist/guardrails/security.js +181 -0
  78. package/dist/guardrails/security.js.map +1 -0
  79. package/dist/guardrails/typecheck.d.ts +15 -0
  80. package/dist/guardrails/typecheck.d.ts.map +1 -0
  81. package/dist/guardrails/typecheck.js +104 -0
  82. package/dist/guardrails/typecheck.js.map +1 -0
  83. package/dist/guardrails/types.d.ts +196 -0
  84. package/dist/guardrails/types.d.ts.map +1 -0
  85. package/dist/guardrails/types.js +8 -0
  86. package/dist/guardrails/types.js.map +1 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +7 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/types.d.ts +489 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/types.js +297 -0
  94. package/dist/types.js.map +1 -0
  95. package/docs/architecture.svg +226 -0
  96. package/docs/development-guardrails.md +541 -0
  97. package/docs/guardrails-concept.svg +252 -0
  98. package/docs/overlays-deep-dive.md +298 -0
  99. package/package.json +66 -0
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Allowlist verification for guardrails
3
+ *
4
+ * Verifies that changed files are within allowed boundaries.
5
+ */
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { execSync } from 'child_process';
9
+ import { loadGuardrailsConfigWithPath } from './config.js';
10
+ /**
11
+ * Simple glob pattern matching with negation support
12
+ * Patterns are evaluated top-to-bottom; last match wins.
13
+ * - "!pattern" → if matched, result becomes false (exclude)
14
+ * - "pattern" → if matched, result becomes true (include)
15
+ */
16
+ export function matchWithNegation(patterns, file) {
17
+ if (!patterns || patterns.length === 0)
18
+ return false;
19
+ let matched = false;
20
+ for (const raw of patterns) {
21
+ const neg = raw.startsWith('!');
22
+ const pattern = neg ? raw.slice(1) : raw;
23
+ if (!pattern)
24
+ continue;
25
+ if (matchGlob(file, pattern)) {
26
+ matched = !neg;
27
+ }
28
+ }
29
+ return matched;
30
+ }
31
+ /**
32
+ * Simple glob pattern matching
33
+ * Supports:
34
+ * - * matches any characters except /
35
+ * - ** matches any characters including / (zero or more path segments)
36
+ * - ? matches single character
37
+ */
38
+ export function matchGlob(file, pattern) {
39
+ // Normalize paths
40
+ const normalizedFile = file.replace(/\\/g, '/');
41
+ const normalizedPattern = pattern.replace(/\\/g, '/');
42
+ return matchGlobInternal(normalizedFile, normalizedPattern);
43
+ }
44
+ /**
45
+ * Internal glob matching implementation using regex
46
+ */
47
+ function matchGlobInternal(file, pattern) {
48
+ // Convert glob pattern to regex step by step
49
+ let regex = '';
50
+ let i = 0;
51
+ while (i < pattern.length) {
52
+ const char = pattern[i];
53
+ const nextChar = pattern[i + 1];
54
+ if (char === '*' && nextChar === '*') {
55
+ // ** - matches any path segments
56
+ const afterStars = pattern[i + 2];
57
+ if (afterStars === '/') {
58
+ // **/ at start or middle - matches zero or more path segments including nothing
59
+ regex += '(?:.*/)?';
60
+ i += 3; // skip **/
61
+ }
62
+ else if (i + 2 === pattern.length || afterStars === undefined) {
63
+ // ** at end - matches everything
64
+ regex += '.*';
65
+ i += 2;
66
+ }
67
+ else {
68
+ // ** without trailing / - matches any characters
69
+ regex += '.*';
70
+ i += 2;
71
+ }
72
+ }
73
+ else if (char === '*') {
74
+ // * - matches any characters except /
75
+ regex += '[^/]*';
76
+ i++;
77
+ }
78
+ else if (char === '?') {
79
+ // ? - matches single character except /
80
+ regex += '[^/]';
81
+ i++;
82
+ }
83
+ else if (char === '/') {
84
+ regex += '/';
85
+ i++;
86
+ }
87
+ else if ('.+^${}()|[]\\'.includes(char)) {
88
+ // Escape regex special chars
89
+ regex += '\\' + char;
90
+ i++;
91
+ }
92
+ else {
93
+ regex += char;
94
+ i++;
95
+ }
96
+ }
97
+ // Anchor the pattern
98
+ regex = `^${regex}$`;
99
+ try {
100
+ return new RegExp(regex).test(file);
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ /**
107
+ * Get list of changed files, filtered to a specific base directory
108
+ */
109
+ export function getChangedFiles(options) {
110
+ const { changedFilesPath, baseRef, baseDir } = options;
111
+ let files;
112
+ if (changedFilesPath) {
113
+ // Read from file (CI mode)
114
+ if (!fs.existsSync(changedFilesPath)) {
115
+ throw new Error(`Changed files list not found: ${changedFilesPath}`);
116
+ }
117
+ files = fs.readFileSync(changedFilesPath, 'utf-8')
118
+ .trim()
119
+ .split('\n')
120
+ .filter(Boolean);
121
+ }
122
+ else {
123
+ // Use git diff (local mode)
124
+ try {
125
+ const ref = baseRef || 'HEAD';
126
+ // Try staged files first
127
+ let out = execSync('git diff --name-only --cached', { encoding: 'utf8' });
128
+ files = out.trim().split('\n').filter(Boolean);
129
+ // If no staged files, try unstaged
130
+ if (files.length === 0) {
131
+ out = execSync('git diff --name-only', { encoding: 'utf8' });
132
+ files = out.trim().split('\n').filter(Boolean);
133
+ }
134
+ // If still no files, try diff against base ref
135
+ if (files.length === 0 && ref !== 'HEAD') {
136
+ out = execSync(`git diff --name-only ${ref}...HEAD`, { encoding: 'utf8' });
137
+ files = out.trim().split('\n').filter(Boolean);
138
+ }
139
+ }
140
+ catch (error) {
141
+ // Git not available or not in a git repo
142
+ return [];
143
+ }
144
+ }
145
+ // Filter and convert paths relative to baseDir
146
+ if (baseDir) {
147
+ // Get git root to resolve absolute paths
148
+ let gitRoot;
149
+ try {
150
+ gitRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
151
+ }
152
+ catch {
153
+ gitRoot = process.cwd();
154
+ }
155
+ const absoluteBaseDir = path.resolve(baseDir);
156
+ // Filter to only files under baseDir and convert to relative paths
157
+ files = files
158
+ .map(f => path.resolve(gitRoot, f)) // Convert to absolute
159
+ .filter(f => f.startsWith(absoluteBaseDir + path.sep) || f === absoluteBaseDir) // Filter to baseDir
160
+ .map(f => path.relative(absoluteBaseDir, f)); // Convert to relative from baseDir
161
+ }
162
+ return files;
163
+ }
164
+ /**
165
+ * Verify changed files against allowlist
166
+ */
167
+ export function verifyAllowlist(changedFiles, config) {
168
+ const violations = [];
169
+ for (const file of changedFiles) {
170
+ // 1. Check if protected (not allowed in normal PRs)
171
+ if (matchWithNegation(config.protected, file)) {
172
+ violations.push({ file, reason: 'protected' });
173
+ continue;
174
+ }
175
+ // 2. Check if generated (allowed, but must pass drift/manifest checks)
176
+ if (matchWithNegation(config.generated, file)) {
177
+ // Generated files are allowed to change, but we don't add a violation
178
+ // The drift/manifest checks will verify integrity
179
+ continue;
180
+ }
181
+ // 3. Must be in allowed list
182
+ if (!matchWithNegation(config.allowed, file)) {
183
+ violations.push({ file, reason: 'not-in-allowlist' });
184
+ }
185
+ }
186
+ return {
187
+ valid: violations.length === 0,
188
+ violations,
189
+ };
190
+ }
191
+ /**
192
+ * Run allowlist check
193
+ */
194
+ export async function runAllowlistCheck(options) {
195
+ const start = Date.now();
196
+ try {
197
+ // Load config with path information
198
+ const { config, baseDir, configPath } = loadGuardrailsConfigWithPath(options.guardrailsPath);
199
+ // Get changed files relative to guardrails config directory
200
+ const changedFiles = getChangedFiles({
201
+ changedFilesPath: options.changedFilesPath,
202
+ baseDir, // Filter to files under guardrails.yaml directory
203
+ });
204
+ if (changedFiles.length === 0) {
205
+ return {
206
+ name: 'allowlist',
207
+ status: 'pass',
208
+ duration: Date.now() - start,
209
+ message: configPath
210
+ ? `No changed files under ${path.basename(path.dirname(configPath))}/`
211
+ : 'No changed files to check',
212
+ };
213
+ }
214
+ // Verify allowlist
215
+ const result = verifyAllowlist(changedFiles, config);
216
+ if (result.valid) {
217
+ return {
218
+ name: 'allowlist',
219
+ status: 'pass',
220
+ duration: Date.now() - start,
221
+ message: `All ${changedFiles.length} changed files are within allowed boundaries`,
222
+ };
223
+ }
224
+ // Build error details
225
+ const details = result.violations.map(v => ` - ${v.file} (${v.reason})`);
226
+ return {
227
+ name: 'allowlist',
228
+ status: 'fail',
229
+ duration: Date.now() - start,
230
+ message: `${result.violations.length} file(s) are not allowed to be modified`,
231
+ details,
232
+ };
233
+ }
234
+ catch (error) {
235
+ return {
236
+ name: 'allowlist',
237
+ status: 'fail',
238
+ duration: Date.now() - start,
239
+ message: error instanceof Error ? error.message : String(error),
240
+ };
241
+ }
242
+ }
243
+ /**
244
+ * Format allowlist result for CLI output
245
+ */
246
+ export function formatAllowlistResult(result) {
247
+ const lines = [];
248
+ if (result.valid) {
249
+ lines.push('✅ All changed files are within allowed boundaries');
250
+ }
251
+ else {
252
+ lines.push('❌ The following files are not allowed to be modified in a normal PR:\n');
253
+ for (const { file, reason } of result.violations) {
254
+ lines.push(` - ${file} (${reason})`);
255
+ }
256
+ lines.push('\n💡 If this is a generated artifact, run the pinned generator and pass drift/manifest checks.');
257
+ lines.push('💡 If this should be editable, update guardrails.yaml (allowed/protected/generated).');
258
+ }
259
+ return lines.join('\n');
260
+ }
261
+ //# sourceMappingURL=allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../../src/guardrails/allowlist.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Guardrails configuration parser
3
+ *
4
+ * Handles loading and validation of guardrails.yaml configuration files.
5
+ */
6
+ import type { GuardrailsConfig } from './types.js';
7
+ /**
8
+ * Default guardrails configuration
9
+ */
10
+ export declare const DEFAULT_GUARDRAILS: GuardrailsConfig;
11
+ /**
12
+ * Find guardrails config file in current directory or ancestors
13
+ */
14
+ export declare function findGuardrailsConfig(startDir?: string): string | null;
15
+ export interface LoadedGuardrailsConfig {
16
+ config: GuardrailsConfig;
17
+ /** Directory containing the guardrails config file (for relative path resolution) */
18
+ baseDir: string;
19
+ /** Full path to the config file (null if using defaults) */
20
+ configPath: string | null;
21
+ }
22
+ /**
23
+ * Load guardrails configuration from file
24
+ * Falls back to defaults if file not found
25
+ */
26
+ export declare function loadGuardrailsConfig(configPath?: string): GuardrailsConfig;
27
+ /**
28
+ * Load guardrails configuration with path information
29
+ * Returns both the config and the base directory for relative path resolution
30
+ */
31
+ export declare function loadGuardrailsConfigWithPath(configPath?: string): LoadedGuardrailsConfig;
32
+ /**
33
+ * Create a guardrails.yaml template
34
+ */
35
+ export declare function generateGuardrailsTemplate(): string;
36
+ /**
37
+ * Write guardrails template to file
38
+ */
39
+ export declare function createGuardrailsConfig(outputPath?: string): void;
40
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/guardrails/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAyBhC,CAAC;AAEF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwBrE;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,gBAAgB,CAAC;IACzB,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAG1E;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,sBAAsB,CAiCxF;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CA4DnD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,GAAE,MAA0C,GAAG,IAAI,CAGnG"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Guardrails configuration parser
3
+ *
4
+ * Handles loading and validation of guardrails.yaml configuration files.
5
+ */
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import yaml from 'js-yaml';
9
+ /**
10
+ * Default guardrails configuration
11
+ */
12
+ export const DEFAULT_GUARDRAILS = {
13
+ allowed: [
14
+ 'spec/**/*.yaml',
15
+ 'spec/**/*.yml',
16
+ 'spec/**/*.hbs',
17
+ 'server/src/**/domains/**/*.ts',
18
+ 'server/src/**/container.ts',
19
+ 'server/src/server.ts',
20
+ 'docs/**/*.md',
21
+ 'README.md',
22
+ 'package.json',
23
+ 'tsconfig.json',
24
+ ],
25
+ protected: [
26
+ 'spec/spectral.yaml',
27
+ 'spec/_shared/overlays/**',
28
+ 'guardrails.yaml',
29
+ '.github/**',
30
+ ],
31
+ generated: [
32
+ 'packages/**',
33
+ '**/*.generated.ts',
34
+ '**/*.generated.yaml',
35
+ '**/*.generated.yml',
36
+ ],
37
+ };
38
+ /**
39
+ * Find guardrails config file in current directory or ancestors
40
+ */
41
+ export function findGuardrailsConfig(startDir) {
42
+ const dir = startDir || process.cwd();
43
+ // Support multiple naming conventions
44
+ const candidates = [
45
+ 'micro-contracts.guardrails.yaml',
46
+ 'micro-contracts.guardrails.yml',
47
+ 'guardrails.yaml', // Legacy name
48
+ 'guardrails.yml',
49
+ ];
50
+ let current = path.resolve(dir);
51
+ const root = path.parse(current).root;
52
+ while (current !== root) {
53
+ for (const candidate of candidates) {
54
+ const configPath = path.join(current, candidate);
55
+ if (fs.existsSync(configPath)) {
56
+ return configPath;
57
+ }
58
+ }
59
+ current = path.dirname(current);
60
+ }
61
+ return null;
62
+ }
63
+ /**
64
+ * Load guardrails configuration from file
65
+ * Falls back to defaults if file not found
66
+ */
67
+ export function loadGuardrailsConfig(configPath) {
68
+ const result = loadGuardrailsConfigWithPath(configPath);
69
+ return result.config;
70
+ }
71
+ /**
72
+ * Load guardrails configuration with path information
73
+ * Returns both the config and the base directory for relative path resolution
74
+ */
75
+ export function loadGuardrailsConfigWithPath(configPath) {
76
+ const resolvedPath = configPath || findGuardrailsConfig();
77
+ if (!resolvedPath || !fs.existsSync(resolvedPath)) {
78
+ // Return default config with current directory as base
79
+ return {
80
+ config: DEFAULT_GUARDRAILS,
81
+ baseDir: process.cwd(),
82
+ configPath: null,
83
+ };
84
+ }
85
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
86
+ const config = yaml.load(content);
87
+ // Validate basic structure
88
+ if (typeof config !== 'object' || config === null) {
89
+ throw new Error(`Invalid guardrails config: ${resolvedPath}`);
90
+ }
91
+ // Merge with defaults for any missing sections
92
+ const mergedConfig = {
93
+ allowed: config.allowed ?? DEFAULT_GUARDRAILS.allowed,
94
+ protected: config.protected ?? DEFAULT_GUARDRAILS.protected,
95
+ generated: config.generated ?? DEFAULT_GUARDRAILS.generated,
96
+ checks: config.checks, // Pass through checks config
97
+ };
98
+ return {
99
+ config: mergedConfig,
100
+ baseDir: path.dirname(resolvedPath),
101
+ configPath: resolvedPath,
102
+ };
103
+ }
104
+ /**
105
+ * Create a guardrails.yaml template
106
+ */
107
+ export function generateGuardrailsTemplate() {
108
+ const template = `# AI-Driven Development Guardrails Configuration
109
+ #
110
+ # This file defines which files can be modified in normal development PRs.
111
+ # Patterns use gitignore-style matching with glob patterns.
112
+ # Prefix with ! to negate (exclude) a pattern.
113
+
114
+ # Files that can be edited in normal development PRs
115
+ allowed:
116
+ # OpenAPI specs (source of truth)
117
+ - spec/**/openapi/*.yaml
118
+ - spec/**/templates/*.hbs
119
+
120
+ # Domain implementations (human-written)
121
+ - server/src/**/domains/**/*.ts
122
+ - server/src/**/container.ts
123
+ - server/src/server.ts
124
+
125
+ # Module-specific overlays (NOT _shared)
126
+ - server/src/*/overlays/**/*.ts
127
+ - "!server/src/_shared/overlays/**"
128
+
129
+ # Configuration
130
+ - micro-contracts.config.yaml
131
+ - package.json
132
+ - tsconfig.json
133
+
134
+ # Documentation
135
+ - docs/**/*.md
136
+ - README.md
137
+
138
+ # Files that require special approval
139
+ protected:
140
+ # Spectral lint rules
141
+ - spec/spectral.yaml
142
+
143
+ # Shared overlay definitions
144
+ - spec/_shared/overlays/**
145
+
146
+ # Shared security overlay implementations
147
+ - server/src/_shared/overlays/**
148
+
149
+ # This guardrails configuration
150
+ - micro-contracts.guardrails.yaml
151
+
152
+ # CI/workflow definitions
153
+ - .github/**
154
+
155
+ # Generated artifacts (committed, but only modified via generate)
156
+ generated:
157
+ # Contract packages
158
+ - packages/**
159
+
160
+ # Generated files
161
+ - "**/*.generated.ts"
162
+ - "**/*.generated.yaml"
163
+ - "**/*.generated.yml"
164
+ `;
165
+ return template;
166
+ }
167
+ /**
168
+ * Write guardrails template to file
169
+ */
170
+ export function createGuardrailsConfig(outputPath = 'micro-contracts.guardrails.yaml') {
171
+ const template = generateGuardrailsTemplate();
172
+ fs.writeFileSync(outputPath, template);
173
+ }
174
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/guardrails/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Documentation consistency check for guardrails
3
+ *
4
+ * Verifies that documentation references (links, file paths, images) are valid.
5
+ */
6
+ import type { CheckResult, CheckOptions } from './types.js';
7
+ export interface DocIssue {
8
+ file: string;
9
+ line: number;
10
+ issue: string;
11
+ }
12
+ /**
13
+ * Check a single markdown file for broken references
14
+ */
15
+ export declare function checkMarkdownFile(docFile: string): DocIssue[];
16
+ /**
17
+ * Find all markdown files to check
18
+ */
19
+ export declare function findMarkdownFiles(): Promise<string[]>;
20
+ /**
21
+ * Run docs consistency check
22
+ */
23
+ export declare function runDocsCheck(options: CheckOptions): Promise<CheckResult>;
24
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/guardrails/docs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAoBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAsD7D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAe3D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkD9E"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Documentation consistency check for guardrails
3
+ *
4
+ * Verifies that documentation references (links, file paths, images) are valid.
5
+ */
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { glob } from 'glob';
9
+ /**
10
+ * Check if a path exists relative to a document file
11
+ */
12
+ function existsRelativeToDoc(docFile, refPath) {
13
+ // Skip empty, anchor-only, or URL
14
+ if (!refPath || refPath.startsWith('#') || refPath.includes('://')) {
15
+ return true;
16
+ }
17
+ // Root-relative (starts with /) → resolve from cwd (repo root)
18
+ // Relative (including ./) → resolve from doc's directory
19
+ const resolved = refPath.startsWith('/')
20
+ ? path.resolve(process.cwd(), refPath.slice(1))
21
+ : path.resolve(path.dirname(docFile), refPath);
22
+ return fs.existsSync(resolved);
23
+ }
24
+ /**
25
+ * Check a single markdown file for broken references
26
+ */
27
+ export function checkMarkdownFile(docFile) {
28
+ const issues = [];
29
+ if (!fs.existsSync(docFile)) {
30
+ return issues;
31
+ }
32
+ const lines = fs.readFileSync(docFile, 'utf-8').split('\n');
33
+ lines.forEach((line, idx) => {
34
+ const lineNum = idx + 1;
35
+ // 1. Check file path references like [examples/...] or `examples/...`
36
+ const pathRefs = line.matchAll(/(?:\[|`)([a-zA-Z0-9_\-./]+\/[a-zA-Z0-9_\-./]+\.[a-zA-Z]+)(?:\]|`)/g);
37
+ for (const match of pathRefs) {
38
+ const refPath = match[1];
39
+ if (!existsRelativeToDoc(docFile, refPath)) {
40
+ issues.push({
41
+ file: docFile,
42
+ line: lineNum,
43
+ issue: `Referenced file does not exist: ${refPath}`,
44
+ });
45
+ }
46
+ }
47
+ // 2. Check markdown link targets like ](path#anchor)
48
+ const linkRefs = line.matchAll(/\]\((?!http)([^)]+)\)/g);
49
+ for (const match of linkRefs) {
50
+ const raw = match[1];
51
+ const linkPath = raw.split('#')[0]; // Remove anchor
52
+ if (linkPath && !existsRelativeToDoc(docFile, linkPath)) {
53
+ issues.push({
54
+ file: docFile,
55
+ line: lineNum,
56
+ issue: `Broken link: ${linkPath}`,
57
+ });
58
+ }
59
+ }
60
+ // 3. Check image references like ![alt](./image.png)
61
+ const imgRefs = line.matchAll(/!\[[^\]]*\]\((?!http)([^)]+)\)/g);
62
+ for (const match of imgRefs) {
63
+ const imgPath = match[1].split('#')[0];
64
+ if (imgPath && !existsRelativeToDoc(docFile, imgPath)) {
65
+ issues.push({
66
+ file: docFile,
67
+ line: lineNum,
68
+ issue: `Image not found: ${imgPath}`,
69
+ });
70
+ }
71
+ }
72
+ });
73
+ return issues;
74
+ }
75
+ /**
76
+ * Find all markdown files to check
77
+ */
78
+ export async function findMarkdownFiles() {
79
+ const files = [];
80
+ // Check README.md at root
81
+ if (fs.existsSync('README.md')) {
82
+ files.push('README.md');
83
+ }
84
+ // Check docs directory
85
+ const docsFiles = await glob('docs/**/*.md', {
86
+ ignore: ['**/node_modules/**'],
87
+ });
88
+ files.push(...docsFiles);
89
+ return files;
90
+ }
91
+ /**
92
+ * Run docs consistency check
93
+ */
94
+ export async function runDocsCheck(options) {
95
+ const start = Date.now();
96
+ try {
97
+ // Find all markdown files
98
+ const docFiles = await findMarkdownFiles();
99
+ if (docFiles.length === 0) {
100
+ return {
101
+ name: 'docs',
102
+ status: 'skip',
103
+ duration: Date.now() - start,
104
+ message: 'No documentation files found',
105
+ };
106
+ }
107
+ const allIssues = [];
108
+ for (const docFile of docFiles) {
109
+ const issues = checkMarkdownFile(docFile);
110
+ allIssues.push(...issues);
111
+ }
112
+ if (allIssues.length > 0) {
113
+ const details = allIssues.map(i => ` ${i.file}:${i.line}: ${i.issue}`);
114
+ return {
115
+ name: 'docs',
116
+ status: 'fail',
117
+ duration: Date.now() - start,
118
+ message: `${allIssues.length} broken reference(s) in ${docFiles.length} file(s)`,
119
+ details,
120
+ };
121
+ }
122
+ return {
123
+ name: 'docs',
124
+ status: 'pass',
125
+ duration: Date.now() - start,
126
+ message: `${docFiles.length} documentation file(s) verified`,
127
+ };
128
+ }
129
+ catch (error) {
130
+ return {
131
+ name: 'docs',
132
+ status: 'fail',
133
+ duration: Date.now() - start,
134
+ message: error instanceof Error ? error.message : String(error),
135
+ };
136
+ }
137
+ }
138
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/guardrails/docs.ts"],"names":[],"mappings":"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"}