forkit-connect 0.1.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 (51) hide show
  1. package/QUICKSTART.md +55 -0
  2. package/README.md +96 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.js +4724 -0
  5. package/dist/index.d.ts +7 -0
  6. package/dist/index.js +21 -0
  7. package/dist/launcher.d.ts +33 -0
  8. package/dist/launcher.js +9344 -0
  9. package/dist/ps-list-loader.d.ts +5 -0
  10. package/dist/ps-list-loader.js +20 -0
  11. package/dist/v1/agent-observation.d.ts +42 -0
  12. package/dist/v1/agent-observation.js +499 -0
  13. package/dist/v1/api.d.ts +276 -0
  14. package/dist/v1/api.js +390 -0
  15. package/dist/v1/credential-store.d.ts +92 -0
  16. package/dist/v1/credential-store.js +797 -0
  17. package/dist/v1/currency.d.ts +41 -0
  18. package/dist/v1/currency.js +127 -0
  19. package/dist/v1/daemon.d.ts +50 -0
  20. package/dist/v1/daemon.js +265 -0
  21. package/dist/v1/discovery.d.ts +61 -0
  22. package/dist/v1/discovery.js +168 -0
  23. package/dist/v1/filesystem-models.d.ts +11 -0
  24. package/dist/v1/filesystem-models.js +261 -0
  25. package/dist/v1/heartbeat.d.ts +45 -0
  26. package/dist/v1/heartbeat.js +463 -0
  27. package/dist/v1/lifecycle-monitor.d.ts +78 -0
  28. package/dist/v1/lifecycle-monitor.js +512 -0
  29. package/dist/v1/lmstudio.d.ts +11 -0
  30. package/dist/v1/lmstudio.js +148 -0
  31. package/dist/v1/ollama.d.ts +19 -0
  32. package/dist/v1/ollama.js +164 -0
  33. package/dist/v1/openai-compatible.d.ts +12 -0
  34. package/dist/v1/openai-compatible.js +124 -0
  35. package/dist/v1/process-scout.d.ts +50 -0
  36. package/dist/v1/process-scout.js +715 -0
  37. package/dist/v1/providers.d.ts +50 -0
  38. package/dist/v1/providers.js +106 -0
  39. package/dist/v1/service.d.ts +680 -0
  40. package/dist/v1/service.js +8286 -0
  41. package/dist/v1/state.d.ts +87 -0
  42. package/dist/v1/state.js +1318 -0
  43. package/dist/v1/test-credential-backend.d.ts +19 -0
  44. package/dist/v1/test-credential-backend.js +49 -0
  45. package/dist/v1/types.d.ts +873 -0
  46. package/dist/v1/types.js +3 -0
  47. package/dist/v1/update.d.ts +38 -0
  48. package/dist/v1/update.js +184 -0
  49. package/dist/v1/vitality-pulse.d.ts +36 -0
  50. package/dist/v1/vitality-pulse.js +512 -0
  51. package/package.json +53 -0
@@ -0,0 +1,715 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGENT_PROCESS_SIGNATURES = exports.AI_PROCESS_SIGNATURES = void 0;
4
+ exports.classifyProcessEntry = classifyProcessEntry;
5
+ exports.matchesRuntimeObservation = matchesRuntimeObservation;
6
+ exports.classifyAgentProcessEntry = classifyAgentProcessEntry;
7
+ exports.scanLikelyAiProcesses = scanLikelyAiProcesses;
8
+ exports.scanLikelyAgentProcesses = scanLikelyAgentProcesses;
9
+ const node_crypto_1 = require("node:crypto");
10
+ const ps_list_loader_1 = require("../ps-list-loader");
11
+ const discovery_1 = require("./discovery");
12
+ const RUNTIME_LAUNCHER_TERMS = ['python', 'python3', 'node', 'nodejs', 'bun', 'deno', 'uvicorn', 'gunicorn', 'cargo', 'go'];
13
+ const OPENAI_COMPAT_SERVER_TERMS = [
14
+ 'api_server',
15
+ 'openai',
16
+ 'chat/completions',
17
+ 'chat-completions',
18
+ 'completions',
19
+ 'v1/models',
20
+ 'v1/chat',
21
+ 'inference server',
22
+ ];
23
+ const RUNTIME_ENGINE_TERMS = [
24
+ 'vllm',
25
+ 'sglang',
26
+ 'litellm',
27
+ 'tabbyapi',
28
+ 'koboldcpp',
29
+ 'fastchat',
30
+ 'xinference',
31
+ 'mistralrs',
32
+ 'mlx_lm',
33
+ 'mlx-lm',
34
+ 'text-generation-inference',
35
+ 'text_generation_inference',
36
+ 'tensorrt-llm',
37
+ 'tensorrt_llm',
38
+ 'llama.cpp',
39
+ 'llama-server',
40
+ 'localai',
41
+ 'open-webui',
42
+ 'comfyui',
43
+ 'automatic1111',
44
+ 'stable-diffusion-webui',
45
+ 'invokeai',
46
+ ];
47
+ const RUNTIME_MODEL_TERMS = [
48
+ 'gguf',
49
+ 'safetensors',
50
+ 'huggingface',
51
+ 'transformers',
52
+ 'diffusers',
53
+ '--model',
54
+ '-m ',
55
+ 'embedding',
56
+ 'inference',
57
+ ];
58
+ const AGENT_LAUNCHER_TERMS = ['python', 'python3', 'node', 'nodejs', 'bun', 'deno'];
59
+ const AGENT_FRAMEWORK_TERMS = [
60
+ 'langgraph',
61
+ 'haystack',
62
+ 'semantic-kernel',
63
+ 'semantic_kernel',
64
+ 'dspy',
65
+ 'smolagents',
66
+ 'agno',
67
+ 'pydantic-ai',
68
+ 'pydantic_ai',
69
+ 'openhands',
70
+ 'aider',
71
+ 'cline',
72
+ 'roo-code',
73
+ 'roo_code',
74
+ 'goose',
75
+ 'mastra',
76
+ ];
77
+ const AGENT_ORCHESTRATION_TERMS = [
78
+ 'agent',
79
+ 'assistant',
80
+ 'planner',
81
+ 'orchestrator',
82
+ 'workflow',
83
+ 'tool calling',
84
+ 'tool-calling',
85
+ 'multi-agent',
86
+ 'autonomous',
87
+ ];
88
+ const AGENT_AI_CORE_TERMS = [
89
+ 'llm',
90
+ 'prompt',
91
+ 'openai',
92
+ 'anthropic',
93
+ 'ollama',
94
+ 'mcp',
95
+ 'tool',
96
+ 'reasoning',
97
+ ];
98
+ const PORT_CAPTURE_PATTERNS = [
99
+ /--port(?:=|\s+)(\d{2,5})/g,
100
+ /(?:^|\s)-p\s+(\d{2,5})(?=\s|$)/g,
101
+ /(?:localhost|127\.0\.0\.1|0\.0\.0\.0):(\d{2,5})/g,
102
+ /\bport[=:](\d{2,5})\b/gi,
103
+ ];
104
+ exports.AI_PROCESS_SIGNATURES = [
105
+ {
106
+ signature: 'ollama',
107
+ knownProvider: 'ollama',
108
+ providerHints: ['ollama'],
109
+ aliases: ['ollama'],
110
+ match: (processName, command) => processName.includes('ollama') || command.includes('ollama'),
111
+ },
112
+ {
113
+ signature: 'lmstudio',
114
+ knownProvider: 'lmstudio',
115
+ providerHints: ['lmstudio'],
116
+ aliases: ['lmstudio', 'lm studio'],
117
+ match: (processName, command) => processName.includes('lmstudio') || command.includes('lm studio'),
118
+ },
119
+ {
120
+ signature: 'llama.cpp',
121
+ knownProvider: null,
122
+ providerHints: ['openai-compatible'],
123
+ expectedPorts: [8080],
124
+ aliases: ['llama.cpp'],
125
+ match: (processName, command) => processName.includes('llama.cpp') || command.includes('llama.cpp'),
126
+ },
127
+ {
128
+ signature: 'llama-server',
129
+ knownProvider: null,
130
+ providerHints: ['openai-compatible'],
131
+ expectedPorts: [8080],
132
+ aliases: ['llama-server'],
133
+ match: (processName, command) => processName.includes('llama-server') || command.includes('llama-server'),
134
+ },
135
+ {
136
+ signature: 'vllm',
137
+ knownProvider: null,
138
+ providerHints: ['openai-compatible'],
139
+ expectedPorts: [8000],
140
+ aliases: ['vllm', 'api_server'],
141
+ match: (processName, command) => processName.includes('vllm') || command.includes(' vllm') || command.includes('vllm.'),
142
+ },
143
+ {
144
+ signature: 'localai',
145
+ knownProvider: null,
146
+ providerHints: ['openai-compatible'],
147
+ expectedPorts: [8080],
148
+ aliases: ['localai'],
149
+ match: (processName, command) => processName.includes('localai') || command.includes('localai'),
150
+ },
151
+ {
152
+ signature: 'text-generation-inference',
153
+ knownProvider: null,
154
+ providerHints: ['openai-compatible'],
155
+ expectedPorts: [3000, 8080],
156
+ aliases: ['text-generation-inference', 'text_generation_inference', 'tgi'],
157
+ match: (processName, command) => processName.includes('text-generation-inference') || command.includes('text-generation-inference') || command.includes('text_generation_inference') || command.includes('tgi'),
158
+ },
159
+ {
160
+ signature: 'sglang',
161
+ knownProvider: null,
162
+ providerHints: ['openai-compatible'],
163
+ expectedPorts: [30000, 8000],
164
+ aliases: ['sglang'],
165
+ match: (processName, command) => processName.includes('sglang') || command.includes('sglang'),
166
+ },
167
+ {
168
+ signature: 'litellm',
169
+ knownProvider: null,
170
+ providerHints: ['openai-compatible'],
171
+ expectedPorts: [4000, 8000],
172
+ aliases: ['litellm'],
173
+ match: (processName, command) => processName.includes('litellm') || command.includes('litellm'),
174
+ },
175
+ {
176
+ signature: 'tabbyapi',
177
+ knownProvider: null,
178
+ providerHints: ['openai-compatible'],
179
+ expectedPorts: [5000, 8080],
180
+ aliases: ['tabbyapi', 'tabby api'],
181
+ match: (processName, command) => processName.includes('tabbyapi') || command.includes('tabbyapi') || command.includes('tabby api'),
182
+ },
183
+ {
184
+ signature: 'koboldcpp',
185
+ knownProvider: null,
186
+ providerHints: ['openai-compatible'],
187
+ expectedPorts: [5001],
188
+ aliases: ['koboldcpp', 'kobold.cpp'],
189
+ match: (processName, command) => processName.includes('koboldcpp') || command.includes('koboldcpp') || command.includes('kobold.cpp'),
190
+ },
191
+ {
192
+ signature: 'fastchat',
193
+ knownProvider: null,
194
+ providerHints: ['openai-compatible'],
195
+ expectedPorts: [8000, 21002],
196
+ aliases: ['fastchat'],
197
+ match: (processName, command) => processName.includes('fastchat') || command.includes('fastchat'),
198
+ },
199
+ {
200
+ signature: 'xinference',
201
+ knownProvider: null,
202
+ providerHints: ['openai-compatible'],
203
+ expectedPorts: [9997],
204
+ aliases: ['xinference'],
205
+ match: (processName, command) => processName.includes('xinference') || command.includes('xinference'),
206
+ },
207
+ {
208
+ signature: 'mistralrs',
209
+ knownProvider: null,
210
+ providerHints: ['openai-compatible'],
211
+ expectedPorts: [8080],
212
+ aliases: ['mistralrs', 'mistral.rs'],
213
+ match: (processName, command) => processName.includes('mistralrs') || command.includes('mistralrs') || command.includes('mistral.rs'),
214
+ },
215
+ {
216
+ signature: 'mlx-lm',
217
+ knownProvider: null,
218
+ providerHints: ['openai-compatible'],
219
+ expectedPorts: [8080],
220
+ aliases: ['mlx-lm', 'mlx_lm'],
221
+ match: (processName, command) => processName.includes('mlx-lm') || command.includes('mlx-lm') || command.includes('mlx_lm'),
222
+ },
223
+ {
224
+ signature: 'comfyui',
225
+ knownProvider: null,
226
+ expectedPorts: [8188],
227
+ aliases: ['comfyui'],
228
+ match: (processName, command) => processName.includes('comfyui') || command.includes('comfyui'),
229
+ },
230
+ {
231
+ signature: 'automatic1111',
232
+ knownProvider: null,
233
+ expectedPorts: [7860],
234
+ aliases: ['automatic1111', 'stable-diffusion-webui'],
235
+ match: (processName, command) => processName.includes('automatic1111')
236
+ || command.includes('automatic1111')
237
+ || command.includes('stable-diffusion-webui'),
238
+ },
239
+ {
240
+ signature: 'invokeai',
241
+ knownProvider: null,
242
+ expectedPorts: [9090],
243
+ aliases: ['invokeai'],
244
+ match: (processName, command) => processName.includes('invokeai') || command.includes('invokeai'),
245
+ },
246
+ {
247
+ signature: 'python-ai-runtime',
248
+ knownProvider: null,
249
+ aliases: ['python', 'vllm', 'llama', 'transformers'],
250
+ confidence: 'medium',
251
+ sourceLabel: 'Detected by Python AI runtime signature',
252
+ match: (processName, command) => processName.startsWith('python')
253
+ && (command.includes('vllm')
254
+ || command.includes('llama')
255
+ || command.includes('transformers')
256
+ || command.includes('diffusers')),
257
+ },
258
+ ];
259
+ exports.AGENT_PROCESS_SIGNATURES = [
260
+ {
261
+ signature: 'codex',
262
+ agentType: 'coding_agent',
263
+ agentName: 'Codex',
264
+ aliases: ['codex'],
265
+ match: (processName, command) => processName.includes('codex') || command.includes(' codex') || command.includes('/codex'),
266
+ },
267
+ {
268
+ signature: 'claude',
269
+ agentType: 'coding_agent',
270
+ agentName: 'Claude',
271
+ aliases: ['claude'],
272
+ match: (processName, command) => processName.includes('claude') || command.includes(' claude') || command.includes('/claude'),
273
+ },
274
+ {
275
+ signature: 'aider',
276
+ agentType: 'coding_agent',
277
+ agentName: 'Aider',
278
+ aliases: ['aider'],
279
+ match: (processName, command) => processName.includes('aider') || command.includes(' aider'),
280
+ },
281
+ {
282
+ signature: 'cursor',
283
+ agentType: 'ide_extension',
284
+ agentName: 'Cursor',
285
+ aliases: ['cursor'],
286
+ match: (processName, command) => processName.includes('cursor') || command.includes('cursor'),
287
+ },
288
+ {
289
+ signature: 'windsurf',
290
+ agentType: 'ide_extension',
291
+ agentName: 'Windsurf',
292
+ aliases: ['windsurf'],
293
+ match: (processName, command) => processName.includes('windsurf') || command.includes('windsurf'),
294
+ },
295
+ {
296
+ signature: 'cline',
297
+ agentType: 'ide_extension',
298
+ agentName: 'Cline',
299
+ aliases: ['cline'],
300
+ match: (processName, command) => processName.includes('cline') || command.includes('cline'),
301
+ },
302
+ {
303
+ signature: 'roo-code',
304
+ agentType: 'ide_extension',
305
+ agentName: 'Roo Code',
306
+ aliases: ['roo-code', 'roo_code'],
307
+ match: (processName, command) => processName.includes('roo-code') || command.includes('roo-code') || command.includes('roo_code'),
308
+ },
309
+ {
310
+ signature: 'vscode-agent',
311
+ agentType: 'ide_extension',
312
+ agentName: 'VS Code AI Tooling',
313
+ aliases: ['vscode', 'code', 'mcp', 'copilot', 'agent'],
314
+ match: (processName, command) => (processName === 'code' || processName.includes('vscode'))
315
+ && (command.includes('mcp') || command.includes('copilot') || command.includes('agent')),
316
+ },
317
+ {
318
+ signature: 'mcp-server',
319
+ agentType: 'mcp_server',
320
+ agentName: 'MCP Server',
321
+ aliases: ['mcp', 'model context protocol'],
322
+ match: (processName, command) => processName.includes('mcp') || command.includes(' mcp') || command.includes('model context protocol'),
323
+ },
324
+ {
325
+ signature: 'langchain',
326
+ agentType: 'local_agent_runtime',
327
+ agentName: 'LangChain Tooling',
328
+ aliases: ['langchain'],
329
+ match: (processName, command) => processName.includes('langchain') || command.includes('langchain'),
330
+ },
331
+ {
332
+ signature: 'llamaindex',
333
+ agentType: 'local_agent_runtime',
334
+ agentName: 'LlamaIndex Tooling',
335
+ aliases: ['llamaindex'],
336
+ match: (processName, command) => processName.includes('llamaindex') || command.includes('llamaindex'),
337
+ },
338
+ {
339
+ signature: 'langgraph',
340
+ agentType: 'local_agent_runtime',
341
+ agentName: 'LangGraph Tooling',
342
+ aliases: ['langgraph'],
343
+ match: (processName, command) => processName.includes('langgraph') || command.includes('langgraph'),
344
+ },
345
+ {
346
+ signature: 'haystack',
347
+ agentType: 'local_agent_runtime',
348
+ agentName: 'Haystack Tooling',
349
+ aliases: ['haystack'],
350
+ match: (processName, command) => processName.includes('haystack') || command.includes('haystack'),
351
+ },
352
+ {
353
+ signature: 'semantic-kernel',
354
+ agentType: 'local_agent_runtime',
355
+ agentName: 'Semantic Kernel Tooling',
356
+ aliases: ['semantic-kernel', 'semantic_kernel'],
357
+ match: (processName, command) => processName.includes('semantic-kernel')
358
+ || command.includes('semantic-kernel')
359
+ || command.includes('semantic_kernel'),
360
+ },
361
+ {
362
+ signature: 'dspy',
363
+ agentType: 'local_agent_runtime',
364
+ agentName: 'DSPy Tooling',
365
+ aliases: ['dspy'],
366
+ match: (processName, command) => processName.includes('dspy') || command.includes('dspy'),
367
+ },
368
+ {
369
+ signature: 'smolagents',
370
+ agentType: 'local_agent_runtime',
371
+ agentName: 'smolagents Tooling',
372
+ aliases: ['smolagents'],
373
+ match: (processName, command) => processName.includes('smolagents') || command.includes('smolagents'),
374
+ },
375
+ {
376
+ signature: 'agno',
377
+ agentType: 'local_agent_runtime',
378
+ agentName: 'Agno Tooling',
379
+ aliases: ['agno'],
380
+ match: (processName, command) => processName.includes('agno') || command.includes('agno'),
381
+ },
382
+ {
383
+ signature: 'pydantic-ai',
384
+ agentType: 'local_agent_runtime',
385
+ agentName: 'PydanticAI Tooling',
386
+ aliases: ['pydantic-ai', 'pydantic_ai'],
387
+ match: (processName, command) => processName.includes('pydantic-ai')
388
+ || command.includes('pydantic-ai')
389
+ || command.includes('pydantic_ai'),
390
+ },
391
+ {
392
+ signature: 'crewai',
393
+ agentType: 'local_agent_runtime',
394
+ agentName: 'CrewAI Tooling',
395
+ aliases: ['crewai'],
396
+ match: (processName, command) => processName.includes('crewai') || command.includes('crewai'),
397
+ },
398
+ {
399
+ signature: 'autogen',
400
+ agentType: 'local_agent_runtime',
401
+ agentName: 'AutoGen Tooling',
402
+ aliases: ['autogen'],
403
+ match: (processName, command) => processName.includes('autogen') || command.includes('autogen'),
404
+ },
405
+ {
406
+ signature: 'openhands',
407
+ agentType: 'coding_agent',
408
+ agentName: 'OpenHands',
409
+ aliases: ['openhands'],
410
+ match: (processName, command) => processName.includes('openhands') || command.includes('openhands'),
411
+ },
412
+ {
413
+ signature: 'claude-code',
414
+ agentType: 'coding_agent',
415
+ agentName: 'Claude Code',
416
+ aliases: ['claude', 'claude-code'],
417
+ match: (processName, command) => processName === 'claude' ||
418
+ processName.includes('claude-code') ||
419
+ command.includes('claude-code') ||
420
+ (processName.includes('claude') && (command.includes('code') || command.includes('--print') || command.includes('--output-format'))),
421
+ },
422
+ {
423
+ signature: 'n8n',
424
+ agentType: 'workflow_automation',
425
+ agentName: 'n8n Workflow Automation',
426
+ aliases: ['n8n'],
427
+ match: (processName, command) => processName === 'n8n' || processName.includes('n8n') || command.includes('n8n'),
428
+ },
429
+ {
430
+ signature: 'lovable',
431
+ agentType: 'coding_agent',
432
+ agentName: 'Lovable',
433
+ aliases: ['lovable'],
434
+ match: (processName, command) => processName.includes('lovable') || command.includes('lovable'),
435
+ },
436
+ {
437
+ signature: 'python-agent-runtime',
438
+ agentType: 'unknown_ai_tool',
439
+ agentName: 'Python AI Tool',
440
+ aliases: ['python', 'agent', 'mcp', 'langchain', 'llamaindex', 'crewai', 'autogen'],
441
+ confidence: 'medium',
442
+ sourceLabel: 'Detected by Python AI tool signature',
443
+ match: (processName, command) => processName.startsWith('python')
444
+ && ['agent', 'mcp', 'langchain', 'llamaindex', 'crewai', 'autogen', 'langgraph', 'haystack'].some((term) => command.includes(term)),
445
+ },
446
+ ];
447
+ function shaFragment(value) {
448
+ return (0, node_crypto_1.createHash)('sha256').update(value, 'utf8').digest('hex').slice(0, 16);
449
+ }
450
+ function normalizeText(value) {
451
+ return String(value || '').trim().toLowerCase();
452
+ }
453
+ function tokenizeCommand(command) {
454
+ return command.split(/\s+/).map((token) => token.trim()).filter(Boolean);
455
+ }
456
+ function basenameFromToken(token) {
457
+ if (!token)
458
+ return 'unknown';
459
+ const normalized = token.replace(/\\/g, '/');
460
+ const parts = normalized.split('/').filter(Boolean);
461
+ return parts[parts.length - 1] || normalized;
462
+ }
463
+ function uniqueStrings(values) {
464
+ return [...new Set(values.map((value) => normalizeText(value)).filter(Boolean))];
465
+ }
466
+ function parseExpectedPortsFromCommand(command) {
467
+ const ports = new Set();
468
+ for (const pattern of PORT_CAPTURE_PATTERNS) {
469
+ for (const match of command.matchAll(pattern)) {
470
+ const numeric = Number(match[1] || '');
471
+ if (Number.isInteger(numeric) && numeric >= 1 && numeric <= 65535) {
472
+ ports.add(numeric);
473
+ }
474
+ }
475
+ }
476
+ return [...ports].sort((left, right) => left - right);
477
+ }
478
+ function collectMatchedTerms(haystack, terms) {
479
+ return uniqueStrings(terms.filter((term) => haystack.includes(term)));
480
+ }
481
+ function detectKnownRuntimeSignature(processName, command) {
482
+ return exports.AI_PROCESS_SIGNATURES.find((candidate) => candidate.match(processName, command)) ?? null;
483
+ }
484
+ function detectKnownAgentSignature(processName, command) {
485
+ return exports.AGENT_PROCESS_SIGNATURES.find((candidate) => candidate.match(processName, command)) ?? null;
486
+ }
487
+ function inferRuntimeHeuristic(processName, command) {
488
+ const haystack = `${processName} ${command}`.trim();
489
+ if (!haystack) {
490
+ return null;
491
+ }
492
+ const launcherTerms = collectMatchedTerms(haystack, RUNTIME_LAUNCHER_TERMS);
493
+ const engineTerms = collectMatchedTerms(haystack, RUNTIME_ENGINE_TERMS);
494
+ const serverTerms = collectMatchedTerms(haystack, OPENAI_COMPAT_SERVER_TERMS);
495
+ const modelTerms = collectMatchedTerms(haystack, RUNTIME_MODEL_TERMS);
496
+ const explicitPorts = parseExpectedPortsFromCommand(command);
497
+ const score = (engineTerms.length > 0 ? 3 : 0)
498
+ + (serverTerms.length > 0 ? 2 : 0)
499
+ + (modelTerms.length > 0 ? 1 : 0)
500
+ + (launcherTerms.length > 0 ? 1 : 0)
501
+ + (explicitPorts.length > 0 ? 1 : 0);
502
+ const looksLikeRuntime = engineTerms.length > 0 || (serverTerms.length > 0 && modelTerms.length > 0);
503
+ if (!looksLikeRuntime || score < 3) {
504
+ return null;
505
+ }
506
+ const matchedTerms = uniqueStrings([
507
+ ...engineTerms,
508
+ ...serverTerms,
509
+ ...modelTerms,
510
+ ...launcherTerms,
511
+ ]);
512
+ const providerHints = uniqueStrings([
513
+ serverTerms.length > 0 || engineTerms.some((term) => term !== 'comfyui' && term !== 'automatic1111' && term !== 'stable-diffusion-webui' && term !== 'invokeai')
514
+ ? 'openai-compatible'
515
+ : null,
516
+ ]);
517
+ return {
518
+ signature: 'unknown-ai-runtime',
519
+ knownProvider: null,
520
+ providerHints,
521
+ expectedPorts: explicitPorts,
522
+ matchedTerms,
523
+ confidence: engineTerms.length > 0 || explicitPorts.length > 0 ? 'medium' : 'low',
524
+ sourceLabel: 'Heuristic AI runtime candidate',
525
+ reason: 'ai_runtime_heuristic_match',
526
+ };
527
+ }
528
+ function inferAgentHeuristic(processName, command) {
529
+ const haystack = `${processName} ${command}`.trim();
530
+ if (!haystack) {
531
+ return null;
532
+ }
533
+ const launcherTerms = collectMatchedTerms(haystack, AGENT_LAUNCHER_TERMS);
534
+ const frameworkTerms = collectMatchedTerms(haystack, AGENT_FRAMEWORK_TERMS);
535
+ const orchestrationTerms = collectMatchedTerms(haystack, AGENT_ORCHESTRATION_TERMS);
536
+ const aiCoreTerms = collectMatchedTerms(haystack, AGENT_AI_CORE_TERMS);
537
+ const score = (frameworkTerms.length > 0 ? 2 : 0)
538
+ + (orchestrationTerms.length > 0 ? 1 : 0)
539
+ + (aiCoreTerms.length > 0 ? 1 : 0)
540
+ + (launcherTerms.length > 0 ? 1 : 0);
541
+ const looksLikeAgent = frameworkTerms.length > 0 || (orchestrationTerms.length > 0 && aiCoreTerms.length > 0);
542
+ if (!looksLikeAgent || score < 3) {
543
+ return null;
544
+ }
545
+ return {
546
+ signature: 'unknown-ai-tool',
547
+ agentType: 'unknown_ai_tool',
548
+ agentName: 'Unknown AI Tool',
549
+ matchedTerms: uniqueStrings([
550
+ ...frameworkTerms,
551
+ ...orchestrationTerms,
552
+ ...aiCoreTerms,
553
+ ...launcherTerms,
554
+ ]),
555
+ confidence: frameworkTerms.length > 0 ? 'medium' : 'low',
556
+ sourceLabel: 'Heuristic AI tool candidate',
557
+ reason: 'ai_agent_heuristic_match',
558
+ };
559
+ }
560
+ function classifyProcessEntry(entry) {
561
+ const processName = normalizeText(entry.name);
562
+ const command = normalizeText(entry.cmd);
563
+ if (!processName && !command) {
564
+ return null;
565
+ }
566
+ const tokens = tokenizeCommand(command);
567
+ const firstToken = tokens[0] || processName;
568
+ const knownSignature = detectKnownRuntimeSignature(processName, command);
569
+ const heuristic = knownSignature ? null : inferRuntimeHeuristic(processName, command);
570
+ if (!knownSignature && !heuristic) {
571
+ return null;
572
+ }
573
+ if (knownSignature) {
574
+ const matchedTerms = uniqueStrings([
575
+ knownSignature.signature,
576
+ knownSignature.knownProvider,
577
+ ...(knownSignature.providerHints ?? []),
578
+ ...(knownSignature.aliases ?? []),
579
+ ].filter((term) => typeof term === 'string' && haystackIncludes(processName, command, term)));
580
+ return {
581
+ pid: entry.pid,
582
+ parent_pid: typeof entry.ppid === 'number' ? entry.ppid : null,
583
+ process_name: processName || 'unknown',
584
+ executable_name: basenameFromToken(firstToken),
585
+ signature: knownSignature.signature,
586
+ known_provider: knownSignature.knownProvider,
587
+ provider_hints: uniqueStrings(knownSignature.providerHints ?? []),
588
+ expected_ports: uniqueNumbers([...(knownSignature.expectedPorts ?? []), ...parseExpectedPortsFromCommand(command)]),
589
+ matched_terms: matchedTerms.length > 0 ? matchedTerms : [knownSignature.signature],
590
+ command_hash: command ? shaFragment(command) : null,
591
+ path_hash: firstToken && firstToken.includes('/') ? shaFragment(firstToken) : null,
592
+ confidence: knownSignature.confidence ?? 'high',
593
+ detection_mode: 'signature',
594
+ source_label: knownSignature.sourceLabel ?? 'Detected by known AI runtime signature',
595
+ reason: `${knownSignature.signature}_signature_match`,
596
+ };
597
+ }
598
+ return {
599
+ pid: entry.pid,
600
+ parent_pid: typeof entry.ppid === 'number' ? entry.ppid : null,
601
+ process_name: processName || 'unknown',
602
+ executable_name: basenameFromToken(firstToken),
603
+ signature: heuristic?.signature ?? 'unknown-ai-runtime',
604
+ known_provider: heuristic?.knownProvider ?? null,
605
+ provider_hints: heuristic?.providerHints ?? [],
606
+ expected_ports: heuristic?.expectedPorts ?? [],
607
+ matched_terms: heuristic?.matchedTerms ?? [],
608
+ command_hash: command ? shaFragment(command) : null,
609
+ path_hash: firstToken && firstToken.includes('/') ? shaFragment(firstToken) : null,
610
+ confidence: heuristic?.confidence ?? 'low',
611
+ detection_mode: 'heuristic',
612
+ source_label: heuristic?.sourceLabel ?? 'Heuristic AI runtime candidate',
613
+ reason: heuristic?.reason ?? 'ai_runtime_heuristic_match',
614
+ };
615
+ }
616
+ function haystackIncludes(processName, command, term) {
617
+ const normalized = normalizeText(term);
618
+ if (!normalized)
619
+ return false;
620
+ return processName.includes(normalized) || command.includes(normalized);
621
+ }
622
+ function uniqueNumbers(values) {
623
+ return [...new Set(values.filter((value) => Number.isInteger(value) && value >= 1 && value <= 65535))].sort((left, right) => left - right);
624
+ }
625
+ function matchesRuntimeObservation(process, runtimeName, runtimeEndpoint) {
626
+ if (process.known_provider === runtimeName || process.signature === runtimeName) {
627
+ return true;
628
+ }
629
+ if (!process.provider_hints?.includes(runtimeName)) {
630
+ return false;
631
+ }
632
+ if (!process.expected_ports?.length) {
633
+ return true;
634
+ }
635
+ const runtimePort = (0, discovery_1.readEndpointPort)(runtimeEndpoint);
636
+ return runtimePort !== null && process.expected_ports.includes(runtimePort);
637
+ }
638
+ function classifyAgentProcessEntry(entry) {
639
+ const processName = normalizeText(entry.name);
640
+ const command = normalizeText(entry.cmd);
641
+ if (!processName && !command) {
642
+ return null;
643
+ }
644
+ const tokens = tokenizeCommand(command);
645
+ const firstToken = tokens[0] || processName;
646
+ const knownSignature = detectKnownAgentSignature(processName, command);
647
+ const heuristic = knownSignature ? null : inferAgentHeuristic(processName, command);
648
+ if (!knownSignature && !heuristic) {
649
+ return null;
650
+ }
651
+ if (knownSignature) {
652
+ const matchedTerms = uniqueStrings([
653
+ knownSignature.signature,
654
+ knownSignature.agentName,
655
+ ...(knownSignature.aliases ?? []),
656
+ ].filter((term) => haystackIncludes(processName, command, term)));
657
+ return {
658
+ process_name: processName || 'unknown',
659
+ executable_name: basenameFromToken(firstToken),
660
+ signature: knownSignature.signature,
661
+ matched_terms: matchedTerms.length > 0 ? matchedTerms : [knownSignature.signature],
662
+ command_hash: command ? shaFragment(command) : null,
663
+ path_hash: firstToken && firstToken.includes('/') ? shaFragment(firstToken) : null,
664
+ agent_name: knownSignature.agentName,
665
+ agent_type: knownSignature.agentType,
666
+ confidence: knownSignature.confidence ?? 'high',
667
+ detection_mode: 'signature',
668
+ source_label: knownSignature.sourceLabel ?? 'Detected by known AI tool signature',
669
+ reason: `${knownSignature.signature}_signature_match`,
670
+ };
671
+ }
672
+ return {
673
+ process_name: processName || 'unknown',
674
+ executable_name: basenameFromToken(firstToken),
675
+ signature: heuristic?.signature ?? 'unknown-ai-tool',
676
+ matched_terms: heuristic?.matchedTerms ?? [],
677
+ command_hash: command ? shaFragment(command) : null,
678
+ path_hash: firstToken && firstToken.includes('/') ? shaFragment(firstToken) : null,
679
+ agent_name: heuristic?.agentName ?? 'Unknown AI Tool',
680
+ agent_type: heuristic?.agentType ?? 'unknown_ai_tool',
681
+ confidence: heuristic?.confidence ?? 'low',
682
+ detection_mode: 'heuristic',
683
+ source_label: heuristic?.sourceLabel ?? 'Heuristic AI tool candidate',
684
+ reason: heuristic?.reason ?? 'ai_agent_heuristic_match',
685
+ };
686
+ }
687
+ async function scanLikelyAiProcesses(listFn = ps_list_loader_1.listProcesses) {
688
+ const processes = await listFn();
689
+ const seen = new Map();
690
+ for (const entry of processes) {
691
+ const classified = classifyProcessEntry(entry);
692
+ if (!classified)
693
+ continue;
694
+ const identity = `${classified.signature}:${classified.process_name}:${classified.executable_name}:${classified.command_hash}`;
695
+ if (!seen.has(identity)) {
696
+ seen.set(identity, classified);
697
+ }
698
+ }
699
+ return [...seen.values()];
700
+ }
701
+ async function scanLikelyAgentProcesses(listFn = ps_list_loader_1.listProcesses) {
702
+ const processes = await listFn();
703
+ const seen = new Map();
704
+ for (const entry of processes) {
705
+ const classified = classifyAgentProcessEntry(entry);
706
+ if (!classified)
707
+ continue;
708
+ const identity = `${classified.signature}:${classified.process_name}:${classified.executable_name}:${classified.command_hash}`;
709
+ if (!seen.has(identity)) {
710
+ seen.set(identity, classified);
711
+ }
712
+ }
713
+ return [...seen.values()];
714
+ }
715
+ //# sourceMappingURL=process-scout.js.map