@holt-os/holt 0.15.0 → 0.15.1
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/README.md +8 -0
- package/dist/cli.js +28 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -494,6 +494,14 @@ It reports, section by section:
|
|
|
494
494
|
- **Always-on / Telegram**: whether a Telegram bot is set up, and a note on hosting the bot on a low-power always-on machine while keeping heavy local models on a bigger one.
|
|
495
495
|
- **Recommended next steps**: a short checklist built from whatever gaps it found.
|
|
496
496
|
|
|
497
|
+
And when you would rather not do the steps yourself:
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
holt doctor --fix
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
`--fix` repairs the common problems in one go: starts Ollama when it is installed but not running, downloads the missing embed model, upgrades any memories saved while embeddings were off, and reports a damaged-config repair if one happened. It ends with a "Repairs" section listing exactly what it did (or "Nothing needed repair"). Every Holt error message points here, so the answer to "something is off" is always the same one command.
|
|
504
|
+
|
|
497
505
|
It is read-only advice: it changes nothing, needs no trust, and always exits cleanly even when a probe fails.
|
|
498
506
|
|
|
499
507
|
The RAM-to-model table lives in `src/specs.ts` (`LOCAL_MODEL_RECS` / `recommendLocalModel`), the single source of truth the wiki maintainer reads too.
|
package/dist/cli.js
CHANGED
|
@@ -98,6 +98,18 @@ function createStatusBar() {
|
|
|
98
98
|
detach
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
+
async function askYesNo(ask, question, def) {
|
|
102
|
+
for (let tries = 0; tries < 3; tries++) {
|
|
103
|
+
const raw = await ask(question);
|
|
104
|
+
if (raw === null) return def;
|
|
105
|
+
const a = raw.trim().toLowerCase();
|
|
106
|
+
if (a === "") return def;
|
|
107
|
+
if (a === "y" || a === "yes") return true;
|
|
108
|
+
if (a === "n" || a === "no") return false;
|
|
109
|
+
console.log(c.dim(` Just "y" or "n" please (enter = ${def ? "yes" : "no"}). You typed "${raw.trim()}".`));
|
|
110
|
+
}
|
|
111
|
+
return def;
|
|
112
|
+
}
|
|
101
113
|
function createReader() {
|
|
102
114
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
103
115
|
const buffer = [];
|
|
@@ -155,8 +167,7 @@ async function ensureTrusted(ask) {
|
|
|
155
167
|
console.log("\n" + c.accent("Trust this folder?"));
|
|
156
168
|
console.log(" " + ws);
|
|
157
169
|
console.log(c.dim(" Holt will read and write here: its config, memory, and any files you ask a brain to touch."));
|
|
158
|
-
|
|
159
|
-
if (ans === "y" || ans === "yes") {
|
|
170
|
+
if (await askYesNo(ask, " Trust and continue? [y/N] ", false)) {
|
|
160
171
|
trustDir(ws);
|
|
161
172
|
console.log(c.green(" Trusted.") + c.dim(" (remembered for next time)") + "\n");
|
|
162
173
|
return true;
|
|
@@ -1369,9 +1380,9 @@ async function setupTelegram(ask) {
|
|
|
1369
1380
|
console.log(c.dim(" Option A: open your new bot in Telegram and send it any message,"));
|
|
1370
1381
|
console.log(c.dim(" then I will auto-detect the chat id."));
|
|
1371
1382
|
console.log(c.dim(" Option B: paste a numeric chat id yourself."));
|
|
1372
|
-
const
|
|
1383
|
+
const autoDetect = await askYesNo(ask, "\n Auto-detect from a message you just sent? [Y/n] ", true);
|
|
1373
1384
|
let allowedChatId = null;
|
|
1374
|
-
if (
|
|
1385
|
+
if (autoDetect) {
|
|
1375
1386
|
console.log(c.dim("\n Checking for a recent message..."));
|
|
1376
1387
|
const updates = await getUpdates(0, token);
|
|
1377
1388
|
allowedChatId = latestChatId(updates);
|
|
@@ -1912,8 +1923,7 @@ async function runQuestions(ask, depth) {
|
|
|
1912
1923
|
return out;
|
|
1913
1924
|
}
|
|
1914
1925
|
async function askKeepExcerpt(ask) {
|
|
1915
|
-
|
|
1916
|
-
return a === "y" || a === "yes";
|
|
1926
|
+
return askYesNo(ask, " Store a short excerpt so Holt can match your tone directly? [y/N] ", false);
|
|
1917
1927
|
}
|
|
1918
1928
|
async function addFileSample(ask, file, v) {
|
|
1919
1929
|
const path = resolve(process.cwd(), file);
|
|
@@ -2161,12 +2171,10 @@ async function init() {
|
|
|
2161
2171
|
const toInstall = chosen.filter((id) => !isInstalled(BRAIN_DEFS[id].command));
|
|
2162
2172
|
const loginWanted = /* @__PURE__ */ new Set();
|
|
2163
2173
|
for (const id of toInstall) {
|
|
2164
|
-
|
|
2165
|
-
if (a !== "n" && a !== "no") loginWanted.add(id);
|
|
2174
|
+
if (await askYesNo(ask, ` ${BRAIN_DEFS[id].label} is not installed. Sign in after install? [Y/n] `, true)) loginWanted.add(id);
|
|
2166
2175
|
}
|
|
2167
2176
|
const connectedApiBrains = [];
|
|
2168
|
-
|
|
2169
|
-
if (apiAns === "y" || apiAns === "yes") {
|
|
2177
|
+
if (await askYesNo(ask, "\nAlso connect a direct API brain (raw key, no CLI needed)? [y/N] ", false)) {
|
|
2170
2178
|
const holder = defaultConfig();
|
|
2171
2179
|
const brain = await connectApiBrain(ask, holder);
|
|
2172
2180
|
if (brain) connectedApiBrains.push(brain);
|
|
@@ -2195,13 +2203,11 @@ Default brain? [${chosen.join("/")}] (${defPick}): `) ?? "").trim();
|
|
|
2195
2203
|
} else {
|
|
2196
2204
|
const ollamaHere = isInstalled("ollama");
|
|
2197
2205
|
const q = ollamaHere ? `Semantic memory needs a local embed model. Pull ${EMBED_MODEL} with Ollama now? [Y/n] ` : "Enable private semantic memory? Installs Ollama plus a small local embed model. Everything stays on your machine. [Y/n] ";
|
|
2198
|
-
|
|
2199
|
-
wantMemorySetup = a !== "n" && a !== "no";
|
|
2206
|
+
wantMemorySetup = await askYesNo(ask, "\n" + q, true);
|
|
2200
2207
|
if (!wantMemorySetup) console.log(c.dim(' Okay. Memory still works with keyword recall; run "holt init" again anytime.'));
|
|
2201
2208
|
}
|
|
2202
2209
|
if (!loadTelegramConfig()) {
|
|
2203
|
-
|
|
2204
|
-
if (tgAns === "y" || tgAns === "yes") await setupTelegram(ask);
|
|
2210
|
+
if (await askYesNo(ask, "\nChat with Holt from your phone over Telegram? [y/N] ", false)) await setupTelegram(ask);
|
|
2205
2211
|
}
|
|
2206
2212
|
close();
|
|
2207
2213
|
for (const id of toInstall) {
|
|
@@ -2261,9 +2267,9 @@ Default brain? [${chosen.join("/")}] (${defPick}): `) ?? "").trim();
|
|
|
2261
2267
|
console.log(c.dim('No brain is ready yet. Install one, then run "holt init" again.\n'));
|
|
2262
2268
|
}
|
|
2263
2269
|
const voiceReader = createReader();
|
|
2264
|
-
const
|
|
2270
|
+
const voiceYes = await askYesNo(voiceReader.ask, "Want Holt to learn how you write, so it can draft in your voice? [y/N] ", false);
|
|
2265
2271
|
voiceReader.close();
|
|
2266
|
-
if (
|
|
2272
|
+
if (voiceYes) {
|
|
2267
2273
|
await voiceInterview();
|
|
2268
2274
|
} else {
|
|
2269
2275
|
console.log(c.dim(' Skipped. Run "holt voice" anytime to set up your writing voice.\n'));
|
|
@@ -4222,9 +4228,9 @@ async function chat() {
|
|
|
4222
4228
|
}
|
|
4223
4229
|
let cfg = loadConfig();
|
|
4224
4230
|
if (!cfg || !cfg.defaultBrain) {
|
|
4225
|
-
const
|
|
4231
|
+
const setupYes = await askYesNo(ask, c.dim("No Holt setup in this folder. Set it up now? [Y/n] "), true);
|
|
4226
4232
|
close();
|
|
4227
|
-
if (
|
|
4233
|
+
if (!setupYes) {
|
|
4228
4234
|
console.log(c.dim(' Run "holt init" here when ready.\n'));
|
|
4229
4235
|
return;
|
|
4230
4236
|
}
|
|
@@ -4426,8 +4432,7 @@ async function chat() {
|
|
|
4426
4432
|
const outside = findOutsidePaths(line, workspace());
|
|
4427
4433
|
for (const dir of outside) {
|
|
4428
4434
|
if (grantedDirs.has(dir)) continue;
|
|
4429
|
-
|
|
4430
|
-
if (ans === "y" || ans === "yes") {
|
|
4435
|
+
if (await askYesNo(ask, c.dim(` Allow this session to access ${dir} (outside this folder)? [y/N] `), false)) {
|
|
4431
4436
|
grantedDirs.add(dir);
|
|
4432
4437
|
console.log(c.green(` granted this session: ${dir}`));
|
|
4433
4438
|
} else {
|
|
@@ -7384,7 +7389,7 @@ function holtTools() {
|
|
|
7384
7389
|
}
|
|
7385
7390
|
|
|
7386
7391
|
// src/version.ts
|
|
7387
|
-
var VERSION = "0.15.
|
|
7392
|
+
var VERSION = "0.15.1";
|
|
7388
7393
|
|
|
7389
7394
|
// src/commands/mcp.ts
|
|
7390
7395
|
function printSetup() {
|
|
@@ -8695,8 +8700,7 @@ async function update() {
|
|
|
8695
8700
|
}
|
|
8696
8701
|
console.log(` Newer version available: ${c.bold(latest)}`);
|
|
8697
8702
|
if (isBrewInstall()) {
|
|
8698
|
-
|
|
8699
|
-
if (a2 === "n" || a2 === "no") {
|
|
8703
|
+
if (!await askYesNo(ask, " Update now via Homebrew? [Y/n] ", true)) {
|
|
8700
8704
|
console.log(c.dim(" Later, then. The command is: brew upgrade holt\n"));
|
|
8701
8705
|
return;
|
|
8702
8706
|
}
|
|
@@ -8706,8 +8710,7 @@ async function update() {
|
|
|
8706
8710
|
else console.log(c.dim("\n Homebrew reported a problem above. You can retry with: brew upgrade holt\n"));
|
|
8707
8711
|
return;
|
|
8708
8712
|
}
|
|
8709
|
-
|
|
8710
|
-
if (a === "n" || a === "no") {
|
|
8713
|
+
if (!await askYesNo(ask, " Update now? [Y/n] ", true)) {
|
|
8711
8714
|
console.log(c.dim(" Later, then. The command is: npm install -g @holt-os/holt\n"));
|
|
8712
8715
|
return;
|
|
8713
8716
|
}
|