@rosh100yx/outlier 0.4.25 → 0.10.2
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 +86 -53
- package/bin/outlier.js +804 -115
- package/data/grid-factors.json +16 -3
- package/package.json +1 -1
- package/src/aggregate.ts +59 -0
- package/src/capabilities.ts +103 -58
- package/src/carbon.ts +66 -14
- package/src/cli.ts +290 -26
- package/src/economics.ts +66 -0
- package/src/emissions.ts +73 -0
- package/src/insights.ts +109 -0
- package/src/sources.ts +110 -0
package/bin/outlier.js
CHANGED
|
@@ -31,6 +31,20 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
31
31
|
return to;
|
|
32
32
|
};
|
|
33
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
38
|
+
var __export = (target, all) => {
|
|
39
|
+
for (var name in all)
|
|
40
|
+
__defProp(target, name, {
|
|
41
|
+
get: all[name],
|
|
42
|
+
enumerable: true,
|
|
43
|
+
configurable: true,
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
34
48
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
35
49
|
|
|
36
50
|
// node_modules/sisteransi/src/index.js
|
|
@@ -161,11 +175,52 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
161
175
|
module.exports.createColors = createColors;
|
|
162
176
|
});
|
|
163
177
|
|
|
178
|
+
// src/economics.ts
|
|
179
|
+
var exports_economics = {};
|
|
180
|
+
__export(exports_economics, {
|
|
181
|
+
projectEconomics: () => projectEconomics
|
|
182
|
+
});
|
|
183
|
+
function projectEconomics(input) {
|
|
184
|
+
const team = input.teamSize ?? DEFAULTS.teamSize;
|
|
185
|
+
const days = input.workdaysPerYear ?? DEFAULTS.workdaysPerYear;
|
|
186
|
+
const ai = Math.max(0, Math.min(1, input.aiRatio));
|
|
187
|
+
const annualOutflowPerDev = input.estUsdSession * (days / 30);
|
|
188
|
+
const annualOutflowTeam = annualOutflowPerDev * team;
|
|
189
|
+
const projections = [
|
|
190
|
+
{
|
|
191
|
+
label: "Authorship shift",
|
|
192
|
+
value: `${(ai * 100).toFixed(0)}% of output → AI`,
|
|
193
|
+
note: team > 1 ? `≈ ${(ai * team).toFixed(1)} of ${team} dev-equivalents of authorship now machine-produced.` : "At team scale, this many dev-equivalents move to the machine."
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
label: "Value capture (offshore)",
|
|
197
|
+
value: `~$${Math.round(annualOutflowTeam).toLocaleString()}/yr`,
|
|
198
|
+
note: "Hard-currency spend leaving to a foreign AI vendor — value captured offshore, not by the local worker."
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
label: "Skill ladder",
|
|
202
|
+
value: ai > 0.7 ? "AT RISK" : ai > 0.4 ? "watch" : "intact",
|
|
203
|
+
note: ai > 0.7 ? "Above ~70%, juniors stop building the skill that makes seniors — premature deprofessionalization." : "Humans still author enough core work to keep building expertise."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
label: "Forex / tax base",
|
|
207
|
+
value: `$${Math.round(annualOutflowPerDev).toLocaleString()}/dev/yr imported`,
|
|
208
|
+
note: "Locally-taxed wages give way to foreign-billed inference: income-tax erosion + a recurring forex import."
|
|
209
|
+
}
|
|
210
|
+
];
|
|
211
|
+
const assumptions = `Projection only. Assumes: team of ${team}, the local log window ≈ one month of work, ` + `${days} workdays/yr. Spend is your measured/estimated local outflow scaled up — an order-of-magnitude shadow, not an audit.`;
|
|
212
|
+
return { projections, assumptions };
|
|
213
|
+
}
|
|
214
|
+
var DEFAULTS;
|
|
215
|
+
var init_economics = __esm(() => {
|
|
216
|
+
DEFAULTS = { teamSize: 1, workdaysPerYear: 230 };
|
|
217
|
+
});
|
|
218
|
+
|
|
164
219
|
// package.json
|
|
165
220
|
var require_package = __commonJS((exports, module) => {
|
|
166
221
|
module.exports = {
|
|
167
222
|
name: "@rosh100yx/outlier",
|
|
168
|
-
version: "0.
|
|
223
|
+
version: "0.10.2",
|
|
169
224
|
description: "AI Code Governance & Capability Auditing for the Terminal. Measures AI reliance, context waste, and enforces local CI/CD policies.",
|
|
170
225
|
bin: {
|
|
171
226
|
outlier: "bin/outlier.js"
|
|
@@ -1798,38 +1853,192 @@ async function getAuthorshipStats(repoPath = process.cwd()) {
|
|
|
1798
1853
|
}
|
|
1799
1854
|
|
|
1800
1855
|
// src/carbon.ts
|
|
1801
|
-
import { homedir } from "os";
|
|
1802
|
-
import { join } from "path";
|
|
1856
|
+
import { homedir as homedir2 } from "os";
|
|
1857
|
+
import { join as join2 } from "path";
|
|
1803
1858
|
import { readFile, access, readdir } from "fs/promises";
|
|
1804
1859
|
// data/grid-factors.json
|
|
1805
1860
|
var grid_factors_default = {
|
|
1806
1861
|
vietnam: 681,
|
|
1807
|
-
|
|
1808
|
-
|
|
1862
|
+
india_average: 715,
|
|
1863
|
+
indonesia: 650,
|
|
1864
|
+
china: 581,
|
|
1809
1865
|
singapore: 408,
|
|
1810
|
-
|
|
1866
|
+
japan: 470,
|
|
1867
|
+
south_korea: 415,
|
|
1868
|
+
australia: 510,
|
|
1869
|
+
us_east: 380,
|
|
1870
|
+
us_west: 210,
|
|
1871
|
+
canada: 120,
|
|
1872
|
+
brazil: 95,
|
|
1873
|
+
uk: 210,
|
|
1874
|
+
germany: 350,
|
|
1875
|
+
france: 21.7,
|
|
1876
|
+
norway: 28,
|
|
1877
|
+
sweden: 41,
|
|
1878
|
+
global_average: 450
|
|
1811
1879
|
};
|
|
1812
1880
|
|
|
1881
|
+
// src/emissions.ts
|
|
1882
|
+
var MODEL_ENERGY_KWH_PER_M_OUTPUT = {
|
|
1883
|
+
opus: 0.66,
|
|
1884
|
+
sonnet: 0.3,
|
|
1885
|
+
haiku: 0.1,
|
|
1886
|
+
"gpt-4": 0.55,
|
|
1887
|
+
"gpt-4o": 0.3,
|
|
1888
|
+
"gpt-5": 0.45,
|
|
1889
|
+
gemini: 0.35,
|
|
1890
|
+
flash: 0.1,
|
|
1891
|
+
local: 0.5,
|
|
1892
|
+
default: 0.45
|
|
1893
|
+
};
|
|
1894
|
+
function modelClass(modelId) {
|
|
1895
|
+
const m2 = (modelId || "").toLowerCase();
|
|
1896
|
+
if (m2.includes("opus"))
|
|
1897
|
+
return "opus";
|
|
1898
|
+
if (m2.includes("sonnet"))
|
|
1899
|
+
return "sonnet";
|
|
1900
|
+
if (m2.includes("haiku"))
|
|
1901
|
+
return "haiku";
|
|
1902
|
+
if (m2.includes("flash") || m2.includes("mini"))
|
|
1903
|
+
return "haiku";
|
|
1904
|
+
if (m2.includes("gpt-5"))
|
|
1905
|
+
return "gpt-5";
|
|
1906
|
+
if (m2.includes("gpt-4o"))
|
|
1907
|
+
return "gpt-4o";
|
|
1908
|
+
if (m2.includes("gpt-4"))
|
|
1909
|
+
return "gpt-4";
|
|
1910
|
+
if (m2.includes("gemini"))
|
|
1911
|
+
return "gemini";
|
|
1912
|
+
if (m2.includes("llama") || m2.includes("qwen") || m2.includes("mistral") || m2.includes("local"))
|
|
1913
|
+
return "local";
|
|
1914
|
+
return "default";
|
|
1915
|
+
}
|
|
1916
|
+
function energyKwhForModel(modelId, outputTokens) {
|
|
1917
|
+
const cls = modelClass(modelId);
|
|
1918
|
+
const coeff = MODEL_ENERGY_KWH_PER_M_OUTPUT[cls] ?? 0.45;
|
|
1919
|
+
return outputTokens / 1e6 * coeff;
|
|
1920
|
+
}
|
|
1921
|
+
function energyKwhByModel(outputByModel) {
|
|
1922
|
+
let kwh = 0;
|
|
1923
|
+
for (const [model, out] of Object.entries(outputByModel)) {
|
|
1924
|
+
kwh += energyKwhForModel(model, out);
|
|
1925
|
+
}
|
|
1926
|
+
return kwh;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
// src/sources.ts
|
|
1930
|
+
import { homedir } from "os";
|
|
1931
|
+
import { join } from "path";
|
|
1932
|
+
import { existsSync } from "fs";
|
|
1933
|
+
import { execSync } from "child_process";
|
|
1934
|
+
var HOME = homedir();
|
|
1935
|
+
function hasCli(cmd) {
|
|
1936
|
+
try {
|
|
1937
|
+
execSync(`command -v ${cmd}`, { stdio: "ignore" });
|
|
1938
|
+
return true;
|
|
1939
|
+
} catch {
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
function hasPath(p2) {
|
|
1944
|
+
try {
|
|
1945
|
+
return existsSync(p2);
|
|
1946
|
+
} catch {
|
|
1947
|
+
return false;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
function detectSources(cwd = process.cwd()) {
|
|
1951
|
+
const tools = [];
|
|
1952
|
+
const add = (t2) => {
|
|
1953
|
+
if (!tools.includes(t2))
|
|
1954
|
+
tools.push(t2);
|
|
1955
|
+
};
|
|
1956
|
+
const cliTools = {
|
|
1957
|
+
claude: "claude",
|
|
1958
|
+
cursor: "cursor",
|
|
1959
|
+
aider: "aider",
|
|
1960
|
+
gemini: "gemini",
|
|
1961
|
+
opencode: "opencode",
|
|
1962
|
+
cody: "cody",
|
|
1963
|
+
continue: "continue",
|
|
1964
|
+
codex: "codex"
|
|
1965
|
+
};
|
|
1966
|
+
for (const [name, cmd] of Object.entries(cliTools)) {
|
|
1967
|
+
if (hasCli(cmd))
|
|
1968
|
+
add(name);
|
|
1969
|
+
}
|
|
1970
|
+
for (const [name, dir] of Object.entries({
|
|
1971
|
+
claude: ".claude",
|
|
1972
|
+
cursor: ".cursor",
|
|
1973
|
+
gemini: ".gemini",
|
|
1974
|
+
codeium: ".codeium",
|
|
1975
|
+
continue: ".continue",
|
|
1976
|
+
aider: ".aider.conf.yml"
|
|
1977
|
+
})) {
|
|
1978
|
+
if (hasPath(join(HOME, dir)))
|
|
1979
|
+
add(name);
|
|
1980
|
+
}
|
|
1981
|
+
if (hasCli("codecarbon"))
|
|
1982
|
+
add("codecarbon");
|
|
1983
|
+
if (hasCli("ccusage"))
|
|
1984
|
+
add("ccusage");
|
|
1985
|
+
const slug = cwd.replace(/\//g, "-");
|
|
1986
|
+
const claudeProjectDir = join(HOME, ".claude", "projects", slug);
|
|
1987
|
+
const tokenomicsLog = join(HOME, ".claude", "tokenomics-log.jsonl");
|
|
1988
|
+
let tokenSource;
|
|
1989
|
+
if (hasPath(tokenomicsLog)) {
|
|
1990
|
+
tokenSource = { name: "caveman tokenomics log", provenance: "measured" };
|
|
1991
|
+
} else if (hasPath(claudeProjectDir)) {
|
|
1992
|
+
tokenSource = { name: "Claude Code transcripts", provenance: "estimated" };
|
|
1993
|
+
} else if (tools.includes("ccusage")) {
|
|
1994
|
+
tokenSource = { name: "ccusage", provenance: "estimated" };
|
|
1995
|
+
} else {
|
|
1996
|
+
tokenSource = { name: "none", provenance: "none" };
|
|
1997
|
+
}
|
|
1998
|
+
let carbonSource;
|
|
1999
|
+
const codecarbonData = hasPath(join(cwd, "emissions.csv")) || hasPath(join(HOME, ".codecarbon", "emissions.csv"));
|
|
2000
|
+
if (codecarbonData) {
|
|
2001
|
+
carbonSource = { name: "CodeCarbon emissions.csv", provenance: "measured" };
|
|
2002
|
+
} else if (tokenSource.provenance !== "none") {
|
|
2003
|
+
carbonSource = { name: "model+grid estimate", provenance: "estimated" };
|
|
2004
|
+
} else {
|
|
2005
|
+
carbonSource = { name: "none", provenance: "none" };
|
|
2006
|
+
}
|
|
2007
|
+
let capabilitySource;
|
|
2008
|
+
if (hasPath(join(HOME, ".claude", "settings.json")) || hasPath(join(cwd, "AGENTS.md")) || hasPath(join(cwd, ".mcp.json"))) {
|
|
2009
|
+
capabilitySource = { name: "local config (settings/AGENTS/MCP)", provenance: "measured" };
|
|
2010
|
+
} else {
|
|
2011
|
+
capabilitySource = { name: "none", provenance: "none" };
|
|
2012
|
+
}
|
|
2013
|
+
return { tools, tokenSource, carbonSource, capabilitySource };
|
|
2014
|
+
}
|
|
2015
|
+
function provLabel(s) {
|
|
2016
|
+
if (s.provenance === "none")
|
|
2017
|
+
return "no local data";
|
|
2018
|
+
return `${s.provenance} · ${s.name}`;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
1813
2021
|
// src/carbon.ts
|
|
1814
2022
|
class ClaudeLogParser {
|
|
1815
2023
|
baseDir;
|
|
1816
2024
|
cwd;
|
|
1817
|
-
constructor(baseDir =
|
|
2025
|
+
constructor(baseDir = homedir2(), cwd = process.cwd()) {
|
|
1818
2026
|
this.baseDir = baseDir;
|
|
1819
2027
|
this.cwd = cwd;
|
|
1820
2028
|
}
|
|
1821
2029
|
async parse() {
|
|
1822
2030
|
const slug = this.cwd.replace(/\//g, "-");
|
|
1823
|
-
const projectDir =
|
|
2031
|
+
const projectDir = join2(this.baseDir, ".claude", "projects", slug);
|
|
1824
2032
|
try {
|
|
1825
2033
|
const files = (await readdir(projectDir)).filter((f2) => f2.endsWith(".jsonl"));
|
|
1826
2034
|
if (files.length > 0) {
|
|
1827
2035
|
let total2 = 0, output2 = 0, cache2 = 0;
|
|
1828
2036
|
const sessions2 = new Set;
|
|
2037
|
+
const outputByModel2 = {};
|
|
1829
2038
|
for (const file of files) {
|
|
1830
2039
|
let text3 = "";
|
|
1831
2040
|
try {
|
|
1832
|
-
text3 = await readFile(
|
|
2041
|
+
text3 = await readFile(join2(projectDir, file), "utf-8");
|
|
1833
2042
|
} catch {
|
|
1834
2043
|
continue;
|
|
1835
2044
|
}
|
|
@@ -1839,7 +2048,8 @@ class ClaudeLogParser {
|
|
|
1839
2048
|
continue;
|
|
1840
2049
|
try {
|
|
1841
2050
|
const d = JSON.parse(line);
|
|
1842
|
-
const
|
|
2051
|
+
const msg = d.message || {};
|
|
2052
|
+
const u4 = msg.usage || d.usage;
|
|
1843
2053
|
if (u4) {
|
|
1844
2054
|
const inp = u4.input_tokens || 0;
|
|
1845
2055
|
const out = u4.output_tokens || 0;
|
|
@@ -1848,24 +2058,27 @@ class ClaudeLogParser {
|
|
|
1848
2058
|
total2 += inp + out + cr + cw;
|
|
1849
2059
|
output2 += out;
|
|
1850
2060
|
cache2 += cr;
|
|
2061
|
+
const model = msg.model || "default";
|
|
2062
|
+
outputByModel2[model] = (outputByModel2[model] || 0) + out;
|
|
1851
2063
|
}
|
|
1852
2064
|
if (d.sessionId)
|
|
1853
2065
|
sessions2.add(d.sessionId);
|
|
1854
2066
|
} catch {}
|
|
1855
2067
|
}
|
|
1856
2068
|
}
|
|
1857
|
-
return { total: total2, output: output2, cache: cache2, sessions: sessions2.size, cost: 0 };
|
|
2069
|
+
return { total: total2, output: output2, cache: cache2, sessions: sessions2.size, cost: 0, outputByModel: outputByModel2 };
|
|
1858
2070
|
}
|
|
1859
2071
|
} catch {}
|
|
1860
|
-
const logPath =
|
|
2072
|
+
const logPath = join2(this.baseDir, ".claude", "tokenomics-log.jsonl");
|
|
1861
2073
|
try {
|
|
1862
2074
|
await access(logPath);
|
|
1863
2075
|
} catch {
|
|
1864
|
-
return { total: 0, output: 0, cache: 0, sessions: 0, cost: 0 };
|
|
2076
|
+
return { total: 0, output: 0, cache: 0, sessions: 0, cost: 0, outputByModel: {} };
|
|
1865
2077
|
}
|
|
1866
2078
|
const text2 = await readFile(logPath, "utf-8");
|
|
1867
2079
|
let total = 0, output = 0, cache = 0, cost = 0;
|
|
1868
2080
|
const sessions = new Set;
|
|
2081
|
+
const outputByModel = {};
|
|
1869
2082
|
for (const line of text2.split(`
|
|
1870
2083
|
`)) {
|
|
1871
2084
|
if (!line.trim())
|
|
@@ -1878,21 +2091,50 @@ class ClaudeLogParser {
|
|
|
1878
2091
|
cost += data.cost_usd || 0;
|
|
1879
2092
|
if (data.session_id)
|
|
1880
2093
|
sessions.add(data.session_id);
|
|
2094
|
+
const model = data.model || "default";
|
|
2095
|
+
outputByModel[model] = (outputByModel[model] || 0) + (data.output_tokens || 0);
|
|
1881
2096
|
} catch {}
|
|
1882
2097
|
}
|
|
1883
|
-
return { total, output, cache, sessions: sessions.size, cost };
|
|
2098
|
+
return { total, output, cache, sessions: sessions.size, cost, outputByModel };
|
|
1884
2099
|
}
|
|
1885
2100
|
}
|
|
1886
2101
|
|
|
1887
2102
|
class CursorLogParser {
|
|
1888
2103
|
async parse() {
|
|
1889
|
-
return { total: 0, output: 0, cache: 0, sessions: 0, cost: 0 };
|
|
2104
|
+
return { total: 0, output: 0, cache: 0, sessions: 0, cost: 0, outputByModel: {} };
|
|
1890
2105
|
}
|
|
1891
2106
|
}
|
|
1892
2107
|
function estimateUsd(output, cacheRead, total) {
|
|
1893
2108
|
const otherInput = Math.max(0, total - output - cacheRead);
|
|
1894
2109
|
return output / 1e6 * 9 + cacheRead / 1e6 * 0.3 + otherInput / 1e6 * 3;
|
|
1895
2110
|
}
|
|
2111
|
+
function readCodeCarbon(cwd, home) {
|
|
2112
|
+
const { readFileSync, existsSync: existsSync2 } = __require("fs");
|
|
2113
|
+
const { join: join3 } = __require("path");
|
|
2114
|
+
for (const p2 of [join3(cwd, "emissions.csv"), join3(home, ".codecarbon", "emissions.csv")]) {
|
|
2115
|
+
try {
|
|
2116
|
+
if (!existsSync2(p2))
|
|
2117
|
+
continue;
|
|
2118
|
+
const lines = readFileSync(p2, "utf-8").trim().split(`
|
|
2119
|
+
`);
|
|
2120
|
+
if (lines.length < 2)
|
|
2121
|
+
continue;
|
|
2122
|
+
const header = lines[0].split(",");
|
|
2123
|
+
const iEm = header.indexOf("emissions");
|
|
2124
|
+
const iEn = header.indexOf("energy_consumed");
|
|
2125
|
+
if (iEm === -1 && iEn === -1)
|
|
2126
|
+
continue;
|
|
2127
|
+
let co2 = 0, kwh = 0;
|
|
2128
|
+
for (const row of lines.slice(1)) {
|
|
2129
|
+
const cols = row.split(",");
|
|
2130
|
+
co2 += parseFloat(cols[iEm]) || 0;
|
|
2131
|
+
kwh += parseFloat(cols[iEn]) || 0;
|
|
2132
|
+
}
|
|
2133
|
+
return { energyKwh: kwh, co2Kg: co2 };
|
|
2134
|
+
} catch {}
|
|
2135
|
+
}
|
|
2136
|
+
return null;
|
|
2137
|
+
}
|
|
1896
2138
|
function getLocalGridFactor() {
|
|
1897
2139
|
try {
|
|
1898
2140
|
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -1907,11 +2149,12 @@ function getLocalGridFactor() {
|
|
|
1907
2149
|
if (tz.includes("Calcutta") || tz.includes("Kolkata") || tz.includes("Asia/Kabul"))
|
|
1908
2150
|
return { region: "India", factor: grid_factors_default.india_average };
|
|
1909
2151
|
} catch (e) {}
|
|
1910
|
-
return { region: "Global Average", factor:
|
|
2152
|
+
return { region: "Global Average", factor: grid_factors_default.global_average };
|
|
1911
2153
|
}
|
|
1912
2154
|
async function getCarbonStats() {
|
|
1913
2155
|
const parsers = [new ClaudeLogParser, new CursorLogParser];
|
|
1914
2156
|
let totalTokens = 0, outputTokens = 0, cacheReadTokens = 0, sessions = 0, loggedCost = 0;
|
|
2157
|
+
const outputByModel = {};
|
|
1915
2158
|
for (const parser of parsers) {
|
|
1916
2159
|
const stats = await parser.parse();
|
|
1917
2160
|
totalTokens += stats.total;
|
|
@@ -1919,9 +2162,15 @@ async function getCarbonStats() {
|
|
|
1919
2162
|
cacheReadTokens += stats.cache;
|
|
1920
2163
|
sessions += stats.sessions;
|
|
1921
2164
|
loggedCost += stats.cost;
|
|
2165
|
+
for (const [m2, out] of Object.entries(stats.outputByModel)) {
|
|
2166
|
+
outputByModel[m2] = (outputByModel[m2] || 0) + out;
|
|
2167
|
+
}
|
|
1922
2168
|
}
|
|
1923
|
-
const energyKwh = outputTokens / 1e6 * 0.662;
|
|
1924
2169
|
const localGrid = getLocalGridFactor();
|
|
2170
|
+
const measured = readCodeCarbon(process.cwd(), homedir2());
|
|
2171
|
+
const energyKwh = measured ? measured.energyKwh : energyKwhByModel(outputByModel);
|
|
2172
|
+
const measuredCo2 = measured ? measured.co2Kg : null;
|
|
2173
|
+
const sources = detectSources();
|
|
1925
2174
|
const costIsReal = loggedCost > 0;
|
|
1926
2175
|
const estUsd = costIsReal ? loggedCost : estimateUsd(outputTokens, cacheReadTokens, totalTokens);
|
|
1927
2176
|
return {
|
|
@@ -1931,84 +2180,271 @@ async function getCarbonStats() {
|
|
|
1931
2180
|
energyKwh,
|
|
1932
2181
|
co2KgVietnam: energyKwh * grid_factors_default.vietnam / 1000,
|
|
1933
2182
|
co2KgFrance: energyKwh * grid_factors_default.france / 1000,
|
|
1934
|
-
localCo2Kg: energyKwh * localGrid.factor / 1000,
|
|
1935
|
-
localRegion: localGrid.region,
|
|
2183
|
+
localCo2Kg: measuredCo2 !== null ? measuredCo2 : energyKwh * localGrid.factor / 1000,
|
|
2184
|
+
localRegion: measured ? "CodeCarbon (measured)" : localGrid.region,
|
|
1936
2185
|
sessions,
|
|
1937
2186
|
estUsd,
|
|
1938
|
-
costIsReal
|
|
2187
|
+
costIsReal,
|
|
2188
|
+
tokenProvenance: sources.tokenSource.provenance,
|
|
2189
|
+
carbonProvenance: sources.carbonSource.provenance,
|
|
2190
|
+
sourceLabel: provLabel(sources.tokenSource)
|
|
1939
2191
|
};
|
|
1940
2192
|
}
|
|
1941
2193
|
|
|
1942
2194
|
// src/capabilities.ts
|
|
1943
|
-
import { homedir as
|
|
1944
|
-
import { join as
|
|
1945
|
-
import { existsSync, readdirSync } from "fs";
|
|
1946
|
-
|
|
1947
|
-
const
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
if (
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
if (
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
2195
|
+
import { homedir as homedir3 } from "os";
|
|
2196
|
+
import { join as join3 } from "path";
|
|
2197
|
+
import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
|
|
2198
|
+
function classifyReach(name) {
|
|
2199
|
+
const n2 = name.toLowerCase();
|
|
2200
|
+
if (/(stripe|payment|infinity|kucoin|wallet|billing|payout)/.test(n2))
|
|
2201
|
+
return "money";
|
|
2202
|
+
if (/(shell|bash|exec|terminal|command|sandbox)/.test(n2))
|
|
2203
|
+
return "exec";
|
|
2204
|
+
if (/(cloudflare|vercel|netlify|modal|deploy|fly\.io|render|heroku|aws|gcp|azure)/.test(n2))
|
|
2205
|
+
return "deploy";
|
|
2206
|
+
if (/(github|gitlab|git|bitbucket)/.test(n2))
|
|
2207
|
+
return "write-remote";
|
|
2208
|
+
if (/(filesystem|file|fs|disk)/.test(n2))
|
|
2209
|
+
return "write-local";
|
|
2210
|
+
if (/(memory|supermemory|mem|obsidian|notion|airtable|coda|database|sql|store)/.test(n2))
|
|
2211
|
+
return "data";
|
|
2212
|
+
if (/(openrouter|ollama|openai|anthropic|llm|model|hugging)/.test(n2))
|
|
2213
|
+
return "model";
|
|
2214
|
+
if (/(exa|web|fetch|search|brave|browser|http|scrape)/.test(n2))
|
|
2215
|
+
return "network";
|
|
2216
|
+
return "network";
|
|
2217
|
+
}
|
|
2218
|
+
var REACH_RISK = {
|
|
2219
|
+
read: 0,
|
|
2220
|
+
model: 1,
|
|
2221
|
+
network: 1,
|
|
2222
|
+
data: 2,
|
|
2223
|
+
"write-local": 2,
|
|
2224
|
+
"write-remote": 3,
|
|
2225
|
+
deploy: 3,
|
|
2226
|
+
exec: 4,
|
|
2227
|
+
money: 4
|
|
2228
|
+
};
|
|
2229
|
+
function scoreBlast(reaches) {
|
|
2230
|
+
const reasons = [];
|
|
2231
|
+
const has = (r2) => reaches.includes(r2);
|
|
2232
|
+
if (has("money"))
|
|
2233
|
+
reasons.push("can move money");
|
|
2234
|
+
if (has("exec"))
|
|
2235
|
+
reasons.push("can run shell commands");
|
|
2236
|
+
if (has("deploy"))
|
|
2237
|
+
reasons.push("can deploy to production");
|
|
2238
|
+
if (has("write-remote"))
|
|
2239
|
+
reasons.push("can push to your remote repos");
|
|
2240
|
+
if (has("write-local"))
|
|
2241
|
+
reasons.push("can write your local files");
|
|
2242
|
+
if (has("data"))
|
|
2243
|
+
reasons.push("can read/write your stored data");
|
|
2244
|
+
const netCount = reaches.filter((r2) => r2 === "network" || r2 === "model").length;
|
|
2245
|
+
if (netCount >= 3)
|
|
2246
|
+
reasons.push(`reaches ${netCount} external services`);
|
|
2247
|
+
const max = reaches.reduce((m2, r2) => Math.max(m2, REACH_RISK[r2]), 0);
|
|
2248
|
+
let radius = "LOW";
|
|
2249
|
+
if (max >= 4)
|
|
2250
|
+
radius = "CRITICAL";
|
|
2251
|
+
else if (max >= 3)
|
|
2252
|
+
radius = "HIGH";
|
|
2253
|
+
else if (max >= 2)
|
|
2254
|
+
radius = "MEDIUM";
|
|
2255
|
+
return { radius, reasons };
|
|
2256
|
+
}
|
|
2257
|
+
function readJson(path) {
|
|
2258
|
+
try {
|
|
2259
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
2260
|
+
} catch {
|
|
2261
|
+
return null;
|
|
1961
2262
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
stats.skills.push(skill);
|
|
1969
|
-
}
|
|
1970
|
-
} catch (e) {}
|
|
2263
|
+
}
|
|
2264
|
+
function countDir(path, ext = ".md") {
|
|
2265
|
+
try {
|
|
2266
|
+
return readdirSync(path).filter((f2) => f2.endsWith(ext)).length;
|
|
2267
|
+
} catch {
|
|
2268
|
+
return 0;
|
|
1971
2269
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
2270
|
+
}
|
|
2271
|
+
async function getCapabilitiesStats(repoPath = process.cwd(), homeDirPath = homedir3()) {
|
|
2272
|
+
const mcpNames = new Set;
|
|
2273
|
+
for (const cfg of [
|
|
2274
|
+
join3(homeDirPath, ".claude.json"),
|
|
2275
|
+
join3(homeDirPath, ".claude", "settings.json"),
|
|
2276
|
+
join3(homeDirPath, ".cursor", "mcp.json"),
|
|
2277
|
+
join3(homeDirPath, ".gemini", "config", "mcp_config.json"),
|
|
2278
|
+
join3(homeDirPath, ".gemini", "settings.json"),
|
|
2279
|
+
join3(repoPath, ".mcp.json"),
|
|
2280
|
+
join3(repoPath, ".cursor", "mcp.json"),
|
|
2281
|
+
join3(repoPath, ".claude", "settings.json")
|
|
2282
|
+
]) {
|
|
2283
|
+
const j = readJson(cfg);
|
|
2284
|
+
if (j?.mcpServers)
|
|
2285
|
+
Object.keys(j.mcpServers).forEach((k) => mcpNames.add(k));
|
|
2286
|
+
}
|
|
2287
|
+
const geminiMcp = join3(homeDirPath, ".gemini", "antigravity-cli", "mcp");
|
|
2288
|
+
if (existsSync2(geminiMcp)) {
|
|
1974
2289
|
try {
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
} catch (e) {}
|
|
2290
|
+
readdirSync(geminiMcp, { withFileTypes: true }).filter((d) => d.isDirectory()).forEach((d) => mcpNames.add(d.name));
|
|
2291
|
+
} catch {}
|
|
1978
2292
|
}
|
|
1979
|
-
const
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
if (
|
|
1986
|
-
|
|
1987
|
-
}
|
|
2293
|
+
const mcps = [...mcpNames].map((name) => ({ name, reach: classifyReach(name) }));
|
|
2294
|
+
const skills = [];
|
|
2295
|
+
for (const p2 of [join3(repoPath, ".agents", "skills"), join3(homeDirPath, ".claude", "skills"), join3(homeDirPath, ".gemini", "skills")]) {
|
|
2296
|
+
if (existsSync2(p2)) {
|
|
2297
|
+
try {
|
|
2298
|
+
readdirSync(p2, { withFileTypes: true }).filter((d) => d.isDirectory()).forEach((d) => {
|
|
2299
|
+
if (!skills.includes(d.name))
|
|
2300
|
+
skills.push(d.name);
|
|
1988
2301
|
});
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
2302
|
+
} catch {}
|
|
2303
|
+
}
|
|
1991
2304
|
}
|
|
1992
|
-
|
|
2305
|
+
const subagents = countDir(join3(homeDirPath, ".claude", "agents")) + countDir(join3(repoPath, ".claude", "agents"));
|
|
2306
|
+
const hooks = [];
|
|
2307
|
+
for (const cfg of [join3(homeDirPath, ".claude", "settings.json"), join3(repoPath, ".claude", "settings.json")]) {
|
|
2308
|
+
const j = readJson(cfg);
|
|
2309
|
+
if (j?.hooks)
|
|
2310
|
+
Object.keys(j.hooks).forEach((k) => {
|
|
2311
|
+
if (!hooks.includes(k))
|
|
2312
|
+
hooks.push(k);
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
const hasOrchestration = existsSync2(join3(repoPath, "AGENTS.md")) || existsSync2(join3(repoPath, ".mcp.json"));
|
|
2316
|
+
const { radius, reasons } = scoreBlast(mcps.map((m2) => m2.reach));
|
|
2317
|
+
return { mcps, skills, subagents, hooks, hasOrchestration, blastRadius: radius, blastReasons: reasons };
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
// src/insights.ts
|
|
2321
|
+
var RANK = { critical: 0, warn: 1, info: 2, good: 3 };
|
|
2322
|
+
function deriveInsights({ authorship, carbon, caps, policyCap = 0.7 }) {
|
|
2323
|
+
const out = [];
|
|
2324
|
+
const ai = authorship ? authorship.ratio : null;
|
|
2325
|
+
const cachePct = carbon && carbon.totalTokens ? carbon.cacheReadTokens / carbon.totalTokens * 100 : null;
|
|
2326
|
+
const blast = caps ? caps.blastRadius : null;
|
|
2327
|
+
const writeOrDeploy = caps ? caps.mcps.filter((m2) => ["money", "exec", "deploy", "write-remote", "write-local"].includes(m2.reach)).length : 0;
|
|
2328
|
+
const heavyTokens = carbon ? carbon.totalTokens > 1e6 : false;
|
|
2329
|
+
if (ai !== null && ai > 0.7 && (blast === "HIGH" || blast === "CRITICAL")) {
|
|
2330
|
+
out.push({
|
|
2331
|
+
severity: "critical",
|
|
2332
|
+
title: "High reliance + high reach",
|
|
2333
|
+
detail: `AI wrote ${(ai * 100).toFixed(0)}% here and your agents can ${writeOrDeploy ? "write/deploy" : "reach external services"}. You may not own code that can ship to prod.`,
|
|
2334
|
+
action: "Review the core paths yourself before delegating more this session."
|
|
2335
|
+
});
|
|
2336
|
+
} else if (ai !== null && ai > 0.7) {
|
|
2337
|
+
out.push({
|
|
2338
|
+
severity: "warn",
|
|
2339
|
+
title: "You are mostly reviewing, not writing",
|
|
2340
|
+
detail: `AI wrote ${(ai * 100).toFixed(0)}% of recent commits — you risk losing the skill to debug it unaided.`,
|
|
2341
|
+
action: "Read the AI-written code through, or hand-write the next core change."
|
|
2342
|
+
});
|
|
2343
|
+
}
|
|
2344
|
+
if (ai !== null && ai < 0.1 && heavyTokens) {
|
|
2345
|
+
out.push({
|
|
2346
|
+
severity: "info",
|
|
2347
|
+
title: "Low AI% may be misleading",
|
|
2348
|
+
detail: "Heavy token use but few AI-tagged commits — your agent probably is not writing Co-Authored-By trailers.",
|
|
2349
|
+
action: "Treat the authorship number as a floor, not the truth, until trailers are on."
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
if (caps && (blast === "CRITICAL" || blast === "HIGH")) {
|
|
2353
|
+
out.push({
|
|
2354
|
+
severity: blast === "CRITICAL" ? "critical" : "warn",
|
|
2355
|
+
title: `Blast radius ${blast}`,
|
|
2356
|
+
detail: `If an agent (or a prompt injection) drives your tools, it ${caps.blastReasons.slice(0, 2).join(" and ") || "has broad reach"}.`,
|
|
2357
|
+
action: "Disable the write/deploy MCP tools you do not need this session."
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
if (cachePct !== null && cachePct > 80) {
|
|
2361
|
+
out.push({
|
|
2362
|
+
severity: "warn",
|
|
2363
|
+
title: "Most of your spend is re-sent context",
|
|
2364
|
+
detail: `${cachePct.toFixed(0)}% of your tokens just re-read old context — that is most of the bill, not new work.`,
|
|
2365
|
+
action: "Start fresh sessions for new tasks; keep context tight."
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
if (ai !== null && ai > policyCap) {
|
|
2369
|
+
out.push({
|
|
2370
|
+
severity: "warn",
|
|
2371
|
+
title: "Over your AI-authorship limit",
|
|
2372
|
+
detail: `AI authorship is ${(ai * 100).toFixed(0)}%, over your ${(policyCap * 100).toFixed(0)}% limit.`,
|
|
2373
|
+
action: "Either raise the cap deliberately, or write the next change yourself."
|
|
2374
|
+
});
|
|
2375
|
+
}
|
|
2376
|
+
if (out.length === 0) {
|
|
2377
|
+
out.push({
|
|
2378
|
+
severity: "good",
|
|
2379
|
+
title: "Low risk",
|
|
2380
|
+
detail: ai !== null ? `You wrote most of this (${(100 - ai * 100).toFixed(0)}%) and your agents have limited reach.` : "No AI logs or git history found to flag.",
|
|
2381
|
+
action: "Carry on — re-run before your next big delegation."
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2384
|
+
return out.sort((a2, b2) => RANK[a2.severity] - RANK[b2.severity]);
|
|
1993
2385
|
}
|
|
1994
2386
|
|
|
1995
2387
|
// src/cli.ts
|
|
1996
|
-
|
|
2388
|
+
init_economics();
|
|
2389
|
+
|
|
2390
|
+
// src/aggregate.ts
|
|
2391
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
1997
2392
|
import { join as join4 } from "path";
|
|
2393
|
+
var BLAST_ORDER = ["LOW", "MEDIUM", "HIGH", "CRITICAL"];
|
|
2394
|
+
function aggregateDir(dir) {
|
|
2395
|
+
const files = readdirSync2(dir).filter((f2) => f2.endsWith(".json"));
|
|
2396
|
+
const audits = [];
|
|
2397
|
+
for (const f2 of files) {
|
|
2398
|
+
try {
|
|
2399
|
+
const j = JSON.parse(readFileSync2(join4(dir, f2), "utf-8"));
|
|
2400
|
+
if (j?.tool === "outlier")
|
|
2401
|
+
audits.push(j);
|
|
2402
|
+
} catch {}
|
|
2403
|
+
}
|
|
2404
|
+
const aiPcts = audits.map((a2) => a2.authorship?.aiPercent).filter((x) => typeof x === "number");
|
|
2405
|
+
const spends = audits.map((a2) => a2.cost?.estUsd || 0);
|
|
2406
|
+
const blasts = audits.map((a2) => a2.reach?.blastRadius).filter(Boolean);
|
|
2407
|
+
const overs = audits.filter((a2) => a2.policy?.status === "over").length;
|
|
2408
|
+
const writeDeploy = audits.reduce((s, a2) => s + (a2.reach?.writeOrDeployCount || 0), 0);
|
|
2409
|
+
const worst = blasts.reduce((m2, b2) => BLAST_ORDER.indexOf(b2) > BLAST_ORDER.indexOf(m2) ? b2 : m2, "LOW");
|
|
2410
|
+
const notes = [];
|
|
2411
|
+
if (aiPcts.length && Math.max(...aiPcts) > 70)
|
|
2412
|
+
notes.push("At least one developer is over 70% AI authorship.");
|
|
2413
|
+
if (worst === "HIGH" || worst === "CRITICAL")
|
|
2414
|
+
notes.push(`Worst-case agent blast radius across the team is ${worst}.`);
|
|
2415
|
+
if (overs > 0)
|
|
2416
|
+
notes.push(`${overs} developer(s) over their AI-authorship limit.`);
|
|
2417
|
+
if (audits.length === 0)
|
|
2418
|
+
notes.push("No outlier --json files found in this folder.");
|
|
2419
|
+
return {
|
|
2420
|
+
developers: audits.length,
|
|
2421
|
+
avgAiPercent: aiPcts.length ? +(aiPcts.reduce((a2, b2) => a2 + b2, 0) / aiPcts.length).toFixed(1) : null,
|
|
2422
|
+
maxAiPercent: aiPcts.length ? Math.max(...aiPcts) : null,
|
|
2423
|
+
totalEstUsd: +spends.reduce((a2, b2) => a2 + b2, 0).toFixed(2),
|
|
2424
|
+
worstBlastRadius: worst,
|
|
2425
|
+
overLimit: overs,
|
|
2426
|
+
reachWriteDeploy: writeDeploy,
|
|
2427
|
+
notes
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
// src/cli.ts
|
|
2432
|
+
import { writeFileSync, readFileSync as readFileSync4, chmodSync, existsSync as existsSync4 } from "fs";
|
|
2433
|
+
import { join as join6 } from "path";
|
|
1998
2434
|
|
|
1999
2435
|
// src/agent.ts
|
|
2000
2436
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
2001
|
-
import { readFileSync, existsSync as
|
|
2002
|
-
import { join as
|
|
2437
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
2438
|
+
import { join as join5 } from "path";
|
|
2003
2439
|
import os from "os";
|
|
2004
2440
|
function detectAgent() {
|
|
2005
2441
|
const agents = ["claude", "cursor", "aider", "hermes", "cody", "continue", "opencode", "gemini"];
|
|
2006
2442
|
try {
|
|
2007
2443
|
const home = os.homedir();
|
|
2008
|
-
const historyFiles = [
|
|
2444
|
+
const historyFiles = [join5(home, ".zsh_history"), join5(home, ".bash_history")];
|
|
2009
2445
|
for (const file of historyFiles) {
|
|
2010
|
-
if (
|
|
2011
|
-
const content =
|
|
2446
|
+
if (existsSync3(file)) {
|
|
2447
|
+
const content = readFileSync3(file, "utf8");
|
|
2012
2448
|
const lines = content.split(`
|
|
2013
2449
|
`).filter(Boolean).slice(-500).reverse();
|
|
2014
2450
|
for (const line of lines) {
|
|
@@ -2045,6 +2481,116 @@ var ASCII_LOGO = `
|
|
|
2045
2481
|
\\____/|_| |_| |_| |_| |_|___|_____|_| \\_\\
|
|
2046
2482
|
`;
|
|
2047
2483
|
var finalReceipt = "";
|
|
2484
|
+
function closeBox(s, W2 = 66) {
|
|
2485
|
+
const wide = new Set(["⚠", "\uD83D\uDED1", "✈", "\uD83C\uDF31", "\uD83D\uDCF8", "\uD83D\uDD2C", "\uD83D\uDCBE", "\uD83D\uDCA1", "✅", "❌", "\uD83D\uDE3E", "\uD83D\uDE00"]);
|
|
2486
|
+
const chW = (ch) => {
|
|
2487
|
+
const cp = ch.codePointAt(0);
|
|
2488
|
+
return cp >= 126976 || wide.has(ch) ? 2 : 1;
|
|
2489
|
+
};
|
|
2490
|
+
const rail = "\x1B[2m│\x1B[0m";
|
|
2491
|
+
const fit = (line, totalVis) => {
|
|
2492
|
+
const parts = line.split(/(\x1b\[[0-9;]*m)/);
|
|
2493
|
+
let out = "", vis = 0, cut = false;
|
|
2494
|
+
for (const p2 of parts) {
|
|
2495
|
+
if (/^\x1b\[/.test(p2)) {
|
|
2496
|
+
out += p2;
|
|
2497
|
+
continue;
|
|
2498
|
+
}
|
|
2499
|
+
for (const ch of p2) {
|
|
2500
|
+
const w = chW(ch);
|
|
2501
|
+
if (vis + w > totalVis - 1) {
|
|
2502
|
+
cut = true;
|
|
2503
|
+
break;
|
|
2504
|
+
}
|
|
2505
|
+
out += ch;
|
|
2506
|
+
vis += w;
|
|
2507
|
+
}
|
|
2508
|
+
if (cut)
|
|
2509
|
+
break;
|
|
2510
|
+
}
|
|
2511
|
+
if (cut) {
|
|
2512
|
+
out += "…";
|
|
2513
|
+
vis += 1;
|
|
2514
|
+
}
|
|
2515
|
+
return out + " ".repeat(Math.max(0, totalVis - vis)) + "\x1B[0m";
|
|
2516
|
+
};
|
|
2517
|
+
return s.split(`
|
|
2518
|
+
`).map((line) => {
|
|
2519
|
+
const plain = line.replace(/\x1b\[[0-9;]*m/g, "");
|
|
2520
|
+
if (/^\s*┌/.test(plain))
|
|
2521
|
+
return " \x1B[2m┌" + "─".repeat(W2) + "┐\x1B[0m";
|
|
2522
|
+
if (/^\s*├/.test(plain))
|
|
2523
|
+
return " \x1B[2m├" + "─".repeat(W2) + "┤\x1B[0m";
|
|
2524
|
+
if (/^\s*└/.test(plain))
|
|
2525
|
+
return " \x1B[2m└" + "─".repeat(W2) + "┘\x1B[0m";
|
|
2526
|
+
if (/^\s*│/.test(plain))
|
|
2527
|
+
return fit(line, 2 + W2) + rail;
|
|
2528
|
+
return line;
|
|
2529
|
+
}).join(`
|
|
2530
|
+
`);
|
|
2531
|
+
}
|
|
2532
|
+
async function emitJson() {
|
|
2533
|
+
const pkg = require_package();
|
|
2534
|
+
const [gitStats, carbon, caps] = await Promise.all([
|
|
2535
|
+
getAuthorshipStats().catch(() => null),
|
|
2536
|
+
getCarbonStats().catch(() => null),
|
|
2537
|
+
getCapabilitiesStats().catch(() => null)
|
|
2538
|
+
]);
|
|
2539
|
+
const aiRatio = gitStats ? gitStats.ratio : 0;
|
|
2540
|
+
const cap = 0.7;
|
|
2541
|
+
const writeOrDeploy = caps ? caps.mcps.filter((m2) => ["money", "exec", "deploy", "write-remote", "write-local"].includes(m2.reach)).length : 0;
|
|
2542
|
+
const out = {
|
|
2543
|
+
tool: "outlier",
|
|
2544
|
+
version: pkg.version,
|
|
2545
|
+
repo: process.cwd().split("/").pop(),
|
|
2546
|
+
generatedAt: new Date().toISOString(),
|
|
2547
|
+
localFirst: true,
|
|
2548
|
+
authorship: gitStats ? {
|
|
2549
|
+
aiPercent: +(gitStats.ratio * 100).toFixed(1),
|
|
2550
|
+
aiRatio: gitStats.ratio,
|
|
2551
|
+
totalCommits: gitStats.total,
|
|
2552
|
+
aiCommits: gitStats.ai,
|
|
2553
|
+
nonMergePercent: +(gitStats.ratioNoMerges * 100).toFixed(1),
|
|
2554
|
+
provenance: "proxy",
|
|
2555
|
+
note: "git Co-Authored-By trailers; under-counts if the agent omits the trailer"
|
|
2556
|
+
} : null,
|
|
2557
|
+
cost: carbon ? {
|
|
2558
|
+
totalTokens: carbon.totalTokens,
|
|
2559
|
+
outputTokens: carbon.outputTokens,
|
|
2560
|
+
cacheReusePercent: carbon.totalTokens ? +(carbon.cacheReadTokens / carbon.totalTokens * 100).toFixed(1) : 0,
|
|
2561
|
+
estUsd: +carbon.estUsd.toFixed(2),
|
|
2562
|
+
costIsReal: carbon.costIsReal,
|
|
2563
|
+
provenance: carbon.tokenProvenance,
|
|
2564
|
+
source: carbon.sourceLabel
|
|
2565
|
+
} : null,
|
|
2566
|
+
carbon: carbon ? {
|
|
2567
|
+
energyKwh: +carbon.energyKwh.toFixed(4),
|
|
2568
|
+
co2Kg: +carbon.localCo2Kg.toFixed(4),
|
|
2569
|
+
region: carbon.localRegion,
|
|
2570
|
+
provenance: carbon.carbonProvenance,
|
|
2571
|
+
note: "counterfactual: cloud inference runs on the provider grid, not yours"
|
|
2572
|
+
} : null,
|
|
2573
|
+
reach: caps ? {
|
|
2574
|
+
blastRadius: caps.blastRadius,
|
|
2575
|
+
reasons: caps.blastReasons,
|
|
2576
|
+
toolCount: caps.mcps.length,
|
|
2577
|
+
writeOrDeployCount: writeOrDeploy,
|
|
2578
|
+
tools: caps.mcps,
|
|
2579
|
+
subagents: caps.subagents,
|
|
2580
|
+
hooks: caps.hooks,
|
|
2581
|
+
skills: caps.skills.length,
|
|
2582
|
+
orchestration: caps.hasOrchestration
|
|
2583
|
+
} : null,
|
|
2584
|
+
policy: {
|
|
2585
|
+
aiCapPercent: cap * 100,
|
|
2586
|
+
status: aiRatio > cap ? "over" : "within"
|
|
2587
|
+
},
|
|
2588
|
+
insights: deriveInsights({ authorship: gitStats, carbon, caps, policyCap: cap }),
|
|
2589
|
+
economics: projectEconomics({ aiRatio, estUsdSession: carbon ? carbon.estUsd : 0, teamSize: 1 })
|
|
2590
|
+
};
|
|
2591
|
+
process.stdout.write(JSON.stringify(out, null, 2) + `
|
|
2592
|
+
`);
|
|
2593
|
+
}
|
|
2048
2594
|
async function runOnboarding() {
|
|
2049
2595
|
console.log(import_picocolors.default.cyan(ASCII_LOGO));
|
|
2050
2596
|
intro(import_picocolors.default.inverse(" outlier: Welcome "));
|
|
@@ -2066,18 +2612,18 @@ As agents write more of our code, we lose visibility into:
|
|
|
2066
2612
|
cancel("Onboarding paused. Run outlier again when you are ready.");
|
|
2067
2613
|
process.exit(0);
|
|
2068
2614
|
}
|
|
2069
|
-
const configPath =
|
|
2615
|
+
const configPath = join6(os2.homedir(), ".outlier_config");
|
|
2070
2616
|
writeFileSync(configPath, JSON.stringify({ onboarded: true, date: new Date().toISOString() }));
|
|
2071
2617
|
}
|
|
2072
2618
|
async function main() {
|
|
2073
2619
|
let action = process.argv[2];
|
|
2074
2620
|
if (action === "daily-greeting") {
|
|
2075
|
-
const configPath2 =
|
|
2621
|
+
const configPath2 = join6(os2.homedir(), ".outlier_config");
|
|
2076
2622
|
const today = new Date().toISOString().split("T")[0];
|
|
2077
2623
|
let alreadyRun = false;
|
|
2078
|
-
if (
|
|
2624
|
+
if (existsSync4(configPath2)) {
|
|
2079
2625
|
try {
|
|
2080
|
-
const cfg = JSON.parse(
|
|
2626
|
+
const cfg = JSON.parse(readFileSync4(configPath2, "utf8"));
|
|
2081
2627
|
if (cfg.lastGreetingDate === today) {
|
|
2082
2628
|
alreadyRun = true;
|
|
2083
2629
|
} else {
|
|
@@ -2088,7 +2634,17 @@ async function main() {
|
|
|
2088
2634
|
}
|
|
2089
2635
|
if (alreadyRun)
|
|
2090
2636
|
process.exit(0);
|
|
2091
|
-
|
|
2637
|
+
const g2 = await getAuthorshipStats().catch(() => null);
|
|
2638
|
+
const cp = await getCapabilitiesStats().catch(() => null);
|
|
2639
|
+
const aiP = g2 ? (g2.ratio * 100).toFixed(0) + "%" : "—";
|
|
2640
|
+
const br = cp ? cp.blastRadius : "—";
|
|
2641
|
+
const brc = br === "HIGH" || br === "CRITICAL" ? import_picocolors.default.red : br === "MEDIUM" ? import_picocolors.default.yellow : import_picocolors.default.green;
|
|
2642
|
+
console.log(`${import_picocolors.default.dim("[outlier]")} AI authorship ${import_picocolors.default.bold(aiP)} · agent reach ${brc(import_picocolors.default.bold(br))} ${import_picocolors.default.dim("· before you delegate, run: outlier preflight")}`);
|
|
2643
|
+
process.exit(0);
|
|
2644
|
+
}
|
|
2645
|
+
if (process.argv.includes("--json")) {
|
|
2646
|
+
await emitJson();
|
|
2647
|
+
process.exit(0);
|
|
2092
2648
|
}
|
|
2093
2649
|
console.log(import_picocolors.default.cyan(ASCII_LOGO));
|
|
2094
2650
|
const pkg = require_package();
|
|
@@ -2102,8 +2658,10 @@ WHAT OUTLIER DOES`));
|
|
|
2102
2658
|
`));
|
|
2103
2659
|
console.log(import_picocolors.default.bold("COMMANDS:"));
|
|
2104
2660
|
console.log(` ${import_picocolors.default.cyan("outlier")} Run the audit (the default — same as 'status')`);
|
|
2661
|
+
console.log(` ${import_picocolors.default.cyan("outlier preflight")} Quick briefing BEFORE you start an agent (reach + skill + spend)`);
|
|
2105
2662
|
console.log(` ${import_picocolors.default.cyan("outlier status")} Full audit: who wrote the code, what it cost, your limit`);
|
|
2106
2663
|
console.log(` ${import_picocolors.default.cyan("outlier status --save")} Save the audit to ./outlier-audit.txt`);
|
|
2664
|
+
console.log(` ${import_picocolors.default.cyan("outlier --json")} Machine-readable audit (for agents, CI, swarms)`);
|
|
2107
2665
|
console.log(` ${import_picocolors.default.cyan("outlier authorship")} Just the AI-vs-human commit breakdown`);
|
|
2108
2666
|
console.log(` ${import_picocolors.default.cyan("outlier carbon")} Just the token spend, cache waste & carbon`);
|
|
2109
2667
|
console.log(` ${import_picocolors.default.cyan("outlier capabilities")} What tools & skills your agents can reach`);
|
|
@@ -2118,8 +2676,8 @@ WHAT OUTLIER DOES`));
|
|
|
2118
2676
|
console.log(import_picocolors.default.dim("How it works → https://github.com/rosh100yx/outlier#how-it-works"));
|
|
2119
2677
|
process.exit(0);
|
|
2120
2678
|
}
|
|
2121
|
-
const configPath =
|
|
2122
|
-
if (!
|
|
2679
|
+
const configPath = join6(os2.homedir(), ".outlier_config");
|
|
2680
|
+
if (!existsSync4(configPath) && !action) {
|
|
2123
2681
|
await runOnboarding();
|
|
2124
2682
|
action = "status";
|
|
2125
2683
|
}
|
|
@@ -2130,7 +2688,7 @@ WHAT OUTLIER DOES`));
|
|
|
2130
2688
|
if (action === "init" || action === "uninit") {
|
|
2131
2689
|
const shell = process.env.SHELL || "";
|
|
2132
2690
|
const rcName = shell.includes("zsh") ? ".zshrc" : ".bashrc";
|
|
2133
|
-
const rcPath =
|
|
2691
|
+
const rcPath = join6(os2.homedir(), rcName);
|
|
2134
2692
|
const START_MARKER = "# --- OUTLIER PRE-FLIGHT RITUAL START ---";
|
|
2135
2693
|
const END_MARKER = "# --- OUTLIER PRE-FLIGHT RITUAL END ---";
|
|
2136
2694
|
const BLOCK = `
|
|
@@ -2150,8 +2708,8 @@ ${END_MARKER}
|
|
|
2150
2708
|
process.exit(0);
|
|
2151
2709
|
}
|
|
2152
2710
|
let content = "";
|
|
2153
|
-
if (
|
|
2154
|
-
content =
|
|
2711
|
+
if (existsSync4(rcPath))
|
|
2712
|
+
content = readFileSync4(rcPath, "utf8");
|
|
2155
2713
|
if (content.includes(START_MARKER)) {
|
|
2156
2714
|
note(`Outlier is already initialized in ${rcName}`);
|
|
2157
2715
|
} else {
|
|
@@ -2160,8 +2718,8 @@ ${END_MARKER}
|
|
|
2160
2718
|
}
|
|
2161
2719
|
process.exit(0);
|
|
2162
2720
|
} else if (action === "uninit") {
|
|
2163
|
-
if (
|
|
2164
|
-
let content =
|
|
2721
|
+
if (existsSync4(rcPath)) {
|
|
2722
|
+
let content = readFileSync4(rcPath, "utf8");
|
|
2165
2723
|
if (content.includes(START_MARKER)) {
|
|
2166
2724
|
const regex = new RegExp(`\\n?${START_MARKER}[\\s\\S]*?${END_MARKER}\\n?`, "g");
|
|
2167
2725
|
content = content.replace(regex, `
|
|
@@ -2230,10 +2788,10 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2230
2788
|
let carbon = null;
|
|
2231
2789
|
let capabilities = null;
|
|
2232
2790
|
let skipDelay = false;
|
|
2233
|
-
const configPath2 =
|
|
2234
|
-
if (
|
|
2791
|
+
const configPath2 = join6(os2.homedir(), ".outlier_config");
|
|
2792
|
+
if (existsSync4(configPath2)) {
|
|
2235
2793
|
try {
|
|
2236
|
-
const cfg = JSON.parse(
|
|
2794
|
+
const cfg = JSON.parse(readFileSync4(configPath2, "utf8"));
|
|
2237
2795
|
if (cfg.seenNarration)
|
|
2238
2796
|
skipDelay = true;
|
|
2239
2797
|
} catch (e) {}
|
|
@@ -2271,7 +2829,7 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2271
2829
|
await new Promise((r2) => setTimeout(r2, 600));
|
|
2272
2830
|
if (!skipDelay) {
|
|
2273
2831
|
try {
|
|
2274
|
-
const cfg =
|
|
2832
|
+
const cfg = existsSync4(configPath2) ? JSON.parse(readFileSync4(configPath2, "utf8")) : {};
|
|
2275
2833
|
cfg.seenNarration = true;
|
|
2276
2834
|
writeFileSync(configPath2, JSON.stringify(cfg));
|
|
2277
2835
|
} catch (e) {}
|
|
@@ -2299,13 +2857,32 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2299
2857
|
let cachePct = "0";
|
|
2300
2858
|
let co2Str = "0.0kg";
|
|
2301
2859
|
let regionStr = "Global Average";
|
|
2860
|
+
let sourceLabel = "no local AI logs found";
|
|
2861
|
+
let noData = true;
|
|
2302
2862
|
if (carbon) {
|
|
2303
2863
|
if (carbon.totalTokens > 0) {
|
|
2304
2864
|
cachePct = (carbon.cacheReadTokens / carbon.totalTokens * 100).toFixed(1);
|
|
2865
|
+
noData = false;
|
|
2305
2866
|
}
|
|
2306
2867
|
co2Str = `${carbon.localCo2Kg.toFixed(2)}kg CO2`;
|
|
2307
2868
|
regionStr = carbon.localRegion;
|
|
2869
|
+
sourceLabel = carbon.sourceLabel;
|
|
2308
2870
|
}
|
|
2871
|
+
let reachStr = import_picocolors.default.dim("run: outlier capabilities");
|
|
2872
|
+
if (capabilities) {
|
|
2873
|
+
const rc = capabilities.blastRadius;
|
|
2874
|
+
const col = rc === "CRITICAL" || rc === "HIGH" ? import_picocolors.default.red : rc === "MEDIUM" ? import_picocolors.default.yellow : import_picocolors.default.green;
|
|
2875
|
+
const risky = capabilities.mcps.filter((m2) => ["money", "exec", "deploy", "write-remote", "write-local"].includes(m2.reach)).length;
|
|
2876
|
+
reachStr = `${col(import_picocolors.default.bold(rc))} · ${capabilities.mcps.length} tools` + (risky ? import_picocolors.default.dim(`, ${risky} can write/deploy`) : "");
|
|
2877
|
+
}
|
|
2878
|
+
const insights = deriveInsights({ authorship: gitStats, carbon, caps: capabilities, policyCap: 0.7 });
|
|
2879
|
+
const sevColor = (s2) => s2 === "critical" ? import_picocolors.default.red : s2 === "warn" ? import_picocolors.default.yellow : s2 === "good" ? import_picocolors.default.green : import_picocolors.default.cyan;
|
|
2880
|
+
const sevMark = (s2) => s2 === "critical" ? "✗" : s2 === "warn" ? "⚠" : s2 === "good" ? "✓" : "i";
|
|
2881
|
+
const insightLines = insights.slice(0, 2).map((ins) => ` ${import_picocolors.default.dim("│")} ${sevColor(ins.severity)(sevMark(ins.severity))} ${import_picocolors.default.bold(ins.title)}
|
|
2882
|
+
` + ` ${import_picocolors.default.dim("│")} ${ins.detail.length > 56 ? ins.detail.slice(0, 55) + "…" : ins.detail}
|
|
2883
|
+
` + ` ${import_picocolors.default.dim("│")} ${import_picocolors.default.cyan("→ " + ins.action)}`).join(`
|
|
2884
|
+
${import_picocolors.default.dim("│")}
|
|
2885
|
+
`);
|
|
2309
2886
|
const isDanger = gitStats && gitStats.ratio > 0.7;
|
|
2310
2887
|
const verdictZone = isDanger ? import_picocolors.default.red("Mostly AI") : import_picocolors.default.green("You're driving");
|
|
2311
2888
|
const verdictText = isDanger ? `AI wrote most of this. Read it through so you can
|
|
@@ -2353,15 +2930,23 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2353
2930
|
${import_picocolors.default.dim("│")} Tokens used ${import_picocolors.default.bold(totalTokensStr)}
|
|
2354
2931
|
${import_picocolors.default.dim("│")} Est. spend ${import_picocolors.default.bold(estUsdStr)}
|
|
2355
2932
|
${import_picocolors.default.dim("│")} Re-used context ${cacheBar} ${import_picocolors.default.bold(cachePct + "%")}
|
|
2356
|
-
${import_picocolors.default.dim("│")} Energy ${import_picocolors.default.bold(co2Str)} ${import_picocolors.default.dim(`(${regionStr} grid
|
|
2933
|
+
${import_picocolors.default.dim("│")} Energy ${import_picocolors.default.bold(co2Str)} ${import_picocolors.default.dim(`(${regionStr} grid)`)}
|
|
2934
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.dim(`Source: ${sourceLabel}`)}
|
|
2357
2935
|
${import_picocolors.default.dim("│")}
|
|
2358
2936
|
${import_picocolors.default.dim("│")} ${cacheVerdict} — ${cacheText.split(`
|
|
2359
2937
|
`).join(`
|
|
2360
2938
|
` + import_picocolors.default.dim("│") + " ")}
|
|
2361
2939
|
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2940
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgCyan(import_picocolors.default.black(" WHAT YOUR AGENTS CAN REACH ")))}
|
|
2941
|
+
${import_picocolors.default.dim("│")} Blast radius ${reachStr}
|
|
2942
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("Full map (deploy/push/write tools): outlier capabilities")}
|
|
2943
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2362
2944
|
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgYellow(import_picocolors.default.black(" YOUR LIMIT ")))}
|
|
2363
2945
|
${import_picocolors.default.dim("│")} AI cap ${import_picocolors.default.bold("70%")} ${import_picocolors.default.dim("· change with: outlier policy")}
|
|
2364
2946
|
${import_picocolors.default.dim("│")} Status ${policyStatus} ${import_picocolors.default.dim("·")} ${policyAction}
|
|
2947
|
+
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2948
|
+
${import_picocolors.default.dim("│")} ${import_picocolors.default.bold(import_picocolors.default.bgGreen(import_picocolors.default.black(" WHAT TO DO ")))}
|
|
2949
|
+
${insightLines}
|
|
2365
2950
|
${import_picocolors.default.dim("├────────────────────────────────────────────────────────")}
|
|
2366
2951
|
${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("Numbers are local estimates — authorship is a proxy and")}
|
|
2367
2952
|
${import_picocolors.default.dim("│")} ${import_picocolors.default.dim("carbon is rough. How it works: outlier --help")}
|
|
@@ -2375,27 +2960,93 @@ Conservative Floor: ${color(nmPct + "%")}`, "Git Authorship Breakdown");
|
|
|
2375
2960
|
console.error(import_picocolors.default.red(e.message));
|
|
2376
2961
|
}
|
|
2377
2962
|
} else if (action === "capabilities") {
|
|
2378
|
-
s.start("
|
|
2963
|
+
s.start("Mapping what your agents can reach...");
|
|
2379
2964
|
try {
|
|
2380
2965
|
const caps = await getCapabilitiesStats();
|
|
2381
|
-
s.stop("
|
|
2382
|
-
|
|
2966
|
+
s.stop("Reach map complete");
|
|
2967
|
+
const radiusColor = caps.blastRadius === "CRITICAL" ? import_picocolors.default.red : caps.blastRadius === "HIGH" ? import_picocolors.default.red : caps.blastRadius === "MEDIUM" ? import_picocolors.default.yellow : import_picocolors.default.green;
|
|
2968
|
+
const order = ["money", "exec", "deploy", "write-remote", "write-local", "data", "network", "model", "read"];
|
|
2969
|
+
const reachLabel = {
|
|
2970
|
+
money: "can move money",
|
|
2971
|
+
exec: "can run shell",
|
|
2972
|
+
deploy: "can deploy",
|
|
2973
|
+
"write-remote": "can push to repos",
|
|
2974
|
+
"write-local": "can write files",
|
|
2975
|
+
data: "data stores",
|
|
2976
|
+
network: "network",
|
|
2977
|
+
model: "models",
|
|
2978
|
+
read: "read-only"
|
|
2979
|
+
};
|
|
2980
|
+
const riskyReaches = new Set(["money", "exec", "deploy", "write-remote", "write-local"]);
|
|
2981
|
+
const toolLines = caps.mcps.length === 0 ? " None detected" : order.filter((r2) => caps.mcps.some((m2) => m2.reach === r2)).map((r2) => {
|
|
2982
|
+
const names = caps.mcps.filter((m2) => m2.reach === r2).map((m2) => m2.name).join(", ");
|
|
2983
|
+
const tag = riskyReaches.has(r2) ? import_picocolors.default.red(`[${reachLabel[r2]}]`) : import_picocolors.default.dim(`[${reachLabel[r2]}]`);
|
|
2984
|
+
return ` ${tag} ${names}`;
|
|
2985
|
+
}).join(`
|
|
2986
|
+
`);
|
|
2987
|
+
note(`${import_picocolors.default.bold("BLAST RADIUS:")} ${radiusColor(import_picocolors.default.bold(caps.blastRadius))} ${import_picocolors.default.dim("— if an agent or a prompt injection drives your tools")}
|
|
2988
|
+
${caps.blastReasons.length ? caps.blastReasons.map((r2) => ` ${import_picocolors.default.red("•")} ${r2}`).join(`
|
|
2989
|
+
`) : import_picocolors.default.green(" • read-only — limited reach")}
|
|
2383
2990
|
|
|
2384
|
-
|
|
2385
|
-
${
|
|
2386
|
-
`)) : " None"}
|
|
2991
|
+
${import_picocolors.default.bold(`What your agents can reach (${caps.mcps.length} MCP tools):`)}
|
|
2992
|
+
${toolLines}
|
|
2387
2993
|
|
|
2388
|
-
|
|
2389
|
-
${caps.
|
|
2390
|
-
|
|
2994
|
+
${import_picocolors.default.bold("Automation & agents:")}
|
|
2995
|
+
Hooks that fire for you: ${caps.hooks.length ? import_picocolors.default.yellow(caps.hooks.join(", ")) : "none"}
|
|
2996
|
+
Sub-agents: ${caps.subagents} Skills: ${caps.skills.length} Orchestration policy: ${caps.hasOrchestration ? import_picocolors.default.green("yes") : import_picocolors.default.yellow("no")}
|
|
2391
2997
|
|
|
2392
|
-
${import_picocolors.default.
|
|
2393
|
-
This repository provides agents with ${caps.mcps.length} toolsets and ${caps.skills.length} skills.
|
|
2394
|
-
${caps.skills.length > 5 ? import_picocolors.default.red("⚠ High Surface Area: Ensure strict authorship review is enabled.") : import_picocolors.default.green("✓ Low Surface Area: Risk contained.")}`, "AI Capabilities Map");
|
|
2998
|
+
${import_picocolors.default.dim("This is your attack surface. Fewer write/deploy tools per session = smaller blast radius.")}`, "Agent Reach & Blast Radius");
|
|
2395
2999
|
} catch (e) {
|
|
2396
3000
|
s.stop("Audit failed");
|
|
2397
3001
|
console.error(import_picocolors.default.red(e.message));
|
|
2398
3002
|
}
|
|
3003
|
+
} else if (action === "aggregate") {
|
|
3004
|
+
const dir = process.argv[3];
|
|
3005
|
+
if (!dir || !existsSync4(dir)) {
|
|
3006
|
+
console.error(import_picocolors.default.red("Usage: outlier aggregate <folder-of-json-audits>"));
|
|
3007
|
+
console.log(import_picocolors.default.dim(" Each dev: outlier --json > team/<name>.json then: outlier aggregate team/"));
|
|
3008
|
+
process.exit(1);
|
|
3009
|
+
}
|
|
3010
|
+
const r2 = aggregateDir(dir);
|
|
3011
|
+
note(`Developers: ${import_picocolors.default.bold(String(r2.developers))}
|
|
3012
|
+
Avg AI authorship: ${import_picocolors.default.bold(r2.avgAiPercent !== null ? r2.avgAiPercent + "%" : "—")} Max: ${r2.maxAiPercent !== null ? r2.maxAiPercent + "%" : "—"}
|
|
3013
|
+
Over their limit: ${r2.overLimit > 0 ? import_picocolors.default.red(String(r2.overLimit)) : import_picocolors.default.green("0")}
|
|
3014
|
+
Team spend (est): ${import_picocolors.default.bold("$" + r2.totalEstUsd)}
|
|
3015
|
+
Worst blast radius:${" "}${r2.worstBlastRadius === "HIGH" || r2.worstBlastRadius === "CRITICAL" ? import_picocolors.default.red(r2.worstBlastRadius) : import_picocolors.default.yellow(r2.worstBlastRadius)} (${r2.reachWriteDeploy} write/deploy tools across the team)
|
|
3016
|
+
${r2.notes.length ? `
|
|
3017
|
+
` + r2.notes.map((n2) => `${import_picocolors.default.yellow("•")} ${n2}`).join(`
|
|
3018
|
+
`) : ""}`, "Team Rollup (local-first — nothing was exported)");
|
|
3019
|
+
} else if (action === "preflight") {
|
|
3020
|
+
s.start("Pre-flight check...");
|
|
3021
|
+
const gitStats = await getAuthorshipStats().catch(() => null);
|
|
3022
|
+
const carbon = await getCarbonStats().catch(() => null);
|
|
3023
|
+
const caps = await getCapabilitiesStats().catch(() => null);
|
|
3024
|
+
s.stop("Ready for take-off");
|
|
3025
|
+
const aiPct = gitStats ? (gitStats.ratio * 100).toFixed(0) : "—";
|
|
3026
|
+
const youPct = gitStats ? (100 - gitStats.ratio * 100).toFixed(0) : "—";
|
|
3027
|
+
const blast = caps ? caps.blastRadius : "UNKNOWN";
|
|
3028
|
+
const blastCol = blast === "CRITICAL" || blast === "HIGH" ? import_picocolors.default.red : blast === "MEDIUM" ? import_picocolors.default.yellow : import_picocolors.default.green;
|
|
3029
|
+
const risky = caps ? caps.mcps.filter((m2) => ["money", "exec", "deploy", "write-remote", "write-local"].includes(m2.reach)).length : 0;
|
|
3030
|
+
const spend = carbon ? `$${carbon.estUsd.toFixed(0)}` : "—";
|
|
3031
|
+
const cachePct = carbon && carbon.totalTokens ? (carbon.cacheReadTokens / carbon.totalTokens * 100).toFixed(0) + "%" : "—";
|
|
3032
|
+
const insights = deriveInsights({ authorship: gitStats, carbon, caps, policyCap: 0.7 });
|
|
3033
|
+
const sevCol = (sv) => sv === "critical" ? import_picocolors.default.red : sv === "warn" ? import_picocolors.default.yellow : sv === "good" ? import_picocolors.default.green : import_picocolors.default.cyan;
|
|
3034
|
+
const sevMk = (sv) => sv === "critical" ? "✗" : sv === "warn" ? "⚠" : sv === "good" ? "✓" : "i";
|
|
3035
|
+
const actionLines = insights.slice(0, 3).map((ins) => ` ${sevCol(ins.severity)(sevMk(ins.severity))} ${import_picocolors.default.cyan("→")} ${ins.action}`).join(`
|
|
3036
|
+
`);
|
|
3037
|
+
console.log("");
|
|
3038
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.cyan(" ✈ PRE-FLIGHT")) + import_picocolors.default.dim(` · ${process.cwd().split("/").pop()}`));
|
|
3039
|
+
console.log(import_picocolors.default.dim(" ────────────────────────────────────────────────────"));
|
|
3040
|
+
console.log(` ${import_picocolors.default.bold("Reach")} ${blastCol(import_picocolors.default.bold(blast))}` + (caps ? import_picocolors.default.dim(` · ${caps.mcps.length} tools, ${risky} can write/deploy`) : ""));
|
|
3041
|
+
console.log(` ${import_picocolors.default.bold("Skill")} AI wrote ${import_picocolors.default.bold(aiPct + "%")} · you own ${import_picocolors.default.bold(youPct + "%")}`);
|
|
3042
|
+
console.log(` ${import_picocolors.default.bold("Spend")} ${import_picocolors.default.bold(spend)} · ${cachePct} re-sent context`);
|
|
3043
|
+
console.log("");
|
|
3044
|
+
console.log(import_picocolors.default.bold(" Before you delegate:"));
|
|
3045
|
+
console.log(actionLines);
|
|
3046
|
+
console.log("");
|
|
3047
|
+
const agent = detectAgent();
|
|
3048
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.magenta(" ✓ Ready? ")) + "Start your session: " + import_picocolors.default.bold(agent || "your AI agent"));
|
|
3049
|
+
console.log("");
|
|
2399
3050
|
} else if (action === "policy") {
|
|
2400
3051
|
const tier = await select({
|
|
2401
3052
|
message: "Select the governance tier to configure:",
|
|
@@ -2425,8 +3076,8 @@ ${caps.skills.length > 5 ? import_picocolors.default.red("⚠ High Surface Area:
|
|
|
2425
3076
|
process.exit(0);
|
|
2426
3077
|
}
|
|
2427
3078
|
s.start(`Applying ${tier} policy guardrails...`);
|
|
2428
|
-
const gitDir =
|
|
2429
|
-
const isRepo =
|
|
3079
|
+
const gitDir = join6(process.cwd(), ".git");
|
|
3080
|
+
const isRepo = existsSync4(gitDir);
|
|
2430
3081
|
if (!isRepo) {
|
|
2431
3082
|
console.error(import_picocolors.default.red("Must be run inside a git repository"));
|
|
2432
3083
|
process.exit(1);
|
|
@@ -2434,8 +3085,8 @@ ${caps.skills.length > 5 ? import_picocolors.default.red("⚠ High Surface Area:
|
|
|
2434
3085
|
const isStrict = process.argv.includes("--strict");
|
|
2435
3086
|
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%)."
|
|
2436
3087
|
echo "Take a moment to review your recent architectural decisions. Ensure you still understand the system."`;
|
|
2437
|
-
const hookPath =
|
|
2438
|
-
if (
|
|
3088
|
+
const hookPath = join6(gitDir, "hooks", "pre-commit");
|
|
3089
|
+
if (existsSync4(hookPath)) {
|
|
2439
3090
|
const { copyFileSync } = __require("fs");
|
|
2440
3091
|
copyFileSync(hookPath, `${hookPath}.backup`);
|
|
2441
3092
|
}
|
|
@@ -2466,16 +3117,31 @@ Rule 1: ${import_picocolors.default.green(`AI Authorship must not exceed $
|
|
|
2466
3117
|
Rule 2: ${import_picocolors.default.green("Require human review on consecutive high-AI sprints")}
|
|
2467
3118
|
Enforcement: ${import_picocolors.default.cyan("Local pre-commit hook installed (backup created)")}`, "Active Governance Policy");
|
|
2468
3119
|
} else if (tier === "regulatory") {
|
|
2469
|
-
s.start("Generating
|
|
2470
|
-
await
|
|
2471
|
-
const
|
|
2472
|
-
|
|
3120
|
+
s.start("Generating human-oversight audit record (Decree 142)...");
|
|
3121
|
+
const gitStats = await getAuthorshipStats().catch(() => null);
|
|
3122
|
+
const caps = await getCapabilitiesStats().catch(() => null);
|
|
3123
|
+
const humanReviewRate = gitStats ? +(1 - gitStats.ratio).toFixed(3) : null;
|
|
3124
|
+
const oversightOk = humanReviewRate !== null && humanReviewRate >= 0.3;
|
|
3125
|
+
const record = {
|
|
3126
|
+
timestamp: new Date().toISOString(),
|
|
3127
|
+
policy: "Vietnam Decree 142/2026 — human oversight of high-risk AI",
|
|
3128
|
+
repo: process.cwd().split("/").pop(),
|
|
3129
|
+
humanAuthorshipRate: humanReviewRate,
|
|
3130
|
+
aiAuthorshipRate: gitStats ? +gitStats.ratio.toFixed(3) : null,
|
|
3131
|
+
humanOversight: oversightOk ? "present" : "insufficient",
|
|
3132
|
+
agentBlastRadius: caps ? caps.blastRadius : "unknown",
|
|
3133
|
+
dataExported: false,
|
|
3134
|
+
note: "Derived from local git history only. No code, prompts, or citizen data leave the machine. Authorship is a proxy for human oversight."
|
|
3135
|
+
};
|
|
3136
|
+
const reportPath = join6(process.cwd(), "outlier-audit-report.jsonl");
|
|
3137
|
+
writeFileSync(reportPath, JSON.stringify(record) + `
|
|
2473
3138
|
`);
|
|
2474
|
-
s.stop("Audit
|
|
2475
|
-
note(`Jurisdiction: ${import_picocolors.default.bold("Vietnam (Decree 142)")}
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
3139
|
+
s.stop("Audit record written");
|
|
3140
|
+
note(`Jurisdiction: ${import_picocolors.default.bold("Vietnam (Decree 142/2026)")}
|
|
3141
|
+
Human oversight: ${oversightOk ? import_picocolors.default.green("present") : import_picocolors.default.red("insufficient")} ${import_picocolors.default.dim(`(${humanReviewRate !== null ? (humanReviewRate * 100).toFixed(0) + "% human-authored" : "no git history"})`)}
|
|
3142
|
+
Agent reach: ${caps ? caps.blastRadius : "unknown"}
|
|
3143
|
+
Privacy: ${import_picocolors.default.green("preserved — nothing exported")}
|
|
3144
|
+
Artifact: ${import_picocolors.default.cyan(reportPath)}`, "Human-Oversight Audit Record");
|
|
2479
3145
|
}
|
|
2480
3146
|
} else if (action === "participate") {
|
|
2481
3147
|
s.start("Connecting to the Outlier research project...");
|
|
@@ -2547,6 +3213,28 @@ ${import_picocolors.default.bold("Submit here (and drop your screenshot!):")} ${
|
|
|
2547
3213
|
■ Next 5-10 Years (The 1M+ LOC Crisis)`));
|
|
2548
3214
|
console.log(` When an agent introduces a fatal state bug in a monolithic architecture, human reviewers will lack the muscle memory to debug it. Outlier measures this exact sovereignty erosion.
|
|
2549
3215
|
`);
|
|
3216
|
+
const gitStats = await getAuthorshipStats().catch(() => null);
|
|
3217
|
+
const carbon = await getCarbonStats().catch(() => null);
|
|
3218
|
+
if (gitStats || carbon) {
|
|
3219
|
+
const { projectEconomics: projectEconomics2 } = await Promise.resolve().then(() => (init_economics(), exports_economics));
|
|
3220
|
+
const teamSize = (() => {
|
|
3221
|
+
const i2 = process.argv.indexOf("--team");
|
|
3222
|
+
return i2 > -1 ? parseInt(process.argv[i2 + 1] || "1") || 1 : 1;
|
|
3223
|
+
})();
|
|
3224
|
+
const econ = projectEconomics2({
|
|
3225
|
+
aiRatio: gitStats ? gitStats.ratio : 0,
|
|
3226
|
+
estUsdSession: carbon ? carbon.estUsd : 0,
|
|
3227
|
+
teamSize
|
|
3228
|
+
});
|
|
3229
|
+
console.log(import_picocolors.default.bold(import_picocolors.default.bgMagenta(" THE MACRO SHADOW ")) + import_picocolors.default.dim(` (team of ${teamSize} — set with --team N)`));
|
|
3230
|
+
for (const p2 of econ.projections) {
|
|
3231
|
+
console.log(` ${import_picocolors.default.bold(p2.label.padEnd(20))} ${import_picocolors.default.cyan(p2.value)}`);
|
|
3232
|
+
console.log(` ${import_picocolors.default.dim(" " + p2.note)}`);
|
|
3233
|
+
}
|
|
3234
|
+
console.log(`
|
|
3235
|
+
` + import_picocolors.default.dim(" " + econ.assumptions) + `
|
|
3236
|
+
`);
|
|
3237
|
+
}
|
|
2550
3238
|
} else if (action === "knowledge") {
|
|
2551
3239
|
console.log(`
|
|
2552
3240
|
` + import_picocolors.default.bold(import_picocolors.default.bgBlue(" CORE LITERATURE & REFERENCES ")) + `
|
|
@@ -2560,12 +3248,13 @@ Read the full academic foundation at: ${import_picocolors.default.underline("htt
|
|
|
2560
3248
|
}
|
|
2561
3249
|
outro("Done — nothing left your machine. (How it works: outlier --help)");
|
|
2562
3250
|
if (typeof finalReceipt !== "undefined" && finalReceipt) {
|
|
2563
|
-
|
|
3251
|
+
const boxed = closeBox(finalReceipt);
|
|
3252
|
+
console.log(boxed);
|
|
2564
3253
|
if (process.argv.includes("--save")) {
|
|
2565
3254
|
const stripAnsi = (s2) => s2.replace(/\x1b\[[0-9;]*m/g, "");
|
|
2566
|
-
const savePath =
|
|
3255
|
+
const savePath = join6(process.cwd(), "outlier-audit.txt");
|
|
2567
3256
|
try {
|
|
2568
|
-
writeFileSync(savePath, stripAnsi(
|
|
3257
|
+
writeFileSync(savePath, stripAnsi(boxed).trimStart() + `
|
|
2569
3258
|
`);
|
|
2570
3259
|
console.log(import_picocolors.default.dim(`
|
|
2571
3260
|
\uD83D\uDCBE Saved to ${savePath}`));
|