@holt-os/holt 0.17.0 → 0.18.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/README.md +13 -4
- package/dist/cli.js +78 -99
- package/package.json +2 -2
- package/skills/audit/SKILL.md +3 -3
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
- **Any brain, one assistant.** Bare `holt` launches a real interactive brain (Claude Code, Codex, or Gemini) branded as Holt, or you connect a direct API brain with your own key. Switch mid-conversation and keep the full context.
|
|
22
22
|
- **Private memory you can see.** Per-folder semantic recall and distilled facts, an interactive knowledge graph (`holt graph`), and a self-maintaining wiki (`holt wiki`) over everything you tell it. Nothing leaves your machine.
|
|
23
23
|
- **Ambient by default.** `holt hook` wires memory into Claude Code so it recalls and remembers with no manual step, and an MCP server exposes the same memory to Cursor and Codex.
|
|
24
|
-
- **Runs your work.** Run a task once, on a schedule, or as a named routine, and reach it from your phone over Telegram.
|
|
24
|
+
- **Runs your work.** Run a task once, on a schedule, or as a named routine, and reach it from your phone over Telegram. Real OS timers on macOS, Linux, and Windows.
|
|
25
25
|
- **Useful on day one.** `/skill onboard` interviews you and fills memory in about fifteen minutes, `/skill audit` shows what is still missing, and `/skill level-up` turns one manual chore a week into something Holt does.
|
|
26
26
|
- **Extensible, zero-infra.** Thirteen built-in skills plus a git-based community registry (`holt skill search`) in the portable `SKILL.md` format.
|
|
27
27
|
- **Writes in your voice.** `holt write` drafts in a style Holt learns from you, with built-in anti-AI checks.
|
|
@@ -63,6 +63,14 @@ That is it. Bare `holt` sets the folder up the first time (trust, brain, memory
|
|
|
63
63
|
|
|
64
64
|
Prefer to step through setup on its own first? `holt init` still does that, then `holt` starts the session.
|
|
65
65
|
|
|
66
|
+
Then, in that first session, run:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
/skill onboard
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
An empty Holt gives generic answers, which is the usual reason people install it and drift away. `onboard` is a fifteen minute interview that fills memory with who you are and what you are working on, and ends by doing one real piece of your work. Everything else gets better once it knows you.
|
|
73
|
+
|
|
66
74
|
## What bare `holt` does
|
|
67
75
|
|
|
68
76
|
`holt` (with no command) is the front door: **your assistant, with memory of you.**
|
|
@@ -441,7 +449,7 @@ Options: `--brain <id>` pick a brain, `--out <file>` also write the reply to a f
|
|
|
441
449
|
|
|
442
450
|
### holt schedule
|
|
443
451
|
|
|
444
|
-
Run a task automatically on a timer, using your OS scheduler (launchd on macOS, cron on Linux). A scheduled run behaves exactly like typing `holt run` in that folder.
|
|
452
|
+
Run a task automatically on a timer, using your OS scheduler (launchd on macOS, cron on Linux, Task Scheduler on Windows). A scheduled run behaves exactly like typing `holt run` in that folder.
|
|
445
453
|
|
|
446
454
|
```bash
|
|
447
455
|
holt schedule add "summarize my inbox and flag what is urgent" 07:00 --notify
|
|
@@ -490,7 +498,7 @@ holt routine remove brief # deletes the routine and its OS timer, if any
|
|
|
490
498
|
|
|
491
499
|
Sources: give exactly one of `--skill <name>`, `--task "<prompt>"`, or `--template <t>`. A skill routine splices that skill's `SKILL.md` body into the prompt at run time; a task routine uses the prompt as-is.
|
|
492
500
|
|
|
493
|
-
Scheduling: `--at HH:MM` (24h, daily) installs an OS timer through the same scheduler `holt schedule` uses (launchd on macOS, cron on Linux) whose command is `holt routine run <name> --quiet`. Omit `--at` for a manual, run-on-demand routine. Removing the routine removes its timer.
|
|
501
|
+
Scheduling: `--at HH:MM` (24h, daily) installs an OS timer through the same scheduler `holt schedule` uses (launchd on macOS, cron on Linux, Task Scheduler on Windows) whose command is `holt routine run <name> --quiet`. Omit `--at` for a manual, run-on-demand routine. Removing the routine removes its timer.
|
|
494
502
|
|
|
495
503
|
Output routing: by default the result prints to stdout. `--out <file>` also writes it to a file (relative to the routine's workspace); `--notify` pushes it to Telegram (guarded cleanly when Telegram is not set up). Both `--out` and `--notify` can also be passed to `holt routine run` for a single run. In `--quiet` mode (what the scheduler uses) stdout is suppressed but `--out` and `--notify` still fire.
|
|
496
504
|
|
|
@@ -622,7 +630,8 @@ Built in always-shippable phases toward a full-vision v1:
|
|
|
622
630
|
4. **Knowledge graph**: see and navigate your own memory with `holt graph` *(shipped)*
|
|
623
631
|
5. **Everywhere**: MCP server so other tools read Holt's memory, plus `holt run`, scheduling, and Telegram *(shipped)*
|
|
624
632
|
6. **Knowledge wiki**: LLM-maintained, cross-linked, regenerable pages over your memory with `holt wiki` *(shipped)*
|
|
625
|
-
7. **
|
|
633
|
+
7. **Onboarding**: a day-one interview that fills memory, plus the weekly audit and level-up ritual *(shipped)*
|
|
634
|
+
8. **Next**: docs site, skill registry publishing, more channels
|
|
626
635
|
|
|
627
636
|
## Contributing
|
|
628
637
|
|
package/dist/cli.js
CHANGED
|
@@ -2515,23 +2515,37 @@ function buildCronLine(job, holtPath) {
|
|
|
2515
2515
|
const command = buildCommand(job, holtPath);
|
|
2516
2516
|
return `${minute} ${hour} * * * ${command} # ${CRON_MARKER}${job.id}`;
|
|
2517
2517
|
}
|
|
2518
|
-
function
|
|
2519
|
-
|
|
2518
|
+
function taskName(id) {
|
|
2519
|
+
return `Holt ${id}`;
|
|
2520
|
+
}
|
|
2521
|
+
function cmdScriptPath(id) {
|
|
2522
|
+
return join8(GLOBAL_DIR, "tasks", `${id}.cmd`);
|
|
2523
|
+
}
|
|
2524
|
+
function cmdQuote(s) {
|
|
2525
|
+
return /[\s&()[\]{}^=;!'+,`~|<>"]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
2526
|
+
}
|
|
2527
|
+
function buildWindowsScript(job, holtPath) {
|
|
2528
|
+
const holt = cmdQuote(holtPath);
|
|
2529
|
+
const lines = ["@echo off", `cd /d ${cmdQuote(job.workspace)}`];
|
|
2520
2530
|
if (job.runArgs && job.runArgs.length > 0) {
|
|
2521
|
-
|
|
2531
|
+
lines.push(`${holt} ${job.runArgs.map(cmdQuote).join(" ")} --quiet`);
|
|
2522
2532
|
} else {
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2533
|
+
const log = cmdQuote(logPath(job.id));
|
|
2534
|
+
let run2 = `${holt} run ${cmdQuote(job.task)}`;
|
|
2535
|
+
if (job.brain) run2 += ` --brain ${cmdQuote(job.brain)}`;
|
|
2536
|
+
run2 += ` --quiet --out ${log}`;
|
|
2537
|
+
lines.push(run2);
|
|
2538
|
+
if (job.notify) {
|
|
2539
|
+
lines.push(`if errorlevel 1 exit /b 1`);
|
|
2540
|
+
lines.push(`type ${log} | ${holt} notify`);
|
|
2541
|
+
}
|
|
2526
2542
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
name: `Holt ${job.id}`
|
|
2534
|
-
};
|
|
2543
|
+
return lines.join("\r\n") + "\r\n";
|
|
2544
|
+
}
|
|
2545
|
+
function buildSchtasksArgs(job, scriptPath) {
|
|
2546
|
+
const { hour, minute } = parseWhen(job.when);
|
|
2547
|
+
const hhmm = `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
|
|
2548
|
+
return ["/Create", "/F", "/SC", "DAILY", "/ST", hhmm, "/TN", taskName(job.id), "/TR", scriptPath];
|
|
2535
2549
|
}
|
|
2536
2550
|
function stripCronLines(crontab, id) {
|
|
2537
2551
|
const marker = `# ${CRON_MARKER}${id}`;
|
|
@@ -7533,7 +7547,7 @@ function holtTools() {
|
|
|
7533
7547
|
}
|
|
7534
7548
|
|
|
7535
7549
|
// src/version.ts
|
|
7536
|
-
var VERSION = "0.
|
|
7550
|
+
var VERSION = "0.18.0";
|
|
7537
7551
|
|
|
7538
7552
|
// src/commands/mcp.ts
|
|
7539
7553
|
function printSetup() {
|
|
@@ -7846,29 +7860,42 @@ async function addCmd(rest) {
|
|
|
7846
7860
|
console.log(` workspace ${job.workspace}`);
|
|
7847
7861
|
if (job.notify) console.log(` notify on (pushes output to Telegram)`);
|
|
7848
7862
|
console.log(` log ${logPath(job.id)}`);
|
|
7849
|
-
|
|
7850
|
-
else if (process.platform === "linux") installLinux(job, holtPath);
|
|
7851
|
-
else printManualInstall(job, holtPath);
|
|
7863
|
+
installForPlatform(job, holtPath);
|
|
7852
7864
|
console.log("");
|
|
7853
7865
|
}
|
|
7854
|
-
function
|
|
7855
|
-
if (process.platform
|
|
7866
|
+
function installForPlatform(job, holtPath) {
|
|
7867
|
+
if (process.platform === "darwin") installDarwin(job, holtPath);
|
|
7868
|
+
else if (process.platform === "linux") installLinux(job, holtPath);
|
|
7869
|
+
else if (process.platform === "win32") installWindows(job, holtPath);
|
|
7870
|
+
else {
|
|
7856
7871
|
console.log(c.dim("\n Your OS has no built-in installer. Install this entry yourself:"));
|
|
7857
7872
|
console.log(" " + buildCronLine(job, holtPath));
|
|
7858
|
-
return;
|
|
7859
7873
|
}
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7874
|
+
}
|
|
7875
|
+
function installWindows(job, holtPath) {
|
|
7876
|
+
const script = cmdScriptPath(job.id);
|
|
7877
|
+
mkdirSync15(dirname9(script), { recursive: true });
|
|
7878
|
+
writeFileSync17(script, buildWindowsScript(job, holtPath), "utf8");
|
|
7879
|
+
const res = spawnSync5("schtasks", buildSchtasksArgs(job, script), { encoding: "utf8" });
|
|
7880
|
+
if (res.status === 0) {
|
|
7881
|
+
console.log(c.green(" Registered with Task Scheduler."));
|
|
7882
|
+
} else {
|
|
7883
|
+
console.log(c.dim(" Wrote the task script, but schtasks did not confirm."));
|
|
7884
|
+
console.log(c.dim(" Register it yourself with:"));
|
|
7869
7885
|
console.log(
|
|
7870
|
-
c.dim(
|
|
7886
|
+
c.dim(` schtasks /Create /F /SC DAILY /ST ${job.when} /TN "${taskName(job.id)}" /TR "${script}"`)
|
|
7871
7887
|
);
|
|
7888
|
+
const why = (res.stderr || "").trim() || (res.error ? res.error.message : "");
|
|
7889
|
+
if (why) console.log(c.dim(` (${why})`));
|
|
7890
|
+
}
|
|
7891
|
+
console.log(c.dim(` task: ${taskName(job.id)}`));
|
|
7892
|
+
console.log(c.dim(` script: ${script}`));
|
|
7893
|
+
}
|
|
7894
|
+
function removeWindows(id) {
|
|
7895
|
+
spawnSync5("schtasks", ["/Delete", "/F", "/TN", taskName(id)], { encoding: "utf8" });
|
|
7896
|
+
try {
|
|
7897
|
+
rmSync7(cmdScriptPath(id));
|
|
7898
|
+
} catch {
|
|
7872
7899
|
}
|
|
7873
7900
|
}
|
|
7874
7901
|
function listCmd2() {
|
|
@@ -7902,6 +7929,11 @@ function removeLinux(id) {
|
|
|
7902
7929
|
const next = stripCronLines(body, id);
|
|
7903
7930
|
spawnSync5("crontab", ["-"], { input: next, encoding: "utf8" });
|
|
7904
7931
|
}
|
|
7932
|
+
function removeForPlatform(id) {
|
|
7933
|
+
if (process.platform === "darwin") removeDarwin(id);
|
|
7934
|
+
else if (process.platform === "linux") removeLinux(id);
|
|
7935
|
+
else if (process.platform === "win32") removeWindows(id);
|
|
7936
|
+
}
|
|
7905
7937
|
function removeCmd(rest) {
|
|
7906
7938
|
const id = rest[0];
|
|
7907
7939
|
if (!id) {
|
|
@@ -7912,8 +7944,7 @@ function removeCmd(rest) {
|
|
|
7912
7944
|
const before = loadJobs();
|
|
7913
7945
|
const existed = before.some((j) => j.id === id);
|
|
7914
7946
|
removeJob(id);
|
|
7915
|
-
|
|
7916
|
-
else if (process.platform === "linux") removeLinux(id);
|
|
7947
|
+
removeForPlatform(id);
|
|
7917
7948
|
if (existed) console.log("\n" + c.green(` Removed schedule ${id}.`) + "\n");
|
|
7918
7949
|
else {
|
|
7919
7950
|
console.error(c.dim(`
|
|
@@ -7950,9 +7981,8 @@ async function schedule(sub, rest = []) {
|
|
|
7950
7981
|
}
|
|
7951
7982
|
|
|
7952
7983
|
// src/commands/routine.ts
|
|
7953
|
-
import {
|
|
7954
|
-
import {
|
|
7955
|
-
import { dirname as dirname10, resolve as resolve7 } from "path";
|
|
7984
|
+
import { writeFileSync as writeFileSync19 } from "fs";
|
|
7985
|
+
import { resolve as resolve7 } from "path";
|
|
7956
7986
|
|
|
7957
7987
|
// src/routines.ts
|
|
7958
7988
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync18, mkdirSync as mkdirSync16 } from "fs";
|
|
@@ -8031,70 +8061,19 @@ function jobForRoutine(r) {
|
|
|
8031
8061
|
function routineJobId(name) {
|
|
8032
8062
|
return `routine-${sanitizeRoutineName(name)}`;
|
|
8033
8063
|
}
|
|
8034
|
-
function installDarwin2(job, holtPath) {
|
|
8035
|
-
const path = plistPath(job.id);
|
|
8036
|
-
mkdirSync17(dirname10(path), { recursive: true });
|
|
8037
|
-
writeFileSync19(path, buildLaunchdPlist(job, holtPath), "utf8");
|
|
8038
|
-
const res = spawnSync6("launchctl", ["load", "-w", path], { encoding: "utf8" });
|
|
8039
|
-
if (res.status === 0) {
|
|
8040
|
-
console.log(c.green(" Loaded into launchd."));
|
|
8041
|
-
} else {
|
|
8042
|
-
console.log(c.dim(" Wrote the plist, but launchctl load did not confirm."));
|
|
8043
|
-
console.log(c.dim(` Load it yourself with: launchctl load -w ${path}`));
|
|
8044
|
-
if (res.stderr && res.stderr.trim()) console.log(c.dim(` (${res.stderr.trim()})`));
|
|
8045
|
-
}
|
|
8046
|
-
console.log(c.dim(` plist: ${path}`));
|
|
8047
|
-
}
|
|
8048
|
-
function currentCrontab2() {
|
|
8049
|
-
const res = spawnSync6("crontab", ["-l"], { encoding: "utf8" });
|
|
8050
|
-
return res.status === 0 && typeof res.stdout === "string" ? res.stdout : "";
|
|
8051
|
-
}
|
|
8052
|
-
function writeCrontab2(body) {
|
|
8053
|
-
const res = spawnSync6("crontab", ["-"], { input: body, encoding: "utf8" });
|
|
8054
|
-
return res.status === 0;
|
|
8055
|
-
}
|
|
8056
|
-
function installLinux2(job, holtPath) {
|
|
8057
|
-
const line = buildCronLine(job, holtPath);
|
|
8058
|
-
const next = appendCronLine(currentCrontab2(), line);
|
|
8059
|
-
if (writeCrontab2(next)) {
|
|
8060
|
-
console.log(c.green(" Added to your crontab."));
|
|
8061
|
-
console.log(c.dim(` line: ${line}`));
|
|
8062
|
-
} else {
|
|
8063
|
-
console.log(c.dim(" Could not update the crontab automatically. Add this line yourself:"));
|
|
8064
|
-
console.log(" " + line);
|
|
8065
|
-
}
|
|
8066
|
-
}
|
|
8067
8064
|
function installSchedule(r) {
|
|
8068
8065
|
const holtPath = resolveHoltPath();
|
|
8069
8066
|
const job = jobForRoutine(r);
|
|
8070
8067
|
removeSchedule(r.name);
|
|
8071
8068
|
addJob(job);
|
|
8072
|
-
|
|
8073
|
-
else if (process.platform === "linux") installLinux2(job, holtPath);
|
|
8074
|
-
else printManualInstall(job, holtPath);
|
|
8075
|
-
}
|
|
8076
|
-
function removeScheduleDarwin(id) {
|
|
8077
|
-
const path = plistPath(id);
|
|
8078
|
-
if (existsSync19(path)) {
|
|
8079
|
-
spawnSync6("launchctl", ["unload", path], { encoding: "utf8" });
|
|
8080
|
-
try {
|
|
8081
|
-
rmSync8(path);
|
|
8082
|
-
} catch {
|
|
8083
|
-
}
|
|
8084
|
-
}
|
|
8085
|
-
}
|
|
8086
|
-
function removeScheduleLinux(id) {
|
|
8087
|
-
const body = currentCrontab2();
|
|
8088
|
-
const next = stripCronLines(body, id);
|
|
8089
|
-
writeCrontab2(next);
|
|
8069
|
+
installForPlatform(job, holtPath);
|
|
8090
8070
|
}
|
|
8091
8071
|
function removeSchedule(name) {
|
|
8092
8072
|
const id = routineJobId(name);
|
|
8093
8073
|
const existed = loadJobs().some((j) => j.id === id);
|
|
8094
8074
|
removeJob(id);
|
|
8095
8075
|
if (!existed) return;
|
|
8096
|
-
|
|
8097
|
-
else if (process.platform === "linux") removeScheduleLinux(id);
|
|
8076
|
+
removeForPlatform(id);
|
|
8098
8077
|
}
|
|
8099
8078
|
function parseAdd2(rest) {
|
|
8100
8079
|
const opts = { notify: false };
|
|
@@ -8449,8 +8428,8 @@ function readStdin3() {
|
|
|
8449
8428
|
}
|
|
8450
8429
|
|
|
8451
8430
|
// src/commands/doctor.ts
|
|
8452
|
-
import { spawn as spawn5, spawnSync as
|
|
8453
|
-
import { existsSync as
|
|
8431
|
+
import { spawn as spawn5, spawnSync as spawnSync6 } from "child_process";
|
|
8432
|
+
import { existsSync as existsSync19 } from "fs";
|
|
8454
8433
|
|
|
8455
8434
|
// src/specs.ts
|
|
8456
8435
|
import os from "os";
|
|
@@ -8612,7 +8591,7 @@ async function fixSemanticMemory(fixed) {
|
|
|
8612
8591
|
}
|
|
8613
8592
|
if (!tags.some((t) => t.startsWith(EMBED_MODEL))) {
|
|
8614
8593
|
note(`The "${EMBED_MODEL}" model is missing. Downloading it (one-time, ~275 MB)...`);
|
|
8615
|
-
const r =
|
|
8594
|
+
const r = spawnSync6("ollama", ["pull", EMBED_MODEL], { stdio: "inherit" });
|
|
8616
8595
|
if (r.status !== 0) {
|
|
8617
8596
|
warn(`Could not download ${EMBED_MODEL}. Check your internet connection and retry.`);
|
|
8618
8597
|
return false;
|
|
@@ -8675,7 +8654,7 @@ async function doctor(args = []) {
|
|
|
8675
8654
|
}
|
|
8676
8655
|
if (embedOk) {
|
|
8677
8656
|
good(`Ollama reachable and "${EMBED_MODEL}" is present. Memory recall is semantic, private, and local.`);
|
|
8678
|
-
if (fix &&
|
|
8657
|
+
if (fix && existsSync19(wsHoltDir())) {
|
|
8679
8658
|
const missing = loadTurns().filter((t) => !Array.isArray(t.emb)).length;
|
|
8680
8659
|
if (missing > 0) {
|
|
8681
8660
|
note(`${missing} memories in this folder lack embeddings. Upgrading them...`);
|
|
@@ -8794,12 +8773,12 @@ async function tour() {
|
|
|
8794
8773
|
}
|
|
8795
8774
|
|
|
8796
8775
|
// src/commands/reset.ts
|
|
8797
|
-
import { existsSync as
|
|
8776
|
+
import { existsSync as existsSync20, rmSync as rmSync8 } from "fs";
|
|
8798
8777
|
async function reset() {
|
|
8799
8778
|
const { ask, close } = createReader();
|
|
8800
8779
|
try {
|
|
8801
8780
|
const dir = wsHoltDir();
|
|
8802
|
-
if (!
|
|
8781
|
+
if (!existsSync20(dir)) {
|
|
8803
8782
|
console.log(c.dim("\n Nothing to reset: Holt has no settings or memory in this folder.\n"));
|
|
8804
8783
|
return;
|
|
8805
8784
|
}
|
|
@@ -8818,7 +8797,7 @@ async function reset() {
|
|
|
8818
8797
|
console.log(c.dim(" Cancelled. Nothing was changed.\n"));
|
|
8819
8798
|
return;
|
|
8820
8799
|
}
|
|
8821
|
-
|
|
8800
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
8822
8801
|
console.log(c.green("\n Done. This folder is a clean slate.") + c.dim(' Run "holt" to set it up again.\n'));
|
|
8823
8802
|
} finally {
|
|
8824
8803
|
close();
|
|
@@ -8826,7 +8805,7 @@ async function reset() {
|
|
|
8826
8805
|
}
|
|
8827
8806
|
|
|
8828
8807
|
// src/commands/update.ts
|
|
8829
|
-
import { spawnSync as
|
|
8808
|
+
import { spawnSync as spawnSync7 } from "child_process";
|
|
8830
8809
|
import { realpathSync as realpathSync4 } from "fs";
|
|
8831
8810
|
async function latestVersion() {
|
|
8832
8811
|
try {
|
|
@@ -8868,7 +8847,7 @@ async function update() {
|
|
|
8868
8847
|
console.log(c.dim(" Later, then. The command is: brew upgrade holt\n"));
|
|
8869
8848
|
return;
|
|
8870
8849
|
}
|
|
8871
|
-
const r2 =
|
|
8850
|
+
const r2 = spawnSync7("brew", ["upgrade", "holt"], { stdio: "inherit" });
|
|
8872
8851
|
if (r2.status === 0) console.log(c.green(`
|
|
8873
8852
|
Updated to ${latest}.`) + "\n");
|
|
8874
8853
|
else console.log(c.dim("\n Homebrew reported a problem above. You can retry with: brew upgrade holt\n"));
|
|
@@ -8878,7 +8857,7 @@ async function update() {
|
|
|
8878
8857
|
console.log(c.dim(" Later, then. The command is: npm install -g @holt-os/holt\n"));
|
|
8879
8858
|
return;
|
|
8880
8859
|
}
|
|
8881
|
-
const r =
|
|
8860
|
+
const r = spawnSync7("npm", ["install", "-g", "@holt-os/holt"], { stdio: "inherit" });
|
|
8882
8861
|
if (r.status === 0) {
|
|
8883
8862
|
console.log(c.green(`
|
|
8884
8863
|
Updated to ${latest}.`) + "\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holt-os/holt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "An open-source personal agent OS: any LLM, private memory you can see and walk.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"build": "tsup src/cli.ts --format esm --clean",
|
|
45
45
|
"start": "node dist/cli.js",
|
|
46
46
|
"typecheck": "tsc --noEmit",
|
|
47
|
-
"test": "tsx scripts/specs.test.ts && tsx scripts/skillcompiler.test.ts",
|
|
47
|
+
"test": "tsx scripts/specs.test.ts && tsx scripts/skillcompiler.test.ts && tsx scripts/scheduler.test.ts",
|
|
48
48
|
"release": "bash scripts/release.sh"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
package/skills/audit/SKILL.md
CHANGED
|
@@ -86,9 +86,9 @@ an essay.
|
|
|
86
86
|
- **Hand-edited facts.** Facts added by editing `facts.md` directly are never
|
|
87
87
|
embedded, so they never come back through recall. They must be re-added with
|
|
88
88
|
`holt memory add`.
|
|
89
|
-
- **
|
|
90
|
-
time
|
|
91
|
-
|
|
89
|
+
- **Timers need the machine awake.** A scheduled job fires only if the computer
|
|
90
|
+
is on at that time; a missed run is skipped, not caught up. If rung four looks
|
|
91
|
+
solid but the log file is empty, check that first.
|
|
92
92
|
- **Automation above an empty memory.** If Run looks solid while Know is thin,
|
|
93
93
|
say so bluntly. That setup produces confident wrong output on a timer, and it
|
|
94
94
|
is the most expensive failure on this list.
|