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/agents.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
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.classifyAgentProcessTrees = classifyAgentProcessTrees;
|
|
7
|
+
exports.parseMacosCpuTime = parseMacosCpuTime;
|
|
8
|
+
exports.detectAgentProducts = detectAgentProducts;
|
|
9
|
+
exports.listSystemProcesses = listSystemProcesses;
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const node_child_process_1 = require("node:child_process");
|
|
12
|
+
const node_util_1 = require("node:util");
|
|
13
|
+
const hash_1 = require("./hash");
|
|
14
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
15
|
+
const SIGNATURES = [
|
|
16
|
+
{ signature: 'codex', name: 'Codex', kind: 'coding-agent', terms: ['codex'], executables: ['codex'] },
|
|
17
|
+
{ signature: 'claude', name: 'Claude Code', kind: 'coding-agent', terms: ['claude', 'claude-code'], executables: ['claude'] },
|
|
18
|
+
{ signature: 'aider', name: 'Aider', kind: 'coding-agent', terms: ['aider'], executables: ['aider'] },
|
|
19
|
+
{ signature: 'openhands', name: 'OpenHands', kind: 'coding-agent', terms: ['openhands'], executables: ['openhands'] },
|
|
20
|
+
{ signature: 'goose', name: 'Goose', kind: 'coding-agent', terms: ['goose'], executables: ['goose'] },
|
|
21
|
+
{ signature: 'cursor', name: 'Cursor', kind: 'ide-agent', terms: ['cursor'], executables: ['cursor'] },
|
|
22
|
+
{ signature: 'windsurf', name: 'Windsurf', kind: 'ide-agent', terms: ['windsurf'], executables: ['windsurf'] },
|
|
23
|
+
{ signature: 'gemini-cli', name: 'Gemini CLI', kind: 'coding-agent', terms: ['gemini', 'gemini-cli'], executables: ['gemini'] },
|
|
24
|
+
{ signature: 'opencode', name: 'OpenCode', kind: 'coding-agent', terms: ['opencode'], executables: ['opencode'] },
|
|
25
|
+
{ signature: 'openclaw', name: 'OpenClaw', kind: 'coding-agent', terms: ['openclaw'], executables: ['openclaw'] },
|
|
26
|
+
{ signature: 'cline', name: 'Cline', kind: 'ide-agent', terms: ['cline'], executables: ['cline'] },
|
|
27
|
+
{ signature: 'roo-code', name: 'Roo Code', kind: 'ide-agent', terms: ['roo-code', 'roo_code'], executables: ['roo-code', 'roo_code'] },
|
|
28
|
+
{ signature: 'mcp-server', name: 'MCP Server', kind: 'mcp-server', terms: ['mcp-server', 'modelcontextprotocol'], executables: ['mcp-server'] },
|
|
29
|
+
{ signature: 'langchain', name: 'LangChain', kind: 'agent-framework', terms: ['langchain'], executables: ['langchain'] },
|
|
30
|
+
{ signature: 'langgraph', name: 'LangGraph', kind: 'agent-framework', terms: ['langgraph'], executables: ['langgraph'] },
|
|
31
|
+
{ signature: 'crewai', name: 'CrewAI', kind: 'agent-framework', terms: ['crewai'], executables: ['crewai'] },
|
|
32
|
+
{ signature: 'autogen', name: 'AutoGen', kind: 'agent-framework', terms: ['autogen'], executables: ['autogen'] },
|
|
33
|
+
{ signature: 'llamaindex', name: 'LlamaIndex', kind: 'agent-framework', terms: ['llamaindex'], executables: ['llamaindex'] },
|
|
34
|
+
{ signature: 'agno', name: 'Agno', kind: 'agent-framework', terms: ['agno'], executables: ['agno'] },
|
|
35
|
+
{ signature: 'pydantic-ai', name: 'PydanticAI', kind: 'agent-framework', terms: ['pydantic-ai', 'pydantic_ai'], executables: ['pydantic-ai', 'pydantic_ai'] },
|
|
36
|
+
{ signature: 'smolagents', name: 'smolagents', kind: 'agent-framework', terms: ['smolagents'], executables: ['smolagents'] },
|
|
37
|
+
];
|
|
38
|
+
function basename(value) {
|
|
39
|
+
const normalized = String(value || '').replaceAll('\\', '/');
|
|
40
|
+
return node_path_1.default.posix.basename(normalized).toLowerCase().replace(/\.exe$/i, '');
|
|
41
|
+
}
|
|
42
|
+
function commandParts(value) {
|
|
43
|
+
return String(value || '')
|
|
44
|
+
.match(/"[^"]*"|'[^']*'|\S+/g)
|
|
45
|
+
?.map((part) => part.replace(/^(?:"|')|(?:"|')$/g, '')) ?? [];
|
|
46
|
+
}
|
|
47
|
+
function moduleName(parts) {
|
|
48
|
+
const moduleFlag = parts.findIndex((part) => part === '-m');
|
|
49
|
+
if (moduleFlag < 0)
|
|
50
|
+
return null;
|
|
51
|
+
const raw = parts[moduleFlag + 1]?.toLowerCase();
|
|
52
|
+
return raw?.split('.')[0] ?? null;
|
|
53
|
+
}
|
|
54
|
+
function packageRunnerName(parts) {
|
|
55
|
+
const runner = basename(parts[0] ?? '');
|
|
56
|
+
let candidates = [];
|
|
57
|
+
if (runner === 'npx' || runner === 'bunx')
|
|
58
|
+
candidates = parts.slice(1);
|
|
59
|
+
else if (runner === 'npm' && (parts[1] === 'exec' || parts[1] === 'x'))
|
|
60
|
+
candidates = parts.slice(2);
|
|
61
|
+
else if (runner === 'pnpm' && (parts[1] === 'dlx' || parts[1] === 'exec'))
|
|
62
|
+
candidates = parts.slice(2);
|
|
63
|
+
else if (runner === 'yarn' && (parts[1] === 'dlx' || parts[1] === 'exec'))
|
|
64
|
+
candidates = parts.slice(2);
|
|
65
|
+
const candidate = candidates.find((part) => part !== '--' && !part.startsWith('-'));
|
|
66
|
+
if (!candidate)
|
|
67
|
+
return null;
|
|
68
|
+
const packageName = candidate.replace(/@(?:latest|next|beta|alpha|canary|\d[^/]*)$/i, '');
|
|
69
|
+
return basename(packageName);
|
|
70
|
+
}
|
|
71
|
+
function nodeBinName(parts) {
|
|
72
|
+
const runner = basename(parts[0] ?? '');
|
|
73
|
+
if (runner !== 'node' && runner !== 'bun' && runner !== 'deno')
|
|
74
|
+
return null;
|
|
75
|
+
const script = String(parts[1] ?? '').replaceAll('\\', '/').toLowerCase();
|
|
76
|
+
if (!script.includes('/.bin/'))
|
|
77
|
+
return null;
|
|
78
|
+
return basename(script);
|
|
79
|
+
}
|
|
80
|
+
function classifyProcess(entry) {
|
|
81
|
+
const processName = basename(entry.name ?? '');
|
|
82
|
+
const command = String(entry.cmd ?? '');
|
|
83
|
+
const parts = commandParts(command);
|
|
84
|
+
const firstCommandToken = parts[0] ?? '';
|
|
85
|
+
const executable = basename(firstCommandToken || processName) || 'unknown';
|
|
86
|
+
const invokedModule = moduleName(parts);
|
|
87
|
+
const invokedPackage = packageRunnerName(parts) ?? nodeBinName(parts);
|
|
88
|
+
for (const signature of SIGNATURES) {
|
|
89
|
+
const executableMatch = signature.executables.includes(processName)
|
|
90
|
+
|| signature.executables.includes(executable);
|
|
91
|
+
const moduleMatch = invokedModule !== null && signature.terms.includes(invokedModule);
|
|
92
|
+
const packageRunnerMatch = invokedPackage !== null
|
|
93
|
+
&& [...signature.terms, ...signature.executables].includes(invokedPackage);
|
|
94
|
+
if (!executableMatch && !moduleMatch && !packageRunnerMatch)
|
|
95
|
+
continue;
|
|
96
|
+
const confidence = executableMatch ? 'high' : 'medium';
|
|
97
|
+
const reason = executableMatch
|
|
98
|
+
? 'exact_executable_match'
|
|
99
|
+
: moduleMatch
|
|
100
|
+
? 'explicit_module_invocation'
|
|
101
|
+
: 'explicit_package_runner_invocation';
|
|
102
|
+
return {
|
|
103
|
+
signature,
|
|
104
|
+
confidence,
|
|
105
|
+
executable,
|
|
106
|
+
evidenceHash: (0, hash_1.sha256)(`${signature.signature}:${processName}:${executable}:${reason}`),
|
|
107
|
+
reason,
|
|
108
|
+
cpuPercent: Number.isFinite(entry.cpu_percent) ? Math.max(0, Number(entry.cpu_percent)) : null,
|
|
109
|
+
memoryPercent: Number.isFinite(entry.memory_percent) ? Math.max(0, Number(entry.memory_percent)) : null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function descendantsOf(processes, rootPid) {
|
|
115
|
+
const excluded = new Set([rootPid]);
|
|
116
|
+
let changed = true;
|
|
117
|
+
while (changed) {
|
|
118
|
+
changed = false;
|
|
119
|
+
for (const entry of processes) {
|
|
120
|
+
if (excluded.has(entry.pid) || entry.ppid === undefined || !excluded.has(entry.ppid))
|
|
121
|
+
continue;
|
|
122
|
+
excluded.add(entry.pid);
|
|
123
|
+
changed = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return excluded;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Builds private process-tree evidence for the activity monitor. PIDs and raw
|
|
130
|
+
* commands remain internal and are deliberately absent from public reports.
|
|
131
|
+
*/
|
|
132
|
+
function classifyAgentProcessTrees(processes, excludedRootPid = process.pid) {
|
|
133
|
+
const excluded = excludedRootPid === null ? new Set() : descendantsOf(processes, excludedRootPid);
|
|
134
|
+
const byPid = new Map(processes.map((entry) => [entry.pid, entry]));
|
|
135
|
+
const direct = new Map();
|
|
136
|
+
for (const entry of processes) {
|
|
137
|
+
if (excluded.has(entry.pid))
|
|
138
|
+
continue;
|
|
139
|
+
const evidence = classifyProcess(entry);
|
|
140
|
+
if (evidence)
|
|
141
|
+
direct.set(entry.pid, evidence);
|
|
142
|
+
}
|
|
143
|
+
const result = [];
|
|
144
|
+
for (const entry of processes) {
|
|
145
|
+
if (excluded.has(entry.pid))
|
|
146
|
+
continue;
|
|
147
|
+
let owner = direct.get(entry.pid) ?? null;
|
|
148
|
+
let relationship = 'direct';
|
|
149
|
+
if (!owner) {
|
|
150
|
+
const visited = new Set();
|
|
151
|
+
let parentPid = entry.ppid;
|
|
152
|
+
for (let depth = 0; parentPid !== undefined && parentPid > 0 && depth < 24; depth += 1) {
|
|
153
|
+
if (visited.has(parentPid) || excluded.has(parentPid))
|
|
154
|
+
break;
|
|
155
|
+
visited.add(parentPid);
|
|
156
|
+
owner = direct.get(parentPid) ?? null;
|
|
157
|
+
if (owner) {
|
|
158
|
+
relationship = 'descendant';
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
parentPid = byPid.get(parentPid)?.ppid;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (!owner)
|
|
165
|
+
continue;
|
|
166
|
+
result.push({
|
|
167
|
+
pid: entry.pid,
|
|
168
|
+
ppid: entry.ppid ?? null,
|
|
169
|
+
signature: owner.signature.signature,
|
|
170
|
+
name: owner.signature.name,
|
|
171
|
+
kind: owner.signature.kind,
|
|
172
|
+
confidence: owner.confidence,
|
|
173
|
+
relationship,
|
|
174
|
+
cpu_percent: Number.isFinite(entry.cpu_percent) ? Math.max(0, Number(entry.cpu_percent)) : null,
|
|
175
|
+
memory_percent: Number.isFinite(entry.memory_percent) ? Math.max(0, Number(entry.memory_percent)) : null,
|
|
176
|
+
cpu_time_ms: Number.isFinite(entry.cpu_time_ms) ? Math.max(0, Number(entry.cpu_time_ms)) : null,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return result.sort((left, right) => left.signature.localeCompare(right.signature) || left.pid - right.pid);
|
|
180
|
+
}
|
|
181
|
+
function parseMacosCpuTime(value) {
|
|
182
|
+
const match = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+(?:\.\d+)?)$/.exec(value.trim());
|
|
183
|
+
if (!match)
|
|
184
|
+
return null;
|
|
185
|
+
const days = Number(match[1] ?? 0);
|
|
186
|
+
const hours = Number(match[2] ?? 0);
|
|
187
|
+
const minutes = Number(match[3] ?? 0);
|
|
188
|
+
const seconds = Number(match[4] ?? 0);
|
|
189
|
+
if (![days, hours, minutes, seconds].every(Number.isFinite))
|
|
190
|
+
return null;
|
|
191
|
+
return Math.round((((days * 24 + hours) * 60 + minutes) * 60 + seconds) * 1000);
|
|
192
|
+
}
|
|
193
|
+
async function macosProcessMetrics() {
|
|
194
|
+
if (process.platform !== 'darwin')
|
|
195
|
+
return new Map();
|
|
196
|
+
try {
|
|
197
|
+
const { stdout } = await execFileAsync('ps', ['-axo', 'pid=,time=,rss='], {
|
|
198
|
+
encoding: 'utf8',
|
|
199
|
+
maxBuffer: 16_000_000,
|
|
200
|
+
env: { ...process.env, LC_ALL: 'C', LANG: 'C' },
|
|
201
|
+
});
|
|
202
|
+
const result = new Map();
|
|
203
|
+
for (const line of stdout.split('\n')) {
|
|
204
|
+
const match = /^\s*(\d+)\s+(\S+)\s+(\d+)\s*$/.exec(line);
|
|
205
|
+
if (!match)
|
|
206
|
+
continue;
|
|
207
|
+
const value = parseMacosCpuTime(match[2]);
|
|
208
|
+
const rssKilobytes = Number(match[3]);
|
|
209
|
+
if (value !== null && Number.isFinite(rssKilobytes)) {
|
|
210
|
+
result.set(Number(match[1]), { cpuTimeMs: value, rssBytes: Math.max(0, rssKilobytes) * 1024 });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return new Map();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function confidenceRank(confidence) {
|
|
220
|
+
return confidence === 'high' ? 3 : confidence === 'medium' ? 2 : 1;
|
|
221
|
+
}
|
|
222
|
+
function detectAgentProducts(processes) {
|
|
223
|
+
const grouped = new Map();
|
|
224
|
+
for (const process of processes) {
|
|
225
|
+
const evidence = classifyProcess(process);
|
|
226
|
+
if (!evidence)
|
|
227
|
+
continue;
|
|
228
|
+
grouped.set(evidence.signature.signature, [
|
|
229
|
+
...(grouped.get(evidence.signature.signature) ?? []),
|
|
230
|
+
evidence,
|
|
231
|
+
]);
|
|
232
|
+
}
|
|
233
|
+
return [...grouped.entries()].map(([signature, evidence]) => {
|
|
234
|
+
const definition = evidence[0].signature;
|
|
235
|
+
const strongestEvidence = [...evidence]
|
|
236
|
+
.sort((left, right) => confidenceRank(right.confidence) - confidenceRank(left.confidence))[0];
|
|
237
|
+
const strongest = strongestEvidence.confidence;
|
|
238
|
+
return {
|
|
239
|
+
agent_id: (0, hash_1.stableId)('agent', signature),
|
|
240
|
+
name: definition.name,
|
|
241
|
+
signature,
|
|
242
|
+
kind: definition.kind,
|
|
243
|
+
confidence: strongest,
|
|
244
|
+
instance_count: evidence.length,
|
|
245
|
+
executable_names: [...new Set(evidence.map((entry) => entry.executable))].sort(),
|
|
246
|
+
evidence_hashes: [...new Set(evidence.map((entry) => entry.evidenceHash))].sort(),
|
|
247
|
+
detection_reason: strongestEvidence.reason,
|
|
248
|
+
evidence_status: 'online',
|
|
249
|
+
resource_snapshot: {
|
|
250
|
+
cpu_percent: aggregateMetric(evidence.map((entry) => entry.cpuPercent)),
|
|
251
|
+
memory_percent: aggregateMetric(evidence.map((entry) => entry.memoryPercent)),
|
|
252
|
+
measurement: 'point-in-time-process-metadata',
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
256
|
+
}
|
|
257
|
+
function aggregateMetric(values) {
|
|
258
|
+
const measured = values.filter((value) => value !== null);
|
|
259
|
+
if (measured.length === 0)
|
|
260
|
+
return null;
|
|
261
|
+
return Math.round(measured.reduce((total, value) => total + value, 0) * 10) / 10;
|
|
262
|
+
}
|
|
263
|
+
async function listSystemProcesses() {
|
|
264
|
+
const dynamicImport = new Function('specifier', 'return import(specifier);');
|
|
265
|
+
const imported = await dynamicImport('ps-list');
|
|
266
|
+
const list = imported.default;
|
|
267
|
+
const [processes, macosMetrics] = await Promise.all([list(), macosProcessMetrics()]);
|
|
268
|
+
return processes.map((process) => ({
|
|
269
|
+
pid: process.pid,
|
|
270
|
+
ppid: process.ppid,
|
|
271
|
+
name: process.name,
|
|
272
|
+
...(process.cmd !== undefined ? { cmd: process.cmd } : {}),
|
|
273
|
+
...(Number.isFinite(process.cpu) ? { cpu_percent: Number(process.cpu) } : {}),
|
|
274
|
+
...(Number.isFinite(process.memory) ? { memory_percent: Number(process.memory) } : {}),
|
|
275
|
+
...(macosMetrics.has(process.pid) ? {
|
|
276
|
+
cpu_time_ms: macosMetrics.get(process.pid).cpuTimeMs,
|
|
277
|
+
rss_bytes: macosMetrics.get(process.pid).rssBytes,
|
|
278
|
+
} : {}),
|
|
279
|
+
}));
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=agents.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SurfaceMetrics } from './evaluate';
|
|
2
|
+
declare const SURFACES: readonly ["agents", "tools", "runtimes", "models", "mcp"];
|
|
3
|
+
export interface ConfidenceInterval {
|
|
4
|
+
lower: number;
|
|
5
|
+
upper: number;
|
|
6
|
+
}
|
|
7
|
+
export interface AggregatedSurfaceMetrics extends SurfaceMetrics {
|
|
8
|
+
precision_95_interval: ConfidenceInterval | null;
|
|
9
|
+
recall_95_interval: ConfidenceInterval | null;
|
|
10
|
+
}
|
|
11
|
+
export interface MacosFieldAggregate {
|
|
12
|
+
aggregation: 'macos-independent-labelled-devices';
|
|
13
|
+
schema_version: '1.0';
|
|
14
|
+
product_version: string;
|
|
15
|
+
evaluation_count: number;
|
|
16
|
+
coverage: {
|
|
17
|
+
architecture: Record<string, number>;
|
|
18
|
+
macos_major: Record<string, number>;
|
|
19
|
+
node_major: Record<string, number>;
|
|
20
|
+
};
|
|
21
|
+
metrics: Record<(typeof SURFACES)[number], AggregatedSurfaceMetrics>;
|
|
22
|
+
uploaded: false;
|
|
23
|
+
field_accuracy_claim_allowed: false;
|
|
24
|
+
}
|
|
25
|
+
export declare function aggregateMacosFieldEvaluations(inputs: unknown[]): MacosFieldAggregate;
|
|
26
|
+
export declare function aggregateMacosFieldEvaluationDirectory(directoryPath: string): Promise<MacosFieldAggregate>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1,151 @@
|
|
|
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.aggregateMacosFieldEvaluations = aggregateMacosFieldEvaluations;
|
|
7
|
+
exports.aggregateMacosFieldEvaluationDirectory = aggregateMacosFieldEvaluationDirectory;
|
|
8
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const SURFACES = ['agents', 'tools', 'runtimes', 'models', 'mcp'];
|
|
11
|
+
function finiteNonNegativeInteger(value, label) {
|
|
12
|
+
if (!Number.isInteger(value) || Number(value) < 0)
|
|
13
|
+
throw new Error(`${label} must be a non-negative integer.`);
|
|
14
|
+
return Number(value);
|
|
15
|
+
}
|
|
16
|
+
function finitePositiveInteger(value, label) {
|
|
17
|
+
const parsed = finiteNonNegativeInteger(value, label);
|
|
18
|
+
if (parsed === 0)
|
|
19
|
+
throw new Error(`${label} must be positive.`);
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
function parseMetric(value, label) {
|
|
23
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
24
|
+
throw new Error(`${label} must be an object.`);
|
|
25
|
+
const record = value;
|
|
26
|
+
const truePositive = finiteNonNegativeInteger(record.true_positive, `${label}.true_positive`);
|
|
27
|
+
const falsePositive = finiteNonNegativeInteger(record.false_positive, `${label}.false_positive`);
|
|
28
|
+
const falseNegative = finiteNonNegativeInteger(record.false_negative, `${label}.false_negative`);
|
|
29
|
+
const actualCount = truePositive + falsePositive;
|
|
30
|
+
const expectedCount = truePositive + falseNegative;
|
|
31
|
+
return {
|
|
32
|
+
actual_count: actualCount,
|
|
33
|
+
expected_count: expectedCount,
|
|
34
|
+
true_positive: truePositive,
|
|
35
|
+
false_positive: falsePositive,
|
|
36
|
+
false_negative: falseNegative,
|
|
37
|
+
precision: actualCount === 0 ? null : truePositive / actualCount,
|
|
38
|
+
recall: expectedCount === 0 ? null : truePositive / expectedCount,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function parseEvaluation(value) {
|
|
42
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
43
|
+
throw new Error('Evaluation must be an object.');
|
|
44
|
+
const record = value;
|
|
45
|
+
if (record.evaluation !== 'macos-local-labelled-device' || record.schema_version !== '1.0') {
|
|
46
|
+
throw new Error('Unsupported macOS field evaluation.');
|
|
47
|
+
}
|
|
48
|
+
if (record.uploaded !== false || record.field_accuracy_claim_allowed !== false) {
|
|
49
|
+
throw new Error('Evaluation privacy flags are invalid.');
|
|
50
|
+
}
|
|
51
|
+
const environment = record.environment;
|
|
52
|
+
if (!environment || environment.platform !== 'darwin' || typeof environment.architecture !== 'string' || !environment.architecture) {
|
|
53
|
+
throw new Error('Evaluation environment is invalid.');
|
|
54
|
+
}
|
|
55
|
+
const macosMajor = environment.macos_major === null
|
|
56
|
+
? null
|
|
57
|
+
: finitePositiveInteger(environment.macos_major, 'environment.macos_major');
|
|
58
|
+
const nodeMajor = finitePositiveInteger(environment.node_major, 'environment.node_major');
|
|
59
|
+
const metricsRecord = record.metrics;
|
|
60
|
+
if (!metricsRecord)
|
|
61
|
+
throw new Error('Evaluation metrics are missing.');
|
|
62
|
+
const productVersion = record.product_version;
|
|
63
|
+
if (typeof productVersion !== 'string' || !productVersion)
|
|
64
|
+
throw new Error('Evaluation product version is invalid.');
|
|
65
|
+
const metrics = Object.fromEntries(SURFACES.map((surface) => [surface, parseMetric(metricsRecord[surface], `metrics.${surface}`)]));
|
|
66
|
+
return {
|
|
67
|
+
evaluation: 'macos-local-labelled-device',
|
|
68
|
+
schema_version: '1.0',
|
|
69
|
+
product_version: productVersion,
|
|
70
|
+
environment: {
|
|
71
|
+
platform: 'darwin',
|
|
72
|
+
architecture: environment.architecture,
|
|
73
|
+
macos_major: macosMajor,
|
|
74
|
+
node_major: nodeMajor,
|
|
75
|
+
},
|
|
76
|
+
metrics: metrics,
|
|
77
|
+
uploaded: false,
|
|
78
|
+
field_accuracy_claim_allowed: false,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function wilson(successes, total) {
|
|
82
|
+
if (total === 0)
|
|
83
|
+
return null;
|
|
84
|
+
const z = 1.959963984540054;
|
|
85
|
+
const proportion = successes / total;
|
|
86
|
+
const denominator = 1 + (z * z) / total;
|
|
87
|
+
const center = (proportion + (z * z) / (2 * total)) / denominator;
|
|
88
|
+
const margin = (z / denominator) * Math.sqrt((proportion * (1 - proportion)) / total + (z * z) / (4 * total * total));
|
|
89
|
+
return { lower: Math.max(0, center - margin), upper: Math.min(1, center + margin) };
|
|
90
|
+
}
|
|
91
|
+
function countValues(values) {
|
|
92
|
+
const counts = new Map();
|
|
93
|
+
for (const value of values) {
|
|
94
|
+
const key = value === null ? 'unknown' : String(value);
|
|
95
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
96
|
+
}
|
|
97
|
+
return Object.fromEntries([...counts.entries()].sort(([left], [right]) => left.localeCompare(right)));
|
|
98
|
+
}
|
|
99
|
+
function aggregateMacosFieldEvaluations(inputs) {
|
|
100
|
+
if (inputs.length === 0)
|
|
101
|
+
throw new Error('At least one macOS field evaluation is required.');
|
|
102
|
+
const evaluations = inputs.map(parseEvaluation);
|
|
103
|
+
const productVersions = new Set(evaluations.map((evaluation) => evaluation.product_version));
|
|
104
|
+
if (productVersions.size !== 1)
|
|
105
|
+
throw new Error('Cannot aggregate evaluations from different product versions.');
|
|
106
|
+
const metrics = Object.fromEntries(SURFACES.map((surface) => {
|
|
107
|
+
const sums = evaluations.reduce((total, evaluation) => {
|
|
108
|
+
const metric = evaluation.metrics[surface];
|
|
109
|
+
total.truePositive += metric.true_positive;
|
|
110
|
+
total.falsePositive += metric.false_positive;
|
|
111
|
+
total.falseNegative += metric.false_negative;
|
|
112
|
+
return total;
|
|
113
|
+
}, { truePositive: 0, falsePositive: 0, falseNegative: 0 });
|
|
114
|
+
const actualCount = sums.truePositive + sums.falsePositive;
|
|
115
|
+
const expectedCount = sums.truePositive + sums.falseNegative;
|
|
116
|
+
return [surface, {
|
|
117
|
+
actual_count: actualCount,
|
|
118
|
+
expected_count: expectedCount,
|
|
119
|
+
true_positive: sums.truePositive,
|
|
120
|
+
false_positive: sums.falsePositive,
|
|
121
|
+
false_negative: sums.falseNegative,
|
|
122
|
+
precision: actualCount === 0 ? null : sums.truePositive / actualCount,
|
|
123
|
+
recall: expectedCount === 0 ? null : sums.truePositive / expectedCount,
|
|
124
|
+
precision_95_interval: wilson(sums.truePositive, actualCount),
|
|
125
|
+
recall_95_interval: wilson(sums.truePositive, expectedCount),
|
|
126
|
+
}];
|
|
127
|
+
}));
|
|
128
|
+
return {
|
|
129
|
+
aggregation: 'macos-independent-labelled-devices',
|
|
130
|
+
schema_version: '1.0',
|
|
131
|
+
product_version: evaluations[0].product_version,
|
|
132
|
+
evaluation_count: evaluations.length,
|
|
133
|
+
coverage: {
|
|
134
|
+
architecture: countValues(evaluations.map((evaluation) => evaluation.environment.architecture)),
|
|
135
|
+
macos_major: countValues(evaluations.map((evaluation) => evaluation.environment.macos_major)),
|
|
136
|
+
node_major: countValues(evaluations.map((evaluation) => evaluation.environment.node_major)),
|
|
137
|
+
},
|
|
138
|
+
metrics: metrics,
|
|
139
|
+
uploaded: false,
|
|
140
|
+
field_accuracy_claim_allowed: false,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async function aggregateMacosFieldEvaluationDirectory(directoryPath) {
|
|
144
|
+
const directory = node_path_1.default.resolve(directoryPath);
|
|
145
|
+
const entries = (await promises_1.default.readdir(directory, { withFileTypes: true }))
|
|
146
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
|
|
147
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
148
|
+
const inputs = await Promise.all(entries.map(async (entry) => JSON.parse(await promises_1.default.readFile(node_path_1.default.join(directory, entry.name), 'utf8'))));
|
|
149
|
+
return aggregateMacosFieldEvaluations(inputs);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=aggregate.js.map
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0"><dict>
|
|
4
|
+
<key>CFBundleDevelopmentRegion</key><string>en</string><key>CFBundleDisplayName</key><string>Forkit AI Footprint</string><key>CFBundleExecutable</key><string>Forkit AI Footprint</string><key>CFBundleIconFile</key><string>ForkitAIFootprint</string><key>CFBundleIdentifier</key><string>dev.forkit.ai-footprints</string><key>CFBundleInfoDictionaryVersion</key><string>6.0</string><key>CFBundleName</key><string>Forkit AI Footprint</string><key>CFBundlePackageType</key><string>APPL</string><key>CFBundleShortVersionString</key><string>0.2.0</string><key>CFBundleVersion</key><string>1</string><key>LSMinimumSystemVersion</key><string>14.0</string>
|
|
5
|
+
</dict></plist>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CensusAgent, Confidence, ProcessEntry } from './types';
|
|
2
|
+
export interface ClassifiedAgentProcess {
|
|
3
|
+
pid: number;
|
|
4
|
+
ppid: number | null;
|
|
5
|
+
signature: string;
|
|
6
|
+
name: string;
|
|
7
|
+
kind: string;
|
|
8
|
+
confidence: Confidence;
|
|
9
|
+
relationship: 'direct' | 'descendant';
|
|
10
|
+
cpu_percent: number | null;
|
|
11
|
+
memory_percent: number | null;
|
|
12
|
+
cpu_time_ms: number | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds private process-tree evidence for the activity monitor. PIDs and raw
|
|
16
|
+
* commands remain internal and are deliberately absent from public reports.
|
|
17
|
+
*/
|
|
18
|
+
export declare function classifyAgentProcessTrees(processes: ProcessEntry[], excludedRootPid?: number | null): ClassifiedAgentProcess[];
|
|
19
|
+
export declare function parseMacosCpuTime(value: string): number | null;
|
|
20
|
+
export declare function detectAgentProducts(processes: ProcessEntry[]): CensusAgent[];
|
|
21
|
+
export declare function listSystemProcesses(): Promise<ProcessEntry[]>;
|
|
22
|
+
//# sourceMappingURL=agents.d.ts.map
|