@rosh100yx/outlier 0.4.15 → 0.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +27 -29
  2. package/bin/outlier.js +117 -50
  3. package/package.json +11 -11
  4. package/src/cli.ts +20 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <div align="center">
2
- <img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/cover.jpg" alt="Outlier Cover" width="100%" />
3
- <h1>outlier</h1>
4
- <p><b>The Governance & Policy Engine for AI Engineering</b></p>
5
- <p><i>Measure AI adoption. Enforce Zero-Trust. Protect Human Mastery.</i></p>
2
+ <img src="https://raw.githubusercontent.com/rosh100yx/outlier/main/assets/cover.jpg" alt="Outlier: AI Code Governance and Policy Engine" width="100%" />
3
+ <h1>Outlier: The Governance & Policy Engine for AI Engineering</h1>
4
+ <p><b>Measure AI adoption. Enforce Zero-Trust. Protect Human Mastery.</b></p>
5
+ <p><i>Outlier is an open-source, local-first CLI tool that measures AI code reliance, enforces zero-trust telemetry, and protects developers from deskilling by auditing local agent logs (Claude, Cursor) and Git history.</i></p>
6
6
  <br/>
7
7
 
8
8
  <p>
@@ -13,8 +13,7 @@
13
13
 
14
14
  <p>
15
15
  <b>Get Started Instantly:</b><br/>
16
- <code>npm install -g @rosh100yx/outlier</code><br/>
17
- <code>outlier status</code>
16
+ <code>npx @rosh100yx/outlier@latest</code>
18
17
  </p>
19
18
 
20
19
  <br/>
@@ -68,27 +67,26 @@
68
67
  ## Commands
69
68
  | Command | Purpose |
70
69
  |---------|---------|
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 |
74
- | `outlier carbon` | Scan local logs for context waste & token costs |
75
- | `outlier capabilities` | Audit active MCPs, skills, and orchestrations |
76
- | `outlier policy` | Configure Personal, Team, or Enterprise guardrails in CI |
77
-
78
- ### Interactive Menu
79
- If you run `outlier` directly, you'll be greeted with our frictionless UX:
70
+ | `npx @rosh100yx/outlier` | Run the full AI reliance & capability audit |
71
+ | `npx @rosh100yx/outlier authorship` | Scan git history for AI co-authorship ratio |
72
+ | `npx @rosh100yx/outlier carbon` | Scan local logs for context waste & token costs |
73
+ | `npx @rosh100yx/outlier capabilities` | Audit active MCPs, skills, and orchestrations |
74
+ | `npx @rosh100yx/outlier policy` | Configure Personal, Team, or Enterprise guardrails in CI |
75
+
76
+ ### The UX Flow
77
+ If you run `npx @rosh100yx/outlier` directly, you'll instantly get your Thermal Receipt and a simple list of follow-up commands:
80
78
  ```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
79
+ └────────────────────────────────────────────────────────┘
80
+
81
+ Explore Outlier:
82
+ ────────────────────────────────────────────────────────────
83
+ outlier policy Configure CI/CD guardrails and thresholds
84
+ outlier capabilities Audit active MCPs, skills, and orchestrations
85
+ outlier impact See the compounding horizon of AI Deskilling
86
+ outlier participate Help build the academic literature
87
+ ────────────────────────────────────────────────────────────
88
+
89
+ Prove Your Mastery: https://x.com/intent/tweet?...
92
90
  ```
93
91
 
94
92
  ## Quickstart: Your First Audit
@@ -106,13 +104,13 @@ If you run `outlier` directly, you'll be greeted with our frictionless UX:
106
104
  ```bash
107
105
  git commit -am "added massive ai feature"
108
106
  ```
109
- *Watch the Bouncer block your commit for deskilling risk.*
107
+ *Watch the Bouncer physically block your commit for deskilling risk.*
110
108
 
111
109
  3. **Measure the Damage**
112
110
  ```bash
113
- npx @rosh100yx/outlier audit
111
+ npx @rosh100yx/outlier
114
112
  ```
115
- *See your exact AI Authorship ratio and Token Waste.*
113
+ *Instantly generate your Thermal Receipt to see your exact AI Authorship ratio and Token Waste.*
116
114
 
117
115
  ## Theoretical Foundations
118
116
  `outlier` is the live, technical implementation of an academic thesis on the thermodynamics of AI code generation and digital sovereignty.
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.15",
168
+ version: "0.4.18",
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"
@@ -180,7 +180,8 @@ var require_package = __commonJS((exports, module) => {
180
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
- postinstall: "node bin/postinstall.js"
183
+ postinstall: "node bin/postinstall.js",
184
+ prepublishOnly: "npm run build"
184
185
  },
185
186
  type: "module",
186
187
  private: false,
@@ -191,17 +192,16 @@ var require_package = __commonJS((exports, module) => {
191
192
  url: "https://github.com/rosh100yx/outlier.git"
192
193
  },
193
194
  keywords: [
194
- "ai",
195
- "governance",
196
- "carbon",
197
- "compliance",
195
+ "ai-governance",
198
196
  "ai-safety",
199
- "policy-engine",
200
- "zero-trust",
201
- "carbon-footprint",
202
- "global-south",
203
- "observability",
197
+ "deskilling",
198
+ "claude-code",
199
+ "cursor",
200
+ "git-hook",
201
+ "pre-commit",
204
202
  "telemetry",
203
+ "carbon-footprint",
204
+ "zero-trust",
205
205
  "authorship",
206
206
  "cli"
207
207
  ],
@@ -943,16 +943,34 @@ var T$1 = class T extends V {
943
943
  }
944
944
  }
945
945
  };
946
+
947
+ class r extends V {
948
+ get cursor() {
949
+ return this.value ? 0 : 1;
950
+ }
951
+ get _value() {
952
+ return this.cursor === 0;
953
+ }
954
+ constructor(t2) {
955
+ super(t2, false), this.value = !!t2.initialValue, this.on("userInput", () => {
956
+ this.value = this._value;
957
+ }), this.on("confirm", (i) => {
958
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i, this.state = "submit", this.close();
959
+ }), this.on("cursor", () => {
960
+ this.value = !this.value;
961
+ });
962
+ }
963
+ }
946
964
  var _ = {
947
965
  Y: { type: "year", len: 4 },
948
966
  M: { type: "month", len: 2 },
949
967
  D: { type: "day", len: 2 }
950
968
  };
951
- function M(r) {
952
- return [...r].map((t2) => _[t2]);
969
+ function M(r2) {
970
+ return [...r2].map((t2) => _[t2]);
953
971
  }
954
- function P(r) {
955
- const i = new Intl.DateTimeFormat(r, {
972
+ function P(r2) {
973
+ const i = new Intl.DateTimeFormat(r2, {
956
974
  year: "numeric",
957
975
  month: "2-digit",
958
976
  day: "2-digit"
@@ -962,32 +980,32 @@ function P(r) {
962
980
  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 });
963
981
  return { segments: s, separator: n };
964
982
  }
965
- function p(r) {
966
- return Number.parseInt((r || "0").replace(/_/g, "0"), 10) || 0;
983
+ function p(r2) {
984
+ return Number.parseInt((r2 || "0").replace(/_/g, "0"), 10) || 0;
967
985
  }
968
- function f(r) {
986
+ function f(r2) {
969
987
  return {
970
- year: p(r.year),
971
- month: p(r.month),
972
- day: p(r.day)
988
+ year: p(r2.year),
989
+ month: p(r2.month),
990
+ day: p(r2.day)
973
991
  };
974
992
  }
975
- function c(r, t2) {
976
- return new Date(r || 2001, t2 || 1, 0).getDate();
993
+ function c(r2, t2) {
994
+ return new Date(r2 || 2001, t2 || 1, 0).getDate();
977
995
  }
978
- function b(r) {
979
- const { year: t2, month: i, day: s } = f(r);
996
+ function b(r2) {
997
+ const { year: t2, month: i, day: s } = f(r2);
980
998
  if (!t2 || t2 < 0 || t2 > 9999 || !i || i < 1 || i > 12 || !s || s < 1)
981
999
  return;
982
1000
  const n = new Date(Date.UTC(t2, i - 1, s));
983
1001
  if (!(n.getUTCFullYear() !== t2 || n.getUTCMonth() !== i - 1 || n.getUTCDate() !== s))
984
1002
  return { year: t2, month: i, day: s };
985
1003
  }
986
- function C(r) {
987
- const t2 = b(r);
1004
+ function C(r2) {
1005
+ const t2 = b(r2);
988
1006
  return t2 ? new Date(Date.UTC(t2.year, t2.month - 1, t2.day)) : undefined;
989
1007
  }
990
- function T2(r, t2, i, s) {
1008
+ function T2(r2, t2, i, s) {
991
1009
  const n = i ? {
992
1010
  year: i.getUTCFullYear(),
993
1011
  month: i.getUTCMonth() + 1,
@@ -997,7 +1015,7 @@ function T2(r, t2, i, s) {
997
1015
  month: s.getUTCMonth() + 1,
998
1016
  day: s.getUTCDate()
999
1017
  } : null;
1000
- return r === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r === "month" ? {
1018
+ return r2 === "year" ? { min: n?.year ?? 1, max: e?.year ?? 9999 } : r2 === "month" ? {
1001
1019
  min: n && t2.year === n.year ? n.month : 1,
1002
1020
  max: e && t2.year === e.year ? e.month : 12
1003
1021
  } : {
@@ -1170,26 +1188,26 @@ var u$1 = class u extends V {
1170
1188
  cursor = 0;
1171
1189
  #t;
1172
1190
  getGroupItems(t2) {
1173
- return this.options.filter((r) => r.group === t2);
1191
+ return this.options.filter((r2) => r2.group === t2);
1174
1192
  }
1175
1193
  isGroupSelected(t2) {
1176
- const r = this.getGroupItems(t2), e = this.value;
1177
- return e === undefined ? false : r.every((s) => e.includes(s.value));
1194
+ const r2 = this.getGroupItems(t2), e = this.value;
1195
+ return e === undefined ? false : r2.every((s) => e.includes(s.value));
1178
1196
  }
1179
1197
  toggleValue() {
1180
1198
  const t2 = this.options[this.cursor];
1181
1199
  if (this.value === undefined && (this.value = []), t2.group === true) {
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));
1200
+ const r2 = t2.value, e = this.getGroupItems(r2);
1201
+ 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));
1184
1202
  } else {
1185
- const r = this.value.includes(t2.value);
1186
- this.value = r ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
1203
+ const r2 = this.value.includes(t2.value);
1204
+ this.value = r2 ? this.value.filter((e) => e !== t2.value) : [...this.value, t2.value];
1187
1205
  }
1188
1206
  }
1189
1207
  constructor(t2) {
1190
1208
  super(t2, false);
1191
- const { options: r } = t2;
1192
- this.#t = t2.selectableGroups !== false, this.options = Object.entries(r).flatMap(([e, s]) => [
1209
+ const { options: r2 } = t2;
1210
+ this.#t = t2.selectableGroups !== false, this.options = Object.entries(r2).flatMap(([e, s]) => [
1193
1211
  { value: e, group: true, label: e },
1194
1212
  ...s.map((i) => ({ ...i, group: e }))
1195
1213
  ]), this.value = [...t2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: e }) => e === t2.cursorAt), this.#t ? 0 : 1), this.on("cursor", (e) => {
@@ -1227,10 +1245,10 @@ class h extends V {
1227
1245
  const t2 = this.userInput;
1228
1246
  if (this.cursor >= t2.length)
1229
1247
  return `${t2}█`;
1230
- const s = t2.slice(0, this.cursor), r = t2[this.cursor], i = t2.slice(this.cursor + 1);
1231
- return r === `
1248
+ const s = t2.slice(0, this.cursor), r2 = t2[this.cursor], i = t2.slice(this.cursor + 1);
1249
+ return r2 === `
1232
1250
  ` ? `${s}█
1233
- ${i}` : `${s}${styleText("inverse", r)}${i}`;
1251
+ ${i}` : `${s}${styleText("inverse", r2)}${i}`;
1234
1252
  }
1235
1253
  get cursor() {
1236
1254
  return this._cursor;
@@ -1263,8 +1281,8 @@ ${i}` : `${s}${styleText("inverse", r)}${i}`;
1263
1281
  if (this.#s)
1264
1282
  return this.focused === "submit" ? true : (this.#r(`
1265
1283
  `), this._cursor++, false);
1266
- const r = this.#t;
1267
- return this.#t = true, r && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
1284
+ const r2 = this.#t;
1285
+ return this.#t = true, r2 && this.cursor === this.userInput.length ? (this.userInput[this.cursor - 1] === `
1268
1286
  ` && (this._setUserInput(this.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)), this._cursor--), true) : (this.#r(`
1269
1287
  `), this._cursor++, false);
1270
1288
  }
@@ -1273,12 +1291,12 @@ ${i}` : `${s}${styleText("inverse", r)}${i}`;
1273
1291
  super({
1274
1292
  ...t2,
1275
1293
  initialUserInput: s
1276
- }, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r, i) => {
1294
+ }, false), s !== undefined && (this._cursor = s.length), this.#s = t2.showSubmit ?? false, this.on("key", (r2, i) => {
1277
1295
  if (i?.name && o$1.has(i.name)) {
1278
1296
  this.#t = false, this.#i(i.name);
1279
1297
  return;
1280
1298
  }
1281
- if (r === "\t" && this.#s) {
1299
+ if (r2 === "\t" && this.#s) {
1282
1300
  this.focused = this.focused === "editor" ? "submit" : "editor";
1283
1301
  return;
1284
1302
  }
@@ -1291,10 +1309,10 @@ ${i}` : `${s}${styleText("inverse", r)}${i}`;
1291
1309
  this._setUserInput(this.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1));
1292
1310
  return;
1293
1311
  }
1294
- r && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r ?? ""), this._cursor++);
1312
+ r2 && (this.#s && this.focused === "submit" && (this.focused = "editor"), this.#r(r2 ?? ""), this._cursor++);
1295
1313
  }
1296
- }), this.on("userInput", (r) => {
1297
- this._setValue(r);
1314
+ }), this.on("userInput", (r2) => {
1315
+ this._setValue(r2);
1298
1316
  }), this.on("finalize", () => {
1299
1317
  this.value || (this.value = t2.defaultValue), this.value === undefined && (this.value = "");
1300
1318
  });
@@ -1334,8 +1352,8 @@ class n extends V {
1334
1352
  const t2 = this.userInput;
1335
1353
  if (this.cursor >= t2.length)
1336
1354
  return `${this.userInput}█`;
1337
- const e = t2.slice(0, this.cursor), [s, ...r] = t2.slice(this.cursor);
1338
- return `${e}${styleText("inverse", s)}${r.join("")}`;
1355
+ const e = t2.slice(0, this.cursor), [s, ...r2] = t2.slice(this.cursor);
1356
+ return `${e}${styleText("inverse", s)}${r2.join("")}`;
1339
1357
  }
1340
1358
  get cursor() {
1341
1359
  return this._cursor;
@@ -1469,6 +1487,41 @@ var limitOptions = ({
1469
1487
  b2.push(n2);
1470
1488
  return u3 && b2.push(C2), b2;
1471
1489
  };
1490
+ var confirm = (i) => {
1491
+ const a2 = i.active ?? "Yes", s = i.inactive ?? "No";
1492
+ return new r({
1493
+ active: a2,
1494
+ inactive: s,
1495
+ signal: i.signal,
1496
+ input: i.input,
1497
+ output: i.output,
1498
+ initialValue: i.initialValue ?? true,
1499
+ render() {
1500
+ 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)}
1501
+ ` : ""}${f2}
1502
+ `, c2 = this.value ? a2 : s;
1503
+ switch (this.state) {
1504
+ case "submit": {
1505
+ const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
1506
+ return `${o2}${r2}${styleText2("dim", c2)}`;
1507
+ }
1508
+ case "cancel": {
1509
+ const r2 = e ? `${styleText2("gray", S_BAR)} ` : "";
1510
+ return `${o2}${r2}${styleText2(["strikethrough", "dim"], c2)}${e ? `
1511
+ ${styleText2("gray", S_BAR)}` : ""}`;
1512
+ }
1513
+ default: {
1514
+ const r2 = e ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e ? styleText2("cyan", S_BAR_END) : "";
1515
+ return `${o2}${r2}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a2}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a2)}`}${i.vertical ? e ? `
1516
+ ${styleText2("cyan", S_BAR)} ` : `
1517
+ ` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s}`}
1518
+ ${g2}
1519
+ `;
1520
+ }
1521
+ }
1522
+ }
1523
+ }).prompt();
1524
+ };
1472
1525
  var MULTISELECT_INSTRUCTIONS = [
1473
1526
  `${styleText2("dim", "↑/↓")} to navigate`,
1474
1527
  `${styleText2("dim", "Space:")} select`,
@@ -1904,10 +1957,24 @@ async function runOnboarding() {
1904
1957
  console.clear();
1905
1958
  console.log(import_picocolors.default.cyan(ASCII_LOGO));
1906
1959
  intro(import_picocolors.default.inverse(" outlier: Welcome "));
1960
+ note(`Outlier is a local-first Policy Engine & Governance Framework for AI Engineering.
1961
+
1962
+ As agents write more of our code, we lose visibility into:
1963
+ 1. Deskilling Risk (Are we becoming spectators in our own codebase?)
1964
+ 2. Carbon Cost (What is the true regional energy cost of token caching?)
1965
+ 3. Capability Drift (What hidden skills are our agents using?)`, "The Problem: AI Safety in Development");
1907
1966
  note(`Outlier operates entirely on your machine.
1908
1967
  - Local Only: No API keys. No cloud telemetry. No data leaves your machine.
1909
1968
  - Native Auditing: We read your local \`~/.claude\` logs and \`.git/\` commit history.
1910
1969
  - Actionable Policies: Enforce rules locally via terminal or Git hooks.`, "Privacy & Zero-Trust Principles");
1970
+ const ready = await confirm({
1971
+ message: "Are you ready to run your first Governance Audit and generate your Thermal Receipt?",
1972
+ initialValue: true
1973
+ });
1974
+ if (isCancel(ready) || !ready) {
1975
+ cancel("Onboarding paused. Run outlier again when you are ready.");
1976
+ process.exit(0);
1977
+ }
1911
1978
  const configPath = join3(os.homedir(), ".outlier_config");
1912
1979
  writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
1913
1980
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rosh100yx/outlier",
3
- "version": "0.4.15",
3
+ "version": "0.4.18",
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"
@@ -15,7 +15,8 @@
15
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
- "postinstall": "node bin/postinstall.js"
18
+ "postinstall": "node bin/postinstall.js",
19
+ "prepublishOnly": "npm run build"
19
20
  },
20
21
  "type": "module",
21
22
  "private": false,
@@ -26,17 +27,16 @@
26
27
  "url": "https://github.com/rosh100yx/outlier.git"
27
28
  },
28
29
  "keywords": [
29
- "ai",
30
- "governance",
31
- "carbon",
32
- "compliance",
30
+ "ai-governance",
33
31
  "ai-safety",
34
- "policy-engine",
35
- "zero-trust",
36
- "carbon-footprint",
37
- "global-south",
38
- "observability",
32
+ "deskilling",
33
+ "claude-code",
34
+ "cursor",
35
+ "git-hook",
36
+ "pre-commit",
39
37
  "telemetry",
38
+ "carbon-footprint",
39
+ "zero-trust",
40
40
  "authorship",
41
41
  "cli"
42
42
  ],
package/src/cli.ts CHANGED
@@ -24,6 +24,16 @@ async function runOnboarding() {
24
24
  console.log(pc.cyan(ASCII_LOGO));
25
25
  intro(pc.inverse(' outlier: Welcome '));
26
26
 
27
+ note(
28
+ `Outlier is a local-first Policy Engine & Governance Framework for AI Engineering.
29
+
30
+ As agents write more of our code, we lose visibility into:
31
+ 1. Deskilling Risk (Are we becoming spectators in our own codebase?)
32
+ 2. Carbon Cost (What is the true regional energy cost of token caching?)
33
+ 3. Capability Drift (What hidden skills are our agents using?)`,
34
+ 'The Problem: AI Safety in Development'
35
+ );
36
+
27
37
  note(
28
38
  `Outlier operates entirely on your machine.
29
39
  - Local Only: No API keys. No cloud telemetry. No data leaves your machine.
@@ -32,6 +42,16 @@ async function runOnboarding() {
32
42
  'Privacy & Zero-Trust Principles'
33
43
  );
34
44
 
45
+ const ready = await confirm({
46
+ message: 'Are you ready to run your first Governance Audit and generate your Thermal Receipt?',
47
+ initialValue: true,
48
+ });
49
+
50
+ if (isCancel(ready) || !ready) {
51
+ cancel('Onboarding paused. Run outlier again when you are ready.');
52
+ process.exit(0);
53
+ }
54
+
35
55
  const configPath = join(os.homedir(), '.outlier_config');
36
56
  writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
37
57
  }