forkit-ai-footprints 0.2.0
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/LICENSE +21 -0
- package/PRIVACY.md +150 -0
- package/README.md +313 -0
- package/STATUS.md +136 -0
- package/dist/agents.d.ts +22 -0
- package/dist/agents.js +281 -0
- package/dist/aggregate.d.ts +28 -0
- package/dist/aggregate.js +151 -0
- package/dist/assets/forkit-icon-dark.png +0 -0
- package/dist/assets/forkit-icon-light.png +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Info.plist +5 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/MacOS/Forkit AI Footprint +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/ForkitAIFootprint.icns +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/ForkitStatusTemplate.png +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/agents.d.ts +22 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/agents.js +281 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.d.ts +28 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.js +151 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/assets/forkit-icon-dark.png +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/assets/forkit-icon-light.png +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/census.d.ts +3 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/census.js +196 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.d.ts +32 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.js +404 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.d.ts +14 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.js +71 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.d.ts +8 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.js +45 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.d.ts +44 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.js +102 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.d.ts +11 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.js +226 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.d.ts +7 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.js +78 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.d.ts +4 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.js +16 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.d.ts +22 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.js +58 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.d.ts +13 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.js +76 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.d.ts +19 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.js +81 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/locales.json +272 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.d.ts +277 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.js +55 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.d.ts +9 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.js +93 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.d.ts +99 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.js +285 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.d.ts +34 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.js +88 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.d.ts +6 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.js +24 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.d.ts +9 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.js +71 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.d.ts +12 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.js +171 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.d.ts +10 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.js +68 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.d.ts +17 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.js +52 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.d.ts +5 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.js +66 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.d.ts +7 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.js +66 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.d.ts +21 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.js +308 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.d.ts +75 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.js +167 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.d.ts +35 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.js +67 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.d.ts +9 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.js +106 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.d.ts +166 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.js +3 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.d.ts +4 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.js +13 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.d.ts +76 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.js +366 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/license +9 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/package.json +44 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/readme.md +56 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/vendor/fastlist-0.3.0-x86.exe +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/package.json +6 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/runtime/node +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/_CodeSignature/CodeResources +931 -0
- package/dist/census.d.ts +3 -0
- package/dist/census.js +196 -0
- package/dist/cli.d.ts +32 -0
- package/dist/cli.js +404 -0
- package/dist/doctor.d.ts +14 -0
- package/dist/doctor.js +71 -0
- package/dist/endpoints.d.ts +8 -0
- package/dist/endpoints.js +45 -0
- package/dist/evaluate.d.ts +44 -0
- package/dist/evaluate.js +102 -0
- package/dist/filesystem.d.ts +11 -0
- package/dist/filesystem.js +226 -0
- package/dist/format.d.ts +7 -0
- package/dist/format.js +78 -0
- package/dist/hash.d.ts +4 -0
- package/dist/hash.js +16 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +58 -0
- package/dist/insights.d.ts +13 -0
- package/dist/insights.js +76 -0
- package/dist/local-device.d.ts +19 -0
- package/dist/local-device.js +81 -0
- package/dist/locales.json +272 -0
- package/dist/localization.d.ts +277 -0
- package/dist/localization.js +55 -0
- package/dist/mcp.d.ts +9 -0
- package/dist/mcp.js +93 -0
- package/dist/monitor.d.ts +99 -0
- package/dist/monitor.js +285 -0
- package/dist/providers/base.d.ts +34 -0
- package/dist/providers/base.js +88 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.js +24 -0
- package/dist/providers/lmstudio.d.ts +9 -0
- package/dist/providers/lmstudio.js +71 -0
- package/dist/providers/ollama.d.ts +12 -0
- package/dist/providers/ollama.js +171 -0
- package/dist/providers/openai-compatible.d.ts +10 -0
- package/dist/providers/openai-compatible.js +68 -0
- package/dist/resource-evidence.d.ts +17 -0
- package/dist/resource-evidence.js +52 -0
- package/dist/runtime-activity.d.ts +5 -0
- package/dist/runtime-activity.js +66 -0
- package/dist/runtime-identity.d.ts +7 -0
- package/dist/runtime-identity.js +66 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.js +308 -0
- package/dist/share-page.d.ts +75 -0
- package/dist/share-page.js +167 -0
- package/dist/sharing.d.ts +35 -0
- package/dist/sharing.js +67 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.js +106 -0
- package/dist/types.d.ts +166 -0
- package/dist/types.js +3 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +13 -0
- package/docs/GLOBAL_DISTRIBUTION.md +79 -0
- package/docs/MACOS_ACCURACY_GATE.md +140 -0
- package/docs/MACOS_TESTER_GUIDE.md +88 -0
- package/examples/macos-truth.template.json +10 -0
- package/package.json +75 -0
- package/release/channels.json +41 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.startAiFootprintsServer = startAiFootprintsServer;
|
|
7
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
9
|
+
const census_1 = require("./census");
|
|
10
|
+
const agents_1 = require("./agents");
|
|
11
|
+
const share_page_1 = require("./share-page");
|
|
12
|
+
const local_device_1 = require("./local-device");
|
|
13
|
+
const monitor_1 = require("./monitor");
|
|
14
|
+
const providers_1 = require("./providers");
|
|
15
|
+
const runtime_activity_1 = require("./runtime-activity");
|
|
16
|
+
const sharing_1 = require("./sharing");
|
|
17
|
+
const insights_1 = require("./insights");
|
|
18
|
+
const localization_1 = require("./localization");
|
|
19
|
+
function securityHeaders(contentType) {
|
|
20
|
+
return {
|
|
21
|
+
'cache-control': 'no-store',
|
|
22
|
+
'content-security-policy': "default-src 'none'; img-src data:; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'self'",
|
|
23
|
+
'content-type': contentType,
|
|
24
|
+
'referrer-policy': 'no-referrer',
|
|
25
|
+
'x-content-type-options': 'nosniff',
|
|
26
|
+
'x-frame-options': 'SAMEORIGIN',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function sendText(response, status, contentType, body) {
|
|
30
|
+
response.writeHead(status, securityHeaders(contentType));
|
|
31
|
+
response.end(body);
|
|
32
|
+
}
|
|
33
|
+
function sendJson(response, status, value) {
|
|
34
|
+
sendText(response, status, 'application/json; charset=utf-8', JSON.stringify(value));
|
|
35
|
+
}
|
|
36
|
+
async function startAiFootprintsServer(options = {}) {
|
|
37
|
+
const hostname = options.hostname ?? '127.0.0.1';
|
|
38
|
+
const requestedPort = options.port ?? 47811;
|
|
39
|
+
const scan = options.scan ?? (() => (0, census_1.runCensus)());
|
|
40
|
+
const recordScan = options.recordScan ?? ((generatedAt) => (0, local_device_1.recordLocalScan)({ now: () => new Date(generatedAt) }));
|
|
41
|
+
const sessionToken = node_crypto_1.default.randomBytes(24).toString('hex');
|
|
42
|
+
const nativeToken = options.nativeToken ?? process.env.FORKIT_AI_FOOTPRINTS_NATIVE_TOKEN ?? null;
|
|
43
|
+
const runtimeProviders = (0, providers_1.createDefaultProviders)();
|
|
44
|
+
let loadedRuntimeCache = new Set();
|
|
45
|
+
let loadedRuntimeCacheAt = 0;
|
|
46
|
+
const monitor = options.monitor ?? new monitor_1.ActivityMonitor({
|
|
47
|
+
classifyProcesses: async (entries) => {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
if (now - loadedRuntimeCacheAt >= 3000) {
|
|
50
|
+
loadedRuntimeCache = await (0, runtime_activity_1.loadedRuntimeSignatures)(runtimeProviders, new Date(now).toISOString());
|
|
51
|
+
loadedRuntimeCacheAt = now;
|
|
52
|
+
}
|
|
53
|
+
return [
|
|
54
|
+
...(0, agents_1.classifyAgentProcessTrees)(entries, process.pid),
|
|
55
|
+
...(0, runtime_activity_1.classifyLoadedRuntimeProcesses)(entries, loadedRuntimeCache, process.pid),
|
|
56
|
+
];
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
let currentReport = await scan();
|
|
60
|
+
let localDevice = await recordScan(currentReport.generated_at);
|
|
61
|
+
currentReport.privacy.local_state_written = true;
|
|
62
|
+
currentReport.privacy.local_state_scope = 'device-journal-only';
|
|
63
|
+
let scanning = false;
|
|
64
|
+
const streams = new Set();
|
|
65
|
+
let origin = '';
|
|
66
|
+
let closing = null;
|
|
67
|
+
let currentLocale = 'en';
|
|
68
|
+
function browserAuthorized(request) {
|
|
69
|
+
return request.headers.origin === origin
|
|
70
|
+
&& request.headers['x-forkit-footprints-session'] === sessionToken;
|
|
71
|
+
}
|
|
72
|
+
function nativeAuthorized(request) {
|
|
73
|
+
return typeof nativeToken === 'string' && nativeToken.length >= 32
|
|
74
|
+
&& request.headers['x-forkit-footprints-native'] === nativeToken;
|
|
75
|
+
}
|
|
76
|
+
function stopStreams() {
|
|
77
|
+
for (const stream of streams) {
|
|
78
|
+
clearInterval(stream.timer);
|
|
79
|
+
stream.response.end();
|
|
80
|
+
}
|
|
81
|
+
streams.clear();
|
|
82
|
+
}
|
|
83
|
+
function browserSnapshot(snapshot = monitor.snapshot()) {
|
|
84
|
+
return {
|
|
85
|
+
...snapshot,
|
|
86
|
+
insights: (0, insights_1.buildLocalInsights)(snapshot, {
|
|
87
|
+
model_record_count: currentReport.summary.model_count,
|
|
88
|
+
confirmed_running_model_count: currentReport.summary.confirmed_running_model_count,
|
|
89
|
+
}, 60, currentLocale).map((insight) => insight.text),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const server = node_http_1.default.createServer(async (request, response) => {
|
|
93
|
+
const host = request.headers.host ?? '';
|
|
94
|
+
if (!origin || host !== new URL(origin).host) {
|
|
95
|
+
sendText(response, 421, 'text/plain; charset=utf-8', 'Invalid local host.');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const requestUrl = new URL(request.url ?? '/', origin);
|
|
99
|
+
const pathname = requestUrl.pathname;
|
|
100
|
+
if (request.method === 'GET' && (pathname === '/' || pathname === '/index.html')) {
|
|
101
|
+
const requestedLocale = requestUrl.searchParams.get('lang');
|
|
102
|
+
currentLocale = requestedLocale === 'en' || requestedLocale === 'de'
|
|
103
|
+
? requestedLocale
|
|
104
|
+
: (0, localization_1.normalizeLocale)(request.headers['accept-language']);
|
|
105
|
+
sendText(response, 200, 'text/html; charset=utf-8', (0, share_page_1.renderCensusSharePage)(currentReport, {
|
|
106
|
+
localDeviceLabel: localDevice.device_label,
|
|
107
|
+
locale: currentLocale,
|
|
108
|
+
rescan: {
|
|
109
|
+
endpoint: '/api/scan',
|
|
110
|
+
monitor_start_endpoint: '/api/monitor/start',
|
|
111
|
+
monitor_stop_endpoint: '/api/monitor/stop',
|
|
112
|
+
monitor_stream_endpoint: '/api/monitor/stream',
|
|
113
|
+
monitor_clear_endpoint: '/api/monitor/clear',
|
|
114
|
+
contribution_preview_endpoint: '/api/contribution/preview',
|
|
115
|
+
locale_endpoint: '/api/ui/locale',
|
|
116
|
+
session_token: sessionToken,
|
|
117
|
+
},
|
|
118
|
+
}));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const browserControl = pathname.startsWith('/api/') && browserAuthorized(request);
|
|
122
|
+
const nativeControl = pathname.startsWith('/api/native/') && nativeAuthorized(request);
|
|
123
|
+
if (request.method === 'POST' && pathname === '/api/monitor/stream') {
|
|
124
|
+
if (!browserControl) {
|
|
125
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
response.writeHead(200, {
|
|
129
|
+
...securityHeaders('application/x-ndjson; charset=utf-8'),
|
|
130
|
+
'content-security-policy': "default-src 'none'",
|
|
131
|
+
});
|
|
132
|
+
const send = () => response.write(`${JSON.stringify(browserSnapshot())}\n`);
|
|
133
|
+
send();
|
|
134
|
+
const timer = setInterval(send, 750);
|
|
135
|
+
timer.unref();
|
|
136
|
+
const stream = { timer, response };
|
|
137
|
+
streams.add(stream);
|
|
138
|
+
request.on('close', () => {
|
|
139
|
+
clearInterval(timer);
|
|
140
|
+
streams.delete(stream);
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (request.method === 'POST' && pathname === '/api/scan') {
|
|
145
|
+
if (!browserControl) {
|
|
146
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (scanning) {
|
|
150
|
+
sendJson(response, 409, { error: 'SCAN_IN_PROGRESS' });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
scanning = true;
|
|
154
|
+
try {
|
|
155
|
+
currentReport = await scan();
|
|
156
|
+
localDevice = await recordScan(currentReport.generated_at);
|
|
157
|
+
currentReport.privacy.local_state_written = true;
|
|
158
|
+
currentReport.privacy.local_state_scope = 'device-journal-only';
|
|
159
|
+
sendJson(response, 200, (0, share_page_1.buildLocalScanView)(currentReport));
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
sendJson(response, 500, { error: 'LOCAL_SCAN_FAILED' });
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
scanning = false;
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const startPath = pathname === '/api/monitor/start' || pathname === '/api/native/start';
|
|
170
|
+
if (request.method === 'POST' && startPath) {
|
|
171
|
+
if (!(browserControl || nativeControl)) {
|
|
172
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const snapshot = await monitor.start();
|
|
177
|
+
sendJson(response, 200, nativeControl ? snapshot : browserSnapshot(snapshot));
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
sendJson(response, 500, { error: 'MONITOR_START_FAILED' });
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const stopPath = pathname === '/api/monitor/stop' || pathname === '/api/native/stop';
|
|
185
|
+
if (request.method === 'POST' && stopPath) {
|
|
186
|
+
if (!(browserControl || nativeControl)) {
|
|
187
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const snapshot = monitor.stop();
|
|
191
|
+
sendJson(response, 200, nativeControl ? snapshot : browserSnapshot(snapshot));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (request.method === 'POST' && pathname === '/api/monitor/clear') {
|
|
195
|
+
if (!browserControl) {
|
|
196
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
sendJson(response, 200, browserSnapshot(monitor.clearHistory()));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (request.method === 'POST' && pathname === '/api/ui/locale') {
|
|
203
|
+
if (!browserControl) {
|
|
204
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
let raw = '';
|
|
208
|
+
for await (const chunk of request) {
|
|
209
|
+
raw += String(chunk);
|
|
210
|
+
if (raw.length > 128) {
|
|
211
|
+
sendJson(response, 413, { error: 'INVALID_LOCALE' });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const value = JSON.parse(raw);
|
|
217
|
+
if (value.locale !== 'en' && value.locale !== 'de')
|
|
218
|
+
throw new Error('INVALID_LOCALE');
|
|
219
|
+
currentLocale = value.locale;
|
|
220
|
+
sendJson(response, 200, { locale: currentLocale });
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
sendJson(response, 400, { error: 'INVALID_LOCALE' });
|
|
224
|
+
}
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (request.method === 'POST' && pathname === '/api/contribution/preview') {
|
|
228
|
+
if (!browserControl) {
|
|
229
|
+
sendJson(response, 403, { error: 'LOCAL_SESSION_REQUIRED' });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
sendJson(response, 200, (0, sharing_1.buildAnonymousAiFootprintPreview)(currentReport, monitor.snapshot()));
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
sendJson(response, 409, { error: error instanceof Error ? error.message : 'CONTRIBUTION_PREVIEW_UNAVAILABLE' });
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (request.method === 'POST' && pathname === '/api/native/status') {
|
|
241
|
+
if (!nativeControl) {
|
|
242
|
+
sendJson(response, 403, { error: 'NATIVE_CONTROL_REQUIRED' });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
sendJson(response, 200, { ...monitor.snapshot(), ui_locale: currentLocale });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (request.method === 'POST' && pathname === '/api/native/quit') {
|
|
249
|
+
if (!nativeControl) {
|
|
250
|
+
sendJson(response, 403, { error: 'NATIVE_CONTROL_REQUIRED' });
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const summary = monitor.stop();
|
|
254
|
+
sendJson(response, 200, summary);
|
|
255
|
+
setImmediate(() => { void closeService(); });
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
sendText(response, 404, 'text/plain; charset=utf-8', 'Not found.');
|
|
259
|
+
});
|
|
260
|
+
async function listen(port) {
|
|
261
|
+
await new Promise((resolve, reject) => {
|
|
262
|
+
const onError = (error) => {
|
|
263
|
+
server.off('listening', onListening);
|
|
264
|
+
reject(error);
|
|
265
|
+
};
|
|
266
|
+
const onListening = () => {
|
|
267
|
+
server.off('error', onError);
|
|
268
|
+
resolve();
|
|
269
|
+
};
|
|
270
|
+
server.once('error', onError);
|
|
271
|
+
server.once('listening', onListening);
|
|
272
|
+
server.listen(port, hostname);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
await listen(requestedPort);
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
if (error.code !== 'EADDRINUSE' || requestedPort === 0)
|
|
280
|
+
throw error;
|
|
281
|
+
await listen(0);
|
|
282
|
+
}
|
|
283
|
+
const address = server.address();
|
|
284
|
+
origin = `http://${hostname}:${address.port}`;
|
|
285
|
+
function closeService() {
|
|
286
|
+
if (closing)
|
|
287
|
+
return closing;
|
|
288
|
+
closing = new Promise((resolve, reject) => {
|
|
289
|
+
monitor.stop();
|
|
290
|
+
stopStreams();
|
|
291
|
+
if (!server.listening) {
|
|
292
|
+
resolve();
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
296
|
+
server.closeIdleConnections();
|
|
297
|
+
});
|
|
298
|
+
return closing;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
server,
|
|
302
|
+
url: `${origin}/`,
|
|
303
|
+
sessionToken,
|
|
304
|
+
monitor,
|
|
305
|
+
close: closeService,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { CensusReport } from './types';
|
|
2
|
+
import { type UiLocale } from './localization';
|
|
3
|
+
export interface CensusShareSnapshot {
|
|
4
|
+
generated_date: string;
|
|
5
|
+
architecture_label: string;
|
|
6
|
+
model_record_count: number;
|
|
7
|
+
verified_runtime_count: number;
|
|
8
|
+
detected_agent_product_count: number;
|
|
9
|
+
detected_agent_process_count: number;
|
|
10
|
+
confirmed_running_model_count: number;
|
|
11
|
+
model_storage_bytes: number;
|
|
12
|
+
model_storage_decimal_display: string;
|
|
13
|
+
model_storage_binary_display: string;
|
|
14
|
+
model_storage_display: string;
|
|
15
|
+
model_storage_file_count: number;
|
|
16
|
+
model_storage_complete: boolean;
|
|
17
|
+
model_storage_measurement: 'recognized-logical-file-bytes';
|
|
18
|
+
external_request_count: 0;
|
|
19
|
+
product_version: string;
|
|
20
|
+
node_major: number;
|
|
21
|
+
}
|
|
22
|
+
export interface CensusLocalDetails {
|
|
23
|
+
agents: Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
kind: string;
|
|
26
|
+
process_count: number;
|
|
27
|
+
}>;
|
|
28
|
+
runtimes: Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
model_count: number;
|
|
31
|
+
loaded_model_count: number;
|
|
32
|
+
}>;
|
|
33
|
+
models: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
source: string;
|
|
36
|
+
loaded: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
tools: Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
status: 'configured' | 'online';
|
|
41
|
+
}>;
|
|
42
|
+
technical: {
|
|
43
|
+
runtime_probes: Array<{
|
|
44
|
+
name: string;
|
|
45
|
+
state: string;
|
|
46
|
+
error_code: string | null;
|
|
47
|
+
}>;
|
|
48
|
+
warnings: Array<{
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface LocalScanView extends CensusShareSnapshot {
|
|
55
|
+
local_details: CensusLocalDetails;
|
|
56
|
+
}
|
|
57
|
+
export interface LocalRescanOptions {
|
|
58
|
+
endpoint: string;
|
|
59
|
+
monitor_start_endpoint: string;
|
|
60
|
+
monitor_stop_endpoint: string;
|
|
61
|
+
monitor_stream_endpoint: string;
|
|
62
|
+
monitor_clear_endpoint: string;
|
|
63
|
+
contribution_preview_endpoint: string;
|
|
64
|
+
locale_endpoint: string;
|
|
65
|
+
session_token: string;
|
|
66
|
+
}
|
|
67
|
+
export interface AiFootprintPageOptions {
|
|
68
|
+
rescan?: LocalRescanOptions;
|
|
69
|
+
localDeviceLabel?: string;
|
|
70
|
+
locale?: UiLocale;
|
|
71
|
+
}
|
|
72
|
+
export declare function buildCensusShareSnapshot(report: CensusReport): CensusShareSnapshot;
|
|
73
|
+
export declare function buildLocalScanView(report: CensusReport): LocalScanView;
|
|
74
|
+
export declare function renderCensusSharePage(report: CensusReport, options?: AiFootprintPageOptions): string;
|
|
75
|
+
//# sourceMappingURL=share-page.d.ts.map
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildCensusShareSnapshot = buildCensusShareSnapshot;
|
|
7
|
+
exports.buildLocalScanView = buildLocalScanView;
|
|
8
|
+
exports.renderCensusSharePage = renderCensusSharePage;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const localization_1 = require("./localization");
|
|
12
|
+
function escapeHtml(value) {
|
|
13
|
+
return String(value).replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
14
|
+
}
|
|
15
|
+
function safeScriptJson(value) { return JSON.stringify(value).replaceAll('<', '\\u003c'); }
|
|
16
|
+
function formatDecimalStorage(bytes) {
|
|
17
|
+
if (bytes <= 0)
|
|
18
|
+
return '0 B';
|
|
19
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
20
|
+
let value = bytes;
|
|
21
|
+
let unit = 0;
|
|
22
|
+
while (unit < units.length - 1 && value >= 1000) {
|
|
23
|
+
value /= 1000;
|
|
24
|
+
unit += 1;
|
|
25
|
+
}
|
|
26
|
+
return `${value.toFixed(value < 10 && unit > 1 ? 2 : value < 100 ? 1 : 0)} ${units[unit]}`;
|
|
27
|
+
}
|
|
28
|
+
function formatBinaryStorage(bytes) {
|
|
29
|
+
if (bytes <= 0)
|
|
30
|
+
return '0 B';
|
|
31
|
+
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'];
|
|
32
|
+
let value = bytes;
|
|
33
|
+
let unit = 0;
|
|
34
|
+
while (unit < units.length - 1 && value >= 1024) {
|
|
35
|
+
value /= 1024;
|
|
36
|
+
unit += 1;
|
|
37
|
+
}
|
|
38
|
+
return `${value.toFixed(value < 10 && unit > 1 ? 2 : value < 100 ? 1 : 0)} ${units[unit]}`;
|
|
39
|
+
}
|
|
40
|
+
function validateRescanOptions(rescan) {
|
|
41
|
+
for (const value of [rescan.endpoint, rescan.monitor_start_endpoint, rescan.monitor_stop_endpoint, rescan.monitor_stream_endpoint, rescan.monitor_clear_endpoint, rescan.contribution_preview_endpoint, rescan.locale_endpoint]) {
|
|
42
|
+
if (!value.startsWith('/') || value.startsWith('//'))
|
|
43
|
+
throw new Error('INVALID_LOCAL_RESCAN_OPTIONS');
|
|
44
|
+
}
|
|
45
|
+
if (!/^[a-f0-9]{48}$/.test(rescan.session_token))
|
|
46
|
+
throw new Error('INVALID_LOCAL_RESCAN_OPTIONS');
|
|
47
|
+
}
|
|
48
|
+
function runtimeLabel(name) {
|
|
49
|
+
if (name === 'ollama')
|
|
50
|
+
return 'Ollama';
|
|
51
|
+
if (name === 'lmstudio')
|
|
52
|
+
return 'LM Studio';
|
|
53
|
+
if (name === 'openai-compatible')
|
|
54
|
+
return 'OpenAI-compatible';
|
|
55
|
+
return name;
|
|
56
|
+
}
|
|
57
|
+
function sourceLabel(model) {
|
|
58
|
+
if (model.runtime === 'ollama')
|
|
59
|
+
return 'Ollama';
|
|
60
|
+
if (model.runtime === 'lmstudio')
|
|
61
|
+
return 'LM Studio';
|
|
62
|
+
if (model.location_hint === 'huggingface-cache')
|
|
63
|
+
return 'Hugging Face cache';
|
|
64
|
+
return model.source === 'filesystem' ? 'Local model files' : runtimeLabel(model.runtime);
|
|
65
|
+
}
|
|
66
|
+
function iconDataUrl(file) {
|
|
67
|
+
try {
|
|
68
|
+
return `data:image/png;base64,${node_fs_1.default.readFileSync(node_path_1.default.join(__dirname, 'assets', file)).toString('base64')}`;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function buildCensusShareSnapshot(report) {
|
|
75
|
+
const decimal = formatDecimalStorage(report.summary.storage_bytes);
|
|
76
|
+
const binary = formatBinaryStorage(report.summary.storage_bytes);
|
|
77
|
+
return {
|
|
78
|
+
generated_date: new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'short', day: 'numeric', timeZone: 'UTC' }).format(new Date(report.generated_at)),
|
|
79
|
+
architecture_label: report.system.architecture === 'arm64' ? 'Apple Silicon' : report.system.architecture === 'x64' ? 'Intel Mac' : report.system.architecture,
|
|
80
|
+
model_record_count: report.summary.model_count,
|
|
81
|
+
verified_runtime_count: report.summary.available_runtime_count,
|
|
82
|
+
detected_agent_product_count: report.summary.agent_product_count,
|
|
83
|
+
detected_agent_process_count: report.summary.agent_process_count,
|
|
84
|
+
confirmed_running_model_count: report.summary.confirmed_running_model_count,
|
|
85
|
+
model_storage_bytes: report.summary.storage_bytes,
|
|
86
|
+
model_storage_decimal_display: decimal,
|
|
87
|
+
model_storage_binary_display: binary,
|
|
88
|
+
model_storage_display: decimal === binary ? decimal : `${decimal} · ${binary}`,
|
|
89
|
+
model_storage_file_count: report.summary.storage_file_count,
|
|
90
|
+
model_storage_complete: report.summary.storage_complete,
|
|
91
|
+
model_storage_measurement: report.summary.storage_measurement,
|
|
92
|
+
external_request_count: report.privacy.external_requests_made,
|
|
93
|
+
product_version: report.product_version,
|
|
94
|
+
node_major: report.system.node_major,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function buildLocalScanView(report) {
|
|
98
|
+
return {
|
|
99
|
+
...buildCensusShareSnapshot(report),
|
|
100
|
+
local_details: {
|
|
101
|
+
agents: report.agents.map((agent) => ({ name: agent.name, kind: agent.kind, process_count: agent.instance_count })),
|
|
102
|
+
runtimes: report.runtimes.filter((runtime) => runtime.name !== 'filesystem' && runtime.status === 'available').map((runtime) => ({
|
|
103
|
+
name: runtimeLabel(runtime.name), model_count: runtime.model_count,
|
|
104
|
+
loaded_model_count: report.models.filter((model) => model.runtime === runtime.name && model.evidence_status === 'confirmed-running').length,
|
|
105
|
+
})),
|
|
106
|
+
models: report.models.map((model) => ({ name: model.name, source: sourceLabel(model), loaded: model.evidence_status === 'confirmed-running' })),
|
|
107
|
+
tools: report.tools.map((tool) => ({ name: tool.name, status: tool.evidence_status })),
|
|
108
|
+
technical: {
|
|
109
|
+
runtime_probes: report.runtimes.filter((runtime) => runtime.name !== 'filesystem').map((runtime) => ({
|
|
110
|
+
name: runtimeLabel(runtime.name), state: runtime.evidence_status, error_code: runtime.error_code,
|
|
111
|
+
})),
|
|
112
|
+
warnings: report.warnings.map((warning) => ({ code: warning.code, message: warning.message })),
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function renderCensusSharePage(report, options = {}) {
|
|
118
|
+
const snapshot = buildCensusShareSnapshot(report);
|
|
119
|
+
const rescan = options.rescan;
|
|
120
|
+
if (rescan)
|
|
121
|
+
validateRescanOptions(rescan);
|
|
122
|
+
const view = rescan ? buildLocalScanView(report) : null;
|
|
123
|
+
const locale = options.locale ?? 'en';
|
|
124
|
+
const t = (key, values = {}) => escapeHtml((0, localization_1.uiText)(locale, key, values));
|
|
125
|
+
const device = escapeHtml(options.localDeviceLabel ?? (locale === 'de' ? 'Dieses Gerät' : 'This device'));
|
|
126
|
+
const lightIcon = iconDataUrl('forkit-icon-light.png');
|
|
127
|
+
const darkIcon = iconDataUrl('forkit-icon-dark.png');
|
|
128
|
+
const brand = lightIcon ? `<picture><source media="(prefers-color-scheme:dark)" srcset="${darkIcon ?? lightIcon}"><img class="brand-icon" src="${lightIcon}" alt=""></picture>` : '<span class="brand-fallback">F</span>';
|
|
129
|
+
return `<!doctype html>
|
|
130
|
+
<html lang="${locale}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><title>Forkit AI Footprint</title>
|
|
131
|
+
<style>
|
|
132
|
+
:root{--bg:#f3eee5;--paper:rgba(255,253,248,.88);--ink:#282624;--muted:#716c64;--line:rgba(42,38,34,.13);--teal:#007f82;--teal2:#d8ecea;--orange:#df8c27;--green:#247f67;--idle:#d8d1c7;--shadow:0 24px 70px rgba(36,32,28,.08)}
|
|
133
|
+
@media(prefers-color-scheme:dark){:root{--bg:#171817;--paper:rgba(35,36,34,.92);--ink:#f2ecdf;--muted:#aaa49a;--line:rgba(242,236,223,.13);--teal:#67beb8;--teal2:#203b39;--orange:#e2af23;--green:#62b99e;--idle:#45423e;--shadow:0 24px 70px rgba(0,0,0,.25)}}
|
|
134
|
+
*{box-sizing:border-box}html{background:var(--bg)}body{margin:0;color:var(--ink);background:radial-gradient(circle at 0 0,rgba(223,140,39,.15),transparent 32rem),radial-gradient(circle at 100% 0,rgba(0,128,128,.14),transparent 34rem),var(--bg);font-family:Inter,ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;-webkit-font-smoothing:antialiased}button,input{font:inherit}[hidden]{display:none!important}.shell{width:min(1040px,calc(100% - 36px));margin:auto;padding:22px 0 30px}.nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:26px}.brand{display:flex;align-items:center;gap:10px;font-weight:830;letter-spacing:-.03em}.brand-icon,.brand-fallback{width:42px;height:42px;border-radius:11px;object-fit:contain}.brand-fallback{display:grid;place-items:center;color:#fff;background:linear-gradient(145deg,var(--teal),var(--orange))}.private{font-size:12px;color:var(--muted)}.private::before{content:'';display:inline-block;width:8px;height:8px;margin-right:8px;border-radius:50%;background:var(--green)}
|
|
135
|
+
.card{border:1px solid var(--line);border-radius:24px;background:var(--paper);box-shadow:var(--shadow);backdrop-filter:blur(18px)}.activity{padding:28px}.topline{display:flex;justify-content:space-between;gap:16px;align-items:start}.eyebrow{margin:0 0 9px;color:var(--teal);font-size:10px;font-weight:850;letter-spacing:.16em;text-transform:uppercase}h1,h2,h3,p{margin-top:0}.state-title{margin:0;font-size:clamp(33px,5vw,58px);line-height:.98;letter-spacing:-.055em}.state-copy{max-width:710px;margin:13px 0 0;color:var(--muted);font-size:13px;line-height:1.55}.badge{display:inline-flex;min-height:31px;align-items:center;padding:0 12px;border-radius:999px;background:var(--idle);font-size:10px;font-weight:850;white-space:nowrap}.badge.working{color:#fff;background:var(--green)}.metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:23px}.metric{min-height:104px;padding:16px;border:1px solid var(--line);border-radius:17px;background:rgba(255,255,255,.18)}.metric-label{color:var(--muted);font-size:9px;font-weight:800;letter-spacing:.1em;text-transform:uppercase}.metric-value{margin-top:12px;font-size:26px;font-weight:820;letter-spacing:-.04em}.metric-note{margin-top:5px;color:var(--muted);font-size:9px;line-height:1.4}.context{display:flex;gap:20px;margin-top:15px;padding:12px 14px;border-radius:14px;background:var(--teal2);font-size:11px}.timeline{display:flex;height:13px;gap:2px;margin-top:18px;overflow:hidden;border-radius:999px;background:var(--idle)}.segment{min-width:4px;height:100%}.segment.working-now{background:var(--green)}.segment.open-idle{background:var(--orange)}.segment.not-running{background:var(--idle)}.legend{display:flex;gap:15px;margin-top:8px;color:var(--muted);font-size:9px}.legend i{display:inline-block;width:7px;height:7px;margin-right:5px;border-radius:50%}.legend .work{background:var(--green)}.legend .idle{background:var(--orange)}
|
|
136
|
+
.actions{display:flex;flex-wrap:wrap;gap:9px;margin-top:18px}.button{min-height:43px;padding:0 17px;border:1px solid var(--teal);border-radius:12px;color:#fff;background:var(--teal);font-weight:780;cursor:pointer}.button.secondary{border-color:var(--line);color:var(--ink);background:transparent}.button:disabled{cursor:not-allowed;opacity:.48}.grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}.panel{padding:23px}.panel h2{margin-bottom:8px;font-size:24px;letter-spacing:-.04em}.panel-copy{color:var(--muted);font-size:11px;line-height:1.5}.insights{margin-top:14px}.insight-list{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin:14px 0 0;padding:0;list-style:none}.insight-list li{min-height:86px;padding:15px;border:1px solid var(--line);border-radius:15px;font-size:14px;font-weight:720;line-height:1.4}.guess-row{display:grid;grid-template-columns:1fr auto;gap:8px;margin-top:16px}.guess-row input{min-height:44px;border:1px solid var(--line);border-radius:12px;padding:0 13px;color:var(--ink);background:transparent;font-weight:760}.footprint-metrics{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-top:16px}.footprint-metrics .metric{min-height:92px}.footprint-metrics .metric-value{font-size:22px}.detail-list{display:grid;gap:9px;margin:12px 0 0;padding:0;list-style:none}.detail-list li{font-size:10px;color:var(--muted);line-height:1.45}.detail-list strong{display:block;color:var(--ink);font-size:11px}.privacy{margin-top:14px;padding:18px 20px}.privacy summary{cursor:pointer;font-size:12px;font-weight:800}.detail-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:14px}.detail-box{padding:15px;border:1px solid var(--line);border-radius:15px}.detail-box h3{font-size:13px}.payload{max-height:220px;overflow:auto;padding:13px;border:1px solid var(--line);border-radius:12px;background:rgba(0,0,0,.05);font:10px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap;word-break:break-word}.footer{display:flex;justify-content:space-between;gap:20px;margin-top:20px;padding:0 4px;color:var(--muted);font-size:9px;line-height:1.5}
|
|
137
|
+
dialog{width:min(760px,calc(100% - 28px));border:0;border-radius:24px;padding:0;color:var(--ink);background:var(--paper);box-shadow:0 40px 100px rgba(0,0,0,.34)}dialog::backdrop{background:rgba(20,20,18,.62)}.dialog-body{padding:22px}.share-canvas{display:block;width:100%;height:auto;border-radius:16px}.share-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
|
|
138
|
+
@media(max-width:760px){.grid{grid-template-columns:1fr}.metrics{grid-template-columns:repeat(3,1fr)}.insight-list,.detail-grid{grid-template-columns:1fr}.topline{display:block}.badge{margin-top:14px}.footer{display:block}.footer span{display:block;margin-top:5px}}@media(max-width:440px){.shell{width:calc(100% - 20px)}.activity,.panel{padding:18px}.metrics,.footprint-metrics{grid-template-columns:1fr}.state-title{font-size:38px}.private{max-width:120px;text-align:right}}
|
|
139
|
+
</style></head><body><main class="shell">
|
|
140
|
+
<header class="nav"><div class="brand">${brand}<span>Forkit AI Footprint</span></div><div><button class="button secondary" id="locale-en" type="button" aria-pressed="${locale === 'en'}">EN</button> <button class="button secondary" id="locale-de" type="button" aria-pressed="${locale === 'de'}">DE</button></div><div class="private">${t('localDevice')}</div></header>
|
|
141
|
+
<section class="card activity"><div class="topline"><div><p class="eyebrow">${t('activityNow')}</p><h1 class="state-title" id="activity-title">${t('monitoringOff')}</h1><p class="state-copy" id="activity-copy">${t('startHelp')}</p></div><span class="badge" id="activity-badge">${t('stopped')}</span></div>
|
|
142
|
+
<div class="context" id="context" hidden><span id="chat-context"></span><span id="workspace-context"></span></div>
|
|
143
|
+
<div class="metrics"><div class="metric"><div class="metric-label">${t('observed')}</div><div class="metric-value" id="observed">0s</div><div class="metric-note">${t('validAwake')}</div></div><div class="metric"><div class="metric-label">${t('aiActive')}</div><div class="metric-value" id="active">0s</div><div class="metric-note">${t('supportedWork')}</div></div><div class="metric"><div class="metric-label">${t('activityRatio')}</div><div class="metric-value" id="ratio">—</div><div class="metric-note">${t('ratioNote')}</div></div></div>
|
|
144
|
+
<div class="timeline" id="timeline" aria-label="${t('activityNow')}"></div><div class="legend"><span><i class="work"></i>${t('working')}</span><span><i class="idle"></i>${t('openIdleLegend')}</span></div>
|
|
145
|
+
${rescan ? `<div class="actions"><button class="button" id="monitor-button" type="button">${t('startMonitoring')}</button><button class="button secondary" id="clear-button" type="button">${t('clearHistory')}</button></div>` : ''}</section>
|
|
146
|
+
<section class="card panel insights" id="insights"><p class="eyebrow" id="insight-eyebrow">${t('earlyObservation')}</p><h2 id="insight-heading">${t('earlyObservationCopy')}</h2><ul class="insight-list" id="insight-list"></ul></section>
|
|
147
|
+
<section class="card panel insights" id="compare-panel"><p class="eyebrow">${t('optionalComparison')}</p><h2 id="compare-title">${t('comparisonQuestion')}</h2><p class="panel-copy" id="compare-copy">${t('comparisonCopy')}</p><p class="panel-copy" id="compare-progress"></p><button class="button secondary" id="review-payload" type="button" disabled>${t('seeGlobal')}</button><div id="consent" hidden><p class="panel-copy"><strong>${t('reviewSharing')}</strong> ${t('payloadIntro')}</p><pre class="payload" id="payload"></pre><div class="actions"><button class="button" id="global-consent" type="button" disabled>${t('shareCompare')}</button><button class="button secondary" id="keep-local" type="button">${t('keepLocal')}</button></div><p class="panel-copy">${t('noIdentity')}</p></div><p class="panel-copy" id="global-result" hidden></p></section>
|
|
148
|
+
<section class="card panel insights"><p class="eyebrow">${t('footprint')}</p><div class="footprint-metrics"><div class="metric"><div class="metric-label">${t('modelRecordsLabel')}</div><div class="metric-value" id="models">${snapshot.model_record_count}</div><div class="metric-note" id="loaded">${snapshot.confirmed_running_model_count ? t('loaded', { count: snapshot.confirmed_running_model_count }) : ''}</div></div><div class="metric"><div class="metric-label">${t('modelStorage')}</div><div class="metric-value" id="storage">${escapeHtml(snapshot.model_storage_decimal_display)}</div><div class="metric-note" id="storage-note">${escapeHtml(snapshot.model_storage_binary_display)} · ${t('recognizedBytes')}</div></div><div class="metric"><div class="metric-label">${t('localEngines')}</div><div class="metric-value" id="engines">${snapshot.verified_runtime_count}</div><div class="metric-note">${t('verifiedAvailable')}</div></div></div><div class="actions"><button class="button" id="share-button" type="button">${t('createShare')}</button>${rescan ? `<button class="button secondary" id="scan-button" type="button">${t('scanAgain')}</button>` : ''}</div><p class="panel-copy" id="scan-status"></p></section>
|
|
149
|
+
${rescan ? `<details class="card privacy"><summary>${t('technical')}</summary><div class="detail-grid"><section class="detail-box" id="runtime-box"><h3>${t('engines')}</h3><ul class="detail-list" id="runtime-list"></ul></section><section class="detail-box" id="model-box"><h3>${t('modelsDevice')}</h3><ul class="detail-list" id="model-list"></ul></section><section class="detail-box" id="app-box"><h3>${t('appsTools')}</h3><ul class="detail-list" id="app-list"></ul></section><section class="detail-box"><h3>${t('measurementBoundary')}</h3><ul class="detail-list"><li><strong>${t('activityMeasurement')}</strong>${t('workingBoundary')}</li><li><strong>${t('storage')}</strong>${t('storageBoundary')}</li></ul></section><section class="detail-box"><h3>${t('forkitResources')}</h3><ul class="detail-list"><li><strong id="overhead">—</strong><span id="overhead-note">${t('measuredLocally')}</span></li></ul></section></div></details>` : ''}
|
|
150
|
+
<footer class="footer"><span>${device} · ${escapeHtml(snapshot.generated_date)} · ${escapeHtml(snapshot.architecture_label)}</span><span>${t('noPrivateFooter')}</span></footer></main>
|
|
151
|
+
<dialog id="share-dialog"><div class="dialog-body"><p class="eyebrow">${t('shareTitle')}</p><h2 id="share-heading">${t('shareHeading')}</h2><canvas class="share-canvas" id="share-canvas" width="1080" height="1080"></canvas><div class="share-actions"><button class="button" id="native-share">${t('share')}</button><button class="button secondary" id="download-share">${t('savePng')}</button><button class="button secondary" id="copy-image">${t('copyImage')}</button><button class="button secondary" id="copy-share">${t('copyCaption')}</button><button class="button secondary" id="close-share">${t('close')}</button></div><p class="panel-copy" id="share-status">${t('sharePrivacy')}</p></div></dialog>
|
|
152
|
+
<script>
|
|
153
|
+
const initial=${safeScriptJson(view ?? snapshot)},config=${rescan ? safeScriptJson(rescan) : 'null'},copy=${safeScriptJson(localization_1.UI_COPY[locale])},locale=${safeScriptJson(locale)},shareLogo=${safeScriptJson(lightIcon)};let footprint={...initial},monitor={lifecycle:'stopped',observed_seconds:0,active_seconds:0,activity_ratio:null,products:[],timeline:[],insights:[],overhead:{current_cpu_percent:null,current_memory_bytes:0,history_bytes:0,sample_count:0,median_cpu_percent:null,p95_cpu_percent:null,max_memory_bytes:0}};const $=id=>document.getElementById(id),text=(key,values={})=>Object.entries(values).reduce((v,[k,x])=>v.replaceAll('{'+k+'}',String(x)),copy[key]),localeTag=locale==='de'?'de-DE':'en-US',format=new Intl.NumberFormat(localeTag),seconds=n=>{const whole=Math.max(0,Math.floor(n));return whole<60?format.format(whole)+(locale==='de'?' Sek.':'s'):whole<3600?format.format(Math.floor(whole/60))+(locale==='de'?' Min. ':'m ')+format.format(whole%60)+(locale==='de'?' Sek.':'s'):format.format(Math.floor(whole/3600))+(locale==='de'?' Std. ':'h ')+format.format(Math.floor((whole%3600)/60))+(locale==='de'?' Min.':'m')},pct=n=>n===null?'—':format.format(Math.round(n*100))+' %',bytes=n=>n<1000000?format.format(Math.round(n/1000))+' KB':format.format(Number((n/1000000).toFixed(1)))+' MB',storage=(n,binary=false)=>{if(!n)return'0 B';const base=binary?1024:1000,units=binary?['B','KiB','MiB','GiB','TiB','PiB']:['B','KB','MB','GB','TB','PB'];let value=n,unit=0;while(unit<units.length-1&&value>=base){value/=base;unit++}const digits=value<10&&unit>1?2:value<100?1:0;return new Intl.NumberFormat(localeTag,{minimumFractionDigits:digits,maximumFractionDigits:digits}).format(value)+' '+units[unit]};
|
|
154
|
+
function auth(url,options={}){return fetch(url,{...options,method:options.method||'POST',headers:{...(options.headers||{}),'content-type':'application/json','x-forkit-footprints-session':config.session_token}})}function names(items){return items.map(item=>item.name)}function list(items){return new Intl.ListFormat(locale==='de'?'de-DE':'en-US',{style:'long',type:'conjunction'}).format(items)}function add(ul,title,detail){const li=document.createElement('li'),strong=document.createElement('strong');strong.textContent=title;li.append(strong,document.createTextNode(detail));ul.append(li)}
|
|
155
|
+
function renderMonitor(){const working=monitor.products.filter(p=>p.state==='working-now'),open=monitor.products.filter(p=>p.state==='open-idle'),badge=$('activity-badge');badge.className='badge';if(monitor.lifecycle==='stopped'){badge.textContent=text('stopped');$('activity-title').textContent=monitor.observed_seconds?text('monitoringStopped'):text('monitoringOff');$('activity-copy').textContent=monitor.observed_seconds?text('summaryPreserved'):text('startHelp');$('monitor-button')&&($('monitor-button').textContent=text('startMonitoring'))}else if(working.length){badge.textContent=text('workingNow');badge.classList.add('working');$('activity-title').textContent=list(names(working));$('activity-copy').textContent=text('workingEvidence');$('monitor-button')&&($('monitor-button').textContent=text('stopMonitoring'))}else if(open.length){badge.textContent=text('openIdle');$('activity-title').textContent=list(names(open));$('activity-copy').textContent=text('idleEvidence');$('monitor-button')&&($('monitor-button').textContent=text('stopMonitoring'))}else{badge.textContent=text('notRunning');$('activity-title').textContent=text('noApp');$('activity-copy').textContent=text('noAppHelp');$('monitor-button')&&($('monitor-button').textContent=text('stopMonitoring'))}
|
|
156
|
+
$('observed').textContent=seconds(monitor.observed_seconds);$('active').textContent=seconds(monitor.active_seconds);$('ratio').textContent=pct(monitor.activity_ratio);if($('overhead')){$('overhead').textContent=monitor.overhead.current_cpu_percent===null?text('warmingUp'):format.format(Number(monitor.overhead.current_cpu_percent.toFixed(1)))+' % CPU';$('overhead-note').textContent=bytes(monitor.overhead.current_memory_bytes)+' RAM · '+bytes(monitor.overhead.history_bytes)}const ctx=[...working,...open].find(p=>p.context&&(p.context.chat||p.context.workspace))?.context;$('context').hidden=!ctx;if(ctx){$('chat-context').textContent=ctx.chat?'Chat · '+ctx.chat:'';$('workspace-context').textContent=ctx.workspace?'Workspace · '+ctx.workspace:''}
|
|
157
|
+
const timeline=$('timeline');timeline.replaceChildren();const total=Math.max(1,monitor.timeline.reduce((n,s)=>n+Math.max(1,new Date(s.ended_at)-new Date(s.started_at)),0));for(const s of monitor.timeline){const el=document.createElement('span');el.className='segment '+s.state;el.style.flex=String(Math.max(1,new Date(s.ended_at)-new Date(s.started_at))/total);timeline.append(el)}const insightList=$('insight-list');insightList.replaceChildren();for(const value of monitor.insights||[]){const li=document.createElement('li');li.textContent=value;insightList.append(li)}const early=monitor.observed_seconds<60;$('insight-eyebrow').textContent=early?text('earlyObservation'):text('observation');$('insight-heading').textContent=early?text('earlyObservationCopy'):text('observationShows');insightList.hidden=early;$('review-payload').disabled=monitor.observed_seconds<600;const remaining=Math.max(0,600-monitor.observed_seconds);$('compare-progress').textContent=remaining?text('globalProgress',{remaining:seconds(remaining)}):''}
|
|
158
|
+
function renderDetails(){if(!config||!footprint.local_details)return;$('storage').textContent=storage(footprint.model_storage_bytes);$('storage-note').textContent=storage(footprint.model_storage_bytes,true)+' · '+text('recognizedBytes');const d=footprint.local_details,rl=$('runtime-list'),ml=$('model-list'),al=$('app-list'),loaded=d.models.filter(m=>m.loaded),onlineTools=d.tools.filter(t=>t.status==='online');for(const x of [rl,ml,al])x.replaceChildren();for(const r of d.runtimes)add(rl,r.name,r.loaded_model_count?text('modelsLoaded',{count:r.loaded_model_count,models:r.loaded_model_count===1?text('model'):text('models')}):text('verifiedAvailable'));for(const m of loaded)add(ml,m.name,text('loaded',{count:''}).trim());for(const a of d.agents)add(al,a.name,text('processActivity'));const seen=new Set(d.agents.map(a=>a.name));for(const tool of onlineTools.filter(v=>!seen.has(v.name)))add(al,tool.name,text('processActivity'));$('runtime-box').hidden=!d.runtimes.length;$('model-box').hidden=!loaded.length;$('app-box').hidden=!d.agents.length&&!onlineTools.length}
|
|
159
|
+
function activeToolNames(){return [...new Set(monitor.products.filter(p=>p.active_seconds>0).map(p=>p.name))]}function primaryInsight(){if(monitor.insights?.length)return monitor.insights[0];if(monitor.observed_seconds)return text('activeShareFallback',{ratio:pct(monitor.activity_ratio)});return text('footprintFallback',{count:footprint.model_record_count,records:footprint.model_record_count===1?text('modelRecord'):text('modelRecords')})}function shareCaption(){const first=text('captionFirst',{ratio:pct(monitor.activity_ratio)}),tools=activeToolNames(),details=[monitor.observed_seconds?text('shareActivity',{observed:seconds(monitor.observed_seconds),active:seconds(monitor.active_seconds),ratio:pct(monitor.activity_ratio)}):'',tools.length?text('shareTool',{tools:list(tools)}):'',text('shareModels',{count:footprint.model_record_count,models:footprint.model_record_count===1?text('model'):text('models'),storage:storage(footprint.model_storage_bytes)})].filter(Boolean).join(' ');return first+'\\n\\n'+details+'\\n\\n'+text('captionQuestion')+'\\n\\nforkit.dev/ai-footprint'}
|
|
160
|
+
function wrap(x,value,left,top,maxWidth,lineHeight,maxLines){const words=value.split(' '),lines=[];let line='';for(const word of words){const next=line?line+' '+word:word;if(x.measureText(next).width>maxWidth&&line){lines.push(line);line=word}else line=next}if(line)lines.push(line);for(let i=0;i<Math.min(lines.length,maxLines);i++)x.fillText(lines[i],left,top+i*lineHeight)}async function draw(){const c=$('share-canvas'),x=c.getContext('2d'),g=x.createLinearGradient(0,0,1080,1080);g.addColorStop(0,'#f6e7d6');g.addColorStop(.56,'#f3eee5');g.addColorStop(1,'#cce9e6');x.fillStyle=g;x.fillRect(0,0,1080,1080);x.fillStyle='rgba(255,253,248,.76)';x.beginPath();x.roundRect(42,42,996,996,38);x.fill();if(shareLogo){const image=await new Promise(resolve=>{const v=new Image();v.onload=()=>resolve(v);v.onerror=()=>resolve(null);v.src=shareLogo});if(image)x.drawImage(image,78,72,82,82)}x.fillStyle='#007f82';x.font='800 25px Inter,sans-serif';x.fillText(text('myFootprint'),78,205);const activity=monitor.observed_seconds?pct(monitor.activity_ratio):format.format(footprint.model_record_count);x.fillStyle='#282624';x.font='900 168px Inter,sans-serif';x.fillText(activity,72,405);x.fillStyle='#007f82';x.font='850 30px Inter,sans-serif';x.fillText(monitor.observed_seconds?text('shareActive'):text('localModels'),82,454);x.fillStyle='rgba(0,127,130,.11)';x.beginPath();x.roundRect(76,520,928,212,28);x.fill();const tools=activeToolNames(),toolValue=tools.length===1?tools[0]:tools.length?format.format(tools.length)+' '+text('activeTools').toLowerCase():'—';x.fillStyle='#716c64';x.font='800 18px Inter,sans-serif';x.fillText(tools.length===1?text('activeTool'):text('activeTools'),108,574);x.fillStyle='#282624';x.font='850 51px Inter,sans-serif';wrap(x,toolValue,108,643,400,54,1);x.fillStyle='#716c64';x.font='800 18px Inter,sans-serif';x.fillText(text('localModels'),570,574);x.fillStyle='#282624';x.font='850 51px Inter,sans-serif';x.fillText(format.format(footprint.model_record_count),570,643);x.strokeStyle='rgba(40,38,36,.12)';x.lineWidth=2;x.beginPath();x.moveTo(530,552);x.lineTo(530,700);x.stroke();x.fillStyle='#282624';x.font='750 29px Inter,sans-serif';wrap(x,text('deviceQuestion'),78,830,880,38,2);x.fillStyle='#716c64';x.font='600 20px Inter,sans-serif';x.fillText('forkit.dev/ai-footprint',78,946);x.textAlign='right';x.fillText(text('observedLocally'),1000,946);x.textAlign='left'}
|
|
161
|
+
for(const next of ['en','de'])$('locale-'+next).addEventListener('click',()=>{localStorage.setItem('forkit-footprints-locale',next);const url=new URL(location.href);url.searchParams.set('lang',next);location.href=url.href});const preferred=localStorage.getItem('forkit-footprints-locale');if(preferred&&preferred!==locale){const url=new URL(location.href);url.searchParams.set('lang',preferred);location.replace(url.href)}
|
|
162
|
+
const dialog=$('share-dialog');$('share-button').addEventListener('click',async()=>{$('share-heading').textContent=primaryInsight();await draw();dialog.showModal()});$('close-share').addEventListener('click',()=>dialog.close());async function blob(){await draw();return new Promise(resolve=>$('share-canvas').toBlob(resolve,'image/png'))}$('download-share').addEventListener('click',async()=>{const b=await blob();if(!b)return;const u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download='my-forkit-ai-footprint.png';a.click();setTimeout(()=>URL.revokeObjectURL(u),1000)});$('copy-share').addEventListener('click',async()=>{await navigator.clipboard.writeText(shareCaption());$('copy-share').textContent=text('copied')});$('copy-image').addEventListener('click',async()=>{const b=await blob();try{await navigator.clipboard.write([new ClipboardItem({'image/png':b})]);$('copy-image').textContent=text('copied')}catch{$('share-status').textContent=text('copyUnavailable')}});$('native-share').addEventListener('click',async()=>{const b=await blob();if(!b)return;const f=new File([b],'my-forkit-ai-footprint.png',{type:'image/png'});if(navigator.share&&(!navigator.canShare||navigator.canShare({files:[f]})))await navigator.share({title:text('shareTitle'),text:shareCaption(),files:[f]});else await navigator.clipboard.writeText(shareCaption())});
|
|
163
|
+
if(config){void auth(config.locale_endpoint,{body:JSON.stringify({locale})});$('monitor-button').addEventListener('click',async()=>{const endpoint=monitor.lifecycle==='monitoring'?config.monitor_stop_endpoint:config.monitor_start_endpoint;const r=await auth(endpoint);if(r.ok){monitor=await r.json();renderMonitor()}});$('clear-button').addEventListener('click',async()=>{if(!confirm(text('clearConfirm')))return;const r=await auth(config.monitor_clear_endpoint);if(r.ok){monitor=await r.json();renderMonitor()}});$('scan-button').addEventListener('click',async()=>{const b=$('scan-button');b.disabled=true;$('scan-status').textContent=text('scanning');try{const r=await auth(config.endpoint);if(!r.ok)throw 0;footprint=await r.json();renderDetails();$('scan-status').textContent=text('refreshed')}catch{$('scan-status').textContent=text('scanFailed')}finally{b.disabled=false}});$('review-payload').addEventListener('click',async()=>{const r=await auth(config.contribution_preview_endpoint);if(!r.ok)return;$('payload').textContent=JSON.stringify(await r.json(),null,2);$('consent').hidden=false});$('keep-local').addEventListener('click',()=>{$('consent').hidden=true});(async()=>{try{const r=await auth(config.monitor_stream_endpoint);if(!r.ok||!r.body)return;const reader=r.body.getReader(),decoder=new TextDecoder();let buf='';while(true){const part=await reader.read();if(part.done)break;buf+=decoder.decode(part.value,{stream:true});const lines=buf.split('\\n');buf=lines.pop()||'';for(const line of lines)if(line){monitor=JSON.parse(line);renderMonitor()}}}catch{}})();renderDetails()}
|
|
164
|
+
renderMonitor();
|
|
165
|
+
</script></body></html>`;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=share-page.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MonitorSnapshot } from './monitor';
|
|
2
|
+
import type { CensusReport } from './types';
|
|
3
|
+
export declare const MINIMUM_COMPARISON_SECONDS = 600;
|
|
4
|
+
export interface AnonymousAiFootprintContribution {
|
|
5
|
+
schema_version: '2.0';
|
|
6
|
+
observation: {
|
|
7
|
+
valid_seconds: number;
|
|
8
|
+
ai_active_seconds: number;
|
|
9
|
+
activity_ratio: number;
|
|
10
|
+
};
|
|
11
|
+
counts: {
|
|
12
|
+
supported_apps_observed_working: number;
|
|
13
|
+
supported_app_categories: string[];
|
|
14
|
+
local_models_discovered: number;
|
|
15
|
+
local_models_loaded: number;
|
|
16
|
+
verified_local_runtimes_available: number;
|
|
17
|
+
};
|
|
18
|
+
model_storage_bytes: number;
|
|
19
|
+
system: {
|
|
20
|
+
platform: 'darwin';
|
|
21
|
+
architecture: string;
|
|
22
|
+
os_major: number;
|
|
23
|
+
};
|
|
24
|
+
versions: {
|
|
25
|
+
scanner: string;
|
|
26
|
+
node_major: number;
|
|
27
|
+
monitor_schema: '1.0';
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function buildAnonymousAiFootprintPreview(report: CensusReport, monitor: MonitorSnapshot, options?: {
|
|
31
|
+
osMajor?: number;
|
|
32
|
+
}): AnonymousAiFootprintContribution;
|
|
33
|
+
/** Consent is separate from local preview construction. This never uploads. */
|
|
34
|
+
export declare function authorizeAnonymousAiFootprintContribution(payload: AnonymousAiFootprintContribution, consent: boolean): AnonymousAiFootprintContribution;
|
|
35
|
+
//# sourceMappingURL=sharing.d.ts.map
|