ollanet 0.6.2 → 0.6.4

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/prompt.js CHANGED
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { stdin as stdinStream } from "node:process";
15
15
  import { appendMessage, cleanTopic, createChat, loadChat, saveChat, toApiMessages, topicFromPrompt, } from "./chat-store.js";
16
- import { configPath, defaultModelForHost, loadConfig, machineSettingsForHost, mergeSettings, parseFormat, settingsFromEnv, settingsSummary, configFromPartial, } from "./config.js";
16
+ import { configPath, defaultModelForHost, loadConfig, lookupAlias, machineSettingsForHost, mergeSettings, parseFormat, settingsFromEnv, settingsSummary, configFromPartial, } from "./config.js";
17
17
  import { envInt, findDiscoveredHost, ollamaBaseUrl, resolveHost, shortName, } from "./hosts.js";
18
18
  import { ollamaChat } from "./ollama-chat.js";
19
19
  import { assemblePrompt, readPromptFile } from "./prompt-input.js";
@@ -31,14 +31,20 @@ export function helpText() {
31
31
 
32
32
  Examples:
33
33
  ollanet prompt localhost "Explain MagicDNS"
34
+ ollanet prompt desk "hello" # alias → machine + model
34
35
  ollanet prompt --chat a1b2c3d4e5f6 "Give an example"
35
36
  ollanet prompt localhost --temperature 0.2 --num-predict 64 "2+2?"
36
37
  ollanet prompt localhost --file ./notes.md
37
38
  ollanet chats
39
+ ollanet alias add desk studio gemma3:12b
38
40
 
39
41
  Each reply is saved under responses/<hash>.json and the hash is printed so you
40
42
  can continue later with --chat. Use --no-save to skip persistence.
41
43
 
44
+ The first token may be an alias from config (\`ollanet alias\`) instead of a
45
+ machine name — that fills both host and model unless you pass --model / a
46
+ positional model.
47
+
42
48
  Config: ${configPath()}
43
49
  Precedence: CLI > env > machineDefaults > defaults
44
50
 
@@ -298,6 +304,9 @@ export async function runPrompt(opts) {
298
304
  if (!machineQuery) {
299
305
  throw new Error("Machine is required for a new chat (or pass chatId).");
300
306
  }
307
+ const alias = lookupAlias(config, machineQuery);
308
+ if (alias)
309
+ machineQuery = alias.machine;
301
310
  const host = await resolveTarget(machineQuery, config);
302
311
  let peeledModel;
303
312
  if (!opts.chatId && !opts.model) {
@@ -309,7 +318,11 @@ export async function runPrompt(opts) {
309
318
  if (!promptText) {
310
319
  throw new Error("No prompt provided.");
311
320
  }
312
- const model = opts.model ?? peeledModel ?? chat?.model ?? defaultModelForHost(config, host);
321
+ const model = opts.model ??
322
+ peeledModel ??
323
+ alias?.model ??
324
+ chat?.model ??
325
+ defaultModelForHost(config, host);
313
326
  if (!model) {
314
327
  throw new Error(`No model specified for "${shortName(host)}" and no default in ${configPath()}.\n` +
315
328
  `Pass a model or add it under defaultModels.`);
@@ -414,6 +427,9 @@ export async function main() {
414
427
  const config = await loadConfig();
415
428
  const targets = await listTargets(config);
416
429
  let machineQuery = parsed.machine;
430
+ const alias = machineQuery ? lookupAlias(config, machineQuery) : undefined;
431
+ if (alias)
432
+ machineQuery = alias.machine;
417
433
  if (parsed.chatId) {
418
434
  // Allow `ollanet prompt <host> --chat HASH "follow-up"` only when the
419
435
  // leading token matches an already-discovered host (not direct-address fallback).
@@ -447,7 +463,9 @@ export async function main() {
447
463
  }
448
464
  try {
449
465
  const result = await runPrompt({
450
- machine: machineQuery,
466
+ // Pass the original alias name when present so runPrompt can apply alias.model
467
+ // after peel; otherwise pass the resolved machine.
468
+ machine: alias ? parsed.machine : machineQuery,
451
469
  model: parsed.model ?? peeledModel,
452
470
  prompt: promptText,
453
471
  chatId: parsed.chatId,
@@ -456,6 +474,7 @@ export async function main() {
456
474
  writeStdout: !json,
457
475
  stream: json ? false : stream,
458
476
  quiet: json,
477
+ config,
459
478
  });
460
479
  if (json) {
461
480
  console.log(JSON.stringify({
package/dist/ps.d.ts CHANGED
@@ -8,7 +8,12 @@ import { type AppConfig } from "./config.js";
8
8
  export declare function helpText(): string;
9
9
  export interface LoadedModel {
10
10
  name: string;
11
+ size?: number;
11
12
  size_vram?: number;
13
+ cpu_percent?: number;
14
+ gpu_percent?: number;
15
+ /** Same wording as `ollama ps` PROCESSOR (e.g. "100% GPU", "83%/17% CPU/GPU"). */
16
+ processor?: string;
12
17
  context_length?: number;
13
18
  digest?: string;
14
19
  tuned: boolean;
@@ -28,5 +33,11 @@ export interface PsOptions {
28
33
  export interface PsResult {
29
34
  hosts: LoadedHost[];
30
35
  }
36
+ /** Match `ollama ps` PROCESSOR: CPU% from (size - size_vram) / size. */
37
+ export declare function processorSplit(size?: number, sizeVram?: number): {
38
+ cpu_percent?: number;
39
+ gpu_percent?: number;
40
+ processor?: string;
41
+ };
31
42
  export declare function listLoaded(opts?: PsOptions): Promise<PsResult>;
32
43
  export declare function main(): Promise<void>;
package/dist/ps.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * ollanet ps
5
5
  * ollanet ps studio
6
6
  */
7
- import { configFromPartial, loadConfig } from "./config.js";
7
+ import { configFromPartial, expandMachineModel, loadConfig } from "./config.js";
8
8
  import { discoverHosts, envInt, ollamaBaseUrl, shortName, } from "./hosts.js";
9
9
  import { ollamaPs, ollamaPsRequired } from "./ollama-chat.js";
10
10
  import { failUsage, isHelpFlag, printHelp, takeFlag } from "./argv.js";
@@ -21,9 +21,11 @@ export function helpText() {
21
21
  Examples:
22
22
  ollanet ps
23
23
  ollanet ps studio
24
+ ollanet ps desk
24
25
  ollanet ps studio --json
25
26
 
26
- scan lists models on disk. ps lists what is loaded in VRAM right now.
27
+ scan lists models on disk. ps lists what is loaded and the CPU/GPU split
28
+ (same rule as ollama ps: size_vram / size). An alias name resolves to its machine.
27
29
 
28
30
  Options:
29
31
  --machine <name> One host (default: every discovered host)
@@ -76,11 +78,31 @@ function formatBytes(bytes) {
76
78
  }
77
79
  return `${value.toFixed(unit === 0 ? 0 : 1)} ${units[unit]}`;
78
80
  }
81
+ /** Match `ollama ps` PROCESSOR: CPU% from (size - size_vram) / size. */
82
+ export function processorSplit(size, sizeVram) {
83
+ const total = size ?? 0;
84
+ const vram = sizeVram ?? 0;
85
+ if (vram === 0 && total === 0)
86
+ return {};
87
+ if (vram === 0)
88
+ return { cpu_percent: 100, gpu_percent: 0, processor: "100% CPU" };
89
+ if (total > 0 && vram === total) {
90
+ return { cpu_percent: 0, gpu_percent: 100, processor: "100% GPU" };
91
+ }
92
+ if (vram > total || total === 0)
93
+ return { processor: "Unknown" };
94
+ const cpu = Math.round(((total - vram) / total) * 100);
95
+ const gpu = 100 - cpu;
96
+ return { cpu_percent: cpu, gpu_percent: gpu, processor: `${cpu}%/${gpu}% CPU/GPU` };
97
+ }
79
98
  function toLoaded(m) {
80
99
  const name = (m.name ?? m.model ?? "").trim();
100
+ const split = processorSplit(m.size, m.size_vram);
81
101
  return {
82
102
  name,
103
+ size: m.size,
83
104
  size_vram: m.size_vram,
105
+ ...split,
84
106
  context_length: m.context_length,
85
107
  digest: m.digest,
86
108
  tuned: looksTuned(name),
@@ -143,7 +165,7 @@ function printPs(result) {
143
165
  const vram = formatBytes(m.size_vram);
144
166
  const ctx = m.context_length != null ? `ctx ${m.context_length}` : "";
145
167
  const tag = m.tuned ? " [tuned]" : "";
146
- const meta = [vram ? `VRAM ${vram}` : "", ctx].filter(Boolean).join(" ");
168
+ const meta = [vram ? `VRAM ${vram}` : "", m.processor, ctx].filter(Boolean).join(" ");
147
169
  process.stdout.write(meta ? ` ${m.name} ${meta}${tag}\n` : ` ${m.name}${tag}\n`);
148
170
  }
149
171
  }
@@ -152,7 +174,11 @@ function printPs(result) {
152
174
  }
153
175
  export async function main() {
154
176
  const parsed = parseArgs(process.argv.slice(2));
155
- const result = await listLoaded({ machine: parsed.machine });
177
+ const config = await loadConfig();
178
+ const machine = parsed.machine
179
+ ? expandMachineModel(config, parsed.machine, undefined).machine
180
+ : undefined;
181
+ const result = await listLoaded({ machine, config });
156
182
  if (parsed.json) {
157
183
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
158
184
  return;
package/dist/pull.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * `studio` is the machine (discovered name, MagicDNS, hostname, or IP).
7
7
  * The *server* downloads from the registry; ollanet only sends POST /api/pull.
8
8
  */
9
+ import { expandMachineModel, loadConfig } from "./config.js";
9
10
  import { envInt, ollamaBaseUrl, shortName } from "./hosts.js";
10
11
  import { ollamaPull } from "./ollama-chat.js";
11
12
  import { failUsage, isHelpFlag, printHelp, takeFlag } from "./argv.js";
@@ -17,16 +18,18 @@ function pullTimeoutMs() {
17
18
  export function helpText() {
18
19
  return `Usage:
19
20
  ollanet pull <machine> <model>
21
+ ollanet pull <alias>
20
22
  ollanet pull --machine <name> --model <name>
21
23
 
22
24
  Examples:
23
25
  ollanet pull studio gemma3:12b
26
+ ollanet pull desk
24
27
  ollanet pull localhost llama3.2:1b
25
28
  ollanet pull 192.168.1.50 gemma3:12b --json
26
29
 
27
30
  The named machine downloads the model onto its own disk. ollanet does not
28
31
  upload weights. Re-pulling the same name updates it when the registry has a
29
- newer digest.
32
+ newer digest. A single alias name expands to that alias's machine + model.
30
33
 
31
34
  Options:
32
35
  --machine <name> Host (discovered name, MagicDNS, hostname, or IP[:port])
@@ -171,20 +174,23 @@ export async function pullModel(opts) {
171
174
  }
172
175
  export async function main() {
173
176
  const parsed = parseArgs(process.argv.slice(2));
174
- if (!parsed.machine || !parsed.model) {
175
- if (!parsed.machine)
177
+ const config = await loadConfig();
178
+ const expanded = expandMachineModel(config, parsed.machine, parsed.model);
179
+ if (!expanded.machine || !expanded.model) {
180
+ if (!expanded.machine)
176
181
  console.error("Machine is required.");
177
182
  else
178
183
  console.error("Model is required.");
179
184
  usage();
180
185
  }
181
186
  const result = await pullModel({
182
- machine: parsed.machine,
183
- model: parsed.model,
187
+ machine: expanded.machine,
188
+ model: expanded.model,
184
189
  insecure: parsed.insecure,
185
190
  stream: parsed.stream,
186
191
  writeStdout: true,
187
192
  quiet: false,
193
+ config,
188
194
  });
189
195
  if (parsed.json) {
190
196
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
package/dist/rm.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * ollanet rm studio llama3.2:1b --yes
5
5
  */
6
- import type { AppConfig } from "./config.js";
6
+ import { type AppConfig } from "./config.js";
7
7
  export declare function helpText(): string;
8
8
  export interface RemoveOptions {
9
9
  machine: string;
package/dist/rm.js CHANGED
@@ -8,20 +8,24 @@ import { envInt, ollamaBaseUrl, shortName } from "./hosts.js";
8
8
  import { ollamaDelete } from "./ollama-chat.js";
9
9
  import { failUsage, isHelpFlag, printHelp, takeFlag } from "./argv.js";
10
10
  import { resolveTarget } from "./target.js";
11
+ import { expandMachineModel, loadConfig } from "./config.js";
11
12
  function rmTimeoutMs() {
12
13
  return envInt("OLLAMA_RM_TIMEOUT_MS", 30_000);
13
14
  }
14
15
  export function helpText() {
15
16
  return `Usage:
16
17
  ollanet rm <machine> <model> --yes
18
+ ollanet rm <alias> --yes
17
19
  ollanet rm --machine <name> --model <name> --yes
18
20
 
19
21
  Examples:
20
22
  ollanet rm studio llama3.2:1b --yes
23
+ ollanet rm desk --yes
21
24
  ollanet rm localhost old-model:7b --yes --json
22
25
 
23
26
  Deletes the named model from that host's disk (POST /api/delete).
24
27
  Non-interactive use (pipes, MCP, CI) requires --yes / confirm: true.
28
+ A single alias name expands to that alias's machine + model.
25
29
 
26
30
  Options:
27
31
  --machine <name> Host (discovered name, MagicDNS, hostname, or IP[:port])
@@ -111,17 +115,20 @@ export async function removeModel(opts) {
111
115
  }
112
116
  export async function main() {
113
117
  const parsed = parseArgs(process.argv.slice(2));
114
- if (!parsed.machine || !parsed.model) {
115
- if (!parsed.machine)
118
+ const config = await loadConfig();
119
+ const expanded = expandMachineModel(config, parsed.machine, parsed.model);
120
+ if (!expanded.machine || !expanded.model) {
121
+ if (!expanded.machine)
116
122
  console.error("Machine is required.");
117
123
  else
118
124
  console.error("Model is required.");
119
125
  usage();
120
126
  }
121
127
  const result = await removeModel({
122
- machine: parsed.machine,
123
- model: parsed.model,
128
+ machine: expanded.machine,
129
+ model: expanded.model,
124
130
  yes: parsed.yes,
131
+ config,
125
132
  });
126
133
  if (parsed.json) {
127
134
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
package/dist/show.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * ollanet show studio gemma4-ctx32k
5
5
  */
6
6
  import { type OllamaShowInfo } from "./ollama-chat.js";
7
- import type { AppConfig } from "./config.js";
7
+ import { type AppConfig } from "./config.js";
8
8
  export declare function helpText(): string;
9
9
  export interface ShowOptions {
10
10
  machine: string;
package/dist/show.js CHANGED
@@ -8,20 +8,24 @@ import { ollamaShow } from "./ollama-chat.js";
8
8
  import { failUsage, isHelpFlag, printHelp, takeFlag } from "./argv.js";
9
9
  import { resolveTarget } from "./target.js";
10
10
  import { looksTuned } from "./tuned.js";
11
+ import { expandMachineModel, loadConfig } from "./config.js";
11
12
  function showTimeoutMs() {
12
13
  return envInt("OLLAMA_SHOW_TIMEOUT_MS", 30_000);
13
14
  }
14
15
  export function helpText() {
15
16
  return `Usage:
16
17
  ollanet show <machine> <model>
18
+ ollanet show <alias>
17
19
  ollanet show --machine <name> --model <name>
18
20
 
19
21
  Examples:
20
22
  ollanet show studio gemma4-ctx32k
23
+ ollanet show desk
21
24
  ollanet show localhost llama3.2:1b --json
22
25
 
23
26
  Reads /api/show on that host — Modelfile, parameters, capabilities.
24
27
  Tuned Finetuna-style names are marked [tuned].
28
+ A single alias name expands to that alias's machine + model.
25
29
 
26
30
  Options:
27
31
  --machine <name> Host (discovered name, MagicDNS, hostname, or IP[:port])
@@ -112,14 +116,20 @@ function printShow(result) {
112
116
  }
113
117
  export async function main() {
114
118
  const parsed = parseArgs(process.argv.slice(2));
115
- if (!parsed.machine || !parsed.model) {
116
- if (!parsed.machine)
119
+ const config = await loadConfig();
120
+ const expanded = expandMachineModel(config, parsed.machine, parsed.model);
121
+ if (!expanded.machine || !expanded.model) {
122
+ if (!expanded.machine)
117
123
  console.error("Machine is required.");
118
124
  else
119
125
  console.error("Model is required.");
120
126
  usage();
121
127
  }
122
- const result = await showModel({ machine: parsed.machine, model: parsed.model });
128
+ const result = await showModel({
129
+ machine: expanded.machine,
130
+ model: expanded.model,
131
+ config,
132
+ });
123
133
  if (parsed.json) {
124
134
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
125
135
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ollanet",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Discover and talk to Ollama on any reachable network — CLI, MCP, and a Node library",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,6 +36,7 @@
36
36
  "ps": "tsx src/cli.ts ps",
37
37
  "chats": "tsx src/cli.ts chats",
38
38
  "bench": "tsx src/cli.ts bench",
39
+ "alias": "tsx src/cli.ts alias",
39
40
  "mcp": "tsx src/cli.ts mcp",
40
41
  "start": "tsx src/cli.ts scan",
41
42
  "typecheck": "tsc --noEmit",