create-academic-research 0.1.3 → 0.1.5

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 CHANGED
@@ -35,9 +35,10 @@ adjacent interdisciplinary CS.
35
35
 
36
36
  The generated repository is agent-neutral. By default the wizard records
37
37
  `agent: universal`, installs one shared project-local `.agents/skills` copy,
38
- and writes generic MCP snippets. Use `--agent <name>` only when you want to
39
- force a specific target recognized by the `skills` CLI, such as `claude-code`,
40
- `codex`, `cursor`, `windsurf`, or another supported local loader.
38
+ and writes generic MCP snippets. Use `--agent <id>` only when you want to force
39
+ a specific target recognized by the `skills` CLI. Run
40
+ `npx academic-research agents list` inside a generated project to see every
41
+ supported target and alias.
41
42
 
42
43
  ## Default Experience
43
44
 
@@ -76,6 +77,7 @@ Inside a generated project:
76
77
  ```bash
77
78
  npx academic-research doctor
78
79
  npx academic-research rename --title "New Title" --slug new-title --package new_title
80
+ npx academic-research agents list
79
81
  npx academic-research skills presets
80
82
  npx academic-research skills install --preset default
81
83
  npx academic-research skills install --preset enhanced
@@ -134,8 +136,9 @@ The create wizard can install that project-local package automatically.
134
136
  Those skills are portable `SKILL.md` instructions, but they require an
135
137
  agent/runtime that can load skills or include the relevant instructions in
136
138
  context. They are not automatic capabilities of every raw model API.
137
- Use `--agent <agent>` for explicit setup, for example `--agent codex` or
138
- `--agent claude-code`.
139
+ Use `--agent <id>` for explicit setup with any id from
140
+ `academic-research agents list`. The shorthand `--agent claude` is normalized
141
+ to the supported `claude-code` target.
139
142
  Avoid `--agent auto` for unattended setup: the upstream `skills` CLI may expand
140
143
  it to every agent it detects on the machine.
141
144
 
@@ -166,8 +169,8 @@ Releases are tag-driven. Update `package.json` and `package-lock.json`, commit
166
169
  the change, create `vX.Y.Z`, and push the tag:
167
170
 
168
171
  ```bash
169
- git tag -a v0.1.3 -m "v0.1.3"
170
- git push origin main v0.1.3
172
+ git tag -a v0.1.5 -m "v0.1.5"
173
+ git push origin main v0.1.5
171
174
  ```
172
175
 
173
176
  Once the GitHub repository is public, the release workflow validates the tag
@@ -0,0 +1,9 @@
1
+ export declare const DEFAULT_AGENT = "universal";
2
+ export declare const AUTO_AGENT = "auto";
3
+ export declare const SUPPORTED_SKILL_AGENT_TARGETS: readonly ["adal", "aider-desk", "amp", "antigravity", "augment", "bob", "claude-code", "cline", "codearts-agent", "codebuddy", "codemaker", "codestudio", "codex", "command-code", "continue", "cortex", "crush", "cursor", "deepagents", "devin", "dexto", "droid", "firebender", "forgecode", "gemini-cli", "github-copilot", "goose", "hermes-agent", "iflow-cli", "junie", "kilo", "kimi-cli", "kiro-cli", "kode", "mcpjam", "mistral-vibe", "mux", "neovate", "openclaw", "opencode", "openhands", "pi", "pochi", "qoder", "qwen-code", "replit", "roo", "rovodev", "tabnine-cli", "trae", "trae-cn", "universal", "warp", "windsurf", "zencoder"];
4
+ export declare const AGENT_TARGET_ALIASES: Record<string, string>;
5
+ export declare function normalizeAgentTarget(agent: string | undefined): string;
6
+ export declare function assertKnownAgentTarget(agent: string | undefined): string;
7
+ export declare function formatAgentTargetList(): string;
8
+ export declare function formatSupportedAgentTargetLines(indent?: string, width?: number): string[];
9
+ export declare function formatAgentAliasLines(indent?: string): string[];
@@ -0,0 +1,126 @@
1
+ export const DEFAULT_AGENT = "universal";
2
+ export const AUTO_AGENT = "auto";
3
+ export const SUPPORTED_SKILL_AGENT_TARGETS = [
4
+ "adal",
5
+ "aider-desk",
6
+ "amp",
7
+ "antigravity",
8
+ "augment",
9
+ "bob",
10
+ "claude-code",
11
+ "cline",
12
+ "codearts-agent",
13
+ "codebuddy",
14
+ "codemaker",
15
+ "codestudio",
16
+ "codex",
17
+ "command-code",
18
+ "continue",
19
+ "cortex",
20
+ "crush",
21
+ "cursor",
22
+ "deepagents",
23
+ "devin",
24
+ "dexto",
25
+ "droid",
26
+ "firebender",
27
+ "forgecode",
28
+ "gemini-cli",
29
+ "github-copilot",
30
+ "goose",
31
+ "hermes-agent",
32
+ "iflow-cli",
33
+ "junie",
34
+ "kilo",
35
+ "kimi-cli",
36
+ "kiro-cli",
37
+ "kode",
38
+ "mcpjam",
39
+ "mistral-vibe",
40
+ "mux",
41
+ "neovate",
42
+ "openclaw",
43
+ "opencode",
44
+ "openhands",
45
+ "pi",
46
+ "pochi",
47
+ "qoder",
48
+ "qwen-code",
49
+ "replit",
50
+ "roo",
51
+ "rovodev",
52
+ "tabnine-cli",
53
+ "trae",
54
+ "trae-cn",
55
+ "universal",
56
+ "warp",
57
+ "windsurf",
58
+ "zencoder"
59
+ ];
60
+ export const AGENT_TARGET_ALIASES = {
61
+ claude: "claude-code",
62
+ claude_code: "claude-code"
63
+ };
64
+ const SUPPORTED_AGENT_TARGETS = new Set([
65
+ AUTO_AGENT,
66
+ ...SUPPORTED_SKILL_AGENT_TARGETS
67
+ ]);
68
+ export function normalizeAgentTarget(agent) {
69
+ const value = agent?.trim();
70
+ if (!value)
71
+ return DEFAULT_AGENT;
72
+ const normalized = value.toLowerCase();
73
+ return AGENT_TARGET_ALIASES[normalized] ?? normalized;
74
+ }
75
+ export function assertKnownAgentTarget(agent) {
76
+ const normalized = normalizeAgentTarget(agent);
77
+ if (!SUPPORTED_AGENT_TARGETS.has(normalized)) {
78
+ const value = agent?.trim() || DEFAULT_AGENT;
79
+ throw new Error([
80
+ `unknown agent target: ${value}`,
81
+ `Use ${DEFAULT_AGENT}, ${AUTO_AGENT}, or one supported skills.sh agent id.`,
82
+ "List targets with: npx -p create-academic-research academic-research agents list",
83
+ `Supported ids: ${specificAgentTargets().join(", ")}`,
84
+ `Aliases: ${formatAgentAliasesInline()}`
85
+ ].join("\n"));
86
+ }
87
+ return normalized;
88
+ }
89
+ export function formatAgentTargetList() {
90
+ const lines = [
91
+ `${DEFAULT_AGENT}\tRecommended shared project-local .agents/skills copy`,
92
+ `${AUTO_AGENT}\tLet the skills CLI detect installed agents; may create multiple agent-specific copies`,
93
+ ...specificAgentTargets().map((agent) => `${agent}\tskills.sh agent id`),
94
+ ...Object.entries(AGENT_TARGET_ALIASES).map(([alias, target]) => `alias\t${alias}\t${target}`)
95
+ ];
96
+ return `${lines.join("\n")}\n`;
97
+ }
98
+ export function formatSupportedAgentTargetLines(indent = " ", width = 100) {
99
+ const labels = specificAgentTargets();
100
+ const lines = [];
101
+ let current = indent;
102
+ for (const label of labels) {
103
+ const next = current === indent ? label : `, ${label}`;
104
+ if (current.length + next.length > width) {
105
+ lines.push(current);
106
+ current = `${indent}${label}`;
107
+ }
108
+ else {
109
+ current += next;
110
+ }
111
+ }
112
+ if (current.trim())
113
+ lines.push(current);
114
+ return lines;
115
+ }
116
+ export function formatAgentAliasLines(indent = " ") {
117
+ return Object.entries(AGENT_TARGET_ALIASES).map(([alias, target]) => `${indent}${alias} -> ${target}`);
118
+ }
119
+ function formatAgentAliasesInline() {
120
+ return Object.entries(AGENT_TARGET_ALIASES)
121
+ .map(([alias, target]) => `${alias} -> ${target}`)
122
+ .join(", ");
123
+ }
124
+ function specificAgentTargets() {
125
+ return SUPPORTED_SKILL_AGENT_TARGETS.filter((agent) => agent !== DEFAULT_AGENT);
126
+ }
@@ -1,6 +1,7 @@
1
+ import { DEFAULT_AGENT, SUPPORTED_SKILL_AGENT_TARGETS } from "./agents.js";
1
2
  import { type Runner } from "./runner.js";
2
3
  import { type McpToolCommandKey } from "./stack.js";
3
- export declare const DEFAULT_AGENT = "universal";
4
+ export { DEFAULT_AGENT, SUPPORTED_SKILL_AGENT_TARGETS };
4
5
  export interface CapabilityState {
5
6
  agent: string;
6
7
  preset: string;
@@ -51,4 +52,3 @@ export declare function installMcpTools(root: string, servers: string[], runner?
51
52
  export declare function uninstallMcpTools(root: string, servers: string[], runner?: Runner): Promise<CapabilityCommandResult>;
52
53
  export declare function doctorMcpServers(root: string): Promise<McpDoctorResult>;
53
54
  export declare function assertKnownMcpServers(servers: string[]): void;
54
- export {};
@@ -1,10 +1,10 @@
1
1
  import { appendFile, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { join, relative } from "node:path";
3
3
  import YAML from "yaml";
4
+ import { assertKnownAgentTarget, AUTO_AGENT, DEFAULT_AGENT, normalizeAgentTarget, SUPPORTED_SKILL_AGENT_TARGETS } from "./agents.js";
4
5
  import { defaultRunner } from "./runner.js";
5
6
  import { AGENT_STACK, presetMcpServers } from "./stack.js";
6
- export const DEFAULT_AGENT = "universal";
7
- const AUTO_AGENT = "auto";
7
+ export { DEFAULT_AGENT, SUPPORTED_SKILL_AGENT_TARGETS };
8
8
  export async function readCapabilities(root) {
9
9
  try {
10
10
  return readCapabilitiesFile(root);
@@ -18,7 +18,7 @@ export async function readCapabilities(root) {
18
18
  }
19
19
  export async function writeCapabilities(root, state) {
20
20
  const next = {
21
- agent: normalizeAgent(state.agent),
21
+ agent: assertKnownAgentTarget(state.agent),
22
22
  preset: state.preset ?? "default",
23
23
  scope: "project-local",
24
24
  mcp_servers: [...(state.mcp_servers ?? [])]
@@ -42,7 +42,7 @@ export async function buildSkillInstallCommands(root, preset = "default", option
42
42
  if (!selected)
43
43
  throw new Error(`unknown skill preset: ${preset}`);
44
44
  const state = await readCapabilities(root);
45
- const agent = normalizeAgent(options.agent ?? state.agent);
45
+ const agent = assertKnownAgentTarget(options.agent ?? state.agent);
46
46
  const commands = [];
47
47
  for (const bundleName of selected.skill_bundles) {
48
48
  const bundle = AGENT_STACK.skill_bundles[bundleName];
@@ -61,7 +61,7 @@ export async function buildSkillInstallCommands(root, preset = "default", option
61
61
  }
62
62
  export async function installSkills(root, preset = "default", options = {}, runner = defaultRunner) {
63
63
  const state = await readCapabilities(root);
64
- const agent = normalizeAgent(options.agent ?? state.agent);
64
+ const agent = assertKnownAgentTarget(options.agent ?? state.agent);
65
65
  const commands = await buildSkillInstallCommands(root, preset, options);
66
66
  for (const command of commands) {
67
67
  await runner.run(command, { cwd: root });
@@ -135,7 +135,7 @@ export async function enableMcpServers(root, servers, options = {}) {
135
135
  const selected = dedupe([...(state.mcp_servers ?? []), ...servers]);
136
136
  await writeCapabilities(root, {
137
137
  ...state,
138
- agent: options.agent ?? state.agent,
138
+ agent: assertKnownAgentTarget(options.agent ?? state.agent),
139
139
  mcp_servers: selected
140
140
  });
141
141
  return { ok: true, servers: selected };
@@ -147,7 +147,7 @@ export async function disableMcpServers(root, servers, options = {}) {
147
147
  const selected = (state.mcp_servers ?? []).filter((server) => !blocked.has(server));
148
148
  await writeCapabilities(root, {
149
149
  ...state,
150
- agent: options.agent ?? state.agent,
150
+ agent: assertKnownAgentTarget(options.agent ?? state.agent),
151
151
  mcp_servers: selected
152
152
  });
153
153
  return { ok: true, servers: selected };
@@ -269,7 +269,7 @@ async function writeCapabilityProfile(root, state) {
269
269
  const lines = [
270
270
  "# Agent Capability Profile",
271
271
  "",
272
- `- Agent target: \`${normalizeAgent(state.agent)}\``,
272
+ `- Agent target: \`${assertKnownAgentTarget(state.agent)}\``,
273
273
  `- Preset: \`${state.preset ?? "default"}\``,
274
274
  "- Scope: `project-local`",
275
275
  "",
@@ -307,7 +307,7 @@ function dedupe(values) {
307
307
  return [...new Set(values)];
308
308
  }
309
309
  function renderSkillCommand(command, agent) {
310
- const normalized = normalizeAgent(agent);
310
+ const normalized = assertKnownAgentTarget(agent);
311
311
  const agentFlag = normalized === AUTO_AGENT ? "" : `--agent '${normalized}'`;
312
312
  return command.replaceAll("{agent_flag}", agentFlag).replaceAll("{agent}", normalized);
313
313
  }
@@ -352,7 +352,7 @@ function splitCommand(command) {
352
352
  function normalizeCapabilityState(value) {
353
353
  const record = typeof value === "object" && value !== null ? value : {};
354
354
  return {
355
- agent: normalizeAgent(typeof record.agent === "string" ? record.agent : undefined),
355
+ agent: assertKnownAgentTarget(typeof record.agent === "string" ? record.agent : undefined),
356
356
  preset: typeof record.preset === "string" ? record.preset : "default",
357
357
  scope: "project-local",
358
358
  mcp_servers: Array.isArray(record.mcp_servers)
@@ -397,12 +397,8 @@ async function removeSkillsFromLock(root, skills) {
397
397
  await writeFile(path, `${JSON.stringify(record, null, 2)}\n`, "utf8");
398
398
  }
399
399
  }
400
- function normalizeAgent(agent) {
401
- const value = agent?.trim();
402
- return value ? value : DEFAULT_AGENT;
403
- }
404
400
  function mcpSnippetFileName(agent) {
405
- const normalized = normalizeAgent(agent);
401
+ const normalized = normalizeAgentTarget(agent);
406
402
  return normalized === DEFAULT_AGENT || normalized === AUTO_AGENT ? "mcp.json" : `${normalized}-mcp.json`;
407
403
  }
408
404
  async function removeInactiveMcpSnippets(outputDir, activeFile) {
package/dist/src/cli.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  type CliMode = "create" | "lifecycle";
2
2
  export declare function main(argv?: string[], mode?: CliMode): Promise<number>;
3
+ export declare function formatInteractiveCreateGuide(): string;
3
4
  export {};
package/dist/src/cli.js CHANGED
@@ -5,6 +5,7 @@ import { disableMcpServers, doctorMcpServers, enableMcpServers, DEFAULT_AGENT, i
5
5
  import { createProject, doctorProject, renameProject } from "./project.js";
6
6
  import { askCreateOptions } from "./prompts.js";
7
7
  import { AGENT_STACK, presetMcpServers } from "./stack.js";
8
+ import { formatAgentAliasLines, formatAgentTargetList, formatSupportedAgentTargetLines } from "./agents.js";
8
9
  import { packageify, slugify, titleFromSlug } from "./names.js";
9
10
  const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
10
11
  const packageVersion = readPackageVersion();
@@ -16,8 +17,8 @@ const MCP_FLAGS = flagSchema(["help"], ["root", "agent"]);
16
17
  export async function main(argv = process.argv.slice(2), mode = "create") {
17
18
  try {
18
19
  if (mode === "create")
19
- return createMain(argv);
20
- return lifecycleMain(argv);
20
+ return await createMain(argv);
21
+ return await lifecycleMain(argv);
21
22
  }
22
23
  catch (error) {
23
24
  console.error(error instanceof Error ? error.message : String(error));
@@ -61,7 +62,7 @@ async function createMain(argv) {
61
62
  : undefined;
62
63
  const installMcpToolsLock = flagBool(parsed.flags, "install-mcp-tools") ? true : undefined;
63
64
  const answers = interactive
64
- ? await askCreateOptions(defaults, {
65
+ ? await askInteractiveCreateOptions(defaults, {
65
66
  installSkills: installSkillsLock,
66
67
  installMcpTools: installMcpToolsLock
67
68
  })
@@ -83,6 +84,10 @@ async function createMain(argv) {
83
84
  console.log("Next: cd into the project and run `npx academic-research doctor`.");
84
85
  return 0;
85
86
  }
87
+ async function askInteractiveCreateOptions(defaults, locks) {
88
+ console.log(formatInteractiveCreateGuide());
89
+ return askCreateOptions(defaults, locks);
90
+ }
86
91
  async function lifecycleMain(argv) {
87
92
  const command = argv[0] ?? "help";
88
93
  if (command === "--help" || command === "-h") {
@@ -97,6 +102,8 @@ async function lifecycleMain(argv) {
97
102
  return doctorCommand(argv.slice(1));
98
103
  if (command === "rename")
99
104
  return renameCommand(argv.slice(1));
105
+ if (command === "agents")
106
+ return agentsCommand(argv.slice(1));
100
107
  if (command === "skills")
101
108
  return skillsCommand(argv.slice(1));
102
109
  if (command === "mcp")
@@ -133,6 +140,21 @@ async function renameCommand(argv) {
133
140
  console.log(`Renamed project to ${result.slug}`);
134
141
  return 0;
135
142
  }
143
+ async function agentsCommand(argv) {
144
+ const subcommand = argv[0] ?? "list";
145
+ const parsed = parseFlags(argv.slice(1), ROOT_FLAGS);
146
+ if (subcommand === "help" || subcommand === "--help" || subcommand === "-h" || flagBool(parsed.flags, "help")) {
147
+ printAgentsHelp();
148
+ return 0;
149
+ }
150
+ if (subcommand === "list") {
151
+ assertOnlyOptions(parsed.flags, "agents list", []);
152
+ assertNoArguments(parsed.positionals, "agents list");
153
+ process.stdout.write(formatAgentTargetList());
154
+ return 0;
155
+ }
156
+ throw new Error(`unknown agents command: ${subcommand}`);
157
+ }
136
158
  async function skillsCommand(argv) {
137
159
  const subcommand = argv[0] ?? "list";
138
160
  const parsed = parseFlags(argv.slice(1), SKILLS_FLAGS);
@@ -388,6 +410,33 @@ function mcpInstallMode(installCommand, runtimeCommand) {
388
410
  return installCommand;
389
411
  return runtimeCommand ? "runtime-only" : "manual";
390
412
  }
413
+ export function formatInteractiveCreateGuide() {
414
+ const presetLines = Object.entries(AGENT_STACK.presets).map(([name, preset]) => ` ${name.padEnd(10)} ${preset.description}`);
415
+ return [
416
+ "Setup choices:",
417
+ "",
418
+ "Capability presets:",
419
+ ...presetLines,
420
+ "",
421
+ "Agent target:",
422
+ " universal Recommended. One shared project-local .agents/skills copy.",
423
+ " auto Let the skills CLI detect installed agents; may create multiple agent-specific copies.",
424
+ " <id> Any supported skills.sh agent id.",
425
+ "",
426
+ "Supported specific agent ids:",
427
+ ...formatSupportedAgentTargetLines(),
428
+ "",
429
+ "Aliases:",
430
+ ...formatAgentAliasLines(),
431
+ "",
432
+ "Skill and MCP behavior:",
433
+ " Skills are copied into the project, not installed globally.",
434
+ " MCP records are written into configs/capabilities.yaml and docs/agent/generated/.",
435
+ " MCP installers are optional and run only finite installer commands.",
436
+ " runtime-only MCP servers are configured for the MCP client but have no install step.",
437
+ ""
438
+ ].join("\n");
439
+ }
391
440
  function printCreateHelp() {
392
441
  console.log([
393
442
  "Usage: create-academic-research <project-name> [options]",
@@ -401,7 +450,7 @@ function printCreateHelp() {
401
450
  " --package <name> Python package name. Default: normalized project name.",
402
451
  " --preset <name> Capability preset: minimal, default, enhanced, literature, writing, full.",
403
452
  " --profile <name> Project profile metadata. Default: academic-general.",
404
- " --agent <name> Agent target. Default: universal.",
453
+ " --agent <id> Agent target: universal, auto, or a supported skills.sh id.",
405
454
  " --install-skills Install project-local skills without prompting.",
406
455
  " --no-install-skills Skip project-local skill installation.",
407
456
  " --install-mcp-tools Run finite external MCP install commands after creation.",
@@ -420,7 +469,7 @@ function printMissingTargetHelp() {
420
469
  }
421
470
  function printLifecycleHelp() {
422
471
  console.log([
423
- "Usage: academic-research <doctor|rename|skills|mcp>",
472
+ "Usage: academic-research <doctor|rename|agents|skills|mcp>",
424
473
  "",
425
474
  "Manage a generated academic research repository after creation.",
426
475
  "",
@@ -429,6 +478,21 @@ function printLifecycleHelp() {
429
478
  " -v, --version Show package version."
430
479
  ].join("\n"));
431
480
  }
481
+ function printAgentsHelp() {
482
+ console.log([
483
+ "Usage: academic-research agents <list>",
484
+ "",
485
+ "List supported project-local agent targets.",
486
+ "",
487
+ "Targets:",
488
+ " universal Recommended shared project-local .agents/skills copy.",
489
+ " auto Let the skills CLI detect installed agents.",
490
+ " <id> A supported skills.sh agent id.",
491
+ "",
492
+ "Options:",
493
+ " -h, --help Show this help."
494
+ ].join("\n"));
495
+ }
432
496
  function printSkillsHelp() {
433
497
  console.log([
434
498
  "Usage: academic-research skills <list|status|presets|install|remove|uninstall|update> [options]",
@@ -438,7 +502,7 @@ function printSkillsHelp() {
438
502
  "Options:",
439
503
  " --root <path> Project root for list, status, install, remove, uninstall, update.",
440
504
  " --preset <name> Capability preset for install.",
441
- " --agent <name> Agent selector for install. Default: project capability agent.",
505
+ " --agent <id> Agent selector for install. Default: project capability agent.",
442
506
  " -h, --help Show this help."
443
507
  ].join("\n"));
444
508
  }
@@ -450,7 +514,7 @@ function printMcpHelp() {
450
514
  "",
451
515
  "Options:",
452
516
  " --root <path> Project root for project-state commands.",
453
- " --agent <name> Agent for enable/disable generated snippets.",
517
+ " --agent <id> Agent for enable/disable generated snippets.",
454
518
  " -h, --help Show this help."
455
519
  ].join("\n"));
456
520
  }
@@ -3,6 +3,7 @@ import { basename, dirname, join, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import YAML from "yaml";
5
5
  import { DEFAULT_AGENT, initializeCapabilities, installSkills } from "./capabilities.js";
6
+ import { assertKnownAgentTarget } from "./agents.js";
6
7
  import { copyDirectory, exists, isNonEmptyDirectory, movePath, readJson, writeJson } from "./files.js";
7
8
  import { packageify, slugify, titleFromSlug } from "./names.js";
8
9
  import { AGENT_STACK } from "./stack.js";
@@ -90,9 +91,9 @@ export async function createProject(options) {
90
91
  const slug = slugify(options.slug ?? title);
91
92
  const packageName = packageify(options.packageName ?? slug);
92
93
  const preset = options.preset ?? "default";
93
- const agent = options.agent ?? DEFAULT_AGENT;
94
+ const agent = assertKnownAgentTarget(options.agent ?? DEFAULT_AGENT);
94
95
  if (!AGENT_STACK.presets[preset]) {
95
- throw new Error(`unknown capability preset: ${preset}`);
96
+ throw new Error(`unknown capability preset: ${preset}. Expected one of: ${Object.keys(AGENT_STACK.presets).join(", ")}`);
96
97
  }
97
98
  await mkdir(dirname(target), { recursive: true });
98
99
  await copyDirectory(templateRoot, target);
@@ -205,7 +206,7 @@ async function writeGeneratedPackageJson(root, { slug }) {
205
206
  const path = join(root, "package.json");
206
207
  const data = await readJson(path);
207
208
  const existingSpec = data.devDependencies?.["create-academic-research"];
208
- const packageSpec = process.env.CREATE_ACADEMIC_RESEARCH_PACKAGE_SPEC ?? existingSpec ?? "^0.1.3";
209
+ const packageSpec = process.env.CREATE_ACADEMIC_RESEARCH_PACKAGE_SPEC ?? existingSpec ?? "0.1.5";
209
210
  data.name = slug;
210
211
  data.devDependencies = {
211
212
  ...(data.devDependencies ?? {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-academic-research",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Create and manage agent-ready academic research repositories.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -53,6 +53,7 @@ Project-local skills and MCP records are managed with:
53
53
 
54
54
  ```bash
55
55
  npx academic-research skills presets
56
+ npx academic-research agents list
56
57
  npx academic-research skills install --preset default
57
58
  npx academic-research skills install --preset enhanced
58
59
  npx academic-research skills list
@@ -12,6 +12,6 @@
12
12
  "mcp:doctor": "academic-research mcp doctor"
13
13
  },
14
14
  "devDependencies": {
15
- "create-academic-research": "^0.1.3"
15
+ "create-academic-research": "0.1.5"
16
16
  }
17
17
  }