@babyclaw/gateway 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +91 -1
- package/dist/index.js +308 -79
- package/dist/index.js.map +1 -1
- package/dist/main.js +255 -71
- package/dist/main.js.map +1 -1
- package/package.json +8 -2
package/dist/main.js
CHANGED
|
@@ -139,7 +139,8 @@ function looksLikeSecret({ value }) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// src/runtime.ts
|
|
142
|
-
import {
|
|
142
|
+
import { mkdirSync as mkdirSync3 } from "fs";
|
|
143
|
+
import { getBundledSkillsDir } from "@babyclaw/skills";
|
|
143
144
|
|
|
144
145
|
// src/ai/agent.ts
|
|
145
146
|
import {
|
|
@@ -1945,9 +1946,26 @@ import { z } from "zod";
|
|
|
1945
1946
|
// src/utils/path.ts
|
|
1946
1947
|
import { resolve, sep } from "path";
|
|
1947
1948
|
import { stat } from "fs/promises";
|
|
1949
|
+
var BUNDLED_SKILLS_PREFIX = "bundled-skills/";
|
|
1948
1950
|
function normalizeSeparators({ path }) {
|
|
1949
1951
|
return path.replaceAll("\\", "/");
|
|
1950
1952
|
}
|
|
1953
|
+
function resolveBundledSkillPath({
|
|
1954
|
+
bundledSkillsDir,
|
|
1955
|
+
requestedPath
|
|
1956
|
+
}) {
|
|
1957
|
+
const relative3 = requestedPath.slice(BUNDLED_SKILLS_PREFIX.length);
|
|
1958
|
+
const normalized = normalizeSeparators({ path: relative3 }).trim();
|
|
1959
|
+
if (normalized.length === 0) {
|
|
1960
|
+
throw new Error("Path is required");
|
|
1961
|
+
}
|
|
1962
|
+
const absoluteRoot = resolve(bundledSkillsDir);
|
|
1963
|
+
const absoluteTarget = resolve(absoluteRoot, normalized);
|
|
1964
|
+
if (!isSubPath({ parent: absoluteRoot, child: absoluteTarget })) {
|
|
1965
|
+
throw new Error("Path escapes bundled skills root");
|
|
1966
|
+
}
|
|
1967
|
+
return absoluteTarget;
|
|
1968
|
+
}
|
|
1951
1969
|
function resolveWorkspacePath({
|
|
1952
1970
|
workspaceRoot,
|
|
1953
1971
|
requestedPath
|
|
@@ -3704,10 +3722,25 @@ function createWorkspaceTools({ context }) {
|
|
|
3704
3722
|
defaultCode: "WORKSPACE_READ_FAILED",
|
|
3705
3723
|
input: { path, format },
|
|
3706
3724
|
action: async () => {
|
|
3707
|
-
const
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3725
|
+
const isBundled = path.startsWith(BUNDLED_SKILLS_PREFIX);
|
|
3726
|
+
let absolutePath;
|
|
3727
|
+
if (isBundled) {
|
|
3728
|
+
if (!context.bundledSkillsDir) {
|
|
3729
|
+
throw new ToolExecutionError({
|
|
3730
|
+
code: "BUNDLED_SKILLS_UNAVAILABLE",
|
|
3731
|
+
message: "Bundled skills directory is not configured"
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3734
|
+
absolutePath = resolveBundledSkillPath({
|
|
3735
|
+
bundledSkillsDir: context.bundledSkillsDir,
|
|
3736
|
+
requestedPath: path
|
|
3737
|
+
});
|
|
3738
|
+
} else {
|
|
3739
|
+
absolutePath = resolveWorkspacePath({
|
|
3740
|
+
workspaceRoot: context.workspaceRoot,
|
|
3741
|
+
requestedPath: path
|
|
3742
|
+
});
|
|
3743
|
+
}
|
|
3711
3744
|
const raw = await readFile6(absolutePath, "utf8");
|
|
3712
3745
|
ensurePayloadWithinLimit({
|
|
3713
3746
|
value: raw,
|
|
@@ -3765,6 +3798,12 @@ function createWorkspaceTools({ context }) {
|
|
|
3765
3798
|
hasValue: value !== void 0
|
|
3766
3799
|
},
|
|
3767
3800
|
action: async () => {
|
|
3801
|
+
if (path.startsWith(BUNDLED_SKILLS_PREFIX)) {
|
|
3802
|
+
throw new ToolExecutionError({
|
|
3803
|
+
code: "BUNDLED_SKILLS_READONLY",
|
|
3804
|
+
message: "Bundled skills are read-only and cannot be written to"
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3768
3807
|
const absolutePath = resolveWorkspacePath({
|
|
3769
3808
|
workspaceRoot: context.workspaceRoot,
|
|
3770
3809
|
requestedPath: path
|
|
@@ -3904,6 +3943,12 @@ function createWorkspaceTools({ context }) {
|
|
|
3904
3943
|
defaultCode: "WORKSPACE_DELETE_FAILED",
|
|
3905
3944
|
input: { path, recursive },
|
|
3906
3945
|
action: async () => {
|
|
3946
|
+
if (path.startsWith(BUNDLED_SKILLS_PREFIX)) {
|
|
3947
|
+
throw new ToolExecutionError({
|
|
3948
|
+
code: "BUNDLED_SKILLS_READONLY",
|
|
3949
|
+
message: "Bundled skills are read-only and cannot be deleted"
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3907
3952
|
const absolutePath = resolveWorkspacePath({
|
|
3908
3953
|
workspaceRoot: context.workspaceRoot,
|
|
3909
3954
|
requestedPath: path
|
|
@@ -3940,6 +3985,12 @@ function createWorkspaceTools({ context }) {
|
|
|
3940
3985
|
defaultCode: "WORKSPACE_MOVE_FAILED",
|
|
3941
3986
|
input: { from_path, to_path, overwrite },
|
|
3942
3987
|
action: async () => {
|
|
3988
|
+
if (from_path.startsWith(BUNDLED_SKILLS_PREFIX) || to_path.startsWith(BUNDLED_SKILLS_PREFIX)) {
|
|
3989
|
+
throw new ToolExecutionError({
|
|
3990
|
+
code: "BUNDLED_SKILLS_READONLY",
|
|
3991
|
+
message: "Bundled skills are read-only and cannot be moved"
|
|
3992
|
+
});
|
|
3993
|
+
}
|
|
3943
3994
|
const fromAbsolute = resolveWorkspacePath({
|
|
3944
3995
|
workspaceRoot: context.workspaceRoot,
|
|
3945
3996
|
requestedPath: from_path
|
|
@@ -4120,44 +4171,15 @@ function createUnifiedTools({
|
|
|
4120
4171
|
};
|
|
4121
4172
|
}
|
|
4122
4173
|
|
|
4123
|
-
// src/
|
|
4124
|
-
import {
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
userPath: join9(workspacePath, "USER.md")
|
|
4131
|
-
};
|
|
4132
|
-
}
|
|
4133
|
-
async function readPersonalityFiles({
|
|
4134
|
-
workspacePath
|
|
4174
|
+
// src/bundled-skills/index.ts
|
|
4175
|
+
import { listBundledSlugs, readBundledSkillContent, getBundledSkillInfo } from "@babyclaw/skills";
|
|
4176
|
+
|
|
4177
|
+
// src/workspace/skills/types.ts
|
|
4178
|
+
function getSkillKey({
|
|
4179
|
+
frontmatter,
|
|
4180
|
+
slug
|
|
4135
4181
|
}) {
|
|
4136
|
-
|
|
4137
|
-
const [identity, soul, user] = await Promise.all([
|
|
4138
|
-
readOptionalFile2({ path: identityPath }),
|
|
4139
|
-
readOptionalFile2({ path: soulPath }),
|
|
4140
|
-
readOptionalFile2({ path: userPath })
|
|
4141
|
-
]);
|
|
4142
|
-
return {
|
|
4143
|
-
identity,
|
|
4144
|
-
soul,
|
|
4145
|
-
user
|
|
4146
|
-
};
|
|
4147
|
-
}
|
|
4148
|
-
function hasCompletePersonalityFiles(files) {
|
|
4149
|
-
return typeof files.identity === "string" && files.identity.trim().length > 0 && typeof files.soul === "string" && files.soul.trim().length > 0 && typeof files.user === "string" && files.user.trim().length > 0;
|
|
4150
|
-
}
|
|
4151
|
-
async function readOptionalFile2({ path }) {
|
|
4152
|
-
try {
|
|
4153
|
-
return await readFile7(path, "utf8");
|
|
4154
|
-
} catch (error) {
|
|
4155
|
-
const maybeErrno = error;
|
|
4156
|
-
if (maybeErrno.code === "ENOENT") {
|
|
4157
|
-
return null;
|
|
4158
|
-
}
|
|
4159
|
-
throw error;
|
|
4160
|
-
}
|
|
4182
|
+
return frontmatter?.openclaw?.skillKey ?? frontmatter?.name ?? slug;
|
|
4161
4183
|
}
|
|
4162
4184
|
|
|
4163
4185
|
// src/workspace/skills/eligibility.ts
|
|
@@ -4167,54 +4189,84 @@ function getEligibleSkills({
|
|
|
4167
4189
|
skillsConfig,
|
|
4168
4190
|
fullConfig
|
|
4169
4191
|
}) {
|
|
4170
|
-
return skills.filter((skill) =>
|
|
4192
|
+
return skills.filter((skill) => {
|
|
4193
|
+
const { frontmatter, slug } = skill;
|
|
4194
|
+
const entry = skillsConfig.entries[getSkillKey({ frontmatter, slug })];
|
|
4195
|
+
if (entry?.enabled === false) return false;
|
|
4196
|
+
return checkSkillEligibility({ frontmatter, skillsConfig, fullConfig }).eligible;
|
|
4197
|
+
});
|
|
4171
4198
|
}
|
|
4172
|
-
function
|
|
4173
|
-
|
|
4199
|
+
function checkSkillEligibility({
|
|
4200
|
+
frontmatter,
|
|
4174
4201
|
skillsConfig,
|
|
4175
4202
|
fullConfig
|
|
4176
4203
|
}) {
|
|
4177
|
-
|
|
4204
|
+
if (frontmatter.disableModelInvocation) {
|
|
4205
|
+
return { eligible: false, reason: "Model invocation disabled" };
|
|
4206
|
+
}
|
|
4178
4207
|
const openclaw = frontmatter.openclaw;
|
|
4179
|
-
const skillKey = openclaw?.skillKey ?? frontmatter.name;
|
|
4180
|
-
const entry = skillsConfig.entries[skillKey];
|
|
4181
|
-
if (entry?.enabled === false) return false;
|
|
4182
|
-
if (frontmatter.disableModelInvocation) return false;
|
|
4183
4208
|
if (openclaw?.os && openclaw.os.length > 0) {
|
|
4184
|
-
if (!openclaw.os.includes(process.platform))
|
|
4209
|
+
if (!openclaw.os.includes(process.platform)) {
|
|
4210
|
+
return {
|
|
4211
|
+
eligible: false,
|
|
4212
|
+
reason: `Requires OS: ${openclaw.os.join(", ")} (current: ${process.platform})`
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
if (openclaw?.always) {
|
|
4217
|
+
return { eligible: true, reason: null };
|
|
4185
4218
|
}
|
|
4186
|
-
if (openclaw?.always) return true;
|
|
4187
4219
|
const requires = openclaw?.requires;
|
|
4188
|
-
if (!requires)
|
|
4220
|
+
if (!requires) {
|
|
4221
|
+
return { eligible: true, reason: null };
|
|
4222
|
+
}
|
|
4189
4223
|
if (requires.bins && requires.bins.length > 0) {
|
|
4190
|
-
|
|
4224
|
+
const missing = requires.bins.filter((bin) => !binaryExists({ name: bin }));
|
|
4225
|
+
if (missing.length > 0) {
|
|
4226
|
+
return { eligible: false, reason: `Missing binaries: ${missing.join(", ")}` };
|
|
4227
|
+
}
|
|
4191
4228
|
}
|
|
4192
4229
|
if (requires.anyBins && requires.anyBins.length > 0) {
|
|
4193
|
-
if (!requires.anyBins.some((bin) => binaryExists({ name: bin })))
|
|
4230
|
+
if (!requires.anyBins.some((bin) => binaryExists({ name: bin }))) {
|
|
4231
|
+
return {
|
|
4232
|
+
eligible: false,
|
|
4233
|
+
reason: `Requires at least one of: ${requires.anyBins.join(", ")}`
|
|
4234
|
+
};
|
|
4235
|
+
}
|
|
4194
4236
|
}
|
|
4195
4237
|
if (requires.env && requires.env.length > 0) {
|
|
4238
|
+
const skillKey = openclaw?.skillKey ?? frontmatter.name;
|
|
4239
|
+
const entry = skillsConfig.entries[skillKey];
|
|
4196
4240
|
const primaryEnv = openclaw?.primaryEnv;
|
|
4197
4241
|
const hasApiKeyInConfig = Boolean(entry?.apiKey);
|
|
4198
4242
|
for (const envVar of requires.env) {
|
|
4199
4243
|
if (process.env[envVar]) continue;
|
|
4200
4244
|
if (primaryEnv === envVar && hasApiKeyInConfig) continue;
|
|
4201
|
-
return false;
|
|
4245
|
+
return { eligible: false, reason: `Missing environment variable: ${envVar}` };
|
|
4202
4246
|
}
|
|
4203
4247
|
}
|
|
4204
4248
|
if (requires.config && requires.config.length > 0) {
|
|
4205
4249
|
for (const configPath of requires.config) {
|
|
4206
|
-
if (!getConfigValue({ config: fullConfig, path: configPath }))
|
|
4250
|
+
if (!getConfigValue({ config: fullConfig, path: configPath })) {
|
|
4251
|
+
return { eligible: false, reason: `Missing config value: ${configPath}` };
|
|
4252
|
+
}
|
|
4207
4253
|
}
|
|
4208
4254
|
}
|
|
4209
|
-
return true;
|
|
4255
|
+
return { eligible: true, reason: null };
|
|
4210
4256
|
}
|
|
4257
|
+
var binaryExistsCache = /* @__PURE__ */ new Map();
|
|
4211
4258
|
function binaryExists({ name }) {
|
|
4259
|
+
const cached = binaryExistsCache.get(name);
|
|
4260
|
+
if (cached !== void 0) return cached;
|
|
4261
|
+
let exists;
|
|
4212
4262
|
try {
|
|
4213
4263
|
execFileSync("which", [name], { stdio: "ignore" });
|
|
4214
|
-
|
|
4264
|
+
exists = true;
|
|
4215
4265
|
} catch {
|
|
4216
|
-
|
|
4266
|
+
exists = false;
|
|
4217
4267
|
}
|
|
4268
|
+
binaryExistsCache.set(name, exists);
|
|
4269
|
+
return exists;
|
|
4218
4270
|
}
|
|
4219
4271
|
function getConfigValue({
|
|
4220
4272
|
config,
|
|
@@ -4229,6 +4281,90 @@ function getConfigValue({
|
|
|
4229
4281
|
return current;
|
|
4230
4282
|
}
|
|
4231
4283
|
|
|
4284
|
+
// src/bundled-skills/index.ts
|
|
4285
|
+
function listBundledSkills({
|
|
4286
|
+
skillsConfig,
|
|
4287
|
+
fullConfig
|
|
4288
|
+
}) {
|
|
4289
|
+
const slugs = listBundledSlugs();
|
|
4290
|
+
return slugs.map((slug) => {
|
|
4291
|
+
const content = readBundledSkillContent({ slug });
|
|
4292
|
+
if (!content) {
|
|
4293
|
+
return {
|
|
4294
|
+
slug,
|
|
4295
|
+
frontmatter: null,
|
|
4296
|
+
enabled: false,
|
|
4297
|
+
eligible: false,
|
|
4298
|
+
ineligibilityReason: "Could not read SKILL.md"
|
|
4299
|
+
};
|
|
4300
|
+
}
|
|
4301
|
+
const raw = parseFrontmatter({ content });
|
|
4302
|
+
const frontmatter = raw ? buildFrontmatter({ raw }) : null;
|
|
4303
|
+
const skillKey = getSkillKey({ frontmatter, slug });
|
|
4304
|
+
const entry = skillsConfig.entries[skillKey];
|
|
4305
|
+
const enabled = entry?.enabled === true;
|
|
4306
|
+
const { eligible, reason } = frontmatter ? checkSkillEligibility({ frontmatter, skillsConfig, fullConfig }) : { eligible: false, reason: "Invalid frontmatter" };
|
|
4307
|
+
return {
|
|
4308
|
+
slug,
|
|
4309
|
+
frontmatter,
|
|
4310
|
+
enabled,
|
|
4311
|
+
eligible,
|
|
4312
|
+
ineligibilityReason: reason
|
|
4313
|
+
};
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4316
|
+
function getEnabledBundledSkills({
|
|
4317
|
+
skillsConfig,
|
|
4318
|
+
fullConfig
|
|
4319
|
+
}) {
|
|
4320
|
+
const all = listBundledSkills({ skillsConfig, fullConfig });
|
|
4321
|
+
return all.filter((s) => s.enabled && s.eligible && s.frontmatter).map((s) => ({
|
|
4322
|
+
frontmatter: s.frontmatter,
|
|
4323
|
+
slug: s.slug,
|
|
4324
|
+
relativePath: `bundled-skills/${s.slug}/SKILL.md`
|
|
4325
|
+
}));
|
|
4326
|
+
}
|
|
4327
|
+
|
|
4328
|
+
// src/onboarding/personality.ts
|
|
4329
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
4330
|
+
import { join as join9 } from "path";
|
|
4331
|
+
function getPersonalityFilePaths({ workspacePath }) {
|
|
4332
|
+
return {
|
|
4333
|
+
identityPath: join9(workspacePath, "IDENTITY.md"),
|
|
4334
|
+
soulPath: join9(workspacePath, "SOUL.md"),
|
|
4335
|
+
userPath: join9(workspacePath, "USER.md")
|
|
4336
|
+
};
|
|
4337
|
+
}
|
|
4338
|
+
async function readPersonalityFiles({
|
|
4339
|
+
workspacePath
|
|
4340
|
+
}) {
|
|
4341
|
+
const { identityPath, soulPath, userPath } = getPersonalityFilePaths({ workspacePath });
|
|
4342
|
+
const [identity, soul, user] = await Promise.all([
|
|
4343
|
+
readOptionalFile2({ path: identityPath }),
|
|
4344
|
+
readOptionalFile2({ path: soulPath }),
|
|
4345
|
+
readOptionalFile2({ path: userPath })
|
|
4346
|
+
]);
|
|
4347
|
+
return {
|
|
4348
|
+
identity,
|
|
4349
|
+
soul,
|
|
4350
|
+
user
|
|
4351
|
+
};
|
|
4352
|
+
}
|
|
4353
|
+
function hasCompletePersonalityFiles(files) {
|
|
4354
|
+
return typeof files.identity === "string" && files.identity.trim().length > 0 && typeof files.soul === "string" && files.soul.trim().length > 0 && typeof files.user === "string" && files.user.trim().length > 0;
|
|
4355
|
+
}
|
|
4356
|
+
async function readOptionalFile2({ path }) {
|
|
4357
|
+
try {
|
|
4358
|
+
return await readFile7(path, "utf8");
|
|
4359
|
+
} catch (error) {
|
|
4360
|
+
const maybeErrno = error;
|
|
4361
|
+
if (maybeErrno.code === "ENOENT") {
|
|
4362
|
+
return null;
|
|
4363
|
+
}
|
|
4364
|
+
throw error;
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
|
|
4232
4368
|
// src/agent/context.ts
|
|
4233
4369
|
async function loadAgentContext({
|
|
4234
4370
|
workspacePath,
|
|
@@ -4241,7 +4377,11 @@ async function loadAgentContext({
|
|
|
4241
4377
|
readWorkspaceGuide({ workspacePath }),
|
|
4242
4378
|
scanWorkspaceSkills({ workspacePath })
|
|
4243
4379
|
]);
|
|
4244
|
-
const
|
|
4380
|
+
const workspaceSkills = getEligibleSkills({ skills: allSkills, skillsConfig, fullConfig });
|
|
4381
|
+
const bundledSkills = getEnabledBundledSkills({ skillsConfig, fullConfig });
|
|
4382
|
+
const workspaceSlugs = new Set(workspaceSkills.map((s) => s.slug));
|
|
4383
|
+
const dedupedBundled = bundledSkills.filter((s) => !workspaceSlugs.has(s.slug));
|
|
4384
|
+
const skills = [...workspaceSkills, ...dedupedBundled];
|
|
4245
4385
|
const personalityFiles = hasCompletePersonalityFiles(rawPersonalityFiles) ? rawPersonalityFiles : void 0;
|
|
4246
4386
|
return { personalityFiles, toolNotesContent, agentsContent, skills };
|
|
4247
4387
|
}
|
|
@@ -4422,6 +4562,7 @@ var AgentTurnOrchestrator = class {
|
|
|
4422
4562
|
if (abortSignal.aborted) return;
|
|
4423
4563
|
const {
|
|
4424
4564
|
workspacePath,
|
|
4565
|
+
bundledSkillsDir,
|
|
4425
4566
|
aiAgent,
|
|
4426
4567
|
sessionManager,
|
|
4427
4568
|
schedulerService,
|
|
@@ -4521,6 +4662,7 @@ ${description}`;
|
|
|
4521
4662
|
toolDeps: this.toolDeps,
|
|
4522
4663
|
executionContext: {
|
|
4523
4664
|
workspaceRoot: workspacePath,
|
|
4665
|
+
bundledSkillsDir,
|
|
4524
4666
|
botTimezone: schedulerService.getTimezone(),
|
|
4525
4667
|
platform: event.platform,
|
|
4526
4668
|
chatId: event.chatId,
|
|
@@ -5835,11 +5977,11 @@ var ChatRegistry = class {
|
|
|
5835
5977
|
|
|
5836
5978
|
// src/config/loader.ts
|
|
5837
5979
|
import { access, mkdir as mkdir5, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
|
|
5838
|
-
import { dirname as
|
|
5980
|
+
import { dirname as dirname6 } from "path";
|
|
5839
5981
|
|
|
5840
5982
|
// src/config/paths.ts
|
|
5841
5983
|
import { homedir as homedir2 } from "os";
|
|
5842
|
-
import { join as join11 } from "path";
|
|
5984
|
+
import { dirname as dirname5, join as join11, resolve as resolve4, isAbsolute } from "path";
|
|
5843
5985
|
var CONFIG_PATH_ENV_VAR = "BABYCLAW_CONFIG_PATH";
|
|
5844
5986
|
function getDefaultConfigPath() {
|
|
5845
5987
|
return join11(homedir2(), ".babyclaw", "babyclaw.json");
|
|
@@ -5851,6 +5993,18 @@ function getConfigPath() {
|
|
|
5851
5993
|
}
|
|
5852
5994
|
return getDefaultConfigPath();
|
|
5853
5995
|
}
|
|
5996
|
+
function getConfigDir() {
|
|
5997
|
+
return dirname5(getConfigPath());
|
|
5998
|
+
}
|
|
5999
|
+
function resolveWorkspaceRoot({ configRoot }) {
|
|
6000
|
+
if (configRoot === "~" || configRoot.startsWith("~/")) {
|
|
6001
|
+
return join11(homedir2(), configRoot.slice(2));
|
|
6002
|
+
}
|
|
6003
|
+
if (isAbsolute(configRoot)) {
|
|
6004
|
+
return configRoot;
|
|
6005
|
+
}
|
|
6006
|
+
return resolve4(getConfigDir(), configRoot);
|
|
6007
|
+
}
|
|
5854
6008
|
|
|
5855
6009
|
// src/config/schema.ts
|
|
5856
6010
|
import { z as z11 } from "zod";
|
|
@@ -6004,9 +6158,9 @@ var babyclawConfigSchema = z11.object({
|
|
|
6004
6158
|
timezone: "UTC"
|
|
6005
6159
|
}),
|
|
6006
6160
|
workspace: z11.object({
|
|
6007
|
-
root: z11.string().min(1).default("
|
|
6161
|
+
root: z11.string().min(1).default("~/babyclaw")
|
|
6008
6162
|
}).strict().default({
|
|
6009
|
-
root: "
|
|
6163
|
+
root: "~/babyclaw"
|
|
6010
6164
|
}),
|
|
6011
6165
|
session: z11.object({
|
|
6012
6166
|
maxMessagesPerSession: z11.number().int().positive().default(120),
|
|
@@ -6066,7 +6220,7 @@ var DEFAULT_CONFIG_TEMPLATE = {
|
|
|
6066
6220
|
timezone: "UTC"
|
|
6067
6221
|
},
|
|
6068
6222
|
workspace: {
|
|
6069
|
-
root: "
|
|
6223
|
+
root: "~/babyclaw"
|
|
6070
6224
|
},
|
|
6071
6225
|
session: {
|
|
6072
6226
|
maxMessagesPerSession: 120,
|
|
@@ -6123,6 +6277,22 @@ ${issues}`);
|
|
|
6123
6277
|
log.info({ configPath }, "Configuration validated successfully");
|
|
6124
6278
|
return parsed.data;
|
|
6125
6279
|
}
|
|
6280
|
+
async function loadConfigRaw() {
|
|
6281
|
+
const configPath = getConfigPath();
|
|
6282
|
+
try {
|
|
6283
|
+
await access(configPath);
|
|
6284
|
+
} catch {
|
|
6285
|
+
return null;
|
|
6286
|
+
}
|
|
6287
|
+
const raw = await readFile8(configPath, "utf8");
|
|
6288
|
+
const json = parseJsonConfig({ raw, configPath });
|
|
6289
|
+
normalizeLegacyTelegramConfig({ json });
|
|
6290
|
+
const parsed = babyclawConfigSchema.safeParse(json);
|
|
6291
|
+
if (!parsed.success) {
|
|
6292
|
+
return null;
|
|
6293
|
+
}
|
|
6294
|
+
return parsed.data;
|
|
6295
|
+
}
|
|
6126
6296
|
async function ensureConfigFileExists({ configPath }) {
|
|
6127
6297
|
try {
|
|
6128
6298
|
await access(configPath);
|
|
@@ -6131,7 +6301,7 @@ async function ensureConfigFileExists({ configPath }) {
|
|
|
6131
6301
|
if (error.code !== "ENOENT") {
|
|
6132
6302
|
throw error;
|
|
6133
6303
|
}
|
|
6134
|
-
await mkdir5(
|
|
6304
|
+
await mkdir5(dirname6(configPath), { recursive: true });
|
|
6135
6305
|
await writeFile5(configPath, getDefaultConfigTemplate(), "utf8");
|
|
6136
6306
|
getLogger().warn({ configPath }, "Created config file. Fill required secrets and restart.");
|
|
6137
6307
|
}
|
|
@@ -6303,6 +6473,7 @@ var HeartbeatExecutor = class {
|
|
|
6303
6473
|
toolDeps: this.toolDeps,
|
|
6304
6474
|
executionContext: {
|
|
6305
6475
|
workspaceRoot: workspacePath,
|
|
6476
|
+
bundledSkillsDir: this.toolDeps.bundledSkillsDir,
|
|
6306
6477
|
botTimezone: schedulerService.getTimezone(),
|
|
6307
6478
|
platform: mainChat.platform,
|
|
6308
6479
|
chatId: platformChatId,
|
|
@@ -6759,6 +6930,7 @@ var SchedulerExecutor = class {
|
|
|
6759
6930
|
toolDeps: this.toolDeps,
|
|
6760
6931
|
executionContext: {
|
|
6761
6932
|
workspaceRoot: workspacePath,
|
|
6933
|
+
bundledSkillsDir: this.toolDeps.bundledSkillsDir,
|
|
6762
6934
|
botTimezone: schedulerService.getTimezone(),
|
|
6763
6935
|
platform: this.channelSender.platform,
|
|
6764
6936
|
chatId: chatIdStr,
|
|
@@ -7505,13 +7677,13 @@ function createDatabase({ workspacePath }) {
|
|
|
7505
7677
|
}
|
|
7506
7678
|
|
|
7507
7679
|
// src/database/migrate.ts
|
|
7508
|
-
import { dirname as
|
|
7680
|
+
import { dirname as dirname7, resolve as resolve5 } from "path";
|
|
7509
7681
|
import { fileURLToPath } from "url";
|
|
7510
7682
|
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
|
7511
|
-
var __dirname =
|
|
7683
|
+
var __dirname = dirname7(fileURLToPath(import.meta.url));
|
|
7512
7684
|
function applyMigrations({ workspacePath }) {
|
|
7513
7685
|
const db = createDatabase({ workspacePath });
|
|
7514
|
-
const migrationsFolder =
|
|
7686
|
+
const migrationsFolder = resolve5(__dirname, "..", "drizzle");
|
|
7515
7687
|
migrate(db, { migrationsFolder });
|
|
7516
7688
|
}
|
|
7517
7689
|
|
|
@@ -7549,7 +7721,8 @@ var GatewayRuntime = class {
|
|
|
7549
7721
|
},
|
|
7550
7722
|
"Gateway configuration summary"
|
|
7551
7723
|
);
|
|
7552
|
-
const workspacePath =
|
|
7724
|
+
const workspacePath = resolveWorkspaceRoot({ configRoot: config.workspace.root });
|
|
7725
|
+
mkdirSync3(workspacePath, { recursive: true });
|
|
7553
7726
|
log.info("Applying database migrations...");
|
|
7554
7727
|
applyMigrations({ workspacePath });
|
|
7555
7728
|
log.info("Database migrations applied");
|
|
@@ -7633,6 +7806,7 @@ var GatewayRuntime = class {
|
|
|
7633
7806
|
const adminSocketPath = getAdminSocketPath();
|
|
7634
7807
|
const toolDeps = {
|
|
7635
7808
|
workspacePath,
|
|
7809
|
+
bundledSkillsDir: getBundledSkillsDir(),
|
|
7636
7810
|
aiAgent,
|
|
7637
7811
|
sessionManager,
|
|
7638
7812
|
schedulerService,
|
|
@@ -7738,6 +7912,16 @@ var GatewayRuntime = class {
|
|
|
7738
7912
|
void this.stop().then(() => process.exit(0));
|
|
7739
7913
|
});
|
|
7740
7914
|
return { ok: true };
|
|
7915
|
+
},
|
|
7916
|
+
"/reload-skills": async () => {
|
|
7917
|
+
const freshConfig = await loadConfigRaw();
|
|
7918
|
+
if (!freshConfig) {
|
|
7919
|
+
return { ok: false, error: "config_not_found" };
|
|
7920
|
+
}
|
|
7921
|
+
toolDeps.skillsConfig = freshConfig.skills;
|
|
7922
|
+
toolDeps.fullConfig = freshConfig;
|
|
7923
|
+
log.info("Skills configuration reloaded via admin socket");
|
|
7924
|
+
return { ok: true };
|
|
7741
7925
|
}
|
|
7742
7926
|
}
|
|
7743
7927
|
});
|