@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.js CHANGED
@@ -5,7 +5,8 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/runtime.ts
8
- import { resolve as resolve5 } from "path";
8
+ import { mkdirSync as mkdirSync3 } from "fs";
9
+ import { getBundledSkillsDir } from "@babyclaw/skills";
9
10
 
10
11
  // src/ai/agent.ts
11
12
  import {
@@ -280,37 +281,84 @@ var SUPPORTED_PROVIDERS = [
280
281
  {
281
282
  id: "anthropic",
282
283
  displayName: "Anthropic",
283
- exampleModels: ["claude-sonnet-4-20250514", "claude-opus-4-6", "claude-haiku-4-5"]
284
+ exampleModels: [
285
+ "claude-sonnet-4-20250514",
286
+ "claude-opus-4-6",
287
+ "claude-haiku-4-5",
288
+ "claude-4.5-sonnet",
289
+ "claude-3.5-sonnet-20241022",
290
+ "claude-3.5-haiku-20241022"
291
+ ]
284
292
  },
285
293
  {
286
294
  id: "openai",
287
295
  displayName: "OpenAI",
288
- exampleModels: ["gpt-4o", "gpt-4o-mini", "o3-mini"]
296
+ exampleModels: [
297
+ "gpt-4o",
298
+ "gpt-4o-mini",
299
+ "gpt-4.1",
300
+ "gpt-4.1-mini",
301
+ "gpt-4.1-nano",
302
+ "o3",
303
+ "o3-mini",
304
+ "o4-mini"
305
+ ]
289
306
  },
290
307
  {
291
308
  id: "google",
292
309
  displayName: "Google Generative AI",
293
- exampleModels: ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash"]
310
+ exampleModels: [
311
+ "gemini-2.5-pro",
312
+ "gemini-2.5-flash",
313
+ "gemini-2.0-flash",
314
+ "gemini-2.0-flash-lite"
315
+ ]
294
316
  },
295
317
  {
296
318
  id: "mistral",
297
319
  displayName: "Mistral",
298
- exampleModels: ["mistral-large-latest", "mistral-small-latest"]
320
+ exampleModels: [
321
+ "mistral-large-latest",
322
+ "mistral-medium-latest",
323
+ "mistral-small-latest",
324
+ "codestral-latest",
325
+ "pixtral-large-latest"
326
+ ]
299
327
  },
300
328
  {
301
329
  id: "xai",
302
330
  displayName: "xAI",
303
- exampleModels: ["grok-3", "grok-3-mini"]
331
+ exampleModels: ["grok-3", "grok-3-fast", "grok-3-mini", "grok-3-mini-fast"]
304
332
  },
305
333
  {
306
334
  id: "openrouter",
307
335
  displayName: "OpenRouter",
308
- exampleModels: ["anthropic/claude-sonnet-4", "openai/gpt-4o", "google/gemini-2.5-pro"]
336
+ exampleModels: [
337
+ "anthropic/claude-sonnet-4",
338
+ "anthropic/claude-opus-4",
339
+ "anthropic/claude-4.5-sonnet",
340
+ "openai/gpt-4o",
341
+ "openai/gpt-4.1",
342
+ "openai/o3",
343
+ "openai/o4-mini",
344
+ "google/gemini-2.5-pro",
345
+ "google/gemini-2.5-flash",
346
+ "deepseek/deepseek-r1",
347
+ "deepseek/deepseek-chat-v3",
348
+ "meta-llama/llama-4-maverick",
349
+ "meta-llama/llama-4-scout"
350
+ ]
309
351
  },
310
352
  {
311
353
  id: "gateway",
312
354
  displayName: "Vercel AI Gateway",
313
- exampleModels: ["anthropic/claude-sonnet-4-20250514", "openai/gpt-4o"]
355
+ exampleModels: [
356
+ "anthropic/claude-sonnet-4-20250514",
357
+ "anthropic/claude-opus-4-6",
358
+ "openai/gpt-4o",
359
+ "openai/gpt-4.1",
360
+ "google/gemini-2.5-pro"
361
+ ]
314
362
  }
315
363
  ];
316
364
  var PROVIDER_FACTORY_MAP = {
@@ -1995,9 +2043,26 @@ import { z } from "zod";
1995
2043
  // src/utils/path.ts
1996
2044
  import { resolve, sep } from "path";
1997
2045
  import { stat } from "fs/promises";
2046
+ var BUNDLED_SKILLS_PREFIX = "bundled-skills/";
1998
2047
  function normalizeSeparators({ path }) {
1999
2048
  return path.replaceAll("\\", "/");
2000
2049
  }
2050
+ function resolveBundledSkillPath({
2051
+ bundledSkillsDir,
2052
+ requestedPath
2053
+ }) {
2054
+ const relative3 = requestedPath.slice(BUNDLED_SKILLS_PREFIX.length);
2055
+ const normalized = normalizeSeparators({ path: relative3 }).trim();
2056
+ if (normalized.length === 0) {
2057
+ throw new Error("Path is required");
2058
+ }
2059
+ const absoluteRoot = resolve(bundledSkillsDir);
2060
+ const absoluteTarget = resolve(absoluteRoot, normalized);
2061
+ if (!isSubPath({ parent: absoluteRoot, child: absoluteTarget })) {
2062
+ throw new Error("Path escapes bundled skills root");
2063
+ }
2064
+ return absoluteTarget;
2065
+ }
2001
2066
  function resolveWorkspacePath({
2002
2067
  workspaceRoot,
2003
2068
  requestedPath
@@ -3754,10 +3819,25 @@ function createWorkspaceTools({ context }) {
3754
3819
  defaultCode: "WORKSPACE_READ_FAILED",
3755
3820
  input: { path, format },
3756
3821
  action: async () => {
3757
- const absolutePath = resolveWorkspacePath({
3758
- workspaceRoot: context.workspaceRoot,
3759
- requestedPath: path
3760
- });
3822
+ const isBundled = path.startsWith(BUNDLED_SKILLS_PREFIX);
3823
+ let absolutePath;
3824
+ if (isBundled) {
3825
+ if (!context.bundledSkillsDir) {
3826
+ throw new ToolExecutionError({
3827
+ code: "BUNDLED_SKILLS_UNAVAILABLE",
3828
+ message: "Bundled skills directory is not configured"
3829
+ });
3830
+ }
3831
+ absolutePath = resolveBundledSkillPath({
3832
+ bundledSkillsDir: context.bundledSkillsDir,
3833
+ requestedPath: path
3834
+ });
3835
+ } else {
3836
+ absolutePath = resolveWorkspacePath({
3837
+ workspaceRoot: context.workspaceRoot,
3838
+ requestedPath: path
3839
+ });
3840
+ }
3761
3841
  const raw = await readFile6(absolutePath, "utf8");
3762
3842
  ensurePayloadWithinLimit({
3763
3843
  value: raw,
@@ -3815,6 +3895,12 @@ function createWorkspaceTools({ context }) {
3815
3895
  hasValue: value !== void 0
3816
3896
  },
3817
3897
  action: async () => {
3898
+ if (path.startsWith(BUNDLED_SKILLS_PREFIX)) {
3899
+ throw new ToolExecutionError({
3900
+ code: "BUNDLED_SKILLS_READONLY",
3901
+ message: "Bundled skills are read-only and cannot be written to"
3902
+ });
3903
+ }
3818
3904
  const absolutePath = resolveWorkspacePath({
3819
3905
  workspaceRoot: context.workspaceRoot,
3820
3906
  requestedPath: path
@@ -3954,6 +4040,12 @@ function createWorkspaceTools({ context }) {
3954
4040
  defaultCode: "WORKSPACE_DELETE_FAILED",
3955
4041
  input: { path, recursive },
3956
4042
  action: async () => {
4043
+ if (path.startsWith(BUNDLED_SKILLS_PREFIX)) {
4044
+ throw new ToolExecutionError({
4045
+ code: "BUNDLED_SKILLS_READONLY",
4046
+ message: "Bundled skills are read-only and cannot be deleted"
4047
+ });
4048
+ }
3957
4049
  const absolutePath = resolveWorkspacePath({
3958
4050
  workspaceRoot: context.workspaceRoot,
3959
4051
  requestedPath: path
@@ -3990,6 +4082,12 @@ function createWorkspaceTools({ context }) {
3990
4082
  defaultCode: "WORKSPACE_MOVE_FAILED",
3991
4083
  input: { from_path, to_path, overwrite },
3992
4084
  action: async () => {
4085
+ if (from_path.startsWith(BUNDLED_SKILLS_PREFIX) || to_path.startsWith(BUNDLED_SKILLS_PREFIX)) {
4086
+ throw new ToolExecutionError({
4087
+ code: "BUNDLED_SKILLS_READONLY",
4088
+ message: "Bundled skills are read-only and cannot be moved"
4089
+ });
4090
+ }
3993
4091
  const fromAbsolute = resolveWorkspacePath({
3994
4092
  workspaceRoot: context.workspaceRoot,
3995
4093
  requestedPath: from_path
@@ -4170,44 +4268,15 @@ function createUnifiedTools({
4170
4268
  };
4171
4269
  }
4172
4270
 
4173
- // src/onboarding/personality.ts
4174
- import { readFile as readFile7 } from "fs/promises";
4175
- import { join as join9 } from "path";
4176
- function getPersonalityFilePaths({ workspacePath }) {
4177
- return {
4178
- identityPath: join9(workspacePath, "IDENTITY.md"),
4179
- soulPath: join9(workspacePath, "SOUL.md"),
4180
- userPath: join9(workspacePath, "USER.md")
4181
- };
4182
- }
4183
- async function readPersonalityFiles({
4184
- workspacePath
4271
+ // src/bundled-skills/index.ts
4272
+ import { listBundledSlugs, readBundledSkillContent, getBundledSkillInfo } from "@babyclaw/skills";
4273
+
4274
+ // src/workspace/skills/types.ts
4275
+ function getSkillKey({
4276
+ frontmatter,
4277
+ slug
4185
4278
  }) {
4186
- const { identityPath, soulPath, userPath } = getPersonalityFilePaths({ workspacePath });
4187
- const [identity, soul, user] = await Promise.all([
4188
- readOptionalFile2({ path: identityPath }),
4189
- readOptionalFile2({ path: soulPath }),
4190
- readOptionalFile2({ path: userPath })
4191
- ]);
4192
- return {
4193
- identity,
4194
- soul,
4195
- user
4196
- };
4197
- }
4198
- function hasCompletePersonalityFiles(files) {
4199
- 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;
4200
- }
4201
- async function readOptionalFile2({ path }) {
4202
- try {
4203
- return await readFile7(path, "utf8");
4204
- } catch (error) {
4205
- const maybeErrno = error;
4206
- if (maybeErrno.code === "ENOENT") {
4207
- return null;
4208
- }
4209
- throw error;
4210
- }
4279
+ return frontmatter?.openclaw?.skillKey ?? frontmatter?.name ?? slug;
4211
4280
  }
4212
4281
 
4213
4282
  // src/workspace/skills/eligibility.ts
@@ -4217,54 +4286,84 @@ function getEligibleSkills({
4217
4286
  skillsConfig,
4218
4287
  fullConfig
4219
4288
  }) {
4220
- return skills.filter((skill) => shouldIncludeSkill({ skill, skillsConfig, fullConfig }));
4289
+ return skills.filter((skill) => {
4290
+ const { frontmatter, slug } = skill;
4291
+ const entry = skillsConfig.entries[getSkillKey({ frontmatter, slug })];
4292
+ if (entry?.enabled === false) return false;
4293
+ return checkSkillEligibility({ frontmatter, skillsConfig, fullConfig }).eligible;
4294
+ });
4221
4295
  }
4222
- function shouldIncludeSkill({
4223
- skill,
4296
+ function checkSkillEligibility({
4297
+ frontmatter,
4224
4298
  skillsConfig,
4225
4299
  fullConfig
4226
4300
  }) {
4227
- const { frontmatter } = skill;
4301
+ if (frontmatter.disableModelInvocation) {
4302
+ return { eligible: false, reason: "Model invocation disabled" };
4303
+ }
4228
4304
  const openclaw = frontmatter.openclaw;
4229
- const skillKey = openclaw?.skillKey ?? frontmatter.name;
4230
- const entry = skillsConfig.entries[skillKey];
4231
- if (entry?.enabled === false) return false;
4232
- if (frontmatter.disableModelInvocation) return false;
4233
4305
  if (openclaw?.os && openclaw.os.length > 0) {
4234
- if (!openclaw.os.includes(process.platform)) return false;
4306
+ if (!openclaw.os.includes(process.platform)) {
4307
+ return {
4308
+ eligible: false,
4309
+ reason: `Requires OS: ${openclaw.os.join(", ")} (current: ${process.platform})`
4310
+ };
4311
+ }
4312
+ }
4313
+ if (openclaw?.always) {
4314
+ return { eligible: true, reason: null };
4235
4315
  }
4236
- if (openclaw?.always) return true;
4237
4316
  const requires = openclaw?.requires;
4238
- if (!requires) return true;
4317
+ if (!requires) {
4318
+ return { eligible: true, reason: null };
4319
+ }
4239
4320
  if (requires.bins && requires.bins.length > 0) {
4240
- if (!requires.bins.every((bin) => binaryExists({ name: bin }))) return false;
4321
+ const missing = requires.bins.filter((bin) => !binaryExists({ name: bin }));
4322
+ if (missing.length > 0) {
4323
+ return { eligible: false, reason: `Missing binaries: ${missing.join(", ")}` };
4324
+ }
4241
4325
  }
4242
4326
  if (requires.anyBins && requires.anyBins.length > 0) {
4243
- if (!requires.anyBins.some((bin) => binaryExists({ name: bin }))) return false;
4327
+ if (!requires.anyBins.some((bin) => binaryExists({ name: bin }))) {
4328
+ return {
4329
+ eligible: false,
4330
+ reason: `Requires at least one of: ${requires.anyBins.join(", ")}`
4331
+ };
4332
+ }
4244
4333
  }
4245
4334
  if (requires.env && requires.env.length > 0) {
4335
+ const skillKey = openclaw?.skillKey ?? frontmatter.name;
4336
+ const entry = skillsConfig.entries[skillKey];
4246
4337
  const primaryEnv = openclaw?.primaryEnv;
4247
4338
  const hasApiKeyInConfig = Boolean(entry?.apiKey);
4248
4339
  for (const envVar of requires.env) {
4249
4340
  if (process.env[envVar]) continue;
4250
4341
  if (primaryEnv === envVar && hasApiKeyInConfig) continue;
4251
- return false;
4342
+ return { eligible: false, reason: `Missing environment variable: ${envVar}` };
4252
4343
  }
4253
4344
  }
4254
4345
  if (requires.config && requires.config.length > 0) {
4255
4346
  for (const configPath of requires.config) {
4256
- if (!getConfigValue({ config: fullConfig, path: configPath })) return false;
4347
+ if (!getConfigValue({ config: fullConfig, path: configPath })) {
4348
+ return { eligible: false, reason: `Missing config value: ${configPath}` };
4349
+ }
4257
4350
  }
4258
4351
  }
4259
- return true;
4352
+ return { eligible: true, reason: null };
4260
4353
  }
4354
+ var binaryExistsCache = /* @__PURE__ */ new Map();
4261
4355
  function binaryExists({ name }) {
4356
+ const cached = binaryExistsCache.get(name);
4357
+ if (cached !== void 0) return cached;
4358
+ let exists;
4262
4359
  try {
4263
4360
  execFileSync("which", [name], { stdio: "ignore" });
4264
- return true;
4361
+ exists = true;
4265
4362
  } catch {
4266
- return false;
4363
+ exists = false;
4267
4364
  }
4365
+ binaryExistsCache.set(name, exists);
4366
+ return exists;
4268
4367
  }
4269
4368
  function getConfigValue({
4270
4369
  config,
@@ -4279,6 +4378,94 @@ function getConfigValue({
4279
4378
  return current;
4280
4379
  }
4281
4380
 
4381
+ // src/bundled-skills/index.ts
4382
+ function listBundledSkills({
4383
+ skillsConfig,
4384
+ fullConfig
4385
+ }) {
4386
+ const slugs = listBundledSlugs();
4387
+ return slugs.map((slug) => {
4388
+ const content = readBundledSkillContent({ slug });
4389
+ if (!content) {
4390
+ return {
4391
+ slug,
4392
+ frontmatter: null,
4393
+ enabled: false,
4394
+ eligible: false,
4395
+ ineligibilityReason: "Could not read SKILL.md"
4396
+ };
4397
+ }
4398
+ const raw = parseFrontmatter({ content });
4399
+ const frontmatter = raw ? buildFrontmatter({ raw }) : null;
4400
+ const skillKey = getSkillKey({ frontmatter, slug });
4401
+ const entry = skillsConfig.entries[skillKey];
4402
+ const enabled = entry?.enabled === true;
4403
+ const { eligible, reason } = frontmatter ? checkSkillEligibility({ frontmatter, skillsConfig, fullConfig }) : { eligible: false, reason: "Invalid frontmatter" };
4404
+ return {
4405
+ slug,
4406
+ frontmatter,
4407
+ enabled,
4408
+ eligible,
4409
+ ineligibilityReason: reason
4410
+ };
4411
+ });
4412
+ }
4413
+ function getEnabledBundledSkills({
4414
+ skillsConfig,
4415
+ fullConfig
4416
+ }) {
4417
+ const all = listBundledSkills({ skillsConfig, fullConfig });
4418
+ return all.filter((s) => s.enabled && s.eligible && s.frontmatter).map((s) => ({
4419
+ frontmatter: s.frontmatter,
4420
+ slug: s.slug,
4421
+ relativePath: `bundled-skills/${s.slug}/SKILL.md`
4422
+ }));
4423
+ }
4424
+ function getBundledSkillPath({ slug }) {
4425
+ const info = getBundledSkillInfo({ slug });
4426
+ return info?.skillDir ?? null;
4427
+ }
4428
+
4429
+ // src/onboarding/personality.ts
4430
+ import { readFile as readFile7 } from "fs/promises";
4431
+ import { join as join9 } from "path";
4432
+ function getPersonalityFilePaths({ workspacePath }) {
4433
+ return {
4434
+ identityPath: join9(workspacePath, "IDENTITY.md"),
4435
+ soulPath: join9(workspacePath, "SOUL.md"),
4436
+ userPath: join9(workspacePath, "USER.md")
4437
+ };
4438
+ }
4439
+ async function readPersonalityFiles({
4440
+ workspacePath
4441
+ }) {
4442
+ const { identityPath, soulPath, userPath } = getPersonalityFilePaths({ workspacePath });
4443
+ const [identity, soul, user] = await Promise.all([
4444
+ readOptionalFile2({ path: identityPath }),
4445
+ readOptionalFile2({ path: soulPath }),
4446
+ readOptionalFile2({ path: userPath })
4447
+ ]);
4448
+ return {
4449
+ identity,
4450
+ soul,
4451
+ user
4452
+ };
4453
+ }
4454
+ function hasCompletePersonalityFiles(files) {
4455
+ 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;
4456
+ }
4457
+ async function readOptionalFile2({ path }) {
4458
+ try {
4459
+ return await readFile7(path, "utf8");
4460
+ } catch (error) {
4461
+ const maybeErrno = error;
4462
+ if (maybeErrno.code === "ENOENT") {
4463
+ return null;
4464
+ }
4465
+ throw error;
4466
+ }
4467
+ }
4468
+
4282
4469
  // src/agent/context.ts
4283
4470
  async function loadAgentContext({
4284
4471
  workspacePath,
@@ -4291,7 +4478,11 @@ async function loadAgentContext({
4291
4478
  readWorkspaceGuide({ workspacePath }),
4292
4479
  scanWorkspaceSkills({ workspacePath })
4293
4480
  ]);
4294
- const skills = getEligibleSkills({ skills: allSkills, skillsConfig, fullConfig });
4481
+ const workspaceSkills = getEligibleSkills({ skills: allSkills, skillsConfig, fullConfig });
4482
+ const bundledSkills = getEnabledBundledSkills({ skillsConfig, fullConfig });
4483
+ const workspaceSlugs = new Set(workspaceSkills.map((s) => s.slug));
4484
+ const dedupedBundled = bundledSkills.filter((s) => !workspaceSlugs.has(s.slug));
4485
+ const skills = [...workspaceSkills, ...dedupedBundled];
4295
4486
  const personalityFiles = hasCompletePersonalityFiles(rawPersonalityFiles) ? rawPersonalityFiles : void 0;
4296
4487
  return { personalityFiles, toolNotesContent, agentsContent, skills };
4297
4488
  }
@@ -4472,6 +4663,7 @@ var AgentTurnOrchestrator = class {
4472
4663
  if (abortSignal.aborted) return;
4473
4664
  const {
4474
4665
  workspacePath,
4666
+ bundledSkillsDir,
4475
4667
  aiAgent,
4476
4668
  sessionManager,
4477
4669
  schedulerService,
@@ -4571,6 +4763,7 @@ ${description}`;
4571
4763
  toolDeps: this.toolDeps,
4572
4764
  executionContext: {
4573
4765
  workspaceRoot: workspacePath,
4766
+ bundledSkillsDir,
4574
4767
  botTimezone: schedulerService.getTimezone(),
4575
4768
  platform: event.platform,
4576
4769
  chatId: event.chatId,
@@ -5885,11 +6078,11 @@ var ChatRegistry = class {
5885
6078
 
5886
6079
  // src/config/loader.ts
5887
6080
  import { access, mkdir as mkdir5, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
5888
- import { dirname as dirname5 } from "path";
6081
+ import { dirname as dirname6 } from "path";
5889
6082
 
5890
6083
  // src/config/paths.ts
5891
6084
  import { homedir as homedir2 } from "os";
5892
- import { join as join11 } from "path";
6085
+ import { dirname as dirname5, join as join11, resolve as resolve4, isAbsolute } from "path";
5893
6086
  var CONFIG_PATH_ENV_VAR = "BABYCLAW_CONFIG_PATH";
5894
6087
  function getDefaultConfigPath() {
5895
6088
  return join11(homedir2(), ".babyclaw", "babyclaw.json");
@@ -5901,6 +6094,19 @@ function getConfigPath() {
5901
6094
  }
5902
6095
  return getDefaultConfigPath();
5903
6096
  }
6097
+ function getConfigDir() {
6098
+ return dirname5(getConfigPath());
6099
+ }
6100
+ var DEFAULT_WORKSPACE_ROOT = "~/babyclaw";
6101
+ function resolveWorkspaceRoot({ configRoot }) {
6102
+ if (configRoot === "~" || configRoot.startsWith("~/")) {
6103
+ return join11(homedir2(), configRoot.slice(2));
6104
+ }
6105
+ if (isAbsolute(configRoot)) {
6106
+ return configRoot;
6107
+ }
6108
+ return resolve4(getConfigDir(), configRoot);
6109
+ }
5904
6110
 
5905
6111
  // src/config/schema.ts
5906
6112
  import { z as z11 } from "zod";
@@ -6054,9 +6260,9 @@ var babyclawConfigSchema = z11.object({
6054
6260
  timezone: "UTC"
6055
6261
  }),
6056
6262
  workspace: z11.object({
6057
- root: z11.string().min(1).default(".")
6263
+ root: z11.string().min(1).default("~/babyclaw")
6058
6264
  }).strict().default({
6059
- root: "."
6265
+ root: "~/babyclaw"
6060
6266
  }),
6061
6267
  session: z11.object({
6062
6268
  maxMessagesPerSession: z11.number().int().positive().default(120),
@@ -6116,7 +6322,7 @@ var DEFAULT_CONFIG_TEMPLATE = {
6116
6322
  timezone: "UTC"
6117
6323
  },
6118
6324
  workspace: {
6119
- root: "."
6325
+ root: "~/babyclaw"
6120
6326
  },
6121
6327
  session: {
6122
6328
  maxMessagesPerSession: 120,
@@ -6191,7 +6397,7 @@ async function loadConfigRaw() {
6191
6397
  }
6192
6398
  async function writeConfig({ config }) {
6193
6399
  const configPath = getConfigPath();
6194
- await mkdir5(dirname5(configPath), { recursive: true });
6400
+ await mkdir5(dirname6(configPath), { recursive: true });
6195
6401
  await writeFile5(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
6196
6402
  }
6197
6403
  async function ensureConfigFileExists({ configPath }) {
@@ -6202,7 +6408,7 @@ async function ensureConfigFileExists({ configPath }) {
6202
6408
  if (error.code !== "ENOENT") {
6203
6409
  throw error;
6204
6410
  }
6205
- await mkdir5(dirname5(configPath), { recursive: true });
6411
+ await mkdir5(dirname6(configPath), { recursive: true });
6206
6412
  await writeFile5(configPath, getDefaultConfigTemplate(), "utf8");
6207
6413
  getLogger().warn({ configPath }, "Created config file. Fill required secrets and restart.");
6208
6414
  }
@@ -6374,6 +6580,7 @@ var HeartbeatExecutor = class {
6374
6580
  toolDeps: this.toolDeps,
6375
6581
  executionContext: {
6376
6582
  workspaceRoot: workspacePath,
6583
+ bundledSkillsDir: this.toolDeps.bundledSkillsDir,
6377
6584
  botTimezone: schedulerService.getTimezone(),
6378
6585
  platform: mainChat.platform,
6379
6586
  chatId: platformChatId,
@@ -6830,6 +7037,7 @@ var SchedulerExecutor = class {
6830
7037
  toolDeps: this.toolDeps,
6831
7038
  executionContext: {
6832
7039
  workspaceRoot: workspacePath,
7040
+ bundledSkillsDir: this.toolDeps.bundledSkillsDir,
6833
7041
  botTimezone: schedulerService.getTimezone(),
6834
7042
  platform: this.channelSender.platform,
6835
7043
  chatId: chatIdStr,
@@ -7576,13 +7784,13 @@ function createDatabase({ workspacePath }) {
7576
7784
  }
7577
7785
 
7578
7786
  // src/database/migrate.ts
7579
- import { dirname as dirname6, resolve as resolve4 } from "path";
7787
+ import { dirname as dirname7, resolve as resolve5 } from "path";
7580
7788
  import { fileURLToPath } from "url";
7581
7789
  import { migrate } from "drizzle-orm/better-sqlite3/migrator";
7582
- var __dirname = dirname6(fileURLToPath(import.meta.url));
7790
+ var __dirname = dirname7(fileURLToPath(import.meta.url));
7583
7791
  function applyMigrations({ workspacePath }) {
7584
7792
  const db = createDatabase({ workspacePath });
7585
- const migrationsFolder = resolve4(__dirname, "..", "drizzle");
7793
+ const migrationsFolder = resolve5(__dirname, "..", "drizzle");
7586
7794
  migrate(db, { migrationsFolder });
7587
7795
  }
7588
7796
 
@@ -7620,7 +7828,8 @@ var GatewayRuntime = class {
7620
7828
  },
7621
7829
  "Gateway configuration summary"
7622
7830
  );
7623
- const workspacePath = resolve5(process.cwd(), config.workspace.root);
7831
+ const workspacePath = resolveWorkspaceRoot({ configRoot: config.workspace.root });
7832
+ mkdirSync3(workspacePath, { recursive: true });
7624
7833
  log.info("Applying database migrations...");
7625
7834
  applyMigrations({ workspacePath });
7626
7835
  log.info("Database migrations applied");
@@ -7704,6 +7913,7 @@ var GatewayRuntime = class {
7704
7913
  const adminSocketPath = getAdminSocketPath();
7705
7914
  const toolDeps = {
7706
7915
  workspacePath,
7916
+ bundledSkillsDir: getBundledSkillsDir(),
7707
7917
  aiAgent,
7708
7918
  sessionManager,
7709
7919
  schedulerService,
@@ -7809,6 +8019,16 @@ var GatewayRuntime = class {
7809
8019
  void this.stop().then(() => process.exit(0));
7810
8020
  });
7811
8021
  return { ok: true };
8022
+ },
8023
+ "/reload-skills": async () => {
8024
+ const freshConfig = await loadConfigRaw();
8025
+ if (!freshConfig) {
8026
+ return { ok: false, error: "config_not_found" };
8027
+ }
8028
+ toolDeps.skillsConfig = freshConfig.skills;
8029
+ toolDeps.fullConfig = freshConfig;
8030
+ log.info("Skills configuration reloaded via admin socket");
8031
+ return { ok: true };
7812
8032
  }
7813
8033
  }
7814
8034
  });
@@ -7909,6 +8129,9 @@ var AdminClient = class {
7909
8129
  async shutdown() {
7910
8130
  return this.get({ path: "/shutdown" });
7911
8131
  }
8132
+ async reloadSkills() {
8133
+ return this.get({ path: "/reload-skills" });
8134
+ }
7912
8135
  get({ path }) {
7913
8136
  return new Promise((resolve6, reject) => {
7914
8137
  const req = request(
@@ -7950,6 +8173,7 @@ export {
7950
8173
  AdminClient,
7951
8174
  CONFIG_PATH_ENV_VAR,
7952
8175
  ClawHubError,
8176
+ DEFAULT_WORKSPACE_ROOT,
7953
8177
  GatewayRuntime,
7954
8178
  SUPPORTED_PROVIDERS,
7955
8179
  SkillAlreadyInstalledError,
@@ -7957,14 +8181,19 @@ export {
7957
8181
  createChildLogger,
7958
8182
  createLogger,
7959
8183
  getAdminSocketPath,
8184
+ getBundledSkillPath,
7960
8185
  getConfigPath,
7961
8186
  getDefaultConfigPath,
7962
8187
  getDefaultConfigTemplate,
8188
+ getEnabledBundledSkills,
7963
8189
  getLogger,
8190
+ getSkillKey,
7964
8191
  installSkillFromClawHub,
8192
+ listBundledSkills,
7965
8193
  loadConfig,
7966
8194
  loadConfigRaw,
7967
8195
  resolveLanguageModel,
8196
+ resolveWorkspaceRoot,
7968
8197
  runSkillSetup,
7969
8198
  writeConfig
7970
8199
  };