@rosh100yx/outlier 0.4.4 → 0.4.14
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 +62 -26
- package/bin/outlier.js +197 -166
- package/bin/postinstall.js +6 -3
- package/package.json +2 -2
- package/src/cli.ts +108 -88
package/README.md
CHANGED
|
@@ -16,28 +16,28 @@
|
|
|
16
16
|
<code>npm install -g @rosh100yx/outlier</code><br/>
|
|
17
17
|
<code>outlier status</code>
|
|
18
18
|
</p>
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
## The Compounding Value of Outlier (Why This Matters)
|
|
22
|
-
Software engineering is undergoing a catastrophic shift in skill acquisition. If you only look at today, AI saves you 30 minutes of writing regex. But if you look at the **compounding horizon of the next 5-10 years**, the value exchange flips.
|
|
23
|
-
|
|
24
|
-
<div align="center">
|
|
25
|
-
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/metr-long-tasks.png" alt="METR Graph" width="800" />
|
|
26
|
-
<p><i>Source: METR (Measuring AI Ability to Complete Long Tasks)</i></p>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
### What Do We Lose and Gain?
|
|
30
|
-
- **Today (The 5-minute task):** You use AI to scaffold a component. You **gain** velocity. You **lose** syntax recall.
|
|
31
|
-
- **Tomorrow (The 5-hour task):** Models like Claude Opus 4.5 will autonomously resolve multi-file architectural tickets (as proven by the METR graph). You **gain** massive scale and leverage. You **lose** granular intimacy with your own system architecture. You transition from a *Creator* to a *Reviewer*.
|
|
32
|
-
- **The Next 5-10 Years:** Unchecked AI reliance leads to **Deskilling**. When an agent introduces a fatal state bug in a 1M+ LOC codebase, the human reviewers will lack the muscle memory and "systems thinking" required to debug it.
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
20
|
+
<br/>
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
┌────────────────────────────────────────────────────────┐
|
|
24
|
+
│ █▀█ █░█ ▀█▀ █░░ █ █▀▀ █▀█ :: THERMAL AUDIT RECEIPT │
|
|
25
|
+
│ █▄█ █▄█ ░█░ █▄▄ █ ██▄ █▀▄ :: TIMESTAMP: 2026-06-23 │
|
|
26
|
+
├────────────────────────────────────────────────────────┤
|
|
27
|
+
│ [ COGNITIVE BUDGET ] │
|
|
28
|
+
│ AI Authorship ................. ▇▇▇▇░░░░░░ 40% │
|
|
29
|
+
│ Human Sovereignty ................. ▇▇▇▇▇▇░░░░ 60% │
|
|
30
|
+
│ │
|
|
31
|
+
│ ↳ Verdict: (=^ ◡ ^=) CENTAUR │
|
|
32
|
+
│ Healthy symbiosis. You orchestrate agents │
|
|
33
|
+
│ but maintain architectural authority. │
|
|
34
|
+
├────────────────────────────────────────────────────────┤
|
|
35
|
+
│ [ FINANCIAL & COMPUTE TOLL ] │
|
|
36
|
+
│ Tokens Burnt ................. 3.12M vs Human │
|
|
37
|
+
│ Cache Bloat ................. ▇▇▇▇▇▇▇▇░░ 80% │
|
|
38
|
+
│ Regional Grid ................. 1.54 kgCO2 │
|
|
39
|
+
└────────────────────────────────────────────────────────┘
|
|
40
|
+
```
|
|
41
41
|
</div>
|
|
42
42
|
|
|
43
43
|
## How It Works
|
|
@@ -68,13 +68,28 @@ We measure the exact cost of AI for humans—not just in API tokens, but in cogn
|
|
|
68
68
|
## Commands
|
|
69
69
|
| Command | Purpose |
|
|
70
70
|
|---------|---------|
|
|
71
|
-
| `outlier` | Start the interactive
|
|
72
|
-
| `outlier
|
|
73
|
-
| `outlier
|
|
74
|
-
| `outlier authorship` | Scan git history for AI co-authorship ratio and Hallucination Risk |
|
|
71
|
+
| `outlier` | Start the interactive Interactive Menu |
|
|
72
|
+
| `outlier status` | Run the full AI reliance & capability audit |
|
|
73
|
+
| `outlier authorship` | Scan git history for AI co-authorship ratio |
|
|
75
74
|
| `outlier carbon` | Scan local logs for context waste & token costs |
|
|
75
|
+
| `outlier capabilities` | Audit active MCPs, skills, and orchestrations |
|
|
76
76
|
| `outlier policy` | Configure Personal, Team, or Enterprise guardrails in CI |
|
|
77
|
-
|
|
77
|
+
|
|
78
|
+
### Interactive Menu
|
|
79
|
+
If you run `outlier` directly, you'll be greeted with our frictionless UX:
|
|
80
|
+
```text
|
|
81
|
+
? Select outlier governance module:
|
|
82
|
+
── AUDIT ──
|
|
83
|
+
❯ Status Full audit (reliance + carbon + capabilities)
|
|
84
|
+
Authorship Human vs AI, per commit
|
|
85
|
+
Carbon Token waste + regional cost
|
|
86
|
+
Capabilities What your agents can reach
|
|
87
|
+
Policy Set guardrails / install the gate
|
|
88
|
+
── LEARN ──
|
|
89
|
+
Impact What happens over the next 5-10 years
|
|
90
|
+
Literature The academic foundation
|
|
91
|
+
Participate Contribute to the research
|
|
92
|
+
```
|
|
78
93
|
|
|
79
94
|
## Quickstart: Your First Audit
|
|
80
95
|
|
|
@@ -131,5 +146,26 @@ This tool is the technical implementation of an ongoing academic thesis on the t
|
|
|
131
146
|
|
|
132
147
|
See our [Contributing Guide](CONTRIBUTING.md) to get started. Great first issues include adding new regional grid factors to `data/grid-factors.json` or writing custom CI/CD pipeline integrations.
|
|
133
148
|
|
|
149
|
+
## The Compounding Horizon of AI Deskilling
|
|
150
|
+
|
|
151
|
+
When you use an AI agent to skip the boring stuff today, it feels amazing. You get your time back. But what happens over the next 5 to 10 years?
|
|
152
|
+
|
|
153
|
+
<div align="center">
|
|
154
|
+
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/metr-long-tasks.png" alt="METR Graph" width="350" />
|
|
155
|
+
<p><i>Source: METR (Measuring AI Ability to Complete Long Tasks)</i></p>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
### What Does This Mean For Developers?
|
|
159
|
+
- **Today (The 5-minute task):** You gain speed. You lose the muscle memory of writing low-level code.
|
|
160
|
+
- **Tomorrow (The 5-hour task):** Agents will solve complex tickets across multiple files. You gain massive scale. You lose the deep, intimate understanding of your own system's architecture.
|
|
161
|
+
- **Next 5-10 Years (The 1M+ LOC Crisis):** When an agent introduces a critical bug in a massive codebase, human reviewers will lack the deeply ingrained "systems thinking" required to debug it.
|
|
162
|
+
|
|
163
|
+
### Why This Project Exists
|
|
164
|
+
`outlier` is the technical circuit breaker that forces developers to stay sharp. We measure the exact cost of AI for humans—not just in API tokens burnt, but in cognitive load and lost mastery.
|
|
165
|
+
|
|
166
|
+
<div align="center">
|
|
167
|
+
<img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/codecore.gif" alt="Codecore Aesthetic" width="300" />
|
|
168
|
+
</div>
|
|
169
|
+
|
|
134
170
|
## License
|
|
135
171
|
MIT License
|
package/bin/outlier.js
CHANGED
|
@@ -161,6 +161,66 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
161
161
|
module.exports.createColors = createColors;
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
+
// package.json
|
|
165
|
+
var require_package = __commonJS((exports, module) => {
|
|
166
|
+
module.exports = {
|
|
167
|
+
name: "@rosh100yx/outlier",
|
|
168
|
+
version: "0.4.14",
|
|
169
|
+
description: "AI Code Governance & Capability Auditing for the Terminal. Measures AI reliance, context waste, and enforces local CI/CD policies.",
|
|
170
|
+
bin: {
|
|
171
|
+
outlier: "bin/outlier.js"
|
|
172
|
+
},
|
|
173
|
+
files: [
|
|
174
|
+
"bin/outlier.js",
|
|
175
|
+
"bin/postinstall.js",
|
|
176
|
+
"src",
|
|
177
|
+
"data"
|
|
178
|
+
],
|
|
179
|
+
scripts: {
|
|
180
|
+
build: "bunx tsc --noEmit && bun build ./src/cli.ts --target=node --outfile bin/outlier.js",
|
|
181
|
+
test: "bun test",
|
|
182
|
+
start: "bun run src/cli.ts",
|
|
183
|
+
postinstall: "node bin/postinstall.js"
|
|
184
|
+
},
|
|
185
|
+
type: "module",
|
|
186
|
+
private: false,
|
|
187
|
+
author: "Roshan Abraham",
|
|
188
|
+
license: "MIT",
|
|
189
|
+
repository: {
|
|
190
|
+
type: "git",
|
|
191
|
+
url: "https://github.com/rosh100yx/outlier.git"
|
|
192
|
+
},
|
|
193
|
+
keywords: [
|
|
194
|
+
"ai",
|
|
195
|
+
"governance",
|
|
196
|
+
"carbon",
|
|
197
|
+
"compliance",
|
|
198
|
+
"ai-safety",
|
|
199
|
+
"policy-engine",
|
|
200
|
+
"zero-trust",
|
|
201
|
+
"carbon-footprint",
|
|
202
|
+
"global-south",
|
|
203
|
+
"observability",
|
|
204
|
+
"telemetry",
|
|
205
|
+
"authorship",
|
|
206
|
+
"cli"
|
|
207
|
+
],
|
|
208
|
+
devDependencies: {
|
|
209
|
+
"@types/bun": "latest"
|
|
210
|
+
},
|
|
211
|
+
peerDependencies: {
|
|
212
|
+
typescript: "^5"
|
|
213
|
+
},
|
|
214
|
+
dependencies: {
|
|
215
|
+
"@clack/prompts": "^1.6.0",
|
|
216
|
+
picocolors: "^1.1.1"
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// src/cli.ts
|
|
222
|
+
import os from "os";
|
|
223
|
+
|
|
164
224
|
// node_modules/@clack/core/dist/index.mjs
|
|
165
225
|
import { styleText } from "node:util";
|
|
166
226
|
import { stdout, stdin } from "node:process";
|
|
@@ -883,34 +943,16 @@ var T$1 = class T extends V {
|
|
|
883
943
|
}
|
|
884
944
|
}
|
|
885
945
|
};
|
|
886
|
-
|
|
887
|
-
class r extends V {
|
|
888
|
-
get cursor() {
|
|
889
|
-
return this.value ? 0 : 1;
|
|
890
|
-
}
|
|
891
|
-
get _value() {
|
|
892
|
-
return this.cursor === 0;
|
|
893
|
-
}
|
|
894
|
-
constructor(t2) {
|
|
895
|
-
super(t2, false), this.value = !!t2.initialValue, this.on("userInput", () => {
|
|
896
|
-
this.value = this._value;
|
|
897
|
-
}), this.on("confirm", (i) => {
|
|
898
|
-
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i, this.state = "submit", this.close();
|
|
899
|
-
}), this.on("cursor", () => {
|
|
900
|
-
this.value = !this.value;
|
|
901
|
-
});
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
946
|
var _ = {
|
|
905
947
|
Y: { type: "year", len: 4 },
|
|
906
948
|
M: { type: "month", len: 2 },
|
|
907
949
|
D: { type: "day", len: 2 }
|
|
908
950
|
};
|
|
909
|
-
function M(
|
|
910
|
-
return [...
|
|
951
|
+
function M(r) {
|
|
952
|
+
return [...r].map((t2) => _[t2]);
|
|
911
953
|
}
|
|
912
|
-
function P(
|
|
913
|
-
const i = new Intl.DateTimeFormat(
|
|
954
|
+
function P(r) {
|
|
955
|
+
const i = new Intl.DateTimeFormat(r, {
|
|
914
956
|
year: "numeric",
|
|
915
957
|
month: "2-digit",
|
|
916
958
|
day: "2-digit"
|
|
@@ -920,32 +962,32 @@ function P(r2) {
|
|
|
920
962
|
e.type === "literal" ? n = e.value.trim() || e.value : (e.type === "year" || e.type === "month" || e.type === "day") && s.push({ type: e.type, len: e.type === "year" ? 4 : 2 });
|
|
921
963
|
return { segments: s, separator: n };
|
|
922
964
|
}
|
|
923
|
-
function p(
|
|
924
|
-
return Number.parseInt((
|
|
965
|
+
function p(r) {
|
|
966
|
+
return Number.parseInt((r || "0").replace(/_/g, "0"), 10) || 0;
|
|
925
967
|
}
|
|
926
|
-
function f(
|
|
968
|
+
function f(r) {
|
|
927
969
|
return {
|
|
928
|
-
year: p(
|
|
929
|
-
month: p(
|
|
930
|
-
day: p(
|
|
970
|
+
year: p(r.year),
|
|
971
|
+
month: p(r.month),
|
|
972
|
+
day: p(r.day)
|
|
931
973
|
};
|
|
932
974
|
}
|
|
933
|
-
function c(
|
|
934
|
-
return new Date(
|
|
975
|
+
function c(r, t2) {
|
|
976
|
+
return new Date(r || 2001, t2 || 1, 0).getDate();
|
|
935
977
|
}
|
|
936
|
-
function b(
|
|
937
|
-
const { year: t2, month: i, day: s } = f(
|
|
978
|
+
function b(r) {
|
|
979
|
+
const { year: t2, month: i, day: s } = f(r);
|
|
938
980
|
if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
|
|
939
981
|
return;
|
|
940
982
|
const n = new Date(Date.UTC(t2, i - 1, s));
|
|
941
983
|
if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
|
|
942
984
|
return { year: t2, month: i, day: s };
|
|
943
985
|
}
|
|
944
|
-
function C(
|
|
945
|
-
const t2 = b(
|
|
986
|
+
function C(r) {
|
|
987
|
+
const t2 = b(r);
|
|
946
988
|
return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
|
|
947
989
|
}
|
|
948
|
-
function T2(
|
|
990
|
+
function T2(r, t2, i, s) {
|
|
949
991
|
const n = i ? {
|
|
950
992
|
year: i.getUTCFullYear(),
|
|
951
993
|
month: i.getUTCMonth() + 1,
|
|
@@ -955,7 +997,7 @@ function T2(r2, t2, i, s) {
|
|
|
955
997
|
month: s.getUTCMonth() + 1,
|
|
956
998
|
day: s.getUTCDate()
|
|
957
999
|
} : null;
|
|
958
|
-
return
|
|
1000
|
+
return r === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r === "month" ? {
|
|
959
1001
|
min: n && t2.year === n.year ? n.month : 1,
|
|
960
1002
|
max: e && t2.year === e.year ? e.month : 12
|
|
961
1003
|
} : {
|
|
@@ -1128,26 +1170,26 @@ var u$1 = class u extends V {
|
|
|
1128
1170
|
cursor = 0;
|
|
1129
1171
|
#t;
|
|
1130
1172
|
getGroupItems(t2) {
|
|
1131
|
-
return this.options.filter((
|
|
1173
|
+
return this.options.filter((r) => r.group === t2);
|
|
1132
1174
|
}
|
|
1133
1175
|
isGroupSelected(t2) {
|
|
1134
|
-
const
|
|
1135
|
-
return e === undefined ? false :
|
|
1176
|
+
const r = this.getGroupItems(t2), e = this.value;
|
|
1177
|
+
return e === undefined ? false : r.every((s) => e.includes(s.value));
|
|
1136
1178
|
}
|
|
1137
1179
|
toggleValue() {
|
|
1138
1180
|
const t2 = this.options[this.cursor];
|
|
1139
1181
|
if (this.value === undefined && (this.value = []), t2.group === true) {
|
|
1140
|
-
const
|
|
1141
|
-
this.isGroupSelected(
|
|
1182
|
+
const r = t2.value, e = this.getGroupItems(r);
|
|
1183
|
+
this.isGroupSelected(r) ? this.value = this.value.filter((s) => e.findIndex((i) => i.value === s) === -1) : this.value = [...this.value, ...e.map((s) => s.value)], this.value = Array.from(new Set(this.value));
|
|
1142
1184
|
} else {
|
|
1143
|
-
const
|
|
1144
|
-
this.value =
|
|
1185
|
+
const r = this.value.includes(t2.value);
|
|
1186
|
+
this.value = r ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
|
|
1145
1187
|
}
|
|
1146
1188
|
}
|
|
1147
1189
|
constructor(t2) {
|
|
1148
1190
|
super(t2, false);
|
|
1149
|
-
const { options:
|
|
1150
|
-
this.#t = t2.selectableGroups !== false, this.options = Object.entries(
|
|
1191
|
+
const { options: r } = t2;
|
|
1192
|
+
this.#t = t2.selectableGroups !== false, this.options = Object.entries(r).flatMap(([e, s]) => [
|
|
1151
1193
|
{ value: e, group: true, label: e },
|
|
1152
1194
|
...s.map((i) => ({ ...i, group: e }))
|
|
1153
1195
|
]), this.value = [...t2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: e }) => e === t2.cursorAt), this.#t ? 0 : 1), this.on("cursor", (e) => {
|
|
@@ -1185,10 +1227,10 @@ class h extends V {
|
|
|
1185
1227
|
const t2 = this.userInput;
|
|
1186
1228
|
if (this.cursor >= t2.length)
|
|
1187
1229
|
return `${t2}█`;
|
|
1188
|
-
const s = t2.slice(0, this.cursor),
|
|
1189
|
-
return
|
|
1230
|
+
const s = t2.slice(0, this.cursor), r = t2[this.cursor], i = t2.slice(this.cursor + 1);
|
|
1231
|
+
return r === `
|
|
1190
1232
|
` ? `${s}█
|
|
1191
|
-
${i}` : `${s}${styleText("inverse",
|
|
1233
|
+
${i}` : `${s}${styleText("inverse", r)}${i}`;
|
|
1192
1234
|
}
|
|
1193
1235
|
get cursor() {
|
|
1194
1236
|
return this._cursor;
|
|
@@ -1221,8 +1263,8 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
|
1221
1263
|
if (this.#s)
|
|
1222
1264
|
return this.focused === "submit" ? true : (this.#r(`
|
|
1223
1265
|
`), this._cursor++, false);
|
|
1224
|
-
const
|
|
1225
|
-
return this.#t = true,
|
|
1266
|
+
const r = this.#t;
|
|
1267
|
+
return this.#t = true, r && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
|
|
1226
1268
|
` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
|
|
1227
1269
|
`), this._cursor++, false);
|
|
1228
1270
|
}
|
|
@@ -1231,12 +1273,12 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
|
1231
1273
|
super({
|
|
1232
1274
|
...t2,
|
|
1233
1275
|
initialUserInput: s
|
|
1234
|
-
}, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (
|
|
1276
|
+
}, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r, i) => {
|
|
1235
1277
|
if (i?.name && o$1.has(i.name)) {
|
|
1236
1278
|
this.#t = false, this.#i(i.name);
|
|
1237
1279
|
return;
|
|
1238
1280
|
}
|
|
1239
|
-
if (
|
|
1281
|
+
if (r === "\t" && this.#s) {
|
|
1240
1282
|
this.focused = this.focused === "editor" ? "submit" : "editor";
|
|
1241
1283
|
return;
|
|
1242
1284
|
}
|
|
@@ -1249,10 +1291,10 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
|
|
|
1249
1291
|
this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
|
|
1250
1292
|
return;
|
|
1251
1293
|
}
|
|
1252
|
-
|
|
1294
|
+
r && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r ?? ""), this._cursor++);
|
|
1253
1295
|
}
|
|
1254
|
-
}), this.on("userInput", (
|
|
1255
|
-
this._setValue(
|
|
1296
|
+
}), this.on("userInput", (r) => {
|
|
1297
|
+
this._setValue(r);
|
|
1256
1298
|
}), this.on("finalize", () => {
|
|
1257
1299
|
this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
|
|
1258
1300
|
});
|
|
@@ -1292,8 +1334,8 @@ class n extends V {
|
|
|
1292
1334
|
const t2 = this.userInput;
|
|
1293
1335
|
if (this.cursor >= t2.length)
|
|
1294
1336
|
return `${this.userInput}█`;
|
|
1295
|
-
const e = t2.slice(0, this.cursor), [s, ...
|
|
1296
|
-
return `${e}${styleText("inverse", s)}${
|
|
1337
|
+
const e = t2.slice(0, this.cursor), [s, ...r] = t2.slice(this.cursor);
|
|
1338
|
+
return `${e}${styleText("inverse", s)}${r.join("")}`;
|
|
1297
1339
|
}
|
|
1298
1340
|
get cursor() {
|
|
1299
1341
|
return this._cursor;
|
|
@@ -1427,41 +1469,6 @@ var limitOptions = ({
|
|
|
1427
1469
|
b2.push(n2);
|
|
1428
1470
|
return u3 && b2.push(C2), b2;
|
|
1429
1471
|
};
|
|
1430
|
-
var confirm = (i) => {
|
|
1431
|
-
const a2 = i.active ?? "Yes", s = i.inactive ?? "No";
|
|
1432
|
-
return new r({
|
|
1433
|
-
active: a2,
|
|
1434
|
-
inactive: s,
|
|
1435
|
-
signal: i.signal,
|
|
1436
|
-
input: i.input,
|
|
1437
|
-
output: i.output,
|
|
1438
|
-
initialValue: i.initialValue ?? true,
|
|
1439
|
-
render() {
|
|
1440
|
-
const e = i.withGuide ?? settings.withGuide, u3 = `${symbol(this.state)} `, l2 = e ? `${styleText2("gray", S_BAR)} ` : "", f2 = wrapTextWithPrefix(i.output, i.message, l2, u3), o2 = `${e ? `${styleText2("gray", S_BAR)}
|
|
1441
|
-
` : ""}${f2}
|
|
1442
|
-
`, c2 = this.value ? a2 : s;
|
|
1443
|
-
switch (this.state) {
|
|
1444
|
-
case "submit": {
|
|
1445
|
-
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
1446
|
-
return `${o2}${r2}${styleText2("dim", c2)}`;
|
|
1447
|
-
}
|
|
1448
|
-
case "cancel": {
|
|
1449
|
-
const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
|
|
1450
|
-
return `${o2}${r2}${styleText2(["strikethrough", "dim"], c2)}${e ? `
|
|
1451
|
-
${styleText2("gray", S_BAR)}` : ""}`;
|
|
1452
|
-
}
|
|
1453
|
-
default: {
|
|
1454
|
-
const r2 = e ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e ? styleText2("cyan", S_BAR_END) : "";
|
|
1455
|
-
return `${o2}${r2}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a2}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a2)}`}${i.vertical ? e ? `
|
|
1456
|
-
${styleText2("cyan", S_BAR)} ` : `
|
|
1457
|
-
` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s}`}
|
|
1458
|
-
${g2}
|
|
1459
|
-
`;
|
|
1460
|
-
}
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
}).prompt();
|
|
1464
|
-
};
|
|
1465
1472
|
var MULTISELECT_INSTRUCTIONS = [
|
|
1466
1473
|
`${styleText2("dim", "↑/↓")} to navigate`,
|
|
1467
1474
|
`${styleText2("dim", "Space:")} select`,
|
|
@@ -1884,7 +1891,6 @@ async function getCapabilitiesStats(repoPath = process.cwd(), homeDirPath = home
|
|
|
1884
1891
|
// src/cli.ts
|
|
1885
1892
|
import { writeFileSync, chmodSync, existsSync as existsSync2 } from "fs";
|
|
1886
1893
|
import { join as join3 } from "path";
|
|
1887
|
-
import os from "os";
|
|
1888
1894
|
var ASCII_LOGO = `
|
|
1889
1895
|
____ _ _ _____ _ ___ _____ ____
|
|
1890
1896
|
/ __ \\| | | |_ _| | |_ _| ___| _ \\
|
|
@@ -1893,46 +1899,23 @@ var ASCII_LOGO = `
|
|
|
1893
1899
|
| |__| | _ | | | | _ || || |___| | \\ \\
|
|
1894
1900
|
\\____/|_| |_| |_| |_| |_|___|_____|_| \\_\\
|
|
1895
1901
|
`;
|
|
1902
|
+
var finalReceipt = "";
|
|
1896
1903
|
async function runOnboarding() {
|
|
1897
1904
|
console.clear();
|
|
1898
1905
|
console.log(import_picocolors.default.cyan(ASCII_LOGO));
|
|
1899
1906
|
intro(import_picocolors.default.inverse(" outlier: Welcome "));
|
|
1900
|
-
note(`Outlier is a local-first Policy Engine & Governance Framework for AI Engineering.
|
|
1901
|
-
|
|
1902
|
-
Our mission is AI Safety for developers:
|
|
1903
|
-
As agents (Cursor, Copilot, Claude) write more of our code, we lose visibility into:
|
|
1904
|
-
1. Deskilling Risk (Are we becoming spectators in our own codebase?)
|
|
1905
|
-
2. Carbon Cost (What is the true regional energy cost of token caching?)
|
|
1906
|
-
3. Capability Drift (What hidden skills and external tools are our agents using?)
|
|
1907
|
-
|
|
1908
|
-
We built Outlier to enforce Zero-Trust and protect Human Mastery. You are in control.`, "The Problem: AI Safety in Development");
|
|
1909
1907
|
note(`Outlier operates entirely on your machine.
|
|
1910
1908
|
- Local Only: No API keys. No cloud telemetry. No data leaves your machine.
|
|
1911
|
-
- Native Auditing: We
|
|
1912
|
-
- Actionable Policies:
|
|
1913
|
-
note(`Available Commands:
|
|
1914
|
-
- status: Run a full system audit (Reliance, Carbon, Capabilities)
|
|
1915
|
-
- policy: Configure team/enterprise guardrails and CLI blockers
|
|
1916
|
-
- carbon: View isolated token caching metrics and regional counterfactuals
|
|
1917
|
-
- authorship: View Git authorship ratio (Human vs AI)`, "How it is used");
|
|
1918
|
-
note(`When you start the audit, Outlier will locally parse your Git commits to identify AI co-authorship and cross-reference your agent logs to calculate token waste.
|
|
1919
|
-
|
|
1920
|
-
The results will assign you a "vibe" and evaluate if you are at risk of deskilling.`, "What to Expect");
|
|
1921
|
-
const ready = await confirm({
|
|
1922
|
-
message: "Are you ready to run your first Governance Audit and measure your AI reliance?",
|
|
1923
|
-
initialValue: true
|
|
1924
|
-
});
|
|
1925
|
-
if (isCancel(ready) || !ready) {
|
|
1926
|
-
cancel("Onboarding paused. Run outlier again when you are ready.");
|
|
1927
|
-
process.exit(0);
|
|
1928
|
-
}
|
|
1909
|
+
- Native Auditing: We read your local \`~/.claude\` logs and \`.git/\` commit history.
|
|
1910
|
+
- Actionable Policies: Enforce rules locally via terminal or Git hooks.`, "Privacy & Zero-Trust Principles");
|
|
1929
1911
|
const configPath = join3(os.homedir(), ".outlier_config");
|
|
1930
1912
|
writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
|
|
1931
1913
|
}
|
|
1932
1914
|
async function main() {
|
|
1933
1915
|
console.clear();
|
|
1934
1916
|
console.log(import_picocolors.default.cyan(ASCII_LOGO));
|
|
1935
|
-
|
|
1917
|
+
const pkg = require_package();
|
|
1918
|
+
console.log(import_picocolors.default.dim(` Outlier v${pkg.version} · AI Code Reliance & Telemetry Engine
|
|
1936
1919
|
`));
|
|
1937
1920
|
let action = process.argv[2];
|
|
1938
1921
|
if (action === "--help" || action === "-h" || action === "help") {
|
|
@@ -1958,22 +1941,29 @@ COMMANDS:`));
|
|
|
1958
1941
|
intro(import_picocolors.default.inverse(" outlier "));
|
|
1959
1942
|
if (!action || action === "audit") {
|
|
1960
1943
|
if (action !== "audit") {
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1944
|
+
let menuLoop = true;
|
|
1945
|
+
while (menuLoop) {
|
|
1946
|
+
action = await select({
|
|
1947
|
+
message: "Select outlier governance module:",
|
|
1948
|
+
options: [
|
|
1949
|
+
{ value: "status", label: import_picocolors.default.bold("Status") + import_picocolors.default.dim(" Full audit (reliance + carbon + capabilities)") },
|
|
1950
|
+
{ value: "authorship", label: import_picocolors.default.bold("Authorship") + import_picocolors.default.dim(" Human vs AI, per commit") },
|
|
1951
|
+
{ value: "carbon", label: import_picocolors.default.bold("Carbon") + import_picocolors.default.dim(" Token waste + regional cost") },
|
|
1952
|
+
{ value: "capabilities", label: import_picocolors.default.bold("Capabilities") + import_picocolors.default.dim(" What your agents can reach") },
|
|
1953
|
+
{ value: "policy", label: import_picocolors.default.bold("Policy") + import_picocolors.default.dim(" Set guardrails / install the gate") },
|
|
1954
|
+
{ value: "_divider", label: import_picocolors.default.dim("───────────────────────────────────────────────────────") },
|
|
1955
|
+
{ value: "impact", label: "Impact" + import_picocolors.default.dim(" What happens over the next 5-10 years") },
|
|
1956
|
+
{ value: "knowledge", label: "Literature" + import_picocolors.default.dim(" The academic foundation") },
|
|
1957
|
+
{ value: "participate", label: "Participate" + import_picocolors.default.dim(" Contribute to the research") }
|
|
1958
|
+
]
|
|
1959
|
+
});
|
|
1960
|
+
if (isCancel(action)) {
|
|
1961
|
+
cancel("Operation cancelled.");
|
|
1962
|
+
process.exit(0);
|
|
1963
|
+
}
|
|
1964
|
+
if (action !== "_divider") {
|
|
1965
|
+
menuLoop = false;
|
|
1966
|
+
}
|
|
1977
1967
|
}
|
|
1978
1968
|
} else {
|
|
1979
1969
|
action = "status";
|
|
@@ -2114,6 +2104,74 @@ ${costIcon}${import_picocolors.default.dim("[3] Tokenomics & Cost")} ${import_pi
|
|
|
2114
2104
|
waste: ${import_picocolors.default.yellow(`⚠ ${cachePct}% of tokens are redundant context reads`)}
|
|
2115
2105
|
carbon: ${import_picocolors.default.green(`✓ ${co2Str} (Est. ${regionStr} Grid)`)}
|
|
2116
2106
|
${import_picocolors.default.bold("Governance:")} ${ruleFailures > 0 ? import_picocolors.default.red(`${failIcon} ${ruleFailures + 1} policy failures`) : import_picocolors.default.green(`${passIcon} All clear`)}`, `${import_picocolors.default.bold("[outlier]")} ${5 - (ruleFailures + 1)}/5 policies • ${authWarning || import_picocolors.default.green(`${passIcon} safe surface`)} • ${co2Str}`);
|
|
2107
|
+
const timestamp = new Date().toISOString().split("T")[0];
|
|
2108
|
+
const isDanger = gitStats && gitStats.ratio > 0.7;
|
|
2109
|
+
const verdictZone = isDanger ? import_picocolors.default.red("DANGER ZONE") : import_picocolors.default.green("SAFE / SOVEREIGN");
|
|
2110
|
+
const verdictText = isDanger ? `You are transitioning from 'Creator' to 'Reviewer'.
|
|
2111
|
+
At this trajectory, you risk losing architectural
|
|
2112
|
+
muscle memory on this codebase within 6 months.` : `You are maintaining strong architectural intimacy.
|
|
2113
|
+
Your human judgement remains the primary driver
|
|
2114
|
+
of logic in this system.`;
|
|
2115
|
+
const isInefficient = parseFloat(cachePct) > 40;
|
|
2116
|
+
const cacheVerdict = isInefficient ? import_picocolors.default.yellow("INEFFICIENT") : import_picocolors.default.green("EFFICIENT");
|
|
2117
|
+
const cacheText = isInefficient ? `You are burning paid API tokens and excess compute
|
|
2118
|
+
on files the agent isn't even touching.` : `Your token usage and human judgment are tightly
|
|
2119
|
+
coupled. High signal-to-noise ratio.`;
|
|
2120
|
+
const policyStatus = ruleFailures > 0 ? import_picocolors.default.red("BLOCKED \uD83D\uDED1 (Threshold Exceeded)") : import_picocolors.default.green("PASS ✅ (Within Threshold)");
|
|
2121
|
+
const policyAction = ruleFailures > 0 ? "Triggering Mandatory Mentoring Scenario." : "No intervention required.";
|
|
2122
|
+
const totalTokensStr = carbon ? (carbon.totalTokens / 1000).toFixed(1) + "k" : "0";
|
|
2123
|
+
const humanSov = gitStats ? ((1 - gitStats.ratio) * 100).toFixed(1) + "%" : "100%";
|
|
2124
|
+
const authorshipStr = authPct + (isDanger ? import_picocolors.default.red(" (High Reliance)") : import_picocolors.default.green(" (Healthy)"));
|
|
2125
|
+
const getProgressBar = (pct, length = 10) => {
|
|
2126
|
+
const filled = Math.max(0, Math.min(length, Math.round(pct / 100 * length)));
|
|
2127
|
+
return "▰".repeat(filled) + "▱".repeat(length - filled);
|
|
2128
|
+
};
|
|
2129
|
+
const aiPctVal = gitStats ? gitStats.ratio * 100 : 0;
|
|
2130
|
+
const aiBar = import_picocolors.default.yellow(getProgressBar(aiPctVal));
|
|
2131
|
+
const humanBar = import_picocolors.default.cyan(getProgressBar(100 - aiPctVal));
|
|
2132
|
+
const cacheBar = import_picocolors.default.magenta(getProgressBar(parseFloat(cachePct) || 0));
|
|
2133
|
+
if (!isStrict) {
|
|
2134
|
+
const dateStr = new Date().toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" }).toUpperCase();
|
|
2135
|
+
const timeStr = new Date().toLocaleTimeString("en-US", { hour12: false });
|
|
2136
|
+
const repoName = process.cwd().split("/").pop() || "Unknown";
|
|
2137
|
+
finalReceipt = `
|
|
2138
|
+
${import_picocolors.default.dim("┌────────────────────────────────────────────────────────")}
|
|
2139
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan("█▀█ █░█ ▀█▀ █░░ █ █▀▀ █▀█")} ${import_picocolors.default.bold(":: THERMAL AUDIT RECEIPT")}
|
|
2140
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan("█▄█ █▄█ ░█░ █▄▄ █ ██▄ █▀▄")} ${import_picocolors.default.dim(`:: TIMESTAMP: ${dateStr}`)}
|
|
2141
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2142
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgBlue(" [ COGNITIVE BUDGET ] "))}
|
|
2143
|
+
${import_picocolors.default.dim("│")} AI Authorship ................. ${aiBar} ${authorshipStr}
|
|
2144
|
+
${import_picocolors.default.dim("│")} Human Sovereignty ................. ${humanBar} ${humanSov}
|
|
2145
|
+
${import_picocolors.default.dim("│")}
|
|
2146
|
+
${import_picocolors.default.dim("│")} ↳ Verdict: ${verdictZone}
|
|
2147
|
+
${import_picocolors.default.dim("│")} ${verdictText.split(`
|
|
2148
|
+
`).join(`
|
|
2149
|
+
` + import_picocolors.default.dim("│") + " ")}
|
|
2150
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2151
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgMagenta(" [ FINANCIAL & COMPUTE TOLL ] "))}
|
|
2152
|
+
${import_picocolors.default.dim("│")} Tokens Burnt ................. ${totalTokensStr} vs Human Judgment
|
|
2153
|
+
${import_picocolors.default.dim("│")} Cache Bloat ................. ${cacheBar} ${cachePct}% (Unmodified context)
|
|
2154
|
+
${import_picocolors.default.dim("│")} Regional Grid ................. ${regionStr}
|
|
2155
|
+
${import_picocolors.default.dim("│")}
|
|
2156
|
+
${import_picocolors.default.dim("│")} ↳ Verdict: ${cacheVerdict}
|
|
2157
|
+
${import_picocolors.default.dim("│")} ${cacheText.split(`
|
|
2158
|
+
`).join(`
|
|
2159
|
+
` + import_picocolors.default.dim("│") + " ")}
|
|
2160
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2161
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgYellow(import_picocolors.default.black(" [ POLICY ENFORCEMENT ] ")))}
|
|
2162
|
+
${import_picocolors.default.dim("│")} Status .................................. ${policyStatus}
|
|
2163
|
+
${import_picocolors.default.dim("│")} Action .................................. ${policyAction}
|
|
2164
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2165
|
+
${import_picocolors.default.dim("│")}
|
|
2166
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.italic(import_picocolors.default.dim("patterns emerge in the commit history,"))}
|
|
2167
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.italic(import_picocolors.default.dim("code becomes commoditized by algorithms."))}
|
|
2168
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.italic(import_picocolors.default.dim("human mastery is the only true moat."))}
|
|
2169
|
+
${import_picocolors.default.dim("│")}
|
|
2170
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.cyan("***STAY VIGILANT***"))}
|
|
2171
|
+
${import_picocolors.default.dim("└────────────────────────────────────────────────────────")}`;
|
|
2172
|
+
} else {
|
|
2173
|
+
note(`status: ${authPct} AI Reliance | ${cachePct}% Cache Bloat | ${co2Str}`, `${import_picocolors.default.bold("[outlier]")} CI/CD Audit`);
|
|
2174
|
+
}
|
|
2117
2175
|
} catch (e) {
|
|
2118
2176
|
s.stop("Audit failed");
|
|
2119
2177
|
console.error(import_picocolors.default.red(e.message));
|
|
@@ -2303,35 +2361,8 @@ Read the full academic foundation at: ${import_picocolors.default.underline("htt
|
|
|
2303
2361
|
`);
|
|
2304
2362
|
}
|
|
2305
2363
|
outro("Local telemetry run completed. No data left your machine.");
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2308
|
-
const dateStr = d.toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" }).toUpperCase();
|
|
2309
|
-
const timeStr = d.toLocaleTimeString("en-US", { hour12: false });
|
|
2310
|
-
let repoName = process.cwd().split("/").pop() || "Unknown";
|
|
2311
|
-
console.log(`
|
|
2312
|
-
${import_picocolors.default.dim("-------------------------")} ${import_picocolors.default.bold("AUDIT RECEIPT")} ${import_picocolors.default.dim("-------------------------")}`);
|
|
2313
|
-
console.log(`
|
|
2314
|
-
Project ${import_picocolors.default.bold(repoName.padEnd(16).substring(0, 16))}`);
|
|
2315
|
-
console.log(` Timestamp ${import_picocolors.default.dim(`${dateStr} ${timeStr}`)}
|
|
2316
|
-
`);
|
|
2317
|
-
console.log(` 01x Authorship Policy ${process.argv.includes("--strict") ? "Strict Mode" : "Vibe Check"}`);
|
|
2318
|
-
console.log(` 02x AI Reliance Risk ${action === "carbon" ? "N/A" : "Assessed"}`);
|
|
2319
|
-
console.log(` 03x Cache Bloat Tokens ${action === "authorship" ? "N/A" : "Audited"}`);
|
|
2320
|
-
console.log(` 04x Regional Grid Check ${action === "authorship" ? "N/A" : "Completed"}
|
|
2321
|
-
`);
|
|
2322
|
-
console.log(import_picocolors.default.dim(" **********************************************************"));
|
|
2323
|
-
console.log(`
|
|
2324
|
-
${import_picocolors.default.italic("patterns emerge in the commit history,")}`);
|
|
2325
|
-
console.log(` ${import_picocolors.default.italic("code becomes commoditized by algorithms.")}`);
|
|
2326
|
-
console.log(` ${import_picocolors.default.italic("human mastery is the only true moat.")}
|
|
2327
|
-
`);
|
|
2328
|
-
console.log(import_picocolors.default.dim(` **********************************************************
|
|
2329
|
-
`));
|
|
2330
|
-
console.log(" Outlier Governance Engine");
|
|
2331
|
-
console.log(import_picocolors.default.bold(`
|
|
2332
|
-
***AUDIT COMPLETE***`));
|
|
2333
|
-
console.log(import_picocolors.default.bold(` ***STAY VIGILANT***
|
|
2334
|
-
`));
|
|
2364
|
+
if (typeof finalReceipt !== "undefined" && finalReceipt) {
|
|
2365
|
+
console.log(finalReceipt);
|
|
2335
2366
|
}
|
|
2336
2367
|
console.log(import_picocolors.default.dim(`└ Share your audit: https://x.com/intent/tweet?text=${encodeURIComponent(`I just audited my codebase for AI reliance and deskilling risk. What does your repo score?
|
|
2337
2368
|
|
package/bin/postinstall.js
CHANGED
|
@@ -9,9 +9,12 @@ console.log(dim('─────────────────────
|
|
|
9
9
|
console.log('To start the interactive wizard and audit your codebase, type:\n');
|
|
10
10
|
console.log(` ${cyan('outlier')}\n`);
|
|
11
11
|
console.log('Available Commands:');
|
|
12
|
-
console.log(` ${cyan('outlier status')}
|
|
13
|
-
console.log(` ${cyan('outlier
|
|
12
|
+
console.log(` ${cyan('outlier status')} Run full AI reliance & capability audit`);
|
|
13
|
+
console.log(` ${cyan('outlier authorship')} Scan git history for AI co-authorship ratio`);
|
|
14
|
+
console.log(` ${cyan('outlier carbon')} Scan local logs for token waste & carbon cost`);
|
|
15
|
+
console.log(` ${cyan('outlier capabilities')} Audit active MCPs, skills, and orchestrations`);
|
|
16
|
+
console.log(` ${cyan('outlier policy')} Configure CI/CD guardrails and thresholds`);
|
|
17
|
+
console.log(` ${cyan('outlier impact')} See the compounding horizon of AI Deskilling`);
|
|
14
18
|
console.log(` ${cyan('outlier knowledge')} Explore core literature and METR references`);
|
|
15
19
|
console.log(` ${cyan('outlier participate')} Help build the literature on AI deskilling`);
|
|
16
|
-
console.log(` ${cyan('outlier help')} See all available commands`);
|
|
17
20
|
console.log(dim('────────────────────────────────────────────────────────────\n'));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rosh100yx/outlier",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.14",
|
|
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
6
|
"outlier": "bin/outlier.js"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"data"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"build": "bun build ./src/cli.ts --target=node --outfile bin/outlier.js",
|
|
15
|
+
"build": "bunx tsc --noEmit && bun build ./src/cli.ts --target=node --outfile bin/outlier.js",
|
|
16
16
|
"test": "bun test",
|
|
17
17
|
"start": "bun run src/cli.ts",
|
|
18
18
|
"postinstall": "node bin/postinstall.js"
|
package/src/cli.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import os from 'os';
|
|
2
3
|
import { intro, outro, select, spinner, isCancel, cancel, note, text, confirm } from '@clack/prompts';
|
|
3
4
|
import pc from 'picocolors';
|
|
4
5
|
import { getAuthorshipStats } from './git';
|
|
@@ -6,7 +7,6 @@ import { getCarbonStats } from './carbon';
|
|
|
6
7
|
import { getCapabilitiesStats } from './capabilities';
|
|
7
8
|
import { writeFileSync, chmodSync, existsSync } from 'fs';
|
|
8
9
|
import { join } from 'path';
|
|
9
|
-
import { execSync } from 'child_process';
|
|
10
10
|
|
|
11
11
|
const ASCII_LOGO = `
|
|
12
12
|
____ _ _ _____ _ ___ _____ ____
|
|
@@ -17,61 +17,21 @@ const ASCII_LOGO = `
|
|
|
17
17
|
\\____/|_| |_| |_| |_| |_|___|_____|_| \\_\\
|
|
18
18
|
`;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
import { confirm } from '@clack/prompts';
|
|
20
|
+
let finalReceipt = '';
|
|
22
21
|
|
|
23
22
|
async function runOnboarding() {
|
|
24
23
|
console.clear();
|
|
25
24
|
console.log(pc.cyan(ASCII_LOGO));
|
|
26
25
|
intro(pc.inverse(' outlier: Welcome '));
|
|
27
26
|
|
|
28
|
-
note(
|
|
29
|
-
`Outlier is a local-first Policy Engine & Governance Framework for AI Engineering.
|
|
30
|
-
|
|
31
|
-
Our mission is AI Safety for developers:
|
|
32
|
-
As agents (Cursor, Copilot, Claude) write more of our code, we lose visibility into:
|
|
33
|
-
1. Deskilling Risk (Are we becoming spectators in our own codebase?)
|
|
34
|
-
2. Carbon Cost (What is the true regional energy cost of token caching?)
|
|
35
|
-
3. Capability Drift (What hidden skills and external tools are our agents using?)
|
|
36
|
-
|
|
37
|
-
We built Outlier to enforce Zero-Trust and protect Human Mastery. You are in control.`,
|
|
38
|
-
'The Problem: AI Safety in Development'
|
|
39
|
-
);
|
|
40
|
-
|
|
41
27
|
note(
|
|
42
28
|
`Outlier operates entirely on your machine.
|
|
43
29
|
- Local Only: No API keys. No cloud telemetry. No data leaves your machine.
|
|
44
|
-
- Native Auditing: We
|
|
45
|
-
- Actionable Policies:
|
|
30
|
+
- Native Auditing: We read your local \`~/.claude\` logs and \`.git/\` commit history.
|
|
31
|
+
- Actionable Policies: Enforce rules locally via terminal or Git hooks.`,
|
|
46
32
|
'Privacy & Zero-Trust Principles'
|
|
47
33
|
);
|
|
48
34
|
|
|
49
|
-
note(
|
|
50
|
-
`Available Commands:
|
|
51
|
-
- status: Run a full system audit (Reliance, Carbon, Capabilities)
|
|
52
|
-
- policy: Configure team/enterprise guardrails and CLI blockers
|
|
53
|
-
- carbon: View isolated token caching metrics and regional counterfactuals
|
|
54
|
-
- authorship: View Git authorship ratio (Human vs AI)`,
|
|
55
|
-
'How it is used'
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
note(
|
|
59
|
-
`When you start the audit, Outlier will locally parse your Git commits to identify AI co-authorship and cross-reference your agent logs to calculate token waste.
|
|
60
|
-
|
|
61
|
-
The results will assign you a "vibe" and evaluate if you are at risk of deskilling.`,
|
|
62
|
-
'What to Expect'
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
const ready = await confirm({
|
|
66
|
-
message: 'Are you ready to run your first Governance Audit and measure your AI reliance?',
|
|
67
|
-
initialValue: true,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (isCancel(ready) || !ready) {
|
|
71
|
-
cancel('Onboarding paused. Run outlier again when you are ready.');
|
|
72
|
-
process.exit(0);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
35
|
const configPath = join(os.homedir(), '.outlier_config');
|
|
76
36
|
writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
|
|
77
37
|
}
|
|
@@ -79,7 +39,8 @@ The results will assign you a "vibe" and evaluate if you are at risk of deskilli
|
|
|
79
39
|
async function main() {
|
|
80
40
|
console.clear();
|
|
81
41
|
console.log(pc.cyan(ASCII_LOGO));
|
|
82
|
-
|
|
42
|
+
const pkg = require('../package.json');
|
|
43
|
+
console.log(pc.dim(` Outlier v${pkg.version} · AI Code Reliance & Telemetry Engine\n`));
|
|
83
44
|
|
|
84
45
|
let action = process.argv[2] as any;
|
|
85
46
|
|
|
@@ -107,23 +68,31 @@ async function main() {
|
|
|
107
68
|
|
|
108
69
|
if (!action || action === 'audit') {
|
|
109
70
|
if (action !== 'audit') {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
71
|
+
let menuLoop = true;
|
|
72
|
+
while (menuLoop) {
|
|
73
|
+
action = await select({
|
|
74
|
+
message: 'Select outlier governance module:',
|
|
75
|
+
options: [
|
|
76
|
+
{ value: 'status', label: pc.bold('Status') + pc.dim(' Full audit (reliance + carbon + capabilities)') },
|
|
77
|
+
{ value: 'authorship', label: pc.bold('Authorship') + pc.dim(' Human vs AI, per commit') },
|
|
78
|
+
{ value: 'carbon', label: pc.bold('Carbon') + pc.dim(' Token waste + regional cost') },
|
|
79
|
+
{ value: 'capabilities', label: pc.bold('Capabilities') + pc.dim(' What your agents can reach') },
|
|
80
|
+
{ value: 'policy', label: pc.bold('Policy') + pc.dim(' Set guardrails / install the gate') },
|
|
81
|
+
{ value: '_divider', label: pc.dim('───────────────────────────────────────────────────────') },
|
|
82
|
+
{ value: 'impact', label: 'Impact' + pc.dim(' What happens over the next 5-10 years') },
|
|
83
|
+
{ value: 'knowledge', label: 'Literature' + pc.dim(' The academic foundation') },
|
|
84
|
+
{ value: 'participate', label: 'Participate' + pc.dim(' Contribute to the research') }
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (isCancel(action)) {
|
|
89
|
+
cancel('Operation cancelled.');
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (action !== '_divider') {
|
|
94
|
+
menuLoop = false;
|
|
95
|
+
}
|
|
127
96
|
}
|
|
128
97
|
} else {
|
|
129
98
|
action = 'status'; // Map the 'audit' alias directly to status for CI
|
|
@@ -286,6 +255,79 @@ ${costIcon}${pc.dim('[3] Tokenomics & Cost')} ${pc.magenta('▰▰▰▰▰▰
|
|
|
286
255
|
${pc.bold('Governance:')} ${ruleFailures > 0 ? pc.red(`${failIcon} ${ruleFailures + 1} policy failures`) : pc.green(`${passIcon} All clear`)}`,
|
|
287
256
|
`${pc.bold('[outlier]')} ${5 - (ruleFailures+1)}/5 policies • ${authWarning || pc.green(`${passIcon} safe surface`)} • ${co2Str}`
|
|
288
257
|
);
|
|
258
|
+
|
|
259
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
260
|
+
const isDanger = gitStats && gitStats.ratio > 0.7;
|
|
261
|
+
const verdictZone = isDanger ? pc.red('DANGER ZONE') : pc.green('SAFE / SOVEREIGN');
|
|
262
|
+
const verdictText = isDanger
|
|
263
|
+
? `You are transitioning from 'Creator' to 'Reviewer'.\n At this trajectory, you risk losing architectural \n muscle memory on this codebase within 6 months.`
|
|
264
|
+
: `You are maintaining strong architectural intimacy.\n Your human judgement remains the primary driver\n of logic in this system.`;
|
|
265
|
+
|
|
266
|
+
const isInefficient = parseFloat(cachePct) > 40;
|
|
267
|
+
const cacheVerdict = isInefficient ? pc.yellow('INEFFICIENT') : pc.green('EFFICIENT');
|
|
268
|
+
const cacheText = isInefficient
|
|
269
|
+
? `You are burning paid API tokens and excess compute\n on files the agent isn't even touching.`
|
|
270
|
+
: `Your token usage and human judgment are tightly\n coupled. High signal-to-noise ratio.`;
|
|
271
|
+
|
|
272
|
+
const policyStatus = ruleFailures > 0 ? pc.red('BLOCKED 🛑 (Threshold Exceeded)') : pc.green('PASS ✅ (Within Threshold)');
|
|
273
|
+
const policyAction = ruleFailures > 0 ? 'Triggering Mandatory Mentoring Scenario.' : 'No intervention required.';
|
|
274
|
+
|
|
275
|
+
const totalTokensStr = carbon ? (carbon.totalTokens / 1000).toFixed(1) + 'k' : '0';
|
|
276
|
+
const humanSov = gitStats ? ((1 - gitStats.ratio) * 100).toFixed(1) + '%' : '100%';
|
|
277
|
+
const authorshipStr = authPct + (isDanger ? pc.red(' (High Reliance)') : pc.green(' (Healthy)'));
|
|
278
|
+
|
|
279
|
+
const getProgressBar = (pct: number, length = 10) => {
|
|
280
|
+
const filled = Math.max(0, Math.min(length, Math.round((pct / 100) * length)));
|
|
281
|
+
return '▰'.repeat(filled) + '▱'.repeat(length - filled);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const aiPctVal = gitStats ? gitStats.ratio * 100 : 0;
|
|
285
|
+
const aiBar = pc.yellow(getProgressBar(aiPctVal));
|
|
286
|
+
const humanBar = pc.cyan(getProgressBar(100 - aiPctVal));
|
|
287
|
+
const cacheBar = pc.magenta(getProgressBar(parseFloat(cachePct) || 0));
|
|
288
|
+
|
|
289
|
+
if (!isStrict) {
|
|
290
|
+
const dateStr = new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }).toUpperCase();
|
|
291
|
+
const timeStr = new Date().toLocaleTimeString('en-US', { hour12: false });
|
|
292
|
+
const repoName = process.cwd().split('/').pop() || 'Unknown';
|
|
293
|
+
|
|
294
|
+
finalReceipt = `
|
|
295
|
+
${pc.dim('┌────────────────────────────────────────────────────────')}
|
|
296
|
+
${pc.dim('│')} ${pc.cyan('█▀█ █░█ ▀█▀ █░░ █ █▀▀ █▀█')} ${pc.bold(':: THERMAL AUDIT RECEIPT')}
|
|
297
|
+
${pc.dim('│')} ${pc.cyan('█▄█ █▄█ ░█░ █▄▄ █ ██▄ █▀▄')} ${pc.dim(`:: TIMESTAMP: ${dateStr}`)}
|
|
298
|
+
${pc.dim('├────────────────────────────────────────────────────────')}
|
|
299
|
+
${pc.dim('│')} ${pc.bold(pc.bgBlue(' [ COGNITIVE BUDGET ] '))}
|
|
300
|
+
${pc.dim('│')} AI Authorship ................. ${aiBar} ${authorshipStr}
|
|
301
|
+
${pc.dim('│')} Human Sovereignty ................. ${humanBar} ${humanSov}
|
|
302
|
+
${pc.dim('│')}
|
|
303
|
+
${pc.dim('│')} ↳ Verdict: ${verdictZone}
|
|
304
|
+
${pc.dim('│')} ${verdictText.split('\n').join('\n ' + pc.dim('│') + ' ')}
|
|
305
|
+
${pc.dim('├────────────────────────────────────────────────────────')}
|
|
306
|
+
${pc.dim('│')} ${pc.bold(pc.bgMagenta(' [ FINANCIAL & COMPUTE TOLL ] '))}
|
|
307
|
+
${pc.dim('│')} Tokens Burnt ................. ${totalTokensStr} vs Human Judgment
|
|
308
|
+
${pc.dim('│')} Cache Bloat ................. ${cacheBar} ${cachePct}% (Unmodified context)
|
|
309
|
+
${pc.dim('│')} Regional Grid ................. ${regionStr}
|
|
310
|
+
${pc.dim('│')}
|
|
311
|
+
${pc.dim('│')} ↳ Verdict: ${cacheVerdict}
|
|
312
|
+
${pc.dim('│')} ${cacheText.split('\n').join('\n ' + pc.dim('│') + ' ')}
|
|
313
|
+
${pc.dim('├────────────────────────────────────────────────────────')}
|
|
314
|
+
${pc.dim('│')} ${pc.bold(pc.bgYellow(pc.black(' [ POLICY ENFORCEMENT ] ')))}
|
|
315
|
+
${pc.dim('│')} Status .................................. ${policyStatus}
|
|
316
|
+
${pc.dim('│')} Action .................................. ${policyAction}
|
|
317
|
+
${pc.dim('├────────────────────────────────────────────────────────')}
|
|
318
|
+
${pc.dim('│')}
|
|
319
|
+
${pc.dim('│')} ${pc.italic(pc.dim('patterns emerge in the commit history,'))}
|
|
320
|
+
${pc.dim('│')} ${pc.italic(pc.dim('code becomes commoditized by algorithms.'))}
|
|
321
|
+
${pc.dim('│')} ${pc.italic(pc.dim('human mastery is the only true moat.'))}
|
|
322
|
+
${pc.dim('│')}
|
|
323
|
+
${pc.dim('│')} ${pc.bold(pc.cyan('***STAY VIGILANT***'))}
|
|
324
|
+
${pc.dim('└────────────────────────────────────────────────────────')}`;
|
|
325
|
+
} else {
|
|
326
|
+
note(
|
|
327
|
+
`status: ${authPct} AI Reliance | ${cachePct}% Cache Bloat | ${co2Str}`,
|
|
328
|
+
`${pc.bold('[outlier]')} CI/CD Audit`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
289
331
|
} catch (e: any) {
|
|
290
332
|
s.stop('Audit failed');
|
|
291
333
|
console.error(pc.red(e.message));
|
|
@@ -484,34 +526,12 @@ Artifact: ${pc.cyan(reportPath)}`,
|
|
|
484
526
|
|
|
485
527
|
outro('Local telemetry run completed. No data left your machine.');
|
|
486
528
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const d = new Date();
|
|
490
|
-
const dateStr = d.toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }).toUpperCase();
|
|
491
|
-
const timeStr = d.toLocaleTimeString('en-US', { hour12: false });
|
|
492
|
-
|
|
493
|
-
let repoName = process.cwd().split('/').pop() || 'Unknown';
|
|
494
|
-
|
|
495
|
-
console.log(`\n${pc.dim('-------------------------')} ${pc.bold('AUDIT RECEIPT')} ${pc.dim('-------------------------')}`);
|
|
496
|
-
console.log(`\n Project ${pc.bold(repoName.padEnd(16).substring(0,16))}`);
|
|
497
|
-
console.log(` Timestamp ${pc.dim(`${dateStr} ${timeStr}`)}\n`);
|
|
498
|
-
|
|
499
|
-
console.log(` 01x Authorship Policy ${process.argv.includes('--strict') ? 'Strict Mode' : 'Vibe Check'}`);
|
|
500
|
-
console.log(` 02x AI Reliance Risk ${action === 'carbon' ? 'N/A' : 'Assessed'}`);
|
|
501
|
-
console.log(` 03x Cache Bloat Tokens ${action === 'authorship' ? 'N/A' : 'Audited'}`);
|
|
502
|
-
console.log(` 04x Regional Grid Check ${action === 'authorship' ? 'N/A' : 'Completed'}\n`);
|
|
503
|
-
|
|
504
|
-
console.log(pc.dim(' **********************************************************'));
|
|
505
|
-
console.log(`\n ${pc.italic('patterns emerge in the commit history,')}`);
|
|
506
|
-
console.log(` ${pc.italic('code becomes commoditized by algorithms.')}`);
|
|
507
|
-
console.log(` ${pc.italic('human mastery is the only true moat.')}\n`);
|
|
508
|
-
console.log(pc.dim(' **********************************************************\n'));
|
|
509
|
-
|
|
510
|
-
console.log(' Outlier Governance Engine');
|
|
511
|
-
console.log(pc.bold('\n ***AUDIT COMPLETE***'));
|
|
512
|
-
console.log(pc.bold(' ***STAY VIGILANT***\n'));
|
|
529
|
+
if (typeof finalReceipt !== 'undefined' && finalReceipt) {
|
|
530
|
+
console.log(finalReceipt);
|
|
513
531
|
}
|
|
514
532
|
|
|
533
|
+
// (Old artifact storytelling block removed to unify receipt UX)
|
|
534
|
+
|
|
515
535
|
console.log(
|
|
516
536
|
pc.dim(
|
|
517
537
|
`└ Share your audit: https://x.com/intent/tweet?text=${encodeURIComponent(
|