@rosh100yx/outlier 0.4.10 → 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 CHANGED
@@ -18,8 +18,26 @@
18
18
  </p>
19
19
 
20
20
  <br/>
21
- <img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/cli-demo.png" alt="Outlier CLI Demo" width="800" />
22
- <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
+ ```
23
41
  </div>
24
42
 
25
43
  ## How It Works
@@ -50,13 +68,28 @@
50
68
  ## Commands
51
69
  | Command | Purpose |
52
70
  |---------|---------|
53
- | `outlier` | Start the interactive Onboarding Wizard (Recommended for first-timers) |
54
- | `outlier --help` | View the CLI help menu and all available commands |
55
- | `outlier status` | Run the full AI reliance & capability audit (Generates the Thermal Receipt) |
56
- | `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 |
57
74
  | `outlier carbon` | Scan local logs for context waste & token costs |
75
+ | `outlier capabilities` | Audit active MCPs, skills, and orchestrations |
58
76
  | `outlier policy` | Configure Personal, Team, or Enterprise guardrails in CI |
59
- | `outlier confessional` | Submit qualitative feedback or feature requests directly from the terminal |
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
+ ```
60
93
 
61
94
  ## Quickstart: Your First Audit
62
95
 
package/bin/outlier.js CHANGED
@@ -165,7 +165,7 @@ var require_picocolors = __commonJS((exports, module) => {
165
165
  var require_package = __commonJS((exports, module) => {
166
166
  module.exports = {
167
167
  name: "@rosh100yx/outlier",
168
- version: "0.4.10",
168
+ version: "0.4.14",
169
169
  description: "AI Code Governance & Capability Auditing for the Terminal. Measures AI reliance, context waste, and enforces local CI/CD policies.",
170
170
  bin: {
171
171
  outlier: "bin/outlier.js"
@@ -177,7 +177,7 @@ var require_package = __commonJS((exports, module) => {
177
177
  "data"
178
178
  ],
179
179
  scripts: {
180
- build: "bun build ./src/cli.ts --target=node --outfile bin/outlier.js",
180
+ build: "bunx tsc --noEmit && bun build ./src/cli.ts --target=node --outfile bin/outlier.js",
181
181
  test: "bun test",
182
182
  start: "bun run src/cli.ts",
183
183
  postinstall: "node bin/postinstall.js"
@@ -218,6 +218,9 @@ var require_package = __commonJS((exports, module) => {
218
218
  };
219
219
  });
220
220
 
221
+ // src/cli.ts
222
+ import os from "os";
223
+
221
224
  // node_modules/@clack/core/dist/index.mjs
222
225
  import { styleText } from "node:util";
223
226
  import { stdout, stdin } from "node:process";
@@ -940,34 +943,16 @@ var T$1 = class T extends V {
940
943
  }
941
944
  }
942
945
  };
943
-
944
- class r extends V {
945
- get cursor() {
946
- return this.value ? 0 : 1;
947
- }
948
- get _value() {
949
- return this.cursor === 0;
950
- }
951
- constructor(t2) {
952
- super(t2, false), this.value = !!t2.initialValue, this.on("userInput", () => {
953
- this.value = this._value;
954
- }), this.on("confirm", (i) => {
955
- this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i, this.state = "submit", this.close();
956
- }), this.on("cursor", () => {
957
- this.value = !this.value;
958
- });
959
- }
960
- }
961
946
  var _ = {
962
947
  Y: { type: "year", len: 4 },
963
948
  M: { type: "month", len: 2 },
964
949
  D: { type: "day", len: 2 }
965
950
  };
966
- function M(r2) {
967
- return [...r2].map((t2) => _[t2]);
951
+ function M(r) {
952
+ return [...r].map((t2) => _[t2]);
968
953
  }
969
- function P(r2) {
970
- const i = new Intl.DateTimeFormat(r2, {
954
+ function P(r) {
955
+ const i = new Intl.DateTimeFormat(r, {
971
956
  year: "numeric",
972
957
  month: "2-digit",
973
958
  day: "2-digit"
@@ -977,32 +962,32 @@ function P(r2) {
977
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 });
978
963
  return { segments: s, separator: n };
979
964
  }
980
- function p(r2) {
981
- return Number.parseInt((r2 || "0").replace(/_/g, "0"), 10) || 0;
965
+ function p(r) {
966
+ return Number.parseInt((r || "0").replace(/_/g, "0"), 10) || 0;
982
967
  }
983
- function f(r2) {
968
+ function f(r) {
984
969
  return {
985
- year: p(r2.year),
986
- month: p(r2.month),
987
- day: p(r2.day)
970
+ year: p(r.year),
971
+ month: p(r.month),
972
+ day: p(r.day)
988
973
  };
989
974
  }
990
- function c(r2, t2) {
991
- return new Date(r2 || 2001, t2 || 1, 0).getDate();
975
+ function c(r, t2) {
976
+ return new Date(r || 2001, t2 || 1, 0).getDate();
992
977
  }
993
- function b(r2) {
994
- const { year: t2, month: i, day: s } = f(r2);
978
+ function b(r) {
979
+ const { year: t2, month: i, day: s } = f(r);
995
980
  if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
996
981
  return;
997
982
  const n = new Date(Date.UTC(t2, i - 1, s));
998
983
  if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
999
984
  return { year: t2, month: i, day: s };
1000
985
  }
1001
- function C(r2) {
1002
- const t2 = b(r2);
986
+ function C(r) {
987
+ const t2 = b(r);
1003
988
  return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
1004
989
  }
1005
- function T2(r2, t2, i, s) {
990
+ function T2(r, t2, i, s) {
1006
991
  const n = i ? {
1007
992
  year: i.getUTCFullYear(),
1008
993
  month: i.getUTCMonth() + 1,
@@ -1012,7 +997,7 @@ function T2(r2, t2, i, s) {
1012
997
  month: s.getUTCMonth() + 1,
1013
998
  day: s.getUTCDate()
1014
999
  } : null;
1015
- return r2 === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r2 === "month" ? {
1000
+ return r === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r === "month" ? {
1016
1001
  min: n && t2.year === n.year ? n.month : 1,
1017
1002
  max: e && t2.year === e.year ? e.month : 12
1018
1003
  } : {
@@ -1185,26 +1170,26 @@ var u$1 = class u extends V {
1185
1170
  cursor = 0;
1186
1171
  #t;
1187
1172
  getGroupItems(t2) {
1188
- return this.options.filter((r2) => r2.group === t2);
1173
+ return this.options.filter((r) => r.group === t2);
1189
1174
  }
1190
1175
  isGroupSelected(t2) {
1191
- const r2 = this.getGroupItems(t2), e = this.value;
1192
- return e === undefined ? false : r2.every((s) => e.includes(s.value));
1176
+ const r = this.getGroupItems(t2), e = this.value;
1177
+ return e === undefined ? false : r.every((s) => e.includes(s.value));
1193
1178
  }
1194
1179
  toggleValue() {
1195
1180
  const t2 = this.options[this.cursor];
1196
1181
  if (this.value === undefined && (this.value = []), t2.group === true) {
1197
- const r2 = t2.value, e = this.getGroupItems(r2);
1198
- this.isGroupSelected(r2) ? 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));
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));
1199
1184
  } else {
1200
- const r2 = this.value.includes(t2.value);
1201
- this.value = r2 ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
1185
+ const r = this.value.includes(t2.value);
1186
+ this.value = r ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
1202
1187
  }
1203
1188
  }
1204
1189
  constructor(t2) {
1205
1190
  super(t2, false);
1206
- const { options: r2 } = t2;
1207
- this.#t = t2.selectableGroups !== false, this.options = Object.entries(r2).flatMap(([e, s]) => [
1191
+ const { options: r } = t2;
1192
+ this.#t = t2.selectableGroups !== false, this.options = Object.entries(r).flatMap(([e, s]) => [
1208
1193
  { value: e, group: true, label: e },
1209
1194
  ...s.map((i) => ({ ...i, group: e }))
1210
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) => {
@@ -1242,10 +1227,10 @@ class h extends V {
1242
1227
  const t2 = this.userInput;
1243
1228
  if (this.cursor >= t2.length)
1244
1229
  return `${t2}█`;
1245
- const s = t2.slice(0, this.cursor), r2 = t2[this.cursor], i = t2.slice(this.cursor + 1);
1246
- return r2 === `
1230
+ const s = t2.slice(0, this.cursor), r = t2[this.cursor], i = t2.slice(this.cursor + 1);
1231
+ return r === `
1247
1232
  ` ? `${s}█
1248
- ${i}` : `${s}${styleText("inverse", r2)}${i}`;
1233
+ ${i}` : `${s}${styleText("inverse", r)}${i}`;
1249
1234
  }
1250
1235
  get cursor() {
1251
1236
  return this._cursor;
@@ -1278,8 +1263,8 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
1278
1263
  if (this.#s)
1279
1264
  return this.focused === "submit" ? true : (this.#r(`
1280
1265
  `), this._cursor++, false);
1281
- const r2 = this.#t;
1282
- return this.#t = true, r2 && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
1266
+ const r = this.#t;
1267
+ return this.#t = true, r && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
1283
1268
  ` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
1284
1269
  `), this._cursor++, false);
1285
1270
  }
@@ -1288,12 +1273,12 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
1288
1273
  super({
1289
1274
  ...t2,
1290
1275
  initialUserInput: s
1291
- }, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r2, i) => {
1276
+ }, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r, i) => {
1292
1277
  if (i?.name && o$1.has(i.name)) {
1293
1278
  this.#t = false, this.#i(i.name);
1294
1279
  return;
1295
1280
  }
1296
- if (r2 === "\t" && this.#s) {
1281
+ if (r === "\t" && this.#s) {
1297
1282
  this.focused = this.focused === "editor" ? "submit" : "editor";
1298
1283
  return;
1299
1284
  }
@@ -1306,10 +1291,10 @@ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
1306
1291
  this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
1307
1292
  return;
1308
1293
  }
1309
- r2 && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r2 ?? ""), this._cursor++);
1294
+ r && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r ?? ""), this._cursor++);
1310
1295
  }
1311
- }), this.on("userInput", (r2) => {
1312
- this._setValue(r2);
1296
+ }), this.on("userInput", (r) => {
1297
+ this._setValue(r);
1313
1298
  }), this.on("finalize", () => {
1314
1299
  this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
1315
1300
  });
@@ -1349,8 +1334,8 @@ class n extends V {
1349
1334
  const t2 = this.userInput;
1350
1335
  if (this.cursor >= t2.length)
1351
1336
  return `${this.userInput}█`;
1352
- const e = t2.slice(0, this.cursor), [s, ...r2] = t2.slice(this.cursor);
1353
- return `${e}${styleText("inverse", s)}${r2.join("")}`;
1337
+ const e = t2.slice(0, this.cursor), [s, ...r] = t2.slice(this.cursor);
1338
+ return `${e}${styleText("inverse", s)}${r.join("")}`;
1354
1339
  }
1355
1340
  get cursor() {
1356
1341
  return this._cursor;
@@ -1484,41 +1469,6 @@ var limitOptions = ({
1484
1469
  b2.push(n2);
1485
1470
  return u3 && b2.push(C2), b2;
1486
1471
  };
1487
- var confirm = (i) => {
1488
- const a2 = i.active ?? "Yes", s = i.inactive ?? "No";
1489
- return new r({
1490
- active: a2,
1491
- inactive: s,
1492
- signal: i.signal,
1493
- input: i.input,
1494
- output: i.output,
1495
- initialValue: i.initialValue ?? true,
1496
- render() {
1497
- 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)}
1498
- ` : ""}${f2}
1499
- `, c2 = this.value ? a2 : s;
1500
- switch (this.state) {
1501
- case "submit": {
1502
- const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
1503
- return `${o2}${r2}${styleText2("dim", c2)}`;
1504
- }
1505
- case "cancel": {
1506
- const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
1507
- return `${o2}${r2}${styleText2(["strikethrough", "dim"], c2)}${e ? `
1508
- ${styleText2("gray", S_BAR)}` : ""}`;
1509
- }
1510
- default: {
1511
- const r2 = e ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e ? styleText2("cyan", S_BAR_END) : "";
1512
- return `${o2}${r2}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a2}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a2)}`}${i.vertical ? e ? `
1513
- ${styleText2("cyan", S_BAR)} ` : `
1514
- ` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s}`}
1515
- ${g2}
1516
- `;
1517
- }
1518
- }
1519
- }
1520
- }).prompt();
1521
- };
1522
1472
  var MULTISELECT_INSTRUCTIONS = [
1523
1473
  `${styleText2("dim", "↑/↓")} to navigate`,
1524
1474
  `${styleText2("dim", "Space:")} select`,
@@ -1941,7 +1891,6 @@ async function getCapabilitiesStats(repoPath = process.cwd(), homeDirPath = home
1941
1891
  // src/cli.ts
1942
1892
  import { writeFileSync, chmodSync, existsSync as existsSync2 } from "fs";
1943
1893
  import { join as join3 } from "path";
1944
- import os from "os";
1945
1894
  var ASCII_LOGO = `
1946
1895
  ____ _ _ _____ _ ___ _____ ____
1947
1896
  / __ \\| | | |_ _| | |_ _| ___| _ \\
@@ -1950,39 +1899,15 @@ var ASCII_LOGO = `
1950
1899
  | |__| | _ | | | | _ || || |___| | \\ \\
1951
1900
  \\____/|_| |_| |_| |_| |_|___|_____|_| \\_\\
1952
1901
  `;
1902
+ var finalReceipt = "";
1953
1903
  async function runOnboarding() {
1954
1904
  console.clear();
1955
1905
  console.log(import_picocolors.default.cyan(ASCII_LOGO));
1956
1906
  intro(import_picocolors.default.inverse(" outlier: Welcome "));
1957
- note(`Outlier is a local-first Policy Engine & Governance Framework for AI Engineering.
1958
-
1959
- Our mission is AI Safety for developers:
1960
- As agents (Cursor, Copilot, Claude) write more of our code, we lose visibility into:
1961
- 1. Deskilling Risk (Are we becoming spectators in our own codebase?)
1962
- 2. Carbon Cost (What is the true regional energy cost of token caching?)
1963
- 3. Capability Drift (What hidden skills and external tools are our agents using?)
1964
-
1965
- We built Outlier to enforce Zero-Trust and protect Human Mastery. You are in control.`, "The Problem: AI Safety in Development");
1966
1907
  note(`Outlier operates entirely on your machine.
1967
1908
  - Local Only: No API keys. No cloud telemetry. No data leaves your machine.
1968
- - Native Auditing: We only read your local \`~/.claude\` logs and \`.git/\` commit history.
1969
- - Actionable Policies: We enforce rules locally via terminal or Git pre-commit hooks.`, "Privacy & Zero-Trust Principles");
1970
- note(`Available Commands:
1971
- - status: Run a full system audit (Reliance, Carbon, Capabilities)
1972
- - policy: Configure team/enterprise guardrails and CLI blockers
1973
- - carbon: View isolated token caching metrics and regional counterfactuals
1974
- - authorship: View Git authorship ratio (Human vs AI)`, "How it is used");
1975
- 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.
1976
-
1977
- The results will assign you a "vibe" and evaluate if you are at risk of deskilling.`, "What to Expect");
1978
- const ready = await confirm({
1979
- message: "Are you ready to run your first Governance Audit and measure your AI reliance?",
1980
- initialValue: true
1981
- });
1982
- if (isCancel(ready) || !ready) {
1983
- cancel("Onboarding paused. Run outlier again when you are ready.");
1984
- process.exit(0);
1985
- }
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");
1986
1911
  const configPath = join3(os.homedir(), ".outlier_config");
1987
1912
  writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
1988
1913
  }
@@ -2016,22 +1941,29 @@ COMMANDS:`));
2016
1941
  intro(import_picocolors.default.inverse(" outlier "));
2017
1942
  if (!action || action === "audit") {
2018
1943
  if (action !== "audit") {
2019
- action = await select({
2020
- message: "Select outlier governance module:",
2021
- options: [
2022
- { value: "status", label: "Status Report", hint: "Run full AI reliance and capability audit" },
2023
- { value: "capabilities", label: "Capabilities Map", hint: "Audit active MCPs, skills, and orchestrations" },
2024
- { value: "authorship", label: "Code Durability", hint: "Scan git history for AI Code Reliance & Hallucination Risk" },
2025
- { value: "carbon", label: "Cache Bloat", hint: "Scan local logs for context waste & token costs" },
2026
- { value: "policy", label: "Policy Profiles", hint: "Set Personal, Team, or Enterprise guardrails in CI" },
2027
- { value: "impact", label: "Impact Horizon", hint: "What do you lose and gain in the next 5-10 years?" },
2028
- { value: "knowledge", label: "Literature Base", hint: "Explore references and the core academic foundation" },
2029
- { value: "participate", label: "Participate", hint: "Contribute to the literature on AI deskilling" }
2030
- ]
2031
- });
2032
- if (isCancel(action)) {
2033
- cancel("Operation cancelled.");
2034
- process.exit(0);
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
+ }
2035
1967
  }
2036
1968
  } else {
2037
1969
  action = "status";
@@ -2202,7 +2134,7 @@ ${import_picocolors.default.bold("Governance:")} ${ruleFailures > 0 ? import_pic
2202
2134
  const dateStr = new Date().toLocaleDateString("en-US", { month: "short", day: "2-digit", year: "numeric" }).toUpperCase();
2203
2135
  const timeStr = new Date().toLocaleTimeString("en-US", { hour12: false });
2204
2136
  const repoName = process.cwd().split("/").pop() || "Unknown";
2205
- console.log(`
2137
+ finalReceipt = `
2206
2138
  ${import_picocolors.default.dim("┌────────────────────────────────────────────────────────")}
2207
2139
  ${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan("█▀█ █░█ ▀█▀ █░░ █ █▀▀ █▀█")} ${import_picocolors.default.bold(":: THERMAL AUDIT RECEIPT")}
2208
2140
  ${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan("█▄█ █▄█ ░█░ █▄▄ █ ██▄ █▀▄")} ${import_picocolors.default.dim(`:: TIMESTAMP: ${dateStr}`)}
@@ -2236,7 +2168,7 @@ ${import_picocolors.default.bold("Governance:")} ${ruleFailures > 0 ? import_pic
2236
2168
  ${import_picocolors.default.dim("│")} ${import_picocolors.default.italic(import_picocolors.default.dim("human mastery is the only true moat."))}
2237
2169
  ${import_picocolors.default.dim("│")}
2238
2170
  ${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.cyan("***STAY VIGILANT***"))}
2239
- ${import_picocolors.default.dim("└────────────────────────────────────────────────────────")}`);
2171
+ ${import_picocolors.default.dim("└────────────────────────────────────────────────────────")}`;
2240
2172
  } else {
2241
2173
  note(`status: ${authPct} AI Reliance | ${cachePct}% Cache Bloat | ${co2Str}`, `${import_picocolors.default.bold("[outlier]")} CI/CD Audit`);
2242
2174
  }
@@ -2429,6 +2361,9 @@ Read the full academic foundation at: ${import_picocolors.default.underline("htt
2429
2361
  `);
2430
2362
  }
2431
2363
  outro("Local telemetry run completed. No data left your machine.");
2364
+ if (typeof finalReceipt !== "undefined" && finalReceipt) {
2365
+ console.log(finalReceipt);
2366
+ }
2432
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?
2433
2368
 
2434
2369
  \uD83D\uDCCF #Outlier`)}`));
@@ -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')} Print your Thermal Audit Receipt`);
13
- console.log(` ${cyan('outlier impact')} See the compounding horizon of AI Deskilling (What you lose/gain)`);
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.10",
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
- import os from 'os';
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 only read your local \`~/.claude\` logs and \`.git/\` commit history.
45
- - Actionable Policies: We enforce rules locally via terminal or Git pre-commit hooks.`,
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
  }
@@ -108,23 +68,31 @@ async function main() {
108
68
 
109
69
  if (!action || action === 'audit') {
110
70
  if (action !== 'audit') {
111
- action = await select({
112
- message: 'Select outlier governance module:',
113
- options: [
114
- { value: 'status', label: 'Status Report', hint: 'Run full AI reliance and capability audit' },
115
- { value: 'capabilities', label: 'Capabilities Map', hint: 'Audit active MCPs, skills, and orchestrations' },
116
- { value: 'authorship', label: 'Code Durability', hint: 'Scan git history for AI Code Reliance & Hallucination Risk' },
117
- { value: 'carbon', label: 'Cache Bloat', hint: 'Scan local logs for context waste & token costs' },
118
- { value: 'policy', label: 'Policy Profiles', hint: 'Set Personal, Team, or Enterprise guardrails in CI' },
119
- { value: 'impact', label: 'Impact Horizon', hint: 'What do you lose and gain in the next 5-10 years?' },
120
- { value: 'knowledge', label: 'Literature Base', hint: 'Explore references and the core academic foundation' },
121
- { value: 'participate', label: 'Participate', hint: 'Contribute to the literature on AI deskilling' }
122
- ],
123
- });
124
-
125
- if (isCancel(action)) {
126
- cancel('Operation cancelled.');
127
- process.exit(0);
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
+ }
128
96
  }
129
97
  } else {
130
98
  action = 'status'; // Map the 'audit' alias directly to status for CI
@@ -323,7 +291,7 @@ ${pc.bold('Governance:')} ${ruleFailures > 0 ? pc.red(`${failIcon} ${ruleFailure
323
291
  const timeStr = new Date().toLocaleTimeString('en-US', { hour12: false });
324
292
  const repoName = process.cwd().split('/').pop() || 'Unknown';
325
293
 
326
- console.log(`
294
+ finalReceipt = `
327
295
  ${pc.dim('┌────────────────────────────────────────────────────────')}
328
296
  ${pc.dim('│')} ${pc.cyan('█▀█ █░█ ▀█▀ █░░ █ █▀▀ █▀█')} ${pc.bold(':: THERMAL AUDIT RECEIPT')}
329
297
  ${pc.dim('│')} ${pc.cyan('█▄█ █▄█ ░█░ █▄▄ █ ██▄ █▀▄')} ${pc.dim(`:: TIMESTAMP: ${dateStr}`)}
@@ -353,7 +321,7 @@ ${pc.bold('Governance:')} ${ruleFailures > 0 ? pc.red(`${failIcon} ${ruleFailure
353
321
  ${pc.dim('│')} ${pc.italic(pc.dim('human mastery is the only true moat.'))}
354
322
  ${pc.dim('│')}
355
323
  ${pc.dim('│')} ${pc.bold(pc.cyan('***STAY VIGILANT***'))}
356
- ${pc.dim('└────────────────────────────────────────────────────────')}`);
324
+ ${pc.dim('└────────────────────────────────────────────────────────')}`;
357
325
  } else {
358
326
  note(
359
327
  `status: ${authPct} AI Reliance | ${cachePct}% Cache Bloat | ${co2Str}`,
@@ -558,6 +526,10 @@ Artifact: ${pc.cyan(reportPath)}`,
558
526
 
559
527
  outro('Local telemetry run completed. No data left your machine.');
560
528
 
529
+ if (typeof finalReceipt !== 'undefined' && finalReceipt) {
530
+ console.log(finalReceipt);
531
+ }
532
+
561
533
  // (Old artifact storytelling block removed to unify receipt UX)
562
534
 
563
535
  console.log(