forkit-ai-footprints 0.2.0 → 0.2.4
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/PRIVACY.md +57 -27
- package/README.md +43 -41
- package/STATUS.md +92 -37
- package/dist/activity-page.d.ts +13 -0
- package/dist/activity-page.js +105 -0
- package/dist/activity-view-model.d.ts +154 -0
- package/dist/activity-view-model.js +364 -0
- package/dist/agents.d.ts +2 -0
- package/dist/agents.js +108 -6
- package/dist/bootstrap/.metadata_never_index +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app.zip +0 -0
- package/dist/cli.js +91 -14
- package/dist/device-presence.d.ts +17 -0
- package/dist/device-presence.js +64 -0
- package/dist/global-preview.d.ts +34 -0
- package/dist/global-preview.js +209 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/insights.d.ts +1 -1
- package/dist/insights.js +10 -8
- package/dist/local-observation-state.d.ts +43 -0
- package/dist/local-observation-state.js +124 -0
- package/dist/locales.json +564 -108
- package/dist/localization.d.ts +564 -108
- package/dist/localization.js +40 -30
- package/dist/monitor.d.ts +38 -2
- package/dist/monitor.js +257 -19
- package/dist/runtime-activity.d.ts +4 -1
- package/dist/runtime-activity.js +21 -5
- package/dist/server.d.ts +5 -0
- package/dist/server.js +160 -17
- package/dist/share-page.d.ts +2 -1
- package/dist/share-page.js +16 -52
- package/dist/sharing.d.ts +12 -1
- package/dist/sharing.js +59 -1
- package/dist/types.d.ts +1 -1
- package/dist/workflow-context.d.ts +13 -0
- package/dist/workflow-context.js +144 -0
- package/docs/GLOBAL_DISTRIBUTION.md +7 -3
- package/docs/MACOS_ACCURACY_GATE.md +3 -3
- package/docs/MACOS_TESTER_GUIDE.md +11 -10
- package/package.json +6 -6
- package/release/channels.json +2 -2
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Info.plist +0 -5
- 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 +0 -22
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/agents.js +0 -281
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.d.ts +0 -28
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.js +0 -151
- 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 +0 -3
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/census.js +0 -196
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.d.ts +0 -32
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.js +0 -404
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.d.ts +0 -14
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.js +0 -71
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.d.ts +0 -8
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.js +0 -45
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.d.ts +0 -44
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.js +0 -102
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.d.ts +0 -11
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.js +0 -226
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.d.ts +0 -7
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.js +0 -78
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.d.ts +0 -4
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.js +0 -16
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.d.ts +0 -22
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.js +0 -58
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.d.ts +0 -13
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.js +0 -76
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.d.ts +0 -19
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.js +0 -81
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/locales.json +0 -272
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.d.ts +0 -277
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.js +0 -55
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.d.ts +0 -9
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.js +0 -93
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.d.ts +0 -99
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.js +0 -285
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.d.ts +0 -34
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.js +0 -88
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.d.ts +0 -6
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.js +0 -24
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.d.ts +0 -9
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.js +0 -71
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.d.ts +0 -12
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.js +0 -171
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.d.ts +0 -10
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.js +0 -68
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.d.ts +0 -17
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.js +0 -52
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.d.ts +0 -5
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.js +0 -66
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.d.ts +0 -7
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.js +0 -66
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.d.ts +0 -21
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.js +0 -308
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.d.ts +0 -75
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.js +0 -167
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.d.ts +0 -35
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.js +0 -67
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.d.ts +0 -9
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.js +0 -106
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.d.ts +0 -166
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.js +0 -3
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.d.ts +0 -4
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.js +0 -13
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.d.ts +0 -76
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.js +0 -366
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/license +0 -9
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/package.json +0 -44
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/readme.md +0 -56
- 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 +0 -6
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/runtime/node +0 -0
- package/dist/bootstrap/Forkit AI Footprint.app/Contents/_CodeSignature/CodeResources +0 -931
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeActivitySegments = mergeActivitySegments;
|
|
4
|
+
exports.normalizeActivitySegments = normalizeActivitySegments;
|
|
5
|
+
exports.calculateSystemContributions = calculateSystemContributions;
|
|
6
|
+
exports.buildResourceHistoryView = buildResourceHistoryView;
|
|
7
|
+
exports.aggregateCurrentAiResources = aggregateCurrentAiResources;
|
|
8
|
+
exports.availableLocalDateKeys = availableLocalDateKeys;
|
|
9
|
+
exports.formatObservationDateRange = formatObservationDateRange;
|
|
10
|
+
exports.selectedTimeRange = selectedTimeRange;
|
|
11
|
+
exports.resolveSelectedSystemSignature = resolveSelectedSystemSignature;
|
|
12
|
+
exports.insightEvidenceTarget = insightEvidenceTarget;
|
|
13
|
+
exports.buildActivityExplorerViewModel = buildActivityExplorerViewModel;
|
|
14
|
+
function finiteTimestamp(value) {
|
|
15
|
+
const parsed = Date.parse(value);
|
|
16
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
17
|
+
}
|
|
18
|
+
function sameStrings(left, right) {
|
|
19
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
20
|
+
}
|
|
21
|
+
function canMerge(left, right, toleranceMs) {
|
|
22
|
+
return left.state === right.state
|
|
23
|
+
&& left.valid === right.valid
|
|
24
|
+
&& left.continuity_id === right.continuity_id
|
|
25
|
+
&& left.excluded_reason === right.excluded_reason
|
|
26
|
+
&& sameStrings(left.system_signatures, right.system_signatures)
|
|
27
|
+
&& right.start_ms - left.end_ms <= toleranceMs;
|
|
28
|
+
}
|
|
29
|
+
function mergeActivitySegments(segments, toleranceMs) {
|
|
30
|
+
const merged = [];
|
|
31
|
+
for (const segment of segments) {
|
|
32
|
+
const previous = merged.at(-1);
|
|
33
|
+
if (previous && canMerge(previous, segment, toleranceMs))
|
|
34
|
+
previous.end_ms = Math.max(previous.end_ms, segment.end_ms);
|
|
35
|
+
else
|
|
36
|
+
merged.push({ ...segment, system_signatures: [...segment.system_signatures] });
|
|
37
|
+
}
|
|
38
|
+
return merged;
|
|
39
|
+
}
|
|
40
|
+
function normalizeActivitySegments(timeline, sampleIntervalMs) {
|
|
41
|
+
const safeInterval = Math.max(1, sampleIntervalMs);
|
|
42
|
+
const source = timeline.flatMap((segment) => {
|
|
43
|
+
const start = finiteTimestamp(segment.started_at);
|
|
44
|
+
const end = finiteTimestamp(segment.ended_at);
|
|
45
|
+
if (start === null || end === null || end < start)
|
|
46
|
+
return [];
|
|
47
|
+
return [{
|
|
48
|
+
start_ms: start,
|
|
49
|
+
end_ms: end,
|
|
50
|
+
state: segment.state === 'working-now' ? 'active' : 'idle',
|
|
51
|
+
valid: true,
|
|
52
|
+
system_signatures: [...new Set(segment.product_signatures)].sort(),
|
|
53
|
+
observation_id: segment.observation_id ?? null,
|
|
54
|
+
continuity_id: segment.continuity_id ?? segment.observation_id ?? null,
|
|
55
|
+
excluded_reason: null,
|
|
56
|
+
}];
|
|
57
|
+
}).sort((left, right) => left.start_ms - right.start_ms || left.end_ms - right.end_ms);
|
|
58
|
+
const withExcluded = [];
|
|
59
|
+
for (const segment of source) {
|
|
60
|
+
const previous = withExcluded.at(-1);
|
|
61
|
+
if (previous) {
|
|
62
|
+
const gap = segment.start_ms - previous.end_ms;
|
|
63
|
+
const sessionChanged = previous.observation_id !== null
|
|
64
|
+
&& segment.observation_id !== null
|
|
65
|
+
&& previous.observation_id !== segment.observation_id;
|
|
66
|
+
if (gap > safeInterval * 3 || (sessionChanged && gap > safeInterval * 1.5)) {
|
|
67
|
+
withExcluded.push({
|
|
68
|
+
start_ms: previous.end_ms,
|
|
69
|
+
end_ms: segment.start_ms,
|
|
70
|
+
state: 'excluded',
|
|
71
|
+
valid: false,
|
|
72
|
+
system_signatures: [],
|
|
73
|
+
observation_id: null,
|
|
74
|
+
continuity_id: null,
|
|
75
|
+
excluded_reason: null,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
withExcluded.push(segment);
|
|
80
|
+
}
|
|
81
|
+
const merged = mergeActivitySegments(withExcluded, safeInterval * 1.5);
|
|
82
|
+
const activeBlocks = [];
|
|
83
|
+
merged.forEach((segment, index) => {
|
|
84
|
+
if (segment.state !== 'active')
|
|
85
|
+
return;
|
|
86
|
+
const previous = activeBlocks.at(-1);
|
|
87
|
+
const continues = previous
|
|
88
|
+
&& previous.continuity_id === segment.continuity_id
|
|
89
|
+
&& segment.start_ms - previous.end_ms <= safeInterval * 3
|
|
90
|
+
&& merged.slice(previous.indexes.at(-1) + 1, index).every((between) => between.state === 'active');
|
|
91
|
+
if (continues) {
|
|
92
|
+
previous.end_ms = Math.max(previous.end_ms, segment.end_ms);
|
|
93
|
+
previous.indexes.push(index);
|
|
94
|
+
}
|
|
95
|
+
else
|
|
96
|
+
activeBlocks.push({ start_ms: segment.start_ms, end_ms: segment.end_ms, indexes: [index], continuity_id: segment.continuity_id });
|
|
97
|
+
});
|
|
98
|
+
const longestBlock = activeBlocks.sort((left, right) => (right.end_ms - right.start_ms) - (left.end_ms - left.start_ms))[0] ?? null;
|
|
99
|
+
const longestIndexes = new Set(longestBlock?.indexes ?? []);
|
|
100
|
+
const activeBlockByIndex = new Map(activeBlocks.flatMap((block, blockIndex) => block.indexes.map((index) => [index, blockIndex])));
|
|
101
|
+
return merged.map((segment, index) => ({
|
|
102
|
+
id: `segment-${index}-${segment.start_ms}`,
|
|
103
|
+
...segment,
|
|
104
|
+
duration_seconds: Math.max(0, segment.end_ms - segment.start_ms) / 1000,
|
|
105
|
+
is_longest_active: longestIndexes.has(index),
|
|
106
|
+
active_block_id: activeBlockByIndex.get(index) ?? null,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
function calculateSystemContributions(products) {
|
|
110
|
+
const hasEmbeddedCodex = products.some((product) => product.signature === 'chatgpt-codex');
|
|
111
|
+
const active = products
|
|
112
|
+
.filter((product) => !(hasEmbeddedCodex && product.signature === 'chatgpt'))
|
|
113
|
+
.filter((product) => Number.isFinite(product.active_seconds) && product.active_seconds > 0)
|
|
114
|
+
.map((product) => ({
|
|
115
|
+
signature: product.signature,
|
|
116
|
+
name: product.name,
|
|
117
|
+
kind: product.kind,
|
|
118
|
+
active_seconds: Math.max(0, product.active_seconds),
|
|
119
|
+
}));
|
|
120
|
+
const total = active.reduce((sum, product) => sum + product.active_seconds, 0);
|
|
121
|
+
return active
|
|
122
|
+
.map((product) => ({ ...product, share: total > 0 ? product.active_seconds / total : 0 }))
|
|
123
|
+
.sort((left, right) => right.active_seconds - left.active_seconds || left.name.localeCompare(right.name));
|
|
124
|
+
}
|
|
125
|
+
function finiteNumber(value) {
|
|
126
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
127
|
+
}
|
|
128
|
+
function weightedAverage(values, value, weight) {
|
|
129
|
+
let total = 0;
|
|
130
|
+
let measured = 0;
|
|
131
|
+
for (const item of values) {
|
|
132
|
+
const next = value(item);
|
|
133
|
+
if (next === null)
|
|
134
|
+
continue;
|
|
135
|
+
const nextWeight = Math.max(0, weight(item));
|
|
136
|
+
if (nextWeight <= 0)
|
|
137
|
+
continue;
|
|
138
|
+
total += next * nextWeight;
|
|
139
|
+
measured += nextWeight;
|
|
140
|
+
}
|
|
141
|
+
return measured > 0 ? total / measured : null;
|
|
142
|
+
}
|
|
143
|
+
function rounded(value, digits = 1) {
|
|
144
|
+
const factor = 10 ** digits;
|
|
145
|
+
return Math.round(value * factor) / factor;
|
|
146
|
+
}
|
|
147
|
+
function buildResourceHistoryView(history = []) {
|
|
148
|
+
const buckets = history.flatMap((bucket) => {
|
|
149
|
+
const start = finiteTimestamp(bucket.started_at);
|
|
150
|
+
const end = finiteTimestamp(bucket.ended_at);
|
|
151
|
+
if (start === null || end === null || end < start)
|
|
152
|
+
return [];
|
|
153
|
+
return [{
|
|
154
|
+
start_ms: start,
|
|
155
|
+
end_ms: end,
|
|
156
|
+
system_signature: bucket.system_signature,
|
|
157
|
+
system_name: bucket.system_name,
|
|
158
|
+
kind: bucket.kind,
|
|
159
|
+
observed_seconds: Math.max(0, Number(bucket.observed_seconds) || 0),
|
|
160
|
+
active_seconds: Math.max(0, Number(bucket.active_seconds) || 0),
|
|
161
|
+
avg_cpu_percent: finiteNumber(bucket.avg_cpu_percent),
|
|
162
|
+
peak_cpu_percent: finiteNumber(bucket.peak_cpu_percent),
|
|
163
|
+
avg_memory_bytes: finiteNumber(bucket.avg_memory_bytes),
|
|
164
|
+
peak_memory_bytes: finiteNumber(bucket.peak_memory_bytes),
|
|
165
|
+
peak_process_count: Math.max(0, Math.trunc(Number(bucket.peak_process_count) || 0)),
|
|
166
|
+
sample_count: Math.max(0, Math.trunc(Number(bucket.sample_count) || 0)),
|
|
167
|
+
}];
|
|
168
|
+
}).sort((left, right) => left.start_ms - right.start_ms || left.system_name.localeCompare(right.system_name));
|
|
169
|
+
const bySystem = new Map();
|
|
170
|
+
for (const bucket of buckets)
|
|
171
|
+
bySystem.set(bucket.system_signature, [...(bySystem.get(bucket.system_signature) ?? []), bucket]);
|
|
172
|
+
const systems = [...bySystem.entries()].map(([signature, entries]) => ({
|
|
173
|
+
signature,
|
|
174
|
+
name: entries.at(-1)?.system_name ?? signature,
|
|
175
|
+
kind: entries.at(-1)?.kind ?? 'unknown',
|
|
176
|
+
observed_seconds: rounded(entries.reduce((sum, bucket) => sum + bucket.observed_seconds, 0)),
|
|
177
|
+
active_seconds: rounded(entries.reduce((sum, bucket) => sum + bucket.active_seconds, 0)),
|
|
178
|
+
avg_cpu_percent: (() => {
|
|
179
|
+
const value = weightedAverage(entries, (bucket) => bucket.avg_cpu_percent, (bucket) => bucket.observed_seconds);
|
|
180
|
+
return value === null ? null : rounded(value);
|
|
181
|
+
})(),
|
|
182
|
+
peak_cpu_percent: entries.reduce((maximum, bucket) => {
|
|
183
|
+
const value = finiteNumber(bucket.peak_cpu_percent);
|
|
184
|
+
return value === null ? maximum : maximum === null ? value : Math.max(maximum, value);
|
|
185
|
+
}, null),
|
|
186
|
+
avg_memory_bytes: (() => {
|
|
187
|
+
const value = weightedAverage(entries, (bucket) => bucket.avg_memory_bytes, (bucket) => bucket.observed_seconds);
|
|
188
|
+
return value === null ? null : Math.round(value);
|
|
189
|
+
})(),
|
|
190
|
+
peak_memory_bytes: entries.reduce((maximum, bucket) => {
|
|
191
|
+
const value = finiteNumber(bucket.peak_memory_bytes);
|
|
192
|
+
return value === null ? maximum : maximum === null ? value : Math.max(maximum, value);
|
|
193
|
+
}, null),
|
|
194
|
+
peak_process_count: entries.reduce((maximum, bucket) => Math.max(maximum, bucket.peak_process_count), 0),
|
|
195
|
+
sample_count: entries.reduce((sum, bucket) => sum + bucket.sample_count, 0),
|
|
196
|
+
})).sort((left, right) => right.active_seconds - left.active_seconds || right.observed_seconds - left.observed_seconds || left.name.localeCompare(right.name));
|
|
197
|
+
return { buckets, systems };
|
|
198
|
+
}
|
|
199
|
+
function aggregateCurrentAiResources(products) {
|
|
200
|
+
const cpu = products.map((product) => finiteNumber(product.cpu_percent)).filter((value) => value !== null);
|
|
201
|
+
const memory = products.map((product) => finiteNumber(product.memory_bytes)).filter((value) => value !== null);
|
|
202
|
+
return {
|
|
203
|
+
cpu_percent: cpu.length ? cpu.reduce((sum, value) => sum + Math.max(0, value), 0) : null,
|
|
204
|
+
memory_bytes: memory.length ? memory.reduce((sum, value) => sum + Math.max(0, value), 0) : null,
|
|
205
|
+
process_count: products.reduce((sum, product) => sum + Math.max(0, Math.trunc(product.process_count || 0)), 0),
|
|
206
|
+
contributing_system_count: products.filter((product) => finiteNumber(product.cpu_percent) !== null || finiteNumber(product.memory_bytes) !== null).length,
|
|
207
|
+
measurement: 'current-detected-process-trees',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function dateKeyFormatter(timeZone) {
|
|
211
|
+
return new Intl.DateTimeFormat('en-CA', {
|
|
212
|
+
timeZone,
|
|
213
|
+
year: 'numeric',
|
|
214
|
+
month: '2-digit',
|
|
215
|
+
day: '2-digit',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function dateKeyParts(timestampMs, formatter) {
|
|
219
|
+
const parts = Object.fromEntries(formatter.formatToParts(new Date(timestampMs)).map((part) => [part.type, part.value]));
|
|
220
|
+
return `${parts.year}-${parts.month}-${parts.day}`;
|
|
221
|
+
}
|
|
222
|
+
function availableLocalDateKeys(segments, timeZone) {
|
|
223
|
+
const keys = new Set();
|
|
224
|
+
const formatter = dateKeyFormatter(timeZone);
|
|
225
|
+
for (const segment of segments) {
|
|
226
|
+
if (segment.state === 'excluded')
|
|
227
|
+
continue;
|
|
228
|
+
const end = Math.max(segment.start_ms, segment.end_ms - 1);
|
|
229
|
+
for (let cursor = segment.start_ms; cursor < end; cursor += 6 * 60 * 60 * 1000)
|
|
230
|
+
keys.add(dateKeyParts(cursor, formatter));
|
|
231
|
+
keys.add(dateKeyParts(end, formatter));
|
|
232
|
+
}
|
|
233
|
+
return [...keys].sort();
|
|
234
|
+
}
|
|
235
|
+
function formatObservationDateRange(extent, locale, timeZone) {
|
|
236
|
+
if (!extent)
|
|
237
|
+
return null;
|
|
238
|
+
const keyFormatter = dateKeyFormatter(timeZone);
|
|
239
|
+
const startKey = dateKeyParts(extent.start_ms, keyFormatter);
|
|
240
|
+
const endKey = dateKeyParts(Math.max(extent.start_ms, extent.end_ms - 1), keyFormatter);
|
|
241
|
+
const formatter = new Intl.DateTimeFormat(locale, {
|
|
242
|
+
timeZone,
|
|
243
|
+
day: 'numeric',
|
|
244
|
+
month: 'short',
|
|
245
|
+
year: 'numeric',
|
|
246
|
+
});
|
|
247
|
+
const start = formatter.format(new Date(extent.start_ms));
|
|
248
|
+
if (startKey === endKey)
|
|
249
|
+
return start;
|
|
250
|
+
return `${start} – ${formatter.format(new Date(Math.max(extent.start_ms, extent.end_ms - 1)))}`;
|
|
251
|
+
}
|
|
252
|
+
function systemActivitySummaries(products, segments, contributions, sampleIntervalMs, resourceHistory) {
|
|
253
|
+
const contributionMap = new Map(contributions.map((item) => [item.signature, item]));
|
|
254
|
+
const resourceMap = new Map(resourceHistory.systems.map((item) => [item.signature, item]));
|
|
255
|
+
return products
|
|
256
|
+
.filter((product) => !(product.signature === 'chatgpt' && products.some((candidate) => candidate.signature === 'chatgpt-codex')))
|
|
257
|
+
.map((product) => {
|
|
258
|
+
const active = segments.filter((segment) => segment.state === 'active' && segment.system_signatures.includes(product.signature));
|
|
259
|
+
const periods = [];
|
|
260
|
+
for (const segment of active) {
|
|
261
|
+
const previous = periods.at(-1);
|
|
262
|
+
if (previous
|
|
263
|
+
&& previous.observation_id === segment.observation_id
|
|
264
|
+
&& segment.start_ms - previous.end_ms <= Math.max(1_500, sampleIntervalMs * 3)) {
|
|
265
|
+
previous.end_ms = Math.max(previous.end_ms, segment.end_ms);
|
|
266
|
+
}
|
|
267
|
+
else
|
|
268
|
+
periods.push({ start_ms: segment.start_ms, end_ms: segment.end_ms, observation_id: segment.observation_id });
|
|
269
|
+
}
|
|
270
|
+
const contribution = contributionMap.get(product.signature) ?? {
|
|
271
|
+
signature: product.signature,
|
|
272
|
+
name: product.name,
|
|
273
|
+
kind: product.kind,
|
|
274
|
+
active_seconds: Math.max(0, product.active_seconds || 0),
|
|
275
|
+
share: 0,
|
|
276
|
+
};
|
|
277
|
+
const resources = resourceMap.get(product.signature);
|
|
278
|
+
return {
|
|
279
|
+
...contribution,
|
|
280
|
+
state: product.state,
|
|
281
|
+
period_count: periods.length,
|
|
282
|
+
longest_active_seconds: periods.reduce((maximum, period) => Math.max(maximum, (period.end_ms - period.start_ms) / 1000), 0),
|
|
283
|
+
first_observed_ms: periods[0]?.start_ms ?? null,
|
|
284
|
+
last_observed_ms: periods.at(-1)?.end_ms ?? null,
|
|
285
|
+
current_cpu_percent: finiteNumber(product.cpu_percent),
|
|
286
|
+
current_memory_bytes: finiteNumber(product.memory_bytes),
|
|
287
|
+
current_process_count: Math.max(0, Math.trunc(product.process_count || 0)),
|
|
288
|
+
resource_observed_seconds: resources?.observed_seconds ?? 0,
|
|
289
|
+
resource_active_seconds: resources?.active_seconds ?? 0,
|
|
290
|
+
avg_cpu_percent: resources?.avg_cpu_percent ?? null,
|
|
291
|
+
peak_cpu_percent: resources?.peak_cpu_percent ?? null,
|
|
292
|
+
avg_memory_bytes: resources?.avg_memory_bytes ?? null,
|
|
293
|
+
peak_memory_bytes: resources?.peak_memory_bytes ?? null,
|
|
294
|
+
peak_process_count: resources?.peak_process_count ?? 0,
|
|
295
|
+
resource_sample_count: resources?.sample_count ?? 0,
|
|
296
|
+
};
|
|
297
|
+
})
|
|
298
|
+
.sort((left, right) => right.active_seconds - left.active_seconds || left.name.localeCompare(right.name));
|
|
299
|
+
}
|
|
300
|
+
function selectedTimeRange(segment) {
|
|
301
|
+
return { start_ms: segment.start_ms, end_ms: segment.end_ms, duration_seconds: segment.duration_seconds };
|
|
302
|
+
}
|
|
303
|
+
function resolveSelectedSystemSignature(view, selectedSignature) {
|
|
304
|
+
return selectedSignature && view.systems.some((system) => system.signature === selectedSignature)
|
|
305
|
+
? selectedSignature
|
|
306
|
+
: null;
|
|
307
|
+
}
|
|
308
|
+
function insightEvidenceTarget(kind, segments, contributions) {
|
|
309
|
+
if (kind === 'longest-block') {
|
|
310
|
+
const longest = segments.filter((segment) => segment.is_longest_active);
|
|
311
|
+
if (longest.length)
|
|
312
|
+
return { type: 'range', start_ms: longest[0].start_ms, end_ms: longest.at(-1).end_ms };
|
|
313
|
+
}
|
|
314
|
+
if (kind === 'workflow' || kind === 'hosted-local') {
|
|
315
|
+
const dominant = contributions[0];
|
|
316
|
+
if (dominant)
|
|
317
|
+
return { type: 'system', signature: dominant.signature };
|
|
318
|
+
}
|
|
319
|
+
return { type: 'observation' };
|
|
320
|
+
}
|
|
321
|
+
function buildActivityExplorerViewModel(snapshot, insights = []) {
|
|
322
|
+
const segments = normalizeActivitySegments(snapshot.timeline, snapshot.sample_interval_ms);
|
|
323
|
+
const resourceHistory = buildResourceHistoryView(snapshot.resource_history ?? []);
|
|
324
|
+
const contributions = calculateSystemContributions(snapshot.products);
|
|
325
|
+
const activeSegments = segments.filter((segment) => segment.state === 'active');
|
|
326
|
+
const activeBlockIds = new Set(activeSegments.flatMap((segment) => segment.active_block_id === null ? [] : [segment.active_block_id]));
|
|
327
|
+
const longestSegments = activeSegments.filter((segment) => segment.is_longest_active);
|
|
328
|
+
const longestRange = longestSegments.length
|
|
329
|
+
? { start_ms: longestSegments[0].start_ms, end_ms: longestSegments.at(-1).end_ms }
|
|
330
|
+
: null;
|
|
331
|
+
const excludedSeconds = segments
|
|
332
|
+
.filter((segment) => segment.state === 'excluded')
|
|
333
|
+
.reduce((sum, segment) => sum + segment.duration_seconds, 0);
|
|
334
|
+
const extent = segments.length > 0
|
|
335
|
+
? { start_ms: segments[0].start_ms, end_ms: segments.at(-1).end_ms }
|
|
336
|
+
: null;
|
|
337
|
+
const systems = systemActivitySummaries(snapshot.products, segments, contributions, snapshot.sample_interval_ms, resourceHistory);
|
|
338
|
+
return {
|
|
339
|
+
segments,
|
|
340
|
+
contributions,
|
|
341
|
+
insights: insights.map((insight) => ({
|
|
342
|
+
...insight,
|
|
343
|
+
evidence: insightEvidenceTarget(insight.kind, segments, contributions),
|
|
344
|
+
})),
|
|
345
|
+
extent,
|
|
346
|
+
active_block_count: activeBlockIds.size,
|
|
347
|
+
longest_active_seconds: longestRange ? Math.max(0, longestRange.end_ms - longestRange.start_ms) / 1000 : 0,
|
|
348
|
+
longest_active_range: longestRange,
|
|
349
|
+
idle_seconds: Math.max(0, snapshot.observed_seconds - snapshot.active_seconds),
|
|
350
|
+
excluded_seconds: excludedSeconds,
|
|
351
|
+
simultaneous_systems_max: activeSegments.reduce((maximum, segment) => Math.max(maximum, segment.system_signatures.length), 0),
|
|
352
|
+
active_tool_count: systems.filter((system) => system.active_seconds > 0 || system.state === 'working-now').length,
|
|
353
|
+
observation_ids: [...new Set(segments.flatMap((segment) => segment.observation_id === null ? [] : [segment.observation_id]))].sort((left, right) => left - right),
|
|
354
|
+
continuity_ids: [...new Set(segments.flatMap((segment) => segment.continuity_id === null ? [] : [segment.continuity_id]))].sort((left, right) => left - right),
|
|
355
|
+
available_date_keys: availableLocalDateKeys(segments),
|
|
356
|
+
systems,
|
|
357
|
+
current_resources: aggregateCurrentAiResources(snapshot.products),
|
|
358
|
+
resource_history: resourceHistory,
|
|
359
|
+
resource_history_state: resourceHistory.buckets.length > 0
|
|
360
|
+
? 'retained-local-buckets'
|
|
361
|
+
: snapshot.lifecycle === 'monitoring' ? 'collecting' : 'not-retained',
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=activity-view-model.js.map
|
package/dist/agents.d.ts
CHANGED
|
@@ -9,7 +9,9 @@ export interface ClassifiedAgentProcess {
|
|
|
9
9
|
relationship: 'direct' | 'descendant';
|
|
10
10
|
cpu_percent: number | null;
|
|
11
11
|
memory_percent: number | null;
|
|
12
|
+
memory_bytes: number | null;
|
|
12
13
|
cpu_time_ms: number | null;
|
|
14
|
+
activity_signal?: boolean;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Builds private process-tree evidence for the activity monitor. PIDs and raw
|
package/dist/agents.js
CHANGED
|
@@ -13,6 +13,10 @@ const node_util_1 = require("node:util");
|
|
|
13
13
|
const hash_1 = require("./hash");
|
|
14
14
|
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
15
15
|
const SIGNATURES = [
|
|
16
|
+
{ signature: 'chatgpt', name: 'ChatGPT', kind: 'ai-app', terms: ['chatgpt'], executables: ['chatgpt'] },
|
|
17
|
+
{ signature: 'jan', name: 'Jan', kind: 'ai-app', terms: ['jan'], executables: ['jan'] },
|
|
18
|
+
{ signature: 'lm-studio', name: 'LM Studio', kind: 'ai-app', terms: ['lm-studio', 'lmstudio', 'lm studio'], executables: ['lm-studio', 'lmstudio', 'lm studio'] },
|
|
19
|
+
{ signature: 'open-webui', name: 'Open WebUI', kind: 'ai-app', terms: ['open-webui', 'open_webui'], executables: ['open-webui', 'open_webui'] },
|
|
16
20
|
{ signature: 'codex', name: 'Codex', kind: 'coding-agent', terms: ['codex'], executables: ['codex'] },
|
|
17
21
|
{ signature: 'claude', name: 'Claude Code', kind: 'coding-agent', terms: ['claude', 'claude-code'], executables: ['claude'] },
|
|
18
22
|
{ signature: 'aider', name: 'Aider', kind: 'coding-agent', terms: ['aider'], executables: ['aider'] },
|
|
@@ -35,6 +39,13 @@ const SIGNATURES = [
|
|
|
35
39
|
{ signature: 'pydantic-ai', name: 'PydanticAI', kind: 'agent-framework', terms: ['pydantic-ai', 'pydantic_ai'], executables: ['pydantic-ai', 'pydantic_ai'] },
|
|
36
40
|
{ signature: 'smolagents', name: 'smolagents', kind: 'agent-framework', terms: ['smolagents'], executables: ['smolagents'] },
|
|
37
41
|
];
|
|
42
|
+
const CHATGPT_CODEX_SIGNATURE = {
|
|
43
|
+
signature: 'chatgpt-codex',
|
|
44
|
+
name: 'ChatGPT · Codex',
|
|
45
|
+
kind: 'ai-app',
|
|
46
|
+
terms: ['chatgpt-codex'],
|
|
47
|
+
executables: ['chatgpt', 'codex'],
|
|
48
|
+
};
|
|
38
49
|
function basename(value) {
|
|
39
50
|
const normalized = String(value || '').replaceAll('\\', '/');
|
|
40
51
|
return node_path_1.default.posix.basename(normalized).toLowerCase().replace(/\.exe$/i, '');
|
|
@@ -44,6 +55,15 @@ function commandParts(value) {
|
|
|
44
55
|
.match(/"[^"]*"|'[^']*'|\S+/g)
|
|
45
56
|
?.map((part) => part.replace(/^(?:"|')|(?:"|')$/g, '')) ?? [];
|
|
46
57
|
}
|
|
58
|
+
function macosAppExecutableName(command) {
|
|
59
|
+
const marker = '.app/Contents/MacOS/';
|
|
60
|
+
const markerIndex = command.indexOf(marker);
|
|
61
|
+
if (markerIndex < 0)
|
|
62
|
+
return null;
|
|
63
|
+
const tail = command.slice(markerIndex + marker.length);
|
|
64
|
+
const executable = tail.split(/\s--/)[0]?.trim();
|
|
65
|
+
return executable ? basename(executable) : null;
|
|
66
|
+
}
|
|
47
67
|
function moduleName(parts) {
|
|
48
68
|
const moduleFlag = parts.findIndex((part) => part === '-m');
|
|
49
69
|
if (moduleFlag < 0)
|
|
@@ -77,12 +97,36 @@ function nodeBinName(parts) {
|
|
|
77
97
|
return null;
|
|
78
98
|
return basename(script);
|
|
79
99
|
}
|
|
100
|
+
function isNonAiSupportProcess(processName, executable, command) {
|
|
101
|
+
const supportText = `${processName} ${executable} ${command}`.toLowerCase();
|
|
102
|
+
return supportText.includes('browser_crashpad_handler')
|
|
103
|
+
|| supportText.includes('crashpad_handler')
|
|
104
|
+
|| processName === 'autoupdate'
|
|
105
|
+
|| processName === 'updater'
|
|
106
|
+
|| executable === 'autoupdate'
|
|
107
|
+
|| executable === 'updater';
|
|
108
|
+
}
|
|
109
|
+
function isPassiveAppHelperProcess(entry) {
|
|
110
|
+
const processText = `${entry.name ?? ''} ${entry.cmd ?? ''}`.toLowerCase();
|
|
111
|
+
return processText.includes('codex (renderer)')
|
|
112
|
+
|| processText.includes('codex (service)')
|
|
113
|
+
|| processText.includes('--type=renderer')
|
|
114
|
+
|| processText.includes('--type=utility')
|
|
115
|
+
|| processText.includes('--type=gpu-process')
|
|
116
|
+
|| processText.includes('browser_crashpad_handler')
|
|
117
|
+
|| processText.includes('crashpad_handler')
|
|
118
|
+
|| processText.includes('/sparkle.framework/')
|
|
119
|
+
|| /\bautoupdate\b/.test(processText)
|
|
120
|
+
|| /\bupdater\b/.test(processText);
|
|
121
|
+
}
|
|
80
122
|
function classifyProcess(entry) {
|
|
81
123
|
const processName = basename(entry.name ?? '');
|
|
82
124
|
const command = String(entry.cmd ?? '');
|
|
83
125
|
const parts = commandParts(command);
|
|
84
126
|
const firstCommandToken = parts[0] ?? '';
|
|
85
|
-
const executable = basename(firstCommandToken || processName) || 'unknown';
|
|
127
|
+
const executable = macosAppExecutableName(command) ?? (basename(firstCommandToken || processName) || 'unknown');
|
|
128
|
+
if (isNonAiSupportProcess(processName, executable, command))
|
|
129
|
+
return null;
|
|
86
130
|
const invokedModule = moduleName(parts);
|
|
87
131
|
const invokedPackage = packageRunnerName(parts) ?? nodeBinName(parts);
|
|
88
132
|
for (const signature of SIGNATURES) {
|
|
@@ -125,6 +169,57 @@ function descendantsOf(processes, rootPid) {
|
|
|
125
169
|
}
|
|
126
170
|
return excluded;
|
|
127
171
|
}
|
|
172
|
+
function nearestDirectAncestor(byPid, direct, start, signature) {
|
|
173
|
+
const visited = new Set();
|
|
174
|
+
let parentPid = start.ppid;
|
|
175
|
+
for (let depth = 0; parentPid !== undefined && parentPid > 0 && depth < 24; depth += 1) {
|
|
176
|
+
if (visited.has(parentPid))
|
|
177
|
+
break;
|
|
178
|
+
visited.add(parentPid);
|
|
179
|
+
const owner = direct.get(parentPid);
|
|
180
|
+
if (owner?.signature.signature === signature)
|
|
181
|
+
return parentPid;
|
|
182
|
+
parentPid = byPid.get(parentPid)?.ppid;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
function asEmbeddedChatGptCodex(evidence) {
|
|
187
|
+
return {
|
|
188
|
+
...evidence,
|
|
189
|
+
signature: CHATGPT_CODEX_SIGNATURE,
|
|
190
|
+
confidence: 'high',
|
|
191
|
+
reason: 'embedded_chatgpt_codex_process_tree',
|
|
192
|
+
evidenceHash: (0, hash_1.sha256)(`${CHATGPT_CODEX_SIGNATURE.signature}:${evidence.executable}:${evidence.reason}`),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function collapseEmbeddedOpenAiAppStack(processes, direct) {
|
|
196
|
+
const byPid = new Map(processes.map((entry) => [entry.pid, entry]));
|
|
197
|
+
const chatGptRootsWithCodex = new Set();
|
|
198
|
+
const embeddedCodexPids = new Set();
|
|
199
|
+
for (const entry of processes) {
|
|
200
|
+
const owner = direct.get(entry.pid);
|
|
201
|
+
if (owner?.signature.signature !== 'codex')
|
|
202
|
+
continue;
|
|
203
|
+
const chatGptRoot = nearestDirectAncestor(byPid, direct, entry, 'chatgpt');
|
|
204
|
+
if (chatGptRoot === null)
|
|
205
|
+
continue;
|
|
206
|
+
chatGptRootsWithCodex.add(chatGptRoot);
|
|
207
|
+
embeddedCodexPids.add(entry.pid);
|
|
208
|
+
}
|
|
209
|
+
if (chatGptRootsWithCodex.size === 0)
|
|
210
|
+
return direct;
|
|
211
|
+
const collapsed = new Map();
|
|
212
|
+
for (const [pid, evidence] of direct) {
|
|
213
|
+
if ((evidence.signature.signature === 'chatgpt' && chatGptRootsWithCodex.has(pid))
|
|
214
|
+
|| (evidence.signature.signature === 'codex' && embeddedCodexPids.has(pid))) {
|
|
215
|
+
collapsed.set(pid, asEmbeddedChatGptCodex(evidence));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
collapsed.set(pid, evidence);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return collapsed;
|
|
222
|
+
}
|
|
128
223
|
/**
|
|
129
224
|
* Builds private process-tree evidence for the activity monitor. PIDs and raw
|
|
130
225
|
* commands remain internal and are deliberately absent from public reports.
|
|
@@ -140,11 +235,12 @@ function classifyAgentProcessTrees(processes, excludedRootPid = process.pid) {
|
|
|
140
235
|
if (evidence)
|
|
141
236
|
direct.set(entry.pid, evidence);
|
|
142
237
|
}
|
|
238
|
+
const collapsedDirect = collapseEmbeddedOpenAiAppStack(processes, direct);
|
|
143
239
|
const result = [];
|
|
144
240
|
for (const entry of processes) {
|
|
145
241
|
if (excluded.has(entry.pid))
|
|
146
242
|
continue;
|
|
147
|
-
let owner =
|
|
243
|
+
let owner = collapsedDirect.get(entry.pid) ?? null;
|
|
148
244
|
let relationship = 'direct';
|
|
149
245
|
if (!owner) {
|
|
150
246
|
const visited = new Set();
|
|
@@ -153,7 +249,7 @@ function classifyAgentProcessTrees(processes, excludedRootPid = process.pid) {
|
|
|
153
249
|
if (visited.has(parentPid) || excluded.has(parentPid))
|
|
154
250
|
break;
|
|
155
251
|
visited.add(parentPid);
|
|
156
|
-
owner =
|
|
252
|
+
owner = collapsedDirect.get(parentPid) ?? null;
|
|
157
253
|
if (owner) {
|
|
158
254
|
relationship = 'descendant';
|
|
159
255
|
break;
|
|
@@ -173,7 +269,9 @@ function classifyAgentProcessTrees(processes, excludedRootPid = process.pid) {
|
|
|
173
269
|
relationship,
|
|
174
270
|
cpu_percent: Number.isFinite(entry.cpu_percent) ? Math.max(0, Number(entry.cpu_percent)) : null,
|
|
175
271
|
memory_percent: Number.isFinite(entry.memory_percent) ? Math.max(0, Number(entry.memory_percent)) : null,
|
|
272
|
+
memory_bytes: Number.isFinite(entry.rss_bytes) ? Math.max(0, Number(entry.rss_bytes)) : null,
|
|
176
273
|
cpu_time_ms: Number.isFinite(entry.cpu_time_ms) ? Math.max(0, Number(entry.cpu_time_ms)) : null,
|
|
274
|
+
activity_signal: !isPassiveAppHelperProcess(entry),
|
|
177
275
|
});
|
|
178
276
|
}
|
|
179
277
|
return result.sort((left, right) => left.signature.localeCompare(right.signature) || left.pid - right.pid);
|
|
@@ -220,11 +318,15 @@ function confidenceRank(confidence) {
|
|
|
220
318
|
return confidence === 'high' ? 3 : confidence === 'medium' ? 2 : 1;
|
|
221
319
|
}
|
|
222
320
|
function detectAgentProducts(processes) {
|
|
223
|
-
const
|
|
321
|
+
const direct = new Map();
|
|
224
322
|
for (const process of processes) {
|
|
225
323
|
const evidence = classifyProcess(process);
|
|
226
|
-
if (
|
|
227
|
-
|
|
324
|
+
if (evidence)
|
|
325
|
+
direct.set(process.pid, evidence);
|
|
326
|
+
}
|
|
327
|
+
const collapsedDirect = collapseEmbeddedOpenAiAppStack(processes, direct);
|
|
328
|
+
const grouped = new Map();
|
|
329
|
+
for (const evidence of collapsedDirect.values()) {
|
|
228
330
|
grouped.set(evidence.signature.signature, [
|
|
229
331
|
...(grouped.get(evidence.signature.signature) ?? []),
|
|
230
332
|
evidence,
|
|
File without changes
|
|
Binary file
|