babyclaw 0.1.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.
@@ -24,6 +24,9 @@ export default command({
24
24
  ["gateway reload", "Check gateway health / signal a reload"],
25
25
  ["skill install", "Install a skill from ClawHub"],
26
26
  ["skill search", "Search for skills on ClawHub"],
27
+ ["skill bundled", "List available bundled skills"],
28
+ ["skill enable", "Enable a bundled skill"],
29
+ ["skill disable", "Disable a bundled skill"],
27
30
  ["doctor", "Run diagnostics on your setup"],
28
31
  ["update", "Update babyclaw to the latest version"],
29
32
  ];
@@ -0,0 +1,47 @@
1
+ import { command } from "@gud/cli";
2
+ import { loadConfigRaw, listBundledSkills } from "@babyclaw/gateway";
3
+ import { c } from "../../ui/theme.js";
4
+ export default command({
5
+ description: "List available bundled skills",
6
+ handler: async ({ client }) => {
7
+ const config = await loadConfigRaw();
8
+ if (!config) {
9
+ client.log(c.error("✗ No configuration found. Run babyclaw setup first."));
10
+ process.exitCode = 1;
11
+ return;
12
+ }
13
+ const skillsConfig = config.skills ?? { entries: {} };
14
+ const fullConfig = config;
15
+ const skills = listBundledSkills({ skillsConfig, fullConfig });
16
+ if (skills.length === 0) {
17
+ client.log(c.muted(" No bundled skills available."));
18
+ return;
19
+ }
20
+ client.log("");
21
+ client.log(c.bold(" Bundled Skills"));
22
+ client.log("");
23
+ for (const skill of skills) {
24
+ const name = skill.frontmatter?.name ?? skill.slug;
25
+ const desc = skill.frontmatter?.description ?? "";
26
+ let status;
27
+ if (skill.enabled) {
28
+ status = c.success("enabled");
29
+ }
30
+ else if (!skill.eligible) {
31
+ status = c.error("ineligible");
32
+ }
33
+ else {
34
+ status = c.muted("disabled");
35
+ }
36
+ client.log(` ${c.bold(name)} ${c.muted("·")} ${status}`);
37
+ if (desc) {
38
+ client.log(` ${c.muted(desc)}`);
39
+ }
40
+ if (!skill.eligible && skill.ineligibilityReason) {
41
+ client.log(` ${c.warning(skill.ineligibilityReason)}`);
42
+ }
43
+ }
44
+ client.log("");
45
+ client.log(c.muted(" Enable a skill with ") + c.info("babyclaw skill enable --slug <name>"));
46
+ },
47
+ });
@@ -0,0 +1,87 @@
1
+ import { command } from "@gud/cli";
2
+ import { loadConfigRaw, writeConfig, listBundledSkills, getSkillKey, AdminClient, getAdminSocketPath, } from "@babyclaw/gateway";
3
+ import { c } from "../../ui/theme.js";
4
+ export default command({
5
+ description: "Disable a bundled skill",
6
+ options: {
7
+ slug: {
8
+ type: "string",
9
+ description: "Bundled skill slug to disable",
10
+ },
11
+ },
12
+ handler: async ({ options, client }) => {
13
+ const config = await loadConfigRaw();
14
+ if (!config) {
15
+ client.log(c.error("✗ No configuration found. Run babyclaw setup first."));
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const skillsConfig = config.skills ?? { entries: {} };
20
+ const fullConfig = config;
21
+ const bundled = listBundledSkills({ skillsConfig, fullConfig });
22
+ let slug = await options.slug();
23
+ if (!slug) {
24
+ const disableable = bundled.filter((s) => s.enabled);
25
+ if (disableable.length === 0) {
26
+ client.log(c.muted(" No skills are currently enabled."));
27
+ return;
28
+ }
29
+ const choices = disableable.map((s) => ({
30
+ title: `${s.frontmatter?.name ?? s.slug} ${c.muted("—")} ${c.muted(s.frontmatter?.description ?? "")}`,
31
+ value: s.slug,
32
+ }));
33
+ choices.push({ title: c.muted("Cancel"), value: "__cancel__" });
34
+ const selected = await client.prompt({
35
+ type: "select",
36
+ message: "Select a skill to disable",
37
+ choices,
38
+ });
39
+ if (selected === "__cancel__")
40
+ return;
41
+ slug = selected;
42
+ }
43
+ const skill = bundled.find((s) => s.slug === slug);
44
+ if (!skill) {
45
+ client.log(c.error(`✗ Bundled skill "${slug}" not found.`));
46
+ client.log(c.muted(" Run ") + c.info("babyclaw skill bundled") + c.muted(" to see available skills."));
47
+ process.exitCode = 1;
48
+ return;
49
+ }
50
+ if (!skill.enabled) {
51
+ client.log(c.warning(`⚠ Skill "${slug}" is already disabled.`));
52
+ return;
53
+ }
54
+ try {
55
+ const skillKey = getSkillKey({ frontmatter: skill.frontmatter, slug });
56
+ const updatedConfig = {
57
+ ...config,
58
+ skills: {
59
+ ...config.skills,
60
+ entries: {
61
+ ...config.skills.entries,
62
+ [skillKey]: {
63
+ ...config.skills.entries[skillKey],
64
+ enabled: false,
65
+ },
66
+ },
67
+ },
68
+ };
69
+ await writeConfig({ config: updatedConfig });
70
+ try {
71
+ const admin = new AdminClient({ socketPath: getAdminSocketPath() });
72
+ await admin.reloadSkills();
73
+ }
74
+ catch {
75
+ // Gateway may not be running -- that's fine, config is saved
76
+ }
77
+ const displayName = skill.frontmatter?.name ?? slug;
78
+ client.log(c.success("✓ Disabled ") + c.bold(displayName));
79
+ client.log(c.muted(" The skill has been removed."));
80
+ }
81
+ catch (error) {
82
+ client.log(c.error(`✗ Failed to disable skill "${slug}"`));
83
+ client.log(c.muted(` ${error instanceof Error ? error.message : String(error)}`));
84
+ process.exitCode = 1;
85
+ }
86
+ },
87
+ });
@@ -0,0 +1,126 @@
1
+ import { command } from "@gud/cli";
2
+ import { loadConfigRaw, writeConfig, listBundledSkills, getBundledSkillPath, runSkillSetup, resolveLanguageModel, resolveWorkspaceRoot, getSkillKey, AdminClient, getAdminSocketPath, } from "@babyclaw/gateway";
3
+ import { c } from "../../ui/theme.js";
4
+ export default command({
5
+ description: "Enable a bundled skill",
6
+ options: {
7
+ slug: {
8
+ type: "string",
9
+ description: "Bundled skill slug to enable",
10
+ },
11
+ "skip-setup": {
12
+ type: "boolean",
13
+ description: "Skip automatic dependency setup",
14
+ },
15
+ },
16
+ handler: async ({ options, client }) => {
17
+ const skipSetup = await options["skip-setup"]();
18
+ const config = await loadConfigRaw();
19
+ if (!config) {
20
+ client.log(c.error("✗ No configuration found. Run babyclaw setup first."));
21
+ process.exitCode = 1;
22
+ return;
23
+ }
24
+ const workspacePath = resolveWorkspaceRoot({
25
+ configRoot: config.workspace.root,
26
+ });
27
+ const skillsConfig = config.skills ?? { entries: {} };
28
+ const fullConfig = config;
29
+ const bundled = listBundledSkills({ skillsConfig, fullConfig });
30
+ let slug = await options.slug();
31
+ if (!slug) {
32
+ const enableable = bundled.filter((s) => s.eligible && !s.enabled);
33
+ if (enableable.length === 0) {
34
+ client.log(c.muted(" No skills available to enable."));
35
+ return;
36
+ }
37
+ const choices = enableable.map((s) => ({
38
+ title: `${s.frontmatter?.name ?? s.slug} ${c.muted("—")} ${c.muted(s.frontmatter?.description ?? "")}`,
39
+ value: s.slug,
40
+ }));
41
+ choices.push({ title: c.muted("Cancel"), value: "__cancel__" });
42
+ const selected = await client.prompt({
43
+ type: "select",
44
+ message: "Select a skill to enable",
45
+ choices,
46
+ });
47
+ if (selected === "__cancel__")
48
+ return;
49
+ slug = selected;
50
+ }
51
+ const skill = bundled.find((s) => s.slug === slug);
52
+ if (!skill) {
53
+ client.log(c.error(`✗ Bundled skill "${slug}" not found.`));
54
+ client.log(c.muted(" Run ") + c.info("babyclaw skill bundled") + c.muted(" to see available skills."));
55
+ process.exitCode = 1;
56
+ return;
57
+ }
58
+ if (!skill.eligible) {
59
+ client.log(c.error(`✗ Skill "${slug}" is not eligible on this system.`));
60
+ if (skill.ineligibilityReason) {
61
+ client.log(c.muted(` ${skill.ineligibilityReason}`));
62
+ }
63
+ process.exitCode = 1;
64
+ return;
65
+ }
66
+ if (skill.enabled) {
67
+ client.log(c.warning(`⚠ Skill "${slug}" is already enabled.`));
68
+ return;
69
+ }
70
+ try {
71
+ const skillKey = getSkillKey({ frontmatter: skill.frontmatter, slug });
72
+ const updatedConfig = {
73
+ ...config,
74
+ skills: {
75
+ ...config.skills,
76
+ entries: {
77
+ ...config.skills.entries,
78
+ [skillKey]: {
79
+ ...config.skills.entries[skillKey],
80
+ enabled: true,
81
+ },
82
+ },
83
+ },
84
+ };
85
+ await writeConfig({ config: updatedConfig });
86
+ try {
87
+ const admin = new AdminClient({ socketPath: getAdminSocketPath() });
88
+ await admin.reloadSkills();
89
+ }
90
+ catch {
91
+ // Gateway may not be running -- that's fine, config is saved
92
+ }
93
+ let setupResult = null;
94
+ let setupError = null;
95
+ const skillPath = getBundledSkillPath({ slug });
96
+ if (!skipSetup && skillPath) {
97
+ try {
98
+ const model = resolveLanguageModel({ config });
99
+ setupResult = await runSkillSetup({
100
+ model,
101
+ skillPath,
102
+ workspacePath,
103
+ });
104
+ }
105
+ catch (err) {
106
+ setupError = err instanceof Error ? err.message : String(err);
107
+ }
108
+ }
109
+ const displayName = skill.frontmatter?.name ?? slug;
110
+ client.log(c.success("✓ Enabled ") + c.bold(displayName));
111
+ if (setupResult && !setupResult.skipped) {
112
+ client.log(c.success(" ✓ Dependencies set up"));
113
+ }
114
+ if (setupError) {
115
+ client.log(c.warning(" ⚠ Dependency setup failed"));
116
+ client.log(c.muted(` ${setupError}`));
117
+ }
118
+ client.log(c.muted(" The skill is now available."));
119
+ }
120
+ catch (error) {
121
+ client.log(c.error(`✗ Failed to enable skill "${slug}"`));
122
+ client.log(c.muted(` ${error instanceof Error ? error.message : String(error)}`));
123
+ process.exitCode = 1;
124
+ }
125
+ },
126
+ });
@@ -1,6 +1,5 @@
1
1
  import { command } from "@gud/cli";
2
- import { resolve } from "node:path";
3
- import { loadConfigRaw, installSkillFromClawHub, runSkillSetup, resolveLanguageModel, SkillAlreadyInstalledError, ClawHubError, } from "@babyclaw/gateway";
2
+ import { loadConfigRaw, installSkillFromClawHub, runSkillSetup, resolveLanguageModel, resolveWorkspaceRoot, SkillAlreadyInstalledError, ClawHubError, } from "@babyclaw/gateway";
4
3
  import { c } from "../../ui/theme.js";
5
4
  export default command({
6
5
  description: "Install a skill from ClawHub",
@@ -30,7 +29,9 @@ export default command({
30
29
  const skipSetup = await options["skip-setup"]();
31
30
  try {
32
31
  const config = await loadConfigRaw();
33
- const workspacePath = resolve(process.cwd(), config?.workspace?.root ?? ".");
32
+ const workspacePath = resolveWorkspaceRoot({
33
+ configRoot: config?.workspace?.root ?? "~/babyclaw",
34
+ });
34
35
  const installResult = await installSkillFromClawHub({
35
36
  slug,
36
37
  version: version || undefined,
@@ -1,6 +1,5 @@
1
1
  import { command } from "@gud/cli";
2
- import { resolve } from "node:path";
3
- import { loadConfigRaw, installSkillFromClawHub, runSkillSetup, resolveLanguageModel, SkillAlreadyInstalledError, } from "@babyclaw/gateway";
2
+ import { loadConfigRaw, installSkillFromClawHub, runSkillSetup, resolveLanguageModel, resolveWorkspaceRoot, SkillAlreadyInstalledError, } from "@babyclaw/gateway";
4
3
  import { c } from "../../ui/theme.js";
5
4
  const CLAWHUB_SEARCH_URL = "https://clawhub.ai/api/v1/search";
6
5
  export default command({
@@ -64,7 +63,9 @@ export default command({
64
63
  client.log("");
65
64
  try {
66
65
  const config = await loadConfigRaw();
67
- const workspacePath = resolve(process.cwd(), config?.workspace?.root ?? ".");
66
+ const workspacePath = resolveWorkspaceRoot({
67
+ configRoot: config?.workspace?.root ?? "~/babyclaw",
68
+ });
68
69
  const installResult = await installSkillFromClawHub({
69
70
  slug,
70
71
  workspacePath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babyclaw",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The babyclaw command-line interface",
5
5
  "keywords": [
6
6
  "agent",
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "@gud/cli": "1.0.0-beta.7",
26
26
  "picocolors": "^1.1.1",
27
- "@babyclaw/gateway": "0.0.1"
27
+ "@babyclaw/gateway": "0.2.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^24.3.0",