@rosh100yx/outlier 0.4.19 → 0.4.22
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/bin/outlier.js +165 -25
- package/package.json +1 -1
- package/src/agent.ts +43 -0
- package/src/cli.ts +108 -13
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.
|
|
168
|
+
version: "0.4.22",
|
|
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"
|
|
@@ -219,7 +219,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
219
219
|
});
|
|
220
220
|
|
|
221
221
|
// src/cli.ts
|
|
222
|
-
import
|
|
222
|
+
import os2 from "os";
|
|
223
223
|
|
|
224
224
|
// node_modules/@clack/core/dist/index.mjs
|
|
225
225
|
import { styleText } from "node:util";
|
|
@@ -1942,8 +1942,49 @@ async function getCapabilitiesStats(repoPath = process.cwd(), homeDirPath = home
|
|
|
1942
1942
|
}
|
|
1943
1943
|
|
|
1944
1944
|
// src/cli.ts
|
|
1945
|
-
import { writeFileSync, chmodSync, existsSync as
|
|
1945
|
+
import { writeFileSync, readFileSync as readFileSync2, chmodSync, existsSync as existsSync3 } from "fs";
|
|
1946
|
+
import { join as join4 } from "path";
|
|
1947
|
+
|
|
1948
|
+
// src/agent.ts
|
|
1949
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
1950
|
+
import { readFileSync, existsSync as existsSync2 } from "fs";
|
|
1946
1951
|
import { join as join3 } from "path";
|
|
1952
|
+
import os from "os";
|
|
1953
|
+
function detectAgent() {
|
|
1954
|
+
const agents = ["claude", "cursor", "aider", "hermes", "cody", "continue", "opencode", "gemini"];
|
|
1955
|
+
try {
|
|
1956
|
+
const home = os.homedir();
|
|
1957
|
+
const historyFiles = [join3(home, ".zsh_history"), join3(home, ".bash_history")];
|
|
1958
|
+
for (const file of historyFiles) {
|
|
1959
|
+
if (existsSync2(file)) {
|
|
1960
|
+
const content = readFileSync(file, "utf8");
|
|
1961
|
+
const lines = content.split(`
|
|
1962
|
+
`).filter(Boolean).slice(-500).reverse();
|
|
1963
|
+
for (const line of lines) {
|
|
1964
|
+
for (const agent of agents) {
|
|
1965
|
+
if (line.includes(agent)) {
|
|
1966
|
+
const result = spawnSync2("which", [agent]);
|
|
1967
|
+
if (result.status === 0) {
|
|
1968
|
+
return agent;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
} catch (e) {}
|
|
1976
|
+
for (const agent of agents) {
|
|
1977
|
+
try {
|
|
1978
|
+
const result = spawnSync2("which", [agent]);
|
|
1979
|
+
if (result.status === 0) {
|
|
1980
|
+
return agent;
|
|
1981
|
+
}
|
|
1982
|
+
} catch (e) {}
|
|
1983
|
+
}
|
|
1984
|
+
return null;
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
// src/cli.ts
|
|
1947
1988
|
var ASCII_LOGO = `
|
|
1948
1989
|
____ _ _ _____ _ ___ _____ ____
|
|
1949
1990
|
/ __ \\| | | |_ _| | |_ _| ___| _ \\
|
|
@@ -1975,16 +2016,35 @@ As agents write more of our code, we lose visibility into:
|
|
|
1975
2016
|
cancel("Onboarding paused. Run outlier again when you are ready.");
|
|
1976
2017
|
process.exit(0);
|
|
1977
2018
|
}
|
|
1978
|
-
const configPath =
|
|
2019
|
+
const configPath = join4(os2.homedir(), ".outlier_config");
|
|
1979
2020
|
writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
|
|
1980
2021
|
}
|
|
1981
2022
|
async function main() {
|
|
2023
|
+
let action = process.argv[2];
|
|
2024
|
+
if (action === "daily-greeting") {
|
|
2025
|
+
const configPath2 = join4(os2.homedir(), ".outlier_config");
|
|
2026
|
+
const today = new Date().toISOString().split("T")[0];
|
|
2027
|
+
let alreadyRun = false;
|
|
2028
|
+
if (existsSync3(configPath2)) {
|
|
2029
|
+
try {
|
|
2030
|
+
const cfg = JSON.parse(readFileSync2(configPath2, "utf8"));
|
|
2031
|
+
if (cfg.lastGreetingDate === today) {
|
|
2032
|
+
alreadyRun = true;
|
|
2033
|
+
} else {
|
|
2034
|
+
cfg.lastGreetingDate = today;
|
|
2035
|
+
writeFileSync(configPath2, JSON.stringify(cfg));
|
|
2036
|
+
}
|
|
2037
|
+
} catch (e) {}
|
|
2038
|
+
}
|
|
2039
|
+
if (alreadyRun)
|
|
2040
|
+
process.exit(0);
|
|
2041
|
+
action = "status";
|
|
2042
|
+
}
|
|
1982
2043
|
console.clear();
|
|
1983
2044
|
console.log(import_picocolors.default.cyan(ASCII_LOGO));
|
|
1984
2045
|
const pkg = require_package();
|
|
1985
2046
|
console.log(import_picocolors.default.dim(` Outlier v${pkg.version} · AI Code Reliance & Telemetry Engine
|
|
1986
2047
|
`));
|
|
1987
|
-
let action = process.argv[2];
|
|
1988
2048
|
if (action === "--help" || action === "-h" || action === "help") {
|
|
1989
2049
|
console.log(import_picocolors.default.bold(`
|
|
1990
2050
|
COMMANDS:`));
|
|
@@ -1996,12 +2056,14 @@ COMMANDS:`));
|
|
|
1996
2056
|
console.log(` ${import_picocolors.default.cyan("outlier impact")} See the compounding horizon of AI Deskilling`);
|
|
1997
2057
|
console.log(` ${import_picocolors.default.cyan("outlier knowledge")} Explore references, graphs, and the core literature`);
|
|
1998
2058
|
console.log(` ${import_picocolors.default.cyan("outlier participate")} Help build the academic literature on AI deskilling`);
|
|
2059
|
+
console.log(` ${import_picocolors.default.cyan("outlier init")} Install the once-per-day shell greeting`);
|
|
2060
|
+
console.log(` ${import_picocolors.default.cyan("outlier uninit")} Remove the shell greeting`);
|
|
1999
2061
|
console.log(`
|
|
2000
2062
|
` + import_picocolors.default.dim("Run without arguments to start the interactive wizard."));
|
|
2001
2063
|
process.exit(0);
|
|
2002
2064
|
}
|
|
2003
|
-
const configPath =
|
|
2004
|
-
if (!
|
|
2065
|
+
const configPath = join4(os2.homedir(), ".outlier_config");
|
|
2066
|
+
if (!existsSync3(configPath) && !action) {
|
|
2005
2067
|
await runOnboarding();
|
|
2006
2068
|
action = "status";
|
|
2007
2069
|
}
|
|
@@ -2009,6 +2071,54 @@ COMMANDS:`));
|
|
|
2009
2071
|
if (!action || action === "audit") {
|
|
2010
2072
|
action = "status";
|
|
2011
2073
|
}
|
|
2074
|
+
if (action === "init" || action === "uninit") {
|
|
2075
|
+
const shell = process.env.SHELL || "";
|
|
2076
|
+
const rcName = shell.includes("zsh") ? ".zshrc" : ".bashrc";
|
|
2077
|
+
const rcPath = join4(os2.homedir(), rcName);
|
|
2078
|
+
const START_MARKER = "# --- OUTLIER PRE-FLIGHT RITUAL START ---";
|
|
2079
|
+
const END_MARKER = "# --- OUTLIER PRE-FLIGHT RITUAL END ---";
|
|
2080
|
+
const BLOCK = `
|
|
2081
|
+
${START_MARKER}
|
|
2082
|
+
if command -v outlier >/dev/null 2>&1; then
|
|
2083
|
+
outlier daily-greeting
|
|
2084
|
+
fi
|
|
2085
|
+
${END_MARKER}
|
|
2086
|
+
`;
|
|
2087
|
+
if (action === "init") {
|
|
2088
|
+
const confirmWrite = await confirm({
|
|
2089
|
+
message: `Add a once-per-day Outlier greeting to your ${rcName}? (You can remove it with 'outlier uninit')`,
|
|
2090
|
+
initialValue: true
|
|
2091
|
+
});
|
|
2092
|
+
if (isCancel(confirmWrite) || !confirmWrite) {
|
|
2093
|
+
cancel("Aborted.");
|
|
2094
|
+
process.exit(0);
|
|
2095
|
+
}
|
|
2096
|
+
let content = "";
|
|
2097
|
+
if (existsSync3(rcPath))
|
|
2098
|
+
content = readFileSync2(rcPath, "utf8");
|
|
2099
|
+
if (content.includes(START_MARKER)) {
|
|
2100
|
+
note(`Outlier is already initialized in ${rcName}`);
|
|
2101
|
+
} else {
|
|
2102
|
+
writeFileSync(rcPath, content + BLOCK);
|
|
2103
|
+
note(`Successfully added to ${rcName}. Open a new terminal to see the pre-flight ritual!`);
|
|
2104
|
+
}
|
|
2105
|
+
process.exit(0);
|
|
2106
|
+
} else if (action === "uninit") {
|
|
2107
|
+
if (existsSync3(rcPath)) {
|
|
2108
|
+
let content = readFileSync2(rcPath, "utf8");
|
|
2109
|
+
if (content.includes(START_MARKER)) {
|
|
2110
|
+
const regex = new RegExp(`\\n?${START_MARKER}[\\s\\S]*?${END_MARKER}\\n?`, "g");
|
|
2111
|
+
content = content.replace(regex, `
|
|
2112
|
+
`);
|
|
2113
|
+
writeFileSync(rcPath, content);
|
|
2114
|
+
note(`Removed Outlier block from ${rcName}`);
|
|
2115
|
+
} else {
|
|
2116
|
+
note(`No Outlier block found in ${rcName}`);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
process.exit(0);
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2012
2122
|
const s = spinner();
|
|
2013
2123
|
if (action === "carbon") {
|
|
2014
2124
|
s.start("Scanning local agent session logs...");
|
|
@@ -2063,28 +2173,53 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2063
2173
|
let gitStats = null;
|
|
2064
2174
|
let carbon = null;
|
|
2065
2175
|
let capabilities = null;
|
|
2176
|
+
let skipDelay = false;
|
|
2177
|
+
const configPath2 = join4(os2.homedir(), ".outlier_config");
|
|
2178
|
+
if (existsSync3(configPath2)) {
|
|
2179
|
+
try {
|
|
2180
|
+
const cfg = JSON.parse(readFileSync2(configPath2, "utf8"));
|
|
2181
|
+
if (cfg.seenNarration)
|
|
2182
|
+
skipDelay = true;
|
|
2183
|
+
} catch (e) {}
|
|
2184
|
+
}
|
|
2066
2185
|
if (!isStrict) {
|
|
2067
2186
|
s.start("[SYSTEM] Booting local-first sandbox...");
|
|
2068
|
-
|
|
2187
|
+
if (!skipDelay)
|
|
2188
|
+
await new Promise((r2) => setTimeout(r2, 800));
|
|
2069
2189
|
s.message(`↳ Guarantee: No API calls. Your code and logs never leave this machine.`);
|
|
2070
|
-
|
|
2190
|
+
if (!skipDelay)
|
|
2191
|
+
await new Promise((r2) => setTimeout(r2, 1200));
|
|
2071
2192
|
s.message("[GIT] Scanning your commit history...");
|
|
2072
2193
|
gitStats = await getAuthorshipStats().catch(() => null);
|
|
2073
|
-
|
|
2194
|
+
if (!skipDelay)
|
|
2195
|
+
await new Promise((r2) => setTimeout(r2, 600));
|
|
2074
2196
|
s.message(`↳ Check: Are you writing the code, or just reviewing what the AI wrote?`);
|
|
2075
|
-
|
|
2197
|
+
if (!skipDelay)
|
|
2198
|
+
await new Promise((r2) => setTimeout(r2, 1200));
|
|
2076
2199
|
s.message("[TOKENS] Parsing local AI logs (~/.claude/)...");
|
|
2077
2200
|
carbon = await getCarbonStats().catch(() => null);
|
|
2078
|
-
|
|
2201
|
+
if (!skipDelay)
|
|
2202
|
+
await new Promise((r2) => setTimeout(r2, 600));
|
|
2079
2203
|
s.message(`↳ Check: How much API waste is your workflow generating locally?`);
|
|
2080
|
-
|
|
2204
|
+
if (!skipDelay)
|
|
2205
|
+
await new Promise((r2) => setTimeout(r2, 1200));
|
|
2081
2206
|
s.message("[ANALYSIS] Calculating your mastery score...");
|
|
2082
2207
|
capabilities = await getCapabilitiesStats().catch(() => null);
|
|
2083
|
-
|
|
2208
|
+
if (!skipDelay)
|
|
2209
|
+
await new Promise((r2) => setTimeout(r2, 600));
|
|
2084
2210
|
s.message(`↳ Warning: Heavy AI use creates the 'Illusion of Competence'. Don't lose your edge.`);
|
|
2085
|
-
|
|
2211
|
+
if (!skipDelay)
|
|
2212
|
+
await new Promise((r2) => setTimeout(r2, 1200));
|
|
2086
2213
|
s.message("[PRINT] Generating Thermal Receipt...");
|
|
2087
|
-
|
|
2214
|
+
if (!skipDelay)
|
|
2215
|
+
await new Promise((r2) => setTimeout(r2, 600));
|
|
2216
|
+
if (!skipDelay) {
|
|
2217
|
+
try {
|
|
2218
|
+
const cfg = existsSync3(configPath2) ? JSON.parse(readFileSync2(configPath2, "utf8")) : {};
|
|
2219
|
+
cfg.seenNarration = true;
|
|
2220
|
+
writeFileSync(configPath2, JSON.stringify(cfg));
|
|
2221
|
+
} catch (e) {}
|
|
2222
|
+
}
|
|
2088
2223
|
} else {
|
|
2089
2224
|
s.start("Running outlier telemetry audit...");
|
|
2090
2225
|
gitStats = await getAuthorshipStats().catch(() => null);
|
|
@@ -2267,8 +2402,8 @@ ${caps.skills.length > 5 ? import_picocolors.default.red("⚠ High Surface Area:
|
|
|
2267
2402
|
process.exit(0);
|
|
2268
2403
|
}
|
|
2269
2404
|
s.start(`Applying ${tier} policy guardrails...`);
|
|
2270
|
-
const gitDir =
|
|
2271
|
-
const isRepo =
|
|
2405
|
+
const gitDir = join4(process.cwd(), ".git");
|
|
2406
|
+
const isRepo = existsSync3(gitDir);
|
|
2272
2407
|
if (!isRepo) {
|
|
2273
2408
|
console.error(import_picocolors.default.red("Must be run inside a git repository"));
|
|
2274
2409
|
process.exit(1);
|
|
@@ -2276,8 +2411,8 @@ ${caps.skills.length > 5 ? import_picocolors.default.red("⚠ High Surface Area:
|
|
|
2276
2411
|
const isStrict = process.argv.includes("--strict");
|
|
2277
2412
|
const bouncerMsg = isStrict ? `echo "⚠️ outlier policy warning: AI authorship ($CURRENT_RATIO%) exceeds threshold ($MAX_RATIO%)"` : `echo "\uD83D\uDEE1️ Outlier Bouncer: Repository AI-generation ($CURRENT_RATIO%) exceeds your defined mastery threshold ($MAX_RATIO%)."
|
|
2278
2413
|
echo "Take a moment to review your recent architectural decisions. Ensure you still understand the system."`;
|
|
2279
|
-
const hookPath =
|
|
2280
|
-
if (
|
|
2414
|
+
const hookPath = join4(gitDir, "hooks", "pre-commit");
|
|
2415
|
+
if (existsSync3(hookPath)) {
|
|
2281
2416
|
const { copyFileSync } = __require("fs");
|
|
2282
2417
|
copyFileSync(hookPath, `${hookPath}.backup`);
|
|
2283
2418
|
}
|
|
@@ -2310,7 +2445,7 @@ Enforcement: ${import_picocolors.default.cyan("Local pre-commit hook installed
|
|
|
2310
2445
|
} else if (tier === "regulatory") {
|
|
2311
2446
|
s.start("Generating Regulatory Compliance Audit (Decree 142)...");
|
|
2312
2447
|
await new Promise((resolve) => setTimeout(resolve, 1200));
|
|
2313
|
-
const reportPath =
|
|
2448
|
+
const reportPath = join4(process.cwd(), "outlier-audit-report.jsonl");
|
|
2314
2449
|
writeFileSync(reportPath, JSON.stringify({ timestamp: new Date().toISOString(), status: "PREVIEW", policy: "Decree 142", simulatedOversight: true }) + `
|
|
2315
2450
|
`);
|
|
2316
2451
|
s.stop("Audit Generated");
|
|
@@ -2405,11 +2540,16 @@ Read the full academic foundation at: ${import_picocolors.default.underline("htt
|
|
|
2405
2540
|
console.log(finalReceipt);
|
|
2406
2541
|
}
|
|
2407
2542
|
if (action === "status") {
|
|
2543
|
+
const agent = detectAgent();
|
|
2408
2544
|
console.log("");
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2545
|
+
if (agent) {
|
|
2546
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.magenta(" ↳ Ready to code? ")) + "Start your session: " + import_picocolors.default.bold(agent));
|
|
2547
|
+
} else {
|
|
2548
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.magenta(" ↳ Ready to code? ")) + "Start your AI agent");
|
|
2549
|
+
}
|
|
2550
|
+
console.log("");
|
|
2551
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.cyan(" └ Research: ")) + "Contribute to the AI deskilling study ➔ " + import_picocolors.default.bold("outlier participate"));
|
|
2552
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.green(" └ Share: ")) + import_picocolors.default.underline("https://x.com/intent/tweet?text=I+just+audited+my+codebase+with+%23Outlier"));
|
|
2413
2553
|
console.log(import_picocolors.default.dim(`
|
|
2414
2554
|
(To see all local governance modules, run: `) + import_picocolors.default.dim(import_picocolors.default.bold("outlier --help")) + import_picocolors.default.dim(")"));
|
|
2415
2555
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rosh100yx/outlier",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
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"
|
package/src/agent.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { readFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
export function detectAgent(): string | null {
|
|
7
|
+
const agents = ['claude', 'cursor', 'aider', 'hermes', 'cody', 'continue', 'opencode', 'gemini'];
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const home = os.homedir();
|
|
11
|
+
const historyFiles = [join(home, '.zsh_history'), join(home, '.bash_history')];
|
|
12
|
+
|
|
13
|
+
for (const file of historyFiles) {
|
|
14
|
+
if (existsSync(file)) {
|
|
15
|
+
// Read file using robust encoding fallback if needed, but utf8 usually works for matching
|
|
16
|
+
const content = readFileSync(file, 'utf8');
|
|
17
|
+
const lines = content.split('\n').filter(Boolean).slice(-500).reverse();
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
for (const agent of agents) {
|
|
20
|
+
// Very rudimentary check to see if the command starts with the agent
|
|
21
|
+
if (line.includes(agent)) {
|
|
22
|
+
const result = spawnSync('which', [agent]);
|
|
23
|
+
if (result.status === 0) {
|
|
24
|
+
return agent;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} catch (e) {}
|
|
32
|
+
|
|
33
|
+
for (const agent of agents) {
|
|
34
|
+
try {
|
|
35
|
+
const result = spawnSync('which', [agent]);
|
|
36
|
+
if (result.status === 0) {
|
|
37
|
+
return agent;
|
|
38
|
+
}
|
|
39
|
+
} catch(e) {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -5,8 +5,9 @@ import pc from 'picocolors';
|
|
|
5
5
|
import { getAuthorshipStats } from './git';
|
|
6
6
|
import { getCarbonStats } from './carbon';
|
|
7
7
|
import { getCapabilitiesStats } from './capabilities';
|
|
8
|
-
import { writeFileSync, chmodSync, existsSync } from 'fs';
|
|
8
|
+
import { writeFileSync, readFileSync, chmodSync, existsSync } from 'fs';
|
|
9
9
|
import { join } from 'path';
|
|
10
|
+
import { detectAgent } from './agent';
|
|
10
11
|
|
|
11
12
|
const ASCII_LOGO = `
|
|
12
13
|
____ _ _ _____ _ ___ _____ ____
|
|
@@ -57,12 +58,32 @@ As agents write more of our code, we lose visibility into:
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
async function main() {
|
|
61
|
+
let action = process.argv[2] as any;
|
|
62
|
+
|
|
63
|
+
if (action === 'daily-greeting') {
|
|
64
|
+
const configPath = join(os.homedir(), '.outlier_config');
|
|
65
|
+
const today = new Date().toISOString().split('T')[0];
|
|
66
|
+
let alreadyRun = false;
|
|
67
|
+
if (existsSync(configPath)) {
|
|
68
|
+
try {
|
|
69
|
+
const cfg = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
70
|
+
if (cfg.lastGreetingDate === today) {
|
|
71
|
+
alreadyRun = true;
|
|
72
|
+
} else {
|
|
73
|
+
cfg.lastGreetingDate = today;
|
|
74
|
+
writeFileSync(configPath, JSON.stringify(cfg));
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {}
|
|
77
|
+
}
|
|
78
|
+
if (alreadyRun) process.exit(0);
|
|
79
|
+
action = 'status';
|
|
80
|
+
}
|
|
81
|
+
|
|
60
82
|
console.clear();
|
|
61
83
|
console.log(pc.cyan(ASCII_LOGO));
|
|
62
84
|
const pkg = require('../package.json');
|
|
63
85
|
console.log(pc.dim(` Outlier v${pkg.version} · AI Code Reliance & Telemetry Engine\n`));
|
|
64
86
|
|
|
65
|
-
let action = process.argv[2] as any;
|
|
66
87
|
|
|
67
88
|
if (action === '--help' || action === '-h' || action === 'help') {
|
|
68
89
|
console.log(pc.bold('\nCOMMANDS:'));
|
|
@@ -74,6 +95,8 @@ async function main() {
|
|
|
74
95
|
console.log(` ${pc.cyan('outlier impact')} See the compounding horizon of AI Deskilling`);
|
|
75
96
|
console.log(` ${pc.cyan('outlier knowledge')} Explore references, graphs, and the core literature`);
|
|
76
97
|
console.log(` ${pc.cyan('outlier participate')} Help build the academic literature on AI deskilling`);
|
|
98
|
+
console.log(` ${pc.cyan('outlier init')} Install the once-per-day shell greeting`);
|
|
99
|
+
console.log(` ${pc.cyan('outlier uninit')} Remove the shell greeting`);
|
|
77
100
|
console.log('\n' + pc.dim('Run without arguments to start the interactive wizard.'));
|
|
78
101
|
process.exit(0);
|
|
79
102
|
}
|
|
@@ -90,6 +113,50 @@ async function main() {
|
|
|
90
113
|
action = 'status'; // Auto-run the main audit loop for highest TTV
|
|
91
114
|
}
|
|
92
115
|
|
|
116
|
+
if (action === 'init' || action === 'uninit') {
|
|
117
|
+
const shell = process.env.SHELL || '';
|
|
118
|
+
const rcName = shell.includes('zsh') ? '.zshrc' : '.bashrc';
|
|
119
|
+
const rcPath = join(os.homedir(), rcName);
|
|
120
|
+
|
|
121
|
+
const START_MARKER = '# --- OUTLIER PRE-FLIGHT RITUAL START ---';
|
|
122
|
+
const END_MARKER = '# --- OUTLIER PRE-FLIGHT RITUAL END ---';
|
|
123
|
+
const BLOCK = `\n${START_MARKER}\nif command -v outlier >/dev/null 2>&1; then\n outlier daily-greeting\nfi\n${END_MARKER}\n`;
|
|
124
|
+
|
|
125
|
+
if (action === 'init') {
|
|
126
|
+
const confirmWrite = await confirm({
|
|
127
|
+
message: `Add a once-per-day Outlier greeting to your ${rcName}? (You can remove it with 'outlier uninit')`,
|
|
128
|
+
initialValue: true
|
|
129
|
+
});
|
|
130
|
+
if (isCancel(confirmWrite) || !confirmWrite) {
|
|
131
|
+
cancel('Aborted.');
|
|
132
|
+
process.exit(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let content = '';
|
|
136
|
+
if (existsSync(rcPath)) content = readFileSync(rcPath, 'utf8');
|
|
137
|
+
if (content.includes(START_MARKER)) {
|
|
138
|
+
note(`Outlier is already initialized in ${rcName}`);
|
|
139
|
+
} else {
|
|
140
|
+
writeFileSync(rcPath, content + BLOCK);
|
|
141
|
+
note(`Successfully added to ${rcName}. Open a new terminal to see the pre-flight ritual!`);
|
|
142
|
+
}
|
|
143
|
+
process.exit(0);
|
|
144
|
+
} else if (action === 'uninit') {
|
|
145
|
+
if (existsSync(rcPath)) {
|
|
146
|
+
let content = readFileSync(rcPath, 'utf8');
|
|
147
|
+
if (content.includes(START_MARKER)) {
|
|
148
|
+
const regex = new RegExp(`\\n?${START_MARKER}[\\s\\S]*?${END_MARKER}\\n?`, 'g');
|
|
149
|
+
content = content.replace(regex, '\n');
|
|
150
|
+
writeFileSync(rcPath, content);
|
|
151
|
+
note(`Removed Outlier block from ${rcName}`);
|
|
152
|
+
} else {
|
|
153
|
+
note(`No Outlier block found in ${rcName}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
93
160
|
const s = spinner();
|
|
94
161
|
|
|
95
162
|
if (action === 'carbon') {
|
|
@@ -157,32 +224,49 @@ Conservative Floor: ${color(nmPct + '%')}`,
|
|
|
157
224
|
let carbon: any = null;
|
|
158
225
|
let capabilities: any = null;
|
|
159
226
|
|
|
227
|
+
let skipDelay = false;
|
|
228
|
+
const configPath = join(os.homedir(), '.outlier_config');
|
|
229
|
+
if (existsSync(configPath)) {
|
|
230
|
+
try {
|
|
231
|
+
const cfg = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
232
|
+
if (cfg.seenNarration) skipDelay = true;
|
|
233
|
+
} catch(e) {}
|
|
234
|
+
}
|
|
235
|
+
|
|
160
236
|
if (!isStrict) {
|
|
161
237
|
s.start('[SYSTEM] Booting local-first sandbox...');
|
|
162
|
-
await new Promise(r => setTimeout(r, 800));
|
|
238
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 800));
|
|
163
239
|
s.message(`↳ Guarantee: No API calls. Your code and logs never leave this machine.`);
|
|
164
|
-
await new Promise(r => setTimeout(r, 1200));
|
|
240
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 1200));
|
|
165
241
|
|
|
166
242
|
s.message('[GIT] Scanning your commit history...');
|
|
167
243
|
gitStats = await getAuthorshipStats().catch(() => null);
|
|
168
|
-
await new Promise(r => setTimeout(r, 600));
|
|
244
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 600));
|
|
169
245
|
s.message(`↳ Check: Are you writing the code, or just reviewing what the AI wrote?`);
|
|
170
|
-
await new Promise(r => setTimeout(r, 1200));
|
|
246
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 1200));
|
|
171
247
|
|
|
172
248
|
s.message('[TOKENS] Parsing local AI logs (~/.claude/)...');
|
|
173
249
|
carbon = await getCarbonStats().catch(() => null);
|
|
174
|
-
await new Promise(r => setTimeout(r, 600));
|
|
250
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 600));
|
|
175
251
|
s.message(`↳ Check: How much API waste is your workflow generating locally?`);
|
|
176
|
-
await new Promise(r => setTimeout(r, 1200));
|
|
252
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 1200));
|
|
177
253
|
|
|
178
254
|
s.message('[ANALYSIS] Calculating your mastery score...');
|
|
179
255
|
capabilities = await getCapabilitiesStats().catch(() => null);
|
|
180
|
-
await new Promise(r => setTimeout(r, 600));
|
|
256
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 600));
|
|
181
257
|
s.message(`↳ Warning: Heavy AI use creates the 'Illusion of Competence'. Don't lose your edge.`);
|
|
182
|
-
await new Promise(r => setTimeout(r, 1200));
|
|
258
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 1200));
|
|
183
259
|
|
|
184
260
|
s.message('[PRINT] Generating Thermal Receipt...');
|
|
185
|
-
await new Promise(r => setTimeout(r, 600));
|
|
261
|
+
if (!skipDelay) await new Promise(r => setTimeout(r, 600));
|
|
262
|
+
|
|
263
|
+
if (!skipDelay) {
|
|
264
|
+
try {
|
|
265
|
+
const cfg = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf8')) : {};
|
|
266
|
+
cfg.seenNarration = true;
|
|
267
|
+
writeFileSync(configPath, JSON.stringify(cfg));
|
|
268
|
+
} catch(e) {}
|
|
269
|
+
}
|
|
186
270
|
} else {
|
|
187
271
|
s.start('Running outlier telemetry audit...');
|
|
188
272
|
gitStats = await getAuthorshipStats().catch(() => null);
|
|
@@ -522,12 +606,23 @@ Artifact: ${pc.cyan(reportPath)}`,
|
|
|
522
606
|
}
|
|
523
607
|
|
|
524
608
|
if (action === 'status') {
|
|
609
|
+
const agent = detectAgent();
|
|
610
|
+
console.log('');
|
|
611
|
+
if (agent) {
|
|
612
|
+
console.log(
|
|
613
|
+
pc.bold(pc.magenta(' ↳ Ready to code? ')) + 'Start your session: ' + pc.bold(agent)
|
|
614
|
+
);
|
|
615
|
+
} else {
|
|
616
|
+
console.log(
|
|
617
|
+
pc.bold(pc.magenta(' ↳ Ready to code? ')) + 'Start your AI agent'
|
|
618
|
+
);
|
|
619
|
+
}
|
|
525
620
|
console.log('');
|
|
526
621
|
console.log(
|
|
527
|
-
pc.bold(pc.cyan(' └
|
|
622
|
+
pc.bold(pc.cyan(' └ Research: ')) + 'Contribute to the AI deskilling study ➔ ' + pc.bold('outlier participate')
|
|
528
623
|
);
|
|
529
624
|
console.log(
|
|
530
|
-
pc.bold(pc.green(' └
|
|
625
|
+
pc.bold(pc.green(' └ Share: ')) + pc.underline('https://x.com/intent/tweet?text=I+just+audited+my+codebase+with+%23Outlier')
|
|
531
626
|
);
|
|
532
627
|
console.log(
|
|
533
628
|
pc.dim('\n (To see all local governance modules, run: ') + pc.dim(pc.bold('outlier --help')) + pc.dim(')')
|