ollanet 0.6.3 → 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/bench.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ollanet bench — speed + lightweight quality suite against Ollama models.
3
3
  */
4
- import { defaultModelForHost, loadConfig, machineSettingsForHost, mergeSettings, settingsFromEnv, } from "./config.js";
4
+ import { defaultModelForHost, loadConfig, lookupAlias, machineSettingsForHost, mergeSettings, settingsFromEnv, } from "./config.js";
5
5
  import { comparabilityKey, getSuiteCases, LONG_THROUGHPUT_NUM_PREDICT, median, suiteRevision, } from "./bench-suite.js";
6
6
  import { benchmarksDir, newBenchId, saveBenchmark } from "./bench-store.js";
7
7
  import { readFile } from "node:fs/promises";
@@ -542,7 +542,16 @@ function pad(s, n) {
542
542
  export async function main() {
543
543
  const parsed = parseArgs(process.argv.slice(2));
544
544
  const config = await loadConfig();
545
- const host = await resolveTarget(parsed.machine, config);
545
+ const alias = lookupAlias(config, parsed.machine);
546
+ let machineQuery = parsed.machine;
547
+ let models = [...parsed.models];
548
+ if (alias) {
549
+ machineQuery = alias.machine;
550
+ if (models.length === 0 && !parsed.all) {
551
+ models = [alias.model];
552
+ }
553
+ }
554
+ const host = await resolveTarget(machineQuery, config);
546
555
  const baseUrl = ollamaBaseUrl(host);
547
556
  const machineLabel = shortName(host);
548
557
  const tags = await ollamaTags(baseUrl, Math.min(BENCH_TIMEOUT_MS, 15_000));
@@ -569,8 +578,8 @@ export async function main() {
569
578
  selected.push(t.name);
570
579
  }
571
580
  }
572
- else if (parsed.models.length > 0) {
573
- for (const q of parsed.models) {
581
+ else if (models.length > 0) {
582
+ for (const q of models) {
574
583
  const resolved = resolveModelName(tags, q);
575
584
  if (!resolved) {
576
585
  console.error(`Unknown model "${q}". Available: ${tagNames.join(", ")}`);
@@ -587,7 +596,7 @@ export async function main() {
587
596
  else {
588
597
  const def = defaultModelForHost(config, host);
589
598
  if (!def) {
590
- console.error(`No model specified for "${machineLabel}". Pass model names, use --all, or set defaultModels.`);
599
+ console.error(`No model specified for "${machineLabel}". Pass model names, use --all, set defaultModels, or use an alias.`);
591
600
  process.exit(1);
592
601
  }
593
602
  const name = resolveModelName(tags, def);
package/dist/cli.d.ts CHANGED
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * ollanet — chat with Ollama servers on any reachable network.
3
+ * ollanet — Ollama over any reachable network (CLI, MCP, library).
4
4
  *
5
5
  * ollanet scan
6
6
  * ollanet prompt <machine-or-ip> "hello"
7
+ * ollanet compare <machine> <model> <model>
7
8
  * ollanet pull <machine> <model>
8
9
  * ollanet show <machine> <model>
9
10
  * ollanet rm <machine> <model> --yes
10
11
  * ollanet ps [machine]
12
+ * ollanet bench <machine> [model...]
11
13
  * ollanet chats
14
+ * ollanet mcp
12
15
  */
13
16
  export {};
package/dist/cli.js CHANGED
@@ -1,19 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * ollanet — chat with Ollama servers on any reachable network.
3
+ * ollanet — Ollama over any reachable network (CLI, MCP, library).
4
4
  *
5
5
  * ollanet scan
6
6
  * ollanet prompt <machine-or-ip> "hello"
7
+ * ollanet compare <machine> <model> <model>
7
8
  * ollanet pull <machine> <model>
8
9
  * ollanet show <machine> <model>
9
10
  * ollanet rm <machine> <model> --yes
10
11
  * ollanet ps [machine]
12
+ * ollanet bench <machine> [model...]
11
13
  * ollanet chats
14
+ * ollanet mcp
12
15
  */
13
16
  const HELP = `ollanet — Ollama over your network
14
17
 
15
- Discover Ollama hosts on localhost, your LAN, Tailscale, or any IP/hostname
16
- you can reach — then chat with hash-addressed transcripts.
18
+ Discover hosts, manage models, prompt and compare, bench tok/s, and continue
19
+ chats by hash. CLI, MCP, and a Node library — same mesh.
17
20
 
18
21
  Usage:
19
22
  ollanet scan [--json] [--all] [--lan] [--last]
@@ -27,6 +30,7 @@ Usage:
27
30
  ollanet ps [machine]
28
31
  ollanet chats [--json] [--id <hash>]
29
32
  ollanet bench <machine|ip> [model...] [--all] [options]
33
+ ollanet alias list|add|rm …
30
34
  ollanet mcp
31
35
  ollanet help [command]
32
36
 
@@ -44,6 +48,8 @@ Examples:
44
48
  ollanet rm studio llama3.2:1b --yes
45
49
  ollanet ps studio
46
50
  ollanet chats
51
+ ollanet alias add desk studio gemma3:12b
52
+ ollanet prompt desk "hello" # expands machine + model
47
53
  ollanet bench localhost --all
48
54
  ollanet bench localhost llama3.2:1b --runs 3
49
55
  ollanet bench localhost gemma3:12b --hot --runs 5
@@ -53,6 +59,7 @@ Examples:
53
59
  Config: ~/.ollanet/config.json when installed, ./config.json in a checkout
54
60
  (override with OLLANET_CONFIG)
55
61
  Hosts: config.hosts, OLLANET_HOSTS, optional Tailscale + --lan
62
+ Aliases: config.aliases — ollanet alias add|list|rm
56
63
  Chats: ~/.ollanet/responses or ./responses (override with OLLANET_RESPONSES_DIR)
57
64
  Scan: ~/.ollanet/last-scan.json or ./last-scan.json (override with OLLANET_LAST_SCAN)
58
65
  `;
@@ -162,6 +169,12 @@ async function main() {
162
169
  await run();
163
170
  return;
164
171
  }
172
+ case "alias":
173
+ case "aliases": {
174
+ const { main: run } = await import("./alias.js");
175
+ await run();
176
+ return;
177
+ }
165
178
  default:
166
179
  console.error(`Unknown command: ${cmd}\n`);
167
180
  process.stderr.write(HELP);
package/dist/compare.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * ollanet compare studio gemma3:12b llama3.2:3b --prompt "Explain MagicDNS"
5
5
  * ollanet compare studio m1 m2 --file task.md
6
6
  */
7
- import { configFromPartial, loadConfig, machineSettingsForHost, mergeSettings, settingsFromEnv, } from "./config.js";
7
+ import { configFromPartial, loadConfig, lookupAlias, machineSettingsForHost, mergeSettings, settingsFromEnv, } from "./config.js";
8
8
  import { envInt, ollamaBaseUrl, shortName } from "./hosts.js";
9
9
  import { consumeSettingsFlag, failUsage, isHelpFlag, printHelp, takeFlag, takeValue } from "./argv.js";
10
10
  import { resolveTarget } from "./target.js";
@@ -244,6 +244,14 @@ export async function main() {
244
244
  console.error("Machine is required.");
245
245
  usage();
246
246
  }
247
+ const config = await loadConfig();
248
+ const alias = lookupAlias(config, parsed.machine);
249
+ const machine = alias ? alias.machine : parsed.machine;
250
+ let models = [...parsed.models];
251
+ if (alias && models.length === 1) {
252
+ // `compare desk other:7b` → alias model vs other on alias host
253
+ models = [alias.model, models[0]];
254
+ }
247
255
  const { stdin: stdinStream } = await import("node:process");
248
256
  let fromStdin = "";
249
257
  if (!stdinStream.isTTY) {
@@ -265,14 +273,15 @@ export async function main() {
265
273
  }
266
274
  const prompt = assemblePrompt({ argv: parsed.prompt, file: fileText, stdin: fromStdin });
267
275
  const record = await runCompare({
268
- machine: parsed.machine,
269
- models: parsed.models,
276
+ machine,
277
+ models,
270
278
  prompt: prompt || undefined,
271
279
  settings: parsed.settings,
272
280
  save: parsed.save,
273
281
  unload: parsed.unload,
274
282
  writeStdout: !parsed.json,
275
283
  quiet: parsed.json,
284
+ config,
276
285
  });
277
286
  if (record.default_prompt) {
278
287
  process.stderr.write("Using default compare prompt (pass --prompt or --file to override).\n");
package/dist/config.d.ts CHANGED
@@ -17,6 +17,11 @@ export interface GenerateSettings {
17
17
  */
18
18
  think?: boolean;
19
19
  }
20
+ /** Named shortcut for a frequent machine + model pair. */
21
+ export interface ModelAlias {
22
+ machine: string;
23
+ model: string;
24
+ }
20
25
  export interface AppConfig {
21
26
  /** Explicit hosts/IPs to probe (LAN, VPN, MagicDNS, etc.). */
22
27
  hosts: HostConfigEntry[];
@@ -28,10 +33,28 @@ export interface AppConfig {
28
33
  machineDefaults: Record<string, GenerateSettings & {
29
34
  model?: string;
30
35
  }>;
36
+ /** Shortcuts: `ollanet prompt <alias> "…"` expands to machine + model. */
37
+ aliases: Record<string, ModelAlias>;
31
38
  }
32
39
  /** Build an AppConfig from an in-memory partial (no file I/O). */
33
40
  export declare function configFromPartial(partial?: Partial<AppConfig>): AppConfig;
34
41
  export declare function loadConfig(): Promise<AppConfig>;
42
+ /**
43
+ * Read-modify-write the config JSON on disk. Preserves unknown keys.
44
+ * Creates the parent directory when missing (installed `~/.ollanet/`).
45
+ */
46
+ export declare function mutateConfigFile(mutate: (file: Record<string, unknown>) => void): Promise<void>;
47
+ /** Alias names: letter start, then letters/digits/_/- (no colons — those look like models). */
48
+ export declare function isValidAliasName(name: string): boolean;
49
+ export declare function lookupAlias(config: AppConfig, name: string | undefined): ModelAlias | undefined;
50
+ /**
51
+ * If `machine` is an alias name, expand to that alias's host.
52
+ * When `model` is omitted, fill it from the alias too.
53
+ */
54
+ export declare function expandMachineModel(config: AppConfig, machine: string | undefined, model: string | undefined): {
55
+ machine?: string;
56
+ model?: string;
57
+ };
35
58
  export declare function normalizeSettings(input: unknown): GenerateSettings;
36
59
  export declare function parseFormat(value: unknown): GenerateSettings["format"] | undefined;
37
60
  export declare function hostLookupKeys(host: HostTarget): string[];
package/dist/config.js CHANGED
@@ -1,4 +1,5 @@
1
- import { readFile } from "node:fs/promises";
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import { shortName, } from "./hosts.js";
3
4
  import { defaultConfigPath } from "./paths.js";
4
5
  function emptyConfig() {
@@ -8,6 +9,7 @@ function emptyConfig() {
8
9
  defaultModels: {},
9
10
  defaults: {},
10
11
  machineDefaults: {},
12
+ aliases: {},
11
13
  };
12
14
  }
13
15
  /** Build an AppConfig from an in-memory partial (no file I/O). */
@@ -19,6 +21,7 @@ export function configFromPartial(partial = {}) {
19
21
  defaultModels: partial.defaultModels ?? empty.defaultModels,
20
22
  defaults: partial.defaults ?? empty.defaults,
21
23
  machineDefaults: partial.machineDefaults ?? empty.machineDefaults,
24
+ aliases: partial.aliases ?? empty.aliases,
22
25
  };
23
26
  }
24
27
  const CONFIG_PATH = process.env.OLLANET_CONFIG ??
@@ -42,6 +45,7 @@ export async function loadConfig() {
42
45
  defaultModels,
43
46
  defaults: normalizeSettings(parsed.defaults),
44
47
  machineDefaults,
48
+ aliases: normalizeAliases(parsed.aliases),
45
49
  };
46
50
  }
47
51
  catch (err) {
@@ -52,6 +56,29 @@ export async function loadConfig() {
52
56
  throw new Error(`Failed to read config at ${CONFIG_PATH}: ${err instanceof Error ? err.message : err}`);
53
57
  }
54
58
  }
59
+ /**
60
+ * Read-modify-write the config JSON on disk. Preserves unknown keys.
61
+ * Creates the parent directory when missing (installed `~/.ollanet/`).
62
+ */
63
+ export async function mutateConfigFile(mutate) {
64
+ let file = {};
65
+ try {
66
+ const raw = await readFile(CONFIG_PATH, "utf8");
67
+ const parsed = JSON.parse(raw);
68
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
69
+ file = parsed;
70
+ }
71
+ }
72
+ catch (err) {
73
+ const code = err.code;
74
+ if (code !== "ENOENT") {
75
+ throw new Error(`Failed to read config at ${CONFIG_PATH}: ${err instanceof Error ? err.message : err}`);
76
+ }
77
+ }
78
+ mutate(file);
79
+ await mkdir(path.dirname(CONFIG_PATH), { recursive: true });
80
+ await writeFile(CONFIG_PATH, `${JSON.stringify(file, null, 2)}\n`, "utf8");
81
+ }
55
82
  function normalizeDiscovery(input) {
56
83
  if (!input || typeof input !== "object")
57
84
  return {};
@@ -77,6 +104,51 @@ function normalizeStringMap(map) {
77
104
  }
78
105
  return out;
79
106
  }
107
+ function normalizeAliases(map) {
108
+ if (!map || typeof map !== "object" || Array.isArray(map))
109
+ return {};
110
+ const out = {};
111
+ for (const [key, value] of Object.entries(map)) {
112
+ const name = key.trim().toLowerCase();
113
+ if (!name || !value || typeof value !== "object" || Array.isArray(value))
114
+ continue;
115
+ const row = value;
116
+ const machine = typeof row.machine === "string" ? row.machine.trim() : "";
117
+ const model = typeof row.model === "string" ? row.model.trim() : "";
118
+ if (!machine || !model)
119
+ continue;
120
+ out[name] = { machine, model };
121
+ }
122
+ return out;
123
+ }
124
+ /** Alias names: letter start, then letters/digits/_/- (no colons — those look like models). */
125
+ export function isValidAliasName(name) {
126
+ return /^[a-z][a-z0-9_-]*$/i.test(name.trim());
127
+ }
128
+ export function lookupAlias(config, name) {
129
+ if (!name?.trim())
130
+ return undefined;
131
+ return config.aliases[name.trim().toLowerCase()];
132
+ }
133
+ /**
134
+ * If `machine` is an alias name, expand to that alias's host.
135
+ * When `model` is omitted, fill it from the alias too.
136
+ */
137
+ export function expandMachineModel(config, machine, model) {
138
+ if (!machine?.trim())
139
+ return { machine, model };
140
+ const alias = lookupAlias(config, machine);
141
+ if (!alias) {
142
+ return {
143
+ machine: machine.trim(),
144
+ model: model?.trim() ? model.trim() : undefined,
145
+ };
146
+ }
147
+ return {
148
+ machine: alias.machine,
149
+ model: model?.trim() ? model.trim() : alias.model,
150
+ };
151
+ }
80
152
  function normalizeMachineDefaults(map) {
81
153
  const out = {};
82
154
  for (const [key, value] of Object.entries(map ?? {})) {
package/dist/help.js CHANGED
@@ -11,6 +11,7 @@ const LOADERS = {
11
11
  ps: () => import("./ps.js"),
12
12
  compare: () => import("./compare.js"),
13
13
  bench: () => import("./bench.js"),
14
+ alias: () => import("./alias.js"),
14
15
  mcp: () => import("./mcp.js"),
15
16
  };
16
17
  const ALIASES = {
@@ -26,6 +27,7 @@ const ALIASES = {
26
27
  vs: "compare",
27
28
  h2h: "compare",
28
29
  benchmark: "bench",
30
+ aliases: "alias",
29
31
  };
30
32
  export function canonicalCommand(name) {
31
33
  const key = name.trim().toLowerCase();
package/dist/index.d.ts CHANGED
@@ -13,8 +13,8 @@ export { lastScan, lastScanPath, loadLastScan } from "./scan-store.js";
13
13
  export type { StoredScan } from "./scan-store.js";
14
14
  export { discoverHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
15
15
  export type { DiscoverOptions, DiscoveryResult, HostTarget, HostSource, HostConfigEntry, } from "./hosts.js";
16
- export { loadConfig, defaultModelForHost, mergeSettings, configFromPartial, } from "./config.js";
17
- export type { AppConfig, DiscoveryConfig, GenerateSettings } from "./config.js";
16
+ export { loadConfig, defaultModelForHost, mergeSettings, configFromPartial, lookupAlias, expandMachineModel, } from "./config.js";
17
+ export type { AppConfig, DiscoveryConfig, GenerateSettings, ModelAlias } from "./config.js";
18
18
  export { runPrompt } from "./prompt.js";
19
19
  export type { PromptRunOptions, PromptRunResult } from "./prompt.js";
20
20
  export { runCompare, DEFAULT_COMPARE_PROMPT } from "./compare.js";
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@
10
10
  export { scanNetwork } from "./scan.js";
11
11
  export { lastScan, lastScanPath, loadLastScan } from "./scan-store.js";
12
12
  export { discoverHosts, resolveHost, ollamaBaseUrl, shortName, ollamaPort, } from "./hosts.js";
13
- export { loadConfig, defaultModelForHost, mergeSettings, configFromPartial, } from "./config.js";
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";
16
16
  export { assemblePrompt, readPromptFile } from "./prompt-input.js";
package/dist/mcp.d.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * ollanet mcp — stdio MCP server (zero deps).
3
3
  *
4
4
  * Speaks the Model Context Protocol over stdin/stdout so agents (Cursor,
5
- * Claude Desktop, etc.) can discover hosts, prompt models, and continue chats.
5
+ * Claude Desktop, etc.) can discover hosts, manage models, prompt, compare,
6
+ * and continue chats.
6
7
  *
7
8
  * ollanet mcp
8
9
  *
package/dist/mcp.js CHANGED
@@ -2,7 +2,8 @@
2
2
  * ollanet mcp — stdio MCP server (zero deps).
3
3
  *
4
4
  * Speaks the Model Context Protocol over stdin/stdout so agents (Cursor,
5
- * Claude Desktop, etc.) can discover hosts, prompt models, and continue chats.
5
+ * Claude Desktop, etc.) can discover hosts, manage models, prompt, compare,
6
+ * and continue chats.
6
7
  *
7
8
  * ollanet mcp
8
9
  *
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.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,10 +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
27
  scan lists models on disk. ps lists what is loaded and the CPU/GPU split
27
- (same rule as ollama ps: size_vram / size).
28
+ (same rule as ollama ps: size_vram / size). An alias name resolves to its machine.
28
29
 
29
30
  Options:
30
31
  --machine <name> One host (default: every discovered host)
@@ -173,7 +174,11 @@ function printPs(result) {
173
174
  }
174
175
  export async function main() {
175
176
  const parsed = parseArgs(process.argv.slice(2));
176
- 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 });
177
182
  if (parsed.json) {
178
183
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
179
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;