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.
- package/.agents/skills/nextjs-best-practices/SKILL.md +208 -0
- package/.agents/skills/sql-optimization-patterns/SKILL.md +509 -0
- package/HEARTBEAT.md +45 -0
- package/README.md +197 -0
- package/USAGE.md +191 -0
- package/dist/package.json +77 -0
- package/dist/src/agent/pi-adapter.js +307 -0
- package/dist/src/agent/pi-adapter.js.map +1 -0
- package/dist/src/agent/tool-adapter.js +86 -0
- package/dist/src/agent/tool-adapter.js.map +1 -0
- package/dist/src/approval/queue.js +114 -0
- package/dist/src/approval/queue.js.map +1 -0
- package/dist/src/ascii-kobold.js +76 -0
- package/dist/src/ascii-kobold.js.map +1 -0
- package/dist/src/cli/client.js +217 -0
- package/dist/src/cli/client.js.map +1 -0
- package/dist/src/cli/commands/agent.js +272 -0
- package/dist/src/cli/commands/agent.js.map +1 -0
- package/dist/src/cli/commands/chat.js +234 -0
- package/dist/src/cli/commands/chat.js.map +1 -0
- package/dist/src/cli/commands/config.js +202 -0
- package/dist/src/cli/commands/config.js.map +1 -0
- package/dist/src/cli/commands/daemon.js +203 -0
- package/dist/src/cli/commands/daemon.js.map +1 -0
- package/dist/src/cli/commands/gateway.js +184 -0
- package/dist/src/cli/commands/gateway.js.map +1 -0
- package/dist/src/cli/commands/init.js +175 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/kobold.js +21 -0
- package/dist/src/cli/commands/kobold.js.map +1 -0
- package/dist/src/cli/commands/logs.js +27 -0
- package/dist/src/cli/commands/logs.js.map +1 -0
- package/dist/src/cli/commands/mode.js +121 -0
- package/dist/src/cli/commands/mode.js.map +1 -0
- package/dist/src/cli/commands/persona.js +261 -0
- package/dist/src/cli/commands/persona.js.map +1 -0
- package/dist/src/cli/commands/start.js +66 -0
- package/dist/src/cli/commands/start.js.map +1 -0
- package/dist/src/cli/commands/status.js +117 -0
- package/dist/src/cli/commands/status.js.map +1 -0
- package/dist/src/cli/commands/stop.js +27 -0
- package/dist/src/cli/commands/stop.js.map +1 -0
- package/dist/src/cli/commands/system.js +128 -0
- package/dist/src/cli/commands/system.js.map +1 -0
- package/dist/src/cli/commands/tui.js +103 -0
- package/dist/src/cli/commands/tui.js.map +1 -0
- package/dist/src/cli/commands/update.js +133 -0
- package/dist/src/cli/commands/update.js.map +1 -0
- package/dist/src/cli/extensions/discord.js +113 -0
- package/dist/src/cli/extensions/discord.js.map +1 -0
- package/dist/src/cli/extensions/env.js +91 -0
- package/dist/src/cli/extensions/env.js.map +1 -0
- package/dist/src/cli/extensions/heartbeat.js +78 -0
- package/dist/src/cli/extensions/heartbeat.js.map +1 -0
- package/dist/src/cli/index.js +24 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/program.js +70 -0
- package/dist/src/cli/program.js.map +1 -0
- package/dist/src/cli/repl.js +184 -0
- package/dist/src/cli/repl.js.map +1 -0
- package/dist/src/cli/shared/discord-service.js +102 -0
- package/dist/src/cli/shared/discord-service.js.map +1 -0
- package/dist/src/config/index.js +10 -0
- package/dist/src/config/index.js.map +1 -0
- package/dist/src/config/loader.js +401 -0
- package/dist/src/config/loader.js.map +1 -0
- package/dist/src/config/paths.js +84 -0
- package/dist/src/config/paths.js.map +1 -0
- package/dist/src/config/types.js +8 -0
- package/dist/src/config/types.js.map +1 -0
- package/dist/src/context-detector.js +60 -0
- package/dist/src/context-detector.js.map +1 -0
- package/dist/src/discord/index.js +376 -0
- package/dist/src/discord/index.js.map +1 -0
- package/dist/src/event-bus/index.js +97 -0
- package/dist/src/event-bus/index.js.map +1 -0
- package/dist/src/extensions/command-args.js +68 -0
- package/dist/src/extensions/command-args.js.map +1 -0
- package/dist/src/extensions/core/agent-registry-extension.js +541 -0
- package/dist/src/extensions/core/agent-registry-extension.js.map +1 -0
- package/dist/src/extensions/core/agent-worker.js +148 -0
- package/dist/src/extensions/core/agent-worker.js.map +1 -0
- package/dist/src/extensions/core/compaction-safeguard.js +154 -0
- package/dist/src/extensions/core/compaction-safeguard.js.map +1 -0
- package/dist/src/extensions/core/confirm-destructive.js +43 -0
- package/dist/src/extensions/core/confirm-destructive.js.map +1 -0
- package/dist/src/extensions/core/context-aware-extension.js +124 -0
- package/dist/src/extensions/core/context-aware-extension.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/extension.js +124 -0
- package/dist/src/extensions/core/context-pruning/extension.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/pruner.js +312 -0
- package/dist/src/extensions/core/context-pruning/pruner.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/runtime.js +48 -0
- package/dist/src/extensions/core/context-pruning/runtime.js.map +1 -0
- package/dist/src/extensions/core/context-pruning/settings.js +105 -0
- package/dist/src/extensions/core/context-pruning/settings.js.map +1 -0
- package/dist/src/extensions/core/dirty-repo-guard.js +42 -0
- package/dist/src/extensions/core/dirty-repo-guard.js.map +1 -0
- package/dist/src/extensions/core/discord-channel-extension.js +205 -0
- package/dist/src/extensions/core/discord-channel-extension.js.map +1 -0
- package/dist/src/extensions/core/discord-extension.js +142 -0
- package/dist/src/extensions/core/discord-extension.js.map +1 -0
- package/dist/src/extensions/core/env-loader-extension.js +157 -0
- package/dist/src/extensions/core/env-loader-extension.js.map +1 -0
- package/dist/src/extensions/core/fileops-extension.js +699 -0
- package/dist/src/extensions/core/fileops-extension.js.map +1 -0
- package/dist/src/extensions/core/gateway-extension.js +730 -0
- package/dist/src/extensions/core/gateway-extension.js.map +1 -0
- package/dist/src/extensions/core/git-checkpoint.js +46 -0
- package/dist/src/extensions/core/git-checkpoint.js.map +1 -0
- package/dist/src/extensions/core/handoff-extension.js +206 -0
- package/dist/src/extensions/core/handoff-extension.js.map +1 -0
- package/dist/src/extensions/core/heartbeat-extension.js +373 -0
- package/dist/src/extensions/core/heartbeat-extension.js.map +1 -0
- package/dist/src/extensions/core/mcp-extension.js +413 -0
- package/dist/src/extensions/core/mcp-extension.js.map +1 -0
- package/dist/src/extensions/core/mode-manager-extension.js +562 -0
- package/dist/src/extensions/core/mode-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/multi-channel-extension.js +435 -0
- package/dist/src/extensions/core/multi-channel-extension.js.map +1 -0
- package/dist/src/extensions/core/ollama-provider-extension.js +66 -0
- package/dist/src/extensions/core/ollama-provider-extension.js.map +1 -0
- package/dist/src/extensions/core/onboarding-extension.js +122 -0
- package/dist/src/extensions/core/onboarding-extension.js.map +1 -0
- package/dist/src/extensions/core/persona-loader-extension.js +139 -0
- package/dist/src/extensions/core/persona-loader-extension.js.map +1 -0
- package/dist/src/extensions/core/pi-notify-extension.js +70 -0
- package/dist/src/extensions/core/pi-notify-extension.js.map +1 -0
- package/dist/src/extensions/core/protected-paths.js +24 -0
- package/dist/src/extensions/core/protected-paths.js.map +1 -0
- package/dist/src/extensions/core/questionnaire-extension.js +242 -0
- package/dist/src/extensions/core/questionnaire-extension.js.map +1 -0
- package/dist/src/extensions/core/self-update-extension.js +181 -0
- package/dist/src/extensions/core/self-update-extension.js.map +1 -0
- package/dist/src/extensions/core/session-bridge-extension.js +78 -0
- package/dist/src/extensions/core/session-bridge-extension.js.map +1 -0
- package/dist/src/extensions/core/session-manager-extension.js +319 -0
- package/dist/src/extensions/core/session-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/session-name-extension.js +88 -0
- package/dist/src/extensions/core/session-name-extension.js.map +1 -0
- package/dist/src/extensions/core/session-pruning-extension.js +480 -0
- package/dist/src/extensions/core/session-pruning-extension.js.map +1 -0
- package/dist/src/extensions/core/task-manager-extension.js +661 -0
- package/dist/src/extensions/core/task-manager-extension.js.map +1 -0
- package/dist/src/extensions/core/update-extension.js +438 -0
- package/dist/src/extensions/core/update-extension.js.map +1 -0
- package/dist/src/extensions/core/websearch-extension.js +463 -0
- package/dist/src/extensions/core/websearch-extension.js.map +1 -0
- package/dist/src/extensions/index.js +5 -0
- package/dist/src/extensions/index.js.map +1 -0
- package/dist/src/extensions/loader.js +80 -0
- package/dist/src/extensions/loader.js.map +1 -0
- package/dist/src/gateway/index.js +353 -0
- package/dist/src/gateway/index.js.map +1 -0
- package/dist/src/index.js +150 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/llm/anthropic.js +86 -0
- package/dist/src/llm/anthropic.js.map +1 -0
- package/dist/src/llm/index.js +9 -0
- package/dist/src/llm/index.js.map +1 -0
- package/dist/src/llm/ollama.js +113 -0
- package/dist/src/llm/ollama.js.map +1 -0
- package/dist/src/llm/router.js +145 -0
- package/dist/src/llm/router.js.map +1 -0
- package/dist/src/llm/types.js +7 -0
- package/dist/src/llm/types.js.map +1 -0
- package/dist/src/memory/index.js +5 -0
- package/dist/src/memory/index.js.map +1 -0
- package/dist/src/memory/store.js +91 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/pi-config.js +80 -0
- package/dist/src/pi-config.js.map +1 -0
- package/dist/src/skills/builtin/file.js +184 -0
- package/dist/src/skills/builtin/file.js.map +1 -0
- package/dist/src/skills/builtin/shell.js +100 -0
- package/dist/src/skills/builtin/shell.js.map +1 -0
- package/dist/src/skills/builtin/subagent.js +62 -0
- package/dist/src/skills/builtin/subagent.js.map +1 -0
- package/dist/src/skills/hello.js +42 -0
- package/dist/src/skills/hello.js.map +1 -0
- package/dist/src/skills/index.js +11 -0
- package/dist/src/skills/index.js.map +1 -0
- package/dist/src/skills/loader.js +382 -0
- package/dist/src/skills/loader.js.map +1 -0
- package/dist/src/skills/types.js +8 -0
- package/dist/src/skills/types.js.map +1 -0
- package/dist/src/utils/working-dir.js +71 -0
- package/dist/src/utils/working-dir.js.map +1 -0
- package/package.json +77 -0
- package/skills/1password/SKILL.md +70 -0
- package/skills/1password/references/cli-examples.md +29 -0
- package/skills/1password/references/get-started.md +17 -0
- package/skills/apple-notes/SKILL.md +77 -0
- package/skills/apple-reminders/SKILL.md +118 -0
- package/skills/bear-notes/SKILL.md +107 -0
- package/skills/blogwatcher/SKILL.md +69 -0
- package/skills/blucli/SKILL.md +47 -0
- package/skills/bluebubbles/SKILL.md +131 -0
- package/skills/camsnap/SKILL.md +45 -0
- package/skills/canvas/SKILL.md +198 -0
- package/skills/clawhub/SKILL.md +77 -0
- package/skills/coding-agent/SKILL.md +284 -0
- package/skills/discord/SKILL.md +197 -0
- package/skills/eightctl/SKILL.md +50 -0
- package/skills/food-order/SKILL.md +48 -0
- package/skills/gemini/SKILL.md +43 -0
- package/skills/gh-issues/SKILL.md +865 -0
- package/skills/gifgrep/SKILL.md +79 -0
- package/skills/github/SKILL.md +163 -0
- package/skills/gog/SKILL.md +116 -0
- package/skills/goplaces/SKILL.md +52 -0
- package/skills/healthcheck/SKILL.md +245 -0
- package/skills/himalaya/SKILL.md +257 -0
- package/skills/himalaya/references/configuration.md +184 -0
- package/skills/himalaya/references/message-composition.md +199 -0
- package/skills/imsg/SKILL.md +122 -0
- package/skills/mcporter/SKILL.md +61 -0
- package/skills/model-usage/SKILL.md +69 -0
- package/skills/model-usage/references/codexbar-cli.md +33 -0
- package/skills/model-usage/scripts/model_usage.py +310 -0
- package/skills/nano-banana-pro/SKILL.md +58 -0
- package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
- package/skills/nano-pdf/SKILL.md +38 -0
- package/skills/notion/SKILL.md +172 -0
- package/skills/obsidian/SKILL.md +81 -0
- package/skills/openai-image-gen/SKILL.md +89 -0
- package/skills/openai-image-gen/scripts/gen.py +240 -0
- package/skills/openai-whisper/SKILL.md +38 -0
- package/skills/openai-whisper-api/SKILL.md +52 -0
- package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
- package/skills/openhue/SKILL.md +112 -0
- package/skills/oracle/SKILL.md +125 -0
- package/skills/ordercli/SKILL.md +78 -0
- package/skills/peekaboo/SKILL.md +190 -0
- package/skills/sag/SKILL.md +87 -0
- package/skills/session-logs/SKILL.md +115 -0
- package/skills/sherpa-onnx-tts/SKILL.md +103 -0
- package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
- package/skills/skill-creator/SKILL.md +370 -0
- package/skills/skill-creator/license.txt +202 -0
- package/skills/skill-creator/scripts/init_skill.py +378 -0
- package/skills/skill-creator/scripts/package_skill.py +111 -0
- package/skills/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/slack/SKILL.md +144 -0
- package/skills/songsee/SKILL.md +49 -0
- package/skills/sonoscli/SKILL.md +46 -0
- package/skills/spotify-player/SKILL.md +64 -0
- package/skills/summarize/SKILL.md +87 -0
- package/skills/things-mac/SKILL.md +86 -0
- package/skills/tmux/SKILL.md +153 -0
- package/skills/tmux/scripts/find-sessions.sh +112 -0
- package/skills/tmux/scripts/wait-for-text.sh +83 -0
- package/skills/trello/SKILL.md +95 -0
- package/skills/video-frames/SKILL.md +46 -0
- package/skills/video-frames/scripts/frame.sh +81 -0
- package/skills/voice-call/SKILL.md +45 -0
- package/skills/wacli/SKILL.md +72 -0
- 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":"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"}
|
|
@@ -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"}
|