youmd 0.8.7 → 0.8.13
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/commands/add.js +1 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/agent.d.ts +4 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +4 -0
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/build.js +2 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/chat.js +1 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -10
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/init.js +5 -5
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.js +8 -1
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/login.js +2 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/machine.d.ts.map +1 -1
- package/dist/commands/machine.js +331 -8
- package/dist/commands/machine.js.map +1 -1
- package/dist/commands/mcp.js +4 -4
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/private.js +2 -2
- package/dist/commands/private.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +31 -0
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/publish.js +1 -1
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/pull.js +1 -1
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.js +1 -1
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/skill.d.ts +1 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +736 -39
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +127 -26
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +84 -3
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/whoami.js +3 -3
- package/dist/commands/whoami.js.map +1 -1
- package/dist/create.js +0 -0
- package/dist/index.js +40 -30
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +190 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +44 -6
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/config.d.ts +20 -12
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +113 -42
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/daemon.d.ts +2 -0
- package/dist/lib/daemon.d.ts.map +1 -1
- package/dist/lib/daemon.js +28 -19
- package/dist/lib/daemon.js.map +1 -1
- package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -1
- package/dist/lib/machine-bootstrap-prompt.js +147 -118
- package/dist/lib/machine-bootstrap-prompt.js.map +1 -1
- package/dist/lib/machine-verify.d.ts +51 -0
- package/dist/lib/machine-verify.d.ts.map +1 -1
- package/dist/lib/machine-verify.js +123 -1
- package/dist/lib/machine-verify.js.map +1 -1
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +3 -8
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/portfolio-audit.d.ts.map +1 -1
- package/dist/lib/portfolio-audit.js +2 -1
- package/dist/lib/portfolio-audit.js.map +1 -1
- package/dist/lib/project.d.ts +3 -3
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +18 -11
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/projectContext.d.ts +10 -9
- package/dist/lib/projectContext.d.ts.map +1 -1
- package/dist/lib/projectContext.js +29 -23
- package/dist/lib/projectContext.js.map +1 -1
- package/dist/lib/realtime-sync.d.ts +26 -0
- package/dist/lib/realtime-sync.d.ts.map +1 -1
- package/dist/lib/realtime-sync.js +51 -7
- package/dist/lib/realtime-sync.js.map +1 -1
- package/dist/lib/render.js +1 -1
- package/dist/lib/render.js.map +1 -1
- package/dist/lib/skill-catalog.d.ts +26 -0
- package/dist/lib/skill-catalog.d.ts.map +1 -1
- package/dist/lib/skill-catalog.js +100 -0
- package/dist/lib/skill-catalog.js.map +1 -1
- package/dist/lib/vault.d.ts +3 -3
- package/dist/lib/vault.d.ts.map +1 -1
- package/dist/lib/vault.js +10 -8
- package/dist/lib/vault.js.map +1 -1
- package/dist/lib/youstack.js +12 -12
- package/dist/lib/youstack.js.map +1 -1
- package/dist/mcp/registry.d.ts +2 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +135 -12
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +135 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/postinstall.js +3 -2
- package/dist/postinstall.js.map +1 -1
- package/dist/you.js +0 -0
- package/package.json +1 -1
- package/scripts/local-agent-stack-inventory.mjs +1188 -0
- package/scripts/skillstack-sync/README.md +33 -25
- package/scripts/skillstack-sync/bootstrap-new-mac.sh +1 -1
- package/scripts/skillstack-sync/capture-agent-config.sh +8 -1
- package/scripts/skillstack-sync/{com.youmd.context-sync.plist → com.you.context-sync.plist} +3 -3
- package/scripts/skillstack-sync/{com.youmd.identity-sync.plist → com.you.identity-sync.plist} +3 -3
- package/scripts/skillstack-sync/{com.youmd.realtime-sync.plist → com.you.realtime-sync.plist} +3 -3
- package/scripts/skillstack-sync/{com.youmd.skillstack-sync.plist → com.you.skillstack-sync.plist} +3 -3
- package/scripts/skillstack-sync/context-sync.sh +1 -1
- package/scripts/skillstack-sync/install-daemons.sh +20 -6
- package/scripts/skillstack-sync/restore-agent-config.sh +1 -1
- package/scripts/skillstack-sync/sync.sh +1 -1
- package/skills/machine-bootstrap.md +57 -55
package/dist/commands/skill.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* you skill — identity-aware agent skill system.
|
|
4
4
|
*
|
|
5
5
|
* Subcommand router following the project.ts pattern.
|
|
6
6
|
* Manages skill lifecycle: install, remove, use, sync, link, init-project.
|
|
@@ -48,6 +48,7 @@ const path = __importStar(require("path"));
|
|
|
48
48
|
const os = __importStar(require("os"));
|
|
49
49
|
const readline = __importStar(require("readline"));
|
|
50
50
|
const yaml = __importStar(require("js-yaml"));
|
|
51
|
+
const child_process_1 = require("child_process");
|
|
51
52
|
const chalk_1 = __importDefault(require("chalk"));
|
|
52
53
|
const skill_catalog_1 = require("../lib/skill-catalog");
|
|
53
54
|
const skills_1 = require("../lib/skills");
|
|
@@ -110,6 +111,308 @@ function truncateAtWord(text, max) {
|
|
|
110
111
|
const lastSpace = truncated.lastIndexOf(" ");
|
|
111
112
|
return (lastSpace > max * 0.5 ? truncated.slice(0, lastSpace) : truncated) + "...";
|
|
112
113
|
}
|
|
114
|
+
function sourcePrefix(source) {
|
|
115
|
+
const idx = source.indexOf(":");
|
|
116
|
+
return idx > 0 ? source.slice(0, idx) : "path";
|
|
117
|
+
}
|
|
118
|
+
function parseFlagArgs(args) {
|
|
119
|
+
const positional = [];
|
|
120
|
+
const flags = {};
|
|
121
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
122
|
+
const arg = args[i];
|
|
123
|
+
if (!arg.startsWith("--")) {
|
|
124
|
+
positional.push(arg);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const eq = arg.indexOf("=");
|
|
128
|
+
if (eq > 0) {
|
|
129
|
+
flags[arg.slice(2, eq)] = arg.slice(eq + 1);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const key = arg.slice(2);
|
|
133
|
+
const next = args[i + 1];
|
|
134
|
+
if (next && !next.startsWith("--")) {
|
|
135
|
+
flags[key] = next;
|
|
136
|
+
i += 1;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
flags[key] = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { positional, flags };
|
|
143
|
+
}
|
|
144
|
+
function flagString(flags, key) {
|
|
145
|
+
const value = flags[key];
|
|
146
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
147
|
+
}
|
|
148
|
+
function resolveInventoryScript() {
|
|
149
|
+
const candidates = [
|
|
150
|
+
process.env.YOU_AGENT_STACK_INVENTORY_SCRIPT || process.env.YOUMD_AGENT_STACK_INVENTORY_SCRIPT,
|
|
151
|
+
path.join(os.homedir(), ".agent-shared", "claude-skills", "agent-stack-inventory", "scripts", "local-agent-stack-inventory.mjs"),
|
|
152
|
+
path.join((0, config_1.getSkillsDir)(), "agent-stack-inventory", "scripts", "local-agent-stack-inventory.mjs"),
|
|
153
|
+
path.join(os.homedir(), ".youmd", "skills", "agent-stack-inventory", "scripts", "local-agent-stack-inventory.mjs"),
|
|
154
|
+
path.resolve(__dirname, "../../scripts/local-agent-stack-inventory.mjs"),
|
|
155
|
+
path.resolve(__dirname, "../../../scripts/local-agent-stack-inventory.mjs"),
|
|
156
|
+
].filter(Boolean);
|
|
157
|
+
for (const candidate of candidates) {
|
|
158
|
+
if (fs.existsSync(candidate))
|
|
159
|
+
return candidate;
|
|
160
|
+
}
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
function readInventorySnapshot(file) {
|
|
164
|
+
return JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
165
|
+
}
|
|
166
|
+
function inventoryNames(snapshot) {
|
|
167
|
+
return new Set((snapshot.uniqueSkills || []).map((skill) => skill.name).filter(Boolean));
|
|
168
|
+
}
|
|
169
|
+
function sortInventoryJsonPaths(files) {
|
|
170
|
+
return files.sort((a, b) => {
|
|
171
|
+
const delta = fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs;
|
|
172
|
+
if (delta !== 0)
|
|
173
|
+
return delta;
|
|
174
|
+
return path.basename(b).localeCompare(path.basename(a));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function findLatestInventoryJson(outDir, sinceMs = 0) {
|
|
178
|
+
if (!fs.existsSync(outDir))
|
|
179
|
+
return null;
|
|
180
|
+
const files = sortInventoryJsonPaths(fs.readdirSync(outDir)
|
|
181
|
+
.filter((file) => /^local-agent-stack-inventory-.*\.json$/.test(file))
|
|
182
|
+
.map((file) => path.join(outDir, file))
|
|
183
|
+
.filter((file) => {
|
|
184
|
+
try {
|
|
185
|
+
return fs.statSync(file).mtimeMs >= sinceMs - 1000;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
}));
|
|
191
|
+
return files[0] || null;
|
|
192
|
+
}
|
|
193
|
+
function renderInventoryTotals(totals) {
|
|
194
|
+
const rows = [
|
|
195
|
+
["unique skill names", totals.uniqueSkillNames],
|
|
196
|
+
["real SKILL.md files", totals.uniqueRealSkillFiles],
|
|
197
|
+
["direct host exposures", totals.directExposureSkillRecords],
|
|
198
|
+
["You.md catalog skills", totals.youmdCatalogSkills],
|
|
199
|
+
["missing from You.md catalog", totals.missingFromYoumdCatalog],
|
|
200
|
+
["DRY review cases", totals.duplicateNameDifferentRealpaths],
|
|
201
|
+
["healthy mirror clusters", totals.sameRealpathMirrors],
|
|
202
|
+
["project/context signals", totals.projectSignals],
|
|
203
|
+
];
|
|
204
|
+
const maxLabel = Math.max(...rows.map(([label]) => label.length));
|
|
205
|
+
for (const [label, value] of rows) {
|
|
206
|
+
if (typeof value !== "number")
|
|
207
|
+
continue;
|
|
208
|
+
console.log(` ${DIM(label.padEnd(maxLabel + 2))}${chalk_1.default.cyan(value.toLocaleString())}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function renderInventoryPhaseTimings(snapshot) {
|
|
212
|
+
const timings = (snapshot.phaseTimings || [])
|
|
213
|
+
.filter((phase) => typeof phase.durationMs === "number")
|
|
214
|
+
.sort((a, b) => (b.durationMs || 0) - (a.durationMs || 0))
|
|
215
|
+
.slice(0, 4);
|
|
216
|
+
if (timings.length === 0)
|
|
217
|
+
return;
|
|
218
|
+
console.log(` ${DIM("slowest phases")}`);
|
|
219
|
+
for (const phase of timings) {
|
|
220
|
+
const seconds = Math.max(0, Math.round((phase.durationMs || 0) / 1000));
|
|
221
|
+
const label = phase.label || phase.phase || "unknown phase";
|
|
222
|
+
const status = phase.failed ? ACCENT(" failed") : "";
|
|
223
|
+
console.log(` ${DIM(label.padEnd(50))}${chalk_1.default.cyan(`${seconds}s`)}${status}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function runInventoryScript(scriptArgs, spinner) {
|
|
227
|
+
return new Promise((resolve, reject) => {
|
|
228
|
+
const child = (0, child_process_1.spawn)(process.execPath, scriptArgs, {
|
|
229
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
230
|
+
});
|
|
231
|
+
const stdout = [];
|
|
232
|
+
const stderr = [];
|
|
233
|
+
let progressBuffer = "";
|
|
234
|
+
child.stdout.on("data", (chunk) => {
|
|
235
|
+
stdout.push(chunk);
|
|
236
|
+
});
|
|
237
|
+
child.stderr.on("data", (chunk) => {
|
|
238
|
+
const text = chunk.toString("utf-8");
|
|
239
|
+
stderr.push(chunk);
|
|
240
|
+
progressBuffer += text;
|
|
241
|
+
const lines = progressBuffer.split(/\r?\n/);
|
|
242
|
+
progressBuffer = lines.pop() || "";
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
const trimmed = line.trim();
|
|
245
|
+
if (!trimmed.startsWith("youmd-inventory-progress "))
|
|
246
|
+
continue;
|
|
247
|
+
try {
|
|
248
|
+
const event = JSON.parse(trimmed.slice("youmd-inventory-progress ".length));
|
|
249
|
+
if (event.label && event.event === "start") {
|
|
250
|
+
spinner.update(event.label);
|
|
251
|
+
}
|
|
252
|
+
else if (event.label && event.event === "failed") {
|
|
253
|
+
spinner.update(`${event.label} failed`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// Non-JSON stderr is collected for failure output below.
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
child.on("error", reject);
|
|
262
|
+
child.on("close", (code) => {
|
|
263
|
+
if (code === 0) {
|
|
264
|
+
resolve(Buffer.concat(stdout).toString("utf-8"));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const detail = Buffer.concat(stderr).toString("utf-8").trim();
|
|
268
|
+
reject(new Error(detail || `inventory exited with code ${code}`));
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
function compactDate(value) {
|
|
273
|
+
if (typeof value === "string" && value)
|
|
274
|
+
return value.replace(/\.\d{3}Z$/, "Z");
|
|
275
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
276
|
+
return new Date(value).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
277
|
+
return "unknown";
|
|
278
|
+
}
|
|
279
|
+
function inventoryTotalsFromSynced(row) {
|
|
280
|
+
return {
|
|
281
|
+
uniqueSkillNames: row.uniqueSkillNames,
|
|
282
|
+
uniqueRealSkillFiles: row.uniqueRealSkillFiles,
|
|
283
|
+
directExposureSkillRecords: row.directExposureSkillRecords,
|
|
284
|
+
canonicalSkillFiles: row.canonicalSkillFiles,
|
|
285
|
+
youmdCatalogSkills: row.youmdCatalogSkills,
|
|
286
|
+
missingFromYoumdCatalog: row.missingFromYoumdCatalog,
|
|
287
|
+
duplicateNameDifferentRealpaths: row.duplicateNameDifferentRealpaths,
|
|
288
|
+
sameRealpathMirrors: row.sameRealpathMirrors,
|
|
289
|
+
projectSignals: row.projectSignals,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function inventoryDelta(localValue, remoteValue) {
|
|
293
|
+
if (typeof localValue !== "number" || typeof remoteValue !== "number")
|
|
294
|
+
return DIM("?");
|
|
295
|
+
const delta = remoteValue - localValue;
|
|
296
|
+
if (delta === 0)
|
|
297
|
+
return chalk_1.default.green("0");
|
|
298
|
+
return delta > 0 ? chalk_1.default.green(`+${delta}`) : ACCENT(String(delta));
|
|
299
|
+
}
|
|
300
|
+
function renderInventoryDrift(drift) {
|
|
301
|
+
if (!drift?.baseline)
|
|
302
|
+
return;
|
|
303
|
+
console.log("");
|
|
304
|
+
console.log(` ${DIM("drift baseline")} ${chalk_1.default.cyan(drift.baseline.hostName)}${DIM(` · ${compactDate(drift.baseline.generatedAt)} · ${drift.baseline.counts.uniqueSkillNames} skills`)}`);
|
|
305
|
+
console.log(` ${DIM("drift summary ")} ` +
|
|
306
|
+
`${chalk_1.default.cyan(String(drift.summary.machineCount))} machines · ` +
|
|
307
|
+
`${drift.summary.driftCount > 0 ? ACCENT(String(drift.summary.driftCount)) : chalk_1.default.green("0")} drift · ` +
|
|
308
|
+
`${drift.summary.staleCount > 0 ? ACCENT(String(drift.summary.staleCount)) : chalk_1.default.green("0")} stale · ` +
|
|
309
|
+
`${drift.summary.unsafeCount > 0 ? ACCENT(String(drift.summary.unsafeCount)) : chalk_1.default.green("0")} unsafe`);
|
|
310
|
+
const issueRows = drift.machines.filter((machine) => machine.status !== "baseline" && machine.issues.length > 0).slice(0, 4);
|
|
311
|
+
for (const machine of issueRows) {
|
|
312
|
+
console.log(` ${ACCENT(machine.status.padEnd(8))} ${chalk_1.default.cyan(machine.hostName)} ${DIM(machine.issues.slice(0, 2).join("; "))}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function inventoryHostName(snapshot) {
|
|
316
|
+
if (typeof snapshot.host === "string" && snapshot.host.trim())
|
|
317
|
+
return snapshot.host.trim();
|
|
318
|
+
if (snapshot.host && typeof snapshot.host === "object" && snapshot.host.hostname) {
|
|
319
|
+
return snapshot.host.hostname;
|
|
320
|
+
}
|
|
321
|
+
return os.hostname();
|
|
322
|
+
}
|
|
323
|
+
function inventorySnapshotLabel(snapshot, fallback) {
|
|
324
|
+
const host = inventoryHostName(snapshot);
|
|
325
|
+
return host || fallback;
|
|
326
|
+
}
|
|
327
|
+
function safeInventoryCount(value) {
|
|
328
|
+
return Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
|
|
329
|
+
}
|
|
330
|
+
function inventorySampleNames(rows) {
|
|
331
|
+
if (!Array.isArray(rows))
|
|
332
|
+
return [];
|
|
333
|
+
return rows
|
|
334
|
+
.flatMap((row) => {
|
|
335
|
+
if (typeof row === "string")
|
|
336
|
+
return [row];
|
|
337
|
+
if (row?.name)
|
|
338
|
+
return [row.name];
|
|
339
|
+
return [];
|
|
340
|
+
})
|
|
341
|
+
.map((name) => name.trim())
|
|
342
|
+
.filter(Boolean)
|
|
343
|
+
.slice(0, 24);
|
|
344
|
+
}
|
|
345
|
+
function inventoryCatalogRows(snapshot) {
|
|
346
|
+
return (snapshot.missingFromCatalog || []).flatMap((row) => {
|
|
347
|
+
if (typeof row === "string")
|
|
348
|
+
return [{ name: row }];
|
|
349
|
+
return [row];
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function buildAgentStackInventorySyncPayload(snapshot, jsonPath, htmlPath, syncRepo = true) {
|
|
353
|
+
const totals = snapshot.totals || {};
|
|
354
|
+
return {
|
|
355
|
+
inventorySchemaVersion: snapshot.inventorySchemaVersion || "local-agent-stack-inventory/v1",
|
|
356
|
+
generatedAt: snapshot.generatedAt || new Date().toISOString(),
|
|
357
|
+
hostName: inventoryHostName(snapshot),
|
|
358
|
+
platform: `${os.platform()} ${os.release()}`,
|
|
359
|
+
rootDir: snapshot.roots?.workspace || snapshot.repoRoot || process.cwd(),
|
|
360
|
+
secretValuesExposed: false,
|
|
361
|
+
reportJsonPath: jsonPath,
|
|
362
|
+
reportHtmlPath: htmlPath,
|
|
363
|
+
source: "youmd-cli",
|
|
364
|
+
agentName: "you skill inventory",
|
|
365
|
+
totals: {
|
|
366
|
+
uniqueSkillNames: safeInventoryCount(totals.uniqueSkillNames),
|
|
367
|
+
uniqueRealSkillFiles: safeInventoryCount(totals.uniqueRealSkillFiles),
|
|
368
|
+
directExposureSkillRecords: safeInventoryCount(totals.directExposureSkillRecords),
|
|
369
|
+
canonicalSkillFiles: safeInventoryCount(totals.canonicalSkillFiles),
|
|
370
|
+
youmdCatalogSkills: safeInventoryCount(totals.youmdCatalogSkills),
|
|
371
|
+
missingFromYoumdCatalog: safeInventoryCount(totals.missingFromYoumdCatalog),
|
|
372
|
+
duplicateNameDifferentRealpaths: safeInventoryCount(totals.duplicateNameDifferentRealpaths),
|
|
373
|
+
sameRealpathMirrors: safeInventoryCount(totals.sameRealpathMirrors),
|
|
374
|
+
projectSignals: safeInventoryCount(totals.projectSignals),
|
|
375
|
+
},
|
|
376
|
+
ownershipRollup: snapshot.ownershipRollup || {},
|
|
377
|
+
syncPolicyRollup: snapshot.syncPolicyRollup || {},
|
|
378
|
+
provenanceRollup: snapshot.provenanceRollup || {},
|
|
379
|
+
missingCatalogSamples: inventorySampleNames(snapshot.missingFromCatalog),
|
|
380
|
+
duplicateNameSamples: inventorySampleNames(snapshot.dryAudit?.duplicateNameDifferentRealpaths),
|
|
381
|
+
mirrorSamples: inventorySampleNames(snapshot.dryAudit?.sameRealpathMirrors),
|
|
382
|
+
syncRepo,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function buildSkillSyncActivityMetadata(synced, errors) {
|
|
386
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
387
|
+
const entries = [];
|
|
388
|
+
for (const name of synced) {
|
|
389
|
+
const entry = (0, skill_catalog_1.findSkill)(catalog, name);
|
|
390
|
+
if (entry)
|
|
391
|
+
entries.push(entry);
|
|
392
|
+
}
|
|
393
|
+
const sharedSkills = entries
|
|
394
|
+
.filter((entry) => entry.source.startsWith("shared:"))
|
|
395
|
+
.map((entry) => entry.name)
|
|
396
|
+
.sort();
|
|
397
|
+
const sourcePrefixes = {};
|
|
398
|
+
const scopes = {};
|
|
399
|
+
for (const entry of entries) {
|
|
400
|
+
const prefix = sourcePrefix(entry.source);
|
|
401
|
+
sourcePrefixes[prefix] = (sourcePrefixes[prefix] ?? 0) + 1;
|
|
402
|
+
scopes[entry.scope] = (scopes[entry.scope] ?? 0) + 1;
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
syncedCount: synced.length,
|
|
406
|
+
errorCount: errors.length,
|
|
407
|
+
skills: synced.slice(0, 20),
|
|
408
|
+
sharedSkillCount: sharedSkills.length,
|
|
409
|
+
sharedSkills: sharedSkills.slice(0, 20),
|
|
410
|
+
sourcePrefixes,
|
|
411
|
+
scopes,
|
|
412
|
+
canonicalSharedRoot: "~/.agent-shared/claude-skills",
|
|
413
|
+
secretValuesExposed: false,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
113
416
|
// ─── Subcommands ──────────────────────────────────────────────────────
|
|
114
417
|
const RECOMMENDED_SKILLS = new Set([
|
|
115
418
|
"youstack-start",
|
|
@@ -121,11 +424,11 @@ const RECOMMENDED_SKILLS = new Set([
|
|
|
121
424
|
async function listSkills() {
|
|
122
425
|
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
123
426
|
console.log("");
|
|
124
|
-
console.log(" " + chalk_1.default.bold("
|
|
427
|
+
console.log(" " + chalk_1.default.bold("you skills") + DIM(` (${catalog.skills.length} in catalog)`));
|
|
125
428
|
console.log("");
|
|
126
429
|
if (catalog.skills.length === 0) {
|
|
127
430
|
console.log(DIM(" no skills registered."));
|
|
128
|
-
console.log(DIM(" run ") + chalk_1.default.cyan("
|
|
431
|
+
console.log(DIM(" run ") + chalk_1.default.cyan("you skill add <name> <source>") + DIM(" to add one."));
|
|
129
432
|
console.log("");
|
|
130
433
|
return;
|
|
131
434
|
}
|
|
@@ -175,7 +478,7 @@ async function listSkills() {
|
|
|
175
478
|
if (installed === 0) {
|
|
176
479
|
console.log("");
|
|
177
480
|
console.log(DIM(" get started: ") +
|
|
178
|
-
chalk_1.default.cyan("
|
|
481
|
+
chalk_1.default.cyan("you skill install youstack-start"));
|
|
179
482
|
}
|
|
180
483
|
console.log("");
|
|
181
484
|
}
|
|
@@ -206,8 +509,8 @@ async function installSkillCmd(args) {
|
|
|
206
509
|
}
|
|
207
510
|
if (!name) {
|
|
208
511
|
console.log("");
|
|
209
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
210
|
-
console.log(DIM(" or:
|
|
512
|
+
console.log(chalk_1.default.yellow(" usage: you skill install <name>"));
|
|
513
|
+
console.log(DIM(" or: you skill install all"));
|
|
211
514
|
console.log("");
|
|
212
515
|
return;
|
|
213
516
|
}
|
|
@@ -279,8 +582,8 @@ async function installSkillCmd(args) {
|
|
|
279
582
|
}
|
|
280
583
|
console.log("");
|
|
281
584
|
console.log(chalk_1.default.yellow(` skill "${name}" not found in catalog or registry.`));
|
|
282
|
-
console.log(DIM(" run ") + chalk_1.default.cyan("
|
|
283
|
-
console.log(DIM(" or: ") + chalk_1.default.cyan("
|
|
585
|
+
console.log(DIM(" run ") + chalk_1.default.cyan("you skill list") + DIM(" to see available skills."));
|
|
586
|
+
console.log(DIM(" or: ") + chalk_1.default.cyan("you skill browse") + DIM(" to check the registry."));
|
|
284
587
|
console.log("");
|
|
285
588
|
return;
|
|
286
589
|
}
|
|
@@ -343,8 +646,8 @@ async function removeSkillCmd(args) {
|
|
|
343
646
|
}
|
|
344
647
|
if (!name) {
|
|
345
648
|
console.log("");
|
|
346
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
347
|
-
console.log(DIM(" or:
|
|
649
|
+
console.log(chalk_1.default.yellow(" usage: you skill remove <name>"));
|
|
650
|
+
console.log(DIM(" or: you skill remove all"));
|
|
348
651
|
console.log("");
|
|
349
652
|
return;
|
|
350
653
|
}
|
|
@@ -364,7 +667,7 @@ async function skillUseCmd(args) {
|
|
|
364
667
|
const name = args[0];
|
|
365
668
|
if (!name) {
|
|
366
669
|
console.log("");
|
|
367
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
670
|
+
console.log(chalk_1.default.yellow(" usage: you skill use <name>"));
|
|
368
671
|
console.log("");
|
|
369
672
|
return;
|
|
370
673
|
}
|
|
@@ -385,7 +688,7 @@ async function skillUseCmd(args) {
|
|
|
385
688
|
console.log("");
|
|
386
689
|
console.log(ACCENT(` ${filled}/${total} identity fields resolved.`) +
|
|
387
690
|
DIM(` missing: ${missing.join(", ")}`));
|
|
388
|
-
console.log(DIM(" fill these via ") + chalk_1.default.cyan("you") + DIM(" or edit .
|
|
691
|
+
console.log(DIM(" fill these via ") + chalk_1.default.cyan("you") + DIM(" or edit .you/preferences/"));
|
|
389
692
|
}
|
|
390
693
|
else {
|
|
391
694
|
console.log(DIM(` ${total}/${total} identity fields resolved.`));
|
|
@@ -428,6 +731,37 @@ async function syncSkillsCmd() {
|
|
|
428
731
|
console.log(` ${ACCENT("\u2717")} ${DIM(err)}`);
|
|
429
732
|
}
|
|
430
733
|
}
|
|
734
|
+
if ((0, config_1.isAuthenticated)()) {
|
|
735
|
+
try {
|
|
736
|
+
const metadata = buildSkillSyncActivityMetadata(result.synced, result.errors);
|
|
737
|
+
const sharedSkillCount = metadata.sharedSkillCount;
|
|
738
|
+
await (0, api_1.recordBrainActivity)({
|
|
739
|
+
activityId: `skill-sync:${os.hostname()}`,
|
|
740
|
+
source: "skill-sync",
|
|
741
|
+
channel: "skills",
|
|
742
|
+
kind: result.errors.length > 0 ? "warn" : sharedSkillCount > 0 ? "shared-skill-sync" : "synced",
|
|
743
|
+
status: result.errors.length > 0 ? "warn" : "ok",
|
|
744
|
+
title: sharedSkillCount > 0
|
|
745
|
+
? `${result.synced.length} skills synced · ${sharedSkillCount} shared`
|
|
746
|
+
: `${result.synced.length} skills synced`,
|
|
747
|
+
detail: result.errors.length > 0
|
|
748
|
+
? `${result.errors.length} sync warning${result.errors.length === 1 ? "" : "s"}`
|
|
749
|
+
: sharedSkillCount > 0
|
|
750
|
+
? `shared skills propagated from ~/.agent-shared: ${metadata.sharedSkills.slice(0, 5).join(", ")}`
|
|
751
|
+
: "installed skills re-rendered against the latest identity bundle",
|
|
752
|
+
sourceHost: os.hostname(),
|
|
753
|
+
sourceAgent: "youmd CLI",
|
|
754
|
+
sourceRuntime: process.version,
|
|
755
|
+
entityType: sharedSkillCount > 0 ? "sharedSkillSync" : "skillSync",
|
|
756
|
+
entityId: os.hostname(),
|
|
757
|
+
metadata,
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
catch (err) {
|
|
761
|
+
if (process.env.DEBUG)
|
|
762
|
+
console.error(`[skill sync] brain activity failed: ${err}`);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
431
765
|
console.log("");
|
|
432
766
|
}
|
|
433
767
|
function addSkillCmd(args) {
|
|
@@ -435,7 +769,7 @@ function addSkillCmd(args) {
|
|
|
435
769
|
const source = args[1];
|
|
436
770
|
if (!name || !source) {
|
|
437
771
|
console.log("");
|
|
438
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
772
|
+
console.log(chalk_1.default.yellow(" usage: you skill add <name> <source>"));
|
|
439
773
|
console.log(DIM(" source: local:/path/to/skill.md, github:owner/repo/path, or registry:<name>"));
|
|
440
774
|
console.log("");
|
|
441
775
|
return;
|
|
@@ -453,14 +787,14 @@ function addSkillCmd(args) {
|
|
|
453
787
|
console.log("");
|
|
454
788
|
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(name)} added to catalog`);
|
|
455
789
|
console.log(DIM(` source: ${source}`));
|
|
456
|
-
console.log(DIM(" run ") + chalk_1.default.cyan(`
|
|
790
|
+
console.log(DIM(" run ") + chalk_1.default.cyan(`you skill install ${name}`) + DIM(" to install."));
|
|
457
791
|
console.log("");
|
|
458
792
|
}
|
|
459
793
|
async function createSkillCmd(args) {
|
|
460
794
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
461
795
|
const ask = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
462
796
|
console.log("");
|
|
463
|
-
console.log(" " + chalk_1.default.bold("
|
|
797
|
+
console.log(" " + chalk_1.default.bold("you skill create"));
|
|
464
798
|
console.log(DIM(" scaffold a new identity-aware skill\n"));
|
|
465
799
|
// Name
|
|
466
800
|
let name = args[0] || "";
|
|
@@ -514,8 +848,8 @@ async function createSkillCmd(args) {
|
|
|
514
848
|
"3. (step 3)",
|
|
515
849
|
"",
|
|
516
850
|
].join("\n");
|
|
517
|
-
// Write to ~/.
|
|
518
|
-
const skillDir = path.join(
|
|
851
|
+
// Write to ~/.you/skills/<name>/SKILL.md
|
|
852
|
+
const skillDir = path.join((0, config_1.getSkillsDir)(), slug);
|
|
519
853
|
fs.mkdirSync(skillDir, { recursive: true });
|
|
520
854
|
fs.writeFileSync(path.join(skillDir, "SKILL.md"), skillContent);
|
|
521
855
|
// Add to catalog
|
|
@@ -535,15 +869,15 @@ async function createSkillCmd(args) {
|
|
|
535
869
|
console.log(DIM(` ${path.join(skillDir, "SKILL.md")}`));
|
|
536
870
|
console.log("");
|
|
537
871
|
console.log(DIM(" edit the SKILL.md, then:"));
|
|
538
|
-
console.log(` ${chalk_1.default.cyan(`
|
|
539
|
-
console.log(` ${chalk_1.default.cyan(`
|
|
872
|
+
console.log(` ${chalk_1.default.cyan(`you skill use ${slug}`)} ${DIM("render with your identity")}`);
|
|
873
|
+
console.log(` ${chalk_1.default.cyan(`you skill link claude`)} ${DIM("link to your project")}`);
|
|
540
874
|
console.log("");
|
|
541
875
|
}
|
|
542
876
|
function pushSkillCmd(args) {
|
|
543
877
|
const name = args[0];
|
|
544
878
|
if (!name) {
|
|
545
879
|
console.log("");
|
|
546
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
880
|
+
console.log(chalk_1.default.yellow(" usage: you skill push <name>"));
|
|
547
881
|
console.log("");
|
|
548
882
|
return;
|
|
549
883
|
}
|
|
@@ -562,7 +896,7 @@ function pushSkillCmd(args) {
|
|
|
562
896
|
console.log("");
|
|
563
897
|
return;
|
|
564
898
|
}
|
|
565
|
-
const skillPath =
|
|
899
|
+
const skillPath = (0, skills_2.getSkillDir)(entry.name);
|
|
566
900
|
if (!fs.existsSync(skillPath)) {
|
|
567
901
|
console.log(chalk_1.default.yellow(` SKILL.md not found for "${name}". install first.`));
|
|
568
902
|
return;
|
|
@@ -623,7 +957,7 @@ function parseInitProjectMode(args) {
|
|
|
623
957
|
}
|
|
624
958
|
async function initProjectCmd(args = []) {
|
|
625
959
|
console.log("");
|
|
626
|
-
console.log(" " + chalk_1.default.bold("
|
|
960
|
+
console.log(" " + chalk_1.default.bold("you skill init-project"));
|
|
627
961
|
const mode = parseInitProjectMode(args);
|
|
628
962
|
// Detect existing .youmd-project
|
|
629
963
|
const youmdProjectPath = path.join(process.cwd(), ".youmd-project");
|
|
@@ -708,6 +1042,7 @@ async function improveCmd() {
|
|
|
708
1042
|
const notInstalled = catalog.skills.filter((s) => !s.installed);
|
|
709
1043
|
// ─── Live outcome insights (L10) ──────────────────────────────────
|
|
710
1044
|
let liveInsights = null;
|
|
1045
|
+
const lowPerformers = [];
|
|
711
1046
|
if ((0, config_1.isAuthenticated)()) {
|
|
712
1047
|
const insightSpinner = new render_1.BrailleSpinner("fetching outcome telemetry");
|
|
713
1048
|
insightSpinner.start();
|
|
@@ -751,7 +1086,6 @@ async function improveCmd() {
|
|
|
751
1086
|
`last used`;
|
|
752
1087
|
console.log(DIM(headerStr));
|
|
753
1088
|
console.log(DIM(" " + "-".repeat(headerStr.length - 2)));
|
|
754
|
-
const lowPerformers = [];
|
|
755
1089
|
for (const s of liveInsights) {
|
|
756
1090
|
const ratePct = Math.round(s.successRate * 100);
|
|
757
1091
|
const rateStr = `${ratePct}%`.padStart(4);
|
|
@@ -847,7 +1181,7 @@ async function improveCmd() {
|
|
|
847
1181
|
for (const f of missing) {
|
|
848
1182
|
console.log(` ${chalk_1.default.yellow(f)}`);
|
|
849
1183
|
}
|
|
850
|
-
console.log(DIM("\n fill via ") + chalk_1.default.cyan("you") + DIM(" or edit .
|
|
1184
|
+
console.log(DIM("\n fill via ") + chalk_1.default.cyan("you") + DIM(" or edit .you/preferences/"));
|
|
851
1185
|
console.log("");
|
|
852
1186
|
}
|
|
853
1187
|
else if (allFields.size > 0) {
|
|
@@ -880,14 +1214,14 @@ async function improveCmd() {
|
|
|
880
1214
|
identityChangedAt !== null &&
|
|
881
1215
|
(Number.isNaN(lastSyncedAtMs) || identityChangedAt > lastSyncedAtMs)) {
|
|
882
1216
|
proposals.push(Number.isNaN(lastSyncedAtMs)
|
|
883
|
-
? "run \"
|
|
884
|
-
: "run \"
|
|
1217
|
+
? "run \"you skill sync\" — installed skills haven't been synced against your identity yet"
|
|
1218
|
+
: "run \"you skill sync\" — your identity changed after the last skill sync");
|
|
885
1219
|
}
|
|
886
1220
|
// Propose linking if skills are installed but not linked into the Claude
|
|
887
1221
|
// Code discovery layout (.claude/skills/<name>/SKILL.md)
|
|
888
1222
|
if (installed.length > 0 &&
|
|
889
1223
|
!(0, host_link_1.hasLinkedClaudeSkills)(process.cwd(), installed.map((s) => s.name))) {
|
|
890
|
-
proposals.push("run \"
|
|
1224
|
+
proposals.push("run \"you skill link claude\" — skills aren't linked to this project's agent");
|
|
891
1225
|
}
|
|
892
1226
|
if (proposals.length > 0) {
|
|
893
1227
|
console.log(" " + chalk_1.default.bold("proposals:"));
|
|
@@ -907,12 +1241,366 @@ async function improveCmd() {
|
|
|
907
1241
|
}
|
|
908
1242
|
console.log("");
|
|
909
1243
|
}
|
|
1244
|
+
if ((0, config_1.isAuthenticated)()) {
|
|
1245
|
+
try {
|
|
1246
|
+
await (0, api_1.recordBrainActivity)({
|
|
1247
|
+
activityId: `skill-improve:${os.hostname()}`,
|
|
1248
|
+
source: "skill-improve",
|
|
1249
|
+
channel: "skills",
|
|
1250
|
+
kind: proposals.length > 0 || lowPerformers.length > 0 ? "proposed" : "checked",
|
|
1251
|
+
status: proposals.length > 0 || lowPerformers.length > 0 ? "warn" : "ok",
|
|
1252
|
+
title: proposals.length > 0 || lowPerformers.length > 0
|
|
1253
|
+
? `skill improvement analysis found ${proposals.length + lowPerformers.length} signal${proposals.length + lowPerformers.length === 1 ? "" : "s"}`
|
|
1254
|
+
: "skill improvement analysis clean",
|
|
1255
|
+
detail: proposals.length > 0
|
|
1256
|
+
? proposals.slice(0, 3).join(" · ")
|
|
1257
|
+
: lowPerformers.length > 0
|
|
1258
|
+
? `low performers: ${lowPerformers.map((s) => s.skill).slice(0, 5).join(", ")}`
|
|
1259
|
+
: "no immediate skill improvements suggested",
|
|
1260
|
+
entityType: "skillImprovementAnalysis",
|
|
1261
|
+
entityId: os.hostname(),
|
|
1262
|
+
sourceHost: os.hostname(),
|
|
1263
|
+
sourceAgent: "youmd CLI",
|
|
1264
|
+
sourceRuntime: process.version,
|
|
1265
|
+
metadata: {
|
|
1266
|
+
installedCount: installed.length,
|
|
1267
|
+
notInstalledCount: notInstalled.length,
|
|
1268
|
+
localUseCount: totalUses,
|
|
1269
|
+
identityFieldCount: allFields.size,
|
|
1270
|
+
missingIdentityFields: missing.slice(0, 20),
|
|
1271
|
+
proposalCount: proposals.length,
|
|
1272
|
+
proposals: proposals.slice(0, 12),
|
|
1273
|
+
lowPerformerCount: lowPerformers.length,
|
|
1274
|
+
lowPerformers: lowPerformers.slice(0, 12).map((skill) => ({
|
|
1275
|
+
skill: skill.skill,
|
|
1276
|
+
uses: skill.uses,
|
|
1277
|
+
successRate: skill.successRate,
|
|
1278
|
+
failure: skill.failure,
|
|
1279
|
+
partial: skill.partial,
|
|
1280
|
+
})),
|
|
1281
|
+
liveInsightCount: liveInsights?.length ?? 0,
|
|
1282
|
+
fleetLineCount: fleetLines.length,
|
|
1283
|
+
secretValuesExposed: false,
|
|
1284
|
+
},
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
catch (err) {
|
|
1288
|
+
if (process.env.DEBUG)
|
|
1289
|
+
console.error(`[skill improve] brain activity failed: ${err}`);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
function inventoryDiffCmd(args) {
|
|
1294
|
+
const { positional, flags } = parseFlagArgs(args);
|
|
1295
|
+
const leftPath = flagString(flags, "left") || positional[0];
|
|
1296
|
+
const rightPath = flagString(flags, "right") || positional[1];
|
|
1297
|
+
if (!leftPath || !rightPath) {
|
|
1298
|
+
console.log("");
|
|
1299
|
+
console.log(chalk_1.default.yellow(" usage: you skill inventory diff --left mac-mini.json --right laptop.json"));
|
|
1300
|
+
console.log(DIM(" or: you skill inventory diff mac-mini.json laptop.json"));
|
|
1301
|
+
console.log("");
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
const left = readInventorySnapshot(path.resolve(leftPath));
|
|
1305
|
+
const right = readInventorySnapshot(path.resolve(rightPath));
|
|
1306
|
+
const leftNames = inventoryNames(left);
|
|
1307
|
+
const rightNames = inventoryNames(right);
|
|
1308
|
+
const onlyLeft = [...leftNames].filter((name) => !rightNames.has(name)).sort();
|
|
1309
|
+
const onlyRight = [...rightNames].filter((name) => !leftNames.has(name)).sort();
|
|
1310
|
+
console.log("");
|
|
1311
|
+
console.log(" " + chalk_1.default.bold("skill inventory diff"));
|
|
1312
|
+
console.log("");
|
|
1313
|
+
console.log(` ${DIM("left ")}${chalk_1.default.cyan(inventorySnapshotLabel(left, path.basename(leftPath)))}${DIM(left.generatedAt ? ` · ${left.generatedAt}` : "")}`);
|
|
1314
|
+
console.log(` ${DIM("right")}${chalk_1.default.cyan(" " + inventorySnapshotLabel(right, path.basename(rightPath)))}${DIM(right.generatedAt ? ` · ${right.generatedAt}` : "")}`);
|
|
1315
|
+
console.log("");
|
|
1316
|
+
const totalRows = [
|
|
1317
|
+
["unique skill names", left.totals?.uniqueSkillNames, right.totals?.uniqueSkillNames],
|
|
1318
|
+
["real SKILL.md files", left.totals?.uniqueRealSkillFiles, right.totals?.uniqueRealSkillFiles],
|
|
1319
|
+
["direct host exposures", left.totals?.directExposureSkillRecords, right.totals?.directExposureSkillRecords],
|
|
1320
|
+
["You.md catalog skills", left.totals?.youmdCatalogSkills, right.totals?.youmdCatalogSkills],
|
|
1321
|
+
["missing from catalog", left.totals?.missingFromYoumdCatalog, right.totals?.missingFromYoumdCatalog],
|
|
1322
|
+
["DRY review cases", left.totals?.duplicateNameDifferentRealpaths, right.totals?.duplicateNameDifferentRealpaths],
|
|
1323
|
+
["mirror clusters", left.totals?.sameRealpathMirrors, right.totals?.sameRealpathMirrors],
|
|
1324
|
+
];
|
|
1325
|
+
const maxLabel = Math.max(...totalRows.map(([label]) => label.length));
|
|
1326
|
+
for (const [label, leftValue, rightValue] of totalRows) {
|
|
1327
|
+
const delta = typeof leftValue === "number" && typeof rightValue === "number"
|
|
1328
|
+
? rightValue - leftValue
|
|
1329
|
+
: undefined;
|
|
1330
|
+
const deltaText = typeof delta === "number"
|
|
1331
|
+
? delta === 0
|
|
1332
|
+
? DIM(" 0")
|
|
1333
|
+
: delta > 0
|
|
1334
|
+
? chalk_1.default.green(` +${delta}`)
|
|
1335
|
+
: ACCENT(` ${delta}`)
|
|
1336
|
+
: "";
|
|
1337
|
+
console.log(` ${DIM(label.padEnd(maxLabel + 2))}` +
|
|
1338
|
+
`${String(leftValue ?? "?").padStart(6)} ${DIM("->")} ${String(rightValue ?? "?").padStart(6)}${deltaText}`);
|
|
1339
|
+
}
|
|
1340
|
+
console.log("");
|
|
1341
|
+
console.log(` ${DIM("skills only in left: ")}${onlyLeft.length}`);
|
|
1342
|
+
for (const name of onlyLeft.slice(0, 20))
|
|
1343
|
+
console.log(` ${ACCENT("-")} ${name}`);
|
|
1344
|
+
if (onlyLeft.length > 20)
|
|
1345
|
+
console.log(DIM(` ... ${onlyLeft.length - 20} more`));
|
|
1346
|
+
console.log("");
|
|
1347
|
+
console.log(` ${DIM("skills only in right: ")}${onlyRight.length}`);
|
|
1348
|
+
for (const name of onlyRight.slice(0, 20))
|
|
1349
|
+
console.log(` ${chalk_1.default.green("+")} ${name}`);
|
|
1350
|
+
if (onlyRight.length > 20)
|
|
1351
|
+
console.log(DIM(` ... ${onlyRight.length - 20} more`));
|
|
1352
|
+
console.log("");
|
|
1353
|
+
}
|
|
1354
|
+
async function inventoryStatusCmd(args) {
|
|
1355
|
+
const { flags } = parseFlagArgs(args);
|
|
1356
|
+
const outDir = path.resolve(flagString(flags, "out-dir") || path.join((0, config_1.getWritableHomeBundleDir)(), "agent-stack-inventory"));
|
|
1357
|
+
const limitRaw = flagString(flags, "limit");
|
|
1358
|
+
const limit = limitRaw && Number.isFinite(Number(limitRaw))
|
|
1359
|
+
? Math.max(1, Math.min(50, Math.trunc(Number(limitRaw))))
|
|
1360
|
+
: 12;
|
|
1361
|
+
const jsonOutput = flags.json === true;
|
|
1362
|
+
const latestPath = findLatestInventoryJson(outDir);
|
|
1363
|
+
const local = latestPath ? readInventorySnapshot(latestPath) : null;
|
|
1364
|
+
const localTotals = local?.totals || {};
|
|
1365
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
1366
|
+
if (jsonOutput) {
|
|
1367
|
+
console.log(JSON.stringify({
|
|
1368
|
+
success: false,
|
|
1369
|
+
error: "not_authenticated",
|
|
1370
|
+
repair: "you login",
|
|
1371
|
+
secretValuesExposed: false,
|
|
1372
|
+
}, null, 2));
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
console.log("");
|
|
1376
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: ") + chalk_1.default.cyan("you login"));
|
|
1377
|
+
console.log(DIM(" then: ") + chalk_1.default.cyan("you skill inventory status"));
|
|
1378
|
+
console.log("");
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
const [res, driftRes] = await Promise.all([
|
|
1382
|
+
(0, api_1.getAgentStackInventories)({ limit }),
|
|
1383
|
+
(0, api_1.getAgentStackInventoryDrift)({ limit }),
|
|
1384
|
+
]);
|
|
1385
|
+
if (!res.ok) {
|
|
1386
|
+
const message = (0, api_1.apiErrorMessage)(res.data) || `HTTP ${res.status}`;
|
|
1387
|
+
if (jsonOutput) {
|
|
1388
|
+
console.log(JSON.stringify({
|
|
1389
|
+
success: false,
|
|
1390
|
+
error: message,
|
|
1391
|
+
secretValuesExposed: false,
|
|
1392
|
+
}, null, 2));
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
console.log("");
|
|
1396
|
+
console.log(chalk_1.default.yellow(` inventory status unavailable: ${message}`));
|
|
1397
|
+
console.log("");
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const inventories = res.data?.inventories ?? [];
|
|
1401
|
+
const drift = driftRes.ok ? driftRes.data : null;
|
|
1402
|
+
if (jsonOutput) {
|
|
1403
|
+
console.log(JSON.stringify({
|
|
1404
|
+
success: true,
|
|
1405
|
+
local: local
|
|
1406
|
+
? {
|
|
1407
|
+
path: latestPath,
|
|
1408
|
+
hostName: inventoryHostName(local),
|
|
1409
|
+
generatedAt: local.generatedAt,
|
|
1410
|
+
rootDir: local.roots?.workspace || local.repoRoot,
|
|
1411
|
+
totals: localTotals,
|
|
1412
|
+
}
|
|
1413
|
+
: null,
|
|
1414
|
+
inventories,
|
|
1415
|
+
drift,
|
|
1416
|
+
secretValuesExposed: false,
|
|
1417
|
+
}, null, 2));
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1420
|
+
console.log("");
|
|
1421
|
+
console.log(" " + chalk_1.default.bold("skill inventory status"));
|
|
1422
|
+
console.log("");
|
|
1423
|
+
if (local && latestPath) {
|
|
1424
|
+
console.log(` ${DIM("local latest")} ${chalk_1.default.cyan(inventoryHostName(local))}${DIM(local.generatedAt ? ` · ${compactDate(local.generatedAt)}` : "")}`);
|
|
1425
|
+
console.log(` ${DIM("local json ")} ${chalk_1.default.cyan(latestPath)}`);
|
|
1426
|
+
if (localTotals) {
|
|
1427
|
+
console.log(` ${DIM("local counts")} ` +
|
|
1428
|
+
`${chalk_1.default.cyan(String(localTotals.uniqueSkillNames ?? "?"))} skills · ` +
|
|
1429
|
+
`${chalk_1.default.cyan(String(localTotals.uniqueRealSkillFiles ?? "?"))} files · ` +
|
|
1430
|
+
`${ACCENT(String(localTotals.missingFromYoumdCatalog ?? 0))} catalog gaps · ` +
|
|
1431
|
+
`${ACCENT(String(localTotals.duplicateNameDifferentRealpaths ?? 0))} DRY reviews`);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
else {
|
|
1435
|
+
console.log(chalk_1.default.yellow(" local latest: missing"));
|
|
1436
|
+
console.log(DIM(" repair: ") + chalk_1.default.cyan(`you skill inventory --out-dir ${outDir} --register-catalog --sync`));
|
|
1437
|
+
}
|
|
1438
|
+
console.log("");
|
|
1439
|
+
if (inventories.length === 0) {
|
|
1440
|
+
console.log(chalk_1.default.yellow(" no synced machine inventories found yet."));
|
|
1441
|
+
}
|
|
1442
|
+
else {
|
|
1443
|
+
const rows = inventories.map((row) => {
|
|
1444
|
+
const totals = inventoryTotalsFromSynced(row);
|
|
1445
|
+
const localHost = local ? inventoryHostName(local) : "";
|
|
1446
|
+
const sameHost = localHost && row.hostName === localHost;
|
|
1447
|
+
return {
|
|
1448
|
+
row,
|
|
1449
|
+
totals,
|
|
1450
|
+
marker: sameHost ? "*" : " ",
|
|
1451
|
+
};
|
|
1452
|
+
});
|
|
1453
|
+
console.log(` ${DIM("synced machines")} ${chalk_1.default.cyan(String(inventories.length))}${DIM(` · limit ${limit}`)}`);
|
|
1454
|
+
console.log("");
|
|
1455
|
+
console.log(` ${DIM(" host".padEnd(26))}` +
|
|
1456
|
+
`${DIM("updated".padEnd(22))}` +
|
|
1457
|
+
`${DIM("skills".padStart(8))}` +
|
|
1458
|
+
`${DIM(" files".padStart(8))}` +
|
|
1459
|
+
`${DIM(" gaps".padStart(8))}` +
|
|
1460
|
+
`${DIM(" dry".padStart(7))}` +
|
|
1461
|
+
`${DIM(" Δskills".padStart(10))}`);
|
|
1462
|
+
for (const { row, totals, marker } of rows) {
|
|
1463
|
+
const host = `${marker} ${row.hostName}`.slice(0, 25).padEnd(26);
|
|
1464
|
+
const updated = compactDate(row.updatedAt).slice(0, 21).padEnd(22);
|
|
1465
|
+
console.log(` ${chalk_1.default.cyan(host)}` +
|
|
1466
|
+
`${DIM(updated)}` +
|
|
1467
|
+
`${String(totals.uniqueSkillNames ?? "?").padStart(8)}` +
|
|
1468
|
+
`${String(totals.uniqueRealSkillFiles ?? "?").padStart(8)}` +
|
|
1469
|
+
`${String(totals.missingFromYoumdCatalog ?? "?").padStart(8)}` +
|
|
1470
|
+
`${String(totals.duplicateNameDifferentRealpaths ?? "?").padStart(7)}` +
|
|
1471
|
+
`${inventoryDelta(localTotals.uniqueSkillNames, totals.uniqueSkillNames).padStart(10)}`);
|
|
1472
|
+
if (row.rootDir)
|
|
1473
|
+
console.log(` ${DIM(" root")} ${DIM(row.rootDir)}`);
|
|
1474
|
+
}
|
|
1475
|
+
console.log("");
|
|
1476
|
+
console.log(DIM(" * matches this machine's local latest host name"));
|
|
1477
|
+
}
|
|
1478
|
+
renderInventoryDrift(drift);
|
|
1479
|
+
console.log("");
|
|
1480
|
+
console.log(DIM(" refresh: ") + chalk_1.default.cyan(`you skill inventory --out-dir ${outDir} --register-catalog --sync`));
|
|
1481
|
+
console.log(DIM(" verify: ") + chalk_1.default.cyan("you machine verify --write-report --sync-report"));
|
|
1482
|
+
console.log(DIM(" exact diff needs two local JSON files: ") + chalk_1.default.cyan("you skill inventory diff macbook.json mac-mini.json"));
|
|
1483
|
+
console.log("");
|
|
1484
|
+
}
|
|
1485
|
+
async function inventoryCmd(args) {
|
|
1486
|
+
if (args[0] === "diff") {
|
|
1487
|
+
inventoryDiffCmd(args.slice(1));
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
if (args[0] === "status" || args[0] === "remote" || args[0] === "machines") {
|
|
1491
|
+
await inventoryStatusCmd(args.slice(1));
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
const { flags } = parseFlagArgs(args);
|
|
1495
|
+
const script = resolveInventoryScript();
|
|
1496
|
+
if (!script) {
|
|
1497
|
+
console.log("");
|
|
1498
|
+
console.log(chalk_1.default.yellow(" agent-stack-inventory script not found on this machine."));
|
|
1499
|
+
console.log(DIM(" expected one of:"));
|
|
1500
|
+
console.log(DIM(" ~/.agent-shared/claude-skills/agent-stack-inventory/scripts/local-agent-stack-inventory.mjs"));
|
|
1501
|
+
console.log(DIM(" ~/.you/skills/agent-stack-inventory/scripts/local-agent-stack-inventory.mjs"));
|
|
1502
|
+
console.log(DIM(" ~/.youmd/skills/agent-stack-inventory/scripts/local-agent-stack-inventory.mjs (legacy)"));
|
|
1503
|
+
console.log("");
|
|
1504
|
+
console.log(DIM(" run ") + chalk_1.default.cyan("you skill install agent-stack-inventory") + DIM(" or sync your shared skills, then retry."));
|
|
1505
|
+
console.log("");
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
const outDir = path.resolve(flagString(flags, "out-dir") || process.cwd());
|
|
1509
|
+
const workspace = flagString(flags, "workspace");
|
|
1510
|
+
const date = flagString(flags, "date");
|
|
1511
|
+
const shouldSync = flags.sync === true;
|
|
1512
|
+
const shouldSyncRepo = flags["no-repo-sync"] !== true;
|
|
1513
|
+
const shouldRegisterCatalog = flags["register-catalog"] === true;
|
|
1514
|
+
const startedAt = Date.now();
|
|
1515
|
+
const scriptArgs = [script, "--out-dir", outDir, "--progress"];
|
|
1516
|
+
if (workspace)
|
|
1517
|
+
scriptArgs.push("--workspace", path.resolve(workspace));
|
|
1518
|
+
if (date)
|
|
1519
|
+
scriptArgs.push("--date", date);
|
|
1520
|
+
console.log("");
|
|
1521
|
+
const spinner = new render_1.BrailleSpinner("mapping the local skill mesh");
|
|
1522
|
+
spinner.start();
|
|
1523
|
+
let output = "";
|
|
1524
|
+
try {
|
|
1525
|
+
output = await runInventoryScript(scriptArgs, spinner);
|
|
1526
|
+
}
|
|
1527
|
+
catch (err) {
|
|
1528
|
+
spinner.fail("inventory failed");
|
|
1529
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1530
|
+
console.log(DIM(` ${message}`));
|
|
1531
|
+
console.log("");
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const latest = findLatestInventoryJson(outDir, startedAt);
|
|
1535
|
+
const parsed = latest ? readInventorySnapshot(latest) : null;
|
|
1536
|
+
spinner.stop("inventory generated");
|
|
1537
|
+
console.log("");
|
|
1538
|
+
if (parsed?.totals) {
|
|
1539
|
+
renderInventoryTotals(parsed.totals);
|
|
1540
|
+
renderInventoryPhaseTimings(parsed);
|
|
1541
|
+
console.log("");
|
|
1542
|
+
}
|
|
1543
|
+
if (shouldRegisterCatalog && parsed) {
|
|
1544
|
+
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
1545
|
+
const result = (0, skill_catalog_1.addInventorySkillsToCatalog)(catalog, inventoryCatalogRows(parsed));
|
|
1546
|
+
const label = result.added > 0 ? chalk_1.default.green(`${result.added} added`) : DIM("no new entries");
|
|
1547
|
+
console.log(` ${DIM("catalog")} ${label}${result.skipped ? DIM(` · ${result.skipped} already known/skipped`) : ""}`);
|
|
1548
|
+
if (result.skills.length > 0) {
|
|
1549
|
+
console.log(` ${DIM("catalog samples")} ${result.skills.slice(0, 8).map((name) => chalk_1.default.cyan(name)).join(DIM(", "))}`);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
let htmlPath = latest ? latest.replace(/\.json$/, ".html") : undefined;
|
|
1553
|
+
let jsonPath = latest || undefined;
|
|
1554
|
+
try {
|
|
1555
|
+
const scriptResult = JSON.parse(output);
|
|
1556
|
+
htmlPath = scriptResult.html || htmlPath;
|
|
1557
|
+
jsonPath = scriptResult.json || jsonPath;
|
|
1558
|
+
if (scriptResult.html)
|
|
1559
|
+
console.log(` ${DIM("html")} ${chalk_1.default.cyan(scriptResult.html)}`);
|
|
1560
|
+
if (scriptResult.json)
|
|
1561
|
+
console.log(` ${DIM("json")} ${chalk_1.default.cyan(scriptResult.json)}`);
|
|
1562
|
+
}
|
|
1563
|
+
catch {
|
|
1564
|
+
if (latest) {
|
|
1565
|
+
console.log(` ${DIM("json")} ${chalk_1.default.cyan(latest)}`);
|
|
1566
|
+
console.log(` ${DIM("html")} ${chalk_1.default.cyan(latest.replace(/\.json$/, ".html"))}`);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
if (shouldSync && parsed) {
|
|
1570
|
+
if (!(0, config_1.isAuthenticated)()) {
|
|
1571
|
+
console.log(DIM(" sync skipped: run `you login` or set YOU_API_KEY to persist this machine inventory."));
|
|
1572
|
+
}
|
|
1573
|
+
else {
|
|
1574
|
+
try {
|
|
1575
|
+
const res = await (0, api_1.syncAgentStackInventory)(buildAgentStackInventorySyncPayload(parsed, jsonPath, htmlPath, shouldSyncRepo));
|
|
1576
|
+
if (res.ok && res.data?.success) {
|
|
1577
|
+
const action = res.data.created ? "created" : "updated";
|
|
1578
|
+
console.log(` ${DIM("sync")} ${chalk_1.default.green(action)} You.md agent stack inventory`);
|
|
1579
|
+
if (res.data.repoSync?.attempted) {
|
|
1580
|
+
const label = res.data.repoSync.ok ? chalk_1.default.green("synced repo snapshot") : ACCENT("repo snapshot skipped");
|
|
1581
|
+
console.log(` ${DIM("repo")} ${label}${res.data.repoSync.error ? DIM(`: ${res.data.repoSync.error}`) : ""}`);
|
|
1582
|
+
}
|
|
1583
|
+
else if (!shouldSyncRepo) {
|
|
1584
|
+
console.log(` ${DIM("repo")} ${DIM("snapshot sync disabled by --no-repo-sync")}`);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
else {
|
|
1588
|
+
console.log(` ${DIM("sync skipped:")} ${(0, api_1.apiErrorMessage)(res.data) || `HTTP ${res.status}`}`);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
catch (err) {
|
|
1592
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1593
|
+
console.log(` ${DIM("sync skipped:")} ${message}`);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
console.log("");
|
|
910
1598
|
}
|
|
911
1599
|
function searchCmd(args) {
|
|
912
1600
|
const query = args.join(" ");
|
|
913
1601
|
if (!query) {
|
|
914
1602
|
console.log("");
|
|
915
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
1603
|
+
console.log(chalk_1.default.yellow(" usage: you skill search <query>"));
|
|
916
1604
|
console.log("");
|
|
917
1605
|
return;
|
|
918
1606
|
}
|
|
@@ -935,7 +1623,7 @@ function searchCmd(args) {
|
|
|
935
1623
|
async function browseCmd() {
|
|
936
1624
|
if (!(0, config_1.isAuthenticated)()) {
|
|
937
1625
|
console.log("");
|
|
938
|
-
console.log(chalk_1.default.yellow(" not authenticated. run:
|
|
1626
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: you login"));
|
|
939
1627
|
console.log("");
|
|
940
1628
|
return;
|
|
941
1629
|
}
|
|
@@ -953,7 +1641,7 @@ async function browseCmd() {
|
|
|
953
1641
|
spinner.stop(`${skills.length} skill${skills.length === 1 ? "" : "s"} in registry`);
|
|
954
1642
|
if (skills.length === 0) {
|
|
955
1643
|
console.log(DIM(" no skills published yet."));
|
|
956
|
-
console.log(DIM(" be the first: ") + chalk_1.default.cyan("
|
|
1644
|
+
console.log(DIM(" be the first: ") + chalk_1.default.cyan("you skill publish <name>"));
|
|
957
1645
|
console.log("");
|
|
958
1646
|
return;
|
|
959
1647
|
}
|
|
@@ -966,7 +1654,7 @@ async function browseCmd() {
|
|
|
966
1654
|
console.log(` ${DIM("v" + s.version)} ${DIM(s.scope)} ${DIM(`[${s.identityFields.join(", ")}]`)}`);
|
|
967
1655
|
}
|
|
968
1656
|
console.log("");
|
|
969
|
-
console.log(DIM(` install with:
|
|
1657
|
+
console.log(DIM(` install with: you skill install <name>`));
|
|
970
1658
|
}
|
|
971
1659
|
catch {
|
|
972
1660
|
spinner.fail("registry unreachable");
|
|
@@ -977,14 +1665,14 @@ async function publishSkillCmd(args) {
|
|
|
977
1665
|
const name = args[0];
|
|
978
1666
|
if (!name) {
|
|
979
1667
|
console.log("");
|
|
980
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
1668
|
+
console.log(chalk_1.default.yellow(" usage: you skill publish <name>"));
|
|
981
1669
|
console.log(DIM(" publishes an installed skill to the you.md registry."));
|
|
982
1670
|
console.log("");
|
|
983
1671
|
return;
|
|
984
1672
|
}
|
|
985
1673
|
if (!(0, config_1.isAuthenticated)()) {
|
|
986
1674
|
console.log("");
|
|
987
|
-
console.log(chalk_1.default.yellow(" not authenticated. run:
|
|
1675
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: you login"));
|
|
988
1676
|
console.log("");
|
|
989
1677
|
return;
|
|
990
1678
|
}
|
|
@@ -1019,7 +1707,7 @@ async function publishSkillCmd(args) {
|
|
|
1019
1707
|
spinner.stop(res.data.updated ? "updated" : "published");
|
|
1020
1708
|
console.log("");
|
|
1021
1709
|
console.log(chalk_1.default.green(" \u2713") + ` ${chalk_1.default.bold(entry.name)} is live on the registry`);
|
|
1022
|
-
console.log(DIM(` others can install with:
|
|
1710
|
+
console.log(DIM(` others can install with: you skill install ${entry.name}`));
|
|
1023
1711
|
}
|
|
1024
1712
|
else {
|
|
1025
1713
|
spinner.fail((0, api_1.apiErrorMessage)(res.data) || "publish failed");
|
|
@@ -1033,7 +1721,7 @@ async function publishSkillCmd(args) {
|
|
|
1033
1721
|
async function remoteStatusCmd() {
|
|
1034
1722
|
if (!(0, config_1.isAuthenticated)()) {
|
|
1035
1723
|
console.log("");
|
|
1036
|
-
console.log(chalk_1.default.yellow(" not authenticated. run:
|
|
1724
|
+
console.log(chalk_1.default.yellow(" not authenticated. run: you login"));
|
|
1037
1725
|
console.log("");
|
|
1038
1726
|
return;
|
|
1039
1727
|
}
|
|
@@ -1070,7 +1758,7 @@ function infoCmd(args) {
|
|
|
1070
1758
|
const name = args[0];
|
|
1071
1759
|
if (!name) {
|
|
1072
1760
|
console.log("");
|
|
1073
|
-
console.log(chalk_1.default.yellow(" usage:
|
|
1761
|
+
console.log(chalk_1.default.yellow(" usage: you skill info <name>"));
|
|
1074
1762
|
console.log("");
|
|
1075
1763
|
return;
|
|
1076
1764
|
}
|
|
@@ -1146,10 +1834,10 @@ function exportSkillsCmd(args) {
|
|
|
1146
1834
|
continue;
|
|
1147
1835
|
// Export the raw SKILL.md
|
|
1148
1836
|
const outPath = path.join(outputDir, `${entry.name}.md`);
|
|
1149
|
-
const raw = fs.readFileSync(
|
|
1837
|
+
const raw = fs.readFileSync((0, skills_2.getSkillDir)(entry.name), "utf-8");
|
|
1150
1838
|
fs.writeFileSync(outPath, raw);
|
|
1151
1839
|
// Also export the rendered version
|
|
1152
|
-
const renderedPath = path.join(
|
|
1840
|
+
const renderedPath = path.join((0, config_1.getSkillsDir)(), entry.name, "RENDERED.md");
|
|
1153
1841
|
if (fs.existsSync(renderedPath)) {
|
|
1154
1842
|
fs.writeFileSync(path.join(outputDir, `${entry.name}.rendered.md`), fs.readFileSync(renderedPath, "utf-8"));
|
|
1155
1843
|
}
|
|
@@ -1216,6 +1904,10 @@ async function skillCommand(subcommand, ...args) {
|
|
|
1216
1904
|
case "improve":
|
|
1217
1905
|
await improveCmd();
|
|
1218
1906
|
break;
|
|
1907
|
+
case "inventory":
|
|
1908
|
+
case "audit":
|
|
1909
|
+
await inventoryCmd(args);
|
|
1910
|
+
break;
|
|
1219
1911
|
case "metrics":
|
|
1220
1912
|
case "stats":
|
|
1221
1913
|
metricsCmd();
|
|
@@ -1245,7 +1937,7 @@ async function skillCommand(subcommand, ...args) {
|
|
|
1245
1937
|
const catalog = (0, skill_catalog_1.readSkillCatalog)();
|
|
1246
1938
|
const installed = catalog.skills.filter((s) => s.installed);
|
|
1247
1939
|
console.log("");
|
|
1248
|
-
console.log(" " + chalk_1.default.bold("
|
|
1940
|
+
console.log(" " + chalk_1.default.bold("you skill") + DIM(" — identity-aware agent skills"));
|
|
1249
1941
|
console.log("");
|
|
1250
1942
|
if (installed.length > 0) {
|
|
1251
1943
|
// Quick identity coverage
|
|
@@ -1283,6 +1975,11 @@ async function skillCommand(subcommand, ...args) {
|
|
|
1283
1975
|
console.log(` ${chalk_1.default.cyan("link <agent>".padEnd(28))} ${DIM("link to claude | cursor | codex")}`);
|
|
1284
1976
|
console.log(` ${chalk_1.default.cyan("init-project [--mode auto|additive|zero-touch|scaffold]".padEnd(28))} ${DIM("bootstrap AGENTS/CLAUDE + project-context/ + .you/ + links")}`);
|
|
1285
1977
|
console.log(` ${chalk_1.default.cyan("improve".padEnd(28))} ${DIM("review metrics, find gaps, propose changes")}`);
|
|
1978
|
+
console.log(` ${chalk_1.default.cyan("inventory [--out-dir dir]".padEnd(28))} ${DIM("map local/global skills, mirrors, catalog gaps, and DRY risks")}`);
|
|
1979
|
+
console.log(` ${chalk_1.default.cyan("inventory --sync".padEnd(28))} ${DIM("persist safe inventory metadata to Convex + repo snapshot")}`);
|
|
1980
|
+
console.log(` ${chalk_1.default.cyan("inventory --no-repo-sync".padEnd(28))} ${DIM("skip GitHub snapshot push when syncing inventory")}`);
|
|
1981
|
+
console.log(` ${chalk_1.default.cyan("inventory status".padEnd(28))} ${DIM("show synced machine inventory summaries and count drift")}`);
|
|
1982
|
+
console.log(` ${chalk_1.default.cyan("inventory diff <a> <b>".padEnd(28))} ${DIM("compare two machine inventory JSON snapshots")}`);
|
|
1286
1983
|
console.log(` ${chalk_1.default.cyan("metrics".padEnd(28))} ${DIM("usage stats and effectiveness scores")}`);
|
|
1287
1984
|
console.log(` ${chalk_1.default.cyan("search <query>".padEnd(28))} ${DIM("search skills by name or description")}`);
|
|
1288
1985
|
console.log(` ${chalk_1.default.cyan("browse".padEnd(28))} ${DIM("browse the public skill registry")}`);
|