bajaclaw 0.10.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/LICENSE +21 -0
- package/README.md +639 -0
- package/bin/bajaclaw.js +35 -0
- package/bin/create-bajaclaw.js +17 -0
- package/dist/agent.d.ts +29 -0
- package/dist/agent.js +231 -0
- package/dist/agent.js.map +1 -0
- package/dist/api/server.d.ts +15 -0
- package/dist/api/server.js +215 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/translate.d.ts +61 -0
- package/dist/api/translate.js +109 -0
- package/dist/api/translate.js.map +1 -0
- package/dist/banner.d.ts +7 -0
- package/dist/banner.js +31 -0
- package/dist/banner.js.map +1 -0
- package/dist/channels/gateway.d.ts +1 -0
- package/dist/channels/gateway.js +76 -0
- package/dist/channels/gateway.js.map +1 -0
- package/dist/claude.d.ts +9 -0
- package/dist/claude.js +170 -0
- package/dist/claude.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +303 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/channel.d.ts +3 -0
- package/dist/commands/channel.js +27 -0
- package/dist/commands/channel.js.map +1 -0
- package/dist/commands/compact.d.ts +8 -0
- package/dist/commands/compact.js +60 -0
- package/dist/commands/compact.js.map +1 -0
- package/dist/commands/daemon.d.ts +7 -0
- package/dist/commands/daemon.js +129 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/dashboard.d.ts +1 -0
- package/dist/commands/dashboard.js +78 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +25 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/dry-run.d.ts +1 -0
- package/dist/commands/dry-run.js +5 -0
- package/dist/commands/dry-run.js.map +1 -0
- package/dist/commands/effort.d.ts +6 -0
- package/dist/commands/effort.js +33 -0
- package/dist/commands/effort.js.map +1 -0
- package/dist/commands/guide.d.ts +4 -0
- package/dist/commands/guide.js +52 -0
- package/dist/commands/guide.js.map +1 -0
- package/dist/commands/health.d.ts +1 -0
- package/dist/commands/health.js +20 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.js +114 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.d.ts +9 -0
- package/dist/commands/mcp.js +63 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/migrate.d.ts +1 -0
- package/dist/commands/migrate.js +58 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/model.d.ts +5 -0
- package/dist/commands/model.js +31 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/persona.d.ts +6 -0
- package/dist/commands/persona.js +67 -0
- package/dist/commands/persona.js.map +1 -0
- package/dist/commands/port.d.ts +15 -0
- package/dist/commands/port.js +88 -0
- package/dist/commands/port.js.map +1 -0
- package/dist/commands/profile.d.ts +4 -0
- package/dist/commands/profile.js +41 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/serve.d.ts +14 -0
- package/dist/commands/serve.js +62 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/setup.d.ts +17 -0
- package/dist/commands/setup.js +228 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/skill.d.ts +7 -0
- package/dist/commands/skill.js +137 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/start.d.ts +6 -0
- package/dist/commands/start.js +25 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +35 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/subagent.d.ts +14 -0
- package/dist/commands/subagent.js +173 -0
- package/dist/commands/subagent.js.map +1 -0
- package/dist/commands/trigger.d.ts +1 -0
- package/dist/commands/trigger.js +13 -0
- package/dist/commands/trigger.js.map +1 -0
- package/dist/commands/uninstall.d.ts +5 -0
- package/dist/commands/uninstall.js +165 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.js +49 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/concurrency.d.ts +1 -0
- package/dist/concurrency.js +17 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +42 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +3 -0
- package/dist/db.js +124 -0
- package/dist/db.js.map +1 -0
- package/dist/delegation.d.ts +6 -0
- package/dist/delegation.js +21 -0
- package/dist/delegation.js.map +1 -0
- package/dist/health-check.d.ts +6 -0
- package/dist/health-check.js +38 -0
- package/dist/health-check.js.map +1 -0
- package/dist/logger.d.ts +11 -0
- package/dist/logger.js +53 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/consumer.d.ts +15 -0
- package/dist/mcp/consumer.js +74 -0
- package/dist/mcp/consumer.js.map +1 -0
- package/dist/mcp/server.d.ts +6 -0
- package/dist/mcp/server.js +260 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/memory/claude-compat.d.ts +4 -0
- package/dist/memory/claude-compat.js +56 -0
- package/dist/memory/claude-compat.js.map +1 -0
- package/dist/memory/compact.d.ts +25 -0
- package/dist/memory/compact.js +195 -0
- package/dist/memory/compact.js.map +1 -0
- package/dist/memory/extract.d.ts +3 -0
- package/dist/memory/extract.js +56 -0
- package/dist/memory/extract.js.map +1 -0
- package/dist/memory/recall.d.ts +5 -0
- package/dist/memory/recall.js +47 -0
- package/dist/memory/recall.js.map +1 -0
- package/dist/model-picker.d.ts +33 -0
- package/dist/model-picker.js +104 -0
- package/dist/model-picker.js.map +1 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.js +49 -0
- package/dist/paths.js.map +1 -0
- package/dist/persona-io.d.ts +5 -0
- package/dist/persona-io.js +29 -0
- package/dist/persona-io.js.map +1 -0
- package/dist/persona.d.ts +12 -0
- package/dist/persona.js +54 -0
- package/dist/persona.js.map +1 -0
- package/dist/prompt.d.ts +5 -0
- package/dist/prompt.js +56 -0
- package/dist/prompt.js.map +1 -0
- package/dist/safety.d.ts +17 -0
- package/dist/safety.js +47 -0
- package/dist/safety.js.map +1 -0
- package/dist/scheduler/cron.d.ts +4 -0
- package/dist/scheduler/cron.js +44 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/index.d.ts +7 -0
- package/dist/scheduler/index.js +15 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/launchd.d.ts +4 -0
- package/dist/scheduler/launchd.js +73 -0
- package/dist/scheduler/launchd.js.map +1 -0
- package/dist/scheduler/schtasks.d.ts +4 -0
- package/dist/scheduler/schtasks.js +45 -0
- package/dist/scheduler/schtasks.js.map +1 -0
- package/dist/scheduler/systemd.d.ts +5 -0
- package/dist/scheduler/systemd.js +86 -0
- package/dist/scheduler/systemd.js.map +1 -0
- package/dist/self-improve.d.ts +4 -0
- package/dist/self-improve.js +48 -0
- package/dist/self-improve.js.map +1 -0
- package/dist/skills/auto-skiller.d.ts +21 -0
- package/dist/skills/auto-skiller.js +156 -0
- package/dist/skills/auto-skiller.js.map +1 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/skills/loader.js +127 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/matcher.d.ts +2 -0
- package/dist/skills/matcher.js +27 -0
- package/dist/skills/matcher.js.map +1 -0
- package/dist/skills/porter.d.ts +27 -0
- package/dist/skills/porter.js +109 -0
- package/dist/skills/porter.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +185 -0
- package/dist/updater.js.map +1 -0
- package/package.json +53 -0
- package/scripts/postinstall.js +33 -0
- package/skills/configure-effort/SKILL.md +36 -0
- package/skills/configure-model/SKILL.md +41 -0
- package/skills/configure-tools/SKILL.md +51 -0
- package/skills/daily-briefing/SKILL.md +19 -0
- package/skills/delegate-to-subagent/SKILL.md +63 -0
- package/skills/email-triage/SKILL.md +21 -0
- package/skills/setup-api/SKILL.md +115 -0
- package/skills/setup-compaction/SKILL.md +102 -0
- package/skills/setup-daemon/SKILL.md +49 -0
- package/skills/setup-dashboard/SKILL.md +39 -0
- package/skills/setup-discord/SKILL.md +54 -0
- package/skills/setup-heartbeat/SKILL.md +51 -0
- package/skills/setup-mcp-port/SKILL.md +54 -0
- package/skills/setup-memory-sync/SKILL.md +45 -0
- package/skills/setup-profile/SKILL.md +44 -0
- package/skills/setup-self-update/SKILL.md +45 -0
- package/skills/setup-subagent/SKILL.md +102 -0
- package/skills/setup-telegram/SKILL.md +54 -0
- package/skills/setup-uninstall/SKILL.md +55 -0
- package/skills/web-research/SKILL.md +20 -0
- package/templates/code/AGENT.md +15 -0
- package/templates/code/HEARTBEAT.md +11 -0
- package/templates/code/SOUL.md +10 -0
- package/templates/code/bajaclaw.config.json +5 -0
- package/templates/code/scripts/launch.bat +4 -0
- package/templates/code/scripts/launch.sh +4 -0
- package/templates/custom/AGENT.md +14 -0
- package/templates/custom/HEARTBEAT.md +11 -0
- package/templates/custom/SOUL.md +10 -0
- package/templates/custom/bajaclaw.config.json +5 -0
- package/templates/custom/scripts/launch.bat +4 -0
- package/templates/custom/scripts/launch.sh +4 -0
- package/templates/outreach/AGENT.md +11 -0
- package/templates/outreach/HEARTBEAT.md +11 -0
- package/templates/outreach/SOUL.md +10 -0
- package/templates/outreach/bajaclaw.config.json +5 -0
- package/templates/outreach/scripts/launch.bat +4 -0
- package/templates/outreach/scripts/launch.sh +4 -0
- package/templates/research/AGENT.md +27 -0
- package/templates/research/HEARTBEAT.md +11 -0
- package/templates/research/SOUL.md +10 -0
- package/templates/research/bajaclaw.config.json +5 -0
- package/templates/research/scripts/launch.bat +4 -0
- package/templates/research/scripts/launch.sh +4 -0
- package/templates/social/AGENT.md +10 -0
- package/templates/social/HEARTBEAT.md +11 -0
- package/templates/social/SOUL.md +10 -0
- package/templates/social/bajaclaw.config.json +5 -0
- package/templates/social/scripts/launch.bat +4 -0
- package/templates/social/scripts/launch.sh +4 -0
- package/templates/support/AGENT.md +10 -0
- package/templates/support/HEARTBEAT.md +11 -0
- package/templates/support/SOUL.md +10 -0
- package/templates/support/bajaclaw.config.json +5 -0
- package/templates/support/scripts/launch.bat +4 -0
- package/templates/support/scripts/launch.sh +4 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { writeFileSync, existsSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
function plistPath(profile, label) {
|
|
6
|
+
return join(homedir(), "Library", "LaunchAgents", `com.bajaclaw.${profile}.${label}.plist`);
|
|
7
|
+
}
|
|
8
|
+
export async function install(profile, label, cronExpr, command) {
|
|
9
|
+
const { hour, minute } = parseHM(cronExpr);
|
|
10
|
+
const xml = buildPlist(`com.bajaclaw.${profile}.${label}`, command, hour, minute);
|
|
11
|
+
const path = plistPath(profile, label);
|
|
12
|
+
writeFileSync(path, xml);
|
|
13
|
+
await execa("launchctl", ["load", "-w", path], { reject: false });
|
|
14
|
+
}
|
|
15
|
+
export async function uninstall(profile, label) {
|
|
16
|
+
const path = plistPath(profile, label);
|
|
17
|
+
if (existsSync(path)) {
|
|
18
|
+
await execa("launchctl", ["unload", "-w", path], { reject: false });
|
|
19
|
+
unlinkSync(path);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function list(profile) {
|
|
23
|
+
// Parse installed labels via launchctl list.
|
|
24
|
+
const r = await execa("launchctl", ["list"], { reject: false });
|
|
25
|
+
const out = [];
|
|
26
|
+
if (r.exitCode !== 0)
|
|
27
|
+
return out;
|
|
28
|
+
for (const line of r.stdout.split(/\r?\n/)) {
|
|
29
|
+
const parts = line.split(/\s+/);
|
|
30
|
+
const label = parts[parts.length - 1];
|
|
31
|
+
if (label?.startsWith(`com.bajaclaw.${profile}.`)) {
|
|
32
|
+
out.push({ cron: "?", task: label, enabled: 1 });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
function parseHM(cronExpr) {
|
|
38
|
+
// Minimal support: "M H * * *" and "*/N * * * *" (picks first run).
|
|
39
|
+
const parts = cronExpr.trim().split(/\s+/);
|
|
40
|
+
const minute = parts[0] ?? "0";
|
|
41
|
+
const hour = parts[1] ?? "*";
|
|
42
|
+
const m = minute.startsWith("*/") ? 0 : Number(minute);
|
|
43
|
+
const h = hour === "*" ? 0 : Number(hour);
|
|
44
|
+
return { hour: isNaN(h) ? 0 : h, minute: isNaN(m) ? 0 : m };
|
|
45
|
+
}
|
|
46
|
+
function buildPlist(label, command, hour, minute) {
|
|
47
|
+
const args = command.map((c) => ` <string>${escapeXml(c)}</string>`).join("\n");
|
|
48
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
49
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
50
|
+
<plist version="1.0">
|
|
51
|
+
<dict>
|
|
52
|
+
<key>Label</key>
|
|
53
|
+
<string>${label}</string>
|
|
54
|
+
<key>ProgramArguments</key>
|
|
55
|
+
<array>
|
|
56
|
+
${args}
|
|
57
|
+
</array>
|
|
58
|
+
<key>StartCalendarInterval</key>
|
|
59
|
+
<dict>
|
|
60
|
+
<key>Hour</key><integer>${hour}</integer>
|
|
61
|
+
<key>Minute</key><integer>${minute}</integer>
|
|
62
|
+
</dict>
|
|
63
|
+
<key>RunAtLoad</key><false/>
|
|
64
|
+
<key>StandardOutPath</key><string>/tmp/${label}.out</string>
|
|
65
|
+
<key>StandardErrorPath</key><string>/tmp/${label}.err</string>
|
|
66
|
+
</dict>
|
|
67
|
+
</plist>
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
function escapeXml(s) {
|
|
71
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=launchd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launchd.js","sourceRoot":"","sources":["../../src/scheduler/launchd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ScheduleEntry } from "../types.js";
|
|
2
|
+
export declare function install(profile: string, label: string, cronExpr: string, command: string[]): Promise<void>;
|
|
3
|
+
export declare function uninstall(profile: string, label: string): Promise<void>;
|
|
4
|
+
export declare function list(profile: string): Promise<ScheduleEntry[]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
function taskName(profile, label) {
|
|
3
|
+
return `BajaClaw-${profile}-${label}`;
|
|
4
|
+
}
|
|
5
|
+
export async function install(profile, label, cronExpr, command) {
|
|
6
|
+
const name = taskName(profile, label);
|
|
7
|
+
const tr = command.map((c) => (c.includes(" ") ? `"${c}"` : c)).join(" ");
|
|
8
|
+
const schedule = toSchtasks(cronExpr);
|
|
9
|
+
const args = [
|
|
10
|
+
"/Create", "/F",
|
|
11
|
+
"/TN", name,
|
|
12
|
+
"/TR", tr,
|
|
13
|
+
"/SC", schedule.sc,
|
|
14
|
+
...(schedule.mo ? ["/MO", schedule.mo] : []),
|
|
15
|
+
...(schedule.st ? ["/ST", schedule.st] : []),
|
|
16
|
+
];
|
|
17
|
+
await execa("schtasks", args, { reject: false });
|
|
18
|
+
}
|
|
19
|
+
export async function uninstall(profile, label) {
|
|
20
|
+
await execa("schtasks", ["/Delete", "/F", "/TN", taskName(profile, label)], { reject: false });
|
|
21
|
+
}
|
|
22
|
+
export async function list(profile) {
|
|
23
|
+
const r = await execa("schtasks", ["/Query", "/FO", "CSV", "/NH"], { reject: false });
|
|
24
|
+
const out = [];
|
|
25
|
+
if (r.exitCode !== 0)
|
|
26
|
+
return out;
|
|
27
|
+
for (const line of r.stdout.split(/\r?\n/)) {
|
|
28
|
+
const m = line.match(/^"([^"]+)"/);
|
|
29
|
+
if (m && m[1].startsWith(`BajaClaw-${profile}-`)) {
|
|
30
|
+
out.push({ cron: "?", task: m[1], enabled: 1 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function toSchtasks(cronExpr) {
|
|
36
|
+
const parts = cronExpr.trim().split(/\s+/);
|
|
37
|
+
const [m = "0", h = "*"] = parts;
|
|
38
|
+
if (m.startsWith("*/"))
|
|
39
|
+
return { sc: "MINUTE", mo: m.slice(2) };
|
|
40
|
+
if (h === "*")
|
|
41
|
+
return { sc: "HOURLY", mo: "1" };
|
|
42
|
+
return { sc: "DAILY", st: `${pad(Number(h))}:${pad(Number(m))}` };
|
|
43
|
+
}
|
|
44
|
+
function pad(n) { return n.toString().padStart(2, "0"); }
|
|
45
|
+
//# sourceMappingURL=schtasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schtasks.js","sourceRoot":"","sources":["../../src/scheduler/schtasks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ScheduleEntry } from "../types.js";
|
|
2
|
+
export declare function available(): boolean;
|
|
3
|
+
export declare function install(profile: string, label: string, cronExpr: string, command: string[]): Promise<void>;
|
|
4
|
+
export declare function uninstall(profile: string, label: string): Promise<void>;
|
|
5
|
+
export declare function list(profile: string): Promise<ScheduleEntry[]>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { writeFileSync, existsSync, unlinkSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
function unitDir() {
|
|
6
|
+
const dir = join(homedir(), ".config", "systemd", "user");
|
|
7
|
+
if (!existsSync(dir))
|
|
8
|
+
mkdirSync(dir, { recursive: true });
|
|
9
|
+
return dir;
|
|
10
|
+
}
|
|
11
|
+
export function available() {
|
|
12
|
+
// Detect user systemd by presence of systemctl and a user bus.
|
|
13
|
+
try {
|
|
14
|
+
const r = require("node:child_process").spawnSync("systemctl", ["--user", "is-system-running"], { encoding: "utf8" });
|
|
15
|
+
return (r.status ?? 1) !== 127;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function unitName(profile, label) {
|
|
22
|
+
return `bajaclaw-${profile}-${label}`;
|
|
23
|
+
}
|
|
24
|
+
export async function install(profile, label, cronExpr, command) {
|
|
25
|
+
const name = unitName(profile, label);
|
|
26
|
+
const svc = `[Unit]
|
|
27
|
+
Description=BajaClaw ${profile}/${label}
|
|
28
|
+
|
|
29
|
+
[Service]
|
|
30
|
+
Type=oneshot
|
|
31
|
+
ExecStart=${command.map(shellEscape).join(" ")}
|
|
32
|
+
`;
|
|
33
|
+
const timer = `[Unit]
|
|
34
|
+
Description=Timer for ${name}
|
|
35
|
+
|
|
36
|
+
[Timer]
|
|
37
|
+
OnCalendar=${toOnCalendar(cronExpr)}
|
|
38
|
+
Persistent=true
|
|
39
|
+
|
|
40
|
+
[Install]
|
|
41
|
+
WantedBy=timers.target
|
|
42
|
+
`;
|
|
43
|
+
writeFileSync(join(unitDir(), `${name}.service`), svc);
|
|
44
|
+
writeFileSync(join(unitDir(), `${name}.timer`), timer);
|
|
45
|
+
await execa("systemctl", ["--user", "daemon-reload"], { reject: false });
|
|
46
|
+
await execa("systemctl", ["--user", "enable", "--now", `${name}.timer`], { reject: false });
|
|
47
|
+
}
|
|
48
|
+
export async function uninstall(profile, label) {
|
|
49
|
+
const name = unitName(profile, label);
|
|
50
|
+
await execa("systemctl", ["--user", "disable", "--now", `${name}.timer`], { reject: false });
|
|
51
|
+
for (const ext of [".service", ".timer"]) {
|
|
52
|
+
const p = join(unitDir(), `${name}${ext}`);
|
|
53
|
+
if (existsSync(p))
|
|
54
|
+
unlinkSync(p);
|
|
55
|
+
}
|
|
56
|
+
await execa("systemctl", ["--user", "daemon-reload"], { reject: false });
|
|
57
|
+
}
|
|
58
|
+
export async function list(profile) {
|
|
59
|
+
const r = await execa("systemctl", ["--user", "list-timers", "--all", "--no-pager"], { reject: false });
|
|
60
|
+
const out = [];
|
|
61
|
+
if (r.exitCode !== 0)
|
|
62
|
+
return out;
|
|
63
|
+
for (const line of r.stdout.split(/\r?\n/)) {
|
|
64
|
+
const prefix = `bajaclaw-${profile}-`;
|
|
65
|
+
if (line.includes(prefix))
|
|
66
|
+
out.push({ cron: "?", task: line.trim(), enabled: 1 });
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function toOnCalendar(cronExpr) {
|
|
71
|
+
const parts = cronExpr.trim().split(/\s+/);
|
|
72
|
+
const [m = "0", h = "*", dom = "*", mon = "*", dow = "*"] = parts;
|
|
73
|
+
if (m.startsWith("*/"))
|
|
74
|
+
return `*:0/${m.slice(2)}`;
|
|
75
|
+
if (dow !== "*")
|
|
76
|
+
return `${dow} ${h}:${m}`;
|
|
77
|
+
if (dom !== "*" || mon !== "*")
|
|
78
|
+
return `*-${mon}-${dom} ${h}:${m}`;
|
|
79
|
+
if (h === "*")
|
|
80
|
+
return `*:${m}`;
|
|
81
|
+
return `${h}:${m}`;
|
|
82
|
+
}
|
|
83
|
+
function shellEscape(s) {
|
|
84
|
+
return /^[A-Za-z0-9_/.:=-]+$/.test(s) ? s : `"${s.replace(/"/g, '\\"')}"`;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=systemd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systemd.js","sourceRoot":"","sources":["../../src/scheduler/systemd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type DB } from "./db.js";
|
|
2
|
+
import type { Logger } from "./logger.js";
|
|
3
|
+
export declare function maybeReflect(profile: string, log: Logger, every?: number): Promise<string | null>;
|
|
4
|
+
export declare function reflect(db: DB, profile: string, log: Logger): Promise<string | null>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Phase 4: reflection cycle. Every N cycles, ask claude to review recent runs and
|
|
2
|
+
// (optionally) emit a candidate SKILL.md. Candidates land in ~/.bajaclaw/skills/auto/
|
|
3
|
+
// pending `bajaclaw skill review`.
|
|
4
|
+
import { writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { runOnce } from "./claude.js";
|
|
7
|
+
import { openDb } from "./db.js";
|
|
8
|
+
import { bajaclawHome } from "./paths.js";
|
|
9
|
+
const DEFAULT_N = 15;
|
|
10
|
+
export async function maybeReflect(profile, log, every = DEFAULT_N) {
|
|
11
|
+
const db = openDb(profile);
|
|
12
|
+
try {
|
|
13
|
+
const row = db.prepare("SELECT COUNT(*) as c FROM cycles WHERE status='ok'").get();
|
|
14
|
+
if (row.c === 0 || row.c % every !== 0)
|
|
15
|
+
return null;
|
|
16
|
+
return await reflect(db, profile, log);
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
db.close();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function reflect(db, profile, log) {
|
|
23
|
+
const recent = db.prepare("SELECT task, response_preview FROM cycles WHERE status='ok' ORDER BY id DESC LIMIT 20").all();
|
|
24
|
+
const summary = recent.map((r, i) => `${i + 1}. ${r.task.slice(0, 200)} -> ${(r.response_preview ?? "").slice(0, 200)}`).join("\n");
|
|
25
|
+
const prompt = `You are reviewing the last ${recent.length} cycles of an autonomous agent.
|
|
26
|
+
If there is a recurring pattern worth capturing as a reusable skill, return a SKILL.md verbatim (starting with '---' frontmatter block with name, description, version 0.1.0). Otherwise return the single word NONE.
|
|
27
|
+
|
|
28
|
+
Recent cycles:
|
|
29
|
+
${summary}`;
|
|
30
|
+
const r = await runOnce(prompt, { model: "claude-opus-4-7", effort: "high", maxTurns: 2, printMode: true });
|
|
31
|
+
if (!r.ok || !r.text || r.text.trim() === "NONE")
|
|
32
|
+
return null;
|
|
33
|
+
if (!r.text.includes("---"))
|
|
34
|
+
return null;
|
|
35
|
+
const m = r.text.match(/name:\s*([\w-]+)/);
|
|
36
|
+
const name = m?.[1] ?? `auto-${Date.now()}`;
|
|
37
|
+
const dir = join(bajaclawHome(), "skills", "auto");
|
|
38
|
+
if (!existsSync(dir))
|
|
39
|
+
mkdirSync(dir, { recursive: true });
|
|
40
|
+
const skillDir = join(dir, name);
|
|
41
|
+
if (!existsSync(skillDir))
|
|
42
|
+
mkdirSync(skillDir, { recursive: true });
|
|
43
|
+
const path = join(skillDir, "SKILL.md");
|
|
44
|
+
writeFileSync(path, r.text);
|
|
45
|
+
log.info("self-improve.candidate", { profile, name, path });
|
|
46
|
+
return path;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=self-improve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-improve.js","sourceRoot":"","sources":["../src/self-improve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ClaudeEvent } from "../types.js";
|
|
2
|
+
import type { Logger } from "../logger.js";
|
|
3
|
+
export interface AutoSkillConfig {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
minToolUses: number;
|
|
6
|
+
maxPerDay: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const AUTO_SKILL_DEFAULT: AutoSkillConfig;
|
|
9
|
+
export interface AutoSkillInput {
|
|
10
|
+
cycleId: number;
|
|
11
|
+
task: string;
|
|
12
|
+
response: string;
|
|
13
|
+
events: ClaudeEvent[];
|
|
14
|
+
cfg?: Partial<AutoSkillConfig>;
|
|
15
|
+
}
|
|
16
|
+
export interface AutoSkillResult {
|
|
17
|
+
wrote: string | null;
|
|
18
|
+
reason?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function synthesize(input: AutoSkillInput, log?: Logger): Promise<AutoSkillResult>;
|
|
21
|
+
export declare function countToolUses(events: ClaudeEvent[]): number;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Auto-skill synthesis. After a cycle that crosses the tool-use threshold,
|
|
2
|
+
// BajaClaw asks a lightweight backend call to look at the (task, response,
|
|
3
|
+
// tool sequence) and emit a candidate SKILL.md. Candidates land in
|
|
4
|
+
// ~/.bajaclaw/skills/auto/<name>/ and are promoted manually via
|
|
5
|
+
// `bajaclaw skill review` + `bajaclaw skill promote`.
|
|
6
|
+
//
|
|
7
|
+
// Inspired by the "create a skill after complex tasks" pattern popularized
|
|
8
|
+
// by agents like Hermes. Our implementation is our own.
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { bajaclawHome } from "../paths.js";
|
|
12
|
+
import { runOnce } from "../claude.js";
|
|
13
|
+
export const AUTO_SKILL_DEFAULT = {
|
|
14
|
+
enabled: true,
|
|
15
|
+
// Conservative: only fire after genuinely complex cycles. Tune up for
|
|
16
|
+
// more noise; tune down for more capture.
|
|
17
|
+
minToolUses: 6,
|
|
18
|
+
maxPerDay: 5,
|
|
19
|
+
};
|
|
20
|
+
const SYNTH_PROMPT = `You just watched an agent complete a task through tool use. Your job is to
|
|
21
|
+
decide whether the procedure it used is worth saving as a reusable skill. A
|
|
22
|
+
good skill captures a repeatable procedure — not a one-off answer.
|
|
23
|
+
|
|
24
|
+
If it is worth saving, output a SKILL.md file as plain markdown, starting
|
|
25
|
+
with a YAML frontmatter block. Use this exact shape:
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
name: <kebab-case-name>
|
|
29
|
+
description: <one sentence — what this skill accomplishes>
|
|
30
|
+
version: 0.1.0
|
|
31
|
+
tools: [<inferred tool list>]
|
|
32
|
+
triggers: [<1-3 phrases that should trigger this skill>]
|
|
33
|
+
effort: low|medium|high
|
|
34
|
+
auto_generated: true
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## When to use
|
|
38
|
+
<when this procedure applies, in 1-3 bullet points>
|
|
39
|
+
|
|
40
|
+
## Quick reference
|
|
41
|
+
<3-5 lines of the most important facts>
|
|
42
|
+
|
|
43
|
+
## Procedure
|
|
44
|
+
1. First step
|
|
45
|
+
2. Second step
|
|
46
|
+
3. ...
|
|
47
|
+
|
|
48
|
+
## Pitfalls
|
|
49
|
+
- <common mistakes to avoid>
|
|
50
|
+
|
|
51
|
+
## Verification
|
|
52
|
+
- <how to confirm the procedure worked>
|
|
53
|
+
|
|
54
|
+
If the task was trivial, a one-off question, or the procedure is too
|
|
55
|
+
specific to be reusable, output the single word NONE and nothing else.
|
|
56
|
+
|
|
57
|
+
<task>
|
|
58
|
+
{{TASK}}
|
|
59
|
+
</task>
|
|
60
|
+
|
|
61
|
+
<tool_sequence>
|
|
62
|
+
{{TOOLS}}
|
|
63
|
+
</tool_sequence>
|
|
64
|
+
|
|
65
|
+
<response>
|
|
66
|
+
{{RESPONSE}}
|
|
67
|
+
</response>`;
|
|
68
|
+
export async function synthesize(input, log) {
|
|
69
|
+
const cfg = { ...AUTO_SKILL_DEFAULT, ...(input.cfg ?? {}) };
|
|
70
|
+
if (!cfg.enabled)
|
|
71
|
+
return { wrote: null, reason: "disabled" };
|
|
72
|
+
const toolUses = countToolUses(input.events);
|
|
73
|
+
if (toolUses < cfg.minToolUses) {
|
|
74
|
+
return { wrote: null, reason: `below threshold (${toolUses}/${cfg.minToolUses})` };
|
|
75
|
+
}
|
|
76
|
+
if (overDailyCap(cfg.maxPerDay)) {
|
|
77
|
+
return { wrote: null, reason: `daily cap reached (${cfg.maxPerDay})` };
|
|
78
|
+
}
|
|
79
|
+
const tools = summarizeToolSequence(input.events);
|
|
80
|
+
// Tighter caps than before to keep the synthesis call cheap.
|
|
81
|
+
const prompt = SYNTH_PROMPT
|
|
82
|
+
.replace("{{TASK}}", input.task.slice(0, 1500))
|
|
83
|
+
.replace("{{TOOLS}}", tools)
|
|
84
|
+
.replace("{{RESPONSE}}", input.response.slice(0, 3000));
|
|
85
|
+
const r = await runOnce(prompt, {
|
|
86
|
+
model: "claude-sonnet-4-6",
|
|
87
|
+
effort: "medium",
|
|
88
|
+
maxTurns: 1,
|
|
89
|
+
printMode: true,
|
|
90
|
+
disallowedTools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob", "WebSearch", "WebFetch"],
|
|
91
|
+
});
|
|
92
|
+
if (!r.ok || !r.text)
|
|
93
|
+
return { wrote: null, reason: "synth call failed" };
|
|
94
|
+
const text = r.text.trim();
|
|
95
|
+
if (text === "NONE" || !text.startsWith("---")) {
|
|
96
|
+
return { wrote: null, reason: "no reusable procedure detected" };
|
|
97
|
+
}
|
|
98
|
+
const name = extractName(text) ?? `auto-${input.cycleId}-${Date.now()}`;
|
|
99
|
+
const dir = join(bajaclawHome(), "skills", "auto", name);
|
|
100
|
+
if (!existsSync(dir))
|
|
101
|
+
mkdirSync(dir, { recursive: true });
|
|
102
|
+
const path = join(dir, "SKILL.md");
|
|
103
|
+
writeFileSync(path, ensureMarkedAutoGenerated(text, input.cycleId));
|
|
104
|
+
log?.info("auto-skill.candidate", { name, path, cycleId: input.cycleId, toolUses });
|
|
105
|
+
return { wrote: path };
|
|
106
|
+
}
|
|
107
|
+
export function countToolUses(events) {
|
|
108
|
+
return events.filter((e) => e.type === "tool_use").length;
|
|
109
|
+
}
|
|
110
|
+
function summarizeToolSequence(events) {
|
|
111
|
+
const tools = events
|
|
112
|
+
.filter((e) => e.type === "tool_use")
|
|
113
|
+
.map((e, i) => {
|
|
114
|
+
const raw = e.name;
|
|
115
|
+
const name = typeof raw === "string" ? raw : "tool";
|
|
116
|
+
return `${i + 1}. ${name}`;
|
|
117
|
+
});
|
|
118
|
+
return tools.join("\n") || "(no tool calls)";
|
|
119
|
+
}
|
|
120
|
+
function extractName(text) {
|
|
121
|
+
const m = text.match(/^name:\s*([a-zA-Z][\w-]*)/m);
|
|
122
|
+
return m?.[1] ?? null;
|
|
123
|
+
}
|
|
124
|
+
function ensureMarkedAutoGenerated(text, cycleId) {
|
|
125
|
+
if (/auto_generated:\s*true/.test(text))
|
|
126
|
+
return text;
|
|
127
|
+
// Inject into frontmatter.
|
|
128
|
+
const m = text.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
129
|
+
if (!m)
|
|
130
|
+
return text;
|
|
131
|
+
const injected = m[0].replace("---\n", `---\nauto_generated: true\nsource_cycle_id: ${cycleId}\ncreated_at: ${new Date().toISOString()}\n`);
|
|
132
|
+
return injected + text.slice(m[0].length);
|
|
133
|
+
}
|
|
134
|
+
function overDailyCap(maxPerDay) {
|
|
135
|
+
try {
|
|
136
|
+
const dir = join(bajaclawHome(), "skills", "auto");
|
|
137
|
+
if (!existsSync(dir))
|
|
138
|
+
return false;
|
|
139
|
+
const { readdirSync, statSync } = require("node:fs");
|
|
140
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
141
|
+
const fresh = readdirSync(dir).filter((name) => {
|
|
142
|
+
try {
|
|
143
|
+
const s = statSync(join(dir, name, "SKILL.md"));
|
|
144
|
+
return s.isFile() && s.mtime.toISOString().slice(0, 10) === today;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return fresh.length >= maxPerDay;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=auto-skiller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-skiller.js","sourceRoot":"","sources":["../../src/skills/auto-skiller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readdirSync, readFileSync, existsSync, statSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { profileDir, profileSkillsDir, userSkillsDir, } from "../paths.js";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
// BajaClaw skills live in BajaClaw-only directories. The desktop CLI's skill
|
|
7
|
+
// directory is not read automatically — use `bajaclaw skill port` to copy
|
|
8
|
+
// specific skills into BajaClaw's scope when you want them shared.
|
|
9
|
+
export function loadAllSkills(profile) {
|
|
10
|
+
const scopes = [
|
|
11
|
+
{ dir: join(profileDir(profile), "skills"), scope: "agent" },
|
|
12
|
+
{ dir: profileSkillsDir(profile), scope: "agent" },
|
|
13
|
+
{ dir: userSkillsDir(), scope: "bajaclaw-user" },
|
|
14
|
+
{ dir: repoBuiltinSkillsDir(), scope: "bajaclaw-builtin" },
|
|
15
|
+
];
|
|
16
|
+
const byName = new Map();
|
|
17
|
+
for (const { dir, scope } of scopes) {
|
|
18
|
+
if (!existsSync(dir))
|
|
19
|
+
continue;
|
|
20
|
+
for (const skill of scanDir(dir, scope)) {
|
|
21
|
+
if (!byName.has(skill.name))
|
|
22
|
+
byName.set(skill.name, skill);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return Array.from(byName.values());
|
|
26
|
+
}
|
|
27
|
+
function repoBuiltinSkillsDir() {
|
|
28
|
+
// __dirname is <repo>/src/skills (tsx) or <repo>/dist/skills (built).
|
|
29
|
+
return join(__dirname, "..", "..", "skills");
|
|
30
|
+
}
|
|
31
|
+
function scanDir(dir, scope) {
|
|
32
|
+
const out = [];
|
|
33
|
+
let entries;
|
|
34
|
+
try {
|
|
35
|
+
entries = readdirSync(dir);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const full = join(dir, entry);
|
|
42
|
+
let s;
|
|
43
|
+
try {
|
|
44
|
+
s = statSync(full);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (!s.isDirectory())
|
|
50
|
+
continue;
|
|
51
|
+
const skillFile = join(full, "SKILL.md");
|
|
52
|
+
if (!existsSync(skillFile))
|
|
53
|
+
continue;
|
|
54
|
+
try {
|
|
55
|
+
const raw = readFileSync(skillFile, "utf8");
|
|
56
|
+
const parsed = parseSkill(raw, full, scope);
|
|
57
|
+
if (parsed)
|
|
58
|
+
out.push(parsed);
|
|
59
|
+
}
|
|
60
|
+
catch { /* ignore */ }
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
export function parseSkill(raw, path, scope) {
|
|
65
|
+
const m = raw.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
|
|
66
|
+
if (!m)
|
|
67
|
+
return null;
|
|
68
|
+
const fm = parseFrontmatter(m[1]);
|
|
69
|
+
const body = m[2].trim();
|
|
70
|
+
const name = String(fm.name ?? "").trim();
|
|
71
|
+
const description = String(fm.description ?? "").trim();
|
|
72
|
+
if (!name)
|
|
73
|
+
return null;
|
|
74
|
+
return {
|
|
75
|
+
name,
|
|
76
|
+
description,
|
|
77
|
+
version: fm.version ? String(fm.version) : undefined,
|
|
78
|
+
tools: Array.isArray(fm.tools) ? fm.tools.map(String) : undefined,
|
|
79
|
+
triggers: Array.isArray(fm.triggers) ? fm.triggers.map(String) : undefined,
|
|
80
|
+
effort: fm.effort,
|
|
81
|
+
body,
|
|
82
|
+
path,
|
|
83
|
+
scope,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function parseFrontmatter(block) {
|
|
87
|
+
const out = {};
|
|
88
|
+
const lines = block.split(/\r?\n/);
|
|
89
|
+
let key = null;
|
|
90
|
+
let listBuffer = null;
|
|
91
|
+
for (const raw of lines) {
|
|
92
|
+
const line = raw.replace(/\s+$/, "");
|
|
93
|
+
if (!line.trim())
|
|
94
|
+
continue;
|
|
95
|
+
if (listBuffer && line.startsWith(" - ")) {
|
|
96
|
+
listBuffer.push(line.slice(4).trim());
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (listBuffer && key) {
|
|
100
|
+
out[key] = listBuffer;
|
|
101
|
+
listBuffer = null;
|
|
102
|
+
key = null;
|
|
103
|
+
}
|
|
104
|
+
const inline = line.match(/^(\w[\w-]*):\s*(.*)$/);
|
|
105
|
+
if (!inline)
|
|
106
|
+
continue;
|
|
107
|
+
const k = inline[1];
|
|
108
|
+
const v = inline[2].trim();
|
|
109
|
+
if (v === "") {
|
|
110
|
+
key = k;
|
|
111
|
+
listBuffer = [];
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (v.startsWith("[") && v.endsWith("]")) {
|
|
115
|
+
out[k] = v.slice(1, -1)
|
|
116
|
+
.split(",")
|
|
117
|
+
.map((s) => s.trim().replace(/^["']|["']$/g, ""))
|
|
118
|
+
.filter(Boolean);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
out[k] = v.replace(/^["']|["']$/g, "");
|
|
122
|
+
}
|
|
123
|
+
if (listBuffer && key)
|
|
124
|
+
out[key] = listBuffer;
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"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"}
|