@the-aico/cli 1.0.1 → 1.0.2

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/index.js CHANGED
@@ -95,8 +95,8 @@ function handleError(error, options = {}) {
95
95
  console.error(kleur.red("\u2716 Validation Error:"));
96
96
  console.error("");
97
97
  for (const issue of error.issues) {
98
- const path9 = issue.path.length > 0 ? issue.path.join(".") : "value";
99
- console.error(` ${kleur.yellow(path9)}: ${issue.message}`);
98
+ const path10 = issue.path.length > 0 ? issue.path.join(".") : "value";
99
+ console.error(` ${kleur.yellow(path10)}: ${issue.message}`);
100
100
  }
101
101
  console.error("");
102
102
  console.error(kleur.cyan(" Suggestion:"));
@@ -238,15 +238,15 @@ var DEFAULT_PLATFORMS = {
238
238
  skills: ".claude/skills",
239
239
  commands: ".claude/commands"
240
240
  },
241
- // Codex 平台配置:
242
- // - skills: 项目目录 .codex/skills/(Codex 原生支持项目级 skills
243
- // - commands (prompts): 全局 ~/.codex/prompts/(一次安装所有项目可用)
244
- // 调用方式:/prompts:aico.{employee}.{command}
245
- // 用户可在 aico.json 中覆盖路径
241
+ // Codex platform configuration:
242
+ // - skills: project directory .codex/skills/ (Codex natively supports project-level skills)
243
+ // - commands (prompts): global ~/.codex/prompts/ (install once, available for all projects)
244
+ // Invocation: /prompts:aico.{employee}.{command}
245
+ // Users can override paths in aico.json
246
246
  codex: {
247
247
  skills: ".codex/skills",
248
248
  commands: "~/.codex/prompts"
249
- // Codex custom prompts (全局)
249
+ // Codex custom prompts (global)
250
250
  }
251
251
  };
252
252
  function createDefaultConfig(defaultPlatform = "claude-code") {
@@ -1224,9 +1224,9 @@ var DependencyResolver = class {
1224
1224
  /**
1225
1225
  * Recursively fetch a skill and all its dependencies
1226
1226
  */
1227
- async fetchWithDependencies(skillName, visited = /* @__PURE__ */ new Set(), path9 = []) {
1228
- if (path9.includes(skillName)) {
1229
- const cycle = [...path9, skillName].join(" \u2192 ");
1227
+ async fetchWithDependencies(skillName, visited = /* @__PURE__ */ new Set(), path10 = []) {
1228
+ if (path10.includes(skillName)) {
1229
+ const cycle = [...path10, skillName].join(" \u2192 ");
1230
1230
  throw new AicoError(
1231
1231
  `Circular dependency detected: ${cycle}`,
1232
1232
  "CIRCULAR_DEPENDENCY",
@@ -1247,7 +1247,7 @@ var DependencyResolver = class {
1247
1247
  const depSkills = await this.fetchWithDependencies(
1248
1248
  dep,
1249
1249
  visited,
1250
- [...path9, skillName]
1250
+ [...path10, skillName]
1251
1251
  );
1252
1252
  allSkills.push(...depSkills);
1253
1253
  }
@@ -2129,14 +2129,370 @@ var list = new Command4().name("list").description("List available or installed
2129
2129
 
2130
2130
  // src/commands/build.ts
2131
2131
  import { Command as Command5 } from "commander";
2132
- import fs6 from "fs-extra";
2133
- import path7 from "path";
2132
+ import fs7 from "fs-extra";
2133
+ import path8 from "path";
2134
2134
  import glob from "fast-glob";
2135
2135
  import { z as z9 } from "zod";
2136
+
2137
+ // src/commands/build-schema.ts
2138
+ import fs6 from "fs-extra";
2139
+ import path7 from "path";
2140
+ var CONFIG_SCHEMA = {
2141
+ $schema: "http://json-schema.org/draft-07/schema#",
2142
+ $id: "https://the-aico.com/schema/config.json",
2143
+ title: "aico Configuration",
2144
+ description: "Configuration file schema for aico.json",
2145
+ type: "object",
2146
+ required: ["defaultPlatform", "platforms"],
2147
+ properties: {
2148
+ $schema: {
2149
+ type: "string",
2150
+ description: "JSON Schema reference"
2151
+ },
2152
+ language: {
2153
+ type: "string",
2154
+ description: "Default language for documentation",
2155
+ default: "en"
2156
+ },
2157
+ defaultPlatform: {
2158
+ type: "string",
2159
+ enum: ["claude-code", "codex"],
2160
+ description: "Default platform for installation"
2161
+ },
2162
+ platforms: {
2163
+ type: "object",
2164
+ description: "Platform-specific path configurations",
2165
+ additionalProperties: {
2166
+ type: "object",
2167
+ required: ["skills", "commands"],
2168
+ properties: {
2169
+ skills: {
2170
+ type: "string",
2171
+ description: "Path to skills directory"
2172
+ },
2173
+ commands: {
2174
+ type: "string",
2175
+ description: "Path to commands directory"
2176
+ }
2177
+ }
2178
+ }
2179
+ },
2180
+ employees: {
2181
+ type: "object",
2182
+ description: "Installed employees state",
2183
+ additionalProperties: {
2184
+ type: "object",
2185
+ required: ["platforms", "installedAt"],
2186
+ properties: {
2187
+ platforms: {
2188
+ type: "array",
2189
+ items: {
2190
+ type: "string",
2191
+ enum: ["claude-code", "codex"]
2192
+ },
2193
+ description: "Platforms this employee is installed on"
2194
+ },
2195
+ installedAt: {
2196
+ type: "string",
2197
+ format: "date-time",
2198
+ description: "Installation timestamp"
2199
+ },
2200
+ version: {
2201
+ type: "string",
2202
+ description: "Installed version"
2203
+ },
2204
+ skills: {
2205
+ type: "array",
2206
+ items: { type: "string" },
2207
+ description: "Installed skill names"
2208
+ },
2209
+ commands: {
2210
+ type: "array",
2211
+ items: { type: "string" },
2212
+ description: "Installed command names"
2213
+ }
2214
+ }
2215
+ }
2216
+ },
2217
+ skills: {
2218
+ type: "object",
2219
+ description: "Standalone installed skills",
2220
+ additionalProperties: {
2221
+ type: "object",
2222
+ required: ["version", "installedAt", "source", "platforms"],
2223
+ properties: {
2224
+ version: {
2225
+ type: "string",
2226
+ description: "Skill version"
2227
+ },
2228
+ installedAt: {
2229
+ type: "string",
2230
+ format: "date-time",
2231
+ description: "Installation timestamp"
2232
+ },
2233
+ source: {
2234
+ type: "string",
2235
+ enum: ["standalone", "employee"],
2236
+ description: "Installation source"
2237
+ },
2238
+ platforms: {
2239
+ type: "array",
2240
+ items: {
2241
+ type: "string",
2242
+ enum: ["claude-code", "codex"]
2243
+ }
2244
+ }
2245
+ }
2246
+ }
2247
+ },
2248
+ sharedSkills: {
2249
+ type: "object",
2250
+ description: "Shared skills with reference tracking",
2251
+ additionalProperties: {
2252
+ type: "object",
2253
+ required: ["version", "installedAt", "platforms", "usedBy"],
2254
+ properties: {
2255
+ version: {
2256
+ type: "string",
2257
+ description: "Skill version"
2258
+ },
2259
+ installedAt: {
2260
+ type: "string",
2261
+ format: "date-time",
2262
+ description: "Installation timestamp"
2263
+ },
2264
+ platforms: {
2265
+ type: "array",
2266
+ items: {
2267
+ type: "string",
2268
+ enum: ["claude-code", "codex"]
2269
+ }
2270
+ },
2271
+ usedBy: {
2272
+ type: "array",
2273
+ items: { type: "string" },
2274
+ description: "Employees that depend on this shared skill"
2275
+ }
2276
+ }
2277
+ }
2278
+ },
2279
+ registries: {
2280
+ type: "object",
2281
+ description: "Custom registry configurations",
2282
+ propertyNames: {
2283
+ pattern: "^@"
2284
+ },
2285
+ additionalProperties: {
2286
+ oneOf: [
2287
+ {
2288
+ type: "string",
2289
+ description: "Registry URL with {name} placeholder"
2290
+ },
2291
+ {
2292
+ type: "object",
2293
+ required: ["url"],
2294
+ properties: {
2295
+ url: {
2296
+ type: "string",
2297
+ description: "Registry URL with {name} placeholder"
2298
+ },
2299
+ headers: {
2300
+ type: "object",
2301
+ additionalProperties: { type: "string" },
2302
+ description: "Custom HTTP headers"
2303
+ }
2304
+ }
2305
+ }
2306
+ ]
2307
+ }
2308
+ }
2309
+ }
2310
+ };
2311
+ var EMPLOYEE_SCHEMA = {
2312
+ $schema: "http://json-schema.org/draft-07/schema#",
2313
+ $id: "https://the-aico.com/schema/employee.json",
2314
+ title: "aico Employee",
2315
+ description: "Employee definition schema for employee.json",
2316
+ type: "object",
2317
+ required: ["name", "role"],
2318
+ properties: {
2319
+ $schema: {
2320
+ type: "string",
2321
+ description: "JSON Schema reference"
2322
+ },
2323
+ name: {
2324
+ type: "string",
2325
+ pattern: "^[a-z0-9-]+$",
2326
+ description: "Employee name (hyphen-case)"
2327
+ },
2328
+ namespace: {
2329
+ type: "string",
2330
+ pattern: "^@[a-z0-9-]+$",
2331
+ description: "Registry namespace (@registry format)"
2332
+ },
2333
+ fullName: {
2334
+ type: "string",
2335
+ pattern: "^@[a-z0-9-]+/[a-z0-9-]+$",
2336
+ description: "Full name (@registry/employee format)"
2337
+ },
2338
+ role: {
2339
+ type: "string",
2340
+ minLength: 1,
2341
+ description: "Employee role title"
2342
+ },
2343
+ description: {
2344
+ type: "string",
2345
+ description: "Employee description"
2346
+ },
2347
+ version: {
2348
+ type: "string",
2349
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
2350
+ description: "Semantic version"
2351
+ },
2352
+ category: {
2353
+ type: "string",
2354
+ enum: ["pm", "frontend", "backend", "devops", "general"],
2355
+ description: "Employee category"
2356
+ },
2357
+ skills: {
2358
+ type: "array",
2359
+ description: "Employee skills",
2360
+ items: {
2361
+ oneOf: [
2362
+ {
2363
+ type: "string",
2364
+ description: "Skill fullName reference"
2365
+ },
2366
+ {
2367
+ type: "object",
2368
+ required: ["name", "files"],
2369
+ properties: {
2370
+ name: {
2371
+ type: "string",
2372
+ pattern: "^[a-z0-9-]+$",
2373
+ description: "Skill name (hyphen-case)"
2374
+ },
2375
+ files: {
2376
+ type: "array",
2377
+ minItems: 1,
2378
+ items: {
2379
+ $ref: "#/definitions/fileSource"
2380
+ }
2381
+ }
2382
+ }
2383
+ }
2384
+ ]
2385
+ }
2386
+ },
2387
+ commands: {
2388
+ type: "array",
2389
+ description: "Employee commands",
2390
+ items: {
2391
+ type: "object",
2392
+ required: ["name", "files"],
2393
+ properties: {
2394
+ name: {
2395
+ type: "string",
2396
+ pattern: "^[a-z0-9-]+$",
2397
+ description: "Command name (hyphen-case)"
2398
+ },
2399
+ files: {
2400
+ type: "array",
2401
+ minItems: 1,
2402
+ items: {
2403
+ $ref: "#/definitions/file"
2404
+ }
2405
+ }
2406
+ }
2407
+ }
2408
+ },
2409
+ docs: {
2410
+ type: "array",
2411
+ description: "Employee documentation",
2412
+ items: {
2413
+ type: "object",
2414
+ required: ["name", "files"],
2415
+ properties: {
2416
+ name: {
2417
+ type: "string",
2418
+ description: "Document name"
2419
+ },
2420
+ files: {
2421
+ type: "array",
2422
+ minItems: 1,
2423
+ items: {
2424
+ $ref: "#/definitions/file"
2425
+ }
2426
+ }
2427
+ }
2428
+ }
2429
+ },
2430
+ dependencies: {
2431
+ type: "array",
2432
+ description: "Shared skill dependencies",
2433
+ items: {
2434
+ type: "string",
2435
+ description: "Dependency reference (@registry/_shared/skill)"
2436
+ }
2437
+ }
2438
+ },
2439
+ definitions: {
2440
+ fileSource: {
2441
+ type: "object",
2442
+ required: ["path", "type"],
2443
+ properties: {
2444
+ path: {
2445
+ type: "string",
2446
+ minLength: 1,
2447
+ description: "Relative file path"
2448
+ },
2449
+ type: {
2450
+ type: "string",
2451
+ enum: ["skill", "command", "doc"],
2452
+ description: "File type"
2453
+ }
2454
+ }
2455
+ },
2456
+ file: {
2457
+ type: "object",
2458
+ required: ["path", "type"],
2459
+ properties: {
2460
+ path: {
2461
+ type: "string",
2462
+ minLength: 1,
2463
+ description: "Relative file path"
2464
+ },
2465
+ type: {
2466
+ type: "string",
2467
+ enum: ["skill", "command", "doc"],
2468
+ description: "File type"
2469
+ },
2470
+ content: {
2471
+ type: "string",
2472
+ description: "File content (populated at build time)"
2473
+ }
2474
+ }
2475
+ }
2476
+ }
2477
+ };
2478
+ async function buildSchemas(outputDir) {
2479
+ const schemaDir = path7.join(outputDir, "schema");
2480
+ await fs6.ensureDir(schemaDir);
2481
+ await fs6.writeJson(path7.join(schemaDir, "config.json"), CONFIG_SCHEMA, {
2482
+ spaces: 2
2483
+ });
2484
+ await fs6.writeJson(path7.join(schemaDir, "employee.json"), EMPLOYEE_SCHEMA, {
2485
+ spaces: 2
2486
+ });
2487
+ logger.success("Built JSON schemas to schema/");
2488
+ }
2489
+
2490
+ // src/commands/build.ts
2136
2491
  var buildOptionsSchema = z9.object({
2137
2492
  cwd: z9.string(),
2138
2493
  employeesDir: z9.string(),
2139
2494
  outputDir: z9.string(),
2495
+ schemaDir: z9.string().optional(),
2140
2496
  registry: z9.string(),
2141
2497
  version: z9.string()
2142
2498
  });
@@ -2151,8 +2507,8 @@ function inferCategory(employeeName) {
2151
2507
  return categoryMap[employeeName] ?? "general";
2152
2508
  }
2153
2509
  async function buildSharedSkills(employeesPath, outputPath, registry, version, skillsIndex) {
2154
- const sharedDir = path7.join(employeesPath, "_shared", "skills");
2155
- if (!await fs6.pathExists(sharedDir)) {
2510
+ const sharedDir = path8.join(employeesPath, "_shared", "skills");
2511
+ if (!await fs7.pathExists(sharedDir)) {
2156
2512
  return 0;
2157
2513
  }
2158
2514
  const skillDirs = await glob("*/SKILL.md", {
@@ -2163,10 +2519,10 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
2163
2519
  }
2164
2520
  const namespace = `${registry}/_shared`;
2165
2521
  for (const skillPath of skillDirs) {
2166
- const skillName = path7.dirname(skillPath);
2522
+ const skillName = path8.dirname(skillPath);
2167
2523
  const skillFullName = `${namespace}/${skillName}`;
2168
- const skillFilePath = path7.join(sharedDir, skillPath);
2169
- const content = await fs6.readFile(skillFilePath, "utf-8");
2524
+ const skillFilePath = path8.join(sharedDir, skillPath);
2525
+ const content = await fs7.readFile(skillFilePath, "utf-8");
2170
2526
  const frontmatter = parseSkillFrontmatter(content);
2171
2527
  if (!frontmatter) {
2172
2528
  logger.warn(`Shared skill ${skillName} missing frontmatter, skipping`);
@@ -2189,15 +2545,15 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
2189
2545
  }
2190
2546
  ]
2191
2547
  };
2192
- const skillOutputDir = path7.join(
2548
+ const skillOutputDir = path8.join(
2193
2549
  outputPath,
2194
2550
  "skills",
2195
2551
  registry.replace("@", ""),
2196
2552
  "_shared"
2197
2553
  );
2198
- await fs6.ensureDir(skillOutputDir);
2199
- await fs6.writeJson(
2200
- path7.join(skillOutputDir, `${skillName}.json`),
2554
+ await fs7.ensureDir(skillOutputDir);
2555
+ await fs7.writeJson(
2556
+ path8.join(skillOutputDir, `${skillName}.json`),
2201
2557
  fullSkill,
2202
2558
  { spaces: 2 }
2203
2559
  );
@@ -2214,11 +2570,12 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
2214
2570
  return skillDirs.length;
2215
2571
  }
2216
2572
  async function runBuild(options) {
2217
- const { cwd, employeesDir, outputDir, registry, version } = options;
2218
- const employeesPath = path7.resolve(cwd, employeesDir);
2219
- const outputPath = path7.resolve(cwd, outputDir);
2220
- if (await fs6.pathExists(outputPath)) {
2221
- await fs6.emptyDir(outputPath);
2573
+ const { cwd, employeesDir, outputDir, schemaDir, registry, version } = options;
2574
+ const employeesPath = path8.resolve(cwd, employeesDir);
2575
+ const outputPath = path8.resolve(cwd, outputDir);
2576
+ const schemaPath = schemaDir ? path8.resolve(cwd, schemaDir) : outputPath;
2577
+ if (await fs7.pathExists(outputPath)) {
2578
+ await fs7.emptyDir(outputPath);
2222
2579
  }
2223
2580
  const employeeFiles = await glob("*/employee.json", {
2224
2581
  cwd: employeesPath,
@@ -2230,19 +2587,17 @@ async function runBuild(options) {
2230
2587
  }
2231
2588
  const s = spinner(`Building ${employeeFiles.length} employee(s)...`).start();
2232
2589
  const skillsIndex = [];
2233
- const employeesIndex = [];
2234
2590
  const legacyIndex = [];
2235
2591
  for (const employeeFile of employeeFiles) {
2236
- const employeeName = path7.dirname(employeeFile);
2237
- const employeeDir = path7.join(employeesPath, employeeName);
2592
+ const employeeName = path8.dirname(employeeFile);
2593
+ const employeeDir = path8.join(employeesPath, employeeName);
2238
2594
  try {
2239
- const employeeJson = await fs6.readJson(
2240
- path7.join(employeeDir, "employee.json")
2595
+ const employeeJson = await fs7.readJson(
2596
+ path8.join(employeeDir, "employee.json")
2241
2597
  );
2242
2598
  const employeeSource = employeeSourceSchema.parse(employeeJson);
2243
2599
  const category = inferCategory(employeeName);
2244
2600
  const namespace = `${registry}/${employeeName}`;
2245
- const employeeFullName = `${registry}/${employeeName}`;
2246
2601
  const employee = {
2247
2602
  ...employeeSource,
2248
2603
  skills: employeeSource.skills.map((sk) => ({
@@ -2258,16 +2613,14 @@ async function runBuild(options) {
2258
2613
  files: d.files.map((f) => ({ ...f, content: "" }))
2259
2614
  }))
2260
2615
  };
2261
- const skillFullNames = [];
2262
2616
  for (const skill of employee.skills) {
2263
2617
  const skillFullName = `${namespace}/${skill.name}`;
2264
- skillFullNames.push(skillFullName);
2265
2618
  const skillFiles = [];
2266
2619
  let skillDescription = "";
2267
2620
  for (const file of skill.files) {
2268
- const filePath = path7.join(employeeDir, file.path);
2269
- if (await fs6.pathExists(filePath)) {
2270
- const content = await fs6.readFile(filePath, "utf-8");
2621
+ const filePath = path8.join(employeeDir, file.path);
2622
+ if (await fs7.pathExists(filePath)) {
2623
+ const content = await fs7.readFile(filePath, "utf-8");
2271
2624
  file.content = content;
2272
2625
  if (file.path.endsWith("SKILL.md")) {
2273
2626
  const frontmatter = parseSkillFrontmatter(content);
@@ -2276,7 +2629,7 @@ async function runBuild(options) {
2276
2629
  }
2277
2630
  }
2278
2631
  skillFiles.push({
2279
- path: path7.basename(file.path),
2632
+ path: path8.basename(file.path),
2280
2633
  type: file.type === "skill" ? "skill" : "reference",
2281
2634
  content
2282
2635
  });
@@ -2295,15 +2648,15 @@ async function runBuild(options) {
2295
2648
  dependencies: [],
2296
2649
  files: skillFiles
2297
2650
  };
2298
- const skillOutputDir = path7.join(
2651
+ const skillOutputDir = path8.join(
2299
2652
  outputPath,
2300
2653
  "skills",
2301
2654
  registry.replace("@", ""),
2302
2655
  employeeName
2303
2656
  );
2304
- await fs6.ensureDir(skillOutputDir);
2305
- await fs6.writeJson(
2306
- path7.join(skillOutputDir, `${skill.name}.json`),
2657
+ await fs7.ensureDir(skillOutputDir);
2658
+ await fs7.writeJson(
2659
+ path8.join(skillOutputDir, `${skill.name}.json`),
2307
2660
  fullSkill,
2308
2661
  { spaces: 2 }
2309
2662
  );
@@ -2319,9 +2672,9 @@ async function runBuild(options) {
2319
2672
  }
2320
2673
  for (const command of employee.commands) {
2321
2674
  for (const file of command.files) {
2322
- const filePath = path7.join(employeeDir, file.path);
2323
- if (await fs6.pathExists(filePath)) {
2324
- file.content = await fs6.readFile(filePath, "utf-8");
2675
+ const filePath = path8.join(employeeDir, file.path);
2676
+ if (await fs7.pathExists(filePath)) {
2677
+ file.content = await fs7.readFile(filePath, "utf-8");
2325
2678
  } else {
2326
2679
  throw new Error(`Command file not found: ${file.path}`);
2327
2680
  }
@@ -2329,48 +2682,17 @@ async function runBuild(options) {
2329
2682
  }
2330
2683
  for (const doc of employee.docs) {
2331
2684
  for (const file of doc.files) {
2332
- const filePath = path7.join(employeeDir, file.path);
2333
- if (await fs6.pathExists(filePath)) {
2334
- file.content = await fs6.readFile(filePath, "utf-8");
2685
+ const filePath = path8.join(employeeDir, file.path);
2686
+ if (await fs7.pathExists(filePath)) {
2687
+ file.content = await fs7.readFile(filePath, "utf-8");
2335
2688
  } else {
2336
2689
  throw new Error(`Doc file not found: ${file.path}`);
2337
2690
  }
2338
2691
  }
2339
2692
  }
2340
- const legacyOutputPath = path7.join(outputPath, `${employee.name}.json`);
2341
- await fs6.ensureDir(outputPath);
2342
- await fs6.writeJson(legacyOutputPath, employee, { spaces: 2 });
2343
- const employeeExtended = {
2344
- $schema: "https://the-aico.com/schema/employee.json",
2345
- name: employee.name,
2346
- namespace: registry,
2347
- fullName: employeeFullName,
2348
- role: employee.role,
2349
- description: employee.description,
2350
- version,
2351
- category,
2352
- skills: skillFullNames,
2353
- commands: employee.commands,
2354
- docs: employee.docs
2355
- };
2356
- const employeesOutputDir = path7.join(outputPath, "employees");
2357
- await fs6.ensureDir(employeesOutputDir);
2358
- await fs6.writeJson(
2359
- path7.join(employeesOutputDir, `${employee.name}.json`),
2360
- employeeExtended,
2361
- { spaces: 2 }
2362
- );
2363
- employeesIndex.push({
2364
- name: employee.name,
2365
- namespace: registry,
2366
- fullName: employeeFullName,
2367
- role: employee.role,
2368
- description: employee.description,
2369
- version,
2370
- skillCount: employee.skills.length,
2371
- commandCount: employee.commands.length,
2372
- category
2373
- });
2693
+ const legacyOutputPath = path8.join(outputPath, `${employee.name}.json`);
2694
+ await fs7.ensureDir(outputPath);
2695
+ await fs7.writeJson(legacyOutputPath, employee, { spaces: 2 });
2374
2696
  legacyIndex.push({
2375
2697
  name: employee.name,
2376
2698
  role: employee.role,
@@ -2393,38 +2715,41 @@ async function runBuild(options) {
2393
2715
  if (sharedSkillCount > 0) {
2394
2716
  s.text = `Built ${sharedSkillCount} shared skill(s)`;
2395
2717
  }
2396
- const skillsIndexPath = path7.join(outputPath, "skills", "index.json");
2397
- await fs6.ensureDir(path7.dirname(skillsIndexPath));
2398
- await fs6.writeJson(skillsIndexPath, skillsIndex, { spaces: 2 });
2399
- const employeesIndexPath = path7.join(outputPath, "employees", "index.json");
2400
- await fs6.ensureDir(path7.dirname(employeesIndexPath));
2401
- await fs6.writeJson(employeesIndexPath, employeesIndex, { spaces: 2 });
2402
- const legacyIndexPath = path7.join(outputPath, "index.json");
2403
- await fs6.writeJson(
2718
+ const skillsIndexPath = path8.join(outputPath, "skills", "index.json");
2719
+ await fs7.ensureDir(path8.dirname(skillsIndexPath));
2720
+ await fs7.writeJson(skillsIndexPath, skillsIndex, { spaces: 2 });
2721
+ const legacyIndexPath = path8.join(outputPath, "index.json");
2722
+ await fs7.writeJson(
2404
2723
  legacyIndexPath,
2405
2724
  { employees: legacyIndex },
2406
2725
  { spaces: 2 }
2407
2726
  );
2727
+ s.text = "Building JSON schemas...";
2728
+ await buildSchemas(schemaPath);
2408
2729
  s.succeed(`Built ${employeeFiles.length} employee(s) to ${outputDir}/`);
2409
2730
  logger.break();
2410
2731
  logger.success("Registry build complete!");
2411
2732
  logger.dim(` Skills: ${skillsIndex.length} (${sharedSkillCount} shared)`);
2412
- logger.dim(` Employees: ${employeesIndex.length}`);
2733
+ logger.dim(` Employees: ${legacyIndex.length}`);
2413
2734
  logger.break();
2414
- for (const emp of employeesIndex) {
2415
- logger.dim(` - ${emp.name}: ${emp.role} (${emp.skillCount} skills)`);
2735
+ for (const emp of legacyIndex) {
2736
+ logger.dim(` - ${emp.name}: ${emp.role}`);
2416
2737
  }
2417
2738
  }
2418
2739
  var build = new Command5().name("build").description("Build registry from employees directory").option(
2419
2740
  "-e, --employees-dir <dir>",
2420
2741
  "Employees source directory",
2421
2742
  "employees"
2422
- ).option("-o, --output-dir <dir>", "Output directory", "registry").option("-r, --registry <name>", "Registry namespace", "@the-aico").option("-v, --version <version>", "Version number", "1.0.0").option("-c, --cwd <cwd>", "Working directory", process.cwd()).action(async (opts) => {
2743
+ ).option("-o, --output-dir <dir>", "Output directory", "registry").option(
2744
+ "-s, --schema-dir <dir>",
2745
+ "Schema output directory (defaults to output-dir)"
2746
+ ).option("-r, --registry <name>", "Registry namespace", "@the-aico").option("-v, --version <version>", "Version number", "1.0.0").option("-c, --cwd <cwd>", "Working directory", process.cwd()).action(async (opts) => {
2423
2747
  try {
2424
2748
  const options = buildOptionsSchema.parse({
2425
2749
  cwd: opts.cwd,
2426
2750
  employeesDir: opts.employeesDir,
2427
2751
  outputDir: opts.outputDir,
2752
+ schemaDir: opts.schemaDir,
2428
2753
  registry: opts.registry,
2429
2754
  version: opts.version
2430
2755
  });
@@ -2435,8 +2760,8 @@ var build = new Command5().name("build").description("Build registry from employ
2435
2760
  });
2436
2761
 
2437
2762
  // src/commands/diff.ts
2438
- import fs7 from "fs-extra";
2439
- import path8 from "path";
2763
+ import fs8 from "fs-extra";
2764
+ import path9 from "path";
2440
2765
  import { Command as Command6 } from "commander";
2441
2766
  import { diffLines } from "diff";
2442
2767
  import { z as z10 } from "zod";
@@ -2449,10 +2774,10 @@ var diffOptionsSchema = z10.object({
2449
2774
  cwd: z10.string()
2450
2775
  });
2451
2776
  async function compareFile(localPath, registryContent) {
2452
- if (!await fs7.pathExists(localPath)) {
2777
+ if (!await fs8.pathExists(localPath)) {
2453
2778
  return null;
2454
2779
  }
2455
- const localContent = await fs7.readFile(localPath, "utf-8");
2780
+ const localContent = await fs8.readFile(localPath, "utf-8");
2456
2781
  const patch = diffLines(localContent, registryContent);
2457
2782
  const hasChanges = patch.some((part) => part.added || part.removed);
2458
2783
  return hasChanges ? patch : null;
@@ -2496,10 +2821,10 @@ async function diffEmployee(employeeName, cwd, config) {
2496
2821
  for (const skill of registryEmployee.skills) {
2497
2822
  const skillDirName = adapter.getSkillDirName(employeeName, skill.name);
2498
2823
  for (const file of skill.files) {
2499
- const localPath = path8.join(
2824
+ const localPath = path9.join(
2500
2825
  skillsDir,
2501
2826
  skillDirName,
2502
- path8.basename(file.path)
2827
+ path9.basename(file.path)
2503
2828
  );
2504
2829
  let registryContent = file.content;
2505
2830
  if (file.path.endsWith("SKILL.md")) {
@@ -2508,7 +2833,7 @@ async function diffEmployee(employeeName, cwd, config) {
2508
2833
  `$1${skillDirName}`
2509
2834
  );
2510
2835
  }
2511
- if (!await fs7.pathExists(localPath)) {
2836
+ if (!await fs8.pathExists(localPath)) {
2512
2837
  if (!skillsAdded.includes(skill.name)) {
2513
2838
  fileChanges.push({
2514
2839
  filePath: localPath,
@@ -2533,8 +2858,8 @@ async function diffEmployee(employeeName, cwd, config) {
2533
2858
  command.name
2534
2859
  );
2535
2860
  for (const file of command.files) {
2536
- const localPath = path8.join(commandsDir, commandFileName);
2537
- if (!await fs7.pathExists(localPath)) {
2861
+ const localPath = path9.join(commandsDir, commandFileName);
2862
+ if (!await fs8.pathExists(localPath)) {
2538
2863
  if (!commandsAdded.includes(command.name)) {
2539
2864
  fileChanges.push({
2540
2865
  filePath: localPath,
@@ -2555,8 +2880,8 @@ async function diffEmployee(employeeName, cwd, config) {
2555
2880
  }
2556
2881
  for (const skillName of skillsRemoved) {
2557
2882
  const skillDirName = adapter.getSkillDirName(employeeName, skillName);
2558
- const skillPath = path8.join(skillsDir, skillDirName);
2559
- if (await fs7.pathExists(skillPath)) {
2883
+ const skillPath = path9.join(skillsDir, skillDirName);
2884
+ if (await fs8.pathExists(skillPath)) {
2560
2885
  fileChanges.push({
2561
2886
  filePath: skillPath,
2562
2887
  type: "removed"
@@ -2568,8 +2893,8 @@ async function diffEmployee(employeeName, cwd, config) {
2568
2893
  employeeName,
2569
2894
  commandName
2570
2895
  );
2571
- const commandPath = path8.join(commandsDir, commandFileName);
2572
- if (await fs7.pathExists(commandPath)) {
2896
+ const commandPath = path9.join(commandsDir, commandFileName);
2897
+ if (await fs8.pathExists(commandPath)) {
2573
2898
  fileChanges.push({
2574
2899
  filePath: commandPath,
2575
2900
  type: "removed"
@@ -2641,7 +2966,7 @@ async function runDiff(options) {
2641
2966
  logger.warn(` Removed commands: ${diff2.commandsRemoved.join(", ")}`);
2642
2967
  }
2643
2968
  for (const change of diff2.fileChanges) {
2644
- const relativePath = path8.relative(cwd, change.filePath);
2969
+ const relativePath = path9.relative(cwd, change.filePath);
2645
2970
  if (change.type === "modified") {
2646
2971
  logger.info(` Modified: ${relativePath}`);
2647
2972
  if (change.patch) {