thomas-agentkit 0.8.0 → 0.9.0-alpha.1
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 +101 -9
- package/dist/cli.js +145 -32
- package/dist/skill-install.js +125 -0
- package/package.json +3 -1
- package/templates/.cursor/rules/agentkit.md +1 -1
- package/templates/.github/copilot-instructions.md +1 -1
- package/templates/AGENTS.md +1 -1
- package/templates/WORKFLOWS.md +1 -1
- package/templates/design-systems/apple.md +74 -209
- package/templates/design-systems/cursor.md +95 -0
- package/templates/design-systems/framer.md +95 -0
- package/templates/design-systems/linear.md +95 -207
- package/templates/design-systems/notion.md +94 -0
- package/templates/design-systems/warp.md +89 -0
- package/templates/skills/agentkit/SKILL.md +101 -0
- package/templates/skills/agentkit/agents/openai.yaml +4 -0
- package/templates/skills/agentkit/references/design-baselines/apple.md +101 -0
- package/templates/skills/agentkit/references/design-baselines/cursor.md +95 -0
- package/templates/skills/agentkit/references/design-baselines/framer.md +95 -0
- package/templates/skills/agentkit/references/design-baselines/linear.md +117 -0
- package/templates/skills/agentkit/references/design-baselines/notion.md +94 -0
- package/templates/skills/agentkit/references/design-baselines/warp.md +89 -0
- package/templates/skills/agentkit/references/design.md +100 -0
- package/templates/skills/agentkit/references/doctor.md +133 -0
- package/templates/skills/agentkit/references/file-contract.md +164 -0
- package/templates/skills/agentkit/references/init.md +213 -0
- package/templates/skills/agentkit/references/learn.md +149 -0
- package/templates/skills/agentkit/references/repair.md +119 -0
- package/templates/skills/agentkit/references/update.md +202 -0
package/README.md
CHANGED
|
@@ -6,14 +6,81 @@ It installs reusable agent instructions, workflow guides, quality checklists, de
|
|
|
6
6
|
|
|
7
7
|
AgentKit is not an AI agent. It is a small scaffolding tool for making repositories easier and safer to work on with AI-assisted development.
|
|
8
8
|
|
|
9
|
+
## Bootstrap paths
|
|
10
|
+
|
|
11
|
+
AgentKit supports two first-time setup paths. Pick one — they are not interchangeable.
|
|
12
|
+
|
|
13
|
+
| | Template path | Skill path |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| **CLI command** | `agentkit init` | `agentkit skill install` |
|
|
16
|
+
| **When to use** | Immediate offline setup; you want files now | Agent-guided setup; guidance created from your repo in a later session |
|
|
17
|
+
| **What you get** | Bundled `.md` templates copied into the project | Bundled `agentkit` Agent Skill installed; no guidance `.md` files yet |
|
|
18
|
+
| **Ongoing maintenance** | CLI `agentkit update` (managed-block merge) | Skill routes in your agent: `/agentkit update`, `/agentkit doctor`, `/agentkit repair`, `/agentkit learn` |
|
|
19
|
+
| **Config** | `installMode: template` | `installMode: skill` |
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
FIRST-TIME SETUP (terminal)
|
|
23
|
+
├── agentkit init → copies templates, installMode: template
|
|
24
|
+
└── agentkit skill install → copies skill to .agents/skills/agentkit/, installMode: skill
|
|
25
|
+
|
|
26
|
+
ONGOING WORK (agent + skill path only)
|
|
27
|
+
├── /agentkit init → agent creates AGENTS.md and companion files from repo context
|
|
28
|
+
├── /agentkit update → agent syncs guidance after code changes
|
|
29
|
+
├── /agentkit doctor → agent audits guidance quality
|
|
30
|
+
├── /agentkit repair → agent repairs guidance structure when explicitly requested
|
|
31
|
+
└── /agentkit learn → agent teaches what changed after implementation
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Interactive `agentkit init` asks whether to copy templates or install the AgentKit skill, then runs the chosen path in the same session.
|
|
35
|
+
|
|
9
36
|
## Usage
|
|
10
37
|
|
|
38
|
+
### Template path
|
|
39
|
+
|
|
11
40
|
Install templates into the current directory:
|
|
12
41
|
|
|
13
42
|
```bash
|
|
14
43
|
npx thomas-agentkit init
|
|
15
44
|
```
|
|
16
45
|
|
|
46
|
+
### Skill path
|
|
47
|
+
|
|
48
|
+
Install the bundled AgentKit skill (v0.9.x+). This does **not** create `AGENTS.md` or other guidance files — run `/agentkit init` in your agent afterward:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx thomas-agentkit skill install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Preview skill install without writing files:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx thomas-agentkit skill install --dry-run
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Overwrite an existing skill install:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx thomas-agentkit skill install --force
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
After install, the CLI prints:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
Installed AgentKit skill in .agents/skills/agentkit/
|
|
70
|
+
Wrote agentkit.config.json (installMode: skill)
|
|
71
|
+
|
|
72
|
+
Next step: In your agent, run agentkit init.
|
|
73
|
+
The skill will create AGENTS.md and companion files from your repository.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
After skill install, use the project-local skill from your agent:
|
|
77
|
+
|
|
78
|
+
- `/agentkit init` creates missing guidance files from repository context.
|
|
79
|
+
- `/agentkit update` syncs managed guidance with current repository context.
|
|
80
|
+
- `/agentkit doctor` audits guidance quality without editing by default.
|
|
81
|
+
- `/agentkit repair` repairs guidance structure, such as malformed managed blocks or thick AI adapters, after an explicit request.
|
|
82
|
+
- `/agentkit learn` teaches recent codebase changes, design decisions, edge cases, validation, and impact without writing files by default.
|
|
83
|
+
|
|
17
84
|
If the package is installed in a project, use the local `agentkit` binary:
|
|
18
85
|
|
|
19
86
|
```bash
|
|
@@ -77,6 +144,8 @@ Standardize install defaults with `agentkit.config.json`:
|
|
|
77
144
|
|
|
78
145
|
```json
|
|
79
146
|
{
|
|
147
|
+
"installMode": "template",
|
|
148
|
+
"agentkitVersion": "0.9.0",
|
|
80
149
|
"preset": "next",
|
|
81
150
|
"templateSet": "standard",
|
|
82
151
|
"designSystem": "linear",
|
|
@@ -105,7 +174,9 @@ npx thomas-agentkit init --write-config
|
|
|
105
174
|
|
|
106
175
|
`--write-config` writes `agentkit.config.json` in the target directory. Existing config files are skipped by default; use `--force` to overwrite one intentionally.
|
|
107
176
|
|
|
108
|
-
|
|
177
|
+
`installMode` is `"template"` or `"skill"` and records how the project was bootstrapped. `agentkitVersion` records the package version at install time. Configs without `installMode` are treated as template-path installs.
|
|
178
|
+
|
|
179
|
+
Config values are validated when loaded. Unknown config keys, invalid preset/template/design-system names, invalid AI tool names, invalid `installMode` values, and non-string personalization values exit with an error.
|
|
109
180
|
|
|
110
181
|
List bundled templates:
|
|
111
182
|
|
|
@@ -119,7 +190,7 @@ List available presets:
|
|
|
119
190
|
npx thomas-agentkit --list-presets
|
|
120
191
|
```
|
|
121
192
|
|
|
122
|
-
List bundled design
|
|
193
|
+
List bundled design baselines (source variants for `DESIGN.md`):
|
|
123
194
|
|
|
124
195
|
```bash
|
|
125
196
|
npx thomas-agentkit --list-design-systems
|
|
@@ -133,7 +204,7 @@ AgentKit can copy these bundled files into the target project:
|
|
|
133
204
|
- `CHANGE-EXPLANATION.md`
|
|
134
205
|
- `CLAUDE.md`
|
|
135
206
|
- `CODE-QUALITY.md`
|
|
136
|
-
- `DESIGN
|
|
207
|
+
- `DESIGN.md`
|
|
137
208
|
- `IMPLEMENTATION-BRIEF-TEMPLATE.md`
|
|
138
209
|
- `PRD-TEMPLATE.md`
|
|
139
210
|
- `SECURITY-CHECKLIST.md`
|
|
@@ -145,7 +216,7 @@ AgentKit can copy these bundled files into the target project:
|
|
|
145
216
|
|
|
146
217
|
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.
|
|
147
218
|
|
|
148
|
-
Bundled design
|
|
219
|
+
Bundled design baselines are stored under `templates/design-systems/` in this repository (`linear`, `apple`, `cursor`, `framer`, `notion`, `warp`). The CLI installs the chosen variant into `DESIGN.md` in the target project; variant paths are not separate install targets. The bundled AgentKit skill also ships copies under `references/design-baselines/` for `/agentkit design`.
|
|
149
220
|
|
|
150
221
|
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.
|
|
151
222
|
|
|
@@ -161,12 +232,12 @@ Generated content
|
|
|
161
232
|
|
|
162
233
|
Interactive personalization only applies during `agentkit init` when files are created or overwritten. It does not write a config file unless `--write-config` is passed, and `agentkit update` does not reapply personalized values.
|
|
163
234
|
|
|
164
|
-
`agentkit.config.json` can set `preset`, `templateSet`, `designSystem`, `aiTools`, and `personalization` defaults. `templateSet` may be `minimal`, `standard`, or `full`; `designSystem` selects which bundled
|
|
235
|
+
`agentkit.config.json` can set `preset`, `templateSet`, `designSystem`, `aiTools`, and `personalization` defaults. `templateSet` may be `minimal`, `standard`, or `full`; `designSystem` selects which bundled baseline fills `DESIGN.md` (`linear`, `apple`, `cursor`, `framer`, `notion`, or `warp`); `aiTools` may include `codex`, `cursor`, `claude`, and `copilot`. `agentkit update` uses config `preset` and `designSystem` and continues to update all managed bundled templates.
|
|
165
236
|
|
|
166
237
|
Template set mappings:
|
|
167
238
|
|
|
168
239
|
- `minimal`: `AGENTS.md`
|
|
169
|
-
- `standard`: `AGENTS.md`, `CHANGE-EXPLANATION.md`, `CODE-QUALITY.md`, `DESIGN
|
|
240
|
+
- `standard`: `AGENTS.md`, `CHANGE-EXPLANATION.md`, `CODE-QUALITY.md`, `DESIGN.md`, `.github/pull_request_template.md`
|
|
170
241
|
- `full`: all bundled templates, including AI tool adapters and planning/testing/security guides
|
|
171
242
|
|
|
172
243
|
AI tool mappings:
|
|
@@ -188,10 +259,31 @@ Presets add stack-specific guidance without scaffolding framework app files.
|
|
|
188
259
|
- `convex`
|
|
189
260
|
- `fullstack` (`Next.js` + `Convex`)
|
|
190
261
|
|
|
262
|
+
## CLI vs agent commands
|
|
263
|
+
|
|
264
|
+
The same names mean different things in the terminal vs in an agent session:
|
|
265
|
+
|
|
266
|
+
| Name | Where | What |
|
|
267
|
+
| --- | --- | --- |
|
|
268
|
+
| `agentkit init` | Terminal | Install **templates** |
|
|
269
|
+
| `agentkit skill install` | Terminal | Install **bundled skill** + config |
|
|
270
|
+
| `agentkit init` | Agent | Create **guidance files** (skill path) |
|
|
271
|
+
| `agentkit update` | Terminal | Template-path managed-block merge only |
|
|
272
|
+
| `agentkit update` | Agent | Sync guidance to repo changes |
|
|
273
|
+
| `agentkit doctor` | Agent | Audit guidance quality |
|
|
274
|
+
| `agentkit repair` | Agent | Repair guidance structure after explicit request |
|
|
275
|
+
| `agentkit learn` | Agent | Teach recent codebase changes and check understanding |
|
|
276
|
+
| `agentkit design` | Agent | Create or refresh `DESIGN.md` from a bundled baseline |
|
|
277
|
+
|
|
278
|
+
Never use CLI `agentkit init` for skill installation.
|
|
279
|
+
|
|
280
|
+
On skill-path repos (`installMode: skill`), CLI `agentkit update` prints an informational message and does not modify guidance files. Use `/agentkit update` in your agent for skill-path guidance sync.
|
|
281
|
+
|
|
191
282
|
## CLI Reference
|
|
192
283
|
|
|
193
284
|
```text
|
|
194
285
|
agentkit init [target] [--force] [--dry-run] [--interactive] [--yes] [--write-config] [--preset <name>] [--design-system <name>]
|
|
286
|
+
agentkit skill install [target] [--force] [--dry-run] [--yes] [--preset <name>] [--design-system <name>]
|
|
195
287
|
agentkit update [target] [--dry-run] [--preset <name>] [--design-system <name>]
|
|
196
288
|
agentkit --list
|
|
197
289
|
agentkit --list-presets
|
|
@@ -206,16 +298,16 @@ Options:
|
|
|
206
298
|
- `--dry-run`: print planned changes without writing files
|
|
207
299
|
- `-i, --interactive`: explicitly prompt for install options
|
|
208
300
|
- `-y, --yes`: accept defaults without prompts
|
|
209
|
-
- `--write-config`: write resolved install defaults to `agentkit.config.json`
|
|
301
|
+
- `--write-config`: write resolved template install defaults to `agentkit.config.json`
|
|
210
302
|
- `--preset <name>`: install stack-specific guidance (`next`, `sveltekit`, `express`, `convex`, `fullstack`)
|
|
211
|
-
- `--design-system <name>`: design
|
|
303
|
+
- `--design-system <name>`: design baseline for `DESIGN.md` (`linear`, `apple`, `cursor`, `framer`, `notion`, `warp`)
|
|
212
304
|
- `--list`: list bundled template files
|
|
213
305
|
- `--list-presets`: list available presets
|
|
214
306
|
- `--list-design-systems`: list available design systems
|
|
215
307
|
- `-h, --help`: show help
|
|
216
308
|
- `-v, --version`: show package version
|
|
217
309
|
|
|
218
|
-
For `agentkit update`, `--preset <name>` refreshes preset-specific managed content, including `STACK.md`. `--design-system <name>` refreshes the managed `DESIGN
|
|
310
|
+
For `agentkit update`, `--preset <name>` refreshes preset-specific managed content, including `STACK.md`. `--design-system <name>` refreshes the managed `DESIGN.md` body from the matching bundled baseline.
|
|
219
311
|
|
|
220
312
|
## Local Development
|
|
221
313
|
|
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { constants as fsConstants, realpathSync } from "node:fs";
|
|
|
5
5
|
import { access, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { getSkillDestinationPaths, getSkillSourceDir, installSkill, listSkillFiles, printSkillInstallResult, } from "./skill-install.js";
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
10
11
|
const packageRoot = path.resolve(__dirname, "..");
|
|
@@ -14,13 +15,33 @@ const validPresets = ["next", "sveltekit", "express", "convex", "fullstack"];
|
|
|
14
15
|
const validProjectTypes = ["generic", ...validPresets];
|
|
15
16
|
const validAiTools = ["codex", "cursor", "claude", "copilot"];
|
|
16
17
|
const validTemplateSets = ["minimal", "standard", "full"];
|
|
17
|
-
const validDesignSystems = [
|
|
18
|
+
const validDesignSystems = [
|
|
19
|
+
"linear",
|
|
20
|
+
"apple",
|
|
21
|
+
"cursor",
|
|
22
|
+
"framer",
|
|
23
|
+
"notion",
|
|
24
|
+
"warp",
|
|
25
|
+
];
|
|
18
26
|
const designSystemLabels = {
|
|
19
|
-
linear: "Linear
|
|
20
|
-
apple: "Apple
|
|
27
|
+
linear: "Linear",
|
|
28
|
+
apple: "Apple",
|
|
29
|
+
cursor: "Cursor",
|
|
30
|
+
framer: "Framer",
|
|
31
|
+
notion: "Notion",
|
|
32
|
+
warp: "Warp",
|
|
21
33
|
};
|
|
22
34
|
const configFileName = "agentkit.config.json";
|
|
23
|
-
const configKeys = [
|
|
35
|
+
const configKeys = [
|
|
36
|
+
"installMode",
|
|
37
|
+
"agentkitVersion",
|
|
38
|
+
"preset",
|
|
39
|
+
"templateSet",
|
|
40
|
+
"aiTools",
|
|
41
|
+
"designSystem",
|
|
42
|
+
"personalization",
|
|
43
|
+
];
|
|
44
|
+
const validInstallModes = ["template", "skill"];
|
|
24
45
|
const personalizationKeys = [
|
|
25
46
|
"projectName",
|
|
26
47
|
"projectDescription",
|
|
@@ -51,7 +72,7 @@ const templateSetFiles = {
|
|
|
51
72
|
"AGENTS.md",
|
|
52
73
|
"CHANGE-EXPLANATION.md",
|
|
53
74
|
"CODE-QUALITY.md",
|
|
54
|
-
"DESIGN
|
|
75
|
+
"DESIGN.md",
|
|
55
76
|
".github/pull_request_template.md",
|
|
56
77
|
],
|
|
57
78
|
full: [],
|
|
@@ -128,7 +149,7 @@ async function collectInstallableTemplatePaths(dir, base) {
|
|
|
128
149
|
for (const entry of entries) {
|
|
129
150
|
const absolutePath = path.join(dir, entry.name);
|
|
130
151
|
if (entry.isDirectory()) {
|
|
131
|
-
if (dir === templatesDir && entry.name === "design-systems") {
|
|
152
|
+
if (dir === templatesDir && (entry.name === "design-systems" || entry.name === "skills")) {
|
|
132
153
|
continue;
|
|
133
154
|
}
|
|
134
155
|
discovered.push(...(await collectInstallableTemplatePaths(absolutePath, base)));
|
|
@@ -143,10 +164,8 @@ async function collectInstallableTemplatePaths(dir, base) {
|
|
|
143
164
|
}
|
|
144
165
|
async function getTemplateFiles() {
|
|
145
166
|
const discovered = await collectInstallableTemplatePaths(templatesDir, templatesDir);
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
: [...discovered, "DESIGN-SYSTEM.md"];
|
|
149
|
-
return withDesignSystem.sort();
|
|
167
|
+
const withDesign = discovered.includes("DESIGN.md") ? discovered : [...discovered, "DESIGN.md"];
|
|
168
|
+
return withDesign.sort();
|
|
150
169
|
}
|
|
151
170
|
function isPresetName(value) {
|
|
152
171
|
return validPresets.includes(value);
|
|
@@ -257,13 +276,31 @@ function readConfigPersonalization(value) {
|
|
|
257
276
|
}
|
|
258
277
|
return personalization;
|
|
259
278
|
}
|
|
279
|
+
function resolveInstallMode(installMode) {
|
|
280
|
+
const normalizedInstallMode = installMode.toLowerCase();
|
|
281
|
+
if (!validInstallModes.includes(normalizedInstallMode)) {
|
|
282
|
+
throw new Error(`Unknown install mode "${installMode}". Valid install modes: ${validInstallModes.join(", ")}.`);
|
|
283
|
+
}
|
|
284
|
+
return normalizedInstallMode;
|
|
285
|
+
}
|
|
286
|
+
export function getInstallMode(config) {
|
|
287
|
+
return config?.installMode ?? "template";
|
|
288
|
+
}
|
|
260
289
|
function parseConfig(rawConfig, configPath) {
|
|
261
290
|
assertPlainObject(rawConfig, configFileName);
|
|
262
291
|
assertKnownKeys(rawConfig, configKeys, configFileName);
|
|
263
292
|
const preset = optionalConfigString(rawConfig, "preset");
|
|
264
293
|
const templateSet = optionalConfigString(rawConfig, "templateSet");
|
|
265
294
|
const designSystem = optionalConfigString(rawConfig, "designSystem");
|
|
295
|
+
const installMode = optionalConfigString(rawConfig, "installMode");
|
|
296
|
+
const agentkitVersion = optionalConfigString(rawConfig, "agentkitVersion");
|
|
266
297
|
const config = {};
|
|
298
|
+
if (installMode !== undefined) {
|
|
299
|
+
config.installMode = resolveInstallMode(installMode);
|
|
300
|
+
}
|
|
301
|
+
if (agentkitVersion !== undefined) {
|
|
302
|
+
config.agentkitVersion = agentkitVersion;
|
|
303
|
+
}
|
|
267
304
|
if (preset !== undefined) {
|
|
268
305
|
config.preset = resolvePreset(preset);
|
|
269
306
|
}
|
|
@@ -394,8 +431,10 @@ function cleanPersonalizationValue(value) {
|
|
|
394
431
|
const trimmed = value?.trim();
|
|
395
432
|
return trimmed ? trimmed : undefined;
|
|
396
433
|
}
|
|
397
|
-
function getResolvedConfig(options) {
|
|
434
|
+
function getResolvedConfig(options, installMode, agentkitVersion) {
|
|
398
435
|
const config = {
|
|
436
|
+
installMode,
|
|
437
|
+
agentkitVersion,
|
|
399
438
|
templateSet: options.templateSet ?? "standard",
|
|
400
439
|
aiTools: options.aiTools ?? [],
|
|
401
440
|
designSystem: effectiveDesignSystem(options.designSystem),
|
|
@@ -488,7 +527,7 @@ export function personalizeTemplateContent(file, content, values) {
|
|
|
488
527
|
return content;
|
|
489
528
|
}
|
|
490
529
|
let personalized = content;
|
|
491
|
-
if (file === "AGENTS.md" || file === "DESIGN
|
|
530
|
+
if (file === "AGENTS.md" || file === "DESIGN.md") {
|
|
492
531
|
personalized = replaceIfProvided(personalized, "[Project Name]", values.projectName);
|
|
493
532
|
}
|
|
494
533
|
if (file === "AGENTS.md") {
|
|
@@ -573,7 +612,7 @@ async function resolveInitTemplateFiles(options) {
|
|
|
573
612
|
}
|
|
574
613
|
return getSelectedTemplateFiles(options.templateSet ?? "standard", options.aiTools ?? [], allTemplateFiles);
|
|
575
614
|
}
|
|
576
|
-
async function installTemplates(targetArg, options) {
|
|
615
|
+
async function installTemplates(targetArg, options, agentkitVersion) {
|
|
577
616
|
const targetDir = path.resolve(process.cwd(), targetArg || ".");
|
|
578
617
|
const files = await resolveInitTemplateFiles(options);
|
|
579
618
|
const preset = resolvePreset(options.preset);
|
|
@@ -583,7 +622,7 @@ async function installTemplates(targetArg, options) {
|
|
|
583
622
|
await mkdir(targetDir, { recursive: true });
|
|
584
623
|
}
|
|
585
624
|
if (options.writeConfig) {
|
|
586
|
-
await installFileIfAllowed(targetDir, configFileName, options, result, () => serializeConfig(getResolvedConfig(options)));
|
|
625
|
+
await installFileIfAllowed(targetDir, configFileName, options, result, () => serializeConfig(getResolvedConfig(options, "template", agentkitVersion)));
|
|
587
626
|
}
|
|
588
627
|
for (const file of files) {
|
|
589
628
|
await installFileIfAllowed(targetDir, file, options, result, async () => {
|
|
@@ -619,7 +658,7 @@ async function buildTemplateContent(file, preset, designSystem) {
|
|
|
619
658
|
}
|
|
620
659
|
return getStackGuidance(preset);
|
|
621
660
|
}
|
|
622
|
-
if (file === "DESIGN
|
|
661
|
+
if (file === "DESIGN.md") {
|
|
623
662
|
const source = path.join(templatesDir, "design-systems", `${designSystem}.md`);
|
|
624
663
|
const content = await readFile(source, "utf8");
|
|
625
664
|
return addStackReference(file, content, preset);
|
|
@@ -790,7 +829,23 @@ async function promptForConflictStrategy(existingFiles) {
|
|
|
790
829
|
],
|
|
791
830
|
}));
|
|
792
831
|
}
|
|
793
|
-
async function
|
|
832
|
+
async function promptForBootstrapPath() {
|
|
833
|
+
return resolvePrompt(await select({
|
|
834
|
+
message: "How do you want to set up AgentKit?",
|
|
835
|
+
initialValue: "template",
|
|
836
|
+
options: [
|
|
837
|
+
{
|
|
838
|
+
label: "Copy templates now (install AGENTS.md and companion files)",
|
|
839
|
+
value: "template",
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
label: "Install AgentKit skill (create guidance files later in your agent)",
|
|
843
|
+
value: "skill",
|
|
844
|
+
},
|
|
845
|
+
],
|
|
846
|
+
}));
|
|
847
|
+
}
|
|
848
|
+
async function collectInstallOptions(resolvedTarget, providedPreset, options) {
|
|
794
849
|
if (!providedPreset) {
|
|
795
850
|
options.preset = await promptForProjectPreset();
|
|
796
851
|
}
|
|
@@ -803,25 +858,50 @@ async function applyInteractiveSelections(resolvedTarget, providedPreset, option
|
|
|
803
858
|
if (templateSet === "standard" || templateSet === "full") {
|
|
804
859
|
options.designSystem = await promptForDesignSystem(options.designSystem);
|
|
805
860
|
}
|
|
806
|
-
|
|
861
|
+
}
|
|
862
|
+
async function resolveConflictForInstall(resolvedTarget, options, bootstrapPath) {
|
|
863
|
+
if (options.force) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
let installFiles;
|
|
867
|
+
if (bootstrapPath === "skill") {
|
|
868
|
+
const skillFiles = await listSkillFiles(getSkillSourceDir(packageRoot));
|
|
869
|
+
installFiles = [...getSkillDestinationPaths(skillFiles), configFileName];
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
807
872
|
const preset = resolvePreset(options.preset);
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
873
|
+
installFiles = preset ? [...(options.files ?? []), "STACK.md"] : (options.files ?? []);
|
|
874
|
+
}
|
|
875
|
+
const existingFiles = await findExistingInstallFiles(resolvedTarget, installFiles);
|
|
876
|
+
if (existingFiles.length > 0) {
|
|
877
|
+
options.force = (await promptForConflictStrategy(existingFiles)) === "overwrite";
|
|
813
878
|
}
|
|
814
879
|
}
|
|
815
|
-
async function
|
|
880
|
+
async function runInteractiveInstall(target, options, agentkitVersion) {
|
|
881
|
+
intro("Welcome to AgentKit");
|
|
882
|
+
const bootstrapPath = await promptForBootstrapPath();
|
|
816
883
|
const providedPreset = resolvePreset(options.preset);
|
|
817
|
-
|
|
818
|
-
|
|
884
|
+
const resolvedTarget = await promptForTarget(target);
|
|
885
|
+
await collectInstallOptions(resolvedTarget, providedPreset, options);
|
|
886
|
+
options.personalization = await promptForPersonalization(options.personalization);
|
|
887
|
+
await resolveConflictForInstall(resolvedTarget, options, bootstrapPath);
|
|
888
|
+
if (bootstrapPath === "skill") {
|
|
889
|
+
const result = await installSkill(resolvedTarget, options, packageRoot, agentkitVersion);
|
|
890
|
+
printSkillInstallResult(result, Boolean(options.dryRun));
|
|
891
|
+
return;
|
|
819
892
|
}
|
|
893
|
+
const result = await installTemplates(resolvedTarget, options, agentkitVersion);
|
|
894
|
+
printInstallResult(result, Boolean(options.dryRun));
|
|
895
|
+
}
|
|
896
|
+
async function runSkillInstallInteractive(target, options, agentkitVersion) {
|
|
820
897
|
intro("Welcome to AgentKit");
|
|
898
|
+
const providedPreset = resolvePreset(options.preset);
|
|
821
899
|
const resolvedTarget = await promptForTarget(target);
|
|
822
|
-
await
|
|
900
|
+
await collectInstallOptions(resolvedTarget, providedPreset, options);
|
|
823
901
|
options.personalization = await promptForPersonalization(options.personalization);
|
|
824
|
-
|
|
902
|
+
await resolveConflictForInstall(resolvedTarget, options, "skill");
|
|
903
|
+
const result = await installSkill(resolvedTarget, options, packageRoot, agentkitVersion);
|
|
904
|
+
printSkillInstallResult(result, Boolean(options.dryRun));
|
|
825
905
|
}
|
|
826
906
|
async function main() {
|
|
827
907
|
if (process.argv.slice(2).includes("--list")) {
|
|
@@ -855,6 +935,7 @@ async function main() {
|
|
|
855
935
|
|
|
856
936
|
Examples:
|
|
857
937
|
agentkit init
|
|
938
|
+
agentkit skill install
|
|
858
939
|
agentkit update
|
|
859
940
|
agentkit init --preset next
|
|
860
941
|
agentkit init ./my-project --yes --dry-run
|
|
@@ -871,22 +952,54 @@ Examples:
|
|
|
871
952
|
.option("-y, --yes", "accept defaults for non-interactive runs")
|
|
872
953
|
.option("--write-config", "write resolved install defaults to agentkit.config.json")
|
|
873
954
|
.option("--preset <name>", `install stack-specific guidance (${formatPresetList()})`)
|
|
874
|
-
.option("--design-system <name>", `design
|
|
955
|
+
.option("--design-system <name>", `design baseline for DESIGN.md (${formatDesignSystemList()})`)
|
|
875
956
|
.action(async (target, options) => {
|
|
876
957
|
await applyInitConfig(options, await loadConfigForTarget(target));
|
|
877
|
-
const
|
|
878
|
-
|
|
958
|
+
const agentkitVersion = await readPackageVersion();
|
|
959
|
+
if (shouldPromptForInit(options, process)) {
|
|
960
|
+
await runInteractiveInstall(target, options, agentkitVersion);
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
const result = await installTemplates(target, options, agentkitVersion);
|
|
879
964
|
printInstallResult(result, Boolean(options.dryRun));
|
|
880
965
|
});
|
|
966
|
+
const skill = program.command("skill").description("install the bundled AgentKit Agent Skill");
|
|
967
|
+
skill
|
|
968
|
+
.command("install")
|
|
969
|
+
.description("install the bundled agentkit skill and write agentkit.config.json")
|
|
970
|
+
.argument("[target]", "target project directory", ".")
|
|
971
|
+
.option("--force", "overwrite existing skill files and config")
|
|
972
|
+
.option("--dry-run", "print planned changes without writing files")
|
|
973
|
+
.option("-i, --interactive", "prompt for install options")
|
|
974
|
+
.option("-y, --yes", "accept defaults for non-interactive runs")
|
|
975
|
+
.option("--preset <name>", `store stack preset in config (${formatPresetList()})`)
|
|
976
|
+
.option("--design-system <name>", `store design system choice in config (${formatDesignSystemList()})`)
|
|
977
|
+
.action(async (target, options) => {
|
|
978
|
+
await applyInitConfig(options, await loadConfigForTarget(target));
|
|
979
|
+
const agentkitVersion = await readPackageVersion();
|
|
980
|
+
if (shouldPromptForInit(options, process)) {
|
|
981
|
+
await runSkillInstallInteractive(target, options, agentkitVersion);
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
const result = await installSkill(target, options, packageRoot, agentkitVersion);
|
|
985
|
+
printSkillInstallResult(result, Boolean(options.dryRun));
|
|
986
|
+
});
|
|
881
987
|
program
|
|
882
988
|
.command("update")
|
|
883
989
|
.description("update AgentKit managed template blocks in a project")
|
|
884
990
|
.argument("[target]", "target project directory", ".")
|
|
885
991
|
.option("--dry-run", "print planned changes without writing files")
|
|
886
992
|
.option("--preset <name>", `update stack-specific guidance (${formatPresetList()})`)
|
|
887
|
-
.option("--design-system <name>", `design
|
|
993
|
+
.option("--design-system <name>", `design baseline for DESIGN.md (${formatDesignSystemList()})`)
|
|
888
994
|
.action(async (target, options) => {
|
|
889
|
-
|
|
995
|
+
const config = await loadConfigForTarget(target);
|
|
996
|
+
if (getInstallMode(config) === "skill") {
|
|
997
|
+
console.log("This project uses installMode: skill.");
|
|
998
|
+
console.log("Run agentkit update in your agent to sync guidance files.");
|
|
999
|
+
console.log("(CLI agentkit update applies to template-path installs.)");
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
applyUpdateConfig(options, config);
|
|
890
1003
|
const result = await updateTemplates(target, options);
|
|
891
1004
|
printUpdateResult(result, Boolean(options.dryRun));
|
|
892
1005
|
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { access, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export const SKILL_DEST_DIR = ".agents/skills/agentkit";
|
|
5
|
+
export const CONFIG_FILE_NAME = "agentkit.config.json";
|
|
6
|
+
export function getSkillSourceDir(packageRoot) {
|
|
7
|
+
return path.join(packageRoot, "templates", "skills", "agentkit");
|
|
8
|
+
}
|
|
9
|
+
export async function listSkillFiles(sourceDir) {
|
|
10
|
+
const files = [];
|
|
11
|
+
async function walk(dir, prefix) {
|
|
12
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
15
|
+
const fullPath = path.join(dir, entry.name);
|
|
16
|
+
if (entry.isDirectory()) {
|
|
17
|
+
await walk(fullPath, relative);
|
|
18
|
+
}
|
|
19
|
+
else if (entry.isFile()) {
|
|
20
|
+
files.push(relative);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
await walk(sourceDir, "");
|
|
25
|
+
return files.sort();
|
|
26
|
+
}
|
|
27
|
+
export function buildSkillConfig(options, agentkitVersion) {
|
|
28
|
+
const config = {
|
|
29
|
+
installMode: "skill",
|
|
30
|
+
agentkitVersion,
|
|
31
|
+
templateSet: options.templateSet ?? "standard",
|
|
32
|
+
aiTools: options.aiTools ?? [],
|
|
33
|
+
designSystem: options.designSystem ?? "linear",
|
|
34
|
+
};
|
|
35
|
+
if (options.preset) {
|
|
36
|
+
config.preset = options.preset;
|
|
37
|
+
}
|
|
38
|
+
if (options.personalization) {
|
|
39
|
+
const personalization = {};
|
|
40
|
+
for (const [key, value] of Object.entries(options.personalization)) {
|
|
41
|
+
const trimmed = value?.trim();
|
|
42
|
+
if (trimmed) {
|
|
43
|
+
personalization[key] = trimmed;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (Object.keys(personalization).length > 0) {
|
|
47
|
+
config.personalization = personalization;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return config;
|
|
51
|
+
}
|
|
52
|
+
export function getSkillDestinationPaths(skillFiles) {
|
|
53
|
+
return skillFiles.map((file) => path.posix.join(SKILL_DEST_DIR, file.replace(/\\/g, "/")));
|
|
54
|
+
}
|
|
55
|
+
async function pathExists(filePath) {
|
|
56
|
+
try {
|
|
57
|
+
await access(filePath, fsConstants.F_OK);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export async function installSkill(targetArg, options, packageRoot, agentkitVersion) {
|
|
65
|
+
const targetDir = path.resolve(process.cwd(), targetArg || ".");
|
|
66
|
+
const sourceDir = getSkillSourceDir(packageRoot);
|
|
67
|
+
const skillFiles = await listSkillFiles(sourceDir);
|
|
68
|
+
const result = { targetDir, created: [], skipped: [] };
|
|
69
|
+
if (!options.dryRun) {
|
|
70
|
+
await mkdir(targetDir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
for (const file of skillFiles) {
|
|
73
|
+
const destination = path.join(targetDir, SKILL_DEST_DIR, file);
|
|
74
|
+
const destinationRelative = path.posix.join(SKILL_DEST_DIR, file.replace(/\\/g, "/"));
|
|
75
|
+
if ((await pathExists(destination)) && !options.force) {
|
|
76
|
+
result.skipped.push(destinationRelative);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
result.created.push(destinationRelative);
|
|
80
|
+
if (!options.dryRun) {
|
|
81
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
82
|
+
const content = await readFile(path.join(sourceDir, file), "utf8");
|
|
83
|
+
await writeFile(destination, content);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const configPath = path.join(targetDir, CONFIG_FILE_NAME);
|
|
87
|
+
const configRelative = CONFIG_FILE_NAME;
|
|
88
|
+
if ((await pathExists(configPath)) && !options.force) {
|
|
89
|
+
if (!result.skipped.includes(configRelative)) {
|
|
90
|
+
result.skipped.push(configRelative);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (!result.created.includes(configRelative)) {
|
|
95
|
+
result.created.push(configRelative);
|
|
96
|
+
}
|
|
97
|
+
if (!options.dryRun) {
|
|
98
|
+
const configContent = `${JSON.stringify(buildSkillConfig(options, agentkitVersion), null, 2)}\n`;
|
|
99
|
+
await writeFile(configPath, configContent);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
export function printSkillInstallResult(result, dryRun = false) {
|
|
105
|
+
if (dryRun) {
|
|
106
|
+
console.log(`Would install AgentKit skill in ${SKILL_DEST_DIR}/`);
|
|
107
|
+
if (result.created.length > 0) {
|
|
108
|
+
console.log(`Would create: ${result.created.join(", ")}`);
|
|
109
|
+
}
|
|
110
|
+
if (result.skipped.length > 0) {
|
|
111
|
+
console.log(`Would skip existing: ${result.skipped.join(", ")}`);
|
|
112
|
+
console.log("Use --force to overwrite existing files.");
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(`Installed AgentKit skill in ${SKILL_DEST_DIR}/`);
|
|
117
|
+
console.log(`Wrote ${CONFIG_FILE_NAME} (installMode: skill)`);
|
|
118
|
+
console.log("");
|
|
119
|
+
console.log("Next step: In your agent, run agentkit init.");
|
|
120
|
+
console.log("The skill will create AGENTS.md and companion files from your repository.");
|
|
121
|
+
if (result.skipped.length > 0) {
|
|
122
|
+
console.log(`Skipped existing: ${result.skipped.join(", ")}`);
|
|
123
|
+
console.log("Use --force to overwrite existing files.");
|
|
124
|
+
}
|
|
125
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thomas-agentkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-alpha.1",
|
|
4
4
|
"description": "Install AI-agent-ready development templates into a project.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"build": "tsc",
|
|
34
34
|
"dev": "tsx src/cli.ts",
|
|
35
35
|
"test": "vitest run",
|
|
36
|
+
"validate:skill": "skills-ref validate ./templates/skills/agentkit",
|
|
36
37
|
"prepack": "npm run build"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"commander": "^12.1.0"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
44
|
+
"skills-ref": "^0.1.5",
|
|
43
45
|
"@types/node": "^22.10.2",
|
|
44
46
|
"tsx": "^4.19.2",
|
|
45
47
|
"typescript": "^5.7.2",
|
|
@@ -11,7 +11,7 @@ Use this rule as a repository guidance router for Cursor agents and composer wor
|
|
|
11
11
|
## When Relevant
|
|
12
12
|
|
|
13
13
|
- **File edits (final message):** change-explanation format in `AGENTS.md` and `CHANGE-EXPLANATION.md`.
|
|
14
|
-
- **UI / styling / layout:** `DESIGN
|
|
14
|
+
- **UI / styling / layout:** `DESIGN.md` or the project design path from `AGENTS.md`.
|
|
15
15
|
- **Review / refactor / dependencies:** `CODE-QUALITY.md`.
|
|
16
16
|
- **Tests / QA strategy:** `TESTING.md` if present.
|
|
17
17
|
- **Auth / secrets / PII:** `SECURITY-CHECKLIST.md` if present.
|