youmd 0.4.9 → 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.
- package/dist/__tests__/api.test.d.ts +2 -0
- package/dist/__tests__/api.test.d.ts.map +1 -0
- package/dist/__tests__/api.test.js +84 -0
- package/dist/__tests__/api.test.js.map +1 -0
- package/dist/__tests__/compiler.test.d.ts +2 -0
- package/dist/__tests__/compiler.test.d.ts.map +1 -0
- package/dist/__tests__/compiler.test.js +127 -0
- package/dist/__tests__/compiler.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +79 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/decompile.test.d.ts +2 -0
- package/dist/__tests__/decompile.test.d.ts.map +1 -0
- package/dist/__tests__/decompile.test.js +102 -0
- package/dist/__tests__/decompile.test.js.map +1 -0
- package/dist/__tests__/hash.test.d.ts +2 -0
- package/dist/__tests__/hash.test.d.ts.map +1 -0
- package/dist/__tests__/hash.test.js +44 -0
- package/dist/__tests__/hash.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +2 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +277 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/skill-renderer.test.d.ts +2 -0
- package/dist/__tests__/skill-renderer.test.d.ts.map +1 -0
- package/dist/__tests__/skill-renderer.test.js +68 -0
- package/dist/__tests__/skill-renderer.test.js.map +1 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +6 -3
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +93 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +96 -21
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +110 -11
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/diff.d.ts +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +402 -16
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/export.js +1 -1
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +138 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/link.d.ts +1 -0
- package/dist/commands/link.d.ts.map +1 -1
- package/dist/commands/link.js +77 -13
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +48 -27
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.d.ts +7 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +115 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/mcp.d.ts +6 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +258 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/preview.d.ts.map +1 -1
- package/dist/commands/preview.js +191 -7
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/private.d.ts.map +1 -1
- package/dist/commands/private.js +248 -0
- package/dist/commands/private.js.map +1 -1
- package/dist/commands/prompts.d.ts +12 -0
- package/dist/commands/prompts.d.ts.map +1 -0
- package/dist/commands/prompts.js +245 -0
- package/dist/commands/prompts.js.map +1 -0
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +69 -6
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +110 -137
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +236 -38
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/register.d.ts.map +1 -1
- package/dist/commands/register.js +40 -84
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/skill.d.ts +8 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +1226 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +221 -69
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +12 -0
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +62 -33
- package/dist/commands/whoami.js.map +1 -1
- package/dist/index.js +187 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +169 -12
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +183 -33
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/ascii.d.ts.map +1 -1
- package/dist/lib/ascii.js +20 -48
- package/dist/lib/ascii.js.map +1 -1
- package/dist/lib/compiler.d.ts +16 -33
- package/dist/lib/compiler.d.ts.map +1 -1
- package/dist/lib/compiler.js +499 -84
- package/dist/lib/compiler.js.map +1 -1
- package/dist/lib/config.d.ts +27 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +50 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/decompile.d.ts +21 -0
- package/dist/lib/decompile.d.ts.map +1 -0
- package/dist/lib/decompile.js +304 -0
- package/dist/lib/decompile.js.map +1 -0
- package/dist/lib/hash.d.ts +3 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/hash.js +31 -0
- package/dist/lib/hash.js.map +1 -0
- package/dist/lib/onboarding.d.ts +4 -4
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +228 -81
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/skill-catalog.d.ts +57 -0
- package/dist/lib/skill-catalog.d.ts.map +1 -0
- package/dist/lib/skill-catalog.js +245 -0
- package/dist/lib/skill-catalog.js.map +1 -0
- package/dist/lib/skill-renderer.d.ts +55 -0
- package/dist/lib/skill-renderer.d.ts.map +1 -0
- package/dist/lib/skill-renderer.js +382 -0
- package/dist/lib/skill-renderer.js.map +1 -0
- package/dist/lib/skills.d.ts +130 -0
- package/dist/lib/skills.d.ts.map +1 -0
- package/dist/lib/skills.js +876 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/vault.d.ts +40 -0
- package/dist/lib/vault.d.ts.map +1 -0
- package/dist/lib/vault.js +187 -0
- package/dist/lib/vault.js.map +1 -0
- package/dist/mcp/server.d.ts +21 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1283 -0
- package/dist/mcp/server.js.map +1 -0
- package/examples/houston/directives/agent.md +13 -0
- package/examples/houston/preferences/agent.md +14 -0
- package/examples/houston/profile/about.md +15 -0
- package/examples/houston/profile/links.md +10 -0
- package/examples/houston/profile/projects.md +37 -0
- package/examples/houston/profile/values.md +9 -0
- package/examples/houston/voice/voice.md +13 -0
- package/examples/jordan/directives/agent.md +13 -0
- package/examples/jordan/preferences/agent.md +16 -0
- package/examples/jordan/profile/about.md +15 -0
- package/examples/jordan/profile/links.md +10 -0
- package/examples/jordan/profile/projects.md +29 -0
- package/examples/jordan/profile/values.md +9 -0
- package/examples/jordan/voice/voice.md +12 -0
- package/examples/priya/directives/agent.md +13 -0
- package/examples/priya/preferences/agent.md +15 -0
- package/examples/priya/profile/about.md +15 -0
- package/examples/priya/profile/links.md +9 -0
- package/examples/priya/profile/projects.md +28 -0
- package/examples/priya/profile/values.md +9 -0
- package/examples/priya/voice/voice.md +12 -0
- package/package.json +15 -6
- package/skills/claude-md-generator.md +91 -0
- package/skills/meta-improve.md +84 -0
- package/skills/proactive-context-fill.md +52 -0
- package/skills/project-context-init.md +77 -0
- package/skills/voice-sync.md +89 -0
- package/skills/you-logs.md +71 -0
|
@@ -0,0 +1,1226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* youmd skill — identity-aware agent skill system.
|
|
4
|
+
*
|
|
5
|
+
* Subcommand router following the project.ts pattern.
|
|
6
|
+
* Manages skill lifecycle: install, remove, use, sync, link, init-project.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.skillCommand = skillCommand;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
49
|
+
const skill_catalog_1 = require("../lib/skill-catalog");
|
|
50
|
+
const skills_1 = require("../lib/skills");
|
|
51
|
+
const skill_renderer_1 = require("../lib/skill-renderer");
|
|
52
|
+
const render_1 = require("../lib/render");
|
|
53
|
+
const config_1 = require("../lib/config");
|
|
54
|
+
const api_1 = require("../lib/api");
|
|
55
|
+
const skills_2 = require("../lib/skills");
|
|
56
|
+
const ACCENT = chalk_1.default.hex("#C46A3A");
|
|
57
|
+
const DIM = chalk_1.default.dim;
|
|
58
|
+
// ─── Personality spinner labels ──────────────────────────────────────
|
|
59
|
+
const SKILL_SPINNERS = {
|
|
60
|
+
install: [
|
|
61
|
+
"downloading your superpowers",
|
|
62
|
+
"wiring identity into skill matrix",
|
|
63
|
+
"importing agent knowledge",
|
|
64
|
+
"bootstrapping skill neurons",
|
|
65
|
+
"fetching your secret sauce",
|
|
66
|
+
],
|
|
67
|
+
use: [
|
|
68
|
+
"resolving identity against skill template",
|
|
69
|
+
"interpolating your whole vibe",
|
|
70
|
+
"mapping your identity to agent instructions",
|
|
71
|
+
"converting you into context",
|
|
72
|
+
"rendering your digital twin's playbook",
|
|
73
|
+
],
|
|
74
|
+
sync: [
|
|
75
|
+
"re-interpolating skills against live identity",
|
|
76
|
+
"propagating identity changes across skills",
|
|
77
|
+
"syncing your soul to all agents",
|
|
78
|
+
"reconciling who you are with what agents know",
|
|
79
|
+
],
|
|
80
|
+
link: [
|
|
81
|
+
"wiring your identity into the agent",
|
|
82
|
+
"bridging identity to agent workspace",
|
|
83
|
+
"establishing the neural handshake",
|
|
84
|
+
],
|
|
85
|
+
init: [
|
|
86
|
+
"computing your project's main character energy",
|
|
87
|
+
"scaffolding your identity into this repo",
|
|
88
|
+
"making this project know who it's working with",
|
|
89
|
+
"infusing project with identity context",
|
|
90
|
+
],
|
|
91
|
+
remove: [
|
|
92
|
+
"severing the identity link",
|
|
93
|
+
"cleaning up skill artifacts",
|
|
94
|
+
"removing agent knowledge",
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
function randomSpinner(category) {
|
|
98
|
+
const labels = SKILL_SPINNERS[category];
|
|
99
|
+
return labels[Math.floor(Math.random() * labels.length)];
|
|
100
|
+
}
|
|
101
|
+
/** Truncate at word boundary instead of mid-word */
|
|
102
|
+
function truncateAtWord(text, max) {
|
|
103
|
+
if (text.length <= max)
|
|
104
|
+
return text;
|
|
105
|
+
const truncated = text.slice(0, max);
|
|
106
|
+
const lastSpace = truncated.lastIndexOf(" ");
|
|
107
|
+
return (lastSpace > max * 0.5 ? truncated.slice(0, lastSpace) : truncated) + "...";
|
|
108
|
+
}
|
|
109
|
+
// ─── Subcommands ──────────────────────────────────────────────────────
|
|
110
|
+
const RECOMMENDED_SKILLS = new Set(["claude-md-generator", "voice-sync"]);
|
|
111
|
+
async function listSkills() {
|
|
112
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
113
|
+
console.log("");
|
|
114
|
+
console.log(" " + chalk_1.default.bold("youmd skills") + DIM(` (${catalog.skills.length} in catalog)`));
|
|
115
|
+
console.log("");
|
|
116
|
+
if (catalog.skills.length === 0) {
|
|
117
|
+
console.log(DIM(" no skills registered."));
|
|
118
|
+
console.log(DIM(" run ") + chalk_1.default.cyan("youmd skill add <name> <source>") + DIM(" to add one."));
|
|
119
|
+
console.log("");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Best-effort: fetch registry metadata for download counts.
|
|
123
|
+
// Network failures are silent — list still works offline.
|
|
124
|
+
const downloads = {};
|
|
125
|
+
try {
|
|
126
|
+
const reg = await (0, api_1.browseSkills)();
|
|
127
|
+
if (reg.ok && reg.data?.skills) {
|
|
128
|
+
for (const s of reg.data.skills) {
|
|
129
|
+
if (typeof s.downloads === "number") {
|
|
130
|
+
downloads[s.name] = s.downloads;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
/* offline is fine */
|
|
137
|
+
}
|
|
138
|
+
const maxName = Math.max(...catalog.skills.map((s) => s.name.length));
|
|
139
|
+
for (const skill of catalog.skills) {
|
|
140
|
+
const status = skill.installed
|
|
141
|
+
? chalk_1.default.green("\u2713 installed")
|
|
142
|
+
: DIM("\u25CB available");
|
|
143
|
+
const scope = skill.scope === "shared"
|
|
144
|
+
? DIM("shared")
|
|
145
|
+
: skill.scope === "project"
|
|
146
|
+
? ACCENT("project")
|
|
147
|
+
: chalk_1.default.yellow("private");
|
|
148
|
+
const fields = skill.identity_fields.length > 0
|
|
149
|
+
? DIM(` [${skill.identity_fields.join(", ")}]`)
|
|
150
|
+
: "";
|
|
151
|
+
const recommended = RECOMMENDED_SKILLS.has(skill.name)
|
|
152
|
+
? " " + ACCENT("recommended")
|
|
153
|
+
: "";
|
|
154
|
+
const dl = downloads[skill.name];
|
|
155
|
+
const dlLabel = typeof dl === "number"
|
|
156
|
+
? DIM(` \u2193 ${dl.toLocaleString()}`)
|
|
157
|
+
: "";
|
|
158
|
+
console.log(` ${status} ${chalk_1.default.cyan(skill.name.padEnd(maxName + 2))}` +
|
|
159
|
+
`${DIM(skill.description)}${recommended}`);
|
|
160
|
+
console.log(` ${DIM("v" + skill.version)} ${scope}${dlLabel}${fields}`);
|
|
161
|
+
}
|
|
162
|
+
console.log("");
|
|
163
|
+
const installed = catalog.skills.filter((s) => s.installed).length;
|
|
164
|
+
console.log(DIM(` ${installed}/${catalog.skills.length} installed`));
|
|
165
|
+
if (installed === 0) {
|
|
166
|
+
console.log("");
|
|
167
|
+
console.log(DIM(" get started: ") +
|
|
168
|
+
chalk_1.default.cyan("youmd skill install claude-md-generator"));
|
|
169
|
+
}
|
|
170
|
+
console.log("");
|
|
171
|
+
}
|
|
172
|
+
async function installSkillCmd(args) {
|
|
173
|
+
const name = args[0];
|
|
174
|
+
// Batch install all
|
|
175
|
+
if (name === "all" || name === "--all" || name === "-a") {
|
|
176
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
177
|
+
const toInstall = catalog.skills.filter((s) => !s.installed);
|
|
178
|
+
if (toInstall.length === 0) {
|
|
179
|
+
console.log("");
|
|
180
|
+
console.log(DIM(" all skills already installed."));
|
|
181
|
+
console.log("");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log("");
|
|
185
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("install"));
|
|
186
|
+
spinner.start();
|
|
187
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
188
|
+
let installed = 0;
|
|
189
|
+
for (const entry of toInstall) {
|
|
190
|
+
let result = (0, skills_1.installSkill)(entry.name);
|
|
191
|
+
if (!result.ok && (entry.source.startsWith("github:") || entry.source.startsWith("https://"))) {
|
|
192
|
+
result = await (0, skills_1.installSkillAsync)(entry.name);
|
|
193
|
+
}
|
|
194
|
+
if (result.ok)
|
|
195
|
+
installed++;
|
|
196
|
+
}
|
|
197
|
+
spinner.stop(`${installed} skills installed`);
|
|
198
|
+
console.log("");
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (!name) {
|
|
202
|
+
console.log("");
|
|
203
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill install <name>"));
|
|
204
|
+
console.log(DIM(" or: youmd skill install all"));
|
|
205
|
+
console.log("");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
209
|
+
const entry = (0, skill_catalog_1.findSkill)(catalog, name);
|
|
210
|
+
if (!entry) {
|
|
211
|
+
// Not in local catalog — check the registry
|
|
212
|
+
if ((0, config_1.isAuthenticated)()) {
|
|
213
|
+
console.log("");
|
|
214
|
+
const regSpinner = new render_1.BrailleSpinner("checking the skill registry");
|
|
215
|
+
regSpinner.start();
|
|
216
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
217
|
+
try {
|
|
218
|
+
const regRes = await (0, api_1.browseSkills)();
|
|
219
|
+
if (regRes.ok) {
|
|
220
|
+
const regSkill = regRes.data.skills.find((s) => s.name === name);
|
|
221
|
+
if (regSkill) {
|
|
222
|
+
regSpinner.stop(`found "${name}" in registry`);
|
|
223
|
+
// Fetch full skill content from registry
|
|
224
|
+
const contentRes = await (0, api_1.getRegistrySkill)(regSkill.name);
|
|
225
|
+
if (contentRes.ok && contentRes.data.content) {
|
|
226
|
+
// Write SKILL.md directly
|
|
227
|
+
const skillDir = (0, skills_2.getSkillDir)(regSkill.name);
|
|
228
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
229
|
+
fs.writeFileSync(path.join(skillDir, "SKILL.md"), contentRes.data.content);
|
|
230
|
+
// Render with identity
|
|
231
|
+
const { renderSkillTemplate, loadIdentityData: loadId } = require("../lib/skill-renderer");
|
|
232
|
+
const rendered = renderSkillTemplate(contentRes.data.content, loadId());
|
|
233
|
+
fs.writeFileSync(path.join(skillDir, "RENDERED.md"), rendered);
|
|
234
|
+
// Add to catalog and mark installed
|
|
235
|
+
(0, skill_catalog_1.addSkillEntry)((0, skill_catalog_1.readSkillCatalog)(), {
|
|
236
|
+
name: regSkill.name,
|
|
237
|
+
description: regSkill.description,
|
|
238
|
+
version: regSkill.version,
|
|
239
|
+
source: `registry:${regSkill.name}`,
|
|
240
|
+
scope: regSkill.scope,
|
|
241
|
+
identity_fields: regSkill.identityFields,
|
|
242
|
+
requires: [],
|
|
243
|
+
installed: true,
|
|
244
|
+
});
|
|
245
|
+
console.log("");
|
|
246
|
+
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(name)} installed from registry` +
|
|
247
|
+
DIM(` [${regSkill.scope}]`));
|
|
248
|
+
if (regSkill.identityFields.length > 0) {
|
|
249
|
+
console.log(DIM(` identity fields: ${regSkill.identityFields.join(", ")}`));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
// Content not available, just add to catalog
|
|
254
|
+
(0, skill_catalog_1.addSkillEntry)((0, skill_catalog_1.readSkillCatalog)(), {
|
|
255
|
+
name: regSkill.name,
|
|
256
|
+
description: regSkill.description,
|
|
257
|
+
version: regSkill.version,
|
|
258
|
+
source: `registry:${regSkill.name}`,
|
|
259
|
+
scope: regSkill.scope,
|
|
260
|
+
identity_fields: regSkill.identityFields,
|
|
261
|
+
requires: [],
|
|
262
|
+
});
|
|
263
|
+
console.log("");
|
|
264
|
+
console.log(DIM(` added to catalog but content not available.`));
|
|
265
|
+
}
|
|
266
|
+
console.log("");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
regSpinner.stop("not found in registry either");
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
regSpinner.fail("registry check failed");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
console.log("");
|
|
277
|
+
console.log(chalk_1.default.yellow(` skill "${name}" not found in catalog or registry.`));
|
|
278
|
+
console.log(DIM(" run ") + chalk_1.default.cyan("youmd skill list") + DIM(" to see available skills."));
|
|
279
|
+
console.log(DIM(" or: ") + chalk_1.default.cyan("youmd skill browse") + DIM(" to check the registry."));
|
|
280
|
+
console.log("");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (entry.installed) {
|
|
284
|
+
console.log("");
|
|
285
|
+
console.log(DIM(` "${entry.name}" is already installed.`));
|
|
286
|
+
console.log("");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
console.log("");
|
|
290
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("install"));
|
|
291
|
+
spinner.start();
|
|
292
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
293
|
+
// Try sync install, fall back to async for remote sources
|
|
294
|
+
let result = (0, skills_1.installSkill)(entry.name);
|
|
295
|
+
if (!result.ok && (entry.source.startsWith("github:") || entry.source.startsWith("https://"))) {
|
|
296
|
+
result = await (0, skills_1.installSkillAsync)(entry.name);
|
|
297
|
+
}
|
|
298
|
+
if (result.ok) {
|
|
299
|
+
spinner.stop(`v${entry.version}`);
|
|
300
|
+
console.log("");
|
|
301
|
+
console.log(" " + chalk_1.default.green("\u2713") + ` ${chalk_1.default.bold(entry.name)} installed` +
|
|
302
|
+
DIM(` [${entry.scope}]`));
|
|
303
|
+
if (entry.identity_fields.length > 0) {
|
|
304
|
+
console.log(DIM(` identity fields: ${entry.identity_fields.join(", ")}`));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
spinner.fail(result.error);
|
|
309
|
+
}
|
|
310
|
+
console.log("");
|
|
311
|
+
}
|
|
312
|
+
async function removeSkillCmd(args) {
|
|
313
|
+
const name = args[0];
|
|
314
|
+
// Batch remove all
|
|
315
|
+
if (name === "all" || name === "--all" || name === "-a") {
|
|
316
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
317
|
+
const toRemove = catalog.skills.filter((s) => s.installed);
|
|
318
|
+
if (toRemove.length === 0) {
|
|
319
|
+
console.log("");
|
|
320
|
+
console.log(DIM(" no skills installed."));
|
|
321
|
+
console.log("");
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
console.log("");
|
|
325
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("remove"));
|
|
326
|
+
spinner.start();
|
|
327
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
328
|
+
let removed = 0;
|
|
329
|
+
for (const entry of toRemove) {
|
|
330
|
+
const result = (0, skills_1.removeSkill)(entry.name);
|
|
331
|
+
if (result.ok)
|
|
332
|
+
removed++;
|
|
333
|
+
}
|
|
334
|
+
spinner.stop(`${removed} skills removed`);
|
|
335
|
+
console.log("");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (!name) {
|
|
339
|
+
console.log("");
|
|
340
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill remove <name>"));
|
|
341
|
+
console.log(DIM(" or: youmd skill remove all"));
|
|
342
|
+
console.log("");
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
console.log("");
|
|
346
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("remove"));
|
|
347
|
+
spinner.start();
|
|
348
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
349
|
+
const result = (0, skills_1.removeSkill)(name);
|
|
350
|
+
if (result.ok) {
|
|
351
|
+
spinner.stop("removed");
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
spinner.fail(result.error);
|
|
355
|
+
}
|
|
356
|
+
console.log("");
|
|
357
|
+
}
|
|
358
|
+
async function useSkillCmd(args) {
|
|
359
|
+
const name = args[0];
|
|
360
|
+
if (!name) {
|
|
361
|
+
console.log("");
|
|
362
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill use <name>"));
|
|
363
|
+
console.log("");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
console.log("");
|
|
367
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("use"));
|
|
368
|
+
spinner.start();
|
|
369
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
370
|
+
const result = (0, skills_1.useSkill)(name);
|
|
371
|
+
if (!result.ok) {
|
|
372
|
+
spinner.fail(result.error);
|
|
373
|
+
console.log("");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
spinner.stop();
|
|
377
|
+
// Show readiness
|
|
378
|
+
if (result.readiness) {
|
|
379
|
+
const { total, filled, missing } = result.readiness;
|
|
380
|
+
if (missing.length > 0) {
|
|
381
|
+
console.log("");
|
|
382
|
+
console.log(ACCENT(` ${filled}/${total} identity fields resolved.`) +
|
|
383
|
+
DIM(` missing: ${missing.join(", ")}`));
|
|
384
|
+
console.log(DIM(" fill these via ") + chalk_1.default.cyan("youmd chat") + DIM(" or edit .youmd/preferences/"));
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.log(DIM(` ${total}/${total} identity fields resolved.`));
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// Show rendered output with rich terminal formatting
|
|
391
|
+
if (result.content) {
|
|
392
|
+
console.log("");
|
|
393
|
+
console.log(DIM(" " + "\u2500".repeat(50)));
|
|
394
|
+
const rendered = (0, render_1.renderRichResponse)(result.content);
|
|
395
|
+
// Limit output to ~40 visual lines
|
|
396
|
+
const renderedLines = rendered.split("\n");
|
|
397
|
+
for (const line of renderedLines.slice(0, 40)) {
|
|
398
|
+
console.log(` ${line}`);
|
|
399
|
+
}
|
|
400
|
+
if (renderedLines.length > 40) {
|
|
401
|
+
console.log(DIM(` ... ${renderedLines.length - 40} more lines`));
|
|
402
|
+
}
|
|
403
|
+
console.log(DIM(" " + "\u2500".repeat(50)));
|
|
404
|
+
}
|
|
405
|
+
console.log("");
|
|
406
|
+
}
|
|
407
|
+
async function syncSkillsCmd() {
|
|
408
|
+
console.log("");
|
|
409
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("sync"));
|
|
410
|
+
spinner.start();
|
|
411
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
412
|
+
const result = (0, skills_1.syncAllSkills)();
|
|
413
|
+
if (result.synced.length > 0) {
|
|
414
|
+
spinner.stop(`${result.synced.length} skills synced`);
|
|
415
|
+
for (const name of result.synced) {
|
|
416
|
+
console.log(` ${chalk_1.default.green("\u2713")} ${DIM(name)}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
spinner.stop("no installed skills to sync");
|
|
421
|
+
}
|
|
422
|
+
if (result.errors.length > 0) {
|
|
423
|
+
console.log("");
|
|
424
|
+
for (const err of result.errors) {
|
|
425
|
+
console.log(` ${ACCENT("\u2717")} ${DIM(err)}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
console.log("");
|
|
429
|
+
}
|
|
430
|
+
function addSkillCmd(args) {
|
|
431
|
+
const name = args[0];
|
|
432
|
+
const source = args[1];
|
|
433
|
+
if (!name || !source) {
|
|
434
|
+
console.log("");
|
|
435
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill add <name> <source>"));
|
|
436
|
+
console.log(DIM(" source: local:/path/to/skill.md or github:owner/repo/path"));
|
|
437
|
+
console.log("");
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
441
|
+
(0, skill_catalog_1.addSkillEntry)(catalog, {
|
|
442
|
+
name,
|
|
443
|
+
description: `Custom skill: ${name}`,
|
|
444
|
+
version: "1.0.0",
|
|
445
|
+
source,
|
|
446
|
+
scope: "shared",
|
|
447
|
+
identity_fields: [],
|
|
448
|
+
requires: [],
|
|
449
|
+
});
|
|
450
|
+
console.log("");
|
|
451
|
+
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(name)} added to catalog`);
|
|
452
|
+
console.log(DIM(` source: ${source}`));
|
|
453
|
+
console.log(DIM(" run ") + chalk_1.default.cyan(`youmd skill install ${name}`) + DIM(" to install."));
|
|
454
|
+
console.log("");
|
|
455
|
+
}
|
|
456
|
+
async function createSkillCmd(args) {
|
|
457
|
+
const readline = require("readline");
|
|
458
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
459
|
+
const ask = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
460
|
+
console.log("");
|
|
461
|
+
console.log(" " + chalk_1.default.bold("youmd skill create"));
|
|
462
|
+
console.log(DIM(" scaffold a new identity-aware skill\n"));
|
|
463
|
+
// Name
|
|
464
|
+
let name = args[0] || "";
|
|
465
|
+
if (!name) {
|
|
466
|
+
name = await ask(ACCENT(" skill name: "));
|
|
467
|
+
}
|
|
468
|
+
if (!name) {
|
|
469
|
+
console.log(chalk_1.default.yellow(" name is required."));
|
|
470
|
+
rl.close();
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-");
|
|
474
|
+
// Description
|
|
475
|
+
const description = await ask(DIM(" description: "));
|
|
476
|
+
// Scope
|
|
477
|
+
const scopeInput = await ask(DIM(" scope (shared/project/private) [shared]: "));
|
|
478
|
+
const scope = (["shared", "project", "private"].includes(scopeInput) ? scopeInput : "shared");
|
|
479
|
+
// Identity fields
|
|
480
|
+
console.log(DIM(" common fields: voice.overall, preferences.agent, directives.agent, profile.about"));
|
|
481
|
+
const fieldsInput = await ask(DIM(" identity fields (comma-separated): "));
|
|
482
|
+
const identityFields = fieldsInput
|
|
483
|
+
? fieldsInput.split(",").map((f) => f.trim()).filter(Boolean)
|
|
484
|
+
: [];
|
|
485
|
+
rl.close();
|
|
486
|
+
// Generate SKILL.md content
|
|
487
|
+
const skillContent = [
|
|
488
|
+
"---",
|
|
489
|
+
`name: ${slug}`,
|
|
490
|
+
`version: 1.0.0`,
|
|
491
|
+
`scope: ${scope}`,
|
|
492
|
+
`identity_fields: [${identityFields.join(", ")}]`,
|
|
493
|
+
`description: "${description || `Custom skill: ${slug}`}"`,
|
|
494
|
+
"---",
|
|
495
|
+
"",
|
|
496
|
+
`# ${slug}`,
|
|
497
|
+
"",
|
|
498
|
+
description || "(describe what this skill does)",
|
|
499
|
+
"",
|
|
500
|
+
...(identityFields.length > 0
|
|
501
|
+
? [
|
|
502
|
+
"## Identity Context",
|
|
503
|
+
"",
|
|
504
|
+
...identityFields.map((f) => `- **${f}:** {{${f}}}`),
|
|
505
|
+
"",
|
|
506
|
+
]
|
|
507
|
+
: []),
|
|
508
|
+
"## What This Skill Does",
|
|
509
|
+
"",
|
|
510
|
+
"1. (step 1)",
|
|
511
|
+
"2. (step 2)",
|
|
512
|
+
"3. (step 3)",
|
|
513
|
+
"",
|
|
514
|
+
].join("\n");
|
|
515
|
+
// Write to ~/.youmd/skills/<name>/SKILL.md
|
|
516
|
+
const os = require("os");
|
|
517
|
+
const skillDir = path.join(os.homedir(), ".youmd", "skills", slug);
|
|
518
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
519
|
+
fs.writeFileSync(path.join(skillDir, "SKILL.md"), skillContent);
|
|
520
|
+
// Add to catalog
|
|
521
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
522
|
+
(0, skill_catalog_1.addSkillEntry)(catalog, {
|
|
523
|
+
name: slug,
|
|
524
|
+
description: description || `Custom skill: ${slug}`,
|
|
525
|
+
version: "1.0.0",
|
|
526
|
+
source: `local:${path.join(skillDir, "SKILL.md")}`,
|
|
527
|
+
scope,
|
|
528
|
+
identity_fields: identityFields,
|
|
529
|
+
requires: [],
|
|
530
|
+
installed: true,
|
|
531
|
+
});
|
|
532
|
+
console.log("");
|
|
533
|
+
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(slug)} created`);
|
|
534
|
+
console.log(DIM(` ${path.join(skillDir, "SKILL.md")}`));
|
|
535
|
+
console.log("");
|
|
536
|
+
console.log(DIM(" edit the SKILL.md, then:"));
|
|
537
|
+
console.log(` ${chalk_1.default.cyan(`youmd skill use ${slug}`)} ${DIM("render with your identity")}`);
|
|
538
|
+
console.log(` ${chalk_1.default.cyan(`youmd skill link claude`)} ${DIM("link to your project")}`);
|
|
539
|
+
console.log("");
|
|
540
|
+
}
|
|
541
|
+
function pushSkillCmd(args) {
|
|
542
|
+
const name = args[0];
|
|
543
|
+
if (!name) {
|
|
544
|
+
console.log("");
|
|
545
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill push <name>"));
|
|
546
|
+
console.log("");
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
550
|
+
const entry = (0, skill_catalog_1.findSkill)(catalog, name);
|
|
551
|
+
if (!entry) {
|
|
552
|
+
console.log("");
|
|
553
|
+
console.log(chalk_1.default.yellow(` skill "${name}" not found.`));
|
|
554
|
+
console.log("");
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (!entry.source.startsWith("local:")) {
|
|
558
|
+
console.log("");
|
|
559
|
+
console.log(DIM(" push is only supported for local: sources right now."));
|
|
560
|
+
console.log(DIM(` source: ${entry.source}`));
|
|
561
|
+
console.log("");
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const skillPath = path.join(require("os").homedir(), ".youmd", "skills", entry.name, "SKILL.md");
|
|
565
|
+
if (!fs.existsSync(skillPath)) {
|
|
566
|
+
console.log(chalk_1.default.yellow(` SKILL.md not found for "${name}". install first.`));
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const destPath = entry.source.slice("local:".length);
|
|
570
|
+
const content = fs.readFileSync(skillPath, "utf-8");
|
|
571
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
572
|
+
fs.writeFileSync(destPath, content);
|
|
573
|
+
console.log("");
|
|
574
|
+
console.log(chalk_1.default.green(" \u2713") + ` ${name} pushed to ${destPath}`);
|
|
575
|
+
console.log("");
|
|
576
|
+
}
|
|
577
|
+
async function linkSkillsCmd(args) {
|
|
578
|
+
let target = (args[0] || "").toLowerCase();
|
|
579
|
+
const validTargets = ["claude", "cursor", "codex"];
|
|
580
|
+
// Auto-detect agent if no target specified
|
|
581
|
+
if (!target) {
|
|
582
|
+
const cwd = process.cwd();
|
|
583
|
+
if (fs.existsSync(path.join(cwd, ".claude")) || fs.existsSync(path.join(cwd, "CLAUDE.md"))) {
|
|
584
|
+
target = "claude";
|
|
585
|
+
}
|
|
586
|
+
else if (fs.existsSync(path.join(cwd, ".cursor"))) {
|
|
587
|
+
target = "cursor";
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
target = "claude"; // default
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (!validTargets.includes(target)) {
|
|
594
|
+
console.log("");
|
|
595
|
+
console.log(chalk_1.default.yellow(` unknown target: ${target}`));
|
|
596
|
+
console.log(DIM(` valid targets: ${validTargets.join(", ")}`));
|
|
597
|
+
console.log("");
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
console.log("");
|
|
601
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("link"));
|
|
602
|
+
spinner.start();
|
|
603
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
604
|
+
const result = (0, skills_1.linkToAgent)(target);
|
|
605
|
+
if (result.ok) {
|
|
606
|
+
spinner.stop(result.path);
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
spinner.fail(result.error);
|
|
610
|
+
}
|
|
611
|
+
console.log("");
|
|
612
|
+
}
|
|
613
|
+
function parseInitProjectMode(args) {
|
|
614
|
+
const modeFlag = args.find((arg) => arg.startsWith("--mode="));
|
|
615
|
+
const modeIndex = args.indexOf("--mode");
|
|
616
|
+
const explicitMode = modeFlag?.slice("--mode=".length) ||
|
|
617
|
+
(modeIndex >= 0 && modeIndex + 1 < args.length ? args[modeIndex + 1] : undefined);
|
|
618
|
+
const value = (explicitMode || "auto").toLowerCase();
|
|
619
|
+
if (value === "auto" || value === "additive" || value === "zero-touch" || value === "scaffold") {
|
|
620
|
+
return value;
|
|
621
|
+
}
|
|
622
|
+
return "auto";
|
|
623
|
+
}
|
|
624
|
+
async function initProjectCmd(args = []) {
|
|
625
|
+
console.log("");
|
|
626
|
+
console.log(" " + chalk_1.default.bold("youmd skill init-project"));
|
|
627
|
+
const mode = parseInitProjectMode(args);
|
|
628
|
+
// Detect existing .youmd-project
|
|
629
|
+
const youmdProjectPath = path.join(process.cwd(), ".youmd-project");
|
|
630
|
+
if (fs.existsSync(youmdProjectPath)) {
|
|
631
|
+
console.log(DIM(" .youmd-project already exists -- re-running will update...\n"));
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
console.log(DIM(` scaffolding identity-aware project structure (${mode} mode)...\n`));
|
|
635
|
+
}
|
|
636
|
+
// Auto-install all catalog skills first (not just 2)
|
|
637
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
638
|
+
const toInstall = catalog.skills.filter((s) => !s.installed);
|
|
639
|
+
if (toInstall.length > 0) {
|
|
640
|
+
const installSpinner = new render_1.BrailleSpinner(randomSpinner("install"));
|
|
641
|
+
installSpinner.start();
|
|
642
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
643
|
+
let installed = 0;
|
|
644
|
+
for (const entry of toInstall) {
|
|
645
|
+
let result = (0, skills_1.installSkill)(entry.name);
|
|
646
|
+
if (!result.ok && (entry.source.startsWith("github:") || entry.source.startsWith("https://"))) {
|
|
647
|
+
result = await (0, skills_1.installSkillAsync)(entry.name);
|
|
648
|
+
}
|
|
649
|
+
if (result.ok)
|
|
650
|
+
installed++;
|
|
651
|
+
}
|
|
652
|
+
installSpinner.stop(`${installed} skills installed`);
|
|
653
|
+
}
|
|
654
|
+
const spinner = new render_1.BrailleSpinner(randomSpinner("init"));
|
|
655
|
+
spinner.start();
|
|
656
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
657
|
+
const result = (0, skills_1.initProject)({ mode });
|
|
658
|
+
spinner.stop();
|
|
659
|
+
console.log("");
|
|
660
|
+
for (const step of result.steps) {
|
|
661
|
+
const icon = step.ok ? chalk_1.default.green("\u2713") : ACCENT("\u2717");
|
|
662
|
+
const detail = step.detail ? DIM(` ${step.detail}`) : "";
|
|
663
|
+
console.log(` ${icon} ${step.name}${detail}`);
|
|
664
|
+
}
|
|
665
|
+
console.log("");
|
|
666
|
+
if (result.ok) {
|
|
667
|
+
console.log(" " + chalk_1.default.green("project initialized with your identity."));
|
|
668
|
+
console.log(DIM(` mode: ${result.mode} -- every agent touching this repo now has the right entrypoints.`));
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
console.log(ACCENT(" some steps failed. check above for details."));
|
|
672
|
+
}
|
|
673
|
+
console.log("");
|
|
674
|
+
}
|
|
675
|
+
function metricsCmd() {
|
|
676
|
+
const metrics = (0, skills_1.getMetrics)();
|
|
677
|
+
console.log("");
|
|
678
|
+
console.log(" " + chalk_1.default.bold("skill metrics"));
|
|
679
|
+
console.log("");
|
|
680
|
+
const skillEntries = Object.entries(metrics.skills);
|
|
681
|
+
if (skillEntries.length === 0) {
|
|
682
|
+
console.log(DIM(" no usage data yet. use some skills first."));
|
|
683
|
+
console.log("");
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const maxName = Math.max(...skillEntries.map(([name]) => name.length));
|
|
687
|
+
for (const [name, data] of skillEntries) {
|
|
688
|
+
const lastUsed = data.lastUsed
|
|
689
|
+
? DIM(` last: ${data.lastUsed.slice(0, 10)}`)
|
|
690
|
+
: "";
|
|
691
|
+
console.log(` ${chalk_1.default.cyan(name.padEnd(maxName + 2))}` +
|
|
692
|
+
`${ACCENT(String(data.uses))} uses ` +
|
|
693
|
+
`${DIM(String(data.installs))} installs${lastUsed}`);
|
|
694
|
+
}
|
|
695
|
+
console.log("");
|
|
696
|
+
const fieldEntries = Object.entries(metrics.identityFields);
|
|
697
|
+
if (fieldEntries.length > 0) {
|
|
698
|
+
console.log(" " + ACCENT("identity field usage:"));
|
|
699
|
+
for (const [field, data] of fieldEntries.sort((a, b) => b[1].references - a[1].references)) {
|
|
700
|
+
console.log(` ${DIM(field.padEnd(25))} ${ACCENT(String(data.references))} refs`);
|
|
701
|
+
}
|
|
702
|
+
console.log("");
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
function improveCmd() {
|
|
706
|
+
const metrics = (0, skills_1.getMetrics)();
|
|
707
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
708
|
+
const identity = (0, skill_renderer_1.loadIdentityData)();
|
|
709
|
+
console.log("");
|
|
710
|
+
console.log(" " + chalk_1.default.bold("skill improvement analysis"));
|
|
711
|
+
console.log("");
|
|
712
|
+
const installed = catalog.skills.filter((s) => s.installed);
|
|
713
|
+
const notInstalled = catalog.skills.filter((s) => !s.installed);
|
|
714
|
+
// ─── Activity Analysis ────────────────────────────────────────────
|
|
715
|
+
const totalUses = Object.values(metrics.skills).reduce((sum, s) => sum + s.uses, 0);
|
|
716
|
+
console.log(" " + ACCENT("overview: ") +
|
|
717
|
+
`${installed.length} installed, ${totalUses} total uses, ` +
|
|
718
|
+
`${Object.keys(metrics.identityFields).length} identity fields tracked`);
|
|
719
|
+
console.log("");
|
|
720
|
+
// Most used
|
|
721
|
+
const mostUsed = Object.entries(metrics.skills)
|
|
722
|
+
.filter(([, data]) => data.uses > 0)
|
|
723
|
+
.sort((a, b) => b[1].uses - a[1].uses)
|
|
724
|
+
.slice(0, 5);
|
|
725
|
+
if (mostUsed.length > 0) {
|
|
726
|
+
console.log(" " + ACCENT("most active:"));
|
|
727
|
+
for (const [name, data] of mostUsed) {
|
|
728
|
+
const bar = ACCENT("\u2588".repeat(Math.min(data.uses, 20))) + DIM("\u2591".repeat(Math.max(0, 20 - data.uses)));
|
|
729
|
+
console.log(` ${chalk_1.default.cyan(name.padEnd(24))} ${bar} ${data.uses}`);
|
|
730
|
+
}
|
|
731
|
+
console.log("");
|
|
732
|
+
}
|
|
733
|
+
// Unused installed skills
|
|
734
|
+
const unused = installed.filter((s) => {
|
|
735
|
+
const m = metrics.skills[s.name];
|
|
736
|
+
return !m || m.uses === 0;
|
|
737
|
+
});
|
|
738
|
+
if (unused.length > 0) {
|
|
739
|
+
console.log(" " + chalk_1.default.yellow("installed but never used:"));
|
|
740
|
+
for (const s of unused) {
|
|
741
|
+
console.log(` ${DIM(s.name)} — consider removing or using`);
|
|
742
|
+
}
|
|
743
|
+
console.log("");
|
|
744
|
+
}
|
|
745
|
+
if (notInstalled.length > 0) {
|
|
746
|
+
console.log(" " + DIM("available but not installed:"));
|
|
747
|
+
for (const s of notInstalled) {
|
|
748
|
+
console.log(` ${chalk_1.default.cyan(s.name)} — ${DIM(s.description)}`);
|
|
749
|
+
}
|
|
750
|
+
console.log("");
|
|
751
|
+
}
|
|
752
|
+
// ─── Identity Coverage ────────────────────────────────────────────
|
|
753
|
+
const allFields = new Set();
|
|
754
|
+
for (const s of catalog.skills) {
|
|
755
|
+
for (const f of s.identity_fields)
|
|
756
|
+
allFields.add(f);
|
|
757
|
+
}
|
|
758
|
+
const filled = [];
|
|
759
|
+
const missing = [];
|
|
760
|
+
for (const field of allFields) {
|
|
761
|
+
const val = (0, skill_renderer_1.resolveVariable)(field, identity);
|
|
762
|
+
if (val) {
|
|
763
|
+
filled.push(field);
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
missing.push(field);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (allFields.size > 0) {
|
|
770
|
+
const pct = Math.round((filled.length / allFields.size) * 100);
|
|
771
|
+
const barWidth = 30;
|
|
772
|
+
const filledBar = Math.round((filled.length / allFields.size) * barWidth);
|
|
773
|
+
const bar = chalk_1.default.green("\u2588".repeat(filledBar)) + DIM("\u2591".repeat(barWidth - filledBar));
|
|
774
|
+
console.log(" " + ACCENT("identity coverage:"));
|
|
775
|
+
console.log(` ${bar} ${pct}% (${filled.length}/${allFields.size})`);
|
|
776
|
+
console.log("");
|
|
777
|
+
}
|
|
778
|
+
if (missing.length > 0) {
|
|
779
|
+
console.log(" " + ACCENT("identity gaps:"));
|
|
780
|
+
console.log(DIM(" referenced by skills but empty in your identity:"));
|
|
781
|
+
for (const f of missing) {
|
|
782
|
+
console.log(` ${chalk_1.default.yellow(f)}`);
|
|
783
|
+
}
|
|
784
|
+
console.log(DIM("\n fill via ") + chalk_1.default.cyan("youmd chat") + DIM(" or edit .youmd/preferences/"));
|
|
785
|
+
console.log("");
|
|
786
|
+
}
|
|
787
|
+
else if (allFields.size > 0) {
|
|
788
|
+
console.log(" " + chalk_1.default.green("\u2713") + DIM(" all identity fields populated."));
|
|
789
|
+
console.log("");
|
|
790
|
+
}
|
|
791
|
+
// ─── Actionable Proposals ─────────────────────────────────────────
|
|
792
|
+
const proposals = [];
|
|
793
|
+
// Propose installing uninstalled skills if identity data exists for them
|
|
794
|
+
for (const s of notInstalled) {
|
|
795
|
+
const hasData = s.identity_fields.some((f) => (0, skill_renderer_1.resolveVariable)(f, identity));
|
|
796
|
+
if (hasData) {
|
|
797
|
+
proposals.push(`install "${s.name}" — you have identity data it needs`);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
// Propose adding directives if agent preference exists but no directives
|
|
801
|
+
if (identity.preferences.agent && !identity.directives.agent) {
|
|
802
|
+
proposals.push("add directives.agent — you have agent preferences but no directives file");
|
|
803
|
+
}
|
|
804
|
+
// Propose voice sync if voice data exists but voice-sync isn't installed
|
|
805
|
+
if (identity.voice.overall && !(0, skill_catalog_1.findSkill)(catalog, "voice-sync")?.installed) {
|
|
806
|
+
proposals.push("install voice-sync — you have voice data that could propagate to all agents");
|
|
807
|
+
}
|
|
808
|
+
// Propose running sync if skills are installed but metrics show 0 syncs
|
|
809
|
+
const syncCount = Object.values(metrics.skills).reduce((sum, s) => sum + s.uses, 0);
|
|
810
|
+
if (installed.length > 0 && syncCount === 0) {
|
|
811
|
+
proposals.push("run \"youmd skill sync\" — installed skills haven't been synced yet");
|
|
812
|
+
}
|
|
813
|
+
// Propose linking if skills installed but no .claude/skills/youmd exists
|
|
814
|
+
if (installed.length > 0) {
|
|
815
|
+
const claudeSkillsDir = path.join(process.cwd(), ".claude", "skills", "youmd");
|
|
816
|
+
if (!fs.existsSync(claudeSkillsDir)) {
|
|
817
|
+
proposals.push("run \"youmd skill link claude\" — skills aren't linked to this project's agent");
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
if (proposals.length > 0) {
|
|
821
|
+
console.log(" " + chalk_1.default.bold("proposals:"));
|
|
822
|
+
for (const p of proposals) {
|
|
823
|
+
console.log(` ${ACCENT("\u203A")} ${p}`);
|
|
824
|
+
}
|
|
825
|
+
console.log("");
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
console.log(" " + chalk_1.default.green("\u2713") + DIM(" no improvements to suggest right now."));
|
|
829
|
+
console.log("");
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function searchCmd(args) {
|
|
833
|
+
const query = args.join(" ");
|
|
834
|
+
if (!query) {
|
|
835
|
+
console.log("");
|
|
836
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill search <query>"));
|
|
837
|
+
console.log("");
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
841
|
+
const results = (0, skill_catalog_1.searchSkills)(catalog, query);
|
|
842
|
+
console.log("");
|
|
843
|
+
if (results.length === 0) {
|
|
844
|
+
console.log(DIM(` no skills matching "${query}".`));
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
console.log(` ${results.length} result${results.length === 1 ? "" : "s"} for "${query}":`);
|
|
848
|
+
console.log("");
|
|
849
|
+
for (const s of results) {
|
|
850
|
+
const status = s.installed ? chalk_1.default.green("\u2713") : DIM("\u2022");
|
|
851
|
+
console.log(` ${status} ${chalk_1.default.cyan(s.name)} — ${DIM(s.description)}`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
console.log("");
|
|
855
|
+
}
|
|
856
|
+
async function browseCmd() {
|
|
857
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
858
|
+
console.log("");
|
|
859
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: youmd login"));
|
|
860
|
+
console.log("");
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
console.log("");
|
|
864
|
+
const spinner = new render_1.BrailleSpinner("scanning the skill registry");
|
|
865
|
+
spinner.start();
|
|
866
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
867
|
+
try {
|
|
868
|
+
const res = await (0, api_1.browseSkills)();
|
|
869
|
+
if (!res.ok) {
|
|
870
|
+
spinner.fail("could not reach registry");
|
|
871
|
+
console.log("");
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const skills = res.data.skills;
|
|
875
|
+
spinner.stop(`${skills.length} skill${skills.length === 1 ? "" : "s"} in registry`);
|
|
876
|
+
if (skills.length === 0) {
|
|
877
|
+
console.log(DIM(" no skills published yet."));
|
|
878
|
+
console.log(DIM(" be the first: ") + chalk_1.default.cyan("youmd skill publish <name>"));
|
|
879
|
+
console.log("");
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
console.log("");
|
|
883
|
+
const maxName = Math.max(...skills.map((s) => s.name.length));
|
|
884
|
+
for (const s of skills) {
|
|
885
|
+
const dl = s.downloads > 0 ? ACCENT(` ${s.downloads} dl`) : "";
|
|
886
|
+
console.log(` ${chalk_1.default.cyan(s.name.padEnd(maxName + 2))}` +
|
|
887
|
+
`${DIM(s.description)}${dl}`);
|
|
888
|
+
console.log(` ${DIM("v" + s.version)} ${DIM(s.scope)} ${DIM(`[${s.identityFields.join(", ")}]`)}`);
|
|
889
|
+
}
|
|
890
|
+
console.log("");
|
|
891
|
+
console.log(DIM(` install with: youmd skill add <name> registry:<name>`));
|
|
892
|
+
}
|
|
893
|
+
catch {
|
|
894
|
+
spinner.fail("registry unreachable");
|
|
895
|
+
}
|
|
896
|
+
console.log("");
|
|
897
|
+
}
|
|
898
|
+
async function publishSkillCmd(args) {
|
|
899
|
+
const name = args[0];
|
|
900
|
+
if (!name) {
|
|
901
|
+
console.log("");
|
|
902
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill publish <name>"));
|
|
903
|
+
console.log(DIM(" publishes an installed skill to the you.md registry."));
|
|
904
|
+
console.log("");
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
908
|
+
console.log("");
|
|
909
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: youmd login"));
|
|
910
|
+
console.log("");
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
914
|
+
const entry = (0, skill_catalog_1.findSkill)(catalog, name);
|
|
915
|
+
if (!entry) {
|
|
916
|
+
console.log("");
|
|
917
|
+
console.log(chalk_1.default.yellow(` skill "${name}" not found in catalog.`));
|
|
918
|
+
console.log("");
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const skillFile = (0, skills_2.readSkillFile)(entry.name);
|
|
922
|
+
if (!skillFile) {
|
|
923
|
+
console.log("");
|
|
924
|
+
console.log(chalk_1.default.yellow(` SKILL.md not found for "${name}". install first.`));
|
|
925
|
+
console.log("");
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
console.log("");
|
|
929
|
+
const spinner = new render_1.BrailleSpinner("publishing to the skill registry");
|
|
930
|
+
spinner.start();
|
|
931
|
+
await new Promise((r) => setTimeout(r, 400));
|
|
932
|
+
try {
|
|
933
|
+
const res = await (0, api_1.publishSkill)({
|
|
934
|
+
name: entry.name,
|
|
935
|
+
description: entry.description,
|
|
936
|
+
version: entry.version,
|
|
937
|
+
scope: entry.scope,
|
|
938
|
+
identityFields: entry.identity_fields,
|
|
939
|
+
content: skillFile.content,
|
|
940
|
+
});
|
|
941
|
+
if (res.ok) {
|
|
942
|
+
spinner.stop(res.data.updated ? "updated" : "published");
|
|
943
|
+
console.log("");
|
|
944
|
+
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(entry.name)} is live on the registry`);
|
|
945
|
+
console.log(DIM(` others can install with: youmd skill add ${entry.name} registry:${entry.name}`));
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
spinner.fail(String(res.data?.error || "publish failed"));
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
catch (err) {
|
|
952
|
+
spinner.fail(err instanceof Error ? err.message : "failed");
|
|
953
|
+
}
|
|
954
|
+
console.log("");
|
|
955
|
+
}
|
|
956
|
+
async function remoteStatusCmd() {
|
|
957
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
958
|
+
console.log("");
|
|
959
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: youmd login"));
|
|
960
|
+
console.log("");
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
console.log("");
|
|
964
|
+
const spinner = new render_1.BrailleSpinner("fetching your skill profile from the cloud");
|
|
965
|
+
spinner.start();
|
|
966
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
967
|
+
try {
|
|
968
|
+
const res = await (0, api_1.getMySkills)();
|
|
969
|
+
if (!res.ok) {
|
|
970
|
+
spinner.fail("could not fetch");
|
|
971
|
+
console.log("");
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
const skills = res.data.skills;
|
|
975
|
+
spinner.stop(`${skills.length} synced to you.md`);
|
|
976
|
+
if (skills.length === 0) {
|
|
977
|
+
console.log(DIM(" no skills synced to your account yet."));
|
|
978
|
+
console.log(DIM(" install skills locally and they'll auto-sync."));
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
console.log("");
|
|
982
|
+
for (const s of skills) {
|
|
983
|
+
const uses = s.useCount > 0 ? ACCENT(` ${s.useCount} uses`) : "";
|
|
984
|
+
console.log(` ${chalk_1.default.green("\u2713")} ${chalk_1.default.cyan(s.skillName)} ${DIM(s.source)}${uses}`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
catch {
|
|
989
|
+
spinner.fail("unreachable");
|
|
990
|
+
}
|
|
991
|
+
console.log("");
|
|
992
|
+
}
|
|
993
|
+
function infoCmd(args) {
|
|
994
|
+
const name = args[0];
|
|
995
|
+
if (!name) {
|
|
996
|
+
console.log("");
|
|
997
|
+
console.log(chalk_1.default.yellow(" usage: youmd skill info <name>"));
|
|
998
|
+
console.log("");
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
1002
|
+
const entry = (0, skill_catalog_1.findSkill)(catalog, name);
|
|
1003
|
+
if (!entry) {
|
|
1004
|
+
console.log("");
|
|
1005
|
+
console.log(chalk_1.default.yellow(` skill "${name}" not found.`));
|
|
1006
|
+
console.log("");
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
const skillFile = (0, skills_2.readSkillFile)(entry.name);
|
|
1010
|
+
const metrics = (0, skills_1.getMetrics)();
|
|
1011
|
+
const m = metrics.skills[entry.name];
|
|
1012
|
+
const identity = (0, skill_renderer_1.loadIdentityData)();
|
|
1013
|
+
console.log("");
|
|
1014
|
+
console.log(" " + chalk_1.default.bold(entry.name) + DIM(` v${entry.version}`));
|
|
1015
|
+
console.log(DIM(` ${entry.description}`));
|
|
1016
|
+
console.log("");
|
|
1017
|
+
// Status
|
|
1018
|
+
console.log(` ${ACCENT("status:")} ${entry.installed ? chalk_1.default.green("installed") : DIM("not installed")}`);
|
|
1019
|
+
console.log(` ${ACCENT("scope:")} ${entry.scope}`);
|
|
1020
|
+
console.log(` ${ACCENT("source:")} ${DIM(entry.source)}`);
|
|
1021
|
+
// Metrics
|
|
1022
|
+
if (m) {
|
|
1023
|
+
console.log(` ${ACCENT("uses:")} ${m.uses}`);
|
|
1024
|
+
console.log(` ${ACCENT("installs:")} ${m.installs}`);
|
|
1025
|
+
if (m.lastUsed)
|
|
1026
|
+
console.log(` ${ACCENT("last used:")} ${DIM(m.lastUsed.slice(0, 10))}`);
|
|
1027
|
+
}
|
|
1028
|
+
// Identity fields
|
|
1029
|
+
if (entry.identity_fields.length > 0) {
|
|
1030
|
+
console.log("");
|
|
1031
|
+
console.log(" " + ACCENT("identity fields:"));
|
|
1032
|
+
for (const field of entry.identity_fields) {
|
|
1033
|
+
const val = (0, skill_renderer_1.resolveVariable)(field, identity);
|
|
1034
|
+
const status = val ? chalk_1.default.green("\u2713") : chalk_1.default.yellow("\u2022");
|
|
1035
|
+
const preview = val ? DIM(` ${truncateAtWord(val, 50)}`) : DIM(" (empty)");
|
|
1036
|
+
console.log(` ${status} ${field}${preview}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
// Content preview
|
|
1040
|
+
if (skillFile) {
|
|
1041
|
+
console.log("");
|
|
1042
|
+
console.log(" " + ACCENT("content:"));
|
|
1043
|
+
const lines = skillFile.content.split("\n").slice(0, 8);
|
|
1044
|
+
for (const line of lines) {
|
|
1045
|
+
console.log(DIM(` ${line}`));
|
|
1046
|
+
}
|
|
1047
|
+
const total = skillFile.content.split("\n").length;
|
|
1048
|
+
if (total > 8) {
|
|
1049
|
+
console.log(DIM(` ... ${total - 8} more lines`));
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
console.log("");
|
|
1053
|
+
}
|
|
1054
|
+
function exportSkillsCmd(args) {
|
|
1055
|
+
const outputDir = args[0] || path.join(process.cwd(), "youmd-skills");
|
|
1056
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
1057
|
+
const installed = catalog.skills.filter((s) => s.installed);
|
|
1058
|
+
if (installed.length === 0) {
|
|
1059
|
+
console.log("");
|
|
1060
|
+
console.log(DIM(" no skills installed to export."));
|
|
1061
|
+
console.log("");
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
1065
|
+
console.log("");
|
|
1066
|
+
let exported = 0;
|
|
1067
|
+
for (const entry of installed) {
|
|
1068
|
+
const skillFile = (0, skills_2.readSkillFile)(entry.name);
|
|
1069
|
+
if (!skillFile)
|
|
1070
|
+
continue;
|
|
1071
|
+
// Export the raw SKILL.md
|
|
1072
|
+
const outPath = path.join(outputDir, `${entry.name}.md`);
|
|
1073
|
+
const raw = fs.readFileSync(path.join(require("os").homedir(), ".youmd", "skills", entry.name, "SKILL.md"), "utf-8");
|
|
1074
|
+
fs.writeFileSync(outPath, raw);
|
|
1075
|
+
// Also export the rendered version
|
|
1076
|
+
const renderedPath = path.join(require("os").homedir(), ".youmd", "skills", entry.name, "RENDERED.md");
|
|
1077
|
+
if (fs.existsSync(renderedPath)) {
|
|
1078
|
+
fs.writeFileSync(path.join(outputDir, `${entry.name}.rendered.md`), fs.readFileSync(renderedPath, "utf-8"));
|
|
1079
|
+
}
|
|
1080
|
+
console.log(` ${chalk_1.default.green("\u2713")} ${entry.name}`);
|
|
1081
|
+
exported++;
|
|
1082
|
+
}
|
|
1083
|
+
// Write catalog.yaml
|
|
1084
|
+
const yaml = require("js-yaml");
|
|
1085
|
+
const exportCatalog = {
|
|
1086
|
+
version: 1,
|
|
1087
|
+
exported: new Date().toISOString(),
|
|
1088
|
+
skills: installed.map((s) => ({
|
|
1089
|
+
name: s.name,
|
|
1090
|
+
description: s.description,
|
|
1091
|
+
version: s.version,
|
|
1092
|
+
scope: s.scope,
|
|
1093
|
+
identity_fields: s.identity_fields,
|
|
1094
|
+
})),
|
|
1095
|
+
};
|
|
1096
|
+
fs.writeFileSync(path.join(outputDir, "catalog.yaml"), yaml.dump(exportCatalog, { lineWidth: 120, noRefs: true }));
|
|
1097
|
+
console.log("");
|
|
1098
|
+
console.log(chalk_1.default.green(` exported ${exported} skills to ${outputDir}/`));
|
|
1099
|
+
console.log(DIM(" share this directory or publish individual skills."));
|
|
1100
|
+
console.log("");
|
|
1101
|
+
}
|
|
1102
|
+
// ─── Main command router ──────────────────────────────────────────────
|
|
1103
|
+
async function skillCommand(subcommand, ...args) {
|
|
1104
|
+
const sub = (subcommand || "").toLowerCase();
|
|
1105
|
+
switch (sub) {
|
|
1106
|
+
case "list":
|
|
1107
|
+
case "ls":
|
|
1108
|
+
await listSkills();
|
|
1109
|
+
break;
|
|
1110
|
+
case "install":
|
|
1111
|
+
await installSkillCmd(args);
|
|
1112
|
+
break;
|
|
1113
|
+
case "remove":
|
|
1114
|
+
case "rm":
|
|
1115
|
+
await removeSkillCmd(args);
|
|
1116
|
+
break;
|
|
1117
|
+
case "use":
|
|
1118
|
+
case "run":
|
|
1119
|
+
await useSkillCmd(args);
|
|
1120
|
+
break;
|
|
1121
|
+
case "sync":
|
|
1122
|
+
await syncSkillsCmd();
|
|
1123
|
+
break;
|
|
1124
|
+
case "add":
|
|
1125
|
+
addSkillCmd(args);
|
|
1126
|
+
break;
|
|
1127
|
+
case "create":
|
|
1128
|
+
case "new":
|
|
1129
|
+
await createSkillCmd(args);
|
|
1130
|
+
break;
|
|
1131
|
+
case "push":
|
|
1132
|
+
pushSkillCmd(args);
|
|
1133
|
+
break;
|
|
1134
|
+
case "link":
|
|
1135
|
+
await linkSkillsCmd(args);
|
|
1136
|
+
break;
|
|
1137
|
+
case "init-project":
|
|
1138
|
+
case "init":
|
|
1139
|
+
await initProjectCmd(args);
|
|
1140
|
+
break;
|
|
1141
|
+
case "improve":
|
|
1142
|
+
improveCmd();
|
|
1143
|
+
break;
|
|
1144
|
+
case "metrics":
|
|
1145
|
+
case "stats":
|
|
1146
|
+
metricsCmd();
|
|
1147
|
+
break;
|
|
1148
|
+
case "search":
|
|
1149
|
+
searchCmd(args);
|
|
1150
|
+
break;
|
|
1151
|
+
case "browse":
|
|
1152
|
+
case "registry":
|
|
1153
|
+
await browseCmd();
|
|
1154
|
+
break;
|
|
1155
|
+
case "publish":
|
|
1156
|
+
await publishSkillCmd(args);
|
|
1157
|
+
break;
|
|
1158
|
+
case "remote":
|
|
1159
|
+
case "cloud":
|
|
1160
|
+
await remoteStatusCmd();
|
|
1161
|
+
break;
|
|
1162
|
+
case "export":
|
|
1163
|
+
exportSkillsCmd(args);
|
|
1164
|
+
break;
|
|
1165
|
+
case "info":
|
|
1166
|
+
case "show":
|
|
1167
|
+
infoCmd(args);
|
|
1168
|
+
break;
|
|
1169
|
+
default: {
|
|
1170
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
1171
|
+
const installed = catalog.skills.filter((s) => s.installed);
|
|
1172
|
+
console.log("");
|
|
1173
|
+
console.log(" " + chalk_1.default.bold("youmd skill") + DIM(" — identity-aware agent skills"));
|
|
1174
|
+
console.log("");
|
|
1175
|
+
if (installed.length > 0) {
|
|
1176
|
+
// Quick identity coverage
|
|
1177
|
+
const identity = (0, skill_renderer_1.loadIdentityData)();
|
|
1178
|
+
const allFields = new Set();
|
|
1179
|
+
for (const s of catalog.skills) {
|
|
1180
|
+
for (const f of s.identity_fields)
|
|
1181
|
+
allFields.add(f);
|
|
1182
|
+
}
|
|
1183
|
+
let filledCount = 0;
|
|
1184
|
+
for (const field of allFields) {
|
|
1185
|
+
if ((0, skill_renderer_1.resolveVariable)(field, identity))
|
|
1186
|
+
filledCount++;
|
|
1187
|
+
}
|
|
1188
|
+
const pct = allFields.size > 0 ? Math.round((filledCount / allFields.size) * 100) : 0;
|
|
1189
|
+
console.log(" " + ACCENT("installed:") +
|
|
1190
|
+
DIM(` ${installed.length}/${catalog.skills.length}`) +
|
|
1191
|
+
DIM(" identity: ") +
|
|
1192
|
+
(pct === 100 ? chalk_1.default.green(`${pct}%`) : ACCENT(`${pct}%`)));
|
|
1193
|
+
for (const s of installed) {
|
|
1194
|
+
console.log(` ${chalk_1.default.green("\u2713")} ${chalk_1.default.cyan(s.name)} ${DIM("v" + s.version)}`);
|
|
1195
|
+
}
|
|
1196
|
+
console.log("");
|
|
1197
|
+
}
|
|
1198
|
+
console.log(" " + chalk_1.default.cyan("commands:"));
|
|
1199
|
+
console.log("");
|
|
1200
|
+
console.log(` ${chalk_1.default.cyan("list".padEnd(28))} ${DIM("show all skills with install status")}`);
|
|
1201
|
+
console.log(` ${chalk_1.default.cyan("install <name|all>".padEnd(28))} ${DIM("install skill(s) from the catalog")}`);
|
|
1202
|
+
console.log(` ${chalk_1.default.cyan("remove <name|all>".padEnd(28))} ${DIM("remove installed skill(s)")}`);
|
|
1203
|
+
console.log(` ${chalk_1.default.cyan("use <name>".padEnd(28))} ${DIM("run a skill with identity interpolation")}`);
|
|
1204
|
+
console.log(` ${chalk_1.default.cyan("sync".padEnd(28))} ${DIM("re-render all skills against live identity")}`);
|
|
1205
|
+
console.log(` ${chalk_1.default.cyan("create [name]".padEnd(28))} ${DIM("scaffold a new custom skill")}`);
|
|
1206
|
+
console.log(` ${chalk_1.default.cyan("add <name> <source>".padEnd(28))} ${DIM("register a new skill in catalog")}`);
|
|
1207
|
+
console.log(` ${chalk_1.default.cyan("push <name>".padEnd(28))} ${DIM("push local changes back to source")}`);
|
|
1208
|
+
console.log(` ${chalk_1.default.cyan("link <agent>".padEnd(28))} ${DIM("link to claude | cursor | codex")}`);
|
|
1209
|
+
console.log(` ${chalk_1.default.cyan("init-project [--mode auto|additive|zero-touch|scaffold]".padEnd(28))} ${DIM("bootstrap AGENTS/CLAUDE + project-context/ + .you/ + links")}`);
|
|
1210
|
+
console.log(` ${chalk_1.default.cyan("improve".padEnd(28))} ${DIM("review metrics, find gaps, propose changes")}`);
|
|
1211
|
+
console.log(` ${chalk_1.default.cyan("metrics".padEnd(28))} ${DIM("usage stats and effectiveness scores")}`);
|
|
1212
|
+
console.log(` ${chalk_1.default.cyan("search <query>".padEnd(28))} ${DIM("search skills by name or description")}`);
|
|
1213
|
+
console.log(` ${chalk_1.default.cyan("browse".padEnd(28))} ${DIM("browse the public skill registry")}`);
|
|
1214
|
+
console.log(` ${chalk_1.default.cyan("publish <name>".padEnd(28))} ${DIM("publish a skill to the registry")}`);
|
|
1215
|
+
console.log(` ${chalk_1.default.cyan("remote".padEnd(28))} ${DIM("show skills synced to your you.md account")}`);
|
|
1216
|
+
console.log(` ${chalk_1.default.cyan("export [dir]".padEnd(28))} ${DIM("export all installed skills to a directory")}`);
|
|
1217
|
+
console.log(` ${chalk_1.default.cyan("info <name>".padEnd(28))} ${DIM("detailed info about a skill")}`);
|
|
1218
|
+
console.log("");
|
|
1219
|
+
console.log(DIM(" skills are identity-aware markdown templates."));
|
|
1220
|
+
console.log(DIM(" {{voice.overall}} and {{preferences.agent}} resolve from your bundle."));
|
|
1221
|
+
console.log("");
|
|
1222
|
+
break;
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
//# sourceMappingURL=skill.js.map
|