thomas-agentkit 0.2.0 → 0.3.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/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/cli.js +128 -4
- package/package.json +18 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Howard Thomas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -32,6 +32,18 @@ Overwrite existing files:
|
|
|
32
32
|
npx thomas-agentkit init --force
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
Update AgentKit-managed template sections:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx thomas-agentkit update
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Preview updates without writing files:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx thomas-agentkit update --dry-run
|
|
45
|
+
```
|
|
46
|
+
|
|
35
47
|
Use the optional interactive flow:
|
|
36
48
|
|
|
37
49
|
```bash
|
|
@@ -75,6 +87,16 @@ When a preset is selected, AgentKit also installs `STACK.md` and adds a note in
|
|
|
75
87
|
|
|
76
88
|
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.
|
|
77
89
|
|
|
90
|
+
New installs wrap generated template content in AgentKit managed block markers:
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<!-- agentkit:start agents -->
|
|
94
|
+
Generated content
|
|
95
|
+
<!-- agentkit:end agents -->
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`agentkit update` only replaces content inside matching managed blocks. User edits before or after those blocks are preserved. Existing legacy files without managed blocks are reported as unmanaged and left untouched.
|
|
99
|
+
|
|
78
100
|
## Presets
|
|
79
101
|
|
|
80
102
|
Presets add stack-specific guidance without scaffolding framework app files.
|
|
@@ -89,6 +111,7 @@ Presets add stack-specific guidance without scaffolding framework app files.
|
|
|
89
111
|
|
|
90
112
|
```text
|
|
91
113
|
agentkit init [target] [--force] [--dry-run] [--interactive] [--yes] [--preset <name>]
|
|
114
|
+
agentkit update [target] [--dry-run] [--preset <name>]
|
|
92
115
|
agentkit --list
|
|
93
116
|
agentkit --list-presets
|
|
94
117
|
agentkit --help
|
|
@@ -107,6 +130,8 @@ Options:
|
|
|
107
130
|
- `-h, --help`: show help
|
|
108
131
|
- `-v, --version`: show package version
|
|
109
132
|
|
|
133
|
+
For `agentkit update`, `--preset <name>` refreshes preset-specific managed content, including `STACK.md`.
|
|
134
|
+
|
|
110
135
|
## Local Development
|
|
111
136
|
|
|
112
137
|
```bash
|
|
@@ -118,6 +143,35 @@ npm test
|
|
|
118
143
|
|
|
119
144
|
The npm package is `thomas-agentkit`. The installed CLI command is `agentkit`, backed by the compiled TypeScript entrypoint at `dist/cli.js`.
|
|
120
145
|
|
|
146
|
+
## Release
|
|
147
|
+
|
|
148
|
+
Before publishing a new package version:
|
|
149
|
+
|
|
150
|
+
1. Update the version in `package.json` intentionally.
|
|
151
|
+
2. Run the full test suite:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm test
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
3. Run the package build step:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npm run prepack
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
4. Inspect the publish contents:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm pack --dry-run
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
5. Publish to npm:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npm publish
|
|
173
|
+
```
|
|
174
|
+
|
|
121
175
|
## Philosophy
|
|
122
176
|
|
|
123
177
|
AgentKit should stay:
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
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,
|
|
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
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -117,6 +117,19 @@ function resolvePreset(preset) {
|
|
|
117
117
|
function getStackGuidance(preset) {
|
|
118
118
|
return preset === "fullstack" ? fullstackGuidance : stackGuidance[preset];
|
|
119
119
|
}
|
|
120
|
+
function getTemplateId(file) {
|
|
121
|
+
return file
|
|
122
|
+
.replace(/\.[^/.]+$/, "")
|
|
123
|
+
.replace(/^\./, "")
|
|
124
|
+
.split("/")
|
|
125
|
+
.filter(Boolean)
|
|
126
|
+
.join("-")
|
|
127
|
+
.toLowerCase();
|
|
128
|
+
}
|
|
129
|
+
function wrapManagedBlock(file, content) {
|
|
130
|
+
const id = getTemplateId(file);
|
|
131
|
+
return `<!-- agentkit:start ${id} -->\n${content.trimEnd()}\n<!-- agentkit:end ${id} -->\n`;
|
|
132
|
+
}
|
|
120
133
|
function addStackReference(file, content, preset) {
|
|
121
134
|
if (file !== "AGENTS.md" || !preset) {
|
|
122
135
|
return content;
|
|
@@ -149,10 +162,11 @@ async function installTemplates(targetArg, options) {
|
|
|
149
162
|
await mkdir(path.dirname(destination), { recursive: true });
|
|
150
163
|
if (preset && file === "AGENTS.md") {
|
|
151
164
|
const content = await readFile(source, "utf8");
|
|
152
|
-
await writeFile(destination, addStackReference(file, content, preset));
|
|
165
|
+
await writeFile(destination, wrapManagedBlock(file, addStackReference(file, content, preset)));
|
|
153
166
|
}
|
|
154
167
|
else {
|
|
155
|
-
await
|
|
168
|
+
const content = await readFile(source, "utf8");
|
|
169
|
+
await writeFile(destination, wrapManagedBlock(file, content));
|
|
156
170
|
}
|
|
157
171
|
}
|
|
158
172
|
}
|
|
@@ -166,12 +180,84 @@ async function installTemplates(targetArg, options) {
|
|
|
166
180
|
else {
|
|
167
181
|
created.push(stackFile);
|
|
168
182
|
if (!options.dryRun) {
|
|
169
|
-
await writeFile(destination, getStackGuidance(preset));
|
|
183
|
+
await writeFile(destination, wrapManagedBlock(stackFile, getStackGuidance(preset)));
|
|
170
184
|
}
|
|
171
185
|
}
|
|
172
186
|
}
|
|
173
187
|
return { targetDir, created, skipped };
|
|
174
188
|
}
|
|
189
|
+
function replaceManagedBlock(file, existingContent, nextContent) {
|
|
190
|
+
const id = getTemplateId(file);
|
|
191
|
+
const startMarker = `<!-- agentkit:start ${id} -->`;
|
|
192
|
+
const endMarker = `<!-- agentkit:end ${id} -->`;
|
|
193
|
+
const startIndex = existingContent.indexOf(startMarker);
|
|
194
|
+
const endIndex = existingContent.indexOf(endMarker);
|
|
195
|
+
if (startIndex === -1 && endIndex === -1) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
|
|
199
|
+
throw new Error(`Malformed managed block in ${file}.`);
|
|
200
|
+
}
|
|
201
|
+
const afterEndIndex = endIndex + endMarker.length;
|
|
202
|
+
const replacement = wrapManagedBlock(file, nextContent).trimEnd();
|
|
203
|
+
return `${existingContent.slice(0, startIndex)}${replacement}${existingContent.slice(afterEndIndex)}`;
|
|
204
|
+
}
|
|
205
|
+
async function buildTemplateContent(file, preset) {
|
|
206
|
+
if (file === "STACK.md") {
|
|
207
|
+
if (!preset) {
|
|
208
|
+
throw new Error("STACK.md requires a preset.");
|
|
209
|
+
}
|
|
210
|
+
return getStackGuidance(preset);
|
|
211
|
+
}
|
|
212
|
+
const source = path.join(templatesDir, file);
|
|
213
|
+
const content = await readFile(source, "utf8");
|
|
214
|
+
return addStackReference(file, content, preset);
|
|
215
|
+
}
|
|
216
|
+
async function updateTemplates(targetArg, options) {
|
|
217
|
+
const targetDir = path.resolve(process.cwd(), targetArg || ".");
|
|
218
|
+
const preset = resolvePreset(options.preset);
|
|
219
|
+
const files = preset ? [...(await getTemplateFiles()), "STACK.md"] : await getTemplateFiles();
|
|
220
|
+
const created = [];
|
|
221
|
+
const updated = [];
|
|
222
|
+
const skipped = [];
|
|
223
|
+
const malformed = [];
|
|
224
|
+
const unchanged = [];
|
|
225
|
+
for (const file of files) {
|
|
226
|
+
const destination = path.join(targetDir, file);
|
|
227
|
+
const nextContent = await buildTemplateContent(file, preset);
|
|
228
|
+
const destinationExists = await exists(destination);
|
|
229
|
+
if (!destinationExists) {
|
|
230
|
+
created.push(file);
|
|
231
|
+
if (!options.dryRun) {
|
|
232
|
+
await mkdir(path.dirname(destination), { recursive: true });
|
|
233
|
+
await writeFile(destination, wrapManagedBlock(file, nextContent));
|
|
234
|
+
}
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const existingContent = await readFile(destination, "utf8");
|
|
238
|
+
let updatedContent;
|
|
239
|
+
try {
|
|
240
|
+
updatedContent = replaceManagedBlock(file, existingContent, nextContent);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
malformed.push(file);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (updatedContent === undefined) {
|
|
247
|
+
skipped.push(file);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (updatedContent === existingContent) {
|
|
251
|
+
unchanged.push(file);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
updated.push(file);
|
|
255
|
+
if (!options.dryRun) {
|
|
256
|
+
await writeFile(destination, updatedContent);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return { targetDir, created, updated, skipped, malformed, unchanged };
|
|
260
|
+
}
|
|
175
261
|
function printInstallResult(result, dryRun = false) {
|
|
176
262
|
const action = dryRun ? "Would install" : "Installed";
|
|
177
263
|
console.log(`${action} AgentKit files in ${result.targetDir}`);
|
|
@@ -186,6 +272,33 @@ function printInstallResult(result, dryRun = false) {
|
|
|
186
272
|
console.log("No bundled templates found.");
|
|
187
273
|
}
|
|
188
274
|
}
|
|
275
|
+
function printUpdateResult(result, dryRun = false) {
|
|
276
|
+
const action = dryRun ? "Would update" : "Updated";
|
|
277
|
+
console.log(`${action} AgentKit files in ${result.targetDir}`);
|
|
278
|
+
if (result.created.length > 0) {
|
|
279
|
+
console.log(`${dryRun ? "Would create" : "Created"}: ${result.created.join(", ")}`);
|
|
280
|
+
}
|
|
281
|
+
if (result.updated.length > 0) {
|
|
282
|
+
console.log(`${dryRun ? "Would update" : "Updated"}: ${result.updated.join(", ")}`);
|
|
283
|
+
}
|
|
284
|
+
if (result.unchanged.length > 0) {
|
|
285
|
+
console.log(`Already current: ${result.unchanged.join(", ")}`);
|
|
286
|
+
}
|
|
287
|
+
if (result.skipped.length > 0) {
|
|
288
|
+
console.log(`Skipped unmanaged: ${result.skipped.join(", ")}`);
|
|
289
|
+
console.log("Add AgentKit managed block markers before updating these files.");
|
|
290
|
+
}
|
|
291
|
+
if (result.malformed.length > 0) {
|
|
292
|
+
console.log(`Skipped malformed: ${result.malformed.join(", ")}`);
|
|
293
|
+
console.log("Fix AgentKit managed block markers before updating these files.");
|
|
294
|
+
}
|
|
295
|
+
if (result.created.length === 0 &&
|
|
296
|
+
result.updated.length === 0 &&
|
|
297
|
+
result.skipped.length === 0 &&
|
|
298
|
+
result.malformed.length === 0) {
|
|
299
|
+
console.log("All managed AgentKit files are current.");
|
|
300
|
+
}
|
|
301
|
+
}
|
|
189
302
|
async function resolveInteractiveTarget(target, options) {
|
|
190
303
|
const providedPreset = resolvePreset(options.preset);
|
|
191
304
|
if (!options.interactive) {
|
|
@@ -250,6 +363,7 @@ async function main() {
|
|
|
250
363
|
|
|
251
364
|
Examples:
|
|
252
365
|
agentkit init
|
|
366
|
+
agentkit update
|
|
253
367
|
agentkit init --preset next
|
|
254
368
|
agentkit init ./my-project --dry-run
|
|
255
369
|
agentkit --list-presets
|
|
@@ -268,6 +382,16 @@ Examples:
|
|
|
268
382
|
const result = await installTemplates(resolvedTarget, options);
|
|
269
383
|
printInstallResult(result, Boolean(options.dryRun));
|
|
270
384
|
});
|
|
385
|
+
program
|
|
386
|
+
.command("update")
|
|
387
|
+
.description("update AgentKit managed template blocks in a project")
|
|
388
|
+
.argument("[target]", "target project directory", ".")
|
|
389
|
+
.option("--dry-run", "print planned changes without writing files")
|
|
390
|
+
.option("--preset <name>", `update stack-specific guidance (${formatPresetList()})`)
|
|
391
|
+
.action(async (target, options) => {
|
|
392
|
+
const result = await updateTemplates(target, options);
|
|
393
|
+
printUpdateResult(result, Boolean(options.dryRun));
|
|
394
|
+
});
|
|
271
395
|
await program.parseAsync(process.argv);
|
|
272
396
|
}
|
|
273
397
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thomas-agentkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Install AI-agent-ready development templates into a project.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/howie1329/Howard-AgentKit.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/howie1329/Howard-AgentKit#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/howie1329/Howard-AgentKit/issues"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"agentkit",
|
|
16
|
+
"ai",
|
|
17
|
+
"agents",
|
|
18
|
+
"codex",
|
|
19
|
+
"cli",
|
|
20
|
+
"scaffolding",
|
|
21
|
+
"templates"
|
|
22
|
+
],
|
|
6
23
|
"type": "module",
|
|
7
24
|
"bin": {
|
|
8
25
|
"agentkit": "./dist/cli.js"
|