thomas-agentkit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +28 -1
  2. package/dist/cli.js +137 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -38,12 +38,24 @@ Use the optional interactive flow:
38
38
  npx thomas-agentkit init --interactive
39
39
  ```
40
40
 
41
+ Install stack-specific agent guidance:
42
+
43
+ ```bash
44
+ npx thomas-agentkit init --preset next
45
+ ```
46
+
41
47
  List bundled templates:
42
48
 
43
49
  ```bash
44
50
  npx thomas-agentkit --list
45
51
  ```
46
52
 
53
+ List available presets:
54
+
55
+ ```bash
56
+ npx thomas-agentkit --list-presets
57
+ ```
58
+
47
59
  ## Installed Files
48
60
 
49
61
  AgentKit copies these bundled files into the target project:
@@ -59,13 +71,26 @@ AgentKit copies these bundled files into the target project:
59
71
  - `.github/copilot-instructions.md`
60
72
  - `.github/pull_request_template.md`
61
73
 
74
+ When a preset is selected, AgentKit also installs `STACK.md` and adds a note in `AGENTS.md` telling agents to read it before changing stack-specific code.
75
+
62
76
  Existing files are skipped by default so local edits are preserved. Use `--force` when you intentionally want to refresh files from the bundled package version.
63
77
 
78
+ ## Presets
79
+
80
+ Presets add stack-specific guidance without scaffolding framework app files.
81
+
82
+ - `next`
83
+ - `sveltekit`
84
+ - `express`
85
+ - `convex`
86
+ - `fullstack` (`Next.js` + `Convex`)
87
+
64
88
  ## CLI Reference
65
89
 
66
90
  ```text
67
- agentkit init [target] [--force] [--dry-run] [--interactive] [--yes]
91
+ agentkit init [target] [--force] [--dry-run] [--interactive] [--yes] [--preset <name>]
68
92
  agentkit --list
93
+ agentkit --list-presets
69
94
  agentkit --help
70
95
  agentkit --version
71
96
  ```
@@ -76,7 +101,9 @@ Options:
76
101
  - `--dry-run`: print planned changes without writing files
77
102
  - `-i, --interactive`: prompt for install options
78
103
  - `-y, --yes`: accept defaults for non-interactive runs
104
+ - `--preset <name>`: install stack-specific guidance (`next`, `sveltekit`, `express`, `convex`, `fullstack`)
79
105
  - `--list`: list bundled template files
106
+ - `--list-presets`: list available presets
80
107
  - `-h, --help`: show help
81
108
  - `-v, --version`: show package version
82
109
 
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { confirm, isCancel, text } from "@clack/prompts";
2
+ import { confirm, isCancel, select, text } from "@clack/prompts";
3
3
  import { Command } from "commander";
4
4
  import { constants as fsConstants } from "node:fs";
5
- import { access, copyFile, mkdir, readdir, readFile, stat } from "node:fs/promises";
5
+ import { access, copyFile, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  const __filename = fileURLToPath(import.meta.url);
@@ -10,6 +10,63 @@ const __dirname = path.dirname(__filename);
10
10
  const packageRoot = path.resolve(__dirname, "..");
11
11
  const templatesDir = path.join(packageRoot, "templates");
12
12
  const packageJsonPath = path.join(packageRoot, "package.json");
13
+ const validPresets = ["next", "sveltekit", "express", "convex", "fullstack"];
14
+ const presetLabels = {
15
+ next: "Next.js",
16
+ sveltekit: "SvelteKit",
17
+ express: "Express",
18
+ convex: "Convex",
19
+ fullstack: "Fullstack",
20
+ };
21
+ const stackGuidance = {
22
+ next: `# Stack Guidance
23
+
24
+ ## Next.js
25
+
26
+ - Follow the app's existing routing model before adding new routes or layouts.
27
+ - Keep server and client component boundaries explicit.
28
+ - Prefer server components for data loading unless interactivity requires a client component.
29
+ - Keep mutations in server actions, route handlers, or existing API layers based on local patterns.
30
+ - Use established styling primitives and design tokens before adding new UI conventions.
31
+ - Validate external input at route, action, and API boundaries.
32
+ - Run the project's Next.js build or typecheck before handoff when touching routing, rendering, or data loading.
33
+ `,
34
+ sveltekit: `# Stack Guidance
35
+
36
+ ## SvelteKit
37
+
38
+ - Follow the existing route, load, action, and server module patterns before adding new files.
39
+ - Keep browser-only code out of server load functions and server modules.
40
+ - Use SvelteKit form actions and load functions where they fit the workflow.
41
+ - Validate external input at action, endpoint, and server boundary entrypoints.
42
+ - Reuse existing stores, components, and styling conventions before creating new ones.
43
+ - Run the project's SvelteKit check or build before handoff when touching routes, rendering, or data loading.
44
+ `,
45
+ express: `# Stack Guidance
46
+
47
+ ## Express
48
+
49
+ - Keep route handlers small and move repeated business logic only when duplication is real.
50
+ - Validate request params, query strings, and bodies at the route boundary.
51
+ - Return explicit status codes and predictable response shapes.
52
+ - Use the project's existing middleware order and error handling pattern.
53
+ - Avoid adding global middleware or dependencies for narrow endpoint changes.
54
+ - Add focused tests for route behavior, validation failures, and error paths.
55
+ `,
56
+ convex: `# Stack Guidance
57
+
58
+ ## Convex
59
+
60
+ - Follow generated Convex types and local function patterns before editing schema or functions.
61
+ - Keep queries, mutations, and actions focused on one clear responsibility.
62
+ - Validate arguments with Convex validators at public function boundaries.
63
+ - Preserve explicit authorization checks for user-scoped data.
64
+ - Prefer indexes and schema changes that match real query needs.
65
+ - Run Convex codegen or the project's Convex validation command after schema or function changes.
66
+ `,
67
+ };
68
+ const fullstackGuidance = `${stackGuidance.next}
69
+ ${stackGuidance.convex.replace("# Stack Guidance\n\n", "")}`;
13
70
  async function exists(filePath) {
14
71
  try {
15
72
  await access(filePath, fsConstants.F_OK);
@@ -41,9 +98,39 @@ async function getTemplateFiles(dir = templatesDir, base = templatesDir) {
41
98
  }));
42
99
  return files.flat().sort();
43
100
  }
101
+ function isPresetName(value) {
102
+ return validPresets.includes(value);
103
+ }
104
+ function formatPresetList() {
105
+ return validPresets.join(", ");
106
+ }
107
+ function resolvePreset(preset) {
108
+ if (!preset) {
109
+ return undefined;
110
+ }
111
+ const normalizedPreset = preset.toLowerCase();
112
+ if (!isPresetName(normalizedPreset)) {
113
+ throw new Error(`Unknown preset "${preset}". Valid presets: ${formatPresetList()}.`);
114
+ }
115
+ return normalizedPreset;
116
+ }
117
+ function getStackGuidance(preset) {
118
+ return preset === "fullstack" ? fullstackGuidance : stackGuidance[preset];
119
+ }
120
+ function addStackReference(file, content, preset) {
121
+ if (file !== "AGENTS.md" || !preset) {
122
+ return content;
123
+ }
124
+ const stackNote = `\nPreset: ${presetLabels[preset]}. Agents must read \`STACK.md\` before changing stack-specific code.\n`;
125
+ if (content.includes("## Guidelines")) {
126
+ return content.replace("\n## Guidelines", `${stackNote}\n## Guidelines`);
127
+ }
128
+ return `${content.trimEnd()}\n${stackNote}`;
129
+ }
44
130
  async function installTemplates(targetArg, options) {
45
131
  const targetDir = path.resolve(process.cwd(), targetArg || ".");
46
132
  const files = await getTemplateFiles();
133
+ const preset = resolvePreset(options.preset);
47
134
  const created = [];
48
135
  const skipped = [];
49
136
  if (!options.dryRun) {
@@ -60,7 +147,27 @@ async function installTemplates(targetArg, options) {
60
147
  created.push(file);
61
148
  if (!options.dryRun) {
62
149
  await mkdir(path.dirname(destination), { recursive: true });
63
- await copyFile(source, destination);
150
+ if (preset && file === "AGENTS.md") {
151
+ const content = await readFile(source, "utf8");
152
+ await writeFile(destination, addStackReference(file, content, preset));
153
+ }
154
+ else {
155
+ await copyFile(source, destination);
156
+ }
157
+ }
158
+ }
159
+ if (preset) {
160
+ const stackFile = "STACK.md";
161
+ const destination = path.join(targetDir, stackFile);
162
+ const destinationExists = await exists(destination);
163
+ if (destinationExists && !options.force) {
164
+ skipped.push(stackFile);
165
+ }
166
+ else {
167
+ created.push(stackFile);
168
+ if (!options.dryRun) {
169
+ await writeFile(destination, getStackGuidance(preset));
170
+ }
64
171
  }
65
172
  }
66
173
  return { targetDir, created, skipped };
@@ -80,6 +187,7 @@ function printInstallResult(result, dryRun = false) {
80
187
  }
81
188
  }
82
189
  async function resolveInteractiveTarget(target, options) {
190
+ const providedPreset = resolvePreset(options.preset);
83
191
  if (!options.interactive) {
84
192
  return target;
85
193
  }
@@ -98,6 +206,22 @@ async function resolveInteractiveTarget(target, options) {
98
206
  if (isCancel(forceResponse)) {
99
207
  process.exit(130);
100
208
  }
209
+ const presetResponse = await select({
210
+ message: "Which preset should AgentKit use?",
211
+ initialValue: providedPreset || "generic",
212
+ options: [
213
+ { label: "Generic", value: "generic" },
214
+ { label: "Next.js", value: "next" },
215
+ { label: "SvelteKit", value: "sveltekit" },
216
+ { label: "Express", value: "express" },
217
+ { label: "Convex", value: "convex" },
218
+ { label: "Fullstack", value: "fullstack" },
219
+ ],
220
+ });
221
+ if (isCancel(presetResponse)) {
222
+ process.exit(130);
223
+ }
224
+ options.preset = presetResponse === "generic" ? undefined : presetResponse;
101
225
  options.force = forceResponse;
102
226
  return targetResponse || ".";
103
227
  }
@@ -109,17 +233,26 @@ async function main() {
109
233
  }
110
234
  return;
111
235
  }
236
+ if (process.argv.slice(2).includes("--list-presets")) {
237
+ for (const preset of validPresets) {
238
+ console.log(preset);
239
+ }
240
+ return;
241
+ }
112
242
  const program = new Command();
113
243
  program
114
244
  .name("agentkit")
115
245
  .description("Bootstrap AI-agent-ready repository docs and workflow templates.")
116
246
  .version(await readPackageVersion(), "-v, --version")
117
247
  .option("--list", "list bundled template files")
248
+ .option("--list-presets", "list available presets")
118
249
  .addHelpText("after", `
119
250
 
120
251
  Examples:
121
252
  agentkit init
253
+ agentkit init --preset next
122
254
  agentkit init ./my-project --dry-run
255
+ agentkit --list-presets
123
256
  agentkit --list`);
124
257
  program
125
258
  .command("init")
@@ -129,6 +262,7 @@ Examples:
129
262
  .option("--dry-run", "print planned changes without writing files")
130
263
  .option("-i, --interactive", "prompt for install options")
131
264
  .option("-y, --yes", "accept defaults for non-interactive runs")
265
+ .option("--preset <name>", `install stack-specific guidance (${formatPresetList()})`)
132
266
  .action(async (target, options) => {
133
267
  const resolvedTarget = await resolveInteractiveTarget(target, options);
134
268
  const result = await installTemplates(resolvedTarget, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thomas-agentkit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Install AI-agent-ready development templates into a project.",
5
5
  "license": "MIT",
6
6
  "type": "module",