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.
Files changed (125) hide show
  1. package/dist/commands/add.js +1 -1
  2. package/dist/commands/add.js.map +1 -1
  3. package/dist/commands/agent.d.ts +4 -0
  4. package/dist/commands/agent.d.ts.map +1 -1
  5. package/dist/commands/agent.js +4 -0
  6. package/dist/commands/agent.js.map +1 -1
  7. package/dist/commands/build.js +2 -2
  8. package/dist/commands/build.js.map +1 -1
  9. package/dist/commands/chat.js +1 -1
  10. package/dist/commands/chat.js.map +1 -1
  11. package/dist/commands/env.d.ts.map +1 -1
  12. package/dist/commands/env.js +11 -10
  13. package/dist/commands/env.js.map +1 -1
  14. package/dist/commands/init.js +5 -5
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/keys.js +8 -1
  17. package/dist/commands/keys.js.map +1 -1
  18. package/dist/commands/login.js +2 -2
  19. package/dist/commands/login.js.map +1 -1
  20. package/dist/commands/machine.d.ts.map +1 -1
  21. package/dist/commands/machine.js +331 -8
  22. package/dist/commands/machine.js.map +1 -1
  23. package/dist/commands/mcp.js +4 -4
  24. package/dist/commands/mcp.js.map +1 -1
  25. package/dist/commands/private.js +2 -2
  26. package/dist/commands/private.js.map +1 -1
  27. package/dist/commands/project.d.ts.map +1 -1
  28. package/dist/commands/project.js +31 -0
  29. package/dist/commands/project.js.map +1 -1
  30. package/dist/commands/publish.js +1 -1
  31. package/dist/commands/publish.js.map +1 -1
  32. package/dist/commands/pull.js +1 -1
  33. package/dist/commands/pull.js.map +1 -1
  34. package/dist/commands/push.js +1 -1
  35. package/dist/commands/push.js.map +1 -1
  36. package/dist/commands/skill.d.ts +1 -1
  37. package/dist/commands/skill.d.ts.map +1 -1
  38. package/dist/commands/skill.js +736 -39
  39. package/dist/commands/skill.js.map +1 -1
  40. package/dist/commands/stack.d.ts.map +1 -1
  41. package/dist/commands/stack.js +127 -26
  42. package/dist/commands/stack.js.map +1 -1
  43. package/dist/commands/status.js +1 -1
  44. package/dist/commands/status.js.map +1 -1
  45. package/dist/commands/sync.d.ts.map +1 -1
  46. package/dist/commands/sync.js +84 -3
  47. package/dist/commands/sync.js.map +1 -1
  48. package/dist/commands/whoami.js +3 -3
  49. package/dist/commands/whoami.js.map +1 -1
  50. package/dist/create.js +0 -0
  51. package/dist/index.js +40 -30
  52. package/dist/index.js.map +1 -1
  53. package/dist/lib/api.d.ts +190 -0
  54. package/dist/lib/api.d.ts.map +1 -1
  55. package/dist/lib/api.js +44 -6
  56. package/dist/lib/api.js.map +1 -1
  57. package/dist/lib/config.d.ts +20 -12
  58. package/dist/lib/config.d.ts.map +1 -1
  59. package/dist/lib/config.js +113 -42
  60. package/dist/lib/config.js.map +1 -1
  61. package/dist/lib/daemon.d.ts +2 -0
  62. package/dist/lib/daemon.d.ts.map +1 -1
  63. package/dist/lib/daemon.js +28 -19
  64. package/dist/lib/daemon.js.map +1 -1
  65. package/dist/lib/machine-bootstrap-prompt.d.ts.map +1 -1
  66. package/dist/lib/machine-bootstrap-prompt.js +147 -118
  67. package/dist/lib/machine-bootstrap-prompt.js.map +1 -1
  68. package/dist/lib/machine-verify.d.ts +51 -0
  69. package/dist/lib/machine-verify.d.ts.map +1 -1
  70. package/dist/lib/machine-verify.js +123 -1
  71. package/dist/lib/machine-verify.js.map +1 -1
  72. package/dist/lib/onboarding.d.ts.map +1 -1
  73. package/dist/lib/onboarding.js +3 -8
  74. package/dist/lib/onboarding.js.map +1 -1
  75. package/dist/lib/portfolio-audit.d.ts.map +1 -1
  76. package/dist/lib/portfolio-audit.js +2 -1
  77. package/dist/lib/portfolio-audit.js.map +1 -1
  78. package/dist/lib/project.d.ts +3 -3
  79. package/dist/lib/project.d.ts.map +1 -1
  80. package/dist/lib/project.js +18 -11
  81. package/dist/lib/project.js.map +1 -1
  82. package/dist/lib/projectContext.d.ts +10 -9
  83. package/dist/lib/projectContext.d.ts.map +1 -1
  84. package/dist/lib/projectContext.js +29 -23
  85. package/dist/lib/projectContext.js.map +1 -1
  86. package/dist/lib/realtime-sync.d.ts +26 -0
  87. package/dist/lib/realtime-sync.d.ts.map +1 -1
  88. package/dist/lib/realtime-sync.js +51 -7
  89. package/dist/lib/realtime-sync.js.map +1 -1
  90. package/dist/lib/render.js +1 -1
  91. package/dist/lib/render.js.map +1 -1
  92. package/dist/lib/skill-catalog.d.ts +26 -0
  93. package/dist/lib/skill-catalog.d.ts.map +1 -1
  94. package/dist/lib/skill-catalog.js +100 -0
  95. package/dist/lib/skill-catalog.js.map +1 -1
  96. package/dist/lib/vault.d.ts +3 -3
  97. package/dist/lib/vault.d.ts.map +1 -1
  98. package/dist/lib/vault.js +10 -8
  99. package/dist/lib/vault.js.map +1 -1
  100. package/dist/lib/youstack.js +12 -12
  101. package/dist/lib/youstack.js.map +1 -1
  102. package/dist/mcp/registry.d.ts +2 -1
  103. package/dist/mcp/registry.d.ts.map +1 -1
  104. package/dist/mcp/registry.js +135 -12
  105. package/dist/mcp/registry.js.map +1 -1
  106. package/dist/mcp/server.d.ts.map +1 -1
  107. package/dist/mcp/server.js +135 -7
  108. package/dist/mcp/server.js.map +1 -1
  109. package/dist/postinstall.js +3 -2
  110. package/dist/postinstall.js.map +1 -1
  111. package/dist/you.js +0 -0
  112. package/package.json +1 -1
  113. package/scripts/local-agent-stack-inventory.mjs +1188 -0
  114. package/scripts/skillstack-sync/README.md +33 -25
  115. package/scripts/skillstack-sync/bootstrap-new-mac.sh +1 -1
  116. package/scripts/skillstack-sync/capture-agent-config.sh +8 -1
  117. package/scripts/skillstack-sync/{com.youmd.context-sync.plist → com.you.context-sync.plist} +3 -3
  118. package/scripts/skillstack-sync/{com.youmd.identity-sync.plist → com.you.identity-sync.plist} +3 -3
  119. package/scripts/skillstack-sync/{com.youmd.realtime-sync.plist → com.you.realtime-sync.plist} +3 -3
  120. package/scripts/skillstack-sync/{com.youmd.skillstack-sync.plist → com.you.skillstack-sync.plist} +3 -3
  121. package/scripts/skillstack-sync/context-sync.sh +1 -1
  122. package/scripts/skillstack-sync/install-daemons.sh +20 -6
  123. package/scripts/skillstack-sync/restore-agent-config.sh +1 -1
  124. package/scripts/skillstack-sync/sync.sh +1 -1
  125. package/skills/machine-bootstrap.md +57 -55
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /**
3
- * youmd skill — identity-aware agent skill system.
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("youmd skills") + DIM(` (${catalog.skills.length} in catalog)`));
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("youmd skill add <name> <source>") + DIM(" to add one."));
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("youmd skill install youstack-start"));
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: youmd skill install <name>"));
210
- console.log(DIM(" or: youmd skill install all"));
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("youmd skill list") + DIM(" to see available skills."));
283
- console.log(DIM(" or: ") + chalk_1.default.cyan("youmd skill browse") + DIM(" to check the registry."));
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: youmd skill remove <name>"));
347
- console.log(DIM(" or: youmd skill remove all"));
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: youmd skill use <name>"));
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 .youmd/preferences/"));
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: youmd skill add <name> <source>"));
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(`youmd skill install ${name}`) + DIM(" to install."));
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("youmd skill create"));
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 ~/.youmd/skills/<name>/SKILL.md
518
- const skillDir = path.join(os.homedir(), ".youmd", "skills", slug);
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(`youmd skill use ${slug}`)} ${DIM("render with your identity")}`);
539
- console.log(` ${chalk_1.default.cyan(`youmd skill link claude`)} ${DIM("link to your project")}`);
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: youmd skill push <name>"));
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 = path.join(os.homedir(), ".youmd", "skills", entry.name, "SKILL.md");
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("youmd skill init-project"));
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 .youmd/preferences/"));
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 \"youmd skill sync\" — installed skills haven't been synced against your identity yet"
884
- : "run \"youmd skill sync\" — your identity changed after the last skill sync");
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 \"youmd skill link claude\" — skills aren't linked to this project's agent");
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: youmd skill search <query>"));
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: youmd login"));
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("youmd skill publish <name>"));
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: youmd skill install <name>`));
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: youmd skill publish <name>"));
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: youmd login"));
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: youmd skill install ${entry.name}`));
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: youmd login"));
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: youmd skill info <name>"));
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(path.join(os.homedir(), ".youmd", "skills", entry.name, "SKILL.md"), "utf-8");
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(os.homedir(), ".youmd", "skills", entry.name, "RENDERED.md");
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("youmd skill") + DIM(" — identity-aware agent skills"));
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")}`);