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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/dist/cli.js +128 -4
  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, copyFile, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
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 copyFile(source, destination);
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.2.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"