@openinference/cli 1.1.0 → 1.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/data/models.json +4 -2
- package/dist/data/models.json +4 -2
- package/dist/hardware.d.ts +3 -0
- package/dist/hardware.d.ts.map +1 -1
- package/dist/hardware.js +18 -7
- package/dist/hardware.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/linereader.d.ts +73 -0
- package/dist/linereader.d.ts.map +1 -0
- package/dist/linereader.js +375 -0
- package/dist/linereader.js.map +1 -0
- package/dist/prompt.d.ts +18 -6
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +136 -52
- package/dist/prompt.js.map +1 -1
- package/dist/recommend-run.js +2 -2
- package/dist/recommend-run.js.map +1 -1
- package/dist/recommend.d.ts +1 -1
- package/dist/recommend.d.ts.map +1 -1
- package/dist/recommend.js +5 -5
- package/dist/recommend.js.map +1 -1
- package/dist/setup.d.ts +4 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +58 -30
- package/dist/setup.js.map +1 -1
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +229 -61
- package/dist/shell.js.map +1 -1
- package/dist/use-cases.d.ts.map +1 -1
- package/dist/use-cases.js +5 -22
- package/dist/use-cases.js.map +1 -1
- package/package.json +1 -1
package/dist/setup.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WIZARD_PICK_COUNT = void 0;
|
|
3
|
+
exports.WIZARD_SHOW_COUNT = exports.WIZARD_PICK_COUNT = void 0;
|
|
4
4
|
exports.runSetup = runSetup;
|
|
5
5
|
exports.printRecommendPreview = printRecommendPreview;
|
|
6
6
|
const recommend_1 = require("./recommend");
|
|
@@ -9,7 +9,10 @@ const config_1 = require("./config");
|
|
|
9
9
|
const prompt_1 = require("./prompt");
|
|
10
10
|
const ollama_1 = require("./ollama");
|
|
11
11
|
const use_cases_1 = require("./use-cases");
|
|
12
|
-
|
|
12
|
+
/** How many picks to compute (so "show more" has content). */
|
|
13
|
+
exports.WIZARD_PICK_COUNT = 15;
|
|
14
|
+
/** How many to show before the user asks for more. */
|
|
15
|
+
exports.WIZARD_SHOW_COUNT = 5;
|
|
13
16
|
async function resolvePool(catalog, hw, opts) {
|
|
14
17
|
const auto = Boolean(opts.yes);
|
|
15
18
|
const lockedUseCase = opts.useCase;
|
|
@@ -102,12 +105,12 @@ async function runSetup(opts) {
|
|
|
102
105
|
(0, prompt_1.printTooSmallHelp)(hw);
|
|
103
106
|
return;
|
|
104
107
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
}
|
|
108
|
+
const needsOllama = !remote && !opts.skipInstall && !(await (0, ollama_1.pingOllama)(baseUrl)) && !(0, ollama_1.isOllamaInstalled)();
|
|
109
|
+
const cpuNote = () => {
|
|
110
|
+
if (!hw.gpuUsable && hw.ramGb < 8) {
|
|
111
|
+
console.log(' Note: CPU-only on limited RAM — only small models are recommended.\n');
|
|
112
|
+
}
|
|
113
|
+
};
|
|
111
114
|
let chosen;
|
|
112
115
|
if (opts.model) {
|
|
113
116
|
const fromRecs = picks.find((r) => r.id === opts.model);
|
|
@@ -123,30 +126,49 @@ async function runSetup(opts) {
|
|
|
123
126
|
throw new Error(`Model "${opts.model}" does not fit this machine.`);
|
|
124
127
|
chosen = { ...m, fit, score: 0 };
|
|
125
128
|
}
|
|
126
|
-
if (!auto)
|
|
129
|
+
if (!auto) {
|
|
127
130
|
console.log(` Using model: ${chosen.name} (${chosen.id})\n`);
|
|
131
|
+
cpuNote();
|
|
132
|
+
const action = await (0, prompt_1.confirmInstall)({ modelName: chosen.name, sizeMb: chosen.sizeMb, needsOllama });
|
|
133
|
+
if (action !== 'install') {
|
|
134
|
+
console.log('\n Setup cancelled. Run `oi` again when ready.\n');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
console.log('');
|
|
138
|
+
}
|
|
128
139
|
}
|
|
129
140
|
else if (auto) {
|
|
130
141
|
chosen = picks[0];
|
|
131
142
|
console.log(` → ${chosen.name} (best match)\n`);
|
|
132
143
|
}
|
|
133
144
|
else {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
// Pick → confirm, with "Browse" looping back to the picker.
|
|
146
|
+
while (true) {
|
|
147
|
+
chosen = await (0, prompt_1.pickRecommendation)(picks, {
|
|
148
|
+
show: exports.WIZARD_SHOW_COUNT,
|
|
149
|
+
totalFit: runnable.length,
|
|
150
|
+
fallback: hardwareFallback,
|
|
151
|
+
useCaseLabel: (0, use_cases_1.useCaseLabel)(useCase),
|
|
152
|
+
budgetGb: hw.budgetGb,
|
|
153
|
+
});
|
|
154
|
+
console.log(` Selected: ${chosen.name}\n`);
|
|
155
|
+
cpuNote();
|
|
156
|
+
const action = await (0, prompt_1.confirmInstall)({
|
|
157
|
+
modelName: chosen.name,
|
|
158
|
+
sizeMb: chosen.sizeMb,
|
|
159
|
+
needsOllama,
|
|
160
|
+
canBrowse: picks.length > 1,
|
|
161
|
+
});
|
|
162
|
+
if (action === 'install') {
|
|
163
|
+
console.log('');
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
if (action === 'cancel') {
|
|
167
|
+
console.log('\n Setup cancelled. Run `oi` again when ready.\n');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.log(' Pick another model:\n'); // browse → loop
|
|
171
|
+
}
|
|
150
172
|
}
|
|
151
173
|
if (remote) {
|
|
152
174
|
console.log(' Connecting to Ollama…\n');
|
|
@@ -188,15 +210,21 @@ async function runSetup(opts) {
|
|
|
188
210
|
function printRecommendPreview(recs, hw, meta) {
|
|
189
211
|
console.log('\n OpenInference — model recommendations\n');
|
|
190
212
|
(0, prompt_1.printHardwareResults)(hw);
|
|
191
|
-
console.log(` Use case: ${(0, use_cases_1.useCaseLabel)(meta.useCase)}`);
|
|
192
|
-
console.log(` ${meta.poolSize}
|
|
193
|
-
|
|
213
|
+
console.log(` Use case: ${(0, use_cases_1.useCaseLabel)(meta.useCase)}\n`);
|
|
214
|
+
console.log(` ${meta.poolSize} ${(0, use_cases_1.useCaseLabel)(meta.useCase)} models available.`);
|
|
215
|
+
const filtered = meta.poolSize - meta.runnableSize;
|
|
216
|
+
if (filtered > 0) {
|
|
217
|
+
console.log(` ${filtered} need more RAM, GPU, or disk than this computer has.`);
|
|
218
|
+
}
|
|
194
219
|
if (recs.length === 0) {
|
|
195
|
-
console.log('
|
|
220
|
+
console.log('\n None will run well here. Try another goal: oi browse --use-case chat\n');
|
|
196
221
|
return;
|
|
197
222
|
}
|
|
198
|
-
console.log(`
|
|
223
|
+
console.log(` Showing the ${recs.length} that will run well:\n`);
|
|
199
224
|
(0, prompt_1.printRecommendations)(recs);
|
|
225
|
+
if (meta.runnableSize > recs.length) {
|
|
226
|
+
console.log(` +${meta.runnableSize - recs.length} more fit your hardware — run \`oi browse\` (or /browse) to see them.`);
|
|
227
|
+
}
|
|
200
228
|
console.log(' Run `oi` for the setup wizard, or `oi -y` to auto-install the top pick.\n');
|
|
201
229
|
}
|
|
202
230
|
//# sourceMappingURL=setup.js.map
|
package/dist/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/shell.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../src/shell.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AA2XF,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyErE"}
|
package/dist/shell.js
CHANGED
|
@@ -4,40 +4,46 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runShell = runShell;
|
|
7
|
-
const
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
9
|
const config_1 = require("./config");
|
|
10
|
+
const ollama_1 = require("./ollama");
|
|
9
11
|
const hardware_1 = require("./hardware");
|
|
10
12
|
const start_1 = require("./start");
|
|
11
13
|
const recommend_run_1 = require("./recommend-run");
|
|
12
14
|
const use_cases_1 = require("./use-cases");
|
|
13
15
|
const chat_1 = require("./chat");
|
|
16
|
+
const recommend_1 = require("./recommend");
|
|
14
17
|
const manage_1 = require("./manage");
|
|
15
18
|
const prompt_1 = require("./prompt");
|
|
16
19
|
const version_1 = require("./version");
|
|
20
|
+
const linereader_1 = require("./linereader");
|
|
17
21
|
// ── colors ──────────────────────────────────────────────
|
|
18
|
-
const
|
|
22
|
+
const C = (code, s) => `\x1b[38;5;${code}m${s}\x1b[0m`;
|
|
23
|
+
const brand = (s) => C(43, s);
|
|
19
24
|
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
20
25
|
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
21
26
|
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
22
27
|
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
23
28
|
const COMMANDS = [
|
|
24
|
-
{ name: '/
|
|
25
|
-
{ name: '/recommend', args: '[
|
|
26
|
-
{ name: '/browse', args: '[
|
|
27
|
-
{ name: '/use', args: '<model>', help: 'Switch active model (pulls if needed)' },
|
|
28
|
-
{ name: '/pull', args: '<model>', help: 'Download a model' },
|
|
29
|
-
{ name: '/models', help: 'List downloaded models' },
|
|
30
|
-
{ name: '/storage', help: 'Where models are stored' },
|
|
31
|
-
{ name: '/
|
|
32
|
-
{ name: '/
|
|
33
|
-
{ name: '/
|
|
34
|
-
{ name: '/clear', help: 'Clear screen and conversation' },
|
|
35
|
-
{ name: '/
|
|
29
|
+
{ name: '/setup', help: 'Pick a goal, scan hardware, install a model', group: 'Setup & models' },
|
|
30
|
+
{ name: '/recommend', args: '[goal]', help: 'Best models for your hardware', group: 'Setup & models' },
|
|
31
|
+
{ name: '/browse', args: '[goal]', help: 'Browse the full catalog', group: 'Setup & models' },
|
|
32
|
+
{ name: '/use', args: '<model>', help: 'Switch active model (pulls if needed)', group: 'Setup & models' },
|
|
33
|
+
{ name: '/pull', args: '<model>', help: 'Download a model', group: 'Setup & models' },
|
|
34
|
+
{ name: '/models', help: 'List downloaded models', group: 'Setup & models' },
|
|
35
|
+
{ name: '/storage', help: 'Where models are stored', group: 'Setup & models' },
|
|
36
|
+
{ name: '/config', help: 'Show model & connection settings', group: 'Setup & models' },
|
|
37
|
+
{ name: '/status', help: 'Show current setup', group: 'Session' },
|
|
38
|
+
{ name: '/scan', help: 'Re-scan this computer', group: 'Session' },
|
|
39
|
+
{ name: '/clear', help: 'Clear screen and conversation', group: 'Session' },
|
|
40
|
+
{ name: '/help', help: 'Show this help', group: 'Session' },
|
|
41
|
+
{ name: '/quit', help: 'Exit', group: 'Session' },
|
|
36
42
|
];
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const USE_CASE_IDS = use_cases_1.USE_CASES.map((u) => u.id);
|
|
44
|
+
// ── logo ────────────────────────────────────────────────
|
|
39
45
|
const LOGO = [
|
|
40
|
-
'██ ██ ██ ___ ____ _____ _ _ ',
|
|
46
|
+
' ██ ██ ██ ___ ____ _____ _ _ ',
|
|
41
47
|
' ██ ██ ██ / _ \\| _ \\| ____| \\ | |',
|
|
42
48
|
' ██ ██ ██ ██ ██ | | | | |_) | _| | \\| |',
|
|
43
49
|
' ██ ██ ██ ██ ██ | |_| | __/| |___| |\\ |',
|
|
@@ -48,41 +54,71 @@ const LOGO = [
|
|
|
48
54
|
' | || |\\ | _| | |___| _ <| |___| |\\ | |___| |___ ',
|
|
49
55
|
' |___|_| \\_|_| |_____|_| \\_\\_____|_| \\_|\\____|_____|',
|
|
50
56
|
];
|
|
51
|
-
|
|
52
|
-
const LETTER_GRAD = [43, 43, 43, 43, 43, 43, 43, 43, 43, 43];
|
|
57
|
+
const LOGO_WIDTH = Math.max(...LOGO.map((l) => l.length)) + 2;
|
|
53
58
|
const BAR_COLOR = 48; // bright spring-green for the ██ blocks
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
const WORD_COLOR = 43; // on-brand teal for the wordmark
|
|
60
|
+
function termWidth() {
|
|
61
|
+
return process.stdout.columns ?? 80;
|
|
62
|
+
}
|
|
63
|
+
function printLogo() {
|
|
57
64
|
console.log('');
|
|
58
|
-
|
|
65
|
+
if (termWidth() < LOGO_WIDTH) {
|
|
66
|
+
// Compact fallback for narrow terminals
|
|
67
|
+
console.log(` ${C(BAR_COLOR, '██')} ${bold(brand('OPEN INFERENCE'))} ${dim('v' + version_1.VERSION)}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const line of LOGO) {
|
|
59
71
|
const bars = line.match(/^[█ ]*/)?.[0] ?? '';
|
|
60
72
|
const rest = line.slice(bars.length);
|
|
61
|
-
console.log(` ${C(BAR_COLOR, bars)}${C(
|
|
62
|
-
}
|
|
73
|
+
console.log(` ${C(BAR_COLOR, bars)}${C(WORD_COLOR, rest)}`);
|
|
74
|
+
}
|
|
63
75
|
console.log('');
|
|
64
76
|
console.log(` ${bold(brand('AI infrastructure, fully governed.'))} ${dim('v' + version_1.VERSION)}`);
|
|
77
|
+
}
|
|
78
|
+
function printWelcome() {
|
|
79
|
+
const cfg = (0, config_1.loadConfig)();
|
|
80
|
+
const hw = (0, hardware_1.detectHardware)();
|
|
65
81
|
console.log('');
|
|
66
82
|
if (cfg) {
|
|
67
|
-
console.log(` ${bold(cfg.modelName)} ${dim('·'
|
|
68
|
-
console.log(
|
|
83
|
+
console.log(` Chatting with ${bold(cfg.modelName)} ${dim('· ' + (0, hardware_1.formatHardware)(hw))}`);
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log(` ${dim('Ask anything below, or:')}`);
|
|
86
|
+
console.log(` ${brand('/models')} ${dim('see installed')} ${brand('/use <model>')} ${dim('switch')}`);
|
|
87
|
+
console.log(` ${brand('/status')} ${dim('your setup')} ${brand('/help')} ${dim('all commands')}`);
|
|
69
88
|
}
|
|
70
89
|
else {
|
|
71
|
-
console.log(` ${dim('
|
|
90
|
+
console.log(` ${dim('Run local open-source AI on your own machine — no API keys, no cloud.')}`);
|
|
72
91
|
console.log(` ${dim((0, hardware_1.formatHardware)(hw))}`);
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(` ${bold('Get started')}`);
|
|
94
|
+
console.log(` ${brand('/setup'.padEnd(20))} ${dim('pick a goal, scan hardware, install a model')}`);
|
|
95
|
+
console.log(` ${brand('/recommend coding'.padEnd(20))} ${dim('see which models fit this computer')}`);
|
|
96
|
+
console.log(` ${brand('/help'.padEnd(20))} ${dim('all commands')}`);
|
|
97
|
+
console.log('');
|
|
98
|
+
console.log(` ${dim('Or just type a question — I’ll set you up first.')}`);
|
|
73
99
|
}
|
|
74
100
|
console.log('');
|
|
75
|
-
console.log(dim(' Type
|
|
101
|
+
console.log(dim(' Type “/” to see commands · ↑↓ to pick · Tab/Enter to choose · /quit to exit'));
|
|
76
102
|
console.log('');
|
|
77
103
|
}
|
|
104
|
+
function printBanner() {
|
|
105
|
+
printLogo();
|
|
106
|
+
printWelcome();
|
|
107
|
+
}
|
|
78
108
|
function printHelp() {
|
|
79
109
|
console.log('');
|
|
80
110
|
console.log(bold(' Commands'));
|
|
81
|
-
for (const
|
|
82
|
-
|
|
83
|
-
console.log(`
|
|
111
|
+
for (const group of ['Setup & models', 'Session']) {
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(` ${dim(group)}`);
|
|
114
|
+
for (const c of COMMANDS.filter((x) => x.group === group)) {
|
|
115
|
+
const usage = `${c.name}${c.args ? ' ' + c.args : ''}`;
|
|
116
|
+
console.log(` ${brand(usage.padEnd(20))} ${dim(c.help)}`);
|
|
117
|
+
}
|
|
84
118
|
}
|
|
85
119
|
console.log('');
|
|
120
|
+
console.log(` ${dim('goals:')} ${USE_CASE_IDS.join(' · ')}`);
|
|
121
|
+
console.log(dim(' Custom model? /use or /pull any tag from ollama.com/library'));
|
|
86
122
|
console.log(dim(' Anything that is not a /command is sent to the active model.'));
|
|
87
123
|
console.log('');
|
|
88
124
|
}
|
|
@@ -100,6 +136,55 @@ function printStatus() {
|
|
|
100
136
|
console.log(` Storage: ${(0, hardware_1.ollamaModelsPath)()}`);
|
|
101
137
|
console.log('');
|
|
102
138
|
}
|
|
139
|
+
function printConfig(opts) {
|
|
140
|
+
const cfg = (0, config_1.loadConfig)();
|
|
141
|
+
console.log('');
|
|
142
|
+
console.log(bold(' Configuration'));
|
|
143
|
+
console.log('');
|
|
144
|
+
if (!cfg) {
|
|
145
|
+
const hw = (0, hardware_1.detectHardware)();
|
|
146
|
+
const gpu = !hw.hasGpu
|
|
147
|
+
? 'none — CPU inference'
|
|
148
|
+
: hw.gpuUsable
|
|
149
|
+
? `${hw.gpuName ?? 'GPU'} (${hw.vramGb} GB)`
|
|
150
|
+
: `${hw.gpuName ?? 'GPU'} (${hw.vramGb} GB — too small, using CPU)`;
|
|
151
|
+
const label = (s) => s.padEnd(12);
|
|
152
|
+
console.log(' No configuration yet — type /setup to create one.');
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log(` ${dim('Current defaults')}`);
|
|
155
|
+
console.log(` ${label('Provider')}Ollama`);
|
|
156
|
+
console.log(` ${label('Model')}none`);
|
|
157
|
+
console.log(` ${label('Host')}${(0, ollama_1.resolveOllamaUrl)(opts.ollamaUrl)}`);
|
|
158
|
+
console.log(` ${label('🎮 GPU')}${gpu}`);
|
|
159
|
+
console.log(` ${label('Config')}${(0, config_1.configPath)()}`);
|
|
160
|
+
console.log('');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const entry = (0, recommend_1.loadCatalog)().find((m) => m.id === cfg.model);
|
|
164
|
+
const base = (0, ollama_1.resolveOllamaUrl)(opts.ollamaUrl);
|
|
165
|
+
const urlSource = opts.ollamaUrl
|
|
166
|
+
? 'from --ollama-url'
|
|
167
|
+
: process.env.OLLAMA_URL
|
|
168
|
+
? 'from $OLLAMA_URL'
|
|
169
|
+
: cfg.ollamaUrl
|
|
170
|
+
? 'from config'
|
|
171
|
+
: 'default';
|
|
172
|
+
const label = (s) => s.padEnd(15);
|
|
173
|
+
console.log(` ${label('Active model')}${bold(cfg.modelName)} ${dim('(' + cfg.model + ')')}`);
|
|
174
|
+
if (entry) {
|
|
175
|
+
const size = entry.sizeMb >= 1000 ? `${(entry.sizeMb / 1024).toFixed(1)} GB` : `${entry.sizeMb} MB`;
|
|
176
|
+
console.log(` ${label('')}${dim(`~${entry.ramGb} GB RAM · ${size} download · quality ${entry.quality}/100`)}`);
|
|
177
|
+
}
|
|
178
|
+
if (cfg.useCase)
|
|
179
|
+
console.log(` ${label('Use case')}${(0, use_cases_1.useCaseLabel)(cfg.useCase)}`);
|
|
180
|
+
console.log(` ${label('Ollama URL')}${base} ${dim('(' + urlSource + ')')}`);
|
|
181
|
+
console.log(` ${label('Model storage')}${(0, hardware_1.ollamaModelsPath)()}`);
|
|
182
|
+
console.log(` ${label('Config file')}${(0, config_1.configPath)()}`);
|
|
183
|
+
console.log(` ${label('Set up')}${new Date(cfg.setupAt).toLocaleDateString()}`);
|
|
184
|
+
console.log('');
|
|
185
|
+
console.log(dim(' Switch model: /use <model> · Reconfigure: /setup'));
|
|
186
|
+
console.log('');
|
|
187
|
+
}
|
|
103
188
|
async function showModels(opts) {
|
|
104
189
|
const names = await (0, chat_1.listInstalledModels)(opts.ollamaUrl);
|
|
105
190
|
if (names.length === 0) {
|
|
@@ -110,26 +195,23 @@ async function showModels(opts) {
|
|
|
110
195
|
names.forEach((n) => console.log(` ${n}`));
|
|
111
196
|
console.log('');
|
|
112
197
|
}
|
|
113
|
-
/** Run one chat turn with a streamed, live-printed reply. */
|
|
198
|
+
/** Run one chat turn with a streamed, live-printed reply and a thinking indicator. */
|
|
114
199
|
async function chat(history, message, opts) {
|
|
115
200
|
history.push({ role: 'user', content: message });
|
|
116
|
-
process.stdout.write('\n');
|
|
201
|
+
process.stdout.write('\n' + dim(' thinking…'));
|
|
117
202
|
let started = false;
|
|
118
203
|
const reply = await (0, chat_1.streamChatTurn)(history, (chunk) => {
|
|
119
204
|
if (!started) {
|
|
120
|
-
process.stdout.write(' ');
|
|
205
|
+
process.stdout.write('\r' + ' '.repeat(12) + '\r ');
|
|
121
206
|
started = true;
|
|
122
207
|
}
|
|
123
208
|
process.stdout.write(chunk.replace(/\n/g, '\n '));
|
|
124
209
|
}, { ollamaUrl: opts.ollamaUrl, remote: opts.remote });
|
|
210
|
+
if (!started)
|
|
211
|
+
process.stdout.write('\r' + ' '.repeat(12) + '\r');
|
|
125
212
|
history.push({ role: 'assistant', content: reply });
|
|
126
213
|
process.stdout.write('\n\n');
|
|
127
214
|
}
|
|
128
|
-
/**
|
|
129
|
-
* Dispatch a slash command. Returns false to signal the shell should exit.
|
|
130
|
-
* `reopen` is used by commands that need their own stdin prompts (the wizard):
|
|
131
|
-
* the caller closes the shell readline before dispatch and reopens after.
|
|
132
|
-
*/
|
|
133
215
|
async function dispatch(raw, history, opts) {
|
|
134
216
|
const [cmd, ...rest] = raw.slice(1).trim().split(/\s+/);
|
|
135
217
|
const arg = rest.join(' ').trim();
|
|
@@ -140,22 +222,27 @@ async function dispatch(raw, history, opts) {
|
|
|
140
222
|
printHelp();
|
|
141
223
|
return {};
|
|
142
224
|
case 'recommend':
|
|
143
|
-
case 'rec':
|
|
144
|
-
|
|
225
|
+
case 'rec': {
|
|
226
|
+
// No goal given → ask the user to pick a task first, then recommend.
|
|
227
|
+
const useCase = (0, use_cases_1.parseUseCaseArg)(arg) ?? (await (0, use_cases_1.pickUseCase)());
|
|
228
|
+
(0, recommend_run_1.runRecommend)({ useCase });
|
|
145
229
|
return {};
|
|
146
|
-
|
|
147
|
-
|
|
230
|
+
}
|
|
231
|
+
case 'browse': {
|
|
232
|
+
const useCase = (0, use_cases_1.parseUseCaseArg)(arg) ?? (await (0, use_cases_1.pickUseCase)());
|
|
233
|
+
(0, recommend_run_1.runBrowse)({ useCase, all: true });
|
|
148
234
|
return {};
|
|
235
|
+
}
|
|
149
236
|
case 'use':
|
|
150
237
|
if (!arg) {
|
|
151
|
-
console.log('\n Usage: /use <model
|
|
238
|
+
console.log('\n Usage: /use <model> (Tab to autocomplete)\n');
|
|
152
239
|
return {};
|
|
153
240
|
}
|
|
154
241
|
await (0, manage_1.runUse)(arg, { ollamaUrl: opts.ollamaUrl, docker: opts.remote });
|
|
155
242
|
return {};
|
|
156
243
|
case 'pull':
|
|
157
244
|
if (!arg) {
|
|
158
|
-
console.log('\n Usage: /pull <model
|
|
245
|
+
console.log('\n Usage: /pull <model> (Tab to autocomplete)\n');
|
|
159
246
|
return {};
|
|
160
247
|
}
|
|
161
248
|
await (0, manage_1.runPull)(arg, { ollamaUrl: opts.ollamaUrl, docker: opts.remote });
|
|
@@ -166,6 +253,10 @@ async function dispatch(raw, history, opts) {
|
|
|
166
253
|
case 'storage':
|
|
167
254
|
await (0, manage_1.runStorage)();
|
|
168
255
|
return {};
|
|
256
|
+
case 'config':
|
|
257
|
+
case 'cfg':
|
|
258
|
+
printConfig(opts);
|
|
259
|
+
return {};
|
|
169
260
|
case 'status':
|
|
170
261
|
printStatus();
|
|
171
262
|
return {};
|
|
@@ -189,36 +280,116 @@ async function dispatch(raw, history, opts) {
|
|
|
189
280
|
return {};
|
|
190
281
|
}
|
|
191
282
|
}
|
|
192
|
-
|
|
193
|
-
|
|
283
|
+
// ── tab completion ──────────────────────────────────────
|
|
284
|
+
let catalogIds = [];
|
|
285
|
+
function loadCatalogIds() {
|
|
286
|
+
if (catalogIds.length)
|
|
287
|
+
return catalogIds;
|
|
288
|
+
try {
|
|
289
|
+
catalogIds = (0, recommend_1.loadCatalog)().map((m) => m.id);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
catalogIds = [];
|
|
293
|
+
}
|
|
294
|
+
return catalogIds;
|
|
295
|
+
}
|
|
296
|
+
function suggest(line) {
|
|
297
|
+
if (!line.startsWith('/'))
|
|
298
|
+
return [];
|
|
299
|
+
const model = /^(\/use|\/pull)\s+(.*)$/.exec(line);
|
|
300
|
+
if (model) {
|
|
301
|
+
const [, cmd, partial] = model;
|
|
302
|
+
const ids = loadCatalogIds();
|
|
303
|
+
const hits = ids
|
|
304
|
+
.filter((id) => id.startsWith(partial))
|
|
305
|
+
.slice(0, 7)
|
|
306
|
+
.map((id) => ({ value: `${cmd} ${id}`, label: id, submit: true }));
|
|
307
|
+
// Let the user pull ANY Ollama tag, even if it's not in our catalog.
|
|
308
|
+
if (partial && !ids.includes(partial)) {
|
|
309
|
+
hits.push({ value: `${cmd} ${partial}`, label: partial, hint: 'pull this exact tag', submit: true });
|
|
310
|
+
}
|
|
311
|
+
return hits;
|
|
312
|
+
}
|
|
313
|
+
const goal = /^(\/recommend|\/browse)\s+(.*)$/.exec(line);
|
|
314
|
+
if (goal) {
|
|
315
|
+
const [, cmd, partial] = goal;
|
|
316
|
+
return use_cases_1.USE_CASES.filter((u) => u.id.startsWith(partial)).map((u) => ({
|
|
317
|
+
value: `${cmd} ${u.id}`,
|
|
318
|
+
label: u.id,
|
|
319
|
+
hint: u.description,
|
|
320
|
+
submit: true,
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
// Once a command has a space/args, stop showing the command menu.
|
|
324
|
+
if (/\s/.test(line))
|
|
325
|
+
return [];
|
|
326
|
+
return COMMANDS.filter((c) => c.name.startsWith(line)).map((c) => {
|
|
327
|
+
const needsArg = c.name === '/use' || c.name === '/pull';
|
|
328
|
+
return {
|
|
329
|
+
value: needsArg ? `${c.name} ` : c.name,
|
|
330
|
+
label: `${c.name}${c.args ? ' ' + c.args : ''}`,
|
|
331
|
+
hint: c.help,
|
|
332
|
+
submit: !needsArg,
|
|
333
|
+
};
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
// ── persistent history ──────────────────────────────────
|
|
337
|
+
function historyPath() {
|
|
338
|
+
return node_path_1.default.join((0, config_1.configDir)(), 'history');
|
|
339
|
+
}
|
|
340
|
+
function loadHistory() {
|
|
341
|
+
try {
|
|
342
|
+
return node_fs_1.default.readFileSync(historyPath(), 'utf8').split('\n').filter(Boolean);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
194
347
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
348
|
+
function saveHistory(lines) {
|
|
349
|
+
try {
|
|
350
|
+
node_fs_1.default.mkdirSync((0, config_1.configDir)(), { recursive: true });
|
|
351
|
+
node_fs_1.default.writeFileSync(historyPath(), lines.slice(-200).join('\n') + '\n', 'utf8');
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
/* history is best-effort */
|
|
355
|
+
}
|
|
197
356
|
}
|
|
198
357
|
async function runShell(opts = {}) {
|
|
199
358
|
printBanner();
|
|
200
359
|
const history = [];
|
|
201
|
-
|
|
360
|
+
const cmdHistory = loadHistory();
|
|
361
|
+
const reader = new linereader_1.LineReader({
|
|
362
|
+
prompt: brand(' › '),
|
|
363
|
+
promptWidth: 4,
|
|
364
|
+
suggest,
|
|
365
|
+
history: cmdHistory,
|
|
366
|
+
});
|
|
367
|
+
const remember = (line) => {
|
|
368
|
+
if (line && line !== cmdHistory[cmdHistory.length - 1])
|
|
369
|
+
cmdHistory.push(line);
|
|
370
|
+
};
|
|
202
371
|
try {
|
|
203
372
|
while (true) {
|
|
204
|
-
const
|
|
373
|
+
const raw = await reader.question();
|
|
374
|
+
if (raw === null)
|
|
375
|
+
break; // Ctrl+C / Ctrl+D
|
|
376
|
+
const line = raw.trim();
|
|
205
377
|
if (!line)
|
|
206
378
|
continue;
|
|
379
|
+
remember(line);
|
|
207
380
|
// Slash command
|
|
208
381
|
if (line.startsWith('/')) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (/^\/(setup)\b/i.test(line)) {
|
|
212
|
-
rl.close();
|
|
382
|
+
// Commands that open their own prompts run the wizard (its own stdin).
|
|
383
|
+
if (/^\/setup\b/i.test(line)) {
|
|
213
384
|
try {
|
|
214
385
|
await (0, start_1.runStart)({ chat: false, force: true, ollamaUrl: opts.ollamaUrl, docker: opts.remote });
|
|
215
386
|
}
|
|
216
387
|
catch (e) {
|
|
217
388
|
console.error(`\n ${red('Error')}: ${msg(e)}\n`);
|
|
218
389
|
}
|
|
219
|
-
rl = makeRl();
|
|
220
390
|
continue;
|
|
221
391
|
}
|
|
392
|
+
let result;
|
|
222
393
|
try {
|
|
223
394
|
result = await dispatch(line, history, opts);
|
|
224
395
|
}
|
|
@@ -233,14 +404,12 @@ async function runShell(opts = {}) {
|
|
|
233
404
|
// Plain text → chat. Run setup first if needed.
|
|
234
405
|
if (!(0, config_1.loadConfig)()) {
|
|
235
406
|
console.log(`\n No model yet — starting setup.\n`);
|
|
236
|
-
rl.close();
|
|
237
407
|
try {
|
|
238
408
|
await (0, start_1.runStart)({ chat: false, ollamaUrl: opts.ollamaUrl, docker: opts.remote });
|
|
239
409
|
}
|
|
240
410
|
catch (e) {
|
|
241
411
|
console.error(`\n ${red('Error')}: ${msg(e)}\n`);
|
|
242
412
|
}
|
|
243
|
-
rl = makeRl();
|
|
244
413
|
if (!(0, config_1.loadConfig)()) {
|
|
245
414
|
console.log(' Setup not finished — type /setup to try again.\n');
|
|
246
415
|
continue;
|
|
@@ -250,7 +419,6 @@ async function runShell(opts = {}) {
|
|
|
250
419
|
await chat(history, line, opts);
|
|
251
420
|
}
|
|
252
421
|
catch (e) {
|
|
253
|
-
// Drop the failed user turn so history stays consistent.
|
|
254
422
|
if (history[history.length - 1]?.role === 'user')
|
|
255
423
|
history.pop();
|
|
256
424
|
console.error(` ${red('Error')}: ${msg(e)}\n`);
|
|
@@ -258,7 +426,7 @@ async function runShell(opts = {}) {
|
|
|
258
426
|
}
|
|
259
427
|
}
|
|
260
428
|
finally {
|
|
261
|
-
|
|
429
|
+
saveHistory(cmdHistory);
|
|
262
430
|
}
|
|
263
431
|
console.log(green('\n Bye.\n'));
|
|
264
432
|
}
|