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.
Files changed (248) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +639 -0
  3. package/bin/bajaclaw.js +35 -0
  4. package/bin/create-bajaclaw.js +17 -0
  5. package/dist/agent.d.ts +29 -0
  6. package/dist/agent.js +231 -0
  7. package/dist/agent.js.map +1 -0
  8. package/dist/api/server.d.ts +15 -0
  9. package/dist/api/server.js +215 -0
  10. package/dist/api/server.js.map +1 -0
  11. package/dist/api/translate.d.ts +61 -0
  12. package/dist/api/translate.js +109 -0
  13. package/dist/api/translate.js.map +1 -0
  14. package/dist/banner.d.ts +7 -0
  15. package/dist/banner.js +31 -0
  16. package/dist/banner.js.map +1 -0
  17. package/dist/channels/gateway.d.ts +1 -0
  18. package/dist/channels/gateway.js +76 -0
  19. package/dist/channels/gateway.js.map +1 -0
  20. package/dist/claude.d.ts +9 -0
  21. package/dist/claude.js +170 -0
  22. package/dist/claude.js.map +1 -0
  23. package/dist/cli.d.ts +2 -0
  24. package/dist/cli.js +303 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/commands/channel.d.ts +3 -0
  27. package/dist/commands/channel.js +27 -0
  28. package/dist/commands/channel.js.map +1 -0
  29. package/dist/commands/compact.d.ts +8 -0
  30. package/dist/commands/compact.js +60 -0
  31. package/dist/commands/compact.js.map +1 -0
  32. package/dist/commands/daemon.d.ts +7 -0
  33. package/dist/commands/daemon.js +129 -0
  34. package/dist/commands/daemon.js.map +1 -0
  35. package/dist/commands/dashboard.d.ts +1 -0
  36. package/dist/commands/dashboard.js +78 -0
  37. package/dist/commands/dashboard.js.map +1 -0
  38. package/dist/commands/doctor.d.ts +1 -0
  39. package/dist/commands/doctor.js +25 -0
  40. package/dist/commands/doctor.js.map +1 -0
  41. package/dist/commands/dry-run.d.ts +1 -0
  42. package/dist/commands/dry-run.js +5 -0
  43. package/dist/commands/dry-run.js.map +1 -0
  44. package/dist/commands/effort.d.ts +6 -0
  45. package/dist/commands/effort.js +33 -0
  46. package/dist/commands/effort.js.map +1 -0
  47. package/dist/commands/guide.d.ts +4 -0
  48. package/dist/commands/guide.js +52 -0
  49. package/dist/commands/guide.js.map +1 -0
  50. package/dist/commands/health.d.ts +1 -0
  51. package/dist/commands/health.js +20 -0
  52. package/dist/commands/health.js.map +1 -0
  53. package/dist/commands/init.d.ts +12 -0
  54. package/dist/commands/init.js +114 -0
  55. package/dist/commands/init.js.map +1 -0
  56. package/dist/commands/mcp.d.ts +9 -0
  57. package/dist/commands/mcp.js +63 -0
  58. package/dist/commands/mcp.js.map +1 -0
  59. package/dist/commands/migrate.d.ts +1 -0
  60. package/dist/commands/migrate.js +58 -0
  61. package/dist/commands/migrate.js.map +1 -0
  62. package/dist/commands/model.d.ts +5 -0
  63. package/dist/commands/model.js +31 -0
  64. package/dist/commands/model.js.map +1 -0
  65. package/dist/commands/persona.d.ts +6 -0
  66. package/dist/commands/persona.js +67 -0
  67. package/dist/commands/persona.js.map +1 -0
  68. package/dist/commands/port.d.ts +15 -0
  69. package/dist/commands/port.js +88 -0
  70. package/dist/commands/port.js.map +1 -0
  71. package/dist/commands/profile.d.ts +4 -0
  72. package/dist/commands/profile.js +41 -0
  73. package/dist/commands/profile.js.map +1 -0
  74. package/dist/commands/serve.d.ts +14 -0
  75. package/dist/commands/serve.js +62 -0
  76. package/dist/commands/serve.js.map +1 -0
  77. package/dist/commands/setup.d.ts +17 -0
  78. package/dist/commands/setup.js +228 -0
  79. package/dist/commands/setup.js.map +1 -0
  80. package/dist/commands/skill.d.ts +7 -0
  81. package/dist/commands/skill.js +137 -0
  82. package/dist/commands/skill.js.map +1 -0
  83. package/dist/commands/start.d.ts +6 -0
  84. package/dist/commands/start.js +25 -0
  85. package/dist/commands/start.js.map +1 -0
  86. package/dist/commands/status.d.ts +1 -0
  87. package/dist/commands/status.js +35 -0
  88. package/dist/commands/status.js.map +1 -0
  89. package/dist/commands/subagent.d.ts +14 -0
  90. package/dist/commands/subagent.js +173 -0
  91. package/dist/commands/subagent.js.map +1 -0
  92. package/dist/commands/trigger.d.ts +1 -0
  93. package/dist/commands/trigger.js +13 -0
  94. package/dist/commands/trigger.js.map +1 -0
  95. package/dist/commands/uninstall.d.ts +5 -0
  96. package/dist/commands/uninstall.js +165 -0
  97. package/dist/commands/uninstall.js.map +1 -0
  98. package/dist/commands/update.d.ts +7 -0
  99. package/dist/commands/update.js +49 -0
  100. package/dist/commands/update.js.map +1 -0
  101. package/dist/concurrency.d.ts +1 -0
  102. package/dist/concurrency.js +17 -0
  103. package/dist/concurrency.js.map +1 -0
  104. package/dist/config.d.ts +5 -0
  105. package/dist/config.js +42 -0
  106. package/dist/config.js.map +1 -0
  107. package/dist/db.d.ts +3 -0
  108. package/dist/db.js +124 -0
  109. package/dist/db.js.map +1 -0
  110. package/dist/delegation.d.ts +6 -0
  111. package/dist/delegation.js +21 -0
  112. package/dist/delegation.js.map +1 -0
  113. package/dist/health-check.d.ts +6 -0
  114. package/dist/health-check.js +38 -0
  115. package/dist/health-check.js.map +1 -0
  116. package/dist/logger.d.ts +11 -0
  117. package/dist/logger.js +53 -0
  118. package/dist/logger.js.map +1 -0
  119. package/dist/mcp/consumer.d.ts +15 -0
  120. package/dist/mcp/consumer.js +74 -0
  121. package/dist/mcp/consumer.js.map +1 -0
  122. package/dist/mcp/server.d.ts +6 -0
  123. package/dist/mcp/server.js +260 -0
  124. package/dist/mcp/server.js.map +1 -0
  125. package/dist/memory/claude-compat.d.ts +4 -0
  126. package/dist/memory/claude-compat.js +56 -0
  127. package/dist/memory/claude-compat.js.map +1 -0
  128. package/dist/memory/compact.d.ts +25 -0
  129. package/dist/memory/compact.js +195 -0
  130. package/dist/memory/compact.js.map +1 -0
  131. package/dist/memory/extract.d.ts +3 -0
  132. package/dist/memory/extract.js +56 -0
  133. package/dist/memory/extract.js.map +1 -0
  134. package/dist/memory/recall.d.ts +5 -0
  135. package/dist/memory/recall.js +47 -0
  136. package/dist/memory/recall.js.map +1 -0
  137. package/dist/model-picker.d.ts +33 -0
  138. package/dist/model-picker.js +104 -0
  139. package/dist/model-picker.js.map +1 -0
  140. package/dist/paths.d.ts +12 -0
  141. package/dist/paths.js +49 -0
  142. package/dist/paths.js.map +1 -0
  143. package/dist/persona-io.d.ts +5 -0
  144. package/dist/persona-io.js +29 -0
  145. package/dist/persona-io.js.map +1 -0
  146. package/dist/persona.d.ts +12 -0
  147. package/dist/persona.js +54 -0
  148. package/dist/persona.js.map +1 -0
  149. package/dist/prompt.d.ts +5 -0
  150. package/dist/prompt.js +56 -0
  151. package/dist/prompt.js.map +1 -0
  152. package/dist/safety.d.ts +17 -0
  153. package/dist/safety.js +47 -0
  154. package/dist/safety.js.map +1 -0
  155. package/dist/scheduler/cron.d.ts +4 -0
  156. package/dist/scheduler/cron.js +44 -0
  157. package/dist/scheduler/cron.js.map +1 -0
  158. package/dist/scheduler/index.d.ts +7 -0
  159. package/dist/scheduler/index.js +15 -0
  160. package/dist/scheduler/index.js.map +1 -0
  161. package/dist/scheduler/launchd.d.ts +4 -0
  162. package/dist/scheduler/launchd.js +73 -0
  163. package/dist/scheduler/launchd.js.map +1 -0
  164. package/dist/scheduler/schtasks.d.ts +4 -0
  165. package/dist/scheduler/schtasks.js +45 -0
  166. package/dist/scheduler/schtasks.js.map +1 -0
  167. package/dist/scheduler/systemd.d.ts +5 -0
  168. package/dist/scheduler/systemd.js +86 -0
  169. package/dist/scheduler/systemd.js.map +1 -0
  170. package/dist/self-improve.d.ts +4 -0
  171. package/dist/self-improve.js +48 -0
  172. package/dist/self-improve.js.map +1 -0
  173. package/dist/skills/auto-skiller.d.ts +21 -0
  174. package/dist/skills/auto-skiller.js +156 -0
  175. package/dist/skills/auto-skiller.js.map +1 -0
  176. package/dist/skills/loader.d.ts +3 -0
  177. package/dist/skills/loader.js +127 -0
  178. package/dist/skills/loader.js.map +1 -0
  179. package/dist/skills/matcher.d.ts +2 -0
  180. package/dist/skills/matcher.js +27 -0
  181. package/dist/skills/matcher.js.map +1 -0
  182. package/dist/skills/porter.d.ts +27 -0
  183. package/dist/skills/porter.js +109 -0
  184. package/dist/skills/porter.js.map +1 -0
  185. package/dist/types.d.ts +110 -0
  186. package/dist/types.js +2 -0
  187. package/dist/types.js.map +1 -0
  188. package/dist/updater.d.ts +25 -0
  189. package/dist/updater.js +185 -0
  190. package/dist/updater.js.map +1 -0
  191. package/package.json +53 -0
  192. package/scripts/postinstall.js +33 -0
  193. package/skills/configure-effort/SKILL.md +36 -0
  194. package/skills/configure-model/SKILL.md +41 -0
  195. package/skills/configure-tools/SKILL.md +51 -0
  196. package/skills/daily-briefing/SKILL.md +19 -0
  197. package/skills/delegate-to-subagent/SKILL.md +63 -0
  198. package/skills/email-triage/SKILL.md +21 -0
  199. package/skills/setup-api/SKILL.md +115 -0
  200. package/skills/setup-compaction/SKILL.md +102 -0
  201. package/skills/setup-daemon/SKILL.md +49 -0
  202. package/skills/setup-dashboard/SKILL.md +39 -0
  203. package/skills/setup-discord/SKILL.md +54 -0
  204. package/skills/setup-heartbeat/SKILL.md +51 -0
  205. package/skills/setup-mcp-port/SKILL.md +54 -0
  206. package/skills/setup-memory-sync/SKILL.md +45 -0
  207. package/skills/setup-profile/SKILL.md +44 -0
  208. package/skills/setup-self-update/SKILL.md +45 -0
  209. package/skills/setup-subagent/SKILL.md +102 -0
  210. package/skills/setup-telegram/SKILL.md +54 -0
  211. package/skills/setup-uninstall/SKILL.md +55 -0
  212. package/skills/web-research/SKILL.md +20 -0
  213. package/templates/code/AGENT.md +15 -0
  214. package/templates/code/HEARTBEAT.md +11 -0
  215. package/templates/code/SOUL.md +10 -0
  216. package/templates/code/bajaclaw.config.json +5 -0
  217. package/templates/code/scripts/launch.bat +4 -0
  218. package/templates/code/scripts/launch.sh +4 -0
  219. package/templates/custom/AGENT.md +14 -0
  220. package/templates/custom/HEARTBEAT.md +11 -0
  221. package/templates/custom/SOUL.md +10 -0
  222. package/templates/custom/bajaclaw.config.json +5 -0
  223. package/templates/custom/scripts/launch.bat +4 -0
  224. package/templates/custom/scripts/launch.sh +4 -0
  225. package/templates/outreach/AGENT.md +11 -0
  226. package/templates/outreach/HEARTBEAT.md +11 -0
  227. package/templates/outreach/SOUL.md +10 -0
  228. package/templates/outreach/bajaclaw.config.json +5 -0
  229. package/templates/outreach/scripts/launch.bat +4 -0
  230. package/templates/outreach/scripts/launch.sh +4 -0
  231. package/templates/research/AGENT.md +27 -0
  232. package/templates/research/HEARTBEAT.md +11 -0
  233. package/templates/research/SOUL.md +10 -0
  234. package/templates/research/bajaclaw.config.json +5 -0
  235. package/templates/research/scripts/launch.bat +4 -0
  236. package/templates/research/scripts/launch.sh +4 -0
  237. package/templates/social/AGENT.md +10 -0
  238. package/templates/social/HEARTBEAT.md +11 -0
  239. package/templates/social/SOUL.md +10 -0
  240. package/templates/social/bajaclaw.config.json +5 -0
  241. package/templates/social/scripts/launch.bat +4 -0
  242. package/templates/social/scripts/launch.sh +4 -0
  243. package/templates/support/AGENT.md +10 -0
  244. package/templates/support/HEARTBEAT.md +11 -0
  245. package/templates/support/SOUL.md +10 -0
  246. package/templates/support/bajaclaw.config.json +5 -0
  247. package/templates/support/scripts/launch.bat +4 -0
  248. 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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
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,3 @@
1
+ import type { Skill, SkillScope } from "../types.js";
2
+ export declare function loadAllSkills(profile: string): Skill[];
3
+ export declare function parseSkill(raw: string, path: string, scope: SkillScope): Skill | null;
@@ -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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"}
@@ -0,0 +1,2 @@
1
+ import type { Skill } from "../types.js";
2
+ export declare function matchSkills(skills: Skill[], task: string, topN?: number): Skill[];