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
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UI_COPY = void 0;
|
|
4
|
+
exports.normalizeLocale = normalizeLocale;
|
|
5
|
+
exports.uiText = uiText;
|
|
6
|
+
exports.UI_COPY = {
|
|
7
|
+
en: {
|
|
8
|
+
localDevice: 'Local on this device', activityNow: 'AI activity now', monitoringOff: 'Ready to observe', stopped: 'READY', workingNow: 'WORKING NOW', openIdle: 'READY', notRunning: 'MONITORING',
|
|
9
|
+
startHelp: 'Start monitoring to see supported AI work as it happens.', summaryPreserved: 'Your AI Footprint is saved locally. Continue whenever you want.', monitoringStopped: 'Observation ready',
|
|
10
|
+
workingEvidence: 'Supported AI work is happening now.', idleEvidence: 'Your supported AI app is ready. Forkit will highlight it when work begins.', noApp: 'Ready for your next AI session', noAppHelp: 'Monitoring is active and will surface supported AI work as it happens.',
|
|
11
|
+
observed: 'Observed', validAwake: 'valid awake time', aiActive: 'AI active', supportedWork: 'supported app work', activityRatio: 'Activity ratio', ratioNote: 'active ÷ observed', overhead: 'Forkit overhead', measuredLocally: 'measured locally', warmingUp: 'measuring…', working: 'Working', openIdleLegend: 'Ready',
|
|
12
|
+
startMonitoring: 'Start Monitoring', stopMonitoring: 'Stop Monitoring', clearHistory: 'Clear history', observation: 'Your observation', earlyObservation: 'Your Footprint is taking shape', earlyObservationCopy: 'Every observed minute adds more detail to your AI Footprint.', observationShows: 'What your AI activity shows.',
|
|
13
|
+
footprint: 'Your AI Footprint', modelRecord: 'model record', modelRecords: 'model records',
|
|
14
|
+
modelRecordsLabel: 'Model records', loaded: '{count} loaded', modelStorage: 'Model storage', recognizedBytes: 'recognized logical bytes', localEngines: 'Local engines', verifiedAvailable: 'verified available now', createShare: 'Create share card', scanAgain: 'Scan again',
|
|
15
|
+
optionalComparison: 'Optional global comparison', comparisonQuestion: 'How does your AI activity compare?', comparisonCopy: 'Explore your position among participating Forkit observations.', globalProgress: 'Your global comparison is taking shape · {remaining} until it’s ready.', seeGlobal: 'See my global position', reviewSharing: 'Review before sharing.', payloadIntro: 'This is the complete aggregate that would leave this device:', shareCompare: 'Share aggregates & compare', keepLocal: 'Keep everything local', noIdentity: 'No account or device identifier. Global contribution is not available in this version.',
|
|
16
|
+
technical: 'Technical details', engines: 'Available engines', modelsDevice: 'Models in use', appsTools: 'AI apps running', probeNotes: 'Probe notes', measurementBoundary: 'How Forkit measures', activityMeasurement: 'AI activity', loadedModel: 'Loaded model', storage: 'Model storage', notMeasured: 'Not measured', forkitResources: 'Forkit resources',
|
|
17
|
+
workingBoundary: 'Recent activity from supported AI app processes.', loadedBoundary: 'Provider-confirmed loaded model.', storageBoundary: 'Recognized local model file sizes.', notMeasuredCopy: 'Prompts, tokens, energy, cost, GPU attribution, per-app network traffic, or exclusive task ownership.',
|
|
18
|
+
noEngine: '', installedNoLoaded: '', modelsLoaded: '{count} {models} loaded', model: 'model', models: 'models', stored: 'stored', noModel: '', processActivity: 'Running locally', detectedNotRunning: '', noTool: '', noProbe: '',
|
|
19
|
+
noPrivateFooter: 'No weights, prompts, commands, paths, config values, account data, or upload', shareTitle: 'Your AI Footprint', shareHeading: 'Your measured AI activity.', share: 'Share', savePng: 'Save PNG', copyImage: 'Copy Image', copyCaption: 'Copy Caption', close: 'Close', sharePrivacy: 'Measured totals and supported tool names only. Chat titles, workspaces, paths, and device identity stay out.', copied: 'Copied', copyUnavailable: 'Image copy is unavailable in this system view. Save the PNG instead.',
|
|
20
|
+
myFootprint: 'MY AI FOOTPRINT', activeTool: 'ACTIVE TOOL', activeTools: 'ACTIVE TOOLS', localModels: 'LOCAL MODELS', observedLocally: 'Observed locally · Forkit AI Footprint', deviceQuestion: 'How much AI is working on your device?', shareActive: 'AI-ACTIVE',
|
|
21
|
+
clearConfirm: 'Clear this local monitoring history?', scanning: 'Scanning local metadata…', refreshed: 'Footprint refreshed locally.', scanFailed: 'Scan could not be refreshed.',
|
|
22
|
+
activeShareFallback: 'Supported AI tools were working during {ratio} of this observation.', footprintFallback: '{count} supported local {records} found.', shareActivity: 'Observed {observed}; AI-active {active} ({ratio}).', shareTool: 'Supported AI activity: {tools}.', shareModels: '{count} local {models}; {storage} recognized model files.', captionFirst: 'My AI was actively working during {ratio} of this observation.', captionQuestion: 'How much AI is actually working on your device?',
|
|
23
|
+
appTitle: 'Forkit AI Footprint', menuStopped: '○ Stopped', menuMonitoring: '● Monitoring', menuWorking: '● Monitoring · {count} working', openFootprint: 'Open AI Footprint', quitForkit: 'Quit Forkit', serviceUnavailable: '○ Service unavailable', serviceStopped: 'Service stopped',
|
|
24
|
+
closeTitle: 'Forkit will keep monitoring in the background.', closeBody: 'You can reopen it or stop monitoring anytime from the Forkit icon. If the macOS menu bar is hidden, move the pointer to the top edge to reveal it.', gotIt: 'Got it', dontShow: "Don’t show this again", quitTitle: 'Stop monitoring and quit?', keepMonitoring: 'Keep Monitoring', stopQuit: 'Stop & Quit', fatalService: 'The local AI Footprints service could not start.', fatalStopped: 'The local service stopped unexpectedly. No monitoring remains active.', quit: 'Quit',
|
|
25
|
+
insightMostlyIdle: 'This observation captured a light AI activity pattern.', insightActivityProduct: '{product} was working during {percent}% of your observation.', insightActivityGeneric: 'Supported AI tools were working during {percent}% of your observation.', insightLongest: 'Your longest continuous AI-active period was {duration}.', insightMulti: 'Active AI work was observed across {count} supported tools.', insightModelsUnused: '{count} local models are ready for a future session.', insightFocused: 'All observed AI activity came from {product}.',
|
|
26
|
+
},
|
|
27
|
+
de: {
|
|
28
|
+
localDevice: 'Lokal auf diesem Gerät', activityNow: 'KI-Aktivität jetzt', monitoringOff: 'Bereit zur Beobachtung', stopped: 'BEREIT', workingNow: 'ARBEITET JETZT', openIdle: 'BEREIT', notRunning: 'MONITORING',
|
|
29
|
+
startHelp: 'Starten Sie das Monitoring und sehen Sie unterstützte KI-Arbeit in Echtzeit.', summaryPreserved: 'Ihr AI Footprint ist lokal gespeichert. Sie können jederzeit fortfahren.', monitoringStopped: 'Beobachtung bereit',
|
|
30
|
+
workingEvidence: 'Unterstützte KI-Arbeit findet gerade statt.', idleEvidence: 'Ihre unterstützte KI-App ist bereit. Forkit hebt sie hervor, sobald die Arbeit beginnt.', noApp: 'Bereit für Ihre nächste KI-Sitzung', noAppHelp: 'Das Monitoring ist aktiv und zeigt unterstützte KI-Arbeit, sobald sie stattfindet.',
|
|
31
|
+
observed: 'Beobachtet', validAwake: 'gültige aktive Gerätezeit', aiActive: 'KI aktiv', supportedWork: 'Arbeit unterstützter Apps', activityRatio: 'Aktivitätsanteil', ratioNote: 'aktiv ÷ beobachtet', overhead: 'Forkit-Ressourcen', measuredLocally: 'lokal gemessen', warmingUp: 'wird gemessen…', working: 'Arbeitet', openIdleLegend: 'Bereit',
|
|
32
|
+
startMonitoring: 'Monitoring starten', stopMonitoring: 'Monitoring stoppen', clearHistory: 'Verlauf löschen', observation: 'Ihre Beobachtung', earlyObservation: 'Ihr Footprint nimmt Gestalt an', earlyObservationCopy: 'Jede beobachtete Minute ergänzt Ihren AI Footprint.', observationShows: 'Das zeigt Ihre KI-Aktivität.',
|
|
33
|
+
footprint: 'Ihr AI Footprint', modelRecord: 'Modelldatensatz', modelRecords: 'Modelldatensätze',
|
|
34
|
+
modelRecordsLabel: 'Modelldatensätze', loaded: '{count} geladen', modelStorage: 'Modellspeicher', recognizedBytes: 'erkannte logische Dateibytes', localEngines: 'Lokale Engines', verifiedAvailable: 'aktuell verifiziert verfügbar', createShare: 'Share-Karte erstellen', scanAgain: 'Erneut scannen',
|
|
35
|
+
optionalComparison: 'Optionaler globaler Vergleich', comparisonQuestion: 'Wie lässt sich Ihre KI-Aktivität vergleichen?', comparisonCopy: 'Entdecken Sie Ihre Position unter teilnehmenden Forkit-Beobachtungen.', globalProgress: 'Ihr globaler Vergleich nimmt Gestalt an · in {remaining} ist er bereit.', seeGlobal: 'Meine globale Position ansehen', reviewSharing: 'Vor dem Teilen prüfen.', payloadIntro: 'Dies ist das vollständige Aggregat, das dieses Gerät verlassen würde:', shareCompare: 'Aggregate teilen & vergleichen', keepLocal: 'Alles lokal behalten', noIdentity: 'Kein Konto und keine Gerätekennung. Globale Beiträge sind in dieser Version nicht verfügbar.',
|
|
36
|
+
technical: 'Technische Details', engines: 'Verfügbare Engines', modelsDevice: 'Modelle in Verwendung', appsTools: 'Laufende KI-Apps', probeNotes: 'Prüfhinweise', measurementBoundary: 'So misst Forkit', activityMeasurement: 'KI-Aktivität', loadedModel: 'Geladenes Modell', storage: 'Modellspeicher', notMeasured: 'Nicht gemessen', forkitResources: 'Forkit-Ressourcen',
|
|
37
|
+
workingBoundary: 'Aktuelle Aktivität unterstützter KI-App-Prozesse.', loadedBoundary: 'Vom Anbieter bestätigtes geladenes Modell.', storageBoundary: 'Erkannte lokale Modelldateigrößen.', notMeasuredCopy: 'Prompts, Tokens, Energie, Kosten, GPU-Zuordnung, Netzwerkverkehr pro App oder exklusive Aufgabenzuordnung.',
|
|
38
|
+
noEngine: '', installedNoLoaded: '', modelsLoaded: '{count} {models} geladen', model: 'Modell', models: 'Modelle', stored: 'gespeichert', noModel: '', processActivity: 'Läuft lokal', detectedNotRunning: '', noTool: '', noProbe: '',
|
|
39
|
+
noPrivateFooter: 'Keine Gewichte, Prompts, Befehle, Pfade, Konfigurationswerte, Kontodaten oder Uploads', shareTitle: 'Ihr AI Footprint', shareHeading: 'Ihre gemessene KI-Aktivität.', share: 'Teilen', savePng: 'PNG speichern', copyImage: 'Bild kopieren', copyCaption: 'Text kopieren', close: 'Schließen', sharePrivacy: 'Nur gemessene Summen und Namen unterstützter Tools. Chat-Titel, Workspaces, Pfade und Gerätekennung bleiben außen vor.', copied: 'Kopiert', copyUnavailable: 'Das Kopieren von Bildern ist in dieser Systemansicht nicht verfügbar. Speichern Sie stattdessen die PNG-Datei.',
|
|
40
|
+
myFootprint: 'MEIN AI FOOTPRINT', activeTool: 'AKTIVES TOOL', activeTools: 'AKTIVE TOOLS', localModels: 'LOKALE MODELLE', observedLocally: 'Lokal beobachtet · Forkit AI Footprint', deviceQuestion: 'Wie viel KI arbeitet auf Ihrem Gerät?', shareActive: 'KI-AKTIV',
|
|
41
|
+
clearConfirm: 'Diesen lokalen Monitoring-Verlauf löschen?', scanning: 'Lokale Metadaten werden gescannt…', refreshed: 'Footprint lokal aktualisiert.', scanFailed: 'Der Scan konnte nicht aktualisiert werden.',
|
|
42
|
+
activeShareFallback: 'Unterstützte KI-Tools arbeiteten während {ratio} dieser Beobachtung.', footprintFallback: '{count} unterstützte lokale {records} gefunden.', shareActivity: '{observed} beobachtet; KI aktiv {active} ({ratio}).', shareTool: 'Unterstützte KI-Aktivität: {tools}.', shareModels: '{count} lokale {models}; {storage} erkannte Modelldateien.', captionFirst: 'Meine KI arbeitete während {ratio} dieser Beobachtung aktiv.', captionQuestion: 'Wie viel KI arbeitet tatsächlich auf Ihrem Gerät?',
|
|
43
|
+
appTitle: 'Forkit AI Footprint', menuStopped: '○ Gestoppt', menuMonitoring: '● Monitoring', menuWorking: '● Monitoring · {count} aktiv', openFootprint: 'AI Footprint öffnen', quitForkit: 'Forkit beenden', serviceUnavailable: '○ Dienst nicht verfügbar', serviceStopped: 'Dienst gestoppt',
|
|
44
|
+
closeTitle: 'Forkit überwacht im Hintergrund weiter.', closeBody: 'Über das Forkit-Symbol können Sie die App jederzeit erneut öffnen oder das Monitoring stoppen. Falls die macOS-Menüleiste ausgeblendet ist, bewegen Sie den Zeiger an den oberen Bildschirmrand.', gotIt: 'Verstanden', dontShow: 'Nicht erneut anzeigen', quitTitle: 'Monitoring stoppen und beenden?', keepMonitoring: 'Monitoring fortsetzen', stopQuit: 'Stoppen & beenden', fatalService: 'Der lokale AI-Footprints-Dienst konnte nicht gestartet werden.', fatalStopped: 'Der lokale Dienst wurde unerwartet beendet. Es ist kein Monitoring mehr aktiv.', quit: 'Beenden',
|
|
45
|
+
insightMostlyIdle: 'Diese Beobachtung zeigt ein leichtes KI-Aktivitätsmuster.', insightActivityProduct: '{product} arbeitete während {percent} % Ihrer Beobachtung.', insightActivityGeneric: 'Unterstützte KI-Tools arbeiteten während {percent} % Ihrer Beobachtung.', insightLongest: 'Ihr längster durchgehender KI-aktiver Zeitraum dauerte {duration}.', insightMulti: 'Aktive KI-Arbeit wurde in {count} unterstützten Tools beobachtet.', insightModelsUnused: '{count} lokale Modelle sind für eine zukünftige Sitzung bereit.', insightFocused: 'Die gesamte beobachtete KI-Aktivität stammte von {product}.',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
function normalizeLocale(value) { return String(value || '').toLowerCase().startsWith('de') ? 'de' : 'en'; }
|
|
49
|
+
function uiText(locale, key, values = {}) {
|
|
50
|
+
let text = exports.UI_COPY[locale][key];
|
|
51
|
+
for (const [name, value] of Object.entries(values))
|
|
52
|
+
text = text.replaceAll(`{${name}}`, String(value));
|
|
53
|
+
return text;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=localization.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CensusMcpConfig } from './types';
|
|
2
|
+
export interface McpDetectionOptions {
|
|
3
|
+
homeDir: string;
|
|
4
|
+
cwd: string;
|
|
5
|
+
env: NodeJS.ProcessEnv;
|
|
6
|
+
platform: NodeJS.Platform;
|
|
7
|
+
}
|
|
8
|
+
export declare function detectMcpConfigs(options: McpDetectionOptions): Promise<CensusMcpConfig[]>;
|
|
9
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
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.detectMcpConfigs = detectMcpConfigs;
|
|
7
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
function configRoot(options) {
|
|
10
|
+
if (options.platform === 'win32') {
|
|
11
|
+
return options.env.APPDATA || node_path_1.default.join(options.homeDir, 'AppData', 'Roaming');
|
|
12
|
+
}
|
|
13
|
+
if (options.platform === 'darwin')
|
|
14
|
+
return node_path_1.default.join(options.homeDir, 'Library', 'Application Support');
|
|
15
|
+
return options.env.XDG_CONFIG_HOME || node_path_1.default.join(options.homeDir, '.config');
|
|
16
|
+
}
|
|
17
|
+
function candidates(options) {
|
|
18
|
+
const root = configRoot(options);
|
|
19
|
+
return [
|
|
20
|
+
{ client: 'Claude Desktop', filePath: node_path_1.default.join(root, 'Claude', 'claude_desktop_config.json'), format: 'json' },
|
|
21
|
+
{ client: 'Claude Code', filePath: node_path_1.default.join(options.homeDir, '.claude.json'), format: 'json' },
|
|
22
|
+
{ client: 'Codex', filePath: node_path_1.default.join(options.homeDir, '.codex', 'config.toml'), format: 'toml' },
|
|
23
|
+
{ client: 'Cursor', filePath: node_path_1.default.join(options.homeDir, '.cursor', 'mcp.json'), format: 'json' },
|
|
24
|
+
{ client: 'Cursor (workspace)', filePath: node_path_1.default.join(options.cwd, '.cursor', 'mcp.json'), format: 'json' },
|
|
25
|
+
{ client: 'Windsurf', filePath: node_path_1.default.join(options.homeDir, '.codeium', 'windsurf', 'mcp_config.json'), format: 'json' },
|
|
26
|
+
{ client: 'VS Code', filePath: node_path_1.default.join(root, 'Code', 'User', 'mcp.json'), format: 'json' },
|
|
27
|
+
{ client: 'VS Code Insiders', filePath: node_path_1.default.join(root, 'Code - Insiders', 'User', 'mcp.json'), format: 'json' },
|
|
28
|
+
{ client: 'Gemini CLI', filePath: node_path_1.default.join(options.homeDir, '.gemini', 'settings.json'), format: 'json' },
|
|
29
|
+
{ client: 'OpenCode', filePath: node_path_1.default.join(options.homeDir, '.config', 'opencode', 'opencode.json'), format: 'json' },
|
|
30
|
+
{ client: 'Zed', filePath: node_path_1.default.join(options.homeDir, '.zed', 'settings.json'), format: 'json' },
|
|
31
|
+
{ client: 'Zed (workspace)', filePath: node_path_1.default.join(options.cwd, '.zed', 'settings.json'), format: 'json' },
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
function jsonServerCount(value) {
|
|
35
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
36
|
+
return 0;
|
|
37
|
+
const record = value;
|
|
38
|
+
if (record.mcpServers && typeof record.mcpServers === 'object' && !Array.isArray(record.mcpServers)) {
|
|
39
|
+
return Object.keys(record.mcpServers).length;
|
|
40
|
+
}
|
|
41
|
+
if (record.mcp && typeof record.mcp === 'object' && !Array.isArray(record.mcp)) {
|
|
42
|
+
const servers = record.mcp.servers;
|
|
43
|
+
if (servers && typeof servers === 'object' && !Array.isArray(servers)) {
|
|
44
|
+
return Object.keys(servers).length;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (record.context_servers && typeof record.context_servers === 'object' && !Array.isArray(record.context_servers)) {
|
|
48
|
+
return Object.keys(record.context_servers).length;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
async function inspect(candidate) {
|
|
53
|
+
let handle = null;
|
|
54
|
+
try {
|
|
55
|
+
handle = await promises_1.default.open(candidate.filePath, 'r');
|
|
56
|
+
const stats = await handle.stat();
|
|
57
|
+
if (!stats.isFile() || stats.size > 1024 * 1024)
|
|
58
|
+
return null;
|
|
59
|
+
const content = await handle.readFile({ encoding: 'utf8' });
|
|
60
|
+
const serverCount = candidate.format === 'json'
|
|
61
|
+
? jsonServerCount(JSON.parse(content))
|
|
62
|
+
: [...content.matchAll(/^\s*\[mcp_servers\.[^\]]+\]\s*$/gm)].length;
|
|
63
|
+
if (serverCount === 0)
|
|
64
|
+
return null;
|
|
65
|
+
return {
|
|
66
|
+
client: candidate.client,
|
|
67
|
+
evidence_status: 'configured',
|
|
68
|
+
confidence: 'high',
|
|
69
|
+
server_count: serverCount,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await handle?.close().catch(() => undefined);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function detectMcpConfigs(options) {
|
|
80
|
+
const seenPaths = new Set();
|
|
81
|
+
const uniqueCandidates = candidates(options).filter((candidate) => {
|
|
82
|
+
const normalized = node_path_1.default.resolve(candidate.filePath);
|
|
83
|
+
if (seenPaths.has(normalized))
|
|
84
|
+
return false;
|
|
85
|
+
seenPaths.add(normalized);
|
|
86
|
+
return true;
|
|
87
|
+
});
|
|
88
|
+
const findings = await Promise.all(uniqueCandidates.map((candidate) => inspect(candidate)));
|
|
89
|
+
return findings
|
|
90
|
+
.filter((finding) => finding !== null)
|
|
91
|
+
.sort((left, right) => left.client.localeCompare(right.client));
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type ClassifiedAgentProcess } from './agents';
|
|
2
|
+
import type { ProcessEntry } from './types';
|
|
3
|
+
export type AiActivityState = 'working-now' | 'open-idle' | 'not-running';
|
|
4
|
+
export type MonitorLifecycle = 'stopped' | 'monitoring';
|
|
5
|
+
export interface ActivityContext {
|
|
6
|
+
chat: string | null;
|
|
7
|
+
workspace: string | null;
|
|
8
|
+
source: 'cooperating-app-metadata' | null;
|
|
9
|
+
}
|
|
10
|
+
export interface AiActivityProduct {
|
|
11
|
+
signature: string;
|
|
12
|
+
name: string;
|
|
13
|
+
kind: string;
|
|
14
|
+
state: AiActivityState;
|
|
15
|
+
process_count: number;
|
|
16
|
+
cpu_percent: number | null;
|
|
17
|
+
memory_percent: number | null;
|
|
18
|
+
recent_cpu_time_delta_ms: number | null;
|
|
19
|
+
active_seconds: number;
|
|
20
|
+
context: ActivityContext;
|
|
21
|
+
}
|
|
22
|
+
export interface ActivityTimelineSegment {
|
|
23
|
+
started_at: string;
|
|
24
|
+
ended_at: string;
|
|
25
|
+
state: 'working-now' | 'open-idle' | 'not-running';
|
|
26
|
+
product_signatures: string[];
|
|
27
|
+
observation_id?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface MonitorOverhead {
|
|
30
|
+
current_cpu_percent: number | null;
|
|
31
|
+
current_memory_bytes: number;
|
|
32
|
+
history_bytes: number;
|
|
33
|
+
sample_count: number;
|
|
34
|
+
median_cpu_percent: number | null;
|
|
35
|
+
p95_cpu_percent: number | null;
|
|
36
|
+
max_memory_bytes: number;
|
|
37
|
+
measurement: 'forkit-process-tree';
|
|
38
|
+
}
|
|
39
|
+
export interface MonitorSnapshot {
|
|
40
|
+
schema_version: '1.0';
|
|
41
|
+
lifecycle: MonitorLifecycle;
|
|
42
|
+
started_at: string | null;
|
|
43
|
+
stopped_at: string | null;
|
|
44
|
+
observed_seconds: number;
|
|
45
|
+
active_seconds: number;
|
|
46
|
+
activity_ratio: number | null;
|
|
47
|
+
products: AiActivityProduct[];
|
|
48
|
+
timeline: ActivityTimelineSegment[];
|
|
49
|
+
overhead: MonitorOverhead;
|
|
50
|
+
sample_interval_ms: number;
|
|
51
|
+
history_limit: number;
|
|
52
|
+
evidence: 'repeated-process-tree-cpu-time-deltas';
|
|
53
|
+
limitation: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ActivityMonitorOptions {
|
|
56
|
+
sampleProcesses?: () => Promise<ProcessEntry[]>;
|
|
57
|
+
now?: () => number;
|
|
58
|
+
intervalMs?: number;
|
|
59
|
+
historyLimit?: number;
|
|
60
|
+
excludedRootPid?: number | null;
|
|
61
|
+
context?: () => ActivityContext;
|
|
62
|
+
classifyProcesses?: (processes: ProcessEntry[]) => ClassifiedAgentProcess[] | Promise<ClassifiedAgentProcess[]>;
|
|
63
|
+
}
|
|
64
|
+
export declare class ActivityMonitor {
|
|
65
|
+
private readonly sampleProcesses;
|
|
66
|
+
private readonly now;
|
|
67
|
+
private readonly intervalMs;
|
|
68
|
+
private readonly historyLimit;
|
|
69
|
+
private readonly excludedRootPid;
|
|
70
|
+
private readonly context;
|
|
71
|
+
private readonly classifyProcesses;
|
|
72
|
+
private lifecycle;
|
|
73
|
+
private startedAt;
|
|
74
|
+
private stoppedAt;
|
|
75
|
+
private previousAt;
|
|
76
|
+
private observationId;
|
|
77
|
+
private previousCpuTimes;
|
|
78
|
+
private observedMs;
|
|
79
|
+
private activeMs;
|
|
80
|
+
private products;
|
|
81
|
+
private timeline;
|
|
82
|
+
private timer;
|
|
83
|
+
private sampling;
|
|
84
|
+
private nodeCpuUsage;
|
|
85
|
+
private nodeCpuAt;
|
|
86
|
+
private overheadCpuSamples;
|
|
87
|
+
private overheadMemorySamples;
|
|
88
|
+
constructor(options?: ActivityMonitorOptions);
|
|
89
|
+
start(options?: {
|
|
90
|
+
schedule?: boolean;
|
|
91
|
+
}): Promise<MonitorSnapshot>;
|
|
92
|
+
sampleNow(): Promise<MonitorSnapshot>;
|
|
93
|
+
stop(): MonitorSnapshot;
|
|
94
|
+
clearHistory(): MonitorSnapshot;
|
|
95
|
+
private updateTimeline;
|
|
96
|
+
private sampleOverhead;
|
|
97
|
+
snapshot(): MonitorSnapshot;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=monitor.d.ts.map
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ActivityMonitor = void 0;
|
|
4
|
+
const agents_1 = require("./agents");
|
|
5
|
+
const DEFAULT_INTERVAL_MS = 1000;
|
|
6
|
+
const DEFAULT_HISTORY_LIMIT = 900;
|
|
7
|
+
function rounded(value, digits = 1) {
|
|
8
|
+
const factor = 10 ** digits;
|
|
9
|
+
return Math.round(value * factor) / factor;
|
|
10
|
+
}
|
|
11
|
+
function sum(values) {
|
|
12
|
+
const measured = values.filter((value) => value !== null);
|
|
13
|
+
return measured.length === 0 ? null : rounded(measured.reduce((total, value) => total + value, 0));
|
|
14
|
+
}
|
|
15
|
+
function percentile(values, fraction) {
|
|
16
|
+
if (values.length === 0)
|
|
17
|
+
return null;
|
|
18
|
+
const sorted = [...values].sort((left, right) => left - right);
|
|
19
|
+
const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * fraction) - 1));
|
|
20
|
+
return rounded(sorted[index]);
|
|
21
|
+
}
|
|
22
|
+
function localContextFromEnvironment() {
|
|
23
|
+
const chat = process.env.FORKIT_AI_FOOTPRINTS_CONTEXT_CHAT?.trim() || null;
|
|
24
|
+
const workspace = process.env.FORKIT_AI_FOOTPRINTS_CONTEXT_WORKSPACE?.trim() || null;
|
|
25
|
+
return {
|
|
26
|
+
chat,
|
|
27
|
+
workspace,
|
|
28
|
+
source: chat || workspace ? 'cooperating-app-metadata' : null,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function groupProcesses(processes) {
|
|
32
|
+
const result = new Map();
|
|
33
|
+
for (const entry of processes)
|
|
34
|
+
result.set(entry.signature, [...(result.get(entry.signature) ?? []), entry]);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function historyByteSize(snapshot) {
|
|
38
|
+
return Buffer.byteLength(JSON.stringify({
|
|
39
|
+
started_at: snapshot.started_at,
|
|
40
|
+
observed_seconds: snapshot.observed_seconds,
|
|
41
|
+
active_seconds: snapshot.active_seconds,
|
|
42
|
+
products: snapshot.products,
|
|
43
|
+
timeline: snapshot.timeline,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
class ActivityMonitor {
|
|
47
|
+
sampleProcesses;
|
|
48
|
+
now;
|
|
49
|
+
intervalMs;
|
|
50
|
+
historyLimit;
|
|
51
|
+
excludedRootPid;
|
|
52
|
+
context;
|
|
53
|
+
classifyProcesses;
|
|
54
|
+
lifecycle = 'stopped';
|
|
55
|
+
startedAt = null;
|
|
56
|
+
stoppedAt = null;
|
|
57
|
+
previousAt = null;
|
|
58
|
+
observationId = 0;
|
|
59
|
+
previousCpuTimes = new Map();
|
|
60
|
+
observedMs = 0;
|
|
61
|
+
activeMs = 0;
|
|
62
|
+
products = new Map();
|
|
63
|
+
timeline = [];
|
|
64
|
+
timer = null;
|
|
65
|
+
sampling = false;
|
|
66
|
+
nodeCpuUsage = null;
|
|
67
|
+
nodeCpuAt = null;
|
|
68
|
+
overheadCpuSamples = [];
|
|
69
|
+
overheadMemorySamples = [];
|
|
70
|
+
constructor(options = {}) {
|
|
71
|
+
this.sampleProcesses = options.sampleProcesses ?? agents_1.listSystemProcesses;
|
|
72
|
+
this.now = options.now ?? Date.now;
|
|
73
|
+
this.intervalMs = Math.max(500, options.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
74
|
+
this.historyLimit = Math.max(10, options.historyLimit ?? DEFAULT_HISTORY_LIMIT);
|
|
75
|
+
this.excludedRootPid = options.excludedRootPid === undefined ? process.pid : options.excludedRootPid;
|
|
76
|
+
this.context = options.context ?? localContextFromEnvironment;
|
|
77
|
+
this.classifyProcesses = options.classifyProcesses ?? ((entries) => (0, agents_1.classifyAgentProcessTrees)(entries, this.excludedRootPid));
|
|
78
|
+
}
|
|
79
|
+
async start(options = {}) {
|
|
80
|
+
if (this.lifecycle === 'monitoring')
|
|
81
|
+
return this.snapshot();
|
|
82
|
+
const now = this.now();
|
|
83
|
+
this.lifecycle = 'monitoring';
|
|
84
|
+
this.observationId += 1;
|
|
85
|
+
this.startedAt = now;
|
|
86
|
+
this.stoppedAt = null;
|
|
87
|
+
this.previousAt = null;
|
|
88
|
+
this.previousCpuTimes.clear();
|
|
89
|
+
this.nodeCpuUsage = process.cpuUsage();
|
|
90
|
+
this.nodeCpuAt = now;
|
|
91
|
+
await this.sampleNow();
|
|
92
|
+
if (options.schedule !== false) {
|
|
93
|
+
this.timer = setInterval(() => { void this.sampleNow(); }, this.intervalMs);
|
|
94
|
+
this.timer.unref();
|
|
95
|
+
}
|
|
96
|
+
return this.snapshot();
|
|
97
|
+
}
|
|
98
|
+
async sampleNow() {
|
|
99
|
+
if (this.lifecycle !== 'monitoring' || this.sampling)
|
|
100
|
+
return this.snapshot();
|
|
101
|
+
this.sampling = true;
|
|
102
|
+
try {
|
|
103
|
+
const entries = await this.sampleProcesses();
|
|
104
|
+
const now = this.now();
|
|
105
|
+
const elapsed = this.previousAt === null ? 0 : Math.max(0, now - this.previousAt);
|
|
106
|
+
const validElapsed = elapsed > 0 && elapsed <= this.intervalMs * 3 ? elapsed : 0;
|
|
107
|
+
const grouped = groupProcesses(await this.classifyProcesses(entries));
|
|
108
|
+
const signatures = new Set([...this.products.keys(), ...grouped.keys()]);
|
|
109
|
+
for (const signature of signatures) {
|
|
110
|
+
const current = grouped.get(signature) ?? [];
|
|
111
|
+
const previous = this.products.get(signature);
|
|
112
|
+
let cpuDeltaMs = 0;
|
|
113
|
+
let deltaCount = 0;
|
|
114
|
+
for (const entry of current) {
|
|
115
|
+
const currentTime = entry.cpu_time_ms;
|
|
116
|
+
const previousTime = this.previousCpuTimes.get(entry.pid);
|
|
117
|
+
if (currentTime === null || previousTime === undefined || currentTime < previousTime)
|
|
118
|
+
continue;
|
|
119
|
+
cpuDeltaMs += currentTime - previousTime;
|
|
120
|
+
deltaCount += 1;
|
|
121
|
+
}
|
|
122
|
+
const measuredDelta = deltaCount > 0 ? cpuDeltaMs : null;
|
|
123
|
+
const strongSignal = current.length > 0
|
|
124
|
+
&& validElapsed > 0
|
|
125
|
+
&& measuredDelta !== null
|
|
126
|
+
&& measuredDelta >= Math.max(20, validElapsed * 0.02);
|
|
127
|
+
const signals = [...(previous?.signals ?? []), strongSignal].slice(-3);
|
|
128
|
+
let state;
|
|
129
|
+
if (current.length === 0)
|
|
130
|
+
state = 'not-running';
|
|
131
|
+
else if (previous?.state === 'working-now')
|
|
132
|
+
state = signals.every((value) => !value) ? 'open-idle' : 'working-now';
|
|
133
|
+
else
|
|
134
|
+
state = signals.slice(-2).length === 2 && signals.slice(-2).every(Boolean) ? 'working-now' : 'open-idle';
|
|
135
|
+
const activeMs = (previous?.activeMs ?? 0) + (validElapsed > 0 && state === 'working-now' ? validElapsed : 0);
|
|
136
|
+
const first = current[0];
|
|
137
|
+
this.products.set(signature, {
|
|
138
|
+
signature,
|
|
139
|
+
name: first?.name ?? previous?.name ?? signature,
|
|
140
|
+
kind: first?.kind ?? previous?.kind ?? 'unknown',
|
|
141
|
+
state,
|
|
142
|
+
signals,
|
|
143
|
+
activeMs,
|
|
144
|
+
processCount: current.length,
|
|
145
|
+
cpuPercent: sum(current.map((entry) => entry.cpu_percent)),
|
|
146
|
+
memoryPercent: sum(current.map((entry) => entry.memory_percent)),
|
|
147
|
+
cpuDeltaMs: measuredDelta,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (validElapsed > 0) {
|
|
151
|
+
this.observedMs += validElapsed;
|
|
152
|
+
if ([...this.products.values()].some((product) => product.state === 'working-now'))
|
|
153
|
+
this.activeMs += validElapsed;
|
|
154
|
+
}
|
|
155
|
+
this.updateTimeline(now);
|
|
156
|
+
this.previousCpuTimes = new Map(entries.flatMap((entry) => Number.isFinite(entry.cpu_time_ms)
|
|
157
|
+
? [[entry.pid, Number(entry.cpu_time_ms)]]
|
|
158
|
+
: []));
|
|
159
|
+
this.previousAt = now;
|
|
160
|
+
this.sampleOverhead(now, entries);
|
|
161
|
+
return this.snapshot();
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
this.sampling = false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
stop() {
|
|
168
|
+
if (this.timer)
|
|
169
|
+
clearInterval(this.timer);
|
|
170
|
+
this.timer = null;
|
|
171
|
+
if (this.lifecycle === 'monitoring')
|
|
172
|
+
this.stoppedAt = this.now();
|
|
173
|
+
this.lifecycle = 'stopped';
|
|
174
|
+
return this.snapshot();
|
|
175
|
+
}
|
|
176
|
+
clearHistory() {
|
|
177
|
+
const now = this.now();
|
|
178
|
+
this.startedAt = this.lifecycle === 'monitoring' ? now : null;
|
|
179
|
+
this.stoppedAt = null;
|
|
180
|
+
this.previousAt = null;
|
|
181
|
+
this.previousCpuTimes.clear();
|
|
182
|
+
this.observedMs = 0;
|
|
183
|
+
this.activeMs = 0;
|
|
184
|
+
this.products.clear();
|
|
185
|
+
this.timeline = [];
|
|
186
|
+
this.overheadCpuSamples = [];
|
|
187
|
+
this.overheadMemorySamples = [];
|
|
188
|
+
this.nodeCpuUsage = process.cpuUsage();
|
|
189
|
+
this.nodeCpuAt = now;
|
|
190
|
+
return this.snapshot();
|
|
191
|
+
}
|
|
192
|
+
updateTimeline(now) {
|
|
193
|
+
const working = [...this.products.values()].filter((product) => product.state === 'working-now');
|
|
194
|
+
const running = [...this.products.values()].filter((product) => product.state !== 'not-running');
|
|
195
|
+
const state = working.length > 0
|
|
196
|
+
? 'working-now'
|
|
197
|
+
: running.length > 0 ? 'open-idle' : 'not-running';
|
|
198
|
+
const signatures = (working.length > 0 ? working : running).map((product) => product.signature).sort();
|
|
199
|
+
const at = new Date(now).toISOString();
|
|
200
|
+
const latest = this.timeline.at(-1);
|
|
201
|
+
if (latest && latest.observation_id === this.observationId && latest.state === state && latest.product_signatures.join('|') === signatures.join('|'))
|
|
202
|
+
latest.ended_at = at;
|
|
203
|
+
else
|
|
204
|
+
this.timeline.push({ started_at: at, ended_at: at, state, product_signatures: signatures, observation_id: this.observationId });
|
|
205
|
+
if (this.timeline.length > this.historyLimit)
|
|
206
|
+
this.timeline.splice(0, this.timeline.length - this.historyLimit);
|
|
207
|
+
}
|
|
208
|
+
sampleOverhead(now, entries) {
|
|
209
|
+
const included = new Set([process.pid]);
|
|
210
|
+
if (process.env.FORKIT_AI_FOOTPRINTS_APP_BUNDLE === '1' && process.ppid > 1)
|
|
211
|
+
included.add(process.ppid);
|
|
212
|
+
let changed = true;
|
|
213
|
+
while (changed) {
|
|
214
|
+
changed = false;
|
|
215
|
+
for (const entry of entries) {
|
|
216
|
+
if (included.has(entry.pid) || entry.ppid === undefined || !included.has(entry.ppid))
|
|
217
|
+
continue;
|
|
218
|
+
included.add(entry.pid);
|
|
219
|
+
changed = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const ownEntries = entries.filter((entry) => included.has(entry.pid));
|
|
223
|
+
const measuredMemory = ownEntries.reduce((total, entry) => total + (Number.isFinite(entry.rss_bytes) ? Number(entry.rss_bytes) : 0), 0);
|
|
224
|
+
const memory = measuredMemory > 0 ? measuredMemory : process.memoryUsage().rss;
|
|
225
|
+
this.overheadMemorySamples.push(memory);
|
|
226
|
+
if (this.overheadMemorySamples.length > this.historyLimit)
|
|
227
|
+
this.overheadMemorySamples.shift();
|
|
228
|
+
if (this.nodeCpuUsage && this.nodeCpuAt !== null && now - this.nodeCpuAt >= this.intervalMs * 0.5) {
|
|
229
|
+
const usage = process.cpuUsage(this.nodeCpuUsage);
|
|
230
|
+
const nodeCpu = ((usage.user + usage.system) / ((now - this.nodeCpuAt) * 1000)) * 100;
|
|
231
|
+
const measuredTreeCpu = ownEntries.reduce((total, entry) => total + (Number.isFinite(entry.cpu_percent) ? Number(entry.cpu_percent) : 0), 0);
|
|
232
|
+
const cpu = process.env.FORKIT_AI_FOOTPRINTS_APP_BUNDLE === '1' && measuredTreeCpu > 0 ? measuredTreeCpu : nodeCpu;
|
|
233
|
+
this.overheadCpuSamples.push(rounded(Math.max(0, cpu)));
|
|
234
|
+
if (this.overheadCpuSamples.length > this.historyLimit)
|
|
235
|
+
this.overheadCpuSamples.shift();
|
|
236
|
+
}
|
|
237
|
+
this.nodeCpuUsage = process.cpuUsage();
|
|
238
|
+
this.nodeCpuAt = now;
|
|
239
|
+
}
|
|
240
|
+
snapshot() {
|
|
241
|
+
const products = [...this.products.values()].map((product) => ({
|
|
242
|
+
signature: product.signature,
|
|
243
|
+
name: product.name,
|
|
244
|
+
kind: product.kind,
|
|
245
|
+
state: product.state,
|
|
246
|
+
process_count: product.processCount,
|
|
247
|
+
cpu_percent: product.cpuPercent,
|
|
248
|
+
memory_percent: product.memoryPercent,
|
|
249
|
+
recent_cpu_time_delta_ms: product.cpuDeltaMs,
|
|
250
|
+
active_seconds: rounded(product.activeMs / 1000),
|
|
251
|
+
context: this.context(),
|
|
252
|
+
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
253
|
+
const base = {
|
|
254
|
+
schema_version: '1.0',
|
|
255
|
+
lifecycle: this.lifecycle,
|
|
256
|
+
started_at: this.startedAt === null ? null : new Date(this.startedAt).toISOString(),
|
|
257
|
+
stopped_at: this.stoppedAt === null ? null : new Date(this.stoppedAt).toISOString(),
|
|
258
|
+
observed_seconds: rounded(this.observedMs / 1000),
|
|
259
|
+
active_seconds: rounded(this.activeMs / 1000),
|
|
260
|
+
activity_ratio: this.observedMs > 0 ? rounded(this.activeMs / this.observedMs, 3) : null,
|
|
261
|
+
products,
|
|
262
|
+
timeline: this.timeline.map((segment) => ({ ...segment, product_signatures: [...segment.product_signatures] })),
|
|
263
|
+
sample_interval_ms: this.intervalMs,
|
|
264
|
+
history_limit: this.historyLimit,
|
|
265
|
+
evidence: 'repeated-process-tree-cpu-time-deltas',
|
|
266
|
+
limitation: 'Working now means sustained recent work in a supported app process tree; it is not prompt, task, token, energy, or cost attribution.',
|
|
267
|
+
};
|
|
268
|
+
const memory = this.overheadMemorySamples.at(-1) ?? process.memoryUsage().rss;
|
|
269
|
+
return {
|
|
270
|
+
...base,
|
|
271
|
+
overhead: {
|
|
272
|
+
current_cpu_percent: this.overheadCpuSamples.at(-1) ?? null,
|
|
273
|
+
current_memory_bytes: memory,
|
|
274
|
+
history_bytes: historyByteSize(base),
|
|
275
|
+
sample_count: this.overheadCpuSamples.length,
|
|
276
|
+
median_cpu_percent: percentile(this.overheadCpuSamples, 0.5),
|
|
277
|
+
p95_cpu_percent: percentile(this.overheadCpuSamples, 0.95),
|
|
278
|
+
max_memory_bytes: Math.max(memory, ...this.overheadMemorySamples),
|
|
279
|
+
measurement: 'forkit-process-tree',
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
exports.ActivityMonitor = ActivityMonitor;
|
|
285
|
+
//# sourceMappingURL=monitor.js.map
|
package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CensusModel, CensusRuntime, Confidence, RuntimeKind, RuntimeStatus } from '../types';
|
|
2
|
+
export declare function fetchJson(url: string, init: RequestInit, fetchImpl: typeof fetch, timeoutMs?: number): Promise<{
|
|
3
|
+
ok: boolean;
|
|
4
|
+
status: number;
|
|
5
|
+
body: unknown;
|
|
6
|
+
error: string | null;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function createRuntime(input: {
|
|
9
|
+
name: RuntimeKind;
|
|
10
|
+
endpoint: string | null;
|
|
11
|
+
status: RuntimeStatus;
|
|
12
|
+
modelCount: number;
|
|
13
|
+
observedAt: string;
|
|
14
|
+
errorCode?: string | null;
|
|
15
|
+
}): CensusRuntime;
|
|
16
|
+
export declare function createModel(input: {
|
|
17
|
+
name: string;
|
|
18
|
+
runtime: RuntimeKind;
|
|
19
|
+
identityKind: CensusModel['identity_kind'];
|
|
20
|
+
identity: string;
|
|
21
|
+
source: CensusModel['source'];
|
|
22
|
+
confidence: Confidence;
|
|
23
|
+
sizeBytes?: number | null;
|
|
24
|
+
modifiedAt?: string | null;
|
|
25
|
+
quantization?: string | null;
|
|
26
|
+
architecture?: string | null;
|
|
27
|
+
parameterSize?: string | null;
|
|
28
|
+
locationHint?: string | null;
|
|
29
|
+
}): CensusModel;
|
|
30
|
+
export declare function readRecord(value: unknown): Record<string, unknown> | null;
|
|
31
|
+
export declare function readArray(value: unknown): unknown[];
|
|
32
|
+
export declare function readString(value: unknown): string | null;
|
|
33
|
+
export declare function readNumber(value: unknown): number | null;
|
|
34
|
+
//# sourceMappingURL=base.d.ts.map
|