0xkobold 0.0.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 (258) hide show
  1. package/.agents/skills/nextjs-best-practices/SKILL.md +208 -0
  2. package/.agents/skills/sql-optimization-patterns/SKILL.md +509 -0
  3. package/HEARTBEAT.md +45 -0
  4. package/README.md +197 -0
  5. package/USAGE.md +191 -0
  6. package/dist/package.json +77 -0
  7. package/dist/src/agent/pi-adapter.js +307 -0
  8. package/dist/src/agent/pi-adapter.js.map +1 -0
  9. package/dist/src/agent/tool-adapter.js +86 -0
  10. package/dist/src/agent/tool-adapter.js.map +1 -0
  11. package/dist/src/approval/queue.js +114 -0
  12. package/dist/src/approval/queue.js.map +1 -0
  13. package/dist/src/ascii-kobold.js +76 -0
  14. package/dist/src/ascii-kobold.js.map +1 -0
  15. package/dist/src/cli/client.js +217 -0
  16. package/dist/src/cli/client.js.map +1 -0
  17. package/dist/src/cli/commands/agent.js +272 -0
  18. package/dist/src/cli/commands/agent.js.map +1 -0
  19. package/dist/src/cli/commands/chat.js +234 -0
  20. package/dist/src/cli/commands/chat.js.map +1 -0
  21. package/dist/src/cli/commands/config.js +202 -0
  22. package/dist/src/cli/commands/config.js.map +1 -0
  23. package/dist/src/cli/commands/daemon.js +203 -0
  24. package/dist/src/cli/commands/daemon.js.map +1 -0
  25. package/dist/src/cli/commands/gateway.js +184 -0
  26. package/dist/src/cli/commands/gateway.js.map +1 -0
  27. package/dist/src/cli/commands/init.js +175 -0
  28. package/dist/src/cli/commands/init.js.map +1 -0
  29. package/dist/src/cli/commands/kobold.js +21 -0
  30. package/dist/src/cli/commands/kobold.js.map +1 -0
  31. package/dist/src/cli/commands/logs.js +27 -0
  32. package/dist/src/cli/commands/logs.js.map +1 -0
  33. package/dist/src/cli/commands/mode.js +121 -0
  34. package/dist/src/cli/commands/mode.js.map +1 -0
  35. package/dist/src/cli/commands/persona.js +261 -0
  36. package/dist/src/cli/commands/persona.js.map +1 -0
  37. package/dist/src/cli/commands/start.js +66 -0
  38. package/dist/src/cli/commands/start.js.map +1 -0
  39. package/dist/src/cli/commands/status.js +117 -0
  40. package/dist/src/cli/commands/status.js.map +1 -0
  41. package/dist/src/cli/commands/stop.js +27 -0
  42. package/dist/src/cli/commands/stop.js.map +1 -0
  43. package/dist/src/cli/commands/system.js +128 -0
  44. package/dist/src/cli/commands/system.js.map +1 -0
  45. package/dist/src/cli/commands/tui.js +103 -0
  46. package/dist/src/cli/commands/tui.js.map +1 -0
  47. package/dist/src/cli/commands/update.js +133 -0
  48. package/dist/src/cli/commands/update.js.map +1 -0
  49. package/dist/src/cli/extensions/discord.js +113 -0
  50. package/dist/src/cli/extensions/discord.js.map +1 -0
  51. package/dist/src/cli/extensions/env.js +91 -0
  52. package/dist/src/cli/extensions/env.js.map +1 -0
  53. package/dist/src/cli/extensions/heartbeat.js +78 -0
  54. package/dist/src/cli/extensions/heartbeat.js.map +1 -0
  55. package/dist/src/cli/index.js +24 -0
  56. package/dist/src/cli/index.js.map +1 -0
  57. package/dist/src/cli/program.js +70 -0
  58. package/dist/src/cli/program.js.map +1 -0
  59. package/dist/src/cli/repl.js +184 -0
  60. package/dist/src/cli/repl.js.map +1 -0
  61. package/dist/src/cli/shared/discord-service.js +102 -0
  62. package/dist/src/cli/shared/discord-service.js.map +1 -0
  63. package/dist/src/config/index.js +10 -0
  64. package/dist/src/config/index.js.map +1 -0
  65. package/dist/src/config/loader.js +401 -0
  66. package/dist/src/config/loader.js.map +1 -0
  67. package/dist/src/config/paths.js +84 -0
  68. package/dist/src/config/paths.js.map +1 -0
  69. package/dist/src/config/types.js +8 -0
  70. package/dist/src/config/types.js.map +1 -0
  71. package/dist/src/context-detector.js +60 -0
  72. package/dist/src/context-detector.js.map +1 -0
  73. package/dist/src/discord/index.js +376 -0
  74. package/dist/src/discord/index.js.map +1 -0
  75. package/dist/src/event-bus/index.js +97 -0
  76. package/dist/src/event-bus/index.js.map +1 -0
  77. package/dist/src/extensions/command-args.js +68 -0
  78. package/dist/src/extensions/command-args.js.map +1 -0
  79. package/dist/src/extensions/core/agent-registry-extension.js +541 -0
  80. package/dist/src/extensions/core/agent-registry-extension.js.map +1 -0
  81. package/dist/src/extensions/core/agent-worker.js +148 -0
  82. package/dist/src/extensions/core/agent-worker.js.map +1 -0
  83. package/dist/src/extensions/core/compaction-safeguard.js +154 -0
  84. package/dist/src/extensions/core/compaction-safeguard.js.map +1 -0
  85. package/dist/src/extensions/core/confirm-destructive.js +43 -0
  86. package/dist/src/extensions/core/confirm-destructive.js.map +1 -0
  87. package/dist/src/extensions/core/context-aware-extension.js +124 -0
  88. package/dist/src/extensions/core/context-aware-extension.js.map +1 -0
  89. package/dist/src/extensions/core/context-pruning/extension.js +124 -0
  90. package/dist/src/extensions/core/context-pruning/extension.js.map +1 -0
  91. package/dist/src/extensions/core/context-pruning/pruner.js +312 -0
  92. package/dist/src/extensions/core/context-pruning/pruner.js.map +1 -0
  93. package/dist/src/extensions/core/context-pruning/runtime.js +48 -0
  94. package/dist/src/extensions/core/context-pruning/runtime.js.map +1 -0
  95. package/dist/src/extensions/core/context-pruning/settings.js +105 -0
  96. package/dist/src/extensions/core/context-pruning/settings.js.map +1 -0
  97. package/dist/src/extensions/core/dirty-repo-guard.js +42 -0
  98. package/dist/src/extensions/core/dirty-repo-guard.js.map +1 -0
  99. package/dist/src/extensions/core/discord-channel-extension.js +205 -0
  100. package/dist/src/extensions/core/discord-channel-extension.js.map +1 -0
  101. package/dist/src/extensions/core/discord-extension.js +142 -0
  102. package/dist/src/extensions/core/discord-extension.js.map +1 -0
  103. package/dist/src/extensions/core/env-loader-extension.js +157 -0
  104. package/dist/src/extensions/core/env-loader-extension.js.map +1 -0
  105. package/dist/src/extensions/core/fileops-extension.js +699 -0
  106. package/dist/src/extensions/core/fileops-extension.js.map +1 -0
  107. package/dist/src/extensions/core/gateway-extension.js +730 -0
  108. package/dist/src/extensions/core/gateway-extension.js.map +1 -0
  109. package/dist/src/extensions/core/git-checkpoint.js +46 -0
  110. package/dist/src/extensions/core/git-checkpoint.js.map +1 -0
  111. package/dist/src/extensions/core/handoff-extension.js +206 -0
  112. package/dist/src/extensions/core/handoff-extension.js.map +1 -0
  113. package/dist/src/extensions/core/heartbeat-extension.js +373 -0
  114. package/dist/src/extensions/core/heartbeat-extension.js.map +1 -0
  115. package/dist/src/extensions/core/mcp-extension.js +413 -0
  116. package/dist/src/extensions/core/mcp-extension.js.map +1 -0
  117. package/dist/src/extensions/core/mode-manager-extension.js +562 -0
  118. package/dist/src/extensions/core/mode-manager-extension.js.map +1 -0
  119. package/dist/src/extensions/core/multi-channel-extension.js +435 -0
  120. package/dist/src/extensions/core/multi-channel-extension.js.map +1 -0
  121. package/dist/src/extensions/core/ollama-provider-extension.js +66 -0
  122. package/dist/src/extensions/core/ollama-provider-extension.js.map +1 -0
  123. package/dist/src/extensions/core/onboarding-extension.js +122 -0
  124. package/dist/src/extensions/core/onboarding-extension.js.map +1 -0
  125. package/dist/src/extensions/core/persona-loader-extension.js +139 -0
  126. package/dist/src/extensions/core/persona-loader-extension.js.map +1 -0
  127. package/dist/src/extensions/core/pi-notify-extension.js +70 -0
  128. package/dist/src/extensions/core/pi-notify-extension.js.map +1 -0
  129. package/dist/src/extensions/core/protected-paths.js +24 -0
  130. package/dist/src/extensions/core/protected-paths.js.map +1 -0
  131. package/dist/src/extensions/core/questionnaire-extension.js +242 -0
  132. package/dist/src/extensions/core/questionnaire-extension.js.map +1 -0
  133. package/dist/src/extensions/core/self-update-extension.js +181 -0
  134. package/dist/src/extensions/core/self-update-extension.js.map +1 -0
  135. package/dist/src/extensions/core/session-bridge-extension.js +78 -0
  136. package/dist/src/extensions/core/session-bridge-extension.js.map +1 -0
  137. package/dist/src/extensions/core/session-manager-extension.js +319 -0
  138. package/dist/src/extensions/core/session-manager-extension.js.map +1 -0
  139. package/dist/src/extensions/core/session-name-extension.js +88 -0
  140. package/dist/src/extensions/core/session-name-extension.js.map +1 -0
  141. package/dist/src/extensions/core/session-pruning-extension.js +480 -0
  142. package/dist/src/extensions/core/session-pruning-extension.js.map +1 -0
  143. package/dist/src/extensions/core/task-manager-extension.js +661 -0
  144. package/dist/src/extensions/core/task-manager-extension.js.map +1 -0
  145. package/dist/src/extensions/core/update-extension.js +438 -0
  146. package/dist/src/extensions/core/update-extension.js.map +1 -0
  147. package/dist/src/extensions/core/websearch-extension.js +463 -0
  148. package/dist/src/extensions/core/websearch-extension.js.map +1 -0
  149. package/dist/src/extensions/index.js +5 -0
  150. package/dist/src/extensions/index.js.map +1 -0
  151. package/dist/src/extensions/loader.js +80 -0
  152. package/dist/src/extensions/loader.js.map +1 -0
  153. package/dist/src/gateway/index.js +353 -0
  154. package/dist/src/gateway/index.js.map +1 -0
  155. package/dist/src/index.js +150 -0
  156. package/dist/src/index.js.map +1 -0
  157. package/dist/src/llm/anthropic.js +86 -0
  158. package/dist/src/llm/anthropic.js.map +1 -0
  159. package/dist/src/llm/index.js +9 -0
  160. package/dist/src/llm/index.js.map +1 -0
  161. package/dist/src/llm/ollama.js +113 -0
  162. package/dist/src/llm/ollama.js.map +1 -0
  163. package/dist/src/llm/router.js +145 -0
  164. package/dist/src/llm/router.js.map +1 -0
  165. package/dist/src/llm/types.js +7 -0
  166. package/dist/src/llm/types.js.map +1 -0
  167. package/dist/src/memory/index.js +5 -0
  168. package/dist/src/memory/index.js.map +1 -0
  169. package/dist/src/memory/store.js +91 -0
  170. package/dist/src/memory/store.js.map +1 -0
  171. package/dist/src/pi-config.js +80 -0
  172. package/dist/src/pi-config.js.map +1 -0
  173. package/dist/src/skills/builtin/file.js +184 -0
  174. package/dist/src/skills/builtin/file.js.map +1 -0
  175. package/dist/src/skills/builtin/shell.js +100 -0
  176. package/dist/src/skills/builtin/shell.js.map +1 -0
  177. package/dist/src/skills/builtin/subagent.js +62 -0
  178. package/dist/src/skills/builtin/subagent.js.map +1 -0
  179. package/dist/src/skills/hello.js +42 -0
  180. package/dist/src/skills/hello.js.map +1 -0
  181. package/dist/src/skills/index.js +11 -0
  182. package/dist/src/skills/index.js.map +1 -0
  183. package/dist/src/skills/loader.js +382 -0
  184. package/dist/src/skills/loader.js.map +1 -0
  185. package/dist/src/skills/types.js +8 -0
  186. package/dist/src/skills/types.js.map +1 -0
  187. package/dist/src/utils/working-dir.js +71 -0
  188. package/dist/src/utils/working-dir.js.map +1 -0
  189. package/package.json +77 -0
  190. package/skills/1password/SKILL.md +70 -0
  191. package/skills/1password/references/cli-examples.md +29 -0
  192. package/skills/1password/references/get-started.md +17 -0
  193. package/skills/apple-notes/SKILL.md +77 -0
  194. package/skills/apple-reminders/SKILL.md +118 -0
  195. package/skills/bear-notes/SKILL.md +107 -0
  196. package/skills/blogwatcher/SKILL.md +69 -0
  197. package/skills/blucli/SKILL.md +47 -0
  198. package/skills/bluebubbles/SKILL.md +131 -0
  199. package/skills/camsnap/SKILL.md +45 -0
  200. package/skills/canvas/SKILL.md +198 -0
  201. package/skills/clawhub/SKILL.md +77 -0
  202. package/skills/coding-agent/SKILL.md +284 -0
  203. package/skills/discord/SKILL.md +197 -0
  204. package/skills/eightctl/SKILL.md +50 -0
  205. package/skills/food-order/SKILL.md +48 -0
  206. package/skills/gemini/SKILL.md +43 -0
  207. package/skills/gh-issues/SKILL.md +865 -0
  208. package/skills/gifgrep/SKILL.md +79 -0
  209. package/skills/github/SKILL.md +163 -0
  210. package/skills/gog/SKILL.md +116 -0
  211. package/skills/goplaces/SKILL.md +52 -0
  212. package/skills/healthcheck/SKILL.md +245 -0
  213. package/skills/himalaya/SKILL.md +257 -0
  214. package/skills/himalaya/references/configuration.md +184 -0
  215. package/skills/himalaya/references/message-composition.md +199 -0
  216. package/skills/imsg/SKILL.md +122 -0
  217. package/skills/mcporter/SKILL.md +61 -0
  218. package/skills/model-usage/SKILL.md +69 -0
  219. package/skills/model-usage/references/codexbar-cli.md +33 -0
  220. package/skills/model-usage/scripts/model_usage.py +310 -0
  221. package/skills/nano-banana-pro/SKILL.md +58 -0
  222. package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
  223. package/skills/nano-pdf/SKILL.md +38 -0
  224. package/skills/notion/SKILL.md +172 -0
  225. package/skills/obsidian/SKILL.md +81 -0
  226. package/skills/openai-image-gen/SKILL.md +89 -0
  227. package/skills/openai-image-gen/scripts/gen.py +240 -0
  228. package/skills/openai-whisper/SKILL.md +38 -0
  229. package/skills/openai-whisper-api/SKILL.md +52 -0
  230. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  231. package/skills/openhue/SKILL.md +112 -0
  232. package/skills/oracle/SKILL.md +125 -0
  233. package/skills/ordercli/SKILL.md +78 -0
  234. package/skills/peekaboo/SKILL.md +190 -0
  235. package/skills/sag/SKILL.md +87 -0
  236. package/skills/session-logs/SKILL.md +115 -0
  237. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  238. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  239. package/skills/skill-creator/SKILL.md +370 -0
  240. package/skills/skill-creator/license.txt +202 -0
  241. package/skills/skill-creator/scripts/init_skill.py +378 -0
  242. package/skills/skill-creator/scripts/package_skill.py +111 -0
  243. package/skills/skill-creator/scripts/quick_validate.py +101 -0
  244. package/skills/slack/SKILL.md +144 -0
  245. package/skills/songsee/SKILL.md +49 -0
  246. package/skills/sonoscli/SKILL.md +46 -0
  247. package/skills/spotify-player/SKILL.md +64 -0
  248. package/skills/summarize/SKILL.md +87 -0
  249. package/skills/things-mac/SKILL.md +86 -0
  250. package/skills/tmux/SKILL.md +153 -0
  251. package/skills/tmux/scripts/find-sessions.sh +112 -0
  252. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  253. package/skills/trello/SKILL.md +95 -0
  254. package/skills/video-frames/SKILL.md +46 -0
  255. package/skills/video-frames/scripts/frame.sh +81 -0
  256. package/skills/voice-call/SKILL.md +45 -0
  257. package/skills/wacli/SKILL.md +72 -0
  258. package/skills/weather/SKILL.md +112 -0
@@ -0,0 +1,401 @@
1
+ /**
2
+ * Config loader for Kobold
3
+ *
4
+ * Similar to koclaw/openclaw's config/loader.js
5
+ * Loads and validates kobold.json config files.
6
+ */
7
+ import * as fs from "node:fs/promises";
8
+ import * as path from "node:path";
9
+ import { getConfigPath, getLocalConfigPath, getDefaultConfigPath, resolveUserPath } from "./paths.js";
10
+ // Default configuration
11
+ const DEFAULT_CONFIG = {
12
+ meta: {
13
+ version: "1.0.0",
14
+ description: "Kobold AI Assistant",
15
+ },
16
+ agents: {
17
+ defaults: {
18
+ name: "Kobold",
19
+ model: "ollama/kimi-k2.5:cloud",
20
+ workspace: "./",
21
+ heartbeat: {
22
+ enabled: true,
23
+ every: "30m",
24
+ prompt: "Read HEARTBEAT.md if it exists. Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.",
25
+ ackMaxChars: 300,
26
+ activeHours: null,
27
+ lightContext: true,
28
+ includeReasoning: false,
29
+ },
30
+ contextPruning: {
31
+ mode: "cache-ttl",
32
+ ttl: "30m",
33
+ keepLastAssistants: 5,
34
+ softTrimRatio: 0.3,
35
+ hardClearRatio: 0.8,
36
+ },
37
+ thinkingDefault: "medium",
38
+ verboseDefault: "off",
39
+ timeoutSeconds: 300,
40
+ },
41
+ list: [
42
+ {
43
+ id: "default",
44
+ name: "Kobold",
45
+ default: true,
46
+ skills: ["code", "analysis", "planning"],
47
+ },
48
+ ],
49
+ },
50
+ models: {
51
+ catalog: {},
52
+ envVarPriority: ["KOBOLD_MODEL", "OLLAMA_MODEL"],
53
+ },
54
+ memory: {
55
+ enabled: true,
56
+ backend: "sqlite",
57
+ dbPath: "~/.config/kobold/memory.db",
58
+ compressionThreshold: 100,
59
+ search: {
60
+ enabled: true,
61
+ vectorStore: "faiss",
62
+ dimensions: 1536,
63
+ },
64
+ },
65
+ extensions: {
66
+ enabled: [
67
+ "ollama-provider",
68
+ "session-bridge",
69
+ "persona-loader",
70
+ "context-aware",
71
+ "mode-manager",
72
+ "heartbeat",
73
+ "task-manager",
74
+ "mcp",
75
+ "gateway",
76
+ ],
77
+ settings: {
78
+ heartbeat: {
79
+ autoInit: true,
80
+ createTemplate: true,
81
+ },
82
+ gateway: {
83
+ port: 18789,
84
+ host: "127.0.0.1",
85
+ cors: {
86
+ origins: ["http://localhost:3000", "http://localhost:5173"],
87
+ },
88
+ },
89
+ mcp: {
90
+ autoDiscover: true,
91
+ servers: ["filesystem", "github"],
92
+ },
93
+ },
94
+ },
95
+ discord: {
96
+ enabled: false,
97
+ autoReply: true,
98
+ channels: {
99
+ notify: {
100
+ id: null,
101
+ alertOnError: true,
102
+ },
103
+ },
104
+ },
105
+ gateway: {
106
+ enabled: true,
107
+ port: 18789,
108
+ host: "127.0.0.1",
109
+ heartbeat: {
110
+ enabled: true,
111
+ intervalSeconds: 30,
112
+ },
113
+ cors: {
114
+ enabled: true,
115
+ origins: ["*"],
116
+ },
117
+ },
118
+ skills: {
119
+ paths: ["./skills", "~/.config/kobold/skills"],
120
+ autoLoad: ["core", "coding", "git"],
121
+ },
122
+ session: {
123
+ storageDir: "~/.config/kobold/sessions",
124
+ autoSave: true,
125
+ maxSize: "100mb",
126
+ backup: {
127
+ enabled: true,
128
+ retention: "7d",
129
+ maxBackups: 10,
130
+ },
131
+ },
132
+ update: {
133
+ checkOnStartup: true,
134
+ autoInstall: false,
135
+ channel: "stable",
136
+ },
137
+ env: {
138
+ KOBOLD_LOG_LEVEL: "info",
139
+ KOBOLD_TEMP_DIR: "~/.config/kobold/tmp",
140
+ },
141
+ cli: {
142
+ keybindings: {
143
+ "ctrl+c": "interrupt",
144
+ "ctrl+d": "shutdown",
145
+ "ctrl+l": "clear",
146
+ "f1": "help",
147
+ "f2": "toggle_mode",
148
+ "ctrl+t": "toggle_tree",
149
+ "ctrl+n": "new_chat",
150
+ },
151
+ theme: "default",
152
+ confirmDestructive: true,
153
+ },
154
+ };
155
+ // Config cache
156
+ let configCache = null;
157
+ /**
158
+ * Parse JSON5 (allowing comments)
159
+ */
160
+ export function parseConfigJson(raw) {
161
+ // Simple JSON5-like parser - strips comments and parses JSON
162
+ const withoutComments = raw
163
+ .replace(/\/\/.*$/gm, "")
164
+ .replace(/\/\*[\s\S]*?\*\//g, "")
165
+ .replace(/,(\s*[}\]])/g, "$1"); // Remove trailing commas
166
+ return JSON.parse(withoutComments);
167
+ }
168
+ /**
169
+ * Deep merge objects
170
+ */
171
+ function deepMerge(target, source) {
172
+ const result = { ...target };
173
+ for (const key in source) {
174
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
175
+ result[key] = deepMerge(result[key] || {}, source[key]);
176
+ }
177
+ else {
178
+ result[key] = source[key];
179
+ }
180
+ }
181
+ return result;
182
+ }
183
+ /**
184
+ * Resolve environment variable references like ${VAR} or ${VAR:-default}
185
+ */
186
+ function resolveEnvVars(value) {
187
+ return value.replace(/\$\{([^}]+)\}/g, (match, expr) => {
188
+ const [varName, defaultVal] = expr.split(":-");
189
+ const envValue = process.env[varName];
190
+ if (envValue !== undefined)
191
+ return envValue;
192
+ if (defaultVal !== undefined)
193
+ return defaultVal;
194
+ return match; // Keep original if not found and no default
195
+ });
196
+ }
197
+ /**
198
+ * Process config to resolve paths and env vars
199
+ */
200
+ function processConfig(config) {
201
+ const processed = JSON.parse(JSON.stringify(config));
202
+ // Resolve paths
203
+ if (processed.memory?.dbPath) {
204
+ processed.memory.dbPath = resolveUserPath(processed.memory.dbPath);
205
+ }
206
+ if (processed.session?.storageDir) {
207
+ processed.session.storageDir = resolveUserPath(processed.session.storageDir);
208
+ }
209
+ if (processed.skills?.paths) {
210
+ processed.skills.paths = processed.skills.paths.map(resolveUserPath);
211
+ }
212
+ return processed;
213
+ }
214
+ /**
215
+ * Validate config and return issues
216
+ */
217
+ function validateConfig(config) {
218
+ const issues = [];
219
+ // Heartbeat validation
220
+ if (config.agents?.defaults?.heartbeat?.every) {
221
+ const every = config.agents.defaults.heartbeat.every;
222
+ if (!/^\d+(m|h|s)$/.test(every) && !/^(?:(\d+)h)?\s*(?:(\d+)m)?\s*(?:(\d+)s?)?$/i.test(every)) {
223
+ issues.push({
224
+ path: "agents.defaults.heartbeat.every",
225
+ message: `Invalid duration format: "${every}". Use like "30m", "1h", "2h30m"`,
226
+ });
227
+ }
228
+ }
229
+ // Gateway port validation
230
+ if (config.gateway?.port) {
231
+ if (config.gateway.port < 1024 || config.gateway.port > 65535) {
232
+ if (config.gateway.port < 1 || config.gateway.port > 65535) {
233
+ issues.push({
234
+ path: "gateway.port",
235
+ message: `Invalid port: ${config.gateway.port}. Must be 1-65535`,
236
+ });
237
+ }
238
+ }
239
+ }
240
+ return issues;
241
+ }
242
+ /**
243
+ * Load config from file
244
+ */
245
+ export async function loadConfigFromFile(filePath) {
246
+ try {
247
+ const raw = await fs.readFile(filePath, "utf-8");
248
+ const parsed = parseConfigJson(raw);
249
+ const resolved = deepMerge(DEFAULT_CONFIG, parsed);
250
+ const issues = validateConfig(resolved);
251
+ const config = processConfig(resolved);
252
+ return {
253
+ path: filePath,
254
+ exists: true,
255
+ raw,
256
+ parsed,
257
+ resolved,
258
+ valid: issues.length === 0,
259
+ config,
260
+ issues,
261
+ };
262
+ }
263
+ catch (err) {
264
+ const errorMessage = err instanceof Error ? err.message : String(err);
265
+ return {
266
+ path: filePath,
267
+ exists: false,
268
+ raw: null,
269
+ parsed: null,
270
+ resolved: DEFAULT_CONFIG,
271
+ valid: false,
272
+ config: DEFAULT_CONFIG,
273
+ issues: [{
274
+ path: "",
275
+ message: `Failed to load config: ${errorMessage}`,
276
+ }],
277
+ };
278
+ }
279
+ }
280
+ /**
281
+ * Load config with caching
282
+ */
283
+ export async function loadConfig() {
284
+ if (configCache) {
285
+ return configCache;
286
+ }
287
+ // Try local config first
288
+ const localPath = getLocalConfigPath();
289
+ const defaultPath = getDefaultConfigPath();
290
+ // Check if local config exists
291
+ try {
292
+ await fs.access(localPath);
293
+ configCache = await loadConfigFromFile(localPath);
294
+ return configCache;
295
+ }
296
+ catch {
297
+ // Try default config
298
+ try {
299
+ await fs.access(defaultPath);
300
+ configCache = await loadConfigFromFile(defaultPath);
301
+ return configCache;
302
+ }
303
+ catch {
304
+ // Return default config if no file found
305
+ configCache = {
306
+ path: defaultPath,
307
+ exists: false,
308
+ raw: null,
309
+ parsed: null,
310
+ resolved: DEFAULT_CONFIG,
311
+ valid: true,
312
+ config: DEFAULT_CONFIG,
313
+ issues: [{
314
+ path: "",
315
+ message: "No config file found, using defaults. Run `kobold init` to create one.",
316
+ }],
317
+ };
318
+ return configCache;
319
+ }
320
+ }
321
+ }
322
+ /**
323
+ * Get current config without reloading
324
+ */
325
+ export function getConfig() {
326
+ return configCache?.config || DEFAULT_CONFIG;
327
+ }
328
+ /**
329
+ * Get config snapshot
330
+ */
331
+ export function getConfigSnapshot() {
332
+ return configCache;
333
+ }
334
+ /**
335
+ * Clear config cache (forces reload)
336
+ */
337
+ export function clearConfigCache() {
338
+ configCache = null;
339
+ }
340
+ /**
341
+ * Write config to file
342
+ */
343
+ export async function writeConfig(config, filePath) {
344
+ const targetPath = filePath || getConfigPath();
345
+ const configDir = path.dirname(targetPath);
346
+ // Ensure directory exists
347
+ try {
348
+ await fs.mkdir(configDir, { recursive: true });
349
+ }
350
+ catch {
351
+ // Directory might already exist
352
+ }
353
+ // Add meta timestamp
354
+ const configWithMeta = {
355
+ ...config,
356
+ meta: {
357
+ ...config.meta,
358
+ lastTouchedAt: new Date().toISOString(),
359
+ },
360
+ };
361
+ // Pretty print with comments template
362
+ const json = JSON.stringify(configWithMeta, null, 2);
363
+ await fs.writeFile(targetPath, json, "utf-8");
364
+ // Clear cache to force reload
365
+ clearConfigCache();
366
+ }
367
+ /**
368
+ * Get a specific config value by path (e.g., "agents.defaults.heartbeat.every")
369
+ */
370
+ export function getConfigValue(path) {
371
+ const config = getConfig();
372
+ const keys = path.split(".");
373
+ let current = config;
374
+ for (const key of keys) {
375
+ if (current && typeof current === "object") {
376
+ current = current[key];
377
+ }
378
+ else {
379
+ return undefined;
380
+ }
381
+ }
382
+ return current;
383
+ }
384
+ /**
385
+ * Set a specific config value by path
386
+ */
387
+ export function setConfigValue(config, path, value) {
388
+ const keys = path.split(".");
389
+ const newConfig = { ...config };
390
+ let current = newConfig;
391
+ for (let i = 0; i < keys.length - 1; i++) {
392
+ const key = keys[i];
393
+ if (!(key in current) || typeof current[key] !== "object") {
394
+ current[key] = {};
395
+ }
396
+ current = current[key];
397
+ }
398
+ current[keys[keys.length - 1]] = value;
399
+ return newConfig;
400
+ }
401
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Config paths and utilities for Kobold
3
+ *
4
+ * Similar to koclaw/openclaw's config-path.ts
5
+ */
6
+ import * as path from "node:path";
7
+ import * as os from "node:os";
8
+ import { existsSync } from "node:fs";
9
+ const KOBOLD_DIR = process.env.KOBOLD_HOME || path.join(os.homedir(), ".config", "kobold");
10
+ export function getConfigDir() {
11
+ return KOBOLD_DIR;
12
+ }
13
+ export function getConfigPath() {
14
+ // Priority: KOBOLD_CONFIG_PATH > --local mode > ./kobold.json > ~/.config/kobold/kobold.json
15
+ // 1. Explicit env var override
16
+ if (process.env.KOBOLD_CONFIG_PATH) {
17
+ return path.resolve(process.env.KOBOLD_CONFIG_PATH);
18
+ }
19
+ // 2. Local mode: always prefer CWD config
20
+ if (process.env.KOBOLD_LOCAL_MODE === 'true') {
21
+ const localConfig = path.join(process.cwd(), "kobold.json");
22
+ // In local mode, return CWD config even if it doesn't exist yet
23
+ // (allows creating new project configs)
24
+ return localConfig;
25
+ }
26
+ // 3. Check for local config in CWD
27
+ const localConfig = path.join(process.cwd(), "kobold.json");
28
+ if (existsSync(localConfig)) {
29
+ return localConfig;
30
+ }
31
+ // 4. Fall back to global config
32
+ return path.join(KOBOLD_DIR, "kobold.json");
33
+ }
34
+ export function getDefaultConfigPath() {
35
+ return path.join(KOBOLD_DIR, "kobold.json");
36
+ }
37
+ export function getLocalConfigPath() {
38
+ return path.join(process.cwd(), "kobold.json");
39
+ }
40
+ export function getSessionDir() {
41
+ // In local mode, store sessions in CWD
42
+ if (process.env.KOBOLD_LOCAL_MODE === 'true') {
43
+ return path.join(process.cwd(), ".kobold", "sessions");
44
+ }
45
+ return path.join(KOBOLD_DIR, "sessions");
46
+ }
47
+ export function getMemoryDbPath() {
48
+ // In local mode, store memory in CWD
49
+ if (process.env.KOBOLD_LOCAL_MODE === 'true') {
50
+ return path.join(process.cwd(), ".kobold", "memory.db");
51
+ }
52
+ return path.join(KOBOLD_DIR, "memory.db");
53
+ }
54
+ export function getSkillsDir() {
55
+ // Check for local skills first
56
+ const localSkills = path.join(process.cwd(), "skills");
57
+ if (existsSync(localSkills)) {
58
+ return localSkills;
59
+ }
60
+ return path.join(KOBOLD_DIR, "skills");
61
+ }
62
+ export function getTempDir() {
63
+ const tempDir = process.env.KOBOLD_LOCAL_MODE === 'true'
64
+ ? path.join(process.cwd(), ".kobold", "tmp")
65
+ : path.join(KOBOLD_DIR, "tmp");
66
+ return tempDir;
67
+ }
68
+ export function resolveUserPath(input) {
69
+ if (input.startsWith("~/")) {
70
+ return path.join(os.homedir(), input.slice(2));
71
+ }
72
+ if (input.startsWith("./") || input.startsWith("../")) {
73
+ return path.resolve(input);
74
+ }
75
+ if (path.isAbsolute(input)) {
76
+ return input;
77
+ }
78
+ // Relative to CWD in local mode, or KOBOLD_DIR otherwise
79
+ if (process.env.KOBOLD_LOCAL_MODE === 'true') {
80
+ return path.join(process.cwd(), input);
81
+ }
82
+ return path.join(KOBOLD_DIR, input);
83
+ }
84
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/config/paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAE3F,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,6FAA6F;IAE7F,+BAA+B;IAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtD,CAAC;IAED,0CAA0C;IAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;QAC5D,gEAAgE;QAChE,wCAAwC;QACxC,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,mCAAmC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;IAC5D,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,gCAAgC;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,uCAAuC;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,qCAAqC;IACrC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,+BAA+B;IAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM;QACtD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC;QAC5C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,yDAAyD;IACzD,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,MAAM,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Kobold Configuration Types
3
+ *
4
+ * Similar to koclaw/openclaw's config system but tailored for 0xKobold.
5
+ * Supports JSON5 config file at ~/.config/kobold/kobold.json
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Context Detector for 0xKobold
3
+ *
4
+ * Detects when TUI was started with --local and switches
5
+ * working directory accordingly.
6
+ */
7
+ import { existsSync, readFileSync } from "fs";
8
+ import { resolve } from "path";
9
+ import { homedir } from "os";
10
+ const CONTEXT_FILE = resolve(homedir(), ".0xkobold", ".active-context");
11
+ const CONTEXT_TIMEOUT = 5 * 60 * 1000; // 5 minutes
12
+ /**
13
+ * Check if there's an active --local TUI context
14
+ */
15
+ export function detectLocalContext() {
16
+ try {
17
+ if (!existsSync(CONTEXT_FILE)) {
18
+ return null;
19
+ }
20
+ const context = JSON.parse(readFileSync(CONTEXT_FILE, "utf-8"));
21
+ // Check if context is still fresh
22
+ const age = Date.now() - context.timestamp;
23
+ if (age > CONTEXT_TIMEOUT) {
24
+ return null;
25
+ }
26
+ return context;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Check if we should switch to the local context directory
34
+ * Call this at startup to detect --local mode
35
+ */
36
+ export function checkAndPromptForContext() {
37
+ const context = detectLocalContext();
38
+ if (!context || !context.isLocal) {
39
+ return false;
40
+ }
41
+ // If already in that directory, nothing to do
42
+ if (process.cwd() === context.workingDir) {
43
+ return false;
44
+ }
45
+ console.log(`🐉 Detected active TUI context in: ${context.workingDir}`);
46
+ console.log(` Use --local flag or cd to that directory to work there.`);
47
+ return true;
48
+ }
49
+ /**
50
+ * Get the context working directory if available
51
+ */
52
+ export function getContextDirectory() {
53
+ const context = detectLocalContext();
54
+ return context?.workingDir ?? null;
55
+ }
56
+ // Auto-check on import (for non-interactive detection)
57
+ if (import.meta.main) {
58
+ checkAndPromptForContext();
59
+ }
60
+ //# sourceMappingURL=context-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-detector.js","sourceRoot":"","sources":["../../src/context-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAQ7B,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACxE,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAEnD;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAgB,CAAC;QAE/E,kCAAkC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;QAC3C,IAAI,GAAG,GAAG,eAAe,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IAErC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,IAAI,OAAO,CAAC,GAAG,EAAE,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sCAAsC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAE1E,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;IACrC,OAAO,OAAO,EAAE,UAAU,IAAI,IAAI,CAAC;AACrC,CAAC;AAED,uDAAuD;AACvD,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,wBAAwB,EAAE,CAAC;AAC7B,CAAC"}