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.
- package/README.md +28 -1
- package/dist/cli.js +137 -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
|
-
|
|
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);
|