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,19 @@
1
+ import type { DetectedModel } from './types';
2
+ import { type RuntimeProvider, type RuntimeProviderScanResult } from './providers';
3
+ export interface OllamaScanResult {
4
+ ok: boolean;
5
+ endpoint: string;
6
+ models: DetectedModel[];
7
+ error: string | null;
8
+ }
9
+ export declare function scanOllama(endpoint?: string): Promise<OllamaScanResult>;
10
+ export declare function modelKey(model: DetectedModel): string;
11
+ export declare class OllamaProvider implements RuntimeProvider {
12
+ readonly endpoint: string;
13
+ private readonly fetchImpl;
14
+ readonly runtimeName = "ollama";
15
+ readonly runtimeType: "local-http";
16
+ constructor(endpoint?: string, fetchImpl?: typeof fetch);
17
+ scan(): Promise<RuntimeProviderScanResult>;
18
+ }
19
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OllamaProvider = void 0;
4
+ exports.scanOllama = scanOllama;
5
+ exports.modelKey = modelKey;
6
+ const providers_1 = require("./providers");
7
+ /** Extract a bare sha256 hex string from Ollama's digest field ("sha256:abc..."). */
8
+ function parseOllamaSha256(digest) {
9
+ const m = /^sha256:([0-9a-f]{64})$/i.exec(digest.trim());
10
+ return m ? m[1] : null;
11
+ }
12
+ /** Fetch enriched metadata for a single Ollama model via /api/show (best-effort, non-blocking). */
13
+ async function fetchOllamaModelDetails(endpoint, modelName, fetchImpl) {
14
+ try {
15
+ const ac = new AbortController();
16
+ const timer = setTimeout(() => ac.abort(), 4000);
17
+ const res = await fetchImpl(`${endpoint}/api/show`, {
18
+ method: 'POST',
19
+ headers: { 'Content-Type': 'application/json' },
20
+ body: JSON.stringify({ model: modelName, verbose: false }),
21
+ signal: ac.signal,
22
+ }).finally(() => clearTimeout(timer));
23
+ if (!res.ok)
24
+ return { details: null, digest: null, weightsDigest: null };
25
+ const body = (await res.json());
26
+ // The layer with mediaType 'application/vnd.ollama.image.model' holds the
27
+ // actual weights blob SHA-256 — a stable, content-addressed fingerprint.
28
+ const modelLayer = body.layers?.find((l) => l.mediaType === 'application/vnd.ollama.image.model');
29
+ return {
30
+ details: body.details ?? null,
31
+ digest: body.digest ?? null,
32
+ weightsDigest: modelLayer?.digest ?? null,
33
+ };
34
+ }
35
+ catch {
36
+ return { details: null, digest: null, weightsDigest: null };
37
+ }
38
+ }
39
+ function normalizeModelKey(modelName, digest) {
40
+ return `${modelName}#${digest}`;
41
+ }
42
+ async function scanOllama(endpoint = 'http://localhost:11434') {
43
+ const result = await new OllamaProvider(endpoint).scan();
44
+ return {
45
+ ok: result.ok,
46
+ endpoint,
47
+ models: result.models,
48
+ error: result.error,
49
+ };
50
+ }
51
+ function modelKey(model) {
52
+ return `${model.model}#${model.digest}`;
53
+ }
54
+ class OllamaProvider {
55
+ endpoint;
56
+ fetchImpl;
57
+ runtimeName = 'ollama';
58
+ runtimeType = 'local-http';
59
+ constructor(endpoint = 'http://localhost:11434', fetchImpl = fetch) {
60
+ this.endpoint = endpoint;
61
+ this.fetchImpl = fetchImpl;
62
+ }
63
+ async scan() {
64
+ const tagsEndpoint = `${this.endpoint}/api/tags`;
65
+ const now = new Date().toISOString();
66
+ try {
67
+ const res = await this.fetchImpl(tagsEndpoint, { method: 'GET' });
68
+ if (!res.ok) {
69
+ return {
70
+ ok: false,
71
+ runtime: (0, providers_1.buildDetectedRuntime)({
72
+ runtimeName: this.runtimeName,
73
+ runtimeType: this.runtimeType,
74
+ endpoint: this.endpoint,
75
+ status: 'error',
76
+ lastSeenAt: now,
77
+ error: `http_${res.status}`,
78
+ }),
79
+ models: [],
80
+ error: `http_${res.status}`,
81
+ };
82
+ }
83
+ const body = (await res.json());
84
+ const entries = body.models ?? [];
85
+ // Fetch enriched details for all models in parallel (non-blocking, best-effort).
86
+ const detailResults = await Promise.allSettled(entries.map((entry) => {
87
+ const name = (entry.name ?? entry.model ?? '').trim();
88
+ return name
89
+ ? fetchOllamaModelDetails(this.endpoint, name, this.fetchImpl)
90
+ : Promise.resolve({ details: null, digest: null, weightsDigest: null });
91
+ }));
92
+ const models = entries
93
+ .map((entry, i) => {
94
+ const name = (entry.name ?? entry.model ?? '').trim();
95
+ const rawDigest = (entry.digest ?? '').trim();
96
+ if (!name || !rawDigest)
97
+ return null;
98
+ const showResult = detailResults[i]?.status === 'fulfilled'
99
+ ? detailResults[i].value
100
+ : { details: null, digest: null, weightsDigest: null };
101
+ // Prefer the weights-blob digest from /api/show for a content-addressed fingerprint.
102
+ // Fall back to the manifest digest from /api/tags for older Ollama versions.
103
+ const weightsDigestRaw = showResult?.weightsDigest ?? null;
104
+ const weightsChecksumHex = weightsDigestRaw ? parseOllamaSha256(weightsDigestRaw) : null;
105
+ const manifestChecksumHex = parseOllamaSha256(rawDigest);
106
+ const checksumHex = weightsChecksumHex ?? manifestChecksumHex;
107
+ const checksumSource = weightsChecksumHex ? 'weights_blob' : (manifestChecksumHex ? 'manifest' : null);
108
+ const details = showResult?.details ?? null;
109
+ return (0, providers_1.normalizeDetectedModel)({
110
+ runtimeName: this.runtimeName,
111
+ runtimeType: this.runtimeType,
112
+ modelName: name,
113
+ modelId: name,
114
+ sourceEndpoint: this.endpoint,
115
+ detectedAt: now,
116
+ digest: rawDigest,
117
+ sizeBytes: Number(entry.size ?? 0),
118
+ modifiedAt: entry.modified_at ?? null,
119
+ checksumValue: checksumHex,
120
+ checksumAlgorithm: checksumHex ? 'sha256' : null,
121
+ checksumSource,
122
+ quantizationLevel: details?.quantization_level ?? null,
123
+ architectureFamily: details?.family ?? null,
124
+ parameterSize: details?.parameter_size ?? null,
125
+ metadata: {
126
+ normalized_model_key: normalizeModelKey(name, rawDigest),
127
+ ...(details?.format ? { format: details.format } : {}),
128
+ ...(details?.families?.length ? { families: details.families } : {}),
129
+ },
130
+ });
131
+ })
132
+ .filter((item) => Boolean(item));
133
+ return {
134
+ ok: true,
135
+ runtime: (0, providers_1.buildDetectedRuntime)({
136
+ runtimeName: this.runtimeName,
137
+ runtimeType: this.runtimeType,
138
+ endpoint: this.endpoint,
139
+ status: 'detected',
140
+ lastSeenAt: now,
141
+ }),
142
+ models,
143
+ error: null,
144
+ };
145
+ }
146
+ catch (error) {
147
+ return {
148
+ ok: false,
149
+ runtime: (0, providers_1.buildDetectedRuntime)({
150
+ runtimeName: this.runtimeName,
151
+ runtimeType: this.runtimeType,
152
+ endpoint: this.endpoint,
153
+ status: 'error',
154
+ lastSeenAt: now,
155
+ error: error instanceof Error ? error.message : 'request_failed',
156
+ }),
157
+ models: [],
158
+ error: error instanceof Error ? error.message : 'request_failed',
159
+ };
160
+ }
161
+ }
162
+ }
163
+ exports.OllamaProvider = OllamaProvider;
164
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1,12 @@
1
+ import { type RuntimeProvider, type RuntimeProviderScanResult } from './providers';
2
+ export declare function getDefaultOpenAICompatibleEndpoints(raw?: string): string[];
3
+ export declare class OpenAICompatibleProvider implements RuntimeProvider {
4
+ readonly endpoint: string;
5
+ private readonly fetchImpl;
6
+ readonly runtimeName = "openai-compatible";
7
+ readonly runtimeType: "local-http";
8
+ constructor(endpoint?: string, fetchImpl?: typeof fetch);
9
+ scan(): Promise<RuntimeProviderScanResult>;
10
+ }
11
+ export declare function createDefaultOpenAICompatibleProviders(fetchImpl?: typeof fetch): OpenAICompatibleProvider[];
12
+ //# sourceMappingURL=openai-compatible.d.ts.map
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenAICompatibleProvider = void 0;
4
+ exports.getDefaultOpenAICompatibleEndpoints = getDefaultOpenAICompatibleEndpoints;
5
+ exports.createDefaultOpenAICompatibleProviders = createDefaultOpenAICompatibleProviders;
6
+ const discovery_1 = require("./discovery");
7
+ const providers_1 = require("./providers");
8
+ const DEFAULT_OPENAI_COMPATIBLE_ENDPOINT = 'http://localhost:8000';
9
+ function normalizeConfiguredEndpoint(endpoint) {
10
+ const trimmed = String(endpoint || '').trim().replace(/\/+$/, '');
11
+ if (!trimmed) {
12
+ return null;
13
+ }
14
+ try {
15
+ const url = new URL(trimmed);
16
+ return `${url.protocol}//${url.host}${url.pathname === '/' ? '' : url.pathname}`.replace(/\/+$/, '');
17
+ }
18
+ catch {
19
+ return trimmed;
20
+ }
21
+ }
22
+ function getDefaultOpenAICompatibleEndpoints(raw = process.env.FORKIT_OPENAI_COMPATIBLE_ENDPOINTS ?? DEFAULT_OPENAI_COMPATIBLE_ENDPOINT) {
23
+ const candidates = String(raw || '')
24
+ .split(/[,\n]/)
25
+ .map((entry) => normalizeConfiguredEndpoint(entry))
26
+ .filter((entry) => Boolean(entry));
27
+ const seen = new Set();
28
+ const endpoints = [];
29
+ for (const candidate of candidates) {
30
+ if (seen.has(candidate))
31
+ continue;
32
+ seen.add(candidate);
33
+ endpoints.push(candidate);
34
+ }
35
+ return endpoints.length > 0 ? endpoints : [DEFAULT_OPENAI_COMPATIBLE_ENDPOINT];
36
+ }
37
+ class OpenAICompatibleProvider {
38
+ endpoint;
39
+ fetchImpl;
40
+ runtimeName = 'openai-compatible';
41
+ runtimeType = 'local-http';
42
+ constructor(endpoint = DEFAULT_OPENAI_COMPATIBLE_ENDPOINT, fetchImpl = fetch) {
43
+ this.endpoint = endpoint;
44
+ this.fetchImpl = fetchImpl;
45
+ }
46
+ async scan() {
47
+ const modelsEndpoint = `${this.endpoint}/v1/models`;
48
+ const now = new Date().toISOString();
49
+ const endpointHashFragment = (0, discovery_1.buildEndpointHash)(this.endpoint).slice(0, 12);
50
+ try {
51
+ const response = await this.fetchImpl(modelsEndpoint, { method: 'GET' });
52
+ if (!response.ok) {
53
+ return {
54
+ ok: false,
55
+ runtime: (0, providers_1.buildDetectedRuntime)({
56
+ runtimeName: this.runtimeName,
57
+ runtimeType: this.runtimeType,
58
+ endpoint: this.endpoint,
59
+ status: 'error',
60
+ lastSeenAt: now,
61
+ error: `http_${response.status}`,
62
+ }),
63
+ models: [],
64
+ error: `http_${response.status}`,
65
+ };
66
+ }
67
+ const body = await response.json();
68
+ const models = (body.data ?? [])
69
+ .map((entry) => {
70
+ const modelId = String(entry.id ?? '').trim();
71
+ if (!modelId)
72
+ return null;
73
+ return (0, providers_1.normalizeDetectedModel)({
74
+ runtimeName: this.runtimeName,
75
+ runtimeType: this.runtimeType,
76
+ modelName: modelId,
77
+ modelId,
78
+ sourceEndpoint: this.endpoint,
79
+ detectedAt: now,
80
+ digest: `openai-compatible:${endpointHashFragment}:${modelId}`,
81
+ metadata: {
82
+ api_shape: 'openai-compatible',
83
+ object: typeof entry.object === 'string' ? entry.object : null,
84
+ owned_by: typeof entry.owned_by === 'string' ? entry.owned_by : null,
85
+ created: entry.created ?? null,
86
+ },
87
+ });
88
+ })
89
+ .filter((item) => Boolean(item));
90
+ return {
91
+ ok: true,
92
+ runtime: (0, providers_1.buildDetectedRuntime)({
93
+ runtimeName: this.runtimeName,
94
+ runtimeType: this.runtimeType,
95
+ endpoint: this.endpoint,
96
+ status: 'detected',
97
+ lastSeenAt: now,
98
+ }),
99
+ models,
100
+ error: null,
101
+ };
102
+ }
103
+ catch (error) {
104
+ return {
105
+ ok: false,
106
+ runtime: (0, providers_1.buildDetectedRuntime)({
107
+ runtimeName: this.runtimeName,
108
+ runtimeType: this.runtimeType,
109
+ endpoint: this.endpoint,
110
+ status: 'error',
111
+ lastSeenAt: now,
112
+ error: error instanceof Error ? error.message : 'request_failed',
113
+ }),
114
+ models: [],
115
+ error: error instanceof Error ? error.message : 'request_failed',
116
+ };
117
+ }
118
+ }
119
+ }
120
+ exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
121
+ function createDefaultOpenAICompatibleProviders(fetchImpl = fetch) {
122
+ return getDefaultOpenAICompatibleEndpoints().map((endpoint) => new OpenAICompatibleProvider(endpoint, fetchImpl));
123
+ }
124
+ //# sourceMappingURL=openai-compatible.js.map
@@ -0,0 +1,50 @@
1
+ import type { AgentType, RuntimePassportConfidence, SanitizedProcessMetadata } from './types';
2
+ export interface ProcessListEntry {
3
+ pid: number;
4
+ ppid?: number;
5
+ name?: string;
6
+ cmd?: string;
7
+ }
8
+ type ProcessDetectionMode = 'signature' | 'heuristic';
9
+ export interface ProcessScoutSignature {
10
+ signature: string;
11
+ knownProvider: string | null;
12
+ providerHints?: string[];
13
+ expectedPorts?: number[];
14
+ aliases?: string[];
15
+ confidence?: RuntimePassportConfidence;
16
+ sourceLabel?: string;
17
+ match(processName: string, command: string): boolean;
18
+ }
19
+ export interface AgentProcessMetadata {
20
+ process_name: string;
21
+ executable_name: string;
22
+ signature: string;
23
+ matched_terms: string[];
24
+ command_hash: string | null;
25
+ path_hash: string | null;
26
+ agent_name: string;
27
+ agent_type: AgentType;
28
+ confidence?: RuntimePassportConfidence;
29
+ detection_mode?: ProcessDetectionMode;
30
+ source_label?: string;
31
+ reason?: string | null;
32
+ }
33
+ export interface AgentProcessSignature {
34
+ signature: string;
35
+ agentType: AgentType;
36
+ agentName: string;
37
+ aliases?: string[];
38
+ confidence?: RuntimePassportConfidence;
39
+ sourceLabel?: string;
40
+ match(processName: string, command: string): boolean;
41
+ }
42
+ export declare const AI_PROCESS_SIGNATURES: ProcessScoutSignature[];
43
+ export declare const AGENT_PROCESS_SIGNATURES: AgentProcessSignature[];
44
+ export declare function classifyProcessEntry(entry: ProcessListEntry): SanitizedProcessMetadata | null;
45
+ export declare function matchesRuntimeObservation(process: Pick<SanitizedProcessMetadata, 'known_provider' | 'signature' | 'provider_hints' | 'expected_ports'>, runtimeName: string, runtimeEndpoint: string): boolean;
46
+ export declare function classifyAgentProcessEntry(entry: ProcessListEntry): AgentProcessMetadata | null;
47
+ export declare function scanLikelyAiProcesses(listFn?: () => Promise<ProcessListEntry[]>): Promise<SanitizedProcessMetadata[]>;
48
+ export declare function scanLikelyAgentProcesses(listFn?: () => Promise<ProcessListEntry[]>): Promise<AgentProcessMetadata[]>;
49
+ export {};
50
+ //# sourceMappingURL=process-scout.d.ts.map