autohand-cli 0.4.0 → 0.6.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.
@@ -0,0 +1,252 @@
1
+ import {
2
+ AUTOHAND_PATHS
3
+ } from "./chunk-737A24RB.js";
4
+
5
+ // src/commands/skills-new.ts
6
+ import path from "path";
7
+ import fs from "fs-extra";
8
+ import chalk from "chalk";
9
+ import enquirer from "enquirer";
10
+
11
+ // src/skills/types.ts
12
+ var SKILL_CONSTRAINTS = {
13
+ NAME_MAX_LENGTH: 64,
14
+ NAME_PATTERN: /^[a-z0-9-]+$/,
15
+ DESCRIPTION_MAX_LENGTH: 1024,
16
+ COMPATIBILITY_MAX_LENGTH: 500
17
+ };
18
+ function isValidSkillName(name) {
19
+ if (!name || typeof name !== "string") return false;
20
+ if (name.length > SKILL_CONSTRAINTS.NAME_MAX_LENGTH) return false;
21
+ return SKILL_CONSTRAINTS.NAME_PATTERN.test(name);
22
+ }
23
+ function validateSkillFrontmatter(frontmatter) {
24
+ const errors = [];
25
+ if (!frontmatter.name) {
26
+ errors.push("Missing required field: name");
27
+ } else if (!isValidSkillName(frontmatter.name)) {
28
+ errors.push(`Invalid name: must be 1-${SKILL_CONSTRAINTS.NAME_MAX_LENGTH} chars, lowercase alphanumeric with hyphens only`);
29
+ }
30
+ if (!frontmatter.description) {
31
+ errors.push("Missing required field: description");
32
+ } else if (frontmatter.description.length > SKILL_CONSTRAINTS.DESCRIPTION_MAX_LENGTH) {
33
+ errors.push(`Description exceeds ${SKILL_CONSTRAINTS.DESCRIPTION_MAX_LENGTH} characters`);
34
+ }
35
+ if (frontmatter.compatibility && frontmatter.compatibility.length > SKILL_CONSTRAINTS.COMPATIBILITY_MAX_LENGTH) {
36
+ errors.push(`Compatibility exceeds ${SKILL_CONSTRAINTS.COMPATIBILITY_MAX_LENGTH} characters`);
37
+ }
38
+ return {
39
+ valid: errors.length === 0,
40
+ errors
41
+ };
42
+ }
43
+
44
+ // src/commands/skills-new.ts
45
+ var metadata = {
46
+ command: "/skills new",
47
+ description: "create a new skill from a description",
48
+ implemented: true,
49
+ prd: "prd/skills_feature.md"
50
+ };
51
+ var SIMILARITY_THRESHOLD = 0.9;
52
+ async function createSkill(ctx) {
53
+ const { llm, skillsRegistry } = ctx;
54
+ if (!skillsRegistry) {
55
+ console.log(chalk.red("Skills registry not available."));
56
+ return null;
57
+ }
58
+ const answers = await enquirer.prompt([
59
+ {
60
+ type: "input",
61
+ name: "name",
62
+ message: "Skill name (lowercase, hyphens allowed)",
63
+ validate: (val) => {
64
+ if (typeof val !== "string" || !val.trim()) {
65
+ return "Name is required";
66
+ }
67
+ if (!isValidSkillName(val.trim())) {
68
+ return "Name must be lowercase alphanumeric with hyphens only (max 64 chars)";
69
+ }
70
+ return true;
71
+ }
72
+ },
73
+ {
74
+ type: "input",
75
+ name: "description",
76
+ message: "Describe what this skill should help with",
77
+ validate: (val) => {
78
+ if (typeof val !== "string" || !val.trim()) {
79
+ return "Description is required";
80
+ }
81
+ if (val.length > 1024) {
82
+ return "Description must be 1024 characters or less";
83
+ }
84
+ return true;
85
+ }
86
+ }
87
+ ]);
88
+ const name = answers.name.trim().toLowerCase();
89
+ const description = answers.description.trim();
90
+ if (!name) {
91
+ console.log(chalk.gray("Canceled: no name provided."));
92
+ return null;
93
+ }
94
+ if (skillsRegistry.hasSkill(name)) {
95
+ console.log(chalk.yellow(`A skill named "${name}" already exists.`));
96
+ const { overwrite } = await enquirer.prompt({
97
+ type: "confirm",
98
+ name: "overwrite",
99
+ message: "Do you want to overwrite it?",
100
+ initial: false
101
+ });
102
+ if (!overwrite) {
103
+ console.log(chalk.gray("Canceled."));
104
+ return null;
105
+ }
106
+ }
107
+ const similar = skillsRegistry.findSimilar(description, SIMILARITY_THRESHOLD);
108
+ if (similar.length > 0) {
109
+ console.log(chalk.yellow("\nFound similar existing skill(s):"));
110
+ for (const match of similar.slice(0, 3)) {
111
+ console.log(chalk.gray(` - ${match.skill.name}: ${match.skill.description}`));
112
+ console.log(chalk.gray(` Similarity: ${(match.score * 100).toFixed(0)}%`));
113
+ }
114
+ console.log();
115
+ const { proceed } = await enquirer.prompt({
116
+ type: "select",
117
+ name: "proceed",
118
+ message: "How would you like to proceed?",
119
+ choices: [
120
+ { name: "continue", message: "Continue creating new skill" },
121
+ { name: "use", message: `Use existing skill "${similar[0].skill.name}" instead` },
122
+ { name: "cancel", message: "Cancel" }
123
+ ]
124
+ });
125
+ if (proceed === "cancel") {
126
+ console.log(chalk.gray("Canceled."));
127
+ return null;
128
+ }
129
+ if (proceed === "use") {
130
+ const existingSkill = similar[0].skill;
131
+ skillsRegistry.activateSkill(existingSkill.name);
132
+ console.log(chalk.green(`\u2713 Activated existing skill: ${existingSkill.name}`));
133
+ return `Activated existing skill "${existingSkill.name}".`;
134
+ }
135
+ }
136
+ console.log(chalk.cyan("\nGenerating skill content..."));
137
+ const prompt = buildPrompt(name, description);
138
+ let content;
139
+ try {
140
+ const completion = await llm.complete({
141
+ messages: [
142
+ {
143
+ role: "system",
144
+ content: `You are an expert at creating Agent Skills (SKILL.md files).
145
+ Generate a complete SKILL.md file with proper YAML frontmatter and markdown body.
146
+ The skill should provide clear, actionable instructions that an AI agent can follow.
147
+ Focus on practical workflows and step-by-step guidance.
148
+ Output only the raw markdown content, no code fences.`
149
+ },
150
+ { role: "user", content: prompt }
151
+ ],
152
+ maxTokens: 1500
153
+ });
154
+ content = completion.content.trim();
155
+ } catch (error) {
156
+ console.error(chalk.red(`Failed to generate skill: ${error.message}`));
157
+ return null;
158
+ }
159
+ console.log();
160
+ console.log(chalk.bold("Preview:"));
161
+ console.log(chalk.gray("\u2500".repeat(50)));
162
+ console.log(content.length > 800 ? content.slice(0, 800) + "\n...(truncated)" : content);
163
+ console.log(chalk.gray("\u2500".repeat(50)));
164
+ console.log();
165
+ const { confirm } = await enquirer.prompt({
166
+ type: "confirm",
167
+ name: "confirm",
168
+ message: "Save this skill?",
169
+ initial: true
170
+ });
171
+ if (!confirm) {
172
+ console.log(chalk.gray("Canceled."));
173
+ return null;
174
+ }
175
+ const skillDir = path.join(AUTOHAND_PATHS.skills, name);
176
+ const skillPath = path.join(skillDir, "SKILL.md");
177
+ try {
178
+ await fs.ensureDir(skillDir);
179
+ await fs.writeFile(skillPath, content + "\n", "utf8");
180
+ console.log(chalk.green(`\u2713 Saved new skill to ${skillPath}`));
181
+ const success = await skillsRegistry.saveSkill(name, content);
182
+ if (success) {
183
+ const { activate } = await enquirer.prompt({
184
+ type: "confirm",
185
+ name: "activate",
186
+ message: "Activate this skill now?",
187
+ initial: true
188
+ });
189
+ if (activate) {
190
+ skillsRegistry.activateSkill(name);
191
+ console.log(chalk.green(`\u2713 Skill "${name}" is now active.`));
192
+ }
193
+ }
194
+ } catch (error) {
195
+ console.error(chalk.red(`Failed to save skill: ${error.message}`));
196
+ return null;
197
+ }
198
+ return `Created new skill: ${name}`;
199
+ }
200
+ function buildPrompt(name, description) {
201
+ return `Create a SKILL.md file for a skill named "${name}".
202
+
203
+ Description: ${description}
204
+
205
+ The file must have:
206
+ 1. YAML frontmatter with:
207
+ - name: ${name}
208
+ - description: A clear one-line description (max 100 chars)
209
+ - Optional: license, compatibility, allowed-tools
210
+
211
+ 2. Markdown body with:
212
+ - A heading with the skill name
213
+ - Clear purpose statement
214
+ - Step-by-step workflow or instructions
215
+ - Best practices or tips
216
+ - Example usage if applicable
217
+
218
+ Make the instructions practical and actionable for an AI coding agent.
219
+ Keep the total content concise but complete (200-400 words in body).
220
+
221
+ Output format:
222
+ ---
223
+ name: ${name}
224
+ description: <description here>
225
+ ---
226
+
227
+ # <Title>
228
+
229
+ <body content here>`;
230
+ }
231
+
232
+ export {
233
+ validateSkillFrontmatter,
234
+ metadata,
235
+ createSkill
236
+ };
237
+ /**
238
+ * @license
239
+ * Copyright 2025 Autohand AI LLC
240
+ * SPDX-License-Identifier: Apache-2.0
241
+ *
242
+ * Skills Types - Agent Skills standard implementation
243
+ * Skills are instruction packages (workflows, guides) that provide specialized
244
+ * instructions to the agent, similar to on-demand AGENTS.md files.
245
+ */
246
+ /**
247
+ * @license
248
+ * Copyright 2025 Autohand AI LLC
249
+ * SPDX-License-Identifier: Apache-2.0
250
+ *
251
+ * Skills new command - Generate a new skill from description using LLM
252
+ */
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AUTH_CONFIG,
3
3
  AUTOHAND_FILES
4
- } from "./chunk-2EPIFDFM.js";
4
+ } from "./chunk-737A24RB.js";
5
5
 
6
6
  // src/config.ts
7
7
  import fs from "fs-extra";
@@ -44,13 +44,14 @@ async function parseConfigFile(configPath) {
44
44
  async function loadConfig(customPath) {
45
45
  const configPath = await detectConfigPath(customPath);
46
46
  await fs.ensureDir(path.dirname(configPath));
47
+ let isNewConfig = false;
47
48
  if (!await fs.pathExists(configPath)) {
48
49
  const defaultConfig = {
49
50
  provider: "openrouter",
50
51
  openrouter: {
51
- apiKey: "replace-me",
52
+ apiKey: "",
52
53
  baseUrl: "https://openrouter.ai/api/v1",
53
- model: "anthropic/claude-3.5-sonnet"
54
+ model: "anthropic/claude-sonnet-4-20250514"
54
55
  },
55
56
  workspace: {
56
57
  defaultRoot: process.cwd(),
@@ -59,12 +60,13 @@ async function loadConfig(customPath) {
59
60
  ui: {
60
61
  theme: "dark",
61
62
  autoConfirm: false
63
+ },
64
+ telemetry: {
65
+ enabled: true
62
66
  }
63
67
  };
64
68
  await fs.writeJson(configPath, defaultConfig, { spaces: 2 });
65
- throw new Error(
66
- `Created default config at ${configPath}. Please update it with your OpenRouter credentials before rerunning.`
67
- );
69
+ isNewConfig = true;
68
70
  }
69
71
  let parsed;
70
72
  try {
@@ -75,7 +77,7 @@ async function loadConfig(customPath) {
75
77
  const normalized = normalizeConfig(parsed);
76
78
  const withEnv = mergeEnvVariables(normalized);
77
79
  validateConfig(withEnv, configPath);
78
- return { ...withEnv, configPath };
80
+ return { ...withEnv, configPath, isNewConfig };
79
81
  }
80
82
  function mergeEnvVariables(config) {
81
83
  return {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AUTOHAND_PATHS
3
- } from "./chunk-2EPIFDFM.js";
3
+ } from "./chunk-737A24RB.js";
4
4
 
5
5
  // src/commands/agents-new.ts
6
6
  import path from "path";
@@ -0,0 +1,104 @@
1
+ // src/commands/permissions.ts
2
+ import chalk from "chalk";
3
+ import enquirer from "enquirer";
4
+ async function permissions(ctx) {
5
+ const whitelist = ctx.permissionManager.getWhitelist();
6
+ const blacklist = ctx.permissionManager.getBlacklist();
7
+ const settings = ctx.permissionManager.getSettings();
8
+ console.log();
9
+ console.log(chalk.bold.cyan("Permissions"));
10
+ console.log(chalk.gray("\u2500".repeat(50)));
11
+ console.log(chalk.gray(`Mode: ${settings.mode || "interactive"}`));
12
+ console.log();
13
+ if (whitelist.length === 0 && blacklist.length === 0) {
14
+ console.log(chalk.gray("No saved permissions yet."));
15
+ console.log();
16
+ console.log(chalk.gray("When you approve or deny a tool/command, it will be saved here."));
17
+ console.log(chalk.gray("Approved items are auto-allowed; denied items are auto-blocked."));
18
+ return null;
19
+ }
20
+ if (whitelist.length > 0) {
21
+ console.log(chalk.bold.green("Approved (Whitelist)"));
22
+ console.log();
23
+ whitelist.forEach((pattern, index) => {
24
+ console.log(chalk.green(` ${index + 1}. ${pattern}`));
25
+ });
26
+ console.log();
27
+ }
28
+ if (blacklist.length > 0) {
29
+ console.log(chalk.bold.red("Denied (Blacklist)"));
30
+ console.log();
31
+ blacklist.forEach((pattern, index) => {
32
+ console.log(chalk.red(` ${index + 1}. ${pattern}`));
33
+ });
34
+ console.log();
35
+ }
36
+ console.log(chalk.gray("\u2500".repeat(50)));
37
+ console.log(chalk.gray(`Total: ${whitelist.length} approved, ${blacklist.length} denied`));
38
+ console.log();
39
+ const { action } = await enquirer.prompt({
40
+ type: "select",
41
+ name: "action",
42
+ message: "What would you like to do?",
43
+ choices: [
44
+ { name: "done", message: "Done" },
45
+ { name: "remove_approved", message: "Remove an approved item" },
46
+ { name: "remove_denied", message: "Remove a denied item" },
47
+ { name: "clear_all", message: "Clear all permissions" }
48
+ ]
49
+ });
50
+ if (action === "done") {
51
+ return null;
52
+ }
53
+ if (action === "remove_approved" && whitelist.length > 0) {
54
+ const { pattern } = await enquirer.prompt({
55
+ type: "select",
56
+ name: "pattern",
57
+ message: "Select item to remove from approved list:",
58
+ choices: whitelist.map((p) => ({ name: p, message: p }))
59
+ });
60
+ await ctx.permissionManager.removeFromWhitelist(pattern);
61
+ console.log(chalk.yellow(`Removed "${pattern}" from approved list.`));
62
+ } else if (action === "remove_denied" && blacklist.length > 0) {
63
+ const { pattern } = await enquirer.prompt({
64
+ type: "select",
65
+ name: "pattern",
66
+ message: "Select item to remove from denied list:",
67
+ choices: blacklist.map((p) => ({ name: p, message: p }))
68
+ });
69
+ await ctx.permissionManager.removeFromBlacklist(pattern);
70
+ console.log(chalk.yellow(`Removed "${pattern}" from denied list.`));
71
+ } else if (action === "clear_all") {
72
+ const { confirm } = await enquirer.prompt({
73
+ type: "confirm",
74
+ name: "confirm",
75
+ message: "Clear all saved permissions? This cannot be undone.",
76
+ initial: false
77
+ });
78
+ if (confirm) {
79
+ for (const pattern of [...whitelist]) {
80
+ await ctx.permissionManager.removeFromWhitelist(pattern);
81
+ }
82
+ for (const pattern of [...blacklist]) {
83
+ await ctx.permissionManager.removeFromBlacklist(pattern);
84
+ }
85
+ console.log(chalk.yellow("All permissions cleared."));
86
+ }
87
+ }
88
+ return null;
89
+ }
90
+ var metadata = {
91
+ command: "/permissions",
92
+ description: "view and manage tool/command approvals",
93
+ implemented: true
94
+ };
95
+
96
+ export {
97
+ permissions,
98
+ metadata
99
+ };
100
+ /**
101
+ * @license
102
+ * Copyright 2025 Autohand AI LLC
103
+ * SPDX-License-Identifier: Apache-2.0
104
+ */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AUTOHAND_PATHS
3
- } from "./chunk-2EPIFDFM.js";
3
+ } from "./chunk-737A24RB.js";
4
4
 
5
5
  // src/commands/agents.ts
6
6
  import chalk from "chalk";
@@ -5,7 +5,7 @@ import readline from "readline";
5
5
  // package.json
6
6
  var package_default = {
7
7
  name: "autohand-cli",
8
- version: "0.4.0",
8
+ version: "0.6.0",
9
9
  description: "Autohand interactive coding agent CLI powered by LLMs.",
10
10
  type: "module",
11
11
  bin: {
@@ -20,7 +20,9 @@ var AUTOHAND_PATHS = {
20
20
  /** Agent definitions */
21
21
  agents: path.join(AUTOHAND_HOME, "agents"),
22
22
  /** Custom tools */
23
- tools: path.join(AUTOHAND_HOME, "tools")
23
+ tools: path.join(AUTOHAND_HOME, "tools"),
24
+ /** Skills (instruction packages) */
25
+ skills: path.join(AUTOHAND_HOME, "skills")
24
26
  };
25
27
  var AUTOHAND_FILES = {
26
28
  /** Main config file */
@@ -51,6 +53,13 @@ var AUTH_CONFIG = {
51
53
  authTimeout: 5 * 60 * 1e3,
52
54
  sessionExpiryDays: 30
53
55
  };
56
+ var SKILL_LOCATIONS = [
57
+ { basePath: path.join(os.homedir(), ".codex", "skills"), source: "codex-user", recursive: true },
58
+ { basePath: path.join(os.homedir(), ".claude", "skills"), source: "claude-user", recursive: false },
59
+ // Project-level Claude skills are resolved at runtime with workspaceRoot
60
+ { basePath: AUTOHAND_PATHS.skills, source: "autohand-user", recursive: true }
61
+ // Project-level Autohand skills are resolved at runtime with workspaceRoot
62
+ ];
54
63
 
55
64
  export {
56
65
  AUTOHAND_HOME,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getAuthClient,
3
3
  saveConfig
4
- } from "./chunk-A7HRTONQ.js";
4
+ } from "./chunk-3OD5MR23.js";
5
5
 
6
6
  // src/commands/logout.ts
7
7
  import chalk from "chalk";
@@ -0,0 +1,191 @@
1
+ // src/commands/skills.ts
2
+ import chalk from "chalk";
3
+ async function skills(ctx, args = []) {
4
+ const { skillsRegistry } = ctx;
5
+ if (!skillsRegistry) {
6
+ console.log(chalk.red("Skills registry not available."));
7
+ return null;
8
+ }
9
+ const subcommand = args[0]?.toLowerCase();
10
+ const skillName = args.slice(1).join(" ").trim() || args[1];
11
+ switch (subcommand) {
12
+ case "use":
13
+ case "activate":
14
+ return activateSkill(skillsRegistry, skillName);
15
+ case "deactivate":
16
+ case "off":
17
+ return deactivateSkill(skillsRegistry, skillName);
18
+ case "info":
19
+ case "show":
20
+ return showSkillInfo(skillsRegistry, skillName);
21
+ default:
22
+ return listSkills(skillsRegistry);
23
+ }
24
+ }
25
+ function listSkills(registry) {
26
+ const allSkills = registry.listSkills();
27
+ const activeSkills = registry.getActiveSkills();
28
+ console.log();
29
+ console.log(chalk.bold.cyan("Available Skills"));
30
+ console.log(chalk.gray("\u2500".repeat(50)));
31
+ if (allSkills.length === 0) {
32
+ console.log(chalk.gray("No skills found."));
33
+ console.log();
34
+ console.log(chalk.gray("Tip: Skills can be added in:"));
35
+ console.log(chalk.gray(" - ~/.autohand/skills/<skill-name>/SKILL.md"));
36
+ console.log(chalk.gray(" - <project>/.autohand/skills/<skill-name>/SKILL.md"));
37
+ return null;
38
+ }
39
+ const bySource = /* @__PURE__ */ new Map();
40
+ for (const skill of allSkills) {
41
+ const existing = bySource.get(skill.source) ?? [];
42
+ existing.push(skill);
43
+ bySource.set(skill.source, existing);
44
+ }
45
+ const sourceLabels = {
46
+ "codex-user": "Codex User Skills (~/.codex/skills/)",
47
+ "claude-user": "Claude User Skills (~/.claude/skills/)",
48
+ "claude-project": "Claude Project Skills (.claude/skills/)",
49
+ "autohand-user": "Autohand User Skills (~/.autohand/skills/)",
50
+ "autohand-project": "Autohand Project Skills (.autohand/skills/)"
51
+ };
52
+ for (const [source, skills2] of bySource) {
53
+ console.log();
54
+ console.log(chalk.bold.yellow(sourceLabels[source] || source));
55
+ console.log();
56
+ for (const skill of skills2) {
57
+ const isActive = skill.isActive;
58
+ const statusIcon = isActive ? chalk.green("\u25CF") : chalk.gray("\u25CB");
59
+ const nameColor = isActive ? chalk.green : chalk.white;
60
+ console.log(` ${statusIcon} ${nameColor(skill.name)}`);
61
+ console.log(chalk.gray(` ${skill.description}`));
62
+ }
63
+ }
64
+ console.log();
65
+ console.log(chalk.gray("\u2500".repeat(50)));
66
+ console.log(chalk.gray(`Total: ${allSkills.length} skills, ${activeSkills.length} active`));
67
+ console.log();
68
+ console.log(chalk.gray("Commands:"));
69
+ console.log(chalk.gray(" /skills use <name> Activate a skill"));
70
+ console.log(chalk.gray(" /skills deactivate <name> Deactivate a skill"));
71
+ console.log(chalk.gray(" /skills info <name> Show skill details"));
72
+ console.log(chalk.gray(" /skills new Create a new skill"));
73
+ return null;
74
+ }
75
+ function activateSkill(registry, name) {
76
+ if (!name) {
77
+ console.log(chalk.red("Usage: /skills use <skill-name>"));
78
+ return null;
79
+ }
80
+ const skill = registry.getSkill(name);
81
+ if (!skill) {
82
+ console.log(chalk.red(`Skill not found: ${name}`));
83
+ const similar = registry.findSimilar(name, 0.2);
84
+ if (similar.length > 0) {
85
+ console.log(chalk.gray("Did you mean:"));
86
+ for (const match of similar.slice(0, 3)) {
87
+ console.log(chalk.gray(` - ${match.skill.name}`));
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ if (skill.isActive) {
93
+ console.log(chalk.yellow(`Skill "${name}" is already active.`));
94
+ return null;
95
+ }
96
+ const success = registry.activateSkill(name);
97
+ if (success) {
98
+ console.log(chalk.green(`\u2713 Activated skill: ${name}`));
99
+ console.log(chalk.gray(` ${skill.description}`));
100
+ return `Skill "${name}" is now active.`;
101
+ } else {
102
+ console.log(chalk.red(`Failed to activate skill: ${name}`));
103
+ return null;
104
+ }
105
+ }
106
+ function deactivateSkill(registry, name) {
107
+ if (!name) {
108
+ console.log(chalk.red("Usage: /skills deactivate <skill-name>"));
109
+ return null;
110
+ }
111
+ const skill = registry.getSkill(name);
112
+ if (!skill) {
113
+ console.log(chalk.red(`Skill not found: ${name}`));
114
+ return null;
115
+ }
116
+ if (!skill.isActive) {
117
+ console.log(chalk.yellow(`Skill "${name}" is not active.`));
118
+ return null;
119
+ }
120
+ const success = registry.deactivateSkill(name);
121
+ if (success) {
122
+ console.log(chalk.green(`\u2713 Deactivated skill: ${name}`));
123
+ return `Skill "${name}" is now inactive.`;
124
+ } else {
125
+ console.log(chalk.red(`Failed to deactivate skill: ${name}`));
126
+ return null;
127
+ }
128
+ }
129
+ function showSkillInfo(registry, name) {
130
+ if (!name) {
131
+ console.log(chalk.red("Usage: /skills info <skill-name>"));
132
+ return null;
133
+ }
134
+ const skill = registry.getSkill(name);
135
+ if (!skill) {
136
+ console.log(chalk.red(`Skill not found: ${name}`));
137
+ return null;
138
+ }
139
+ console.log();
140
+ console.log(chalk.bold.cyan(`Skill: ${skill.name}`));
141
+ console.log(chalk.gray("\u2500".repeat(50)));
142
+ console.log();
143
+ console.log(chalk.white("Description: ") + skill.description);
144
+ console.log(chalk.white("Status: ") + (skill.isActive ? chalk.green("Active") : chalk.gray("Inactive")));
145
+ console.log(chalk.white("Source: ") + skill.source);
146
+ console.log(chalk.white("Path: ") + chalk.gray(skill.path));
147
+ if (skill.license) {
148
+ console.log(chalk.white("License: ") + skill.license);
149
+ }
150
+ if (skill.compatibility) {
151
+ console.log(chalk.white("Compatibility: ") + skill.compatibility);
152
+ }
153
+ if (skill["allowed-tools"]) {
154
+ console.log(chalk.white("Allowed Tools: ") + skill["allowed-tools"]);
155
+ }
156
+ if (skill.metadata && Object.keys(skill.metadata).length > 0) {
157
+ console.log(chalk.white("Metadata:"));
158
+ for (const [key, value] of Object.entries(skill.metadata)) {
159
+ console.log(chalk.gray(` ${key}: ${value}`));
160
+ }
161
+ }
162
+ console.log();
163
+ console.log(chalk.bold("Content:"));
164
+ console.log(chalk.gray("\u2500".repeat(50)));
165
+ const bodyPreview = skill.body.length > 500 ? skill.body.slice(0, 500) + chalk.gray("\n... (truncated)") : skill.body;
166
+ console.log(bodyPreview || chalk.gray("(no body content)"));
167
+ return null;
168
+ }
169
+ var metadata = {
170
+ command: "/skills",
171
+ description: "list and manage available skills",
172
+ implemented: true
173
+ };
174
+ var useMetadata = {
175
+ command: "/skills use",
176
+ description: "activate a skill",
177
+ implemented: true
178
+ };
179
+
180
+ export {
181
+ skills,
182
+ metadata,
183
+ useMetadata
184
+ };
185
+ /**
186
+ * @license
187
+ * Copyright 2025 Autohand AI LLC
188
+ * SPDX-License-Identifier: Apache-2.0
189
+ *
190
+ * Skills command - List and manage available skills
191
+ */
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AUTOHAND_FILES
3
- } from "./chunk-2EPIFDFM.js";
3
+ } from "./chunk-737A24RB.js";
4
4
 
5
5
  // src/commands/feedback.ts
6
6
  import fs from "fs-extra";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getAuthClient,
3
3
  saveConfig
4
- } from "./chunk-A7HRTONQ.js";
4
+ } from "./chunk-3OD5MR23.js";
5
5
  import {
6
6
  AUTH_CONFIG
7
- } from "./chunk-2EPIFDFM.js";
7
+ } from "./chunk-737A24RB.js";
8
8
 
9
9
  // src/commands/login.ts
10
10
  import chalk from "chalk";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  feedback,
3
3
  metadata
4
- } from "./chunk-2QAL3HH4.js";
5
- import "./chunk-2EPIFDFM.js";
4
+ } from "./chunk-PRZTK2FX.js";
5
+ import "./chunk-737A24RB.js";
6
6
  export {
7
7
  feedback,
8
8
  metadata