@rosh100yx/outlier 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -8
- package/bin/outlier +0 -0
- package/package.json +7 -4
- package/src/cli.ts +130 -22
- package/bin/outlier.js +0 -14
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="assets/cover.jpg" alt="Outlier Cover" width="100%" />
|
|
2
|
+
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/cover.jpg" alt="Outlier Cover" width="100%" />
|
|
3
3
|
<h1>outlier</h1>
|
|
4
4
|
<p><b>The Governance & Policy Engine for AI Engineering</b></p>
|
|
5
5
|
<p><i>Measure AI adoption. Enforce Zero-Trust. Protect Human Mastery.</i></p>
|
|
6
|
+
<br/>
|
|
7
|
+
<a href="https://github.com/rosh100yx/outlier/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=%5BFEATURE%5D+">
|
|
8
|
+
<img src="https://img.shields.io/badge/%E2%9C%A8_Feature_Request-Submit_an_idea-blueviolet?style=for-the-badge&logo=github" alt="Feature Request" />
|
|
9
|
+
</a>
|
|
6
10
|
|
|
7
11
|
<p>
|
|
8
12
|
<img src="https://img.shields.io/badge/Compliance-Strict-blue?style=for-the-badge" />
|
|
@@ -17,7 +21,7 @@
|
|
|
17
21
|
</p>
|
|
18
22
|
|
|
19
23
|
<br/>
|
|
20
|
-
<img src="assets/cli-demo.png" alt="Outlier CLI Demo" width="800" />
|
|
24
|
+
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/cli-demo.png" alt="Outlier CLI Demo" width="800" />
|
|
21
25
|
<br/>
|
|
22
26
|
</div>
|
|
23
27
|
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
> *"In a room full of agents" shifts the perspective. It acknowledges that the developer is no longer a solo coder; they are a manager of bots. The product exists to make sure the human doesn't get lazy while managing them. We all want our time back, but we don't want to lose control of the craft.*
|
|
33
37
|
|
|
34
38
|
<div align="center">
|
|
35
|
-
<img src="assets/codecore.gif" alt="Codecore Aesthetic" width="300" />
|
|
39
|
+
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/codecore.gif" alt="Codecore Aesthetic" width="300" />
|
|
36
40
|
</div>
|
|
37
41
|
|
|
38
42
|
## How It Works
|
|
@@ -63,10 +67,13 @@
|
|
|
63
67
|
## Commands
|
|
64
68
|
| Command | Purpose |
|
|
65
69
|
|---------|---------|
|
|
66
|
-
| `outlier
|
|
67
|
-
| `outlier
|
|
68
|
-
| `outlier
|
|
69
|
-
| `outlier
|
|
70
|
+
| `outlier` | Start the interactive Onboarding Wizard (Recommended for first-timers) |
|
|
71
|
+
| `outlier --help` | View the CLI help menu and all available commands |
|
|
72
|
+
| `outlier status` | Run the full AI reliance & capability audit (Generates the Thermal Receipt) |
|
|
73
|
+
| `outlier authorship` | Scan git history for AI co-authorship ratio and Hallucination Risk |
|
|
74
|
+
| `outlier carbon` | Scan local logs for context waste & token costs |
|
|
75
|
+
| `outlier policy` | Configure Personal, Team, or Enterprise guardrails in CI |
|
|
76
|
+
| `outlier confessional` | Submit qualitative feedback or feature requests directly from the terminal |
|
|
70
77
|
|
|
71
78
|
## Quickstart: Your First Audit
|
|
72
79
|
|
|
@@ -100,7 +107,7 @@
|
|
|
100
107
|
## FAQ
|
|
101
108
|
|
|
102
109
|
**Does this send my code or prompts to the cloud?**
|
|
103
|
-
|
|
110
|
+
**Absolutely not.** `outlier` is built on a strict **Zero-Trust, Local-First Architecture**. It runs native parsing commands against your `.git/` history and your local `~/.claude/` session logs. It never calls an API, it never extracts your proprietary data, and it never phones home. Your research, your code, and your prompts stay 100% on your machine. We believe in open-source integrity.
|
|
104
111
|
|
|
105
112
|
**Do I need to be using a specific IDE?**
|
|
106
113
|
`outlier` is IDE-agnostic. It works by parsing standard `Co-Authored-By` Git trailers, meaning it supports Claude Code, Cursor, Aider, and manual generation.
|
package/bin/outlier
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rosh100yx/outlier",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "AI Code Governance & Capability Auditing for the Terminal. Measures AI reliance, context waste, and enforces local CI/CD policies.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"outlier": "bin/outlier
|
|
6
|
+
"outlier": "bin/outlier"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
|
-
"bin/outlier
|
|
9
|
+
"bin/outlier",
|
|
10
10
|
"src",
|
|
11
11
|
"data"
|
|
12
12
|
],
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
"private": false,
|
|
20
20
|
"author": "Roshan Abraham",
|
|
21
21
|
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/rosh100yx/outlier.git"
|
|
25
|
+
},
|
|
22
26
|
"keywords": [
|
|
23
27
|
"ai",
|
|
24
28
|
"governance",
|
|
@@ -42,7 +46,6 @@
|
|
|
42
46
|
},
|
|
43
47
|
"dependencies": {
|
|
44
48
|
"@clack/prompts": "^1.6.0",
|
|
45
|
-
"commander": "^15.0.0",
|
|
46
49
|
"picocolors": "^1.1.1"
|
|
47
50
|
}
|
|
48
51
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { intro, outro, select, spinner, isCancel, cancel, note } from '@clack/prompts';
|
|
2
|
+
import { intro, outro, select, spinner, isCancel, cancel, note, text } from '@clack/prompts';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import { getAuthorshipStats } from './git';
|
|
5
5
|
import { getCarbonStats } from './carbon';
|
|
6
6
|
import { getCapabilitiesStats } from './capabilities';
|
|
7
7
|
import { writeFileSync, chmodSync, existsSync } from 'fs';
|
|
8
8
|
import { join } from 'path';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
9
10
|
|
|
10
11
|
const ASCII_LOGO = `
|
|
11
12
|
____ _ _ _____ _ ___ _____ ____
|
|
@@ -78,10 +79,22 @@ The results will assign you a "vibe" and evaluate if you are at risk of deskilli
|
|
|
78
79
|
async function main() {
|
|
79
80
|
console.clear();
|
|
80
81
|
console.log(pc.cyan(ASCII_LOGO));
|
|
81
|
-
console.log(pc.dim(' Outlier v0.
|
|
82
|
+
console.log(pc.dim(' Outlier v0.4.1 · AI Code Reliance & Telemetry Engine\n'));
|
|
82
83
|
|
|
83
84
|
let action = process.argv[2] as any;
|
|
84
85
|
|
|
86
|
+
if (action === '--help' || action === '-h' || action === 'help') {
|
|
87
|
+
console.log(pc.bold('\nCOMMANDS:'));
|
|
88
|
+
console.log(` ${pc.cyan('outlier')} Interactive menu (Onboarding for first-timers)`);
|
|
89
|
+
console.log(` ${pc.cyan('outlier status')} Run full AI reliance & capability audit`);
|
|
90
|
+
console.log(` ${pc.cyan('outlier authorship')} Scan git history for AI co-authorship ratio`);
|
|
91
|
+
console.log(` ${pc.cyan('outlier carbon')} Scan local logs for token waste & carbon cost`);
|
|
92
|
+
console.log(` ${pc.cyan('outlier policy')} Configure CI/CD guardrails and thresholds`);
|
|
93
|
+
console.log(` ${pc.cyan('outlier confessional')} Submit qualitative feedback or feature requests`);
|
|
94
|
+
console.log('\n' + pc.dim('Run without arguments to start the interactive wizard.'));
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
|
|
85
98
|
const configPath = join(os.homedir(), '.outlier_config');
|
|
86
99
|
if (!existsSync(configPath) && !action) {
|
|
87
100
|
await runOnboarding();
|
|
@@ -99,7 +112,8 @@ async function main() {
|
|
|
99
112
|
{ value: 'capabilities', label: 'Capabilities Map', hint: 'Audit active MCPs, skills, and orchestrations' },
|
|
100
113
|
{ value: 'authorship', label: 'Code Durability', hint: 'Scan git history for AI Code Reliance & Hallucination Risk' },
|
|
101
114
|
{ value: 'carbon', label: 'Cache Bloat', hint: 'Scan local logs for context waste & token costs' },
|
|
102
|
-
{ value: 'policy', label: 'Policy Profiles', hint: 'Set Personal, Team, or Enterprise guardrails in CI' }
|
|
115
|
+
{ value: 'policy', label: 'Policy Profiles', hint: 'Set Personal, Team, or Enterprise guardrails in CI' },
|
|
116
|
+
{ value: 'confessional', label: 'Confessional', hint: 'Tell us how AI is really affecting your job (Feature Requests)' }
|
|
103
117
|
],
|
|
104
118
|
});
|
|
105
119
|
|
|
@@ -137,15 +151,13 @@ Ratio: ~31x carbon penalty on coal-heavy grid`,
|
|
|
137
151
|
s.stop('Audit failed');
|
|
138
152
|
console.error(pc.red(e.message));
|
|
139
153
|
}
|
|
140
|
-
} else if (action === 'authorship'
|
|
141
|
-
s.start('Scanning local git history
|
|
142
|
-
|
|
154
|
+
} else if (action === 'authorship') {
|
|
155
|
+
s.start('Scanning local git history...');
|
|
143
156
|
try {
|
|
144
157
|
const gitStats = await getAuthorshipStats().catch(() => null);
|
|
145
|
-
const carbon = await getCarbonStats().catch(() => null);
|
|
146
158
|
s.stop('Audit complete');
|
|
147
159
|
|
|
148
|
-
if (
|
|
160
|
+
if (gitStats) {
|
|
149
161
|
const pct = (gitStats.ratio * 100).toFixed(1);
|
|
150
162
|
const nmPct = (gitStats.ratioNoMerges * 100).toFixed(1);
|
|
151
163
|
|
|
@@ -169,14 +181,53 @@ AI Co-Authored: ${gitStats.aiNoMerges}
|
|
|
169
181
|
Conservative Floor: ${color(nmPct + '%')}`,
|
|
170
182
|
'Git Authorship Breakdown'
|
|
171
183
|
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
}
|
|
185
|
+
} catch (e: any) {
|
|
186
|
+
s.stop('Audit failed');
|
|
187
|
+
console.error(pc.red(e.message));
|
|
188
|
+
}
|
|
189
|
+
} else if (action === 'status') {
|
|
190
|
+
const isStrict = process.argv.includes('--strict');
|
|
191
|
+
|
|
192
|
+
let gitStats: any = null;
|
|
193
|
+
let carbon: any = null;
|
|
194
|
+
let capabilities: any = null;
|
|
195
|
+
|
|
196
|
+
if (!isStrict) {
|
|
197
|
+
s.start('[SYSTEM] Booting local-first sandbox...');
|
|
198
|
+
await new Promise(r => setTimeout(r, 800));
|
|
199
|
+
s.message(`↳ Guarantee: No API calls. Your code and logs never leave this machine.`);
|
|
200
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
201
|
+
|
|
202
|
+
s.message('[GIT] Scanning your commit history...');
|
|
203
|
+
gitStats = await getAuthorshipStats().catch(() => null);
|
|
204
|
+
await new Promise(r => setTimeout(r, 600));
|
|
205
|
+
s.message(`↳ Check: Are you writing the code, or just reviewing what the AI wrote?`);
|
|
206
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
207
|
+
|
|
208
|
+
s.message('[TOKENS] Parsing local AI logs (~/.claude/)...');
|
|
209
|
+
carbon = await getCarbonStats().catch(() => null);
|
|
210
|
+
await new Promise(r => setTimeout(r, 600));
|
|
211
|
+
s.message(`↳ Check: How much API waste is your workflow generating locally?`);
|
|
212
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
213
|
+
|
|
214
|
+
s.message('[ANALYSIS] Calculating your mastery score...');
|
|
215
|
+
capabilities = await getCapabilitiesStats().catch(() => null);
|
|
216
|
+
await new Promise(r => setTimeout(r, 600));
|
|
217
|
+
s.message(`↳ Warning: Heavy AI use creates the 'Illusion of Competence'. Don't lose your edge.`);
|
|
218
|
+
await new Promise(r => setTimeout(r, 1200));
|
|
219
|
+
|
|
220
|
+
s.message('[PRINT] Generating Thermal Receipt...');
|
|
221
|
+
await new Promise(r => setTimeout(r, 600));
|
|
222
|
+
} else {
|
|
223
|
+
s.start('Running outlier telemetry audit...');
|
|
224
|
+
gitStats = await getAuthorshipStats().catch(() => null);
|
|
225
|
+
carbon = await getCarbonStats().catch(() => null);
|
|
226
|
+
capabilities = await getCapabilitiesStats().catch(() => null);
|
|
227
|
+
}
|
|
228
|
+
s.stop('Audit complete');
|
|
229
|
+
|
|
230
|
+
try {
|
|
180
231
|
let authPct = '0%';
|
|
181
232
|
let ruleFailures = 0;
|
|
182
233
|
let authWarning = '';
|
|
@@ -231,7 +282,6 @@ ${costIcon}${pc.dim('[3] Tokenomics & Cost')} ${pc.magenta('▰▰▰▰▰▰
|
|
|
231
282
|
${pc.bold('Governance:')} ${ruleFailures > 0 ? pc.red(`${failIcon} ${ruleFailures + 1} policy failures`) : pc.green(`${passIcon} All clear`)}`,
|
|
232
283
|
`${pc.bold('[outlier]')} ${5 - (ruleFailures+1)}/5 policies • ${authWarning || pc.green(`${passIcon} safe surface`)} • ${co2Str}`
|
|
233
284
|
);
|
|
234
|
-
}
|
|
235
285
|
} catch (e: any) {
|
|
236
286
|
s.stop('Audit failed');
|
|
237
287
|
console.error(pc.red(e.message));
|
|
@@ -304,8 +354,8 @@ ${caps.skills.length > 5 ? pc.red('⚠ High Surface Area: Ensure strict authorsh
|
|
|
304
354
|
|
|
305
355
|
const isStrict = process.argv.includes('--strict');
|
|
306
356
|
const bouncerMsg = isStrict
|
|
307
|
-
? `echo "
|
|
308
|
-
: `echo "
|
|
357
|
+
? `echo "⚠️ outlier policy warning: AI authorship ($CURRENT_RATIO%) exceeds threshold ($MAX_RATIO%)"`
|
|
358
|
+
: `echo "🛡️ Outlier Bouncer: Repository AI-generation ($CURRENT_RATIO%) exceeds your defined mastery threshold ($MAX_RATIO%)."\n echo "Take a moment to review your recent architectural decisions. Ensure you still understand the system."`;
|
|
309
359
|
|
|
310
360
|
const hookPath = join(gitDir, 'hooks', 'pre-commit');
|
|
311
361
|
if (existsSync(hookPath)) {
|
|
@@ -323,10 +373,11 @@ if [ "$TOTAL" -eq 0 ]; then exit 0; fi
|
|
|
323
373
|
CURRENT_RATIO=$(awk "BEGIN {print ($AI / $TOTAL) * 100}")
|
|
324
374
|
MAX_RATIO=${maxAuthorship}
|
|
325
375
|
|
|
326
|
-
OVER_LIMIT=$(awk "BEGIN {
|
|
376
|
+
OVER_LIMIT=$(awk "BEGIN {print ($CURRENT_RATIO > $MAX_RATIO) ? 1 : 0}")
|
|
327
377
|
if [ "$OVER_LIMIT" -eq 1 ]; then
|
|
328
378
|
${bouncerMsg}
|
|
329
|
-
|
|
379
|
+
# Warn instead of hard-blocking the commit, protecting human iterations
|
|
380
|
+
exit 0
|
|
330
381
|
fi
|
|
331
382
|
echo "✅ Governance Policy OK"
|
|
332
383
|
`;
|
|
@@ -348,7 +399,7 @@ Enforcement: ${pc.cyan('Local pre-commit hook installed (backup created)')}`,
|
|
|
348
399
|
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
349
400
|
|
|
350
401
|
const reportPath = join(process.cwd(), 'outlier-audit-report.jsonl');
|
|
351
|
-
writeFileSync(reportPath, JSON.stringify({ timestamp: new Date().toISOString(), status: '
|
|
402
|
+
writeFileSync(reportPath, JSON.stringify({ timestamp: new Date().toISOString(), status: 'PREVIEW', policy: 'Decree 142', simulatedOversight: true }) + '\n');
|
|
352
403
|
s.stop('Audit Generated');
|
|
353
404
|
|
|
354
405
|
note(
|
|
@@ -359,6 +410,55 @@ Artifact: ${pc.cyan(reportPath)}`,
|
|
|
359
410
|
'Regulatory Compliance'
|
|
360
411
|
);
|
|
361
412
|
}
|
|
413
|
+
} else if (action === 'confessional') {
|
|
414
|
+
s.start('Connecting to the human element...');
|
|
415
|
+
await new Promise(resolve => setTimeout(resolve, 600));
|
|
416
|
+
s.stop('Secure connection established.');
|
|
417
|
+
|
|
418
|
+
const q1 = await select({
|
|
419
|
+
message: pc.cyan('What is your current engineering reality today?'),
|
|
420
|
+
options: [
|
|
421
|
+
{ value: 'artisan', label: 'Solo Artisan (I write 90%+ of the code myself)' },
|
|
422
|
+
{ value: 'manager', label: 'AI Manager (I prompt, the agents write)' },
|
|
423
|
+
{ value: 'reviewer', label: 'Full-time Reviewer (I spend my days reviewing agent PRs)' }
|
|
424
|
+
]
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
if (isCancel(q1)) { cancel('Confession aborted.'); process.exit(0); }
|
|
428
|
+
|
|
429
|
+
const q2 = await select({
|
|
430
|
+
message: pc.cyan('Do you feel you are losing your deep architectural mastery? (Deskilling)'),
|
|
431
|
+
options: [
|
|
432
|
+
{ value: 'yes_heavy', label: 'Yes, heavily. I forget how my own systems work.' },
|
|
433
|
+
{ value: 'yes_slight', label: 'Slightly. I rely on the AI to fix its own bugs.' },
|
|
434
|
+
{ value: 'no', label: 'No. I maintain strict oversight and mastery.' }
|
|
435
|
+
]
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
if (isCancel(q2)) { cancel('Confession aborted.'); process.exit(0); }
|
|
439
|
+
|
|
440
|
+
const feedback = await text({
|
|
441
|
+
message: pc.cyan('In your own words, what is AI actually doing to your codebase or your job?\n(Note: This will draft a public GitHub issue)'),
|
|
442
|
+
placeholder: 'Honestly, I just let the agent write the regex...',
|
|
443
|
+
validate(value) {
|
|
444
|
+
if (!value || value.length === 0) return `C'mon, confess something!`;
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
if (isCancel(feedback)) {
|
|
449
|
+
cancel('Confession aborted.');
|
|
450
|
+
process.exit(0);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
note(
|
|
454
|
+
`${pc.italic(`"${feedback}"`)}\n\nYour confession is safe with us. But if you want to make it official (and help us build what you need for the literature), we've generated a secure transmission link for you.`,
|
|
455
|
+
'The Confessional'
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
const surveyData = `**Engineering Reality:** ${q1}\n**Deskilling Impact:** ${q2}\n**Thoughts:**\n${feedback}`;
|
|
459
|
+
|
|
460
|
+
const url = `https://github.com/rosh100yx/outlier/issues/new?assignees=&labels=enhancement&projects=&template=feature_request.md&title=%5BConfessional%5D+Feedback&body=${encodeURIComponent("Drop a screenshot of your Thermal Receipt here! \n\n" + surveyData)}`;
|
|
461
|
+
console.log(`\n${pc.bold('Submit here (and drop your screenshot!):')} ${pc.underline(pc.cyan(url))}\n`);
|
|
362
462
|
}
|
|
363
463
|
|
|
364
464
|
outro('Local telemetry run completed. No data left your machine.');
|
|
@@ -398,6 +498,14 @@ Artifact: ${pc.cyan(reportPath)}`,
|
|
|
398
498
|
)}`
|
|
399
499
|
)
|
|
400
500
|
);
|
|
501
|
+
|
|
502
|
+
console.log(
|
|
503
|
+
pc.dim(`└ Have thoughts on AI deskilling? Tell us: `) + pc.cyan(`npx @rosh100yx/outlier confessional`)
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
console.log(
|
|
507
|
+
pc.dim(`└ Keep your local policies updated: `) + pc.cyan(`npx @rosh100yx/outlier@latest`)
|
|
508
|
+
);
|
|
401
509
|
}
|
|
402
510
|
|
|
403
511
|
main().catch(console.error);
|
package/bin/outlier.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawnSync } from 'child_process';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
|
|
9
|
-
const cliPath = path.join(__dirname, '../src/cli.ts');
|
|
10
|
-
const result = spawnSync('bun', ['run', cliPath, ...process.argv.slice(2)], {
|
|
11
|
-
stdio: 'inherit'
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
process.exit(result.status || 0);
|