agent-method 1.5.13 → 1.5.15

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.
@@ -1,4 +1,9 @@
1
- /** wwa upgrade — brownfield-safe methodology update. */
1
+ /**
2
+ * wwa upgrade — brownfield-safe methodology update.
3
+ *
4
+ * Invariant (all wwa commands): canonical names persist in the working directory;
5
+ * versioned/archived copies live only under .wwa-archive/ (see helpers.WWA_ARCHIVE_DIR).
6
+ */
2
7
 
3
8
  import {
4
9
  readFileSync, existsSync, mkdirSync, copyFileSync, unlinkSync,
@@ -6,7 +11,7 @@ import {
6
11
  import { resolve, join, dirname } from "node:path";
7
12
  import {
8
13
  findEntryPoint, readMethodVersion, basename_of, pkg, packageRoot,
9
- safeWriteFile, safeCopyFile,
14
+ safeWriteFile, safeCopyFile, WWA_ARCHIVE_DIR,
10
15
  } from "./helpers.js";
11
16
 
12
17
  export function register(program) {
@@ -206,12 +211,12 @@ export function register(program) {
206
211
  }
207
212
  }
208
213
 
209
- // 6. Non-destructive template/schema upgrades (versioned files + backlog)
214
+ // 6. Non-destructive template/schema upgrades (archived originals + live latest)
210
215
  //
211
- // When templates or schemas change, we never overwrite existing project files.
212
- // Instead we:
213
- // - Write a versioned file alongside the original (e.g. CLAUDE.v2.md, doc-tokens.v2.yaml)
214
- // - Add a backlog entry pointing to the new file so the user/agent can migrate.
216
+ // When templates or schemas change, we never delete user content. Instead we:
217
+ // - Archive the existing file into a subdirectory (e.g. .wwa-archive/entry-points/CLAUDE.md)
218
+ // - Replace the live file with the latest template/schema
219
+ // - Add a backlog entry pointing to the archived copy so migration can be reviewed.
215
220
 
216
221
  // 6a. Entry point templates (CLAUDE.md / .cursorrules / AGENT.md)
217
222
  if (ep) {
@@ -220,19 +225,20 @@ export function register(program) {
220
225
  if (existsSync(templatePath)) {
221
226
  const change = classifyMarkdownChange(templatePath, ep);
222
227
  if (change === "present_diverged_user") {
223
- const v2Path = nextVersionedPath(ep);
224
- const relV2 = v2Path.replace(d, "").replace(/^[\\/]/, "");
225
- if (!existsSync(v2Path)) {
226
- actions.push(`Write versioned entry point template ${relV2}`);
227
- if (!opts.dryRun) {
228
- mkdirSync(dirname(v2Path), { recursive: true });
229
- safeCopyFile(templatePath, v2Path);
230
- }
228
+ const archiveDir = join(d, WWA_ARCHIVE_DIR, "entry-points");
229
+ const baseArchivePath = join(archiveDir, entryName);
230
+ const archivePath = nextVersionedPathInsideArchive(archiveDir, entryName);
231
+ const relArchive = archivePath.replace(d, "").replace(/^[\\/]/, "");
232
+ actions.push(`Archive existing entry point to ${relArchive} and replace with latest template`);
233
+ if (!opts.dryRun) {
234
+ mkdirSync(dirname(archivePath), { recursive: true });
235
+ safeCopyFile(ep, archivePath);
236
+ safeCopyFile(templatePath, ep);
231
237
  }
232
238
  ensureBacklogEntry(
233
239
  d,
234
- relV2,
235
- `- [ ] **Review new entry point template** — A new version of ${relV2} is available. Review differences and migrate conventions when convenient.`
240
+ relArchive,
241
+ `- [ ] **Review upgraded entry point** — Existing entry point archived at ${relArchive}. Compare with current ${entryName} and reconcile any custom conventions.`
236
242
  );
237
243
  }
238
244
  }
@@ -249,19 +255,19 @@ export function register(program) {
249
255
  if (existsSync(projectTokensPath) && existsSync(templateTokensPath)) {
250
256
  const change = classifyYamlChange(templateTokensPath, projectTokensPath);
251
257
  if (change === "schema_changed" || change === "present_diverged_user") {
252
- const v2Path = nextVersionedPath(projectTokensPath);
253
- const relV2 = v2Path.replace(d, "").replace(/^[\\/]/, "");
254
- if (!existsSync(v2Path)) {
255
- actions.push(`Write versioned schema ${relV2}`);
256
- if (!opts.dryRun) {
257
- mkdirSync(dirname(v2Path), { recursive: true });
258
- safeCopyFile(templateTokensPath, v2Path);
259
- }
258
+ const archiveDir = join(d, WWA_ARCHIVE_DIR, "registry");
259
+ const archivePath = nextVersionedPathInsideArchive(archiveDir, "doc-tokens.yaml");
260
+ const relArchive = archivePath.replace(d, "").replace(/^[\\/]/, "");
261
+ actions.push(`Archive existing registry/doc-tokens.yaml to ${relArchive} and replace with latest schema`);
262
+ if (!opts.dryRun) {
263
+ mkdirSync(dirname(archivePath), { recursive: true });
264
+ safeCopyFile(projectTokensPath, archivePath);
265
+ safeCopyFile(templateTokensPath, projectTokensPath);
260
266
  }
261
267
  ensureBacklogEntry(
262
268
  d,
263
- relV2,
264
- `- [ ] **Migrate doc-tokens schema** — New schema written to ${relV2}. Plan migration and update tooling as needed.`
269
+ relArchive,
270
+ `- [ ] **Review doc-tokens schema migration** — Previous schema archived at ${relArchive}. Confirm that tooling and docs are compatible with the updated registry/doc-tokens.yaml.`
265
271
  );
266
272
  }
267
273
  }
@@ -282,8 +288,12 @@ export function register(program) {
282
288
  }
283
289
 
284
290
  // ---------------------------------------------------------------------------
285
- // Helper functions — change classification, versioned paths, backlog entries
291
+ // Helper functions — change classification, archive paths, backlog entries
286
292
  // ---------------------------------------------------------------------------
293
+ //
294
+ // Versioned filenames are only ever created inside the archive subdirectory,
295
+ // never in the working directory, so canonical names (CLAUDE.md, doc-tokens.yaml)
296
+ // always persist in place.
287
297
 
288
298
  function classifyMarkdownChange(templatePath, projectPath) {
289
299
  if (!existsSync(projectPath) || !existsSync(templatePath)) return "missing";
@@ -303,16 +313,17 @@ function classifyYamlChange(templatePath, projectPath) {
303
313
  return "schema_changed";
304
314
  }
305
315
 
306
- function nextVersionedPath(projectPath) {
307
- const match = projectPath.match(/^(.*)(\.[^./\\]+)$/);
308
- const stem = match ? match[1] : projectPath;
316
+ /**
317
+ * Return a path for an archived copy, with a version suffix only inside the archive dir.
318
+ * Ensures we never write *.v2.* in the working directory — only under archiveDir.
319
+ */
320
+ function nextVersionedPathInsideArchive(archiveDir, filename) {
321
+ const match = filename.match(/^(.*)(\.[^./\\]+)$/);
322
+ const stem = match ? match[1] : filename;
309
323
  const ext = match ? match[2] : "";
310
324
  let counter = 2;
311
- // Generate stem.v2.ext, stem.v3.ext, ... until we find a free path
312
- // (e.g. CLAUDE.v2.md, doc-tokens.v2.yaml).
313
- // eslint-disable-next-line no-constant-condition
314
- while (true) {
315
- const candidate = `${stem}.v${counter}${ext}`;
325
+ for (;;) {
326
+ const candidate = join(archiveDir, `${stem}.v${counter}${ext}`);
316
327
  if (!existsSync(candidate)) return candidate;
317
328
  counter += 1;
318
329
  }
package/lib/init.js CHANGED
@@ -57,8 +57,7 @@ export async function initProject(projectType, directory, opts = {}) {
57
57
 
58
58
  const templateDir = join(methodRoot, "templates", tier);
59
59
  if (!existsSync(templateDir)) {
60
- console.error(`Template directory not found: ${templateDir}`);
61
- process.exit(1);
60
+ throw new Error(`Template directory not found: ${templateDir}`);
62
61
  }
63
62
 
64
63
  console.log(`\nSetting up ${FRIENDLY_NAMES[projectType] || projectType} project`);