ollanet 0.6.7 → 0.6.9
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/dist/config.js +2 -0
- package/dist/hosts.d.ts +11 -0
- package/dist/hosts.js +98 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/scan.d.ts +2 -0
- package/dist/scan.js +3 -1
- package/package.json +1 -1
package/dist/config.js
CHANGED
package/dist/hosts.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface HostTarget {
|
|
|
23
23
|
hostname: string;
|
|
24
24
|
dnsName: string;
|
|
25
25
|
ip: string;
|
|
26
|
+
/**
|
|
27
|
+
* Other IPs that reach this same instance. Used when loopback and Tailscale
|
|
28
|
+
* Self (or a LAN NIC) are the same machine — we probe once and keep both
|
|
29
|
+
* addresses for resolve / display.
|
|
30
|
+
*/
|
|
31
|
+
also?: string[];
|
|
26
32
|
online: boolean;
|
|
27
33
|
os: string;
|
|
28
34
|
isSelf: boolean;
|
|
@@ -44,6 +50,11 @@ export interface DiscoverOptions {
|
|
|
44
50
|
}
|
|
45
51
|
export declare function shortName(host: HostTarget): string;
|
|
46
52
|
export declare function ollamaBaseUrl(host: HostTarget, port?: number): string;
|
|
53
|
+
/**
|
|
54
|
+
* Collapse loopback, Tailscale Self, and this machine's NIC IPs into one host
|
|
55
|
+
* per port so scan does not list the same Ollama twice.
|
|
56
|
+
*/
|
|
57
|
+
export declare function foldLocalHosts(hosts: HostTarget[]): HostTarget[];
|
|
47
58
|
/** Discover candidate Ollama hosts from localhost, config, env, Tailscale, and optional LAN scan. */
|
|
48
59
|
export declare function discoverHosts(opts?: DiscoverOptions): Promise<DiscoveryResult>;
|
|
49
60
|
/**
|
package/dist/hosts.js
CHANGED
|
@@ -37,10 +37,12 @@ export function ollamaBaseUrl(host, port = host.port || ollamaPort()) {
|
|
|
37
37
|
return `http://${hostPart}:${port}`;
|
|
38
38
|
}
|
|
39
39
|
function makeHost(partial) {
|
|
40
|
+
const also = [...new Set((partial.also ?? []).filter((ip) => ip && ip !== partial.ip))];
|
|
40
41
|
return {
|
|
41
42
|
hostname: partial.hostname,
|
|
42
43
|
dnsName: partial.dnsName ?? "",
|
|
43
44
|
ip: partial.ip,
|
|
45
|
+
...(also.length > 0 ? { also } : {}),
|
|
44
46
|
online: partial.online ?? true,
|
|
45
47
|
os: partial.os ?? "unknown",
|
|
46
48
|
isSelf: partial.isSelf ?? false,
|
|
@@ -71,6 +73,7 @@ function mergeHosts(hosts) {
|
|
|
71
73
|
os: existing.os !== "unknown" ? existing.os : host.os,
|
|
72
74
|
isSelf: existing.isSelf || host.isSelf,
|
|
73
75
|
source: existing.source === "direct" ? host.source : existing.source,
|
|
76
|
+
also: [...new Set([...(existing.also ?? []), ...(host.also ?? [])])].filter((ip) => ip !== existing.ip && ip !== host.ip),
|
|
74
77
|
});
|
|
75
78
|
}
|
|
76
79
|
return [...byKey.values()].sort((a, b) => {
|
|
@@ -79,6 +82,96 @@ function mergeHosts(hosts) {
|
|
|
79
82
|
return shortName(a).localeCompare(shortName(b));
|
|
80
83
|
});
|
|
81
84
|
}
|
|
85
|
+
function isIpv4Literal(value) {
|
|
86
|
+
return /^\d{1,3}(\.\d{1,3}){3}$/.test(value);
|
|
87
|
+
}
|
|
88
|
+
function localIdentityIps() {
|
|
89
|
+
const ips = new Set(["127.0.0.1", "::1"]);
|
|
90
|
+
for (const entries of Object.values(os.networkInterfaces())) {
|
|
91
|
+
for (const entry of entries ?? []) {
|
|
92
|
+
if (entry.family === "IPv4")
|
|
93
|
+
ips.add(entry.address);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return ips;
|
|
97
|
+
}
|
|
98
|
+
function isThisDevice(host, localIps) {
|
|
99
|
+
return host.isSelf || localIps.has(host.ip);
|
|
100
|
+
}
|
|
101
|
+
function nameQuality(host) {
|
|
102
|
+
const n = host.hostname;
|
|
103
|
+
if (!n || isIpv4Literal(n) || n.toLowerCase() === "localhost")
|
|
104
|
+
return 0;
|
|
105
|
+
if (host.source === "config" || host.source === "env")
|
|
106
|
+
return 3;
|
|
107
|
+
if (host.source === "tailscale")
|
|
108
|
+
return 2;
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
function dnsQuality(dns) {
|
|
112
|
+
if (!dns || dns.toLowerCase() === "localhost" || isIpv4Literal(dns))
|
|
113
|
+
return 0;
|
|
114
|
+
if (dns.includes("."))
|
|
115
|
+
return 2;
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
function pickFoldSource(group, probeIsLoopback) {
|
|
119
|
+
const sources = new Set(group.map((h) => h.source));
|
|
120
|
+
if (sources.has("config"))
|
|
121
|
+
return "config";
|
|
122
|
+
if (sources.has("env"))
|
|
123
|
+
return "env";
|
|
124
|
+
if (sources.has("localhost") && probeIsLoopback)
|
|
125
|
+
return "localhost";
|
|
126
|
+
if (sources.has("tailscale"))
|
|
127
|
+
return "tailscale";
|
|
128
|
+
return group[0].source;
|
|
129
|
+
}
|
|
130
|
+
function mergeThisDevice(group) {
|
|
131
|
+
const ips = [...new Set(group.flatMap((h) => [h.ip, ...(h.also ?? [])]))];
|
|
132
|
+
const loopback = ips.find((ip) => ip === "127.0.0.1" || ip === "::1");
|
|
133
|
+
const ip = loopback ?? ips[0];
|
|
134
|
+
const named = [...group].sort((a, b) => nameQuality(b) - nameQuality(a))[0];
|
|
135
|
+
const dnsHost = [...group].sort((a, b) => dnsQuality(b.dnsName) - dnsQuality(a.dnsName))[0];
|
|
136
|
+
return makeHost({
|
|
137
|
+
hostname: named.hostname,
|
|
138
|
+
dnsName: dnsQuality(dnsHost.dnsName) > 0 ? dnsHost.dnsName : named.dnsName,
|
|
139
|
+
ip,
|
|
140
|
+
also: ips.filter((addr) => addr !== ip),
|
|
141
|
+
online: group.some((h) => h.online),
|
|
142
|
+
os: group.find((h) => h.os !== "unknown")?.os ?? named.os,
|
|
143
|
+
isSelf: true,
|
|
144
|
+
source: pickFoldSource(group, Boolean(loopback)),
|
|
145
|
+
port: group[0].port,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Collapse loopback, Tailscale Self, and this machine's NIC IPs into one host
|
|
150
|
+
* per port so scan does not list the same Ollama twice.
|
|
151
|
+
*/
|
|
152
|
+
export function foldLocalHosts(hosts) {
|
|
153
|
+
const localIps = localIdentityIps();
|
|
154
|
+
const groups = new Map();
|
|
155
|
+
const rest = [];
|
|
156
|
+
for (const host of hosts) {
|
|
157
|
+
if (!isThisDevice(host, localIps)) {
|
|
158
|
+
rest.push(host);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const list = groups.get(host.port) ?? [];
|
|
162
|
+
list.push(host);
|
|
163
|
+
groups.set(host.port, list);
|
|
164
|
+
}
|
|
165
|
+
const folded = [];
|
|
166
|
+
for (const group of groups.values()) {
|
|
167
|
+
folded.push(group.length === 1 ? { ...group[0], isSelf: true } : mergeThisDevice(group));
|
|
168
|
+
}
|
|
169
|
+
return [...folded, ...rest].sort((a, b) => {
|
|
170
|
+
if (a.isSelf !== b.isSelf)
|
|
171
|
+
return a.isSelf ? -1 : 1;
|
|
172
|
+
return shortName(a).localeCompare(shortName(b));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
82
175
|
function localhostTargets() {
|
|
83
176
|
const hostname = os.hostname() || "localhost";
|
|
84
177
|
return [
|
|
@@ -378,7 +471,7 @@ export async function discoverHosts(opts = {}) {
|
|
|
378
471
|
sources.push("lan");
|
|
379
472
|
}
|
|
380
473
|
}
|
|
381
|
-
const hosts = mergeHosts(collected);
|
|
474
|
+
const hosts = foldLocalHosts(mergeHosts(collected));
|
|
382
475
|
const networkLabel = labels[0] ??
|
|
383
476
|
(sources.includes("tailscale")
|
|
384
477
|
? "tailscale"
|
|
@@ -388,7 +481,10 @@ export async function discoverHosts(opts = {}) {
|
|
|
388
481
|
return { hosts, sources, networkLabel };
|
|
389
482
|
}
|
|
390
483
|
function hostNameMatches(host, q) {
|
|
391
|
-
const names = [host.hostname, host.dnsName, shortName(host), host.ip].map((n) => n.toLowerCase());
|
|
484
|
+
const names = [host.hostname, host.dnsName, shortName(host), host.ip, ...(host.also ?? [])].map((n) => n.toLowerCase());
|
|
485
|
+
if (host.isSelf || host.ip === "127.0.0.1" || (host.also ?? []).includes("127.0.0.1")) {
|
|
486
|
+
names.push("localhost");
|
|
487
|
+
}
|
|
392
488
|
return names.includes(q) || names.some((n) => n.startsWith(`${q}.`));
|
|
393
489
|
}
|
|
394
490
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { scanNetwork } from "./scan.js";
|
|
|
11
11
|
export type { ScanOptions, ScanPayload, ScannedServer, ScanFailure } from "./scan.js";
|
|
12
12
|
export { lastScan, lastScanPath, loadLastScan } from "./scan-store.js";
|
|
13
13
|
export type { StoredScan } from "./scan-store.js";
|
|
14
|
-
export { discoverHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
|
|
14
|
+
export { discoverHosts, foldLocalHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
|
|
15
15
|
export type { DiscoverOptions, DiscoveryResult, HostTarget, HostSource, HostConfigEntry, } from "./hosts.js";
|
|
16
16
|
export { loadConfig, defaultModelForHost, mergeSettings, configFromPartial, lookupAlias, expandMachineModel, } from "./config.js";
|
|
17
17
|
export type { AppConfig, DiscoveryConfig, GenerateSettings, ModelAlias } from "./config.js";
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { scanNetwork } from "./scan.js";
|
|
11
11
|
export { lastScan, lastScanPath, loadLastScan } from "./scan-store.js";
|
|
12
|
-
export { discoverHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
|
|
12
|
+
export { discoverHosts, foldLocalHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
|
|
13
13
|
export { loadConfig, defaultModelForHost, mergeSettings, configFromPartial, lookupAlias, expandMachineModel, } from "./config.js";
|
|
14
14
|
export { runPrompt } from "./prompt.js";
|
|
15
15
|
export { runCompare, DEFAULT_COMPARE_PROMPT } from "./compare.js";
|
package/dist/scan.d.ts
CHANGED
package/dist/scan.js
CHANGED
|
@@ -105,8 +105,9 @@ function printPayload(payload, cached) {
|
|
|
105
105
|
for (const server of payload.servers) {
|
|
106
106
|
const label = server.dnsName || server.hostname;
|
|
107
107
|
const selfTag = server.self ? " [this device]" : "";
|
|
108
|
+
const also = server.also?.length ? ` also: ${server.also.join(", ")}` : "";
|
|
108
109
|
console.log(`${label}${selfTag}`);
|
|
109
|
-
console.log(` IP: ${server.ip} source: ${server.source} OS: ${server.os}`);
|
|
110
|
+
console.log(` IP: ${server.ip}${also} source: ${server.source} OS: ${server.os}`);
|
|
110
111
|
console.log(` Endpoint: ${server.endpoint}`);
|
|
111
112
|
if (server.models.length === 0) {
|
|
112
113
|
console.log(" Models: (none)");
|
|
@@ -138,6 +139,7 @@ function toPayload(results, networkLabel, sources) {
|
|
|
138
139
|
hostname: r.host.hostname,
|
|
139
140
|
dnsName: r.host.dnsName,
|
|
140
141
|
ip: r.host.ip,
|
|
142
|
+
...(r.host.also?.length ? { also: r.host.also } : {}),
|
|
141
143
|
port: r.host.port,
|
|
142
144
|
os: r.host.os,
|
|
143
145
|
source: r.host.source,
|