awesome-agents 0.1.0 → 0.1.3

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/src/help.js ADDED
@@ -0,0 +1,530 @@
1
+ import { stripVTControlCharacters } from "node:util";
2
+ import { PACKAGE_NAME, SUPPORTED_AGENTS } from "./constants.js";
3
+
4
+ const reset = "\x1b[0m";
5
+ const codes = {
6
+ bold: "\x1b[1m",
7
+ dim: "\x1b[2m",
8
+ command: "\x1b[38;5;110m",
9
+ option: "\x1b[38;5;81m",
10
+ profile: "\x1b[38;5;149m",
11
+ path: "\x1b[38;5;145m",
12
+ success: "\x1b[38;5;108m",
13
+ warning: "\x1b[38;5;179m",
14
+ error: "\x1b[38;5;203m",
15
+ bannerA: "\x1b[38;5;111m",
16
+ bannerB: "\x1b[38;5;109m",
17
+ bannerC: "\x1b[38;5;149m"
18
+ };
19
+
20
+ export const ui = {
21
+ bold: (value) => color(value, codes.bold),
22
+ command: (value) => color(value, codes.command),
23
+ option: (value) => color(value, codes.option),
24
+ profile: (value) => color(value, codes.profile),
25
+ path: (value) => color(value, codes.path),
26
+ success: (value) => color(value, codes.success),
27
+ warning: (value) => color(value, codes.warning),
28
+ error: (value) => color(value, codes.error),
29
+ dim: (value) => color(value, codes.dim),
30
+ prompt: () => color("$", codes.success)
31
+ };
32
+
33
+ export function configureHelp(program) {
34
+ program.configureOutput({
35
+ getOutHasColors: shouldUseColor,
36
+ getErrHasColors: shouldUseColor,
37
+ stripColor: (value) => stripVTControlCharacters(value)
38
+ });
39
+
40
+ program.configureHelp({
41
+ formatHelp(command) {
42
+ return formatHelp(command);
43
+ }
44
+ });
45
+ }
46
+
47
+ function formatHelp(command) {
48
+ const name = command.name();
49
+ const definition = command.parent ? commandHelp[name] : mainHelp;
50
+ return renderHelp(definition ?? genericHelp(command));
51
+ }
52
+
53
+ function renderHelp(definition) {
54
+ const lines = [];
55
+
56
+ if (definition.banner) {
57
+ lines.push(...definition.banner, "");
58
+ }
59
+
60
+ lines.push(`${ui.bold("Usage:")} ${definition.usage}`, "");
61
+
62
+ if (definition.description) {
63
+ lines.push(definition.description, "");
64
+ }
65
+
66
+ for (const section of definition.sections) {
67
+ lines.push(`${ui.bold(section.title)}`);
68
+ for (const row of section.rows) {
69
+ lines.push(formatRow(row));
70
+ }
71
+ lines.push("");
72
+ }
73
+
74
+ if (definition.examples?.length) {
75
+ lines.push(ui.bold("Examples:"));
76
+ for (const example of definition.examples) {
77
+ lines.push(formatExample(example));
78
+ }
79
+ lines.push("");
80
+ }
81
+
82
+ if (definition.footer) {
83
+ lines.push(definition.footer);
84
+ }
85
+
86
+ return `${trimBlankLines(lines).join("\n")}\n`;
87
+ }
88
+
89
+ function formatRow(row) {
90
+ if (typeof row === "string") {
91
+ return ` ${row}`;
92
+ }
93
+
94
+ const term = row.term ?? "";
95
+ const description = row.description ?? "";
96
+ const detail = row.detail ?? [];
97
+ const first = ` ${padVisible(term, row.width ?? 30)} ${description}`.trimEnd();
98
+ const lines = [first];
99
+
100
+ for (const value of detail) {
101
+ lines.push(` ${" ".repeat(row.width ?? 30)} ${value}`.trimEnd());
102
+ }
103
+
104
+ return lines.join("\n");
105
+ }
106
+
107
+ function formatExample(example) {
108
+ const comment = example.comment ? ` ${ui.dim(`# ${example.comment}`)}` : "";
109
+ return ` ${ui.prompt()} ${example.command}${comment}`;
110
+ }
111
+
112
+ function genericHelp(command) {
113
+ return {
114
+ usage: command.usage(),
115
+ description: command.description(),
116
+ sections: [
117
+ {
118
+ title: "Options:",
119
+ rows: command.options.map((option) => ({
120
+ term: ui.option(option.flags),
121
+ description: option.description
122
+ }))
123
+ }
124
+ ]
125
+ };
126
+ }
127
+
128
+ function trimBlankLines(lines) {
129
+ const result = [...lines];
130
+ while (result.at(-1) === "") {
131
+ result.pop();
132
+ }
133
+ return result;
134
+ }
135
+
136
+ function padVisible(value, width) {
137
+ const visible = stripVTControlCharacters(value).length;
138
+ return `${value}${" ".repeat(Math.max(0, width - visible))}`;
139
+ }
140
+
141
+ function color(value, code) {
142
+ return shouldUseColor() ? `${code}${value}${reset}` : value;
143
+ }
144
+
145
+ function shouldUseColor() {
146
+ if (
147
+ process.env.NO_COLOR ||
148
+ process.env.FORCE_COLOR === "0" ||
149
+ process.env.FORCE_COLOR === "false" ||
150
+ process.env.CLICOLOR === "0" ||
151
+ process.env.TERM === "dumb"
152
+ ) {
153
+ return false;
154
+ }
155
+ return true;
156
+ }
157
+
158
+ export function formatMissingSourceError(commandName = "add") {
159
+ return [
160
+ "",
161
+ ` ${ui.error("ERROR")} Missing required argument: source`,
162
+ "",
163
+ " Usage:",
164
+ ` npx ${PACKAGE_NAME} ${commandName} <source> [options]`,
165
+ "",
166
+ " Examples:",
167
+ ` npx ${PACKAGE_NAME} ${commandName} ${exampleSource} --agent ${exampleProfile}`,
168
+ ` npx ${PACKAGE_NAME} ${commandName} ./agents-source --list`,
169
+ "",
170
+ " Tip:",
171
+ ` Sources contain ${stripVTControlCharacters(sourceHint)}. Use --list before installing.`,
172
+ ""
173
+ ].join("\n");
174
+ }
175
+
176
+ const sourceHint = `${ui.profile("agents/profiles/*.{agent.yaml,agf.yaml,md}")} plus optional ${ui.profile("agents/adapters/<harness>/*")}`;
177
+ const harnesses = SUPPORTED_AGENTS.join("|");
178
+ const exampleSource = "owner/repo";
179
+ const exampleProfile = "triage-agent";
180
+ const banner = [
181
+ color(" _ ", codes.bannerA),
182
+ color(" /_\\ __ _____ ___ ___ _ __ ___ ___ ", codes.bannerA),
183
+ color(" //_\\\\ \\ /\\ / / _ \\/ __|/ _ \\| '_ ` _ \\ / _ \\ ", codes.bannerB),
184
+ color(" / _ \\ V V / __/\\__ \\ (_) | | | | | | __/ ", codes.bannerB),
185
+ color(" \\_/ \\_/\\_/\\_/ \\___||___/\\___/|_| |_| |_|\\___| ", codes.bannerC),
186
+ color(" __ _ __ _ ___ _ __ | |_ ___ ", codes.bannerC),
187
+ color(" / _` |/ _` |/ _ \\ '_ \\| __/ __| ", codes.bannerB),
188
+ color(" | (_| | (_| | __/ | | | |_\\__ \\ ", codes.bannerB),
189
+ color(" \\__,_|\\__, |\\___|_| |_|\\__|___/ ", codes.bannerA),
190
+ color(" |___/ ", codes.bannerA),
191
+ ` ${ui.dim("Operational profiles for Codex, Claude Code, and OpenCode")}`
192
+ ];
193
+
194
+ const mainHelp = {
195
+ banner,
196
+ usage: `${PACKAGE_NAME} <command> [options]`,
197
+ description: "Install reusable operational agent profiles into Codex, Claude Code, and OpenCode.",
198
+ sections: [
199
+ {
200
+ title: "Manage Profiles:",
201
+ rows: [
202
+ {
203
+ term: `${ui.command("add")} <source>`,
204
+ description: "Install profiles from a source (alias: install)",
205
+ detail: [
206
+ `e.g. ${ui.path(exampleSource)}`,
207
+ ` ${ui.path("./agents-source")}`
208
+ ]
209
+ },
210
+ {
211
+ term: `${ui.command("use")} <source>`,
212
+ description: "Print one rendered profile without installing it"
213
+ },
214
+ {
215
+ term: `${ui.command("remove")} [profiles...]`,
216
+ description: "Remove installed profiles (alias: rm)"
217
+ },
218
+ {
219
+ term: `${ui.command("list")}, ${ui.command("ls")}`,
220
+ description: "List installed profiles"
221
+ }
222
+ ]
223
+ },
224
+ {
225
+ title: "Updates:",
226
+ rows: [
227
+ {
228
+ term: `${ui.command("update")} [profiles...]`,
229
+ description: "Reinstall profiles from their recorded source (alias: upgrade)"
230
+ }
231
+ ]
232
+ },
233
+ {
234
+ title: "Project:",
235
+ rows: [
236
+ {
237
+ term: `${ui.command("init")} [name]`,
238
+ description: "Initialize an agent-profile source layout"
239
+ }
240
+ ]
241
+ },
242
+ {
243
+ title: "Add Options:",
244
+ rows: installOptions()
245
+ },
246
+ {
247
+ title: "Use Options:",
248
+ rows: useOptions()
249
+ },
250
+ {
251
+ title: "List Options:",
252
+ rows: listOptions()
253
+ },
254
+ {
255
+ title: "Remove Options:",
256
+ rows: removeOptions()
257
+ },
258
+ {
259
+ title: "Update Options:",
260
+ rows: updateOptions()
261
+ },
262
+ {
263
+ title: "Options:",
264
+ rows: [
265
+ { term: ui.option("-h, --help"), description: "Show this help message" },
266
+ { term: ui.option("-v, --version"), description: "Show version number" }
267
+ ]
268
+ }
269
+ ],
270
+ examples: [
271
+ { command: `${PACKAGE_NAME} add ${exampleSource} --list`, comment: "inspect source profiles" },
272
+ { command: `${PACKAGE_NAME} add ${exampleSource} --agent ${exampleProfile}` },
273
+ { command: `${PACKAGE_NAME} add ${exampleSource} --agent ${exampleProfile} --harness opencode` },
274
+ { command: `${PACKAGE_NAME} add ${exampleSource} --all --dry-run`, comment: "preview every write" },
275
+ { command: `${PACKAGE_NAME} use ${exampleSource}@${exampleProfile} --harness claude-code` },
276
+ { command: `${PACKAGE_NAME} list --json`, comment: "machine-readable output" },
277
+ { command: `${PACKAGE_NAME} remove ${exampleProfile} --agent codex --dry-run` },
278
+ { command: `${PACKAGE_NAME} update ${exampleProfile} --agent codex` }
279
+ ],
280
+ footer: `Sources use ${sourceHint}. Set ${ui.option("NO_COLOR=1")} to disable ANSI color.`
281
+ };
282
+
283
+ const commandHelp = {
284
+ add: {
285
+ usage: `${PACKAGE_NAME} add <source> [profile options] [target options]`,
286
+ description: "Install harness-native agent profile files from a repository or local checkout.",
287
+ sections: [
288
+ {
289
+ title: "Install Flow:",
290
+ rows: [
291
+ "1. Read canonical profiles from agents/profiles/*.{agent.yaml,agf.yaml,md}.",
292
+ "2. Merge optional harness notes from agents/adapters/<harness>/*.",
293
+ "3. Render Codex, Claude Code, or OpenCode files and record them in the registry."
294
+ ]
295
+ },
296
+ {
297
+ title: "Source Forms:",
298
+ rows: [
299
+ { term: ui.path("owner/repo"), description: "Shallow-clone a GitHub repository" },
300
+ { term: ui.path("https://github.com/owner/repo"), description: "Use an explicit GitHub URL" },
301
+ { term: ui.path("./agents-source"), description: "Use a local source checkout" },
302
+ { term: ui.path("~/agents-source"), description: "Use a home-relative local source" }
303
+ ]
304
+ },
305
+ {
306
+ title: "Select Profiles:",
307
+ rows: [
308
+ { term: ui.option("--agent triage-agent"), description: "Preferred shorthand: install one profile slug" },
309
+ { term: ui.option("--profile triage-agent"), description: "Explicit profile selector" },
310
+ { term: ui.option("--skill triage-agent"), description: "Compatibility alias for --profile" },
311
+ { term: ui.option("--all"), description: "Install every source profile" },
312
+ { term: ui.option("--list"), description: "Show available profiles and exit" }
313
+ ]
314
+ },
315
+ {
316
+ title: "Choose Targets:",
317
+ rows: [
318
+ { term: ui.option("(default)"), description: "Codex, installed globally as a config profile" },
319
+ { term: ui.option("--harness opencode"), description: "Render for one harness" },
320
+ { term: ui.option("--harness codex claude-code"), description: "Render for multiple harnesses" },
321
+ { term: ui.option("--harness *"), description: "Render for every supported harness" },
322
+ { term: ui.option("--global"), description: "Install into the user-level harness directory" },
323
+ { term: ui.option("--project"), description: "Install project-local files where the harness supports it" }
324
+ ]
325
+ },
326
+ {
327
+ title: "Target Files:",
328
+ rows: [
329
+ { term: ui.command("codex"), description: `${ui.path("~/.codex/<profile>.config.toml")} (project-local Codex profiles are not supported)` },
330
+ { term: ui.command("claude-code"), description: `${ui.path("~/.claude/agents/<profile>.md")} or ${ui.path(".claude/agents/<profile>.md")}` },
331
+ { term: ui.command("opencode"), description: `${ui.path("~/.config/opencode/agents/<profile>.md")} or ${ui.path(".opencode/agents/<profile>.md")}` },
332
+ { term: ui.command("registry"), description: `${ui.path("~/.awesome-agents/installed.json")} or ${ui.path(".awesome-agents/installed.json")}` }
333
+ ]
334
+ },
335
+ {
336
+ title: "Safety And Output:",
337
+ rows: [
338
+ `Existing files are overwritten only when they contain ${ui.profile("Generated by awesome-agents")}.`,
339
+ `${ui.option("--dry-run")} previews target files and registry writes.`,
340
+ `${ui.option("--force")} overrides the generated-marker check.`,
341
+ `${ui.option("--json")} prints machine-readable output without ANSI color.`,
342
+ `${ui.option("--home <dir>")} overrides HOME for tests and scripted installs.`
343
+ ]
344
+ }
345
+ ],
346
+ examples: [
347
+ { command: `${PACKAGE_NAME} add ${exampleSource} --list` },
348
+ { command: `${PACKAGE_NAME} add ${exampleSource} --agent ${exampleProfile}` },
349
+ { command: `${PACKAGE_NAME} add ${exampleSource} --agent ${exampleProfile} --harness codex opencode` },
350
+ { command: `${PACKAGE_NAME} add ${exampleSource} --all --dry-run` }
351
+ ],
352
+ footer: `Generated files are marked with ${ui.profile("Generated by awesome-agents")}.`
353
+ },
354
+ install: {
355
+ usage: `${PACKAGE_NAME} install <source> [profile options] [target options]`,
356
+ description: `${ui.command("install")} is an alias for ${ui.command("add")}.`,
357
+ sections: [
358
+ { title: "Options:", rows: installOptions({ includeHome: true }) }
359
+ ],
360
+ examples: [
361
+ { command: `${PACKAGE_NAME} install ${exampleSource} --agent ${exampleProfile}` }
362
+ ]
363
+ },
364
+ use: {
365
+ usage: `${PACKAGE_NAME} use <source> [options]`,
366
+ description: "Render one profile to stdout without installing it.",
367
+ sections: [
368
+ {
369
+ title: "Arguments:",
370
+ rows: [
371
+ { term: ui.profile("source"), description: "Source plus optional profile, for example owner/repo@profile" }
372
+ ]
373
+ },
374
+ { title: "Options:", rows: useOptions({ includeHome: true }) }
375
+ ],
376
+ examples: [
377
+ { command: `${PACKAGE_NAME} use ${exampleSource}@${exampleProfile} --harness codex` },
378
+ { command: `${PACKAGE_NAME} use ${exampleSource} --agent ${exampleProfile} --harness claude-code` }
379
+ ]
380
+ },
381
+ list: {
382
+ usage: `${PACKAGE_NAME} list|ls [options]`,
383
+ description: "List profiles recorded in the awesome-agents registry.",
384
+ sections: [
385
+ { title: "Options:", rows: listOptions({ includeHome: true }) }
386
+ ],
387
+ examples: [
388
+ { command: `${PACKAGE_NAME} list` },
389
+ { command: `${PACKAGE_NAME} ls --global --agent opencode` },
390
+ { command: `${PACKAGE_NAME} ls --json` }
391
+ ]
392
+ },
393
+ remove: {
394
+ usage: `${PACKAGE_NAME} remove|rm [profiles...] [options]`,
395
+ description: "Remove generated profile files and update the registry.",
396
+ sections: [
397
+ {
398
+ title: "Arguments:",
399
+ rows: [
400
+ { term: ui.profile("profiles"), description: "Installed profile slugs to remove" }
401
+ ]
402
+ },
403
+ { title: "Options:", rows: removeOptions({ includeHome: true }) }
404
+ ],
405
+ examples: [
406
+ { command: `${PACKAGE_NAME} remove ${exampleProfile} --agent codex --dry-run` },
407
+ { command: `${PACKAGE_NAME} rm --all --global` }
408
+ ],
409
+ footer: `By default, remove only deletes files marked with ${ui.profile("Generated by awesome-agents")}.`
410
+ },
411
+ update: {
412
+ usage: `${PACKAGE_NAME} update|upgrade [profiles...] [options]`,
413
+ description: "Reinstall recorded profiles from their original source.",
414
+ sections: [
415
+ {
416
+ title: "Arguments:",
417
+ rows: [
418
+ { term: ui.profile("profiles"), description: "Installed profile slugs to update" }
419
+ ]
420
+ },
421
+ { title: "Options:", rows: updateOptions({ includeHome: true }) }
422
+ ],
423
+ examples: [
424
+ { command: `${PACKAGE_NAME} update` },
425
+ { command: `${PACKAGE_NAME} update ${exampleProfile} --agent codex --dry-run` },
426
+ { command: `${PACKAGE_NAME} upgrade --global --json` }
427
+ ]
428
+ },
429
+ init: {
430
+ usage: `${PACKAGE_NAME} init [name] [options]`,
431
+ description: "Create a profile source layout in the current directory.",
432
+ sections: [
433
+ {
434
+ title: "Arguments:",
435
+ rows: [
436
+ { term: ui.profile("name"), description: "New profile slug" }
437
+ ]
438
+ },
439
+ { title: "Options:", rows: initOptions() }
440
+ ],
441
+ examples: [
442
+ { command: `${PACKAGE_NAME} init ios-release-manager` },
443
+ { command: `${PACKAGE_NAME} init --dry-run` }
444
+ ],
445
+ footer: `Creates ${sourceHint}.`
446
+ }
447
+ };
448
+
449
+ function installOptions({ includeHome = false } = {}) {
450
+ return compact([
451
+ { term: ui.option("-g, --global"), description: "Install globally instead of into the current project" },
452
+ { term: ui.option("-p, --project"), description: "Install into the current project; not supported for Codex profiles" },
453
+ { term: ui.option("-a, --agent <profiles...>"), description: "Select agent profile slugs; harness names still work for compatibility" },
454
+ { term: ui.option("--harness <harnesses...>"), description: `Select target harnesses: ${harnesses}, or *` },
455
+ { term: ui.option("-s, --profile <profiles...>"), description: "Explicit profile selector; accepts *" },
456
+ { term: ui.option("--skill <profiles...>"), description: "Compatibility alias for --profile" },
457
+ { term: ui.option("-l, --list"), description: "List available source profiles without installing" },
458
+ { term: ui.option("--all"), description: "Install all profiles to all supported harnesses" },
459
+ { term: ui.option("-y, --yes"), description: "Accepted for npx skills parity; prompts are not used" },
460
+ { term: ui.option("--dry-run"), description: "Print planned installs without writing files" },
461
+ { term: ui.option("--force"), description: "Allow overwriting files without the generated marker" },
462
+ { term: ui.option("--json"), description: "Output JSON without ANSI color" },
463
+ includeHome ? { term: ui.option("--home <dir>"), description: "Override HOME for path expansion" } : null,
464
+ { term: ui.option("-h, --help"), description: "Show command help" }
465
+ ]);
466
+ }
467
+
468
+ function useOptions({ includeHome = false } = {}) {
469
+ return compact([
470
+ { term: ui.option("-s, --profile <profile>"), description: "Profile slug to render" },
471
+ { term: ui.option("--skill <profile>"), description: "Compatibility alias for --profile" },
472
+ { term: ui.option("-a, --agent <profile|harness>"), description: "Profile selector; harness names still work for compatibility" },
473
+ { term: ui.option("--harness <harness>"), description: `Target harness renderer: ${harnesses}` },
474
+ { term: ui.option("--json"), description: "Output rendered content plus metadata as JSON" },
475
+ includeHome ? { term: ui.option("--home <dir>"), description: "Override HOME for path expansion" } : null,
476
+ { term: ui.option("-h, --help"), description: "Show command help" }
477
+ ]);
478
+ }
479
+
480
+ function listOptions({ includeHome = false } = {}) {
481
+ return compact([
482
+ { term: ui.option("-g, --global"), description: "List global installs" },
483
+ { term: ui.option("-p, --project"), description: "List project installs" },
484
+ { term: ui.option("-a, --agent <harnesses...>"), description: "Filter by target harness" },
485
+ { term: ui.option("--json"), description: "Output JSON without ANSI color" },
486
+ includeHome ? { term: ui.option("--home <dir>"), description: "Override HOME for path expansion" } : null,
487
+ { term: ui.option("-h, --help"), description: "Show command help" }
488
+ ]);
489
+ }
490
+
491
+ function removeOptions({ includeHome = false } = {}) {
492
+ return compact([
493
+ { term: ui.option("-g, --global"), description: "Remove global installs" },
494
+ { term: ui.option("-p, --project"), description: "Remove project installs" },
495
+ { term: ui.option("-a, --agent <harnesses...>"), description: "Filter by target harness" },
496
+ { term: ui.option("--all"), description: "Remove every matching installed profile" },
497
+ { term: ui.option("-y, --yes"), description: "Accepted for npx skills parity; prompts are not used" },
498
+ { term: ui.option("--dry-run"), description: "Print planned removals without deleting files" },
499
+ { term: ui.option("--force"), description: "Allow removing files without the generated marker" },
500
+ { term: ui.option("--json"), description: "Output JSON without ANSI color" },
501
+ includeHome ? { term: ui.option("--home <dir>"), description: "Override HOME for path expansion" } : null,
502
+ { term: ui.option("-h, --help"), description: "Show command help" }
503
+ ]);
504
+ }
505
+
506
+ function updateOptions({ includeHome = false } = {}) {
507
+ return compact([
508
+ { term: ui.option("-g, --global"), description: "Update global installs" },
509
+ { term: ui.option("-p, --project"), description: "Update project installs" },
510
+ { term: ui.option("-a, --agent <harnesses...>"), description: "Filter by target harness" },
511
+ { term: ui.option("-y, --yes"), description: "Accepted for npx skills parity; prompts are not used" },
512
+ { term: ui.option("--dry-run"), description: "Print planned updates without writing files" },
513
+ { term: ui.option("--json"), description: "Output JSON without ANSI color" },
514
+ includeHome ? { term: ui.option("--home <dir>"), description: "Override HOME for path expansion" } : null,
515
+ { term: ui.option("-h, --help"), description: "Show command help" }
516
+ ]);
517
+ }
518
+
519
+ function initOptions() {
520
+ return [
521
+ { term: ui.option("--dry-run"), description: "Print planned files without writing" },
522
+ { term: ui.option("--force"), description: "Overwrite existing initialized files" },
523
+ { term: ui.option("--json"), description: "Output JSON without ANSI color" },
524
+ { term: ui.option("-h, --help"), description: "Show command help" }
525
+ ];
526
+ }
527
+
528
+ function compact(values) {
529
+ return values.filter(Boolean);
530
+ }