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.
Files changed (150) hide show
  1. package/LICENSE +21 -0
  2. package/PRIVACY.md +150 -0
  3. package/README.md +313 -0
  4. package/STATUS.md +136 -0
  5. package/dist/agents.d.ts +22 -0
  6. package/dist/agents.js +281 -0
  7. package/dist/aggregate.d.ts +28 -0
  8. package/dist/aggregate.js +151 -0
  9. package/dist/assets/forkit-icon-dark.png +0 -0
  10. package/dist/assets/forkit-icon-light.png +0 -0
  11. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Info.plist +5 -0
  12. package/dist/bootstrap/Forkit AI Footprint.app/Contents/MacOS/Forkit AI Footprint +0 -0
  13. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/ForkitAIFootprint.icns +0 -0
  14. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/ForkitStatusTemplate.png +0 -0
  15. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/agents.d.ts +22 -0
  16. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/agents.js +281 -0
  17. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.d.ts +28 -0
  18. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/aggregate.js +151 -0
  19. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/assets/forkit-icon-dark.png +0 -0
  20. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/assets/forkit-icon-light.png +0 -0
  21. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/census.d.ts +3 -0
  22. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/census.js +196 -0
  23. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.d.ts +32 -0
  24. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/cli.js +404 -0
  25. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.d.ts +14 -0
  26. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/doctor.js +71 -0
  27. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.d.ts +8 -0
  28. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/endpoints.js +45 -0
  29. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.d.ts +44 -0
  30. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/evaluate.js +102 -0
  31. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.d.ts +11 -0
  32. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/filesystem.js +226 -0
  33. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.d.ts +7 -0
  34. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/format.js +78 -0
  35. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.d.ts +4 -0
  36. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/hash.js +16 -0
  37. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.d.ts +22 -0
  38. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/index.js +58 -0
  39. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.d.ts +13 -0
  40. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/insights.js +76 -0
  41. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.d.ts +19 -0
  42. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/local-device.js +81 -0
  43. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/locales.json +272 -0
  44. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.d.ts +277 -0
  45. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/localization.js +55 -0
  46. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.d.ts +9 -0
  47. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/mcp.js +93 -0
  48. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.d.ts +99 -0
  49. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/monitor.js +285 -0
  50. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.d.ts +34 -0
  51. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/base.js +88 -0
  52. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.d.ts +6 -0
  53. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/index.js +24 -0
  54. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.d.ts +9 -0
  55. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/lmstudio.js +71 -0
  56. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.d.ts +12 -0
  57. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/ollama.js +171 -0
  58. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.d.ts +10 -0
  59. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/providers/openai-compatible.js +68 -0
  60. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.d.ts +17 -0
  61. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/resource-evidence.js +52 -0
  62. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.d.ts +5 -0
  63. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-activity.js +66 -0
  64. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.d.ts +7 -0
  65. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/runtime-identity.js +66 -0
  66. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.d.ts +21 -0
  67. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/server.js +308 -0
  68. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.d.ts +75 -0
  69. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/share-page.js +167 -0
  70. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.d.ts +35 -0
  71. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/sharing.js +67 -0
  72. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.d.ts +9 -0
  73. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/tools.js +106 -0
  74. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.d.ts +166 -0
  75. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/types.js +3 -0
  76. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.d.ts +4 -0
  77. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/dist/version.js +13 -0
  78. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.d.ts +76 -0
  79. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/index.js +366 -0
  80. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/license +9 -0
  81. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/package.json +44 -0
  82. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/readme.md +56 -0
  83. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe +0 -0
  84. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/node_modules/ps-list/vendor/fastlist-0.3.0-x86.exe +0 -0
  85. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/app/package.json +6 -0
  86. package/dist/bootstrap/Forkit AI Footprint.app/Contents/Resources/runtime/node +0 -0
  87. package/dist/bootstrap/Forkit AI Footprint.app/Contents/_CodeSignature/CodeResources +931 -0
  88. package/dist/census.d.ts +3 -0
  89. package/dist/census.js +196 -0
  90. package/dist/cli.d.ts +32 -0
  91. package/dist/cli.js +404 -0
  92. package/dist/doctor.d.ts +14 -0
  93. package/dist/doctor.js +71 -0
  94. package/dist/endpoints.d.ts +8 -0
  95. package/dist/endpoints.js +45 -0
  96. package/dist/evaluate.d.ts +44 -0
  97. package/dist/evaluate.js +102 -0
  98. package/dist/filesystem.d.ts +11 -0
  99. package/dist/filesystem.js +226 -0
  100. package/dist/format.d.ts +7 -0
  101. package/dist/format.js +78 -0
  102. package/dist/hash.d.ts +4 -0
  103. package/dist/hash.js +16 -0
  104. package/dist/index.d.ts +22 -0
  105. package/dist/index.js +58 -0
  106. package/dist/insights.d.ts +13 -0
  107. package/dist/insights.js +76 -0
  108. package/dist/local-device.d.ts +19 -0
  109. package/dist/local-device.js +81 -0
  110. package/dist/locales.json +272 -0
  111. package/dist/localization.d.ts +277 -0
  112. package/dist/localization.js +55 -0
  113. package/dist/mcp.d.ts +9 -0
  114. package/dist/mcp.js +93 -0
  115. package/dist/monitor.d.ts +99 -0
  116. package/dist/monitor.js +285 -0
  117. package/dist/providers/base.d.ts +34 -0
  118. package/dist/providers/base.js +88 -0
  119. package/dist/providers/index.d.ts +6 -0
  120. package/dist/providers/index.js +24 -0
  121. package/dist/providers/lmstudio.d.ts +9 -0
  122. package/dist/providers/lmstudio.js +71 -0
  123. package/dist/providers/ollama.d.ts +12 -0
  124. package/dist/providers/ollama.js +171 -0
  125. package/dist/providers/openai-compatible.d.ts +10 -0
  126. package/dist/providers/openai-compatible.js +68 -0
  127. package/dist/resource-evidence.d.ts +17 -0
  128. package/dist/resource-evidence.js +52 -0
  129. package/dist/runtime-activity.d.ts +5 -0
  130. package/dist/runtime-activity.js +66 -0
  131. package/dist/runtime-identity.d.ts +7 -0
  132. package/dist/runtime-identity.js +66 -0
  133. package/dist/server.d.ts +21 -0
  134. package/dist/server.js +308 -0
  135. package/dist/share-page.d.ts +75 -0
  136. package/dist/share-page.js +167 -0
  137. package/dist/sharing.d.ts +35 -0
  138. package/dist/sharing.js +67 -0
  139. package/dist/tools.d.ts +9 -0
  140. package/dist/tools.js +106 -0
  141. package/dist/types.d.ts +166 -0
  142. package/dist/types.js +3 -0
  143. package/dist/version.d.ts +4 -0
  144. package/dist/version.js +13 -0
  145. package/docs/GLOBAL_DISTRIBUTION.md +79 -0
  146. package/docs/MACOS_ACCURACY_GATE.md +140 -0
  147. package/docs/MACOS_TESTER_GUIDE.md +88 -0
  148. package/examples/macos-truth.template.json +10 -0
  149. package/package.json +75 -0
  150. package/release/channels.json +41 -0
@@ -0,0 +1,76 @@
1
+ export type Options = {
2
+ /**
3
+ Include other users' processes as well as your own.
4
+
5
+ On Windows this has no effect and will always be the user's own processes.
6
+
7
+ @default true
8
+ */
9
+ readonly all?: boolean;
10
+ };
11
+
12
+ export type ProcessDescriptor = {
13
+ readonly pid: number;
14
+ readonly name: string;
15
+ readonly ppid: number;
16
+
17
+ /**
18
+ Full command line with arguments.
19
+
20
+ Not supported on Windows.
21
+ */
22
+ readonly cmd?: string;
23
+
24
+ /**
25
+ CPU usage as a percentage (0-100).
26
+
27
+ Not supported on Windows.
28
+ */
29
+ readonly cpu?: number;
30
+
31
+ /**
32
+ Memory usage as a percentage (0-100).
33
+
34
+ Not supported on Windows.
35
+ */
36
+ readonly memory?: number;
37
+
38
+ /**
39
+ User ID of the process owner.
40
+
41
+ Not supported on Windows.
42
+ */
43
+ readonly uid?: number;
44
+
45
+ /**
46
+ Best-effort attempt to get the full executable path.
47
+ - Linux: Reads from `/proc/{pid}/exe` when available
48
+ - macOS: Extracted from command line when possible
49
+ - Falls back to `comm` (which may be truncated)
50
+
51
+ Not supported on Windows.
52
+ */
53
+ readonly path?: string;
54
+
55
+ /**
56
+ The date and time when the process was started.
57
+
58
+ Not supported on Windows. May be `undefined` if the date cannot be parsed.
59
+ */
60
+ readonly startTime?: Date;
61
+ };
62
+
63
+ /**
64
+ Get running processes.
65
+
66
+ @returns A list of running processes.
67
+
68
+ @example
69
+ ```
70
+ import psList from 'ps-list';
71
+
72
+ console.log(await psList());
73
+ //=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5, path: '/usr/local/bin/node', startTime: 2025-01-15T10:30:00.000Z}, …]
74
+ ```
75
+ */
76
+ export default function psList(options?: Options): Promise<ProcessDescriptor[]>;
@@ -0,0 +1,366 @@
1
+ import process from 'node:process';
2
+ import fs from 'node:fs';
3
+ import {promisify} from 'node:util';
4
+ import path from 'node:path';
5
+ import {fileURLToPath} from 'node:url';
6
+ import childProcess from 'node:child_process';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ const DEFAULT_MAX_BUFFER = 64_000_000; // 64 MB
11
+ const MAXIMUM_PATH_COMBINATION_ATTEMPTS = 6; // Limit path parsing attempts for performance
12
+
13
+ const execFile = promisify(childProcess.execFile);
14
+
15
+ // Process list field names (used in ps command output)
16
+ const PROCESS_FIELDS = {
17
+ CPU_PERCENT: '%cpu',
18
+ MEMORY_PERCENT: '%mem',
19
+ PROCESS_ID: 'pid',
20
+ PARENT_PROCESS_ID: 'ppid',
21
+ USER_ID: 'uid',
22
+ START_TIME: 'lstart',
23
+ COMMAND_NAME: 'comm',
24
+ ARGUMENTS: 'args',
25
+ };
26
+
27
+ // Helper to build ps command flags consistently
28
+ const buildProcessCommandFlags = includeAllUsersProcesses => (includeAllUsersProcesses === false ? '' : 'a') + 'wwxo';
29
+
30
+ // Safe Date parsing with validation
31
+ const makeStartTime = startTimeString => {
32
+ if (!startTimeString) {
33
+ return undefined;
34
+ }
35
+
36
+ const parsedDate = new Date(startTimeString);
37
+ return Number.isNaN(parsedDate.getTime()) ? undefined : parsedDate;
38
+ };
39
+
40
+ // Extract executable path from command line using filesystem validation only
41
+ const extractExecutablePath = commandLine => {
42
+ if (!commandLine) {
43
+ return '';
44
+ }
45
+
46
+ // Skip non-path commands (no filesystem validation possible)
47
+ if (!commandLine.startsWith('/') && !commandLine.startsWith('"')) {
48
+ return '';
49
+ }
50
+
51
+ // Handle quoted paths first: "/path with spaces/executable"
52
+ if (commandLine.startsWith('"')) {
53
+ const quotedPathMatch = commandLine.match(/^"([^"]+)"/);
54
+ if (quotedPathMatch && fs.existsSync(quotedPathMatch[1])) {
55
+ return quotedPathMatch[1];
56
+ }
57
+
58
+ return '';
59
+ }
60
+
61
+ // For unquoted absolute paths, try different strategies
62
+ const commandParts = commandLine.split(' ');
63
+
64
+ // Strategy 1: Simple first token (most common case)
65
+ const firstCommandToken = commandParts[0];
66
+ if (fs.existsSync(firstCommandToken)) {
67
+ return firstCommandToken;
68
+ }
69
+
70
+ // Strategy 2: Progressive combination for paths with spaces
71
+ // Limit to reasonable number of attempts for performance
72
+ const maximumCombinationAttempts = Math.min(commandParts.length, MAXIMUM_PATH_COMBINATION_ATTEMPTS);
73
+ for (let tokenCount = 2; tokenCount <= maximumCombinationAttempts; tokenCount++) {
74
+ const candidateExecutablePath = commandParts.slice(0, tokenCount).join(' ');
75
+ if (fs.existsSync(candidateExecutablePath)) {
76
+ return candidateExecutablePath;
77
+ }
78
+ }
79
+
80
+ return '';
81
+ };
82
+
83
+ // Resolve executable path - simple approach
84
+ const resolveExecutablePath = (operatingSystemPlatform, processId, commandLine) => {
85
+ // On Linux, try /proc/{pid}/exe first for accurate path
86
+ if (operatingSystemPlatform === 'linux' && processId) {
87
+ try {
88
+ const symbolicLink = fs.readlinkSync(`/proc/${processId}/exe`);
89
+ return symbolicLink.replace(/\s+\(deleted\)$/, '');
90
+ } catch {
91
+ // Continue to other methods
92
+ }
93
+ }
94
+
95
+ // Extract path from command line
96
+ return extractExecutablePath(commandLine);
97
+ };
98
+
99
+ // Parse and validate numeric field with fallback
100
+ const parseNumericField = (fieldValue, parserFunction = Number.parseInt, defaultValue = 0) => {
101
+ if (!fieldValue) {
102
+ return defaultValue;
103
+ }
104
+
105
+ const parsedValue = parserFunction(fieldValue, 10);
106
+ return Number.isNaN(parsedValue) ? defaultValue : parsedValue;
107
+ };
108
+
109
+ // Parse integer or return undefined - used for uid to avoid conflating unknown with root (0)
110
+ const parseIntegerOrUndefined = fieldValue => {
111
+ if (fieldValue === undefined || fieldValue === '') {
112
+ return undefined;
113
+ }
114
+
115
+ const parsedValue = Number.parseInt(fieldValue, 10);
116
+ return Number.isNaN(parsedValue) ? undefined : parsedValue;
117
+ };
118
+
119
+ // Unified field parser
120
+ const parseProcessFields = ({processId, parentProcessId, userId, cpuUsage, memoryUsage, commandName, startTimeString, command}) => {
121
+ // Parse numeric fields with proper defaults
122
+ const parsedProcessId = parseNumericField(processId);
123
+ const parsedParentProcessId = parseNumericField(parentProcessId);
124
+ const parsedUserId = parseIntegerOrUndefined(userId);
125
+ const parsedCpuUsagePercentage = parseNumericField(cpuUsage, Number.parseFloat);
126
+ const parsedMemoryUsagePercentage = parseNumericField(memoryUsage, Number.parseFloat);
127
+
128
+ // Resolve executable path from command line
129
+ const resolvedExecutablePath = resolveExecutablePath(process.platform, parsedProcessId, command);
130
+
131
+ // Derive process name: prefer basename of path, fallback to command name
132
+ const derivedProcessName = resolvedExecutablePath ? path.basename(resolvedExecutablePath) : (commandName || '');
133
+
134
+ return {
135
+ pid: parsedProcessId,
136
+ ppid: parsedParentProcessId,
137
+ uid: parsedUserId, // Undefined when uid can't be parsed (avoid conflating with root)
138
+ cpu: parsedCpuUsagePercentage,
139
+ memory: parsedMemoryUsagePercentage,
140
+ name: derivedProcessName,
141
+ path: resolvedExecutablePath,
142
+ startTime: makeStartTime(startTimeString),
143
+ cmd: command || '',
144
+ };
145
+ };
146
+
147
+ const windows = async () => {
148
+ // Source: https://github.com/MarkTiedemann/fastlist
149
+ let binary;
150
+ switch (process.arch) {
151
+ case 'x64': {
152
+ binary = 'fastlist-0.3.0-x64.exe';
153
+ break;
154
+ }
155
+
156
+ case 'ia32': {
157
+ binary = 'fastlist-0.3.0-x86.exe';
158
+ break;
159
+ }
160
+
161
+ case 'arm64': {
162
+ throw new Error('Windows ARM64 is not supported yet.');
163
+ }
164
+
165
+ default: {
166
+ throw new Error(`Unsupported architecture: ${process.arch}`);
167
+ }
168
+ }
169
+
170
+ const binaryPath = path.join(__dirname, 'vendor', binary);
171
+ const {stdout} = await execFile(binaryPath, {
172
+ maxBuffer: DEFAULT_MAX_BUFFER,
173
+ windowsHide: true,
174
+ encoding: 'utf8',
175
+ });
176
+
177
+ return stdout
178
+ .trim()
179
+ .split(/\r?\n/)
180
+ .map(line => line.split('\t'))
181
+ .map(([processId, parentProcessId, processName]) => ({
182
+ pid: Number.parseInt(processId, 10),
183
+ ppid: Number.parseInt(parentProcessId, 10),
184
+ name: processName,
185
+ }));
186
+ };
187
+
188
+ // Fallback implementation with multiple ps calls
189
+ const nonWindowsFallbackMultipleCalls = async (options = {}) => {
190
+ const processDataByProcessId = {};
191
+ const processCommandFlags = buildProcessCommandFlags(options.all);
192
+
193
+ const fields = [
194
+ PROCESS_FIELDS.COMMAND_NAME,
195
+ PROCESS_FIELDS.ARGUMENTS,
196
+ PROCESS_FIELDS.PARENT_PROCESS_ID,
197
+ PROCESS_FIELDS.USER_ID,
198
+ PROCESS_FIELDS.CPU_PERCENT,
199
+ PROCESS_FIELDS.MEMORY_PERCENT,
200
+ PROCESS_FIELDS.START_TIME,
201
+ ];
202
+
203
+ await Promise.all(fields.map(async fieldName => {
204
+ // Use headerless output with = syntax
205
+ const {stdout} = await execFile('ps', [processCommandFlags, `${PROCESS_FIELDS.PROCESS_ID}=,${fieldName}=`], {
206
+ maxBuffer: DEFAULT_MAX_BUFFER,
207
+ encoding: 'utf8',
208
+ env: {
209
+ ...process.env,
210
+ LC_ALL: 'C',
211
+ LANG: 'C',
212
+ },
213
+ });
214
+
215
+ for (const line of stdout.trim().split('\n')) {
216
+ const trimmedLine = line.trim();
217
+ const spaceIndex = trimmedLine.indexOf(' ');
218
+ if (spaceIndex === -1) {
219
+ // No space found - treat entire line as processId with empty field value
220
+ const processId = trimmedLine;
221
+ const fieldValue = '';
222
+ processDataByProcessId[processId] ??= {};
223
+ processDataByProcessId[processId][fieldName] = fieldValue;
224
+ continue;
225
+ }
226
+
227
+ const processId = trimmedLine.slice(0, spaceIndex);
228
+ const fieldValue = trimmedLine.slice(spaceIndex + 1).trim();
229
+
230
+ processDataByProcessId[processId] ??= {};
231
+ processDataByProcessId[processId][fieldName] = fieldValue;
232
+ }
233
+ }));
234
+
235
+ // Filter out incomplete entries and convert to process objects
236
+ return Object.entries(processDataByProcessId)
237
+ .filter(([, data]) => data[PROCESS_FIELDS.COMMAND_NAME] && data[PROCESS_FIELDS.PARENT_PROCESS_ID] !== undefined)
238
+ .map(([processId, data]) => parseProcessFields({
239
+ processId,
240
+ parentProcessId: data[PROCESS_FIELDS.PARENT_PROCESS_ID],
241
+ userId: data[PROCESS_FIELDS.USER_ID],
242
+ cpuUsage: data[PROCESS_FIELDS.CPU_PERCENT],
243
+ memoryUsage: data[PROCESS_FIELDS.MEMORY_PERCENT],
244
+ commandName: data[PROCESS_FIELDS.COMMAND_NAME],
245
+ startTimeString: data[PROCESS_FIELDS.START_TIME],
246
+ command: data[PROCESS_FIELDS.ARGUMENTS] ?? '',
247
+ }));
248
+ };
249
+
250
+ // Main implementation with headerless output and simpler parsing
251
+ const nonWindowsCall = async (options = {}) => {
252
+ const processCommandFlags = buildProcessCommandFlags(options.all);
253
+
254
+ // Common execFile options to avoid duplication
255
+ const executeFileOptions = {
256
+ maxBuffer: DEFAULT_MAX_BUFFER,
257
+ encoding: 'utf8',
258
+ env: {
259
+ ...process.env,
260
+ LC_ALL: 'C',
261
+ LANG: 'C',
262
+ },
263
+ };
264
+
265
+ // Build field lists for ps commands
266
+ const processFieldCommaSeparatedList = [
267
+ PROCESS_FIELDS.PROCESS_ID,
268
+ PROCESS_FIELDS.PARENT_PROCESS_ID,
269
+ PROCESS_FIELDS.USER_ID,
270
+ PROCESS_FIELDS.CPU_PERCENT,
271
+ PROCESS_FIELDS.MEMORY_PERCENT,
272
+ PROCESS_FIELDS.START_TIME,
273
+ PROCESS_FIELDS.COMMAND_NAME,
274
+ ].map(fieldName => `${fieldName}=`).join(',');
275
+
276
+ const commandFieldCommaSeparatedList = [
277
+ PROCESS_FIELDS.PROCESS_ID,
278
+ PROCESS_FIELDS.ARGUMENTS,
279
+ ].map(fieldName => `${fieldName}=`).join(',');
280
+
281
+ // Use headerless output with = syntax for consistent parsing
282
+ const processListingPromises = [
283
+ execFile('ps', [processCommandFlags, processFieldCommaSeparatedList], executeFileOptions),
284
+ execFile('ps', [processCommandFlags, commandFieldCommaSeparatedList], executeFileOptions),
285
+ ];
286
+
287
+ const [processOutput, commandOutput] = await Promise.all(processListingPromises);
288
+ const processLines = processOutput.stdout.trim().split('\n');
289
+ const commandLines = commandOutput.stdout.trim().split('\n');
290
+
291
+ // Build command lookup map
292
+ const commandLinesByProcessId = {};
293
+ for (const line of commandLines) {
294
+ const trimmedLine = line.trim();
295
+ const spaceIndex = trimmedLine.indexOf(' ');
296
+ if (spaceIndex === -1) {
297
+ // No space found - treat entire line as processId with empty command
298
+ const processId = trimmedLine;
299
+ commandLinesByProcessId[processId] = '';
300
+ continue;
301
+ }
302
+
303
+ const processId = trimmedLine.slice(0, spaceIndex);
304
+ const command = trimmedLine.slice(spaceIndex + 1).trim();
305
+ commandLinesByProcessId[processId] = command;
306
+ }
307
+
308
+ // Parse process lines - format: pid ppid uid cpu mem lstart comm
309
+ const processes = [];
310
+ for (const line of processLines) {
311
+ const trimmedLine = line.trim();
312
+ if (!trimmedLine) {
313
+ continue;
314
+ }
315
+
316
+ // Parse fixed-width fields more carefully
317
+ // Format: "pid ppid uid cpu mem Day Mon DD HH:MM:SS YYYY comm"
318
+ // First 5 fields should be numeric values (pid, ppid, uid are integers; cpu, memory are floats)
319
+ // Regex breakdown: ^(\d+) = pid, \s+(\d+) = ppid, \s+(\d+) = uid, \s+([\d.]+) = cpu%, \s+([\d.]+) = mem%, \s+(.+) = rest
320
+ const processLineRegexMatch = trimmedLine.match(/^(\d+)\s+(\d+)\s+(\d+)\s+([\d.]+)\s+([\d.]+)\s+(.+)/);
321
+ if (!processLineRegexMatch) {
322
+ continue;
323
+ }
324
+
325
+ const [, processId, parentProcessId, userId, cpuUsage, memoryUsage, dateAndCommandPortion] = processLineRegexMatch;
326
+
327
+ // Parse lstart from dateAndCommandPortion - it's always: "Day Mon DD HH:MM:SS YYYY"
328
+ // This regex handles both single and double digit days
329
+ // Regex breakdown: ((?:\w{3}\s+){2} = "Day Mon ", \d{1,2} = day, \s+(?:\d{2}:){2}\d{2} = "HH:MM:SS", \s+\d{4}) = " YYYY"
330
+ const startTimeRegexMatch = dateAndCommandPortion.match(/^((?:\w{3}\s+){2}\d{1,2}\s+(?:\d{2}:){2}\d{2}\s+\d{4})\s+(.*)$/);
331
+
332
+ let startTimeString = '';
333
+ let processCommandName = dateAndCommandPortion; // Fallback if start time parsing fails
334
+
335
+ if (startTimeRegexMatch) {
336
+ startTimeString = startTimeRegexMatch[1];
337
+ processCommandName = startTimeRegexMatch[2] || '';
338
+ }
339
+
340
+ processes.push(parseProcessFields({
341
+ processId,
342
+ parentProcessId,
343
+ userId,
344
+ cpuUsage,
345
+ memoryUsage,
346
+ commandName: processCommandName,
347
+ startTimeString,
348
+ command: commandLinesByProcessId[processId] ?? '',
349
+ }));
350
+ }
351
+
352
+ return processes;
353
+ };
354
+
355
+ const nonWindows = async (options = {}) => {
356
+ try {
357
+ return await nonWindowsCall(options);
358
+ } catch {
359
+ // Fallback to multiple calls if main approach fails
360
+ return nonWindowsFallbackMultipleCalls(options);
361
+ }
362
+ };
363
+
364
+ const psList = process.platform === 'win32' ? windows : nonWindows;
365
+
366
+ export default psList;
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "ps-list",
3
+ "version": "9.0.0",
4
+ "description": "Get running processes",
5
+ "license": "MIT",
6
+ "repository": "sindresorhus/ps-list",
7
+ "funding": "https://github.com/sponsors/sindresorhus",
8
+ "author": {
9
+ "name": "Sindre Sorhus",
10
+ "email": "sindresorhus@gmail.com",
11
+ "url": "https://sindresorhus.com"
12
+ },
13
+ "type": "module",
14
+ "exports": {
15
+ "types": "./index.d.ts",
16
+ "default": "./index.js"
17
+ },
18
+ "sideEffects": false,
19
+ "engines": {
20
+ "node": ">=20"
21
+ },
22
+ "scripts": {
23
+ "test": "xo && ava && tsd"
24
+ },
25
+ "files": [
26
+ "index.js",
27
+ "index.d.ts",
28
+ "vendor/*.exe"
29
+ ],
30
+ "keywords": [
31
+ "ps",
32
+ "proc",
33
+ "process",
34
+ "processes",
35
+ "list",
36
+ "running",
37
+ "tasklist"
38
+ ],
39
+ "devDependencies": {
40
+ "ava": "^6.4.1",
41
+ "tsd": "^0.33.0",
42
+ "xo": "^0.59.0"
43
+ }
44
+ }
@@ -0,0 +1,56 @@
1
+ # ps-list
2
+
3
+ > Get running processes
4
+
5
+ Works on macOS, Linux, and Windows. Windows ARM64 is not supported yet.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install ps-list
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```js
16
+ import psList from 'ps-list';
17
+
18
+ console.log(await psList());
19
+ //=> [{pid: 3213, name: 'node', cmd: 'node test.js', ppid: 1, uid: 501, cpu: 0.1, memory: 1.5, path: '/usr/local/bin/node', startTime: 2025-01-15T10:30:00.000Z}, …]
20
+ ```
21
+
22
+ ## API
23
+
24
+ ### psList(options?)
25
+
26
+ Returns a `Promise<ProcessDescriptor[]>` with the running processes.
27
+
28
+ On macOS and Linux:
29
+ - The `name` property is truncated to 15 characters by the system
30
+ - The `cmd` property contains the full command line with arguments
31
+ - The `cpu` property is the CPU usage percentage (0-100)
32
+ - The `memory` property is the memory usage percentage (0-100)
33
+ - The `path` property is a best-effort attempt to get the full executable path:
34
+ - On Linux: reads from `/proc/{pid}/exe` when available
35
+ - On macOS: extracted from command line when possible
36
+ - Falls back to `comm` (which may be truncated)
37
+ - The `startTime` property contains the process start time as a Date object
38
+
39
+ The `cmd`, `cpu`, `memory`, `uid`, `path`, and `startTime` properties are not available on Windows.
40
+
41
+ #### options
42
+
43
+ Type: `object`
44
+
45
+ ##### all
46
+
47
+ Type: `boolean`\
48
+ Default: `true`
49
+
50
+ Include other users' processes as well as your own.
51
+
52
+ On Windows this has no effect and will always be the user's own processes.
53
+
54
+ ## Related
55
+
56
+ - [fastlist](https://github.com/MarkTiedemann/fastlist) - The binary used in this module to list the running processes on Windows
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "forkit-ai-footprints-bundled",
3
+ "version": "0.2.0",
4
+ "private": true,
5
+ "type": "commonjs"
6
+ }