@the-aico/cli 1.0.0 → 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/README.md +43 -0
- package/dist/index.js +450 -131
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -16,12 +16,12 @@ var defaultSuggestions = {
|
|
|
16
16
|
REGISTRY_UNAVAILABLE: "The registry server is unavailable. Try again later.",
|
|
17
17
|
// Resource errors
|
|
18
18
|
NOT_FOUND: "The requested resource was not found.",
|
|
19
|
-
SKILL_NOT_FOUND: "Use `
|
|
20
|
-
EMPLOYEE_NOT_FOUND: "Use `
|
|
19
|
+
SKILL_NOT_FOUND: "Use `aico list --skills` to see available skills.",
|
|
20
|
+
EMPLOYEE_NOT_FOUND: "Use `aico list` to see available employees.",
|
|
21
21
|
// Configuration errors
|
|
22
|
-
NOT_INITIALIZED: "Run `
|
|
23
|
-
CONFIG_INVALID: "Check your aico.json for syntax errors or run `
|
|
24
|
-
CONFIG_EXISTS: "Use `
|
|
22
|
+
NOT_INITIALIZED: "Run `aico init` to initialize the project.",
|
|
23
|
+
CONFIG_INVALID: "Check your aico.json for syntax errors or run `aico init --force`.",
|
|
24
|
+
CONFIG_EXISTS: "Use `aico init --force` to overwrite existing config.",
|
|
25
25
|
CONFIG_PARSE_ERROR: "Your aico.json contains invalid JSON. Check for syntax errors.",
|
|
26
26
|
// Dependency errors
|
|
27
27
|
DEPENDENCY_MISSING: "Install the missing dependency first, or use `--no-deps` to skip.",
|
|
@@ -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
|
|
99
|
-
console.error(` ${kleur.yellow(
|
|
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:
|
|
243
|
-
// - commands (prompts):
|
|
244
|
-
//
|
|
245
|
-
//
|
|
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") {
|
|
@@ -512,10 +512,8 @@ async function runInit(options) {
|
|
|
512
512
|
logger.dim(`Default platform: ${platform}`);
|
|
513
513
|
logger.break();
|
|
514
514
|
logger.info("Next steps:");
|
|
515
|
-
logger.log(` ${logger.highlight("
|
|
516
|
-
logger.log(
|
|
517
|
-
` ${logger.highlight("npx aico list")} View available employees`
|
|
518
|
-
);
|
|
515
|
+
logger.log(` ${logger.highlight("aico add pm")} Add the PM employee`);
|
|
516
|
+
logger.log(` ${logger.highlight("aico list")} View available employees`);
|
|
519
517
|
}
|
|
520
518
|
var init = new Command().name("init").description("Initialize aico in your project").option(
|
|
521
519
|
"-p, --default-platform <platform>",
|
|
@@ -1226,9 +1224,9 @@ var DependencyResolver = class {
|
|
|
1226
1224
|
/**
|
|
1227
1225
|
* Recursively fetch a skill and all its dependencies
|
|
1228
1226
|
*/
|
|
1229
|
-
async fetchWithDependencies(skillName, visited = /* @__PURE__ */ new Set(),
|
|
1230
|
-
if (
|
|
1231
|
-
const cycle = [...
|
|
1227
|
+
async fetchWithDependencies(skillName, visited = /* @__PURE__ */ new Set(), path10 = []) {
|
|
1228
|
+
if (path10.includes(skillName)) {
|
|
1229
|
+
const cycle = [...path10, skillName].join(" \u2192 ");
|
|
1232
1230
|
throw new AicoError(
|
|
1233
1231
|
`Circular dependency detected: ${cycle}`,
|
|
1234
1232
|
"CIRCULAR_DEPENDENCY",
|
|
@@ -1249,7 +1247,7 @@ var DependencyResolver = class {
|
|
|
1249
1247
|
const depSkills = await this.fetchWithDependencies(
|
|
1250
1248
|
dep,
|
|
1251
1249
|
visited,
|
|
1252
|
-
[...
|
|
1250
|
+
[...path10, skillName]
|
|
1253
1251
|
);
|
|
1254
1252
|
allSkills.push(...depSkills);
|
|
1255
1253
|
}
|
|
@@ -2031,12 +2029,8 @@ var remove = new Command3().name("remove").description("Remove employees or skil
|
|
|
2031
2029
|
"Please specify at least one employee or skill to remove."
|
|
2032
2030
|
);
|
|
2033
2031
|
logger.dim("Examples:");
|
|
2034
|
-
logger.dim(
|
|
2035
|
-
|
|
2036
|
-
);
|
|
2037
|
-
logger.dim(
|
|
2038
|
-
" npx aico remove @the-aico/pm/brainstorming # Remove skill"
|
|
2039
|
-
);
|
|
2032
|
+
logger.dim(" aico remove pm # Remove employee");
|
|
2033
|
+
logger.dim(" aico remove @the-aico/pm/brainstorming # Remove skill");
|
|
2040
2034
|
process.exit(1);
|
|
2041
2035
|
}
|
|
2042
2036
|
const options = removeOptionsSchema.parse({
|
|
@@ -2070,7 +2064,7 @@ async function runList(options) {
|
|
|
2070
2064
|
const employees = Object.entries(config.employees);
|
|
2071
2065
|
if (employees.length === 0) {
|
|
2072
2066
|
logger.info("No employees installed.");
|
|
2073
|
-
logger.dim("Run `
|
|
2067
|
+
logger.dim("Run `aico add <employee>` to add an employee.");
|
|
2074
2068
|
return;
|
|
2075
2069
|
}
|
|
2076
2070
|
logger.bold("Installed employees:");
|
|
@@ -2101,8 +2095,8 @@ async function runList(options) {
|
|
|
2101
2095
|
);
|
|
2102
2096
|
}
|
|
2103
2097
|
logger.break();
|
|
2104
|
-
logger.dim("Use `
|
|
2105
|
-
logger.dim("Use `
|
|
2098
|
+
logger.dim("Use `aico add <employee>` to add an employee.");
|
|
2099
|
+
logger.dim("Use `aico list --installed` to see installed employees.");
|
|
2106
2100
|
} catch {
|
|
2107
2101
|
logger.warn(
|
|
2108
2102
|
"Could not fetch registry. Showing installed employees only."
|
|
@@ -2135,14 +2129,370 @@ var list = new Command4().name("list").description("List available or installed
|
|
|
2135
2129
|
|
|
2136
2130
|
// src/commands/build.ts
|
|
2137
2131
|
import { Command as Command5 } from "commander";
|
|
2138
|
-
import
|
|
2139
|
-
import
|
|
2132
|
+
import fs7 from "fs-extra";
|
|
2133
|
+
import path8 from "path";
|
|
2140
2134
|
import glob from "fast-glob";
|
|
2141
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
|
|
2142
2491
|
var buildOptionsSchema = z9.object({
|
|
2143
2492
|
cwd: z9.string(),
|
|
2144
2493
|
employeesDir: z9.string(),
|
|
2145
2494
|
outputDir: z9.string(),
|
|
2495
|
+
schemaDir: z9.string().optional(),
|
|
2146
2496
|
registry: z9.string(),
|
|
2147
2497
|
version: z9.string()
|
|
2148
2498
|
});
|
|
@@ -2157,8 +2507,8 @@ function inferCategory(employeeName) {
|
|
|
2157
2507
|
return categoryMap[employeeName] ?? "general";
|
|
2158
2508
|
}
|
|
2159
2509
|
async function buildSharedSkills(employeesPath, outputPath, registry, version, skillsIndex) {
|
|
2160
|
-
const sharedDir =
|
|
2161
|
-
if (!await
|
|
2510
|
+
const sharedDir = path8.join(employeesPath, "_shared", "skills");
|
|
2511
|
+
if (!await fs7.pathExists(sharedDir)) {
|
|
2162
2512
|
return 0;
|
|
2163
2513
|
}
|
|
2164
2514
|
const skillDirs = await glob("*/SKILL.md", {
|
|
@@ -2169,10 +2519,10 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
|
|
|
2169
2519
|
}
|
|
2170
2520
|
const namespace = `${registry}/_shared`;
|
|
2171
2521
|
for (const skillPath of skillDirs) {
|
|
2172
|
-
const skillName =
|
|
2522
|
+
const skillName = path8.dirname(skillPath);
|
|
2173
2523
|
const skillFullName = `${namespace}/${skillName}`;
|
|
2174
|
-
const skillFilePath =
|
|
2175
|
-
const content = await
|
|
2524
|
+
const skillFilePath = path8.join(sharedDir, skillPath);
|
|
2525
|
+
const content = await fs7.readFile(skillFilePath, "utf-8");
|
|
2176
2526
|
const frontmatter = parseSkillFrontmatter(content);
|
|
2177
2527
|
if (!frontmatter) {
|
|
2178
2528
|
logger.warn(`Shared skill ${skillName} missing frontmatter, skipping`);
|
|
@@ -2195,15 +2545,15 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
|
|
|
2195
2545
|
}
|
|
2196
2546
|
]
|
|
2197
2547
|
};
|
|
2198
|
-
const skillOutputDir =
|
|
2548
|
+
const skillOutputDir = path8.join(
|
|
2199
2549
|
outputPath,
|
|
2200
2550
|
"skills",
|
|
2201
2551
|
registry.replace("@", ""),
|
|
2202
2552
|
"_shared"
|
|
2203
2553
|
);
|
|
2204
|
-
await
|
|
2205
|
-
await
|
|
2206
|
-
|
|
2554
|
+
await fs7.ensureDir(skillOutputDir);
|
|
2555
|
+
await fs7.writeJson(
|
|
2556
|
+
path8.join(skillOutputDir, `${skillName}.json`),
|
|
2207
2557
|
fullSkill,
|
|
2208
2558
|
{ spaces: 2 }
|
|
2209
2559
|
);
|
|
@@ -2220,11 +2570,12 @@ async function buildSharedSkills(employeesPath, outputPath, registry, version, s
|
|
|
2220
2570
|
return skillDirs.length;
|
|
2221
2571
|
}
|
|
2222
2572
|
async function runBuild(options) {
|
|
2223
|
-
const { cwd, employeesDir, outputDir, registry, version } = options;
|
|
2224
|
-
const employeesPath =
|
|
2225
|
-
const outputPath =
|
|
2226
|
-
|
|
2227
|
-
|
|
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);
|
|
2228
2579
|
}
|
|
2229
2580
|
const employeeFiles = await glob("*/employee.json", {
|
|
2230
2581
|
cwd: employeesPath,
|
|
@@ -2236,19 +2587,17 @@ async function runBuild(options) {
|
|
|
2236
2587
|
}
|
|
2237
2588
|
const s = spinner(`Building ${employeeFiles.length} employee(s)...`).start();
|
|
2238
2589
|
const skillsIndex = [];
|
|
2239
|
-
const employeesIndex = [];
|
|
2240
2590
|
const legacyIndex = [];
|
|
2241
2591
|
for (const employeeFile of employeeFiles) {
|
|
2242
|
-
const employeeName =
|
|
2243
|
-
const employeeDir =
|
|
2592
|
+
const employeeName = path8.dirname(employeeFile);
|
|
2593
|
+
const employeeDir = path8.join(employeesPath, employeeName);
|
|
2244
2594
|
try {
|
|
2245
|
-
const employeeJson = await
|
|
2246
|
-
|
|
2595
|
+
const employeeJson = await fs7.readJson(
|
|
2596
|
+
path8.join(employeeDir, "employee.json")
|
|
2247
2597
|
);
|
|
2248
2598
|
const employeeSource = employeeSourceSchema.parse(employeeJson);
|
|
2249
2599
|
const category = inferCategory(employeeName);
|
|
2250
2600
|
const namespace = `${registry}/${employeeName}`;
|
|
2251
|
-
const employeeFullName = `${registry}/${employeeName}`;
|
|
2252
2601
|
const employee = {
|
|
2253
2602
|
...employeeSource,
|
|
2254
2603
|
skills: employeeSource.skills.map((sk) => ({
|
|
@@ -2264,16 +2613,14 @@ async function runBuild(options) {
|
|
|
2264
2613
|
files: d.files.map((f) => ({ ...f, content: "" }))
|
|
2265
2614
|
}))
|
|
2266
2615
|
};
|
|
2267
|
-
const skillFullNames = [];
|
|
2268
2616
|
for (const skill of employee.skills) {
|
|
2269
2617
|
const skillFullName = `${namespace}/${skill.name}`;
|
|
2270
|
-
skillFullNames.push(skillFullName);
|
|
2271
2618
|
const skillFiles = [];
|
|
2272
2619
|
let skillDescription = "";
|
|
2273
2620
|
for (const file of skill.files) {
|
|
2274
|
-
const filePath =
|
|
2275
|
-
if (await
|
|
2276
|
-
const content = await
|
|
2621
|
+
const filePath = path8.join(employeeDir, file.path);
|
|
2622
|
+
if (await fs7.pathExists(filePath)) {
|
|
2623
|
+
const content = await fs7.readFile(filePath, "utf-8");
|
|
2277
2624
|
file.content = content;
|
|
2278
2625
|
if (file.path.endsWith("SKILL.md")) {
|
|
2279
2626
|
const frontmatter = parseSkillFrontmatter(content);
|
|
@@ -2282,7 +2629,7 @@ async function runBuild(options) {
|
|
|
2282
2629
|
}
|
|
2283
2630
|
}
|
|
2284
2631
|
skillFiles.push({
|
|
2285
|
-
path:
|
|
2632
|
+
path: path8.basename(file.path),
|
|
2286
2633
|
type: file.type === "skill" ? "skill" : "reference",
|
|
2287
2634
|
content
|
|
2288
2635
|
});
|
|
@@ -2301,15 +2648,15 @@ async function runBuild(options) {
|
|
|
2301
2648
|
dependencies: [],
|
|
2302
2649
|
files: skillFiles
|
|
2303
2650
|
};
|
|
2304
|
-
const skillOutputDir =
|
|
2651
|
+
const skillOutputDir = path8.join(
|
|
2305
2652
|
outputPath,
|
|
2306
2653
|
"skills",
|
|
2307
2654
|
registry.replace("@", ""),
|
|
2308
2655
|
employeeName
|
|
2309
2656
|
);
|
|
2310
|
-
await
|
|
2311
|
-
await
|
|
2312
|
-
|
|
2657
|
+
await fs7.ensureDir(skillOutputDir);
|
|
2658
|
+
await fs7.writeJson(
|
|
2659
|
+
path8.join(skillOutputDir, `${skill.name}.json`),
|
|
2313
2660
|
fullSkill,
|
|
2314
2661
|
{ spaces: 2 }
|
|
2315
2662
|
);
|
|
@@ -2325,9 +2672,9 @@ async function runBuild(options) {
|
|
|
2325
2672
|
}
|
|
2326
2673
|
for (const command of employee.commands) {
|
|
2327
2674
|
for (const file of command.files) {
|
|
2328
|
-
const filePath =
|
|
2329
|
-
if (await
|
|
2330
|
-
file.content = await
|
|
2675
|
+
const filePath = path8.join(employeeDir, file.path);
|
|
2676
|
+
if (await fs7.pathExists(filePath)) {
|
|
2677
|
+
file.content = await fs7.readFile(filePath, "utf-8");
|
|
2331
2678
|
} else {
|
|
2332
2679
|
throw new Error(`Command file not found: ${file.path}`);
|
|
2333
2680
|
}
|
|
@@ -2335,48 +2682,17 @@ async function runBuild(options) {
|
|
|
2335
2682
|
}
|
|
2336
2683
|
for (const doc of employee.docs) {
|
|
2337
2684
|
for (const file of doc.files) {
|
|
2338
|
-
const filePath =
|
|
2339
|
-
if (await
|
|
2340
|
-
file.content = await
|
|
2685
|
+
const filePath = path8.join(employeeDir, file.path);
|
|
2686
|
+
if (await fs7.pathExists(filePath)) {
|
|
2687
|
+
file.content = await fs7.readFile(filePath, "utf-8");
|
|
2341
2688
|
} else {
|
|
2342
2689
|
throw new Error(`Doc file not found: ${file.path}`);
|
|
2343
2690
|
}
|
|
2344
2691
|
}
|
|
2345
2692
|
}
|
|
2346
|
-
const legacyOutputPath =
|
|
2347
|
-
await
|
|
2348
|
-
await
|
|
2349
|
-
const employeeExtended = {
|
|
2350
|
-
$schema: "https://the-aico.com/schema/employee.json",
|
|
2351
|
-
name: employee.name,
|
|
2352
|
-
namespace: registry,
|
|
2353
|
-
fullName: employeeFullName,
|
|
2354
|
-
role: employee.role,
|
|
2355
|
-
description: employee.description,
|
|
2356
|
-
version,
|
|
2357
|
-
category,
|
|
2358
|
-
skills: skillFullNames,
|
|
2359
|
-
commands: employee.commands,
|
|
2360
|
-
docs: employee.docs
|
|
2361
|
-
};
|
|
2362
|
-
const employeesOutputDir = path7.join(outputPath, "employees");
|
|
2363
|
-
await fs6.ensureDir(employeesOutputDir);
|
|
2364
|
-
await fs6.writeJson(
|
|
2365
|
-
path7.join(employeesOutputDir, `${employee.name}.json`),
|
|
2366
|
-
employeeExtended,
|
|
2367
|
-
{ spaces: 2 }
|
|
2368
|
-
);
|
|
2369
|
-
employeesIndex.push({
|
|
2370
|
-
name: employee.name,
|
|
2371
|
-
namespace: registry,
|
|
2372
|
-
fullName: employeeFullName,
|
|
2373
|
-
role: employee.role,
|
|
2374
|
-
description: employee.description,
|
|
2375
|
-
version,
|
|
2376
|
-
skillCount: employee.skills.length,
|
|
2377
|
-
commandCount: employee.commands.length,
|
|
2378
|
-
category
|
|
2379
|
-
});
|
|
2693
|
+
const legacyOutputPath = path8.join(outputPath, `${employee.name}.json`);
|
|
2694
|
+
await fs7.ensureDir(outputPath);
|
|
2695
|
+
await fs7.writeJson(legacyOutputPath, employee, { spaces: 2 });
|
|
2380
2696
|
legacyIndex.push({
|
|
2381
2697
|
name: employee.name,
|
|
2382
2698
|
role: employee.role,
|
|
@@ -2399,38 +2715,41 @@ async function runBuild(options) {
|
|
|
2399
2715
|
if (sharedSkillCount > 0) {
|
|
2400
2716
|
s.text = `Built ${sharedSkillCount} shared skill(s)`;
|
|
2401
2717
|
}
|
|
2402
|
-
const skillsIndexPath =
|
|
2403
|
-
await
|
|
2404
|
-
await
|
|
2405
|
-
const
|
|
2406
|
-
await
|
|
2407
|
-
await fs6.writeJson(employeesIndexPath, employeesIndex, { spaces: 2 });
|
|
2408
|
-
const legacyIndexPath = path7.join(outputPath, "index.json");
|
|
2409
|
-
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(
|
|
2410
2723
|
legacyIndexPath,
|
|
2411
2724
|
{ employees: legacyIndex },
|
|
2412
2725
|
{ spaces: 2 }
|
|
2413
2726
|
);
|
|
2727
|
+
s.text = "Building JSON schemas...";
|
|
2728
|
+
await buildSchemas(schemaPath);
|
|
2414
2729
|
s.succeed(`Built ${employeeFiles.length} employee(s) to ${outputDir}/`);
|
|
2415
2730
|
logger.break();
|
|
2416
2731
|
logger.success("Registry build complete!");
|
|
2417
2732
|
logger.dim(` Skills: ${skillsIndex.length} (${sharedSkillCount} shared)`);
|
|
2418
|
-
logger.dim(` Employees: ${
|
|
2733
|
+
logger.dim(` Employees: ${legacyIndex.length}`);
|
|
2419
2734
|
logger.break();
|
|
2420
|
-
for (const emp of
|
|
2421
|
-
logger.dim(` - ${emp.name}: ${emp.role}
|
|
2735
|
+
for (const emp of legacyIndex) {
|
|
2736
|
+
logger.dim(` - ${emp.name}: ${emp.role}`);
|
|
2422
2737
|
}
|
|
2423
2738
|
}
|
|
2424
2739
|
var build = new Command5().name("build").description("Build registry from employees directory").option(
|
|
2425
2740
|
"-e, --employees-dir <dir>",
|
|
2426
2741
|
"Employees source directory",
|
|
2427
2742
|
"employees"
|
|
2428
|
-
).option("-o, --output-dir <dir>", "Output directory", "registry").option(
|
|
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) => {
|
|
2429
2747
|
try {
|
|
2430
2748
|
const options = buildOptionsSchema.parse({
|
|
2431
2749
|
cwd: opts.cwd,
|
|
2432
2750
|
employeesDir: opts.employeesDir,
|
|
2433
2751
|
outputDir: opts.outputDir,
|
|
2752
|
+
schemaDir: opts.schemaDir,
|
|
2434
2753
|
registry: opts.registry,
|
|
2435
2754
|
version: opts.version
|
|
2436
2755
|
});
|
|
@@ -2441,8 +2760,8 @@ var build = new Command5().name("build").description("Build registry from employ
|
|
|
2441
2760
|
});
|
|
2442
2761
|
|
|
2443
2762
|
// src/commands/diff.ts
|
|
2444
|
-
import
|
|
2445
|
-
import
|
|
2763
|
+
import fs8 from "fs-extra";
|
|
2764
|
+
import path9 from "path";
|
|
2446
2765
|
import { Command as Command6 } from "commander";
|
|
2447
2766
|
import { diffLines } from "diff";
|
|
2448
2767
|
import { z as z10 } from "zod";
|
|
@@ -2455,10 +2774,10 @@ var diffOptionsSchema = z10.object({
|
|
|
2455
2774
|
cwd: z10.string()
|
|
2456
2775
|
});
|
|
2457
2776
|
async function compareFile(localPath, registryContent) {
|
|
2458
|
-
if (!await
|
|
2777
|
+
if (!await fs8.pathExists(localPath)) {
|
|
2459
2778
|
return null;
|
|
2460
2779
|
}
|
|
2461
|
-
const localContent = await
|
|
2780
|
+
const localContent = await fs8.readFile(localPath, "utf-8");
|
|
2462
2781
|
const patch = diffLines(localContent, registryContent);
|
|
2463
2782
|
const hasChanges = patch.some((part) => part.added || part.removed);
|
|
2464
2783
|
return hasChanges ? patch : null;
|
|
@@ -2502,10 +2821,10 @@ async function diffEmployee(employeeName, cwd, config) {
|
|
|
2502
2821
|
for (const skill of registryEmployee.skills) {
|
|
2503
2822
|
const skillDirName = adapter.getSkillDirName(employeeName, skill.name);
|
|
2504
2823
|
for (const file of skill.files) {
|
|
2505
|
-
const localPath =
|
|
2824
|
+
const localPath = path9.join(
|
|
2506
2825
|
skillsDir,
|
|
2507
2826
|
skillDirName,
|
|
2508
|
-
|
|
2827
|
+
path9.basename(file.path)
|
|
2509
2828
|
);
|
|
2510
2829
|
let registryContent = file.content;
|
|
2511
2830
|
if (file.path.endsWith("SKILL.md")) {
|
|
@@ -2514,7 +2833,7 @@ async function diffEmployee(employeeName, cwd, config) {
|
|
|
2514
2833
|
`$1${skillDirName}`
|
|
2515
2834
|
);
|
|
2516
2835
|
}
|
|
2517
|
-
if (!await
|
|
2836
|
+
if (!await fs8.pathExists(localPath)) {
|
|
2518
2837
|
if (!skillsAdded.includes(skill.name)) {
|
|
2519
2838
|
fileChanges.push({
|
|
2520
2839
|
filePath: localPath,
|
|
@@ -2539,8 +2858,8 @@ async function diffEmployee(employeeName, cwd, config) {
|
|
|
2539
2858
|
command.name
|
|
2540
2859
|
);
|
|
2541
2860
|
for (const file of command.files) {
|
|
2542
|
-
const localPath =
|
|
2543
|
-
if (!await
|
|
2861
|
+
const localPath = path9.join(commandsDir, commandFileName);
|
|
2862
|
+
if (!await fs8.pathExists(localPath)) {
|
|
2544
2863
|
if (!commandsAdded.includes(command.name)) {
|
|
2545
2864
|
fileChanges.push({
|
|
2546
2865
|
filePath: localPath,
|
|
@@ -2561,8 +2880,8 @@ async function diffEmployee(employeeName, cwd, config) {
|
|
|
2561
2880
|
}
|
|
2562
2881
|
for (const skillName of skillsRemoved) {
|
|
2563
2882
|
const skillDirName = adapter.getSkillDirName(employeeName, skillName);
|
|
2564
|
-
const skillPath =
|
|
2565
|
-
if (await
|
|
2883
|
+
const skillPath = path9.join(skillsDir, skillDirName);
|
|
2884
|
+
if (await fs8.pathExists(skillPath)) {
|
|
2566
2885
|
fileChanges.push({
|
|
2567
2886
|
filePath: skillPath,
|
|
2568
2887
|
type: "removed"
|
|
@@ -2574,8 +2893,8 @@ async function diffEmployee(employeeName, cwd, config) {
|
|
|
2574
2893
|
employeeName,
|
|
2575
2894
|
commandName
|
|
2576
2895
|
);
|
|
2577
|
-
const commandPath =
|
|
2578
|
-
if (await
|
|
2896
|
+
const commandPath = path9.join(commandsDir, commandFileName);
|
|
2897
|
+
if (await fs8.pathExists(commandPath)) {
|
|
2579
2898
|
fileChanges.push({
|
|
2580
2899
|
filePath: commandPath,
|
|
2581
2900
|
type: "removed"
|
|
@@ -2647,7 +2966,7 @@ async function runDiff(options) {
|
|
|
2647
2966
|
logger.warn(` Removed commands: ${diff2.commandsRemoved.join(", ")}`);
|
|
2648
2967
|
}
|
|
2649
2968
|
for (const change of diff2.fileChanges) {
|
|
2650
|
-
const relativePath =
|
|
2969
|
+
const relativePath = path9.relative(cwd, change.filePath);
|
|
2651
2970
|
if (change.type === "modified") {
|
|
2652
2971
|
logger.info(` Modified: ${relativePath}`);
|
|
2653
2972
|
if (change.patch) {
|
|
@@ -2970,7 +3289,7 @@ function formatJSON(items) {
|
|
|
2970
3289
|
category: item.category,
|
|
2971
3290
|
description: item.description,
|
|
2972
3291
|
tags: item.tags,
|
|
2973
|
-
install: item.type === "employee" ? `
|
|
3292
|
+
install: item.type === "employee" ? `aico add ${item.name}` : `aico add ${item.fullName}`
|
|
2974
3293
|
}))
|
|
2975
3294
|
};
|
|
2976
3295
|
return JSON.stringify(output, null, 2);
|
|
@@ -3016,7 +3335,7 @@ var search = new Command8().name("search").description("Search for skills and em
|
|
|
3016
3335
|
logger.log(formatTable(results));
|
|
3017
3336
|
logger.break();
|
|
3018
3337
|
if (results.length > 0) {
|
|
3019
|
-
logger.dim("Install:
|
|
3338
|
+
logger.dim("Install: aico add <name>");
|
|
3020
3339
|
}
|
|
3021
3340
|
}
|
|
3022
3341
|
} catch (error) {
|
|
@@ -3287,7 +3606,7 @@ var check = new Command9().name("check").description("Check environment and conf
|
|
|
3287
3606
|
const hasWarn = results.some((r) => r.status === "warn");
|
|
3288
3607
|
if (hasError) {
|
|
3289
3608
|
logger.log(
|
|
3290
|
-
kleur5.red("\u2716 Some checks failed. Run `
|
|
3609
|
+
kleur5.red("\u2716 Some checks failed. Run `aico init` to fix.")
|
|
3291
3610
|
);
|
|
3292
3611
|
} else if (hasWarn) {
|
|
3293
3612
|
logger.log(
|