haki-skills 0.2.6 → 0.3.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.
@@ -85,6 +85,7 @@ const {
85
85
  cmdRoadmapUpdateStatus,
86
86
  } = require("./lib/roadmap.cjs");
87
87
  const { cmdStateDetect, cmdStateJson } = require("./lib/state.cjs");
88
+ const { cmdSkill } = require("./lib/skill.cjs");
88
89
 
89
90
  function main() {
90
91
  const args = process.argv.slice(2);
@@ -153,6 +154,12 @@ function main() {
153
154
  break;
154
155
  }
155
156
 
157
+ // ─── Skill ───────────────────────────────────────────────────────
158
+ case "skill": {
159
+ cmdSkill(subCommand, restArgs[0]);
160
+ break;
161
+ }
162
+
156
163
  // ─── State ────────────────────────────────────────────────────────
157
164
  case "state": {
158
165
  withRunEvents(cwd, `state.${subCommand || "unknown"}`, restArgs, () => {
@@ -0,0 +1,197 @@
1
+ /**
2
+ * .agent/bin/lib/skill.cjs
3
+ *
4
+ * Skill-related commands for haki-tools.
5
+ * - list: List all skills with name and description
6
+ * - info: Show single skill details
7
+ * - invoke: Print skill SKILL.md content to stdout
8
+ * - registry: Generate .agent/registry.json
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ // __dirname = .agent/bin/lib/
17
+ // Resolve skills relative to this file: lib/ → bin/ → .agent/ → skills
18
+ const THIS_DIR = __dirname; // e.g. D:\...\haki-skills\.agent\bin\lib
19
+ const UP_TO_BIN = path.resolve(THIS_DIR, '..'); // .agent/bin
20
+ const UP_TO_AGENT = path.resolve(UP_TO_BIN, '..'); // .agent
21
+ const SKILLS_DIR = path.join(UP_TO_AGENT, 'skills');
22
+ const REGISTRY = path.join(UP_TO_AGENT, 'registry.json');
23
+
24
+ // ── Frontmatter parser ────────────────────────────────────────────────
25
+
26
+ function parseFrontmatter(content) {
27
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
28
+ if (!match) return null;
29
+
30
+ const raw = match[1];
31
+ const body = content.slice(match[0].length);
32
+ const attrs = {};
33
+
34
+ raw.split(/\r?\n/).forEach(function(line) {
35
+ const i = line.indexOf(':');
36
+ if (i === -1) return;
37
+ const k = line.slice(0, i).trim();
38
+ let v = line.slice(i + 1).trim();
39
+ if ((v.charAt(0) === '"' && v.charAt(v.length - 1) === '"') ||
40
+ (v.charAt(0) === "'" && v.charAt(v.length - 1) === "'")) {
41
+ v = v.slice(1, -1);
42
+ }
43
+ attrs[k] = v;
44
+ });
45
+
46
+ return { attrs: attrs, body: body };
47
+ }
48
+
49
+ // ── Load all skills ────────────────────────────────────────────────────
50
+
51
+ function loadAllSkills() {
52
+ const dirs = fs.readdirSync(SKILLS_DIR).filter(function(f) {
53
+ return fs.statSync(path.join(SKILLS_DIR, f)).isDirectory();
54
+ });
55
+
56
+ return dirs.map(function(dir) {
57
+ const skillPath = path.join(SKILLS_DIR, dir, 'SKILL.md');
58
+ const exists = fs.existsSync(skillPath);
59
+
60
+ // Collect templates and scripts
61
+ const skillDir = path.join(SKILLS_DIR, dir);
62
+ const templates = [];
63
+ const scripts = [];
64
+ try {
65
+ fs.readdirSync(path.join(skillDir, 'templates')).forEach(function(f) {
66
+ templates.push('templates/' + f);
67
+ });
68
+ } catch (e) { /* no templates dir */ }
69
+ try {
70
+ fs.readdirSync(path.join(skillDir, 'scripts')).forEach(function(f) {
71
+ scripts.push('scripts/' + f);
72
+ });
73
+ } catch (e) { /* no scripts dir */ }
74
+
75
+ if (!exists) {
76
+ return {
77
+ name: null,
78
+ description: null,
79
+ path: dir + '/SKILL.md',
80
+ templates: templates,
81
+ scripts: scripts,
82
+ exists: false,
83
+ raw: null,
84
+ };
85
+ }
86
+
87
+ const content = fs.readFileSync(skillPath, 'utf8');
88
+ const parsed = parseFrontmatter(content);
89
+
90
+ return {
91
+ name: parsed ? (parsed.attrs.name || dir) : dir,
92
+ description: parsed ? (parsed.attrs.description || '') : '',
93
+ path: dir + '/SKILL.md',
94
+ templates: templates,
95
+ scripts: scripts,
96
+ exists: true,
97
+ raw: content,
98
+ };
99
+ });
100
+ }
101
+
102
+ // ── Commands ───────────────────────────────────────────────────────────
103
+
104
+ function cmdSkillList() {
105
+ const skills = loadAllSkills();
106
+
107
+ console.log('\nAvailable skills (' + skills.length + '):\n');
108
+ skills.forEach(function(s) {
109
+ const mark = s.exists ? '' : ' [MISSING SKILL.md]';
110
+ const desc = s.description
111
+ ? ' — ' + s.description.slice(0, 70) + (s.description.length > 70 ? '...' : '')
112
+ : '';
113
+ console.log(' ' + s.name + mark + desc);
114
+ });
115
+ console.log('');
116
+ }
117
+
118
+ function cmdSkillInfo(name) {
119
+ const skills = loadAllSkills();
120
+ const skill = skills.find(function(s) { return s.name === name; });
121
+
122
+ if (!skill) {
123
+ const names = skills.map(function(s) { return s.name; }).join(', ');
124
+ throw new Error('Unknown skill: ' + name + '\nAvailable: ' + names);
125
+ }
126
+
127
+ if (!skill.exists) {
128
+ throw new Error('SKILL.md missing for: ' + skill.path);
129
+ }
130
+
131
+ console.log('\n=== ' + skill.name + ' ===');
132
+ if (skill.description) console.log(skill.description + '\n');
133
+ console.log('Path: .agent/skills/' + skill.path);
134
+ if (skill.templates.length) console.log('Templates: ' + skill.templates.join(', '));
135
+ if (skill.scripts.length) console.log('Scripts: ' + skill.scripts.join(', '));
136
+ console.log('');
137
+ }
138
+
139
+ function cmdSkillInvoke(name) {
140
+ const skills = loadAllSkills();
141
+ const skill = skills.find(function(s) { return s.name === name; });
142
+
143
+ if (!skill) {
144
+ const names = skills.map(function(s) { return s.name; }).join(', ');
145
+ throw new Error('Unknown skill: ' + name + '\nAvailable: ' + names);
146
+ }
147
+ if (!skill.exists) {
148
+ throw new Error('SKILL.md missing for: ' + skill.path);
149
+ }
150
+
151
+ process.stdout.write(skill.raw);
152
+ }
153
+
154
+ function cmdSkillRegistry() {
155
+ const skills = loadAllSkills();
156
+ const registry = {
157
+ skills: skills.map(function(s) {
158
+ return {
159
+ name: s.name || s.path.replace('/SKILL.md', ''),
160
+ description: s.description || '',
161
+ path: '.agent/skills/' + s.path,
162
+ templates: s.templates.map(function(t) { return '.agent/skills/' + s.path.replace('/SKILL.md', '/') + t; }),
163
+ scripts: s.scripts.map(function(t) { return '.agent/skills/' + s.path.replace('/SKILL.md', '/') + t; }),
164
+ };
165
+ }),
166
+ generated: new Date().toISOString(),
167
+ };
168
+
169
+ fs.writeFileSync(REGISTRY, JSON.stringify(registry, null, 2), 'utf8');
170
+ console.log('Generated registry.json (' + registry.skills.length + ' skills)');
171
+ }
172
+
173
+ // ── Routing ────────────────────────────────────────────────────────────
174
+
175
+ function cmdSkill(subCmd, name) {
176
+ switch (subCmd) {
177
+ case 'list':
178
+ case undefined:
179
+ cmdSkillList();
180
+ break;
181
+ case 'info':
182
+ if (!name) throw new Error('Usage: haki-tools skill info <name>');
183
+ cmdSkillInfo(name);
184
+ break;
185
+ case 'invoke':
186
+ if (!name) throw new Error('Usage: haki-tools skill invoke <name>');
187
+ cmdSkillInvoke(name);
188
+ break;
189
+ case 'registry':
190
+ cmdSkillRegistry();
191
+ break;
192
+ default:
193
+ throw new Error('Usage: haki-tools skill <list|info|invoke|registry> [name]');
194
+ }
195
+ }
196
+
197
+ module.exports = { cmdSkill, cmdSkillList, cmdSkillInfo, cmdSkillInvoke, cmdSkillRegistry };
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: taste-research
3
+ description: "Reference research directory for design taste topics. Not a skill — see README.md for topic index."
4
+ ---
5
+
6
+ # Taste Research
7
+
8
+ This is a **reference directory**, not an executable skill.
9
+
10
+ Content: Research on design taste, AI laziness patterns, and remediation strategies.
11
+
12
+ See [README.md](./README.md) for available topic indexes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haki-skills",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "AI workflow system — project initialization, task planning, and execution with TDD-first approach",
5
5
  "bin": {
6
6
  "haki-skills": "./bin/install.js",