delimit-cli 1.0.0 → 2.1.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/.github/workflows/api-governance.yml +43 -0
- package/README.md +70 -113
- package/adapters/codex-skill.js +87 -0
- package/adapters/cursor-extension.js +190 -0
- package/adapters/gemini-action.js +93 -0
- package/adapters/openai-function.js +112 -0
- package/adapters/xai-plugin.js +151 -0
- package/bin/delimit-cli.js +921 -0
- package/bin/delimit.js +237 -1
- package/delimit.yml +19 -0
- package/hooks/evidence-status.sh +12 -0
- package/hooks/git/commit-msg +4 -0
- package/hooks/git/pre-commit +4 -0
- package/hooks/git/pre-push +4 -0
- package/hooks/install-hooks.sh +583 -0
- package/hooks/message-auth-hook.js +9 -0
- package/hooks/message-governance-hook.js +9 -0
- package/hooks/models/claude-post.js +4 -0
- package/hooks/models/claude-pre.js +4 -0
- package/hooks/models/codex-post.js +4 -0
- package/hooks/models/codex-pre.js +4 -0
- package/hooks/models/cursor-post.js +4 -0
- package/hooks/models/cursor-pre.js +4 -0
- package/hooks/models/gemini-post.js +4 -0
- package/hooks/models/gemini-pre.js +4 -0
- package/hooks/models/openai-post.js +4 -0
- package/hooks/models/openai-pre.js +4 -0
- package/hooks/models/windsurf-post.js +4 -0
- package/hooks/models/windsurf-pre.js +4 -0
- package/hooks/models/xai-post.js +4 -0
- package/hooks/models/xai-pre.js +4 -0
- package/hooks/post-bash-hook.js +13 -0
- package/hooks/post-mcp-hook.js +13 -0
- package/hooks/post-response-hook.js +4 -0
- package/hooks/post-tool-hook.js +126 -0
- package/hooks/post-write-hook.js +13 -0
- package/hooks/pre-bash-hook.js +30 -0
- package/hooks/pre-mcp-hook.js +13 -0
- package/hooks/pre-read-hook.js +13 -0
- package/hooks/pre-search-hook.js +13 -0
- package/hooks/pre-submit-hook.js +4 -0
- package/hooks/pre-task-hook.js +13 -0
- package/hooks/pre-tool-hook.js +121 -0
- package/hooks/pre-web-hook.js +13 -0
- package/hooks/pre-write-hook.js +31 -0
- package/hooks/test-hooks.sh +12 -0
- package/hooks/update-delimit.sh +6 -0
- package/lib/agent.js +509 -0
- package/lib/api-engine.js +156 -0
- package/lib/auth-setup.js +891 -0
- package/lib/decision-engine.js +474 -0
- package/lib/hooks-installer.js +416 -0
- package/lib/platform-adapters.js +353 -0
- package/lib/proxy-handler.js +114 -0
- package/package.json +38 -30
- package/scripts/infect.js +128 -0
- package/test-decision-engine.js +181 -0
- package/test-hook.js +27 -0
- package/dist/commands/validate.d.ts +0 -2
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/validate.js +0 -106
- package/dist/commands/validate.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -71
- package/dist/index.js.map +0 -1
- package/dist/types/index.d.ts +0 -39
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +0 -1
- package/dist/utils/api.d.ts +0 -3
- package/dist/utils/api.d.ts.map +0 -1
- package/dist/utils/api.js +0 -64
- package/dist/utils/api.js.map +0 -1
- package/dist/utils/file.d.ts +0 -7
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/file.js +0 -69
- package/dist/utils/file.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -14
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -28
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/masker.d.ts +0 -14
- package/dist/utils/masker.d.ts.map +0 -1
- package/dist/utils/masker.js +0 -89
- package/dist/utils/masker.js.map +0 -1
- package/src/commands/validate.ts +0 -150
- package/src/index.ts +0 -80
- package/src/types/index.ts +0 -41
- package/src/utils/api.ts +0 -68
- package/src/utils/file.ts +0 -71
- package/src/utils/logger.ts +0 -27
- package/src/utils/masker.ts +0 -101
- package/test-sensitive.yaml +0 -109
- package/tsconfig.json +0 -23
package/bin/delimit.js
CHANGED
|
@@ -1,2 +1,238 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
const { spawn, spawnSync, execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const command = args[0];
|
|
10
|
+
|
|
11
|
+
// Color codes for terminal output
|
|
12
|
+
const RESET = '\x1b[0m';
|
|
13
|
+
const BLUE = '\x1b[34m';
|
|
14
|
+
const GREEN = '\x1b[32m';
|
|
15
|
+
const YELLOW = '\x1b[33m';
|
|
16
|
+
const RED = '\x1b[31m';
|
|
17
|
+
const BOLD = '\x1b[1m';
|
|
18
|
+
|
|
19
|
+
function log(message, color = BLUE) {
|
|
20
|
+
console.log(`${color}${BOLD}[Delimit]${RESET} ${message}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function error(message) {
|
|
24
|
+
console.error(`${RED}${BOLD}[Delimit ERROR]${RESET} ${message}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findRealExecutable(command, customPath) {
|
|
28
|
+
const paths = customPath.split(':');
|
|
29
|
+
for (const dir of paths) {
|
|
30
|
+
const fullPath = path.join(dir, command);
|
|
31
|
+
try {
|
|
32
|
+
fs.accessSync(fullPath, fs.constants.X_OK);
|
|
33
|
+
return fullPath;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
// Continue searching
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (command === 'pre-commit-check' || command === 'pre-commit') {
|
|
42
|
+
log('Running pre-commit governance checks...', GREEN);
|
|
43
|
+
|
|
44
|
+
// Verify PATH is still infected
|
|
45
|
+
if (!process.env.PATH.includes('.delimit/shims')) {
|
|
46
|
+
error('Governance layer is not active in your PATH!');
|
|
47
|
+
error('Commit REJECTED. Please restart your terminal or run: source ~/.bashrc');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get staged files
|
|
52
|
+
try {
|
|
53
|
+
const stagedFiles = execSync('git diff --cached --name-only').toString().trim().split('\n').filter(f => f);
|
|
54
|
+
|
|
55
|
+
if (stagedFiles.length > 0) {
|
|
56
|
+
log(`Validating ${stagedFiles.length} staged file(s)...`);
|
|
57
|
+
|
|
58
|
+
// Check for secrets, API keys, etc.
|
|
59
|
+
for (const file of stagedFiles) {
|
|
60
|
+
if (file && fs.existsSync(file)) {
|
|
61
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
62
|
+
|
|
63
|
+
// Basic secret detection
|
|
64
|
+
const secretPatterns = [
|
|
65
|
+
/api[_-]?key\s*[:=]\s*["'][^"']+["']/gi,
|
|
66
|
+
/secret\s*[:=]\s*["'][^"']+["']/gi,
|
|
67
|
+
/password\s*[:=]\s*["'][^"']+["']/gi,
|
|
68
|
+
/token\s*[:=]\s*["'][^"']+["']/gi,
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
for (const pattern of secretPatterns) {
|
|
72
|
+
if (pattern.test(content)) {
|
|
73
|
+
error(`Potential secret detected in ${file}`);
|
|
74
|
+
error('Commit BLOCKED by Delimit governance.');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
log('✓ Security scan passed', GREEN);
|
|
82
|
+
log('✓ No exposed secrets detected', GREEN);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
log('✓ All governance checks passed', GREEN);
|
|
86
|
+
log('Evidence recorded: ~/.delimit/evidence/' + Date.now() + '.json', YELLOW);
|
|
87
|
+
|
|
88
|
+
// Record evidence
|
|
89
|
+
const evidenceDir = path.join(os.homedir(), '.delimit', 'evidence');
|
|
90
|
+
fs.mkdirSync(evidenceDir, { recursive: true });
|
|
91
|
+
fs.writeFileSync(
|
|
92
|
+
path.join(evidenceDir, Date.now() + '.json'),
|
|
93
|
+
JSON.stringify({
|
|
94
|
+
action: 'pre-commit',
|
|
95
|
+
timestamp: new Date().toISOString(),
|
|
96
|
+
files: stagedFiles,
|
|
97
|
+
result: 'passed'
|
|
98
|
+
}, null, 2)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
} catch (e) {
|
|
102
|
+
error('Failed to run governance checks: ' + e.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
process.exit(0);
|
|
107
|
+
|
|
108
|
+
} else if (command === 'pre-push-check' || command === 'pre-push') {
|
|
109
|
+
log('Running pre-push governance checks...', GREEN);
|
|
110
|
+
|
|
111
|
+
// Verify we're not pushing directly to main/master
|
|
112
|
+
try {
|
|
113
|
+
const currentBranch = execSync('git branch --show-current').toString().trim();
|
|
114
|
+
if (currentBranch === 'main' || currentBranch === 'master') {
|
|
115
|
+
error('Direct push to ' + currentBranch + ' branch is not allowed!');
|
|
116
|
+
error('Please create a feature branch and pull request.');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// Allow if can't determine branch
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
log('✓ Branch protection validated', GREEN);
|
|
124
|
+
log('✓ Push governance passed', GREEN);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
|
|
127
|
+
} else if (command === 'proxy') {
|
|
128
|
+
// Handle AI tool proxying
|
|
129
|
+
const toolFlag = args.find(a => a.startsWith('--tool='));
|
|
130
|
+
if (!toolFlag) {
|
|
131
|
+
error('Missing --tool= flag');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const tool = toolFlag.split('=')[1];
|
|
136
|
+
const dashDashIndex = args.indexOf('--');
|
|
137
|
+
const originalArgs = dashDashIndex >= 0 ? args.slice(dashDashIndex + 1) : [];
|
|
138
|
+
|
|
139
|
+
// Pre-execution governance
|
|
140
|
+
console.log('');
|
|
141
|
+
log(`═══════════════════════════════════════════════════`, BLUE);
|
|
142
|
+
log(`AI GOVERNANCE ACTIVE: ${tool.toUpperCase()}`, BLUE);
|
|
143
|
+
log(`═══════════════════════════════════════════════════`, BLUE);
|
|
144
|
+
log(`Timestamp: ${new Date().toISOString()}`, YELLOW);
|
|
145
|
+
log(`Command: ${tool} ${originalArgs.join(' ')}`, YELLOW);
|
|
146
|
+
log(`User: ${process.env.USER || 'unknown'}`, YELLOW);
|
|
147
|
+
log(`Directory: ${process.cwd()}`, YELLOW);
|
|
148
|
+
log(`═══════════════════════════════════════════════════`, BLUE);
|
|
149
|
+
console.log('');
|
|
150
|
+
|
|
151
|
+
// Find real tool (removing shims from PATH)
|
|
152
|
+
const originalPath = process.env.PATH.replace(new RegExp(`${os.homedir()}/\\.delimit/shims:?`, 'g'), '');
|
|
153
|
+
const realToolPath = findRealExecutable(tool, originalPath);
|
|
154
|
+
|
|
155
|
+
if (!realToolPath) {
|
|
156
|
+
error(`Could not find the original '${tool}' executable.`);
|
|
157
|
+
error('Make sure ' + tool + ' is installed.');
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Execute the real tool
|
|
162
|
+
const result = spawnSync(realToolPath, originalArgs, {
|
|
163
|
+
stdio: 'inherit',
|
|
164
|
+
env: {
|
|
165
|
+
...process.env,
|
|
166
|
+
DELIMIT_GOVERNED: 'true',
|
|
167
|
+
DELIMIT_SESSION: Date.now().toString()
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Post-execution governance
|
|
172
|
+
console.log('');
|
|
173
|
+
log(`═══════════════════════════════════════════════════`, GREEN);
|
|
174
|
+
log(`GOVERNANCE COMPLETE: ${tool.toUpperCase()}`, GREEN);
|
|
175
|
+
log(`Session recorded: ~/.delimit/sessions/${Date.now()}.json`, GREEN);
|
|
176
|
+
log(`All changes will be validated at commit time`, GREEN);
|
|
177
|
+
log(`═══════════════════════════════════════════════════`, GREEN);
|
|
178
|
+
console.log('');
|
|
179
|
+
|
|
180
|
+
process.exit(result.status || 0);
|
|
181
|
+
|
|
182
|
+
} else if (command === 'status') {
|
|
183
|
+
log('Delimit Governance Status', BLUE);
|
|
184
|
+
log('═══════════════════════════════════════════', BLUE);
|
|
185
|
+
|
|
186
|
+
// Check PATH infection
|
|
187
|
+
const pathInfected = process.env.PATH.includes('.delimit/shims');
|
|
188
|
+
log(`PATH Hijack: ${pathInfected ? '✓ ACTIVE' : '✗ INACTIVE'}`, pathInfected ? GREEN : RED);
|
|
189
|
+
|
|
190
|
+
// Check Git hooks
|
|
191
|
+
try {
|
|
192
|
+
const hooksPath = execSync('git config --global core.hooksPath').toString().trim();
|
|
193
|
+
const hooksActive = hooksPath.includes('.delimit/hooks');
|
|
194
|
+
log(`Git Hooks: ${hooksActive ? '✓ ACTIVE' : '✗ INACTIVE'}`, hooksActive ? GREEN : RED);
|
|
195
|
+
} catch (e) {
|
|
196
|
+
log('Git Hooks: ✗ NOT CONFIGURED', RED);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check for shims
|
|
200
|
+
const shimsDir = path.join(os.homedir(), '.delimit', 'shims');
|
|
201
|
+
const shims = fs.existsSync(shimsDir) ? fs.readdirSync(shimsDir) : [];
|
|
202
|
+
log(`AI Tool Shims: ${shims.length} installed`, shims.length > 0 ? GREEN : YELLOW);
|
|
203
|
+
if (shims.length > 0) {
|
|
204
|
+
shims.forEach(shim => log(` - ${shim}`, YELLOW));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
log('═══════════════════════════════════════════', BLUE);
|
|
208
|
+
|
|
209
|
+
} else if (command === 'install' || command === 'infect') {
|
|
210
|
+
log('Installing Delimit governance layer...', GREEN);
|
|
211
|
+
execSync(`node ${path.join(__dirname, '../../scripts/install-governance.js')}`);
|
|
212
|
+
|
|
213
|
+
} else {
|
|
214
|
+
// Default help
|
|
215
|
+
console.log(`
|
|
216
|
+
${BLUE}${BOLD}Delimit - Unavoidable AI Governance Layer${RESET}
|
|
217
|
+
═══════════════════════════════════════════════════════
|
|
218
|
+
|
|
219
|
+
Usage: delimit [command]
|
|
220
|
+
|
|
221
|
+
Commands:
|
|
222
|
+
status Check governance status
|
|
223
|
+
install/infect Install governance layer system-wide
|
|
224
|
+
|
|
225
|
+
Internal Commands (called by hooks/shims):
|
|
226
|
+
pre-commit-check Run pre-commit governance
|
|
227
|
+
pre-push-check Run pre-push governance
|
|
228
|
+
proxy Proxy AI tool commands
|
|
229
|
+
|
|
230
|
+
After installation, Delimit will:
|
|
231
|
+
• Intercept all AI tool commands (claude, gemini, codex)
|
|
232
|
+
• Validate all Git commits and pushes
|
|
233
|
+
• Record evidence of all AI-assisted development
|
|
234
|
+
• Make ungoverned development impossible
|
|
235
|
+
|
|
236
|
+
Version: 1.0.0
|
|
237
|
+
`);
|
|
238
|
+
}
|
package/delimit.yml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
defaultMode: advisory
|
|
2
|
+
|
|
3
|
+
rules:
|
|
4
|
+
- name: "Production Protection"
|
|
5
|
+
mode: enforce
|
|
6
|
+
triggers:
|
|
7
|
+
- gitBranch: [main, master, production]
|
|
8
|
+
|
|
9
|
+
- name: "Payment Code Security"
|
|
10
|
+
mode: enforce
|
|
11
|
+
triggers:
|
|
12
|
+
- path: "**/payment/**"
|
|
13
|
+
- content: ["stripe", "payment", "billing"]
|
|
14
|
+
|
|
15
|
+
- name: "Documentation Freedom"
|
|
16
|
+
mode: advisory
|
|
17
|
+
triggers:
|
|
18
|
+
- path: "**/*.md"
|
|
19
|
+
final: true
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
echo "Evidence Collection Status"
|
|
3
|
+
echo "========================="
|
|
4
|
+
evidence_dir="${HOME}/.delimit/evidence"
|
|
5
|
+
if [ -d "$evidence_dir" ]; then
|
|
6
|
+
count=$(find "$evidence_dir" -name "*.json" 2>/dev/null | wc -l)
|
|
7
|
+
echo "Evidence files: $count"
|
|
8
|
+
echo "Latest evidence:"
|
|
9
|
+
ls -lt "$evidence_dir" 2>/dev/null | head -5
|
|
10
|
+
else
|
|
11
|
+
echo "No evidence collected yet"
|
|
12
|
+
fi
|