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/sharing.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MINIMUM_COMPARISON_SECONDS = void 0;
|
|
4
|
+
exports.buildAnonymousAiFootprintPreview = buildAnonymousAiFootprintPreview;
|
|
5
|
+
exports.authorizeAnonymousAiFootprintContribution = authorizeAnonymousAiFootprintContribution;
|
|
6
|
+
const node_child_process_1 = require("node:child_process");
|
|
7
|
+
exports.MINIMUM_COMPARISON_SECONDS = 600;
|
|
8
|
+
function macosMajorVersion() {
|
|
9
|
+
try {
|
|
10
|
+
const productVersion = (0, node_child_process_1.execFileSync)('/usr/bin/sw_vers', ['-productVersion'], {
|
|
11
|
+
encoding: 'utf8',
|
|
12
|
+
timeout: 2_000,
|
|
13
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
14
|
+
}).trim();
|
|
15
|
+
const major = Number(productVersion.split('.')[0]);
|
|
16
|
+
return Number.isInteger(major) && major > 0 ? major : 0;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function buildAnonymousAiFootprintPreview(report, monitor, options = {}) {
|
|
23
|
+
if (report.system.platform !== 'darwin')
|
|
24
|
+
throw new Error('ANONYMOUS_FOOTPRINT_MACOS_REQUIRED');
|
|
25
|
+
if (!report.summary.storage_complete)
|
|
26
|
+
throw new Error('ANONYMOUS_FOOTPRINT_STORAGE_INCOMPLETE');
|
|
27
|
+
if (monitor.observed_seconds < exports.MINIMUM_COMPARISON_SECONDS)
|
|
28
|
+
throw new Error('ANONYMOUS_FOOTPRINT_MINIMUM_OBSERVATION_REQUIRED');
|
|
29
|
+
if (monitor.active_seconds < 0 || monitor.active_seconds > monitor.observed_seconds)
|
|
30
|
+
throw new Error('ANONYMOUS_FOOTPRINT_INVALID_ACTIVITY_DURATION');
|
|
31
|
+
const validSeconds = Math.floor(monitor.observed_seconds);
|
|
32
|
+
const activeSeconds = Math.min(validSeconds, Math.floor(monitor.active_seconds));
|
|
33
|
+
const workingProducts = monitor.products.filter((product) => product.active_seconds > 0);
|
|
34
|
+
return {
|
|
35
|
+
schema_version: '2.0',
|
|
36
|
+
observation: {
|
|
37
|
+
valid_seconds: validSeconds,
|
|
38
|
+
ai_active_seconds: activeSeconds,
|
|
39
|
+
activity_ratio: validSeconds === 0 ? 0 : Math.round((activeSeconds / validSeconds) * 1000) / 1000,
|
|
40
|
+
},
|
|
41
|
+
counts: {
|
|
42
|
+
supported_apps_observed_working: workingProducts.length,
|
|
43
|
+
supported_app_categories: [...new Set(workingProducts.map((product) => product.kind))].sort(),
|
|
44
|
+
local_models_discovered: report.summary.model_count,
|
|
45
|
+
local_models_loaded: report.summary.confirmed_running_model_count,
|
|
46
|
+
verified_local_runtimes_available: report.summary.available_runtime_count,
|
|
47
|
+
},
|
|
48
|
+
model_storage_bytes: report.summary.storage_bytes,
|
|
49
|
+
system: {
|
|
50
|
+
platform: 'darwin',
|
|
51
|
+
architecture: report.system.architecture,
|
|
52
|
+
os_major: options.osMajor ?? macosMajorVersion(),
|
|
53
|
+
},
|
|
54
|
+
versions: {
|
|
55
|
+
scanner: report.product_version,
|
|
56
|
+
node_major: report.system.node_major,
|
|
57
|
+
monitor_schema: monitor.schema_version,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Consent is separate from local preview construction. This never uploads. */
|
|
62
|
+
function authorizeAnonymousAiFootprintContribution(payload, consent) {
|
|
63
|
+
if (!consent)
|
|
64
|
+
throw new Error('ANONYMOUS_FOOTPRINT_CONSENT_REQUIRED');
|
|
65
|
+
return payload;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=sharing.js.map
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CensusAgent, CensusTool } from './types';
|
|
2
|
+
export interface ToolDetectionOptions {
|
|
3
|
+
homeDir: string;
|
|
4
|
+
env: NodeJS.ProcessEnv;
|
|
5
|
+
platform: NodeJS.Platform;
|
|
6
|
+
agents: CensusAgent[];
|
|
7
|
+
}
|
|
8
|
+
export declare function detectAiTools(options: ToolDetectionOptions): Promise<CensusTool[]>;
|
|
9
|
+
//# sourceMappingURL=tools.d.ts.map
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
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.detectAiTools = detectAiTools;
|
|
7
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const hash_1 = require("./hash");
|
|
10
|
+
async function exists(targetPath) {
|
|
11
|
+
try {
|
|
12
|
+
await promises_1.default.access(targetPath);
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function executableCandidates(command, platform, env) {
|
|
20
|
+
if (platform !== 'win32')
|
|
21
|
+
return [command];
|
|
22
|
+
const extensions = String(env.PATHEXT || '.EXE;.CMD;.BAT')
|
|
23
|
+
.split(';')
|
|
24
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
25
|
+
.filter(Boolean);
|
|
26
|
+
return [command, ...extensions.map((extension) => `${command}${extension}`)];
|
|
27
|
+
}
|
|
28
|
+
async function commandExists(command, platform, env) {
|
|
29
|
+
const directories = String(env.PATH || env.Path || env.path || '')
|
|
30
|
+
.split(node_path_1.default.delimiter)
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.slice(0, 256);
|
|
33
|
+
const candidates = executableCandidates(command, platform, env);
|
|
34
|
+
for (const directory of directories) {
|
|
35
|
+
for (const candidate of candidates) {
|
|
36
|
+
if (await exists(node_path_1.default.join(directory, candidate)))
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
function definitions(homeDir) {
|
|
43
|
+
return [
|
|
44
|
+
{ name: 'Claude Code', signatures: ['claude'], commands: ['claude'], configPaths: [node_path_1.default.join(homeDir, '.claude')] },
|
|
45
|
+
{ name: 'Codex', signatures: ['codex'], commands: ['codex'], configPaths: [node_path_1.default.join(homeDir, '.codex')], appPaths: ['/Applications/Codex.app', node_path_1.default.join(homeDir, 'Applications', 'Codex.app')] },
|
|
46
|
+
{ name: 'Cursor', signatures: ['cursor'], commands: ['cursor'], configPaths: [node_path_1.default.join(homeDir, '.cursor')], appPaths: ['/Applications/Cursor.app', node_path_1.default.join(homeDir, 'Applications', 'Cursor.app')] },
|
|
47
|
+
{ name: 'Windsurf', signatures: ['windsurf'], commands: ['windsurf'], configPaths: [node_path_1.default.join(homeDir, '.codeium', 'windsurf')], appPaths: ['/Applications/Windsurf.app', node_path_1.default.join(homeDir, 'Applications', 'Windsurf.app')] },
|
|
48
|
+
{ name: 'Gemini CLI', signatures: ['gemini-cli'], commands: ['gemini'], configPaths: [node_path_1.default.join(homeDir, '.gemini')] },
|
|
49
|
+
{ name: 'GitHub Copilot', signatures: ['github-copilot'], commands: [], configPaths: [] },
|
|
50
|
+
{ name: 'OpenCode', signatures: ['opencode'], commands: ['opencode'], configPaths: [node_path_1.default.join(homeDir, '.config', 'opencode')] },
|
|
51
|
+
{ name: 'OpenClaw', signatures: ['openclaw'], commands: ['openclaw'], configPaths: [node_path_1.default.join(homeDir, '.openclaw')] },
|
|
52
|
+
{ name: 'Jan', signatures: [], commands: ['jan'], configPaths: [node_path_1.default.join(homeDir, 'Library', 'Application Support', 'Jan')], appPaths: ['/Applications/Jan.app', node_path_1.default.join(homeDir, 'Applications', 'Jan.app')] },
|
|
53
|
+
{ name: 'LM Studio', signatures: [], commands: ['lms'], configPaths: [node_path_1.default.join(homeDir, '.lmstudio')], appPaths: ['/Applications/LM Studio.app', node_path_1.default.join(homeDir, 'Applications', 'LM Studio.app')] },
|
|
54
|
+
{ name: 'Zed', signatures: [], commands: ['zed'], configPaths: [node_path_1.default.join(homeDir, '.zed')], appPaths: ['/Applications/Zed.app', node_path_1.default.join(homeDir, 'Applications', 'Zed.app')] },
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
async function hasCopilotExtension(homeDir) {
|
|
58
|
+
const roots = [
|
|
59
|
+
node_path_1.default.join(homeDir, '.vscode', 'extensions'),
|
|
60
|
+
node_path_1.default.join(homeDir, '.vscode-insiders', 'extensions'),
|
|
61
|
+
];
|
|
62
|
+
for (const root of roots) {
|
|
63
|
+
try {
|
|
64
|
+
const names = await promises_1.default.readdir(root);
|
|
65
|
+
if (names.some((name) => /^github\.copilot(?:-chat)?(?:-|$)/i.test(name)))
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Missing or unreadable extension roots are normal.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
async function detectAiTools(options) {
|
|
75
|
+
const tools = [];
|
|
76
|
+
for (const definition of definitions(options.homeDir)) {
|
|
77
|
+
const detectorTypes = new Set();
|
|
78
|
+
const matchingAgents = options.agents.filter((agent) => definition.signatures.includes(agent.signature));
|
|
79
|
+
if (matchingAgents.length > 0)
|
|
80
|
+
detectorTypes.add('process');
|
|
81
|
+
const commandInstalled = (await Promise.all(definition.commands.map((command) => commandExists(command, options.platform, options.env)))).some(Boolean);
|
|
82
|
+
const appInstalled = options.platform === 'darwin'
|
|
83
|
+
&& (await Promise.all((definition.appPaths ?? []).map((targetPath) => exists(targetPath)))).some(Boolean);
|
|
84
|
+
if (commandInstalled || appInstalled) {
|
|
85
|
+
detectorTypes.add('executable');
|
|
86
|
+
}
|
|
87
|
+
const configured = definition.name === 'GitHub Copilot'
|
|
88
|
+
? await hasCopilotExtension(options.homeDir)
|
|
89
|
+
: (await Promise.all(definition.configPaths.map((targetPath) => exists(targetPath)))).some(Boolean);
|
|
90
|
+
if (configured)
|
|
91
|
+
detectorTypes.add('config');
|
|
92
|
+
if (detectorTypes.size === 0)
|
|
93
|
+
continue;
|
|
94
|
+
const instanceCount = matchingAgents.reduce((total, agent) => total + agent.instance_count, 0);
|
|
95
|
+
tools.push({
|
|
96
|
+
tool_id: (0, hash_1.stableId)('tool', definition.name),
|
|
97
|
+
name: definition.name,
|
|
98
|
+
evidence_status: detectorTypes.has('process') ? 'online' : 'configured',
|
|
99
|
+
confidence: detectorTypes.has('process') || detectorTypes.size >= 2 ? 'high' : 'medium',
|
|
100
|
+
detector_types: [...detectorTypes].sort(),
|
|
101
|
+
instance_count: instanceCount,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return tools.sort((left, right) => left.name.localeCompare(right.name));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=tools.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
export type Confidence = 'high' | 'medium' | 'low';
|
|
2
|
+
export type EvidenceStatus = 'discovered' | 'configured' | 'online' | 'confirmed-running';
|
|
3
|
+
export type RuntimeKind = 'ollama' | 'lmstudio' | 'openai-compatible' | 'filesystem';
|
|
4
|
+
export type RuntimeStatus = 'available' | 'unavailable' | 'inventory-only';
|
|
5
|
+
export interface CensusRuntime {
|
|
6
|
+
runtime_id: string;
|
|
7
|
+
name: RuntimeKind;
|
|
8
|
+
status: RuntimeStatus;
|
|
9
|
+
endpoint: string | null;
|
|
10
|
+
model_count: number;
|
|
11
|
+
observed_at: string;
|
|
12
|
+
error_code: string | null;
|
|
13
|
+
evidence_status: 'configured' | 'online' | 'unavailable';
|
|
14
|
+
}
|
|
15
|
+
export interface CensusModel {
|
|
16
|
+
model_id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
runtime: RuntimeKind;
|
|
19
|
+
identity_kind: 'content-sha256' | 'provider-id' | 'metadata-sha256';
|
|
20
|
+
identity: string;
|
|
21
|
+
size_bytes: number | null;
|
|
22
|
+
modified_at: string | null;
|
|
23
|
+
quantization: string | null;
|
|
24
|
+
architecture: string | null;
|
|
25
|
+
parameter_size: string | null;
|
|
26
|
+
source: 'runtime-api' | 'filesystem';
|
|
27
|
+
location_hint: string | null;
|
|
28
|
+
confidence: Confidence;
|
|
29
|
+
evidence_status: 'discovered' | 'confirmed-running';
|
|
30
|
+
}
|
|
31
|
+
export type AgentKind = 'coding-agent' | 'ide-agent' | 'agent-framework' | 'mcp-server';
|
|
32
|
+
export interface CensusAgent {
|
|
33
|
+
agent_id: string;
|
|
34
|
+
name: string;
|
|
35
|
+
signature: string;
|
|
36
|
+
kind: AgentKind;
|
|
37
|
+
confidence: Confidence;
|
|
38
|
+
instance_count: number;
|
|
39
|
+
executable_names: string[];
|
|
40
|
+
evidence_hashes: string[];
|
|
41
|
+
detection_reason: string;
|
|
42
|
+
evidence_status: 'online';
|
|
43
|
+
resource_snapshot: {
|
|
44
|
+
cpu_percent: number | null;
|
|
45
|
+
memory_percent: number | null;
|
|
46
|
+
measurement: 'point-in-time-process-metadata';
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export interface CensusTool {
|
|
50
|
+
tool_id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
evidence_status: 'configured' | 'online';
|
|
53
|
+
confidence: Confidence;
|
|
54
|
+
detector_types: Array<'config' | 'executable' | 'process'>;
|
|
55
|
+
instance_count: number;
|
|
56
|
+
}
|
|
57
|
+
export interface CensusMcpConfig {
|
|
58
|
+
client: string;
|
|
59
|
+
evidence_status: 'configured';
|
|
60
|
+
confidence: Confidence;
|
|
61
|
+
server_count: number;
|
|
62
|
+
}
|
|
63
|
+
export interface CensusWarning {
|
|
64
|
+
code: string;
|
|
65
|
+
message: string;
|
|
66
|
+
scope: 'runtime' | 'model' | 'agent' | 'privacy' | 'system';
|
|
67
|
+
}
|
|
68
|
+
export interface CensusSummary {
|
|
69
|
+
runtime_count: number;
|
|
70
|
+
available_runtime_count: number;
|
|
71
|
+
model_count: number;
|
|
72
|
+
agent_product_count: number;
|
|
73
|
+
agent_process_count: number;
|
|
74
|
+
agent_cpu_percent: number | null;
|
|
75
|
+
agent_memory_percent: number | null;
|
|
76
|
+
tool_count: number;
|
|
77
|
+
mcp_config_count: number;
|
|
78
|
+
confirmed_running_model_count: number;
|
|
79
|
+
storage_bytes: number;
|
|
80
|
+
storage_file_count: number;
|
|
81
|
+
storage_complete: boolean;
|
|
82
|
+
storage_measurement: 'recognized-logical-file-bytes';
|
|
83
|
+
warning_count: number;
|
|
84
|
+
}
|
|
85
|
+
export interface CensusReport {
|
|
86
|
+
schema_version: '1.3';
|
|
87
|
+
product: 'forkit-ai-footprints';
|
|
88
|
+
product_version: string;
|
|
89
|
+
census_id: string;
|
|
90
|
+
generated_at: string;
|
|
91
|
+
system: {
|
|
92
|
+
platform: NodeJS.Platform;
|
|
93
|
+
architecture: string;
|
|
94
|
+
node_major: number;
|
|
95
|
+
};
|
|
96
|
+
privacy: {
|
|
97
|
+
mode: 'metadata-only';
|
|
98
|
+
raw_commands_retained: false;
|
|
99
|
+
model_file_contents_read: false;
|
|
100
|
+
config_values_emitted: false;
|
|
101
|
+
sensitive_content_retained: false;
|
|
102
|
+
remote_endpoints_allowed: false;
|
|
103
|
+
external_requests_made: 0;
|
|
104
|
+
backend_contacted: false;
|
|
105
|
+
account_read: false;
|
|
106
|
+
local_state_written: boolean;
|
|
107
|
+
local_state_scope: 'none' | 'device-journal-only';
|
|
108
|
+
};
|
|
109
|
+
summary: CensusSummary;
|
|
110
|
+
runtimes: CensusRuntime[];
|
|
111
|
+
models: CensusModel[];
|
|
112
|
+
agents: CensusAgent[];
|
|
113
|
+
tools: CensusTool[];
|
|
114
|
+
mcp_configs: CensusMcpConfig[];
|
|
115
|
+
guess: {
|
|
116
|
+
provided: number | null;
|
|
117
|
+
discovered: number;
|
|
118
|
+
difference: number | null;
|
|
119
|
+
};
|
|
120
|
+
warnings: CensusWarning[];
|
|
121
|
+
}
|
|
122
|
+
export interface RuntimeScanResult {
|
|
123
|
+
runtime: CensusRuntime;
|
|
124
|
+
models: CensusModel[];
|
|
125
|
+
warnings: CensusWarning[];
|
|
126
|
+
storage?: {
|
|
127
|
+
logical_bytes: number;
|
|
128
|
+
recognized_file_count: number;
|
|
129
|
+
complete: boolean;
|
|
130
|
+
measurement: 'recognized-logical-file-bytes';
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export interface RuntimeProvider {
|
|
134
|
+
readonly name: RuntimeKind;
|
|
135
|
+
scan(observedAt: string): Promise<RuntimeScanResult>;
|
|
136
|
+
}
|
|
137
|
+
export interface ProcessEntry {
|
|
138
|
+
pid: number;
|
|
139
|
+
ppid?: number;
|
|
140
|
+
name?: string;
|
|
141
|
+
cmd?: string;
|
|
142
|
+
cpu_percent?: number;
|
|
143
|
+
memory_percent?: number;
|
|
144
|
+
/** Internal resident memory from the operating system. Never emitted in a Census report. */
|
|
145
|
+
rss_bytes?: number;
|
|
146
|
+
/** Internal cumulative process CPU time. Never emitted in a Census report. */
|
|
147
|
+
cpu_time_ms?: number;
|
|
148
|
+
}
|
|
149
|
+
export interface CensusOptions {
|
|
150
|
+
includeRuntimes?: boolean;
|
|
151
|
+
includeFilesystem?: boolean;
|
|
152
|
+
includeAgents?: boolean;
|
|
153
|
+
includeTools?: boolean;
|
|
154
|
+
includeMcp?: boolean;
|
|
155
|
+
filesystemRoots?: string[];
|
|
156
|
+
processEntries?: ProcessEntry[];
|
|
157
|
+
providers?: RuntimeProvider[];
|
|
158
|
+
now?: () => Date;
|
|
159
|
+
guess?: number | null;
|
|
160
|
+
homeDir?: string;
|
|
161
|
+
cwd?: string;
|
|
162
|
+
env?: NodeJS.ProcessEnv;
|
|
163
|
+
platform?: NodeJS.Platform;
|
|
164
|
+
architecture?: string;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
package/dist/version.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
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.SCHEMA_VERSION = exports.PRODUCT_VERSION = exports.PRODUCT_NAME = void 0;
|
|
7
|
+
exports.PRODUCT_NAME = 'forkit-ai-footprints';
|
|
8
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
9
|
+
// package.json is the only product-version source. npm, the CLI, native
|
|
10
|
+
// bundles, GitHub release tags, and package-manager metadata must derive from it.
|
|
11
|
+
exports.PRODUCT_VERSION = package_json_1.default.version;
|
|
12
|
+
exports.SCHEMA_VERSION = '1.3';
|
|
13
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Forkit AI Footprints global distribution
|
|
2
|
+
|
|
3
|
+
Status: v0.2.0 npm-first Apple Silicon macOS release approved.
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
Offer a free, professional installation path to Mac users anywhere in the
|
|
8
|
+
world, while ensuring npm, Homebrew, GitHub Releases, the future Mac installer,
|
|
9
|
+
and the website can never silently recommend different product versions.
|
|
10
|
+
|
|
11
|
+
## One release identity
|
|
12
|
+
|
|
13
|
+
`package.json` is the only version source. The CLI imports it at build time and
|
|
14
|
+
the native Mac package builder reads it directly. `npm run release:check`
|
|
15
|
+
rejects a different lockfile version, CLI version source, native package version,
|
|
16
|
+
or documented status version.
|
|
17
|
+
|
|
18
|
+
`npm run release:manifest` generates the candidate release manifest under
|
|
19
|
+
`artifacts/release/`. The generated manifest is metadata only; generating it
|
|
20
|
+
does not publish anything.
|
|
21
|
+
|
|
22
|
+
## Global channels
|
|
23
|
+
|
|
24
|
+
| Channel | Audience | Cost to users | Current state |
|
|
25
|
+
|---|---|---:|---|
|
|
26
|
+
| GitHub Release | canonical immutable source/release identity | Free | v0.2.0 release |
|
|
27
|
+
| npm public registry | primary Apple Silicon bootstrap; installs a persistent app in `~/Applications` | Free | v0.2.0 |
|
|
28
|
+
| Homebrew tap | optional future package-manager channel | Free | Tap not created |
|
|
29
|
+
| Signed `.pkg` | future click installation | Free to users | Blocked on paid Apple identity and notarization |
|
|
30
|
+
|
|
31
|
+
Homebrew and npm are not tied to the founder's Mac. They are global registries.
|
|
32
|
+
The npm command is a one-time bootstrap: it copies a self-contained GUI app into
|
|
33
|
+
the current user's Applications folder and opens it. Later use is through
|
|
34
|
+
Applications, Spotlight, Dock, or the Forkit menu-bar icon without Terminal.
|
|
35
|
+
The current product support claim is still macOS on Apple Silicon until broader
|
|
36
|
+
field validation exists.
|
|
37
|
+
|
|
38
|
+
## Release order
|
|
39
|
+
|
|
40
|
+
1. Bump `package.json` and `package-lock.json` together.
|
|
41
|
+
2. Run tests, package smoke, real-Mac validation, and `npm run release:check`.
|
|
42
|
+
3. Build the npm tarball and candidate release manifest on a clean hosted runner.
|
|
43
|
+
4. Create one draft GitHub Release for `v<version>` and attach the tarball,
|
|
44
|
+
manifest, checksum, SBOM, and provenance evidence.
|
|
45
|
+
5. After founder approval, publish the exact tested package. A brand-new npm
|
|
46
|
+
package requires one interactive first publication before its trusted
|
|
47
|
+
publisher can be configured; all later releases use GitHub Actions OIDC.
|
|
48
|
+
6. Update the Homebrew tap from the immutable release URL and SHA-256.
|
|
49
|
+
7. Mark a channel `available` in the release manifest only after its registry
|
|
50
|
+
resolves to the same version and checksum.
|
|
51
|
+
8. Let Forkit.dev read the verified manifest and recommend the simplest
|
|
52
|
+
available channel. If coherence fails, the website must show no install CTA.
|
|
53
|
+
|
|
54
|
+
The release automation should run only for an approved release tag or a manual
|
|
55
|
+
release action—not for normal commits—so it does not waste GitHub Actions runs.
|
|
56
|
+
|
|
57
|
+
## Hugging Face cache boundary
|
|
58
|
+
|
|
59
|
+
AI Footprints supports the official Hub file cache at
|
|
60
|
+
`~/.cache/huggingface/hub`, `$HF_HOME/hub`, `$HF_HUB_CACHE`, and the
|
|
61
|
+
XDG-configured equivalent. It recognizes `models--<org>--<repo>` directories
|
|
62
|
+
and follows snapshot links while deduplicating the same physical blob across
|
|
63
|
+
revisions.
|
|
64
|
+
|
|
65
|
+
`HF_XET_CACHE` is deliberately excluded. It contains transport chunks that can
|
|
66
|
+
be shared across files and would double-count model storage. Datasets, Spaces,
|
|
67
|
+
assets, incomplete downloads, and unreferenced extensionless blobs are also not
|
|
68
|
+
reported as model storage. The reported value is therefore exact for recognized
|
|
69
|
+
model artifacts inside supported roots, not the total size of every Hugging
|
|
70
|
+
Face cache directory.
|
|
71
|
+
|
|
72
|
+
## Brand assets
|
|
73
|
+
|
|
74
|
+
The website's `/brand/icon-dark.svg` and `/brand/icon-light.svg` are byte-for-byte
|
|
75
|
+
copies of the supplied `Logo_Forkit/logo_Only/color_Dark/color_Dark.svg` and
|
|
76
|
+
`Logo_Forkit/logo_Only/color_Light/color_Light.svg`. The dark-outline mark is for
|
|
77
|
+
light surfaces; the light-outline mark is for dark surfaces. The product name
|
|
78
|
+
remains live text so the older “Forkit Dev” wordmark is not incorrectly presented
|
|
79
|
+
as the AI Footprints product name.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# macOS Accuracy and Release Gate
|
|
2
|
+
|
|
3
|
+
Forkit AI Footprints must not claim a global accuracy percentage or broaden its
|
|
4
|
+
platform support until this gate is reviewed. Passing local tests is necessary
|
|
5
|
+
but is not field accuracy.
|
|
6
|
+
|
|
7
|
+
## Current supported claim
|
|
8
|
+
|
|
9
|
+
- operating system: macOS only;
|
|
10
|
+
- current real-device evidence: one Apple Silicon Mac;
|
|
11
|
+
- Intel Mac: not yet field validated;
|
|
12
|
+
- distribution: public npm bootstrap for Apple Silicon macOS;
|
|
13
|
+
- network: loopback runtime APIs only, with no uploader or Forkit.dev client.
|
|
14
|
+
|
|
15
|
+
## Evidence classes
|
|
16
|
+
|
|
17
|
+
- `online`: a supported runtime API responded, or a running agent has exact
|
|
18
|
+
executable, explicit module, or explicit package-runner evidence;
|
|
19
|
+
- `configured`: installation/configuration metadata exists, without claiming a
|
|
20
|
+
process is active;
|
|
21
|
+
- `confirmed-running`: Ollama `/api/ps` reported the model as loaded;
|
|
22
|
+
- `discovered`: inventory evidence exists without proof of active execution.
|
|
23
|
+
|
|
24
|
+
Filesystem findings remain best-effort and low confidence. Process instance
|
|
25
|
+
counts are not independent-agent or user-session counts.
|
|
26
|
+
|
|
27
|
+
## Local labelled evaluation
|
|
28
|
+
|
|
29
|
+
Each tester creates a local JSON truth file after manually checking their Mac:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"schema_version": "1.0",
|
|
34
|
+
"expected": {
|
|
35
|
+
"agent_signatures": ["codex"],
|
|
36
|
+
"tool_names": ["Codex"],
|
|
37
|
+
"online_runtime_names": ["ollama"],
|
|
38
|
+
"model_keys": ["ollama:example-model:latest"],
|
|
39
|
+
"mcp_clients": ["Codex"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run evaluate:macos -- /absolute/path/to/local-truth.json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Testers using the packed or installed CLI run the equivalent public command:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
forkit-census evaluate --truth /absolute/path/to/local-truth.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The result contains aggregate counts and metrics only. It does not contain the
|
|
57
|
+
truth-file item names and is not uploaded.
|
|
58
|
+
|
|
59
|
+
Each tester reviews the result and may then explicitly share that result file,
|
|
60
|
+
but never the truth file. The coordinator aggregates a directory of reviewed
|
|
61
|
+
results locally:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
forkit-census aggregate --results /absolute/path/to/macos-field-results
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The aggregate reports CPU, macOS-major, and Node-major coverage plus Wilson 95%
|
|
68
|
+
confidence intervals. It cannot enable an accuracy claim automatically. The
|
|
69
|
+
coordinator must separately verify one submission per independently labelled
|
|
70
|
+
Mac because the privacy-preserving output contains no persistent device ID.
|
|
71
|
+
Different Census versions must not be pooled.
|
|
72
|
+
|
|
73
|
+
The evaluator emits aggregate counts and per-surface precision/recall locally.
|
|
74
|
+
It does not emit item names, raw commands, full paths, credentials, or upload
|
|
75
|
+
anything. Truth files must not be committed because model names can be private.
|
|
76
|
+
|
|
77
|
+
## Public-release minimums
|
|
78
|
+
|
|
79
|
+
1. At least 100 manually labelled Macs across the latest three supported macOS
|
|
80
|
+
major releases and representative Apple Silicon generations.
|
|
81
|
+
2. Intel Mac must remain explicitly unsupported unless separately represented
|
|
82
|
+
and passing.
|
|
83
|
+
3. At least 300 confirmed/online positive findings with no unreviewed false
|
|
84
|
+
positive if a 99% precision claim is planned. Report a 95% confidence
|
|
85
|
+
interval, not only the point estimate.
|
|
86
|
+
4. The lower 95% confidence bound for confirmed/online precision must be at
|
|
87
|
+
least 99% per surface that uses that claim.
|
|
88
|
+
5. The lower 95% confidence bound for recall within the declared supported
|
|
89
|
+
catalog must be at least 90% per surface.
|
|
90
|
+
6. Zero external scan requests, zero sensitive report leaks, and zero registry,
|
|
91
|
+
Passport, Mint, Runtime_C2, or production writes.
|
|
92
|
+
7. Repeated unchanged-device item sets must be at least 99% stable; time and
|
|
93
|
+
process-instance counts are excluded from this comparison.
|
|
94
|
+
8. Package install, tests, doctor, and isolated tarball smoke must pass on Node
|
|
95
|
+
20, 22, and 24 on hosted macOS runners and on real Macs.
|
|
96
|
+
|
|
97
|
+
The tarball smoke is a separate release gate and must run before `npm publish`;
|
|
98
|
+
it is intentionally not nested inside npm's publication lifecycle.
|
|
99
|
+
|
|
100
|
+
These are release gates, not current achievements. No public accuracy claim is
|
|
101
|
+
allowed until an independently reviewed aggregate evaluation satisfies them.
|
|
102
|
+
|
|
103
|
+
## Accuracy interpretation
|
|
104
|
+
|
|
105
|
+
Different numbers have different meanings; there is no honest single accuracy
|
|
106
|
+
percentage for the whole product.
|
|
107
|
+
|
|
108
|
+
- **Known agents/tools:** the curated process corpus is a conformance test, not
|
|
109
|
+
field prevalence. The release target is a lower 95% precision bound of 99%
|
|
110
|
+
and a lower 95% supported-catalog recall bound of 90% after the field minimum.
|
|
111
|
+
- **Supported runtimes and loaded models:** a successful loopback API response
|
|
112
|
+
is strong current-state evidence. Unsupported/custom runtimes remain outside
|
|
113
|
+
recall and must not be described as absent AI.
|
|
114
|
+
- **Model inventory:** file metadata and runtime records are exact for evidence
|
|
115
|
+
the scanner recognizes, but total recall across every possible model format
|
|
116
|
+
and directory is unknown until representative field labelling.
|
|
117
|
+
- **Model storage:** the byte sum is exact for recognized files whose metadata
|
|
118
|
+
can be read. It is not total AI disk use when a format or location is outside
|
|
119
|
+
the supported catalog.
|
|
120
|
+
- **Agent CPU/memory:** the values are operating-system samples for strongly
|
|
121
|
+
detected processes. They are not exclusive task attribution and receive no
|
|
122
|
+
per-task accuracy percentage in this release.
|
|
123
|
+
- **Verified global installations:** App Attest plus replay/risk controls can
|
|
124
|
+
strongly establish a genuine supported app installation, but this is an
|
|
125
|
+
integrity result rather than detector precision. It cannot prove that every
|
|
126
|
+
local artifact is meaningful or prevent all deliberate local environment
|
|
127
|
+
manipulation.
|
|
128
|
+
|
|
129
|
+
The practical public target is therefore **≥99% precision and ≥90% recall
|
|
130
|
+
within the explicitly supported catalog**, with Wilson lower bounds satisfying
|
|
131
|
+
the release rules above. The current evidence does not yet authorize those
|
|
132
|
+
figures as achieved accuracy.
|
|
133
|
+
|
|
134
|
+
## Controlled CI is not field evidence
|
|
135
|
+
|
|
136
|
+
The labelled compatibility workflow may run tests and privacy/stability checks
|
|
137
|
+
on GitHub-hosted Apple Silicon and Intel macOS runners. Those machines improve
|
|
138
|
+
OS and architecture compatibility evidence, but they do not contain a human's
|
|
139
|
+
independently established inventory truth and must never be counted toward the
|
|
140
|
+
100-Mac field minimum.
|