ai.matey.cli 0.2.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.
- package/LICENSE +21 -0
- package/dist/cjs/convert-request.js +365 -0
- package/dist/cjs/convert-request.js.map +1 -0
- package/dist/cjs/convert-response.js +211 -0
- package/dist/cjs/convert-response.js.map +1 -0
- package/dist/cjs/converters/request-converters.js +183 -0
- package/dist/cjs/converters/request-converters.js.map +1 -0
- package/dist/cjs/converters/response-converters.js +203 -0
- package/dist/cjs/converters/response-converters.js.map +1 -0
- package/dist/cjs/create-backend.js +569 -0
- package/dist/cjs/create-backend.js.map +1 -0
- package/dist/cjs/index.js +31 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/main.js +181 -0
- package/dist/cjs/main.js.map +1 -0
- package/dist/cjs/ollama/commands/list.js +70 -0
- package/dist/cjs/ollama/commands/list.js.map +1 -0
- package/dist/cjs/ollama/commands/ps.js +80 -0
- package/dist/cjs/ollama/commands/ps.js.map +1 -0
- package/dist/cjs/ollama/commands/pull.js +198 -0
- package/dist/cjs/ollama/commands/pull.js.map +1 -0
- package/dist/cjs/ollama/commands/run.js +279 -0
- package/dist/cjs/ollama/commands/run.js.map +1 -0
- package/dist/cjs/ollama/commands/show.js +138 -0
- package/dist/cjs/ollama/commands/show.js.map +1 -0
- package/dist/cjs/ollama/index.js +238 -0
- package/dist/cjs/ollama/index.js.map +1 -0
- package/dist/cjs/ollama/types.js +10 -0
- package/dist/cjs/ollama/types.js.map +1 -0
- package/dist/cjs/proxy.js +406 -0
- package/dist/cjs/proxy.js.map +1 -0
- package/dist/cjs/utils/backend-loader.js +112 -0
- package/dist/cjs/utils/backend-loader.js.map +1 -0
- package/dist/cjs/utils/index.js +29 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/model-translation.js +138 -0
- package/dist/cjs/utils/model-translation.js.map +1 -0
- package/dist/cjs/utils/output-formatter.js +241 -0
- package/dist/cjs/utils/output-formatter.js.map +1 -0
- package/dist/cjs/utils/pipeline-inspector.js +90 -0
- package/dist/cjs/utils/pipeline-inspector.js.map +1 -0
- package/dist/cjs/utils/state-manager.js +114 -0
- package/dist/cjs/utils/state-manager.js.map +1 -0
- package/dist/esm/convert-request.js +331 -0
- package/dist/esm/convert-request.js.map +1 -0
- package/dist/esm/convert-response.js +177 -0
- package/dist/esm/convert-response.js.map +1 -0
- package/dist/esm/converters/request-converters.js +175 -0
- package/dist/esm/converters/request-converters.js.map +1 -0
- package/dist/esm/converters/response-converters.js +191 -0
- package/dist/esm/converters/response-converters.js.map +1 -0
- package/dist/esm/create-backend.js +533 -0
- package/dist/esm/create-backend.js.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/main.js +149 -0
- package/dist/esm/main.js.map +1 -0
- package/dist/esm/ollama/commands/list.js +67 -0
- package/dist/esm/ollama/commands/list.js.map +1 -0
- package/dist/esm/ollama/commands/ps.js +77 -0
- package/dist/esm/ollama/commands/ps.js.map +1 -0
- package/dist/esm/ollama/commands/pull.js +195 -0
- package/dist/esm/ollama/commands/pull.js.map +1 -0
- package/dist/esm/ollama/commands/run.js +243 -0
- package/dist/esm/ollama/commands/run.js.map +1 -0
- package/dist/esm/ollama/commands/show.js +135 -0
- package/dist/esm/ollama/commands/show.js.map +1 -0
- package/dist/esm/ollama/index.js +235 -0
- package/dist/esm/ollama/index.js.map +1 -0
- package/dist/esm/ollama/types.js +9 -0
- package/dist/esm/ollama/types.js.map +1 -0
- package/dist/esm/proxy.js +403 -0
- package/dist/esm/proxy.js.map +1 -0
- package/dist/esm/utils/backend-loader.js +74 -0
- package/dist/esm/utils/backend-loader.js.map +1 -0
- package/dist/esm/utils/index.js +13 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/model-translation.js +99 -0
- package/dist/esm/utils/model-translation.js.map +1 -0
- package/dist/esm/utils/output-formatter.js +224 -0
- package/dist/esm/utils/output-formatter.js.map +1 -0
- package/dist/esm/utils/pipeline-inspector.js +84 -0
- package/dist/esm/utils/pipeline-inspector.js.map +1 -0
- package/dist/esm/utils/state-manager.js +111 -0
- package/dist/esm/utils/state-manager.js.map +1 -0
- package/dist/types/convert-request.d.ts +15 -0
- package/dist/types/convert-request.d.ts.map +1 -0
- package/dist/types/convert-response.d.ts +16 -0
- package/dist/types/convert-response.d.ts.map +1 -0
- package/dist/types/converters/request-converters.d.ts +139 -0
- package/dist/types/converters/request-converters.d.ts.map +1 -0
- package/dist/types/converters/response-converters.d.ts +134 -0
- package/dist/types/converters/response-converters.d.ts.map +1 -0
- package/dist/types/create-backend.d.ts +20 -0
- package/dist/types/create-backend.d.ts.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/main.d.ts +19 -0
- package/dist/types/main.d.ts.map +1 -0
- package/dist/types/ollama/commands/list.d.ts +32 -0
- package/dist/types/ollama/commands/list.d.ts.map +1 -0
- package/dist/types/ollama/commands/ps.d.ts +27 -0
- package/dist/types/ollama/commands/ps.d.ts.map +1 -0
- package/dist/types/ollama/commands/pull.d.ts +21 -0
- package/dist/types/ollama/commands/pull.d.ts.map +1 -0
- package/dist/types/ollama/commands/run.d.ts +48 -0
- package/dist/types/ollama/commands/run.d.ts.map +1 -0
- package/dist/types/ollama/commands/show.d.ts +36 -0
- package/dist/types/ollama/commands/show.d.ts.map +1 -0
- package/dist/types/ollama/index.d.ts +12 -0
- package/dist/types/ollama/index.d.ts.map +1 -0
- package/dist/types/ollama/types.d.ts +58 -0
- package/dist/types/ollama/types.d.ts.map +1 -0
- package/dist/types/proxy.d.ts +16 -0
- package/dist/types/proxy.d.ts.map +1 -0
- package/dist/types/utils/backend-loader.d.ts +55 -0
- package/dist/types/utils/backend-loader.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +13 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/model-translation.d.ts +64 -0
- package/dist/types/utils/model-translation.d.ts.map +1 -0
- package/dist/types/utils/output-formatter.d.ts +113 -0
- package/dist/types/utils/output-formatter.d.ts.map +1 -0
- package/dist/types/utils/pipeline-inspector.d.ts +50 -0
- package/dist/types/utils/pipeline-inspector.d.ts.map +1 -0
- package/dist/types/utils/state-manager.d.ts +91 -0
- package/dist/types/utils/state-manager.d.ts.map +1 -0
- package/package.json +75 -0
- package/readme.md +32 -0
package/dist/cjs/main.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* AI.Matey CLI - Main Entry Point
|
|
5
|
+
*
|
|
6
|
+
* Unified CLI with subcommands for various utilities.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ai-matey <command> [options]
|
|
10
|
+
*
|
|
11
|
+
* Commands:
|
|
12
|
+
* convert-response Convert IR responses to provider formats
|
|
13
|
+
* emulate-ollama Emulate Ollama CLI interface
|
|
14
|
+
* (future) emulate-openai, emulate-anthropic, etc.
|
|
15
|
+
*
|
|
16
|
+
* @module cli/main
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.main = main;
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Help Text
|
|
55
|
+
// ============================================================================
|
|
56
|
+
function showHelp() {
|
|
57
|
+
console.log(`
|
|
58
|
+
AI.Matey CLI v0.1.0
|
|
59
|
+
Universal AI Adapter System - Provider-agnostic interface for AI APIs
|
|
60
|
+
|
|
61
|
+
USAGE:
|
|
62
|
+
ai-matey <command> [options]
|
|
63
|
+
|
|
64
|
+
COMMANDS:
|
|
65
|
+
convert-response Convert Universal IR responses to provider formats
|
|
66
|
+
(OpenAI, Anthropic, Gemini, Ollama, Mistral)
|
|
67
|
+
|
|
68
|
+
convert-request Convert between Universal IR and provider request formats
|
|
69
|
+
(bidirectional: IR ↔ OpenAI, Anthropic, etc.)
|
|
70
|
+
|
|
71
|
+
emulate-ollama Emulate Ollama CLI interface using any backend
|
|
72
|
+
(compatible with Ollama commands: run, list, ps, show)
|
|
73
|
+
|
|
74
|
+
create-backend Generate a backend adapter template for emulate commands
|
|
75
|
+
(supports OpenAI-compatible APIs, Groq, Together AI, etc.)
|
|
76
|
+
|
|
77
|
+
proxy Start an HTTP proxy server that accepts provider requests
|
|
78
|
+
and routes them through any backend (OpenAI-compatible!)
|
|
79
|
+
|
|
80
|
+
GLOBAL OPTIONS:
|
|
81
|
+
-h, --help Show this help message
|
|
82
|
+
-v, --version Show version number
|
|
83
|
+
|
|
84
|
+
EXAMPLES:
|
|
85
|
+
# Convert IR response to OpenAI format
|
|
86
|
+
ai-matey convert-response --format openai --input response.json
|
|
87
|
+
|
|
88
|
+
# Convert OpenAI request to IR (for migration)
|
|
89
|
+
ai-matey convert-request --from openai --to ir --input openai-req.json
|
|
90
|
+
|
|
91
|
+
# Create a backend adapter
|
|
92
|
+
ai-matey create-backend --provider groq --output ./groq-backend.mjs
|
|
93
|
+
|
|
94
|
+
# Emulate Ollama CLI with your backend
|
|
95
|
+
ai-matey emulate-ollama --backend ./groq-backend.mjs run llama3-8b-8192
|
|
96
|
+
|
|
97
|
+
# Start OpenAI-compatible proxy server
|
|
98
|
+
ai-matey proxy --backend ./groq-backend.mjs --port 3000
|
|
99
|
+
|
|
100
|
+
# Get help for a specific command
|
|
101
|
+
ai-matey convert-response --help
|
|
102
|
+
ai-matey convert-request --help
|
|
103
|
+
ai-matey emulate-ollama --help
|
|
104
|
+
ai-matey create-backend --help
|
|
105
|
+
ai-matey proxy --help
|
|
106
|
+
|
|
107
|
+
Run 'ai-matey <command> --help' for more information on a specific command.
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
function showVersion() {
|
|
111
|
+
console.log('ai-matey version 0.1.0');
|
|
112
|
+
}
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// Subcommand Routing
|
|
115
|
+
// ============================================================================
|
|
116
|
+
async function main() {
|
|
117
|
+
const args = process.argv.slice(2);
|
|
118
|
+
// Handle no arguments
|
|
119
|
+
if (args.length === 0) {
|
|
120
|
+
showHelp();
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
const command = args[0];
|
|
124
|
+
// Handle global flags (only if no command or if help/version is the first arg)
|
|
125
|
+
if (command === '--help' || command === '-h') {
|
|
126
|
+
showHelp();
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
if (command === '--version' || command === '-v') {
|
|
130
|
+
showVersion();
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
// Route to subcommand
|
|
134
|
+
switch (command) {
|
|
135
|
+
case 'convert-response': {
|
|
136
|
+
const { main: convertMain } = await Promise.resolve().then(() => __importStar(require('./convert-response.js')));
|
|
137
|
+
// Remove the command name from args
|
|
138
|
+
process.argv = [process.argv[0] || 'node', process.argv[1] || 'ai-matey', ...args.slice(1)];
|
|
139
|
+
await convertMain();
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
case 'convert-request': {
|
|
143
|
+
const { main: convertRequestMain } = await Promise.resolve().then(() => __importStar(require('./convert-request.js')));
|
|
144
|
+
// Remove the command name from args
|
|
145
|
+
process.argv = [process.argv[0] || 'node', process.argv[1] || 'ai-matey', ...args.slice(1)];
|
|
146
|
+
await convertRequestMain();
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'emulate-ollama': {
|
|
150
|
+
const { main: ollamaMain } = await Promise.resolve().then(() => __importStar(require('./ollama/index.js')));
|
|
151
|
+
// Remove the command name from args
|
|
152
|
+
process.argv = [process.argv[0] || 'node', process.argv[1] || 'ai-matey', ...args.slice(1)];
|
|
153
|
+
await ollamaMain();
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case 'create-backend': {
|
|
157
|
+
const { main: createBackendMain } = await Promise.resolve().then(() => __importStar(require('./create-backend.js')));
|
|
158
|
+
// Remove the command name from args
|
|
159
|
+
process.argv = [process.argv[0] || 'node', process.argv[1] || 'ai-matey', ...args.slice(1)];
|
|
160
|
+
await createBackendMain();
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'proxy': {
|
|
164
|
+
const { main: proxyMain } = await Promise.resolve().then(() => __importStar(require('./proxy.js')));
|
|
165
|
+
// Remove the command name from args
|
|
166
|
+
process.argv = [process.argv[0] || 'node', process.argv[1] || 'ai-matey', ...args.slice(1)];
|
|
167
|
+
await proxyMain();
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
console.error(`Error: Unknown command '${command}'`);
|
|
172
|
+
console.error(`Run 'ai-matey --help' to see available commands.`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Run main when executed directly
|
|
177
|
+
main().catch((error) => {
|
|
178
|
+
console.error('Fatal error:', error instanceof Error ? error.message : String(error));
|
|
179
|
+
process.exit(1);
|
|
180
|
+
});
|
|
181
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Ollama `list` Command
|
|
4
|
+
*
|
|
5
|
+
* List available models.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/ollama/commands/list
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.listCommand = listCommand;
|
|
11
|
+
const output_formatter_js_1 = require("../../utils/output-formatter.js");
|
|
12
|
+
/**
|
|
13
|
+
* Execute the list command.
|
|
14
|
+
*/
|
|
15
|
+
async function listCommand(options) {
|
|
16
|
+
const { backend, modelMapping, json = false, verbose = false } = options;
|
|
17
|
+
try {
|
|
18
|
+
// Check if backend supports listModels
|
|
19
|
+
const listModels = backend.listModels;
|
|
20
|
+
if (typeof listModels !== 'function') {
|
|
21
|
+
console.error((0, output_formatter_js_1.colorize)(`Backend ${backend.metadata.name} does not support listing models`, 'yellow'));
|
|
22
|
+
console.log('\nThis backend may require manual model configuration.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Fetch models
|
|
26
|
+
const result = await listModels.call(backend);
|
|
27
|
+
if (!result || !result.models || result.models.length === 0) {
|
|
28
|
+
console.log((0, output_formatter_js_1.colorize)('No models available', 'gray'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const models = result.models;
|
|
32
|
+
if (json) {
|
|
33
|
+
console.log(JSON.stringify(models, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Format as table
|
|
37
|
+
const rows = models.map((model) => {
|
|
38
|
+
const name = model.name || model.id;
|
|
39
|
+
const translatedName = modelMapping
|
|
40
|
+
? Object.entries(modelMapping).find(([_, v]) => v === name)?.[0]
|
|
41
|
+
: undefined;
|
|
42
|
+
return {
|
|
43
|
+
name: translatedName ? `${translatedName} ${(0, output_formatter_js_1.colorize)(`(${name})`, 'gray')}` : name,
|
|
44
|
+
id: model.id?.slice(0, 12) || 'N/A',
|
|
45
|
+
size: model.contextWindow ? `${(model.contextWindow / 1000).toFixed(0)}K ctx` : 'N/A',
|
|
46
|
+
modified: model.created ? (0, output_formatter_js_1.formatRelativeTime)(new Date(model.created).getTime()) : 'N/A',
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
console.log();
|
|
50
|
+
const table = (0, output_formatter_js_1.formatTable)({
|
|
51
|
+
columns: [
|
|
52
|
+
{ key: 'name', header: 'NAME' },
|
|
53
|
+
{ key: 'id', header: 'ID' },
|
|
54
|
+
{ key: 'size', header: 'CONTEXT' },
|
|
55
|
+
{ key: 'modified', header: 'MODIFIED' },
|
|
56
|
+
],
|
|
57
|
+
rows,
|
|
58
|
+
});
|
|
59
|
+
console.log(table);
|
|
60
|
+
console.log();
|
|
61
|
+
if (verbose) {
|
|
62
|
+
console.log((0, output_formatter_js_1.colorize)(`Total models: ${models.length}`, 'gray'));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
console.error((0, output_formatter_js_1.colorize)(`Error listing models: ${error instanceof Error ? error.message : String(error)}`, 'red'));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/ollama/commands/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Ollama `ps` Command
|
|
4
|
+
*
|
|
5
|
+
* List running models.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/ollama/commands/ps
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.psCommand = psCommand;
|
|
11
|
+
const state_manager_js_1 = require("../../utils/state-manager.js");
|
|
12
|
+
const backend_loader_js_1 = require("../../utils/backend-loader.js");
|
|
13
|
+
const output_formatter_js_1 = require("../../utils/output-formatter.js");
|
|
14
|
+
/**
|
|
15
|
+
* Execute the ps command.
|
|
16
|
+
*/
|
|
17
|
+
async function psCommand(options) {
|
|
18
|
+
const { backend, json = false, verbose = false } = options;
|
|
19
|
+
try {
|
|
20
|
+
// Get running models from state manager
|
|
21
|
+
const runningModels = state_manager_js_1.stateManager.getAll();
|
|
22
|
+
if (runningModels.length === 0) {
|
|
23
|
+
if (json) {
|
|
24
|
+
console.log('[]');
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log((0, output_formatter_js_1.colorize)('No models currently running', 'gray'));
|
|
28
|
+
}
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (json) {
|
|
32
|
+
console.log(JSON.stringify(runningModels, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Format as table
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
const rows = runningModels.map((model) => {
|
|
38
|
+
const ttlRemaining = model.ttl
|
|
39
|
+
? Math.max(0, model.ttl - (now - model.lastActivity))
|
|
40
|
+
: undefined;
|
|
41
|
+
return {
|
|
42
|
+
name: model.name,
|
|
43
|
+
id: model.pid?.toString().slice(0, 12) || 'N/A',
|
|
44
|
+
size: model.size ? (0, output_formatter_js_1.formatSize)(model.size) : 'N/A',
|
|
45
|
+
processor: (0, backend_loader_js_1.isModelRunner)(backend) ? 'GPU/CPU' : 'API',
|
|
46
|
+
until: ttlRemaining ? `${(0, output_formatter_js_1.formatDuration)(ttlRemaining)} from now` : 'Running',
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
console.log();
|
|
50
|
+
const table = (0, output_formatter_js_1.formatTable)({
|
|
51
|
+
columns: [
|
|
52
|
+
{ key: 'name', header: 'NAME' },
|
|
53
|
+
{ key: 'id', header: 'ID' },
|
|
54
|
+
{ key: 'size', header: 'SIZE' },
|
|
55
|
+
{ key: 'processor', header: 'PROCESSOR' },
|
|
56
|
+
{ key: 'until', header: 'UNTIL' },
|
|
57
|
+
],
|
|
58
|
+
rows,
|
|
59
|
+
});
|
|
60
|
+
console.log(table);
|
|
61
|
+
console.log();
|
|
62
|
+
if (verbose) {
|
|
63
|
+
console.log((0, output_formatter_js_1.colorize)(`Total running: ${runningModels.length}`, 'gray'));
|
|
64
|
+
// Show backend stats if available
|
|
65
|
+
if ((0, backend_loader_js_1.isModelRunner)(backend)) {
|
|
66
|
+
const runner = backend;
|
|
67
|
+
const stats = runner.getStats();
|
|
68
|
+
if (stats) {
|
|
69
|
+
console.log((0, output_formatter_js_1.colorize)(`Backend uptime: ${(0, output_formatter_js_1.formatDuration)(stats.uptime || 0)}`, 'gray'));
|
|
70
|
+
console.log((0, output_formatter_js_1.colorize)(`Request count: ${stats.requestCount || 0}`, 'gray'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error((0, output_formatter_js_1.colorize)(`Error listing running models: ${error instanceof Error ? error.message : String(error)}`, 'red'));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=ps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ps.js","sourceRoot":"","sources":["../../../../src/ollama/commands/ps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pull Command - Download GGUF models from Ollama registry
|
|
4
|
+
*
|
|
5
|
+
* Downloads .gguf model files from the Ollama registry API.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/ollama/commands/pull
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.pullCommand = pullCommand;
|
|
11
|
+
const promises_1 = require("node:fs/promises");
|
|
12
|
+
const node_path_1 = require("node:path");
|
|
13
|
+
const node_fs_1 = require("node:fs");
|
|
14
|
+
const promises_2 = require("node:stream/promises");
|
|
15
|
+
const node_stream_1 = require("node:stream");
|
|
16
|
+
const output_formatter_js_1 = require("../../utils/output-formatter.js");
|
|
17
|
+
/**
|
|
18
|
+
* Ollama registry base URL.
|
|
19
|
+
*/
|
|
20
|
+
const OLLAMA_REGISTRY = 'https://registry.ollama.ai/v2/library';
|
|
21
|
+
/**
|
|
22
|
+
* Parse model specification into name and tag.
|
|
23
|
+
* Format: model:tag or model (defaults to 'latest')
|
|
24
|
+
*/
|
|
25
|
+
function parseModel(modelSpec) {
|
|
26
|
+
const parts = modelSpec.split(':');
|
|
27
|
+
const name = parts[0] || 'llama3.1';
|
|
28
|
+
const tag = parts[1] || 'latest';
|
|
29
|
+
return { name, tag };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Format bytes for human-readable display.
|
|
33
|
+
*/
|
|
34
|
+
function formatBytes(bytes) {
|
|
35
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
36
|
+
let size = bytes;
|
|
37
|
+
let unitIndex = 0;
|
|
38
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
39
|
+
size /= 1024;
|
|
40
|
+
unitIndex++;
|
|
41
|
+
}
|
|
42
|
+
return `${size.toFixed(2)} ${units[unitIndex]}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Fetch manifest from Ollama registry.
|
|
46
|
+
*/
|
|
47
|
+
async function fetchManifest(name, tag, verbose) {
|
|
48
|
+
const manifestUrl = `${OLLAMA_REGISTRY}/${name}/manifests/${tag}`;
|
|
49
|
+
if (verbose) {
|
|
50
|
+
(0, output_formatter_js_1.info)(`Fetching manifest: ${manifestUrl}`);
|
|
51
|
+
}
|
|
52
|
+
const response = await fetch(manifestUrl, {
|
|
53
|
+
headers: {
|
|
54
|
+
Accept: 'application/vnd.docker.distribution.manifest.v2+json',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
if (response.status === 404) {
|
|
59
|
+
throw new Error(`Model not found: ${name}:${tag}\n\nAvailable models at https://ollama.com/library`);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Failed to fetch manifest: ${response.status} ${response.statusText}`);
|
|
62
|
+
}
|
|
63
|
+
const manifest = await response.json();
|
|
64
|
+
const data = manifest;
|
|
65
|
+
if (verbose) {
|
|
66
|
+
(0, output_formatter_js_1.info)(`Manifest retrieved: ${data.layers?.length || 0} layers`);
|
|
67
|
+
}
|
|
68
|
+
return data;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Find GGUF layer in manifest.
|
|
72
|
+
*/
|
|
73
|
+
function findGGUFLayer(manifest) {
|
|
74
|
+
if (!manifest.layers || !Array.isArray(manifest.layers)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
// Look for layers with GGUF-related media types or the largest layer
|
|
78
|
+
// Ollama typically uses application/vnd.ollama.image.model for the model file
|
|
79
|
+
const modelLayer = manifest.layers.find((layer) => layer.mediaType === 'application/vnd.ollama.image.model');
|
|
80
|
+
if (modelLayer) {
|
|
81
|
+
return {
|
|
82
|
+
digest: modelLayer.digest,
|
|
83
|
+
size: modelLayer.size || 0,
|
|
84
|
+
mediaType: modelLayer.mediaType,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Fallback: Use the largest layer (usually the model)
|
|
88
|
+
const largestLayer = manifest.layers.reduce((largest, layer) => {
|
|
89
|
+
return (layer.size || 0) > (largest?.size || 0) ? layer : largest;
|
|
90
|
+
}, null);
|
|
91
|
+
if (largestLayer) {
|
|
92
|
+
return {
|
|
93
|
+
digest: largestLayer.digest,
|
|
94
|
+
size: largestLayer.size || 0,
|
|
95
|
+
mediaType: largestLayer.mediaType,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Download blob from Ollama registry with progress.
|
|
102
|
+
*/
|
|
103
|
+
async function downloadBlob(name, digest, outputPath, size, verbose) {
|
|
104
|
+
const blobUrl = `${OLLAMA_REGISTRY}/${name}/blobs/${digest}`;
|
|
105
|
+
if (verbose) {
|
|
106
|
+
(0, output_formatter_js_1.info)(`Downloading from: ${blobUrl}`);
|
|
107
|
+
}
|
|
108
|
+
// Ensure output directory exists
|
|
109
|
+
const dir = (0, node_path_1.dirname)(outputPath);
|
|
110
|
+
if (!(0, node_fs_1.existsSync)(dir)) {
|
|
111
|
+
await (0, promises_1.mkdir)(dir, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
const response = await fetch(blobUrl);
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
throw new Error(`Failed to download blob: ${response.status} ${response.statusText}`);
|
|
116
|
+
}
|
|
117
|
+
if (!response.body) {
|
|
118
|
+
throw new Error('Response body is null');
|
|
119
|
+
}
|
|
120
|
+
// Create progress tracker
|
|
121
|
+
let downloaded = 0;
|
|
122
|
+
let lastProgress = 0;
|
|
123
|
+
const startTime = Date.now();
|
|
124
|
+
const nodeStream = node_stream_1.Readable.fromWeb(response.body);
|
|
125
|
+
const fileStream = (0, node_fs_1.createWriteStream)(outputPath);
|
|
126
|
+
// Track progress
|
|
127
|
+
nodeStream.on('data', (chunk) => {
|
|
128
|
+
downloaded += chunk.length;
|
|
129
|
+
const progress = Math.floor((downloaded / size) * 100);
|
|
130
|
+
// Update progress every 5%
|
|
131
|
+
if (progress >= lastProgress + 5 || progress === 100) {
|
|
132
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
133
|
+
const speed = downloaded / elapsed;
|
|
134
|
+
const remaining = size - downloaded;
|
|
135
|
+
const eta = remaining / speed;
|
|
136
|
+
process.stdout.write(`\r${formatBytes(downloaded)} / ${formatBytes(size)} (${progress}%) - ` +
|
|
137
|
+
`${formatBytes(speed)}/s - ETA: ${Math.floor(eta)}s`);
|
|
138
|
+
lastProgress = progress;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
await (0, promises_2.pipeline)(nodeStream, fileStream);
|
|
142
|
+
// Final newline after progress
|
|
143
|
+
process.stdout.write('\n');
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Pull command - Download GGUF model from Ollama registry.
|
|
147
|
+
*/
|
|
148
|
+
async function pullCommand(options) {
|
|
149
|
+
const { model: modelSpec, output, verbose = false } = options;
|
|
150
|
+
try {
|
|
151
|
+
// Parse model specification
|
|
152
|
+
const { name, tag } = parseModel(modelSpec);
|
|
153
|
+
(0, output_formatter_js_1.info)(`Pulling ${name}:${tag} from Ollama registry...`);
|
|
154
|
+
// Step 1: Fetch manifest
|
|
155
|
+
const manifest = await fetchManifest(name, tag, verbose);
|
|
156
|
+
// Step 2: Find GGUF layer
|
|
157
|
+
const layer = findGGUFLayer(manifest);
|
|
158
|
+
if (!layer) {
|
|
159
|
+
throw new Error('No model layer found in manifest. This may not be a GGUF model.');
|
|
160
|
+
}
|
|
161
|
+
if (verbose) {
|
|
162
|
+
(0, output_formatter_js_1.info)(`Found model layer:`);
|
|
163
|
+
(0, output_formatter_js_1.info)(` Digest: ${layer.digest}`);
|
|
164
|
+
(0, output_formatter_js_1.info)(` Size: ${formatBytes(layer.size)}`);
|
|
165
|
+
(0, output_formatter_js_1.info)(` Media Type: ${layer.mediaType}`);
|
|
166
|
+
}
|
|
167
|
+
// Step 3: Determine output path
|
|
168
|
+
const defaultOutput = (0, node_path_1.resolve)(process.cwd(), 'models', `${name}-${tag}.gguf`);
|
|
169
|
+
const outputPath = output ? (0, node_path_1.resolve)(process.cwd(), output) : defaultOutput;
|
|
170
|
+
// Check if file already exists
|
|
171
|
+
if ((0, node_fs_1.existsSync)(outputPath)) {
|
|
172
|
+
(0, output_formatter_js_1.warn)(`File already exists: ${outputPath}`);
|
|
173
|
+
const confirmOverwrite = process.env.FORCE_OVERWRITE === 'true';
|
|
174
|
+
if (!confirmOverwrite) {
|
|
175
|
+
(0, output_formatter_js_1.error)('Use FORCE_OVERWRITE=true to overwrite existing file');
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
(0, output_formatter_js_1.info)(`Downloading to: ${outputPath}`);
|
|
180
|
+
(0, output_formatter_js_1.info)(`Size: ${formatBytes(layer.size)}`);
|
|
181
|
+
// Step 4: Download blob
|
|
182
|
+
await downloadBlob(name, layer.digest, outputPath, layer.size, verbose);
|
|
183
|
+
(0, output_formatter_js_1.success)(`\n✓ Model downloaded successfully: ${outputPath}`);
|
|
184
|
+
console.log('\nNext steps:');
|
|
185
|
+
console.log(` 1. Use with node-llama-cpp backend:`);
|
|
186
|
+
console.log(` ai-matey create-backend --provider node-llamacpp`);
|
|
187
|
+
console.log(` 2. Set modelPath in backend config to: ${outputPath}`);
|
|
188
|
+
console.log(` 3. Run: ai-matey emulate-ollama --backend ./backend.mjs run ${name}`);
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
(0, output_formatter_js_1.error)(`Failed to pull model: ${err instanceof Error ? err.message : String(err)}`);
|
|
192
|
+
if (verbose && err instanceof Error) {
|
|
193
|
+
console.error(err.stack);
|
|
194
|
+
}
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../../src/ollama/commands/pull.ts"],"names":[],"mappings":"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"}
|